Skip to content

Commit

Permalink
backport of commit ab39f19
Browse files Browse the repository at this point in the history
  • Loading branch information
philrenaud authored Jan 7, 2025
1 parent f27c521 commit 834875d
Show file tree
Hide file tree
Showing 11 changed files with 94 additions and 45 deletions.
3 changes: 3 additions & 0 deletions .changelog/24723.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:improvement
ui: add leadership status for servers in other regions
```
13 changes: 8 additions & 5 deletions ui/app/models/agent.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ import { inject as service } from '@ember/service';
import { computed } from '@ember/object';
import Model from '@ember-data/model';
import { attr } from '@ember-data/model';
import classic from 'ember-classic-decorator';
import { tracked } from '@glimmer/tracking';
import { action } from '@ember/object';
import formatHost from 'nomad-ui/utils/format-host';

@classic
export default class Agent extends Model {
@service system;

Expand All @@ -29,9 +29,12 @@ export default class Agent extends Model {
return formatHost(address, rpcPort);
}

@computed('rpcAddr', 'system.leader.rpcAddr')
get isLeader() {
return this.get('system.leader.rpcAddr') === this.rpcAddr;
@tracked isLeader = false;

@action async checkForLeadership() {
const leaders = await this.system.leaders;
this.isLeader = leaders.includes(this.rpcAddr);
return this.isLeader;
}

@computed('tags.build')
Expand Down
5 changes: 0 additions & 5 deletions ui/app/routes/clients.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,6 @@ import classic from 'ember-classic-decorator';
@classic
export default class ClientsRoute extends Route.extend(WithForbiddenState) {
@service store;
@service system;

beforeModel() {
return this.get('system.leader');
}

model() {
return RSVP.hash({
Expand Down
10 changes: 6 additions & 4 deletions ui/app/routes/servers.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,16 @@ export default class ServersRoute extends Route.extend(WithForbiddenState) {
@service store;
@service system;

beforeModel() {
return this.get('system.leader');
async beforeModel() {
await this.system.leaders;
}

model() {
async model() {
const agents = await this.store.findAll('agent');
await Promise.all(agents.map((agent) => agent.checkForLeadership()));
return RSVP.hash({
nodes: this.store.findAll('node'),
agents: this.store.findAll('agent'),
agents,
}).catch(notifyForbidden(this));
}
}
28 changes: 12 additions & 16 deletions ui/app/services/system.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,27 +12,23 @@ import { namespace } from '../adapters/application';
import jsonWithDefault from '../utils/json-with-default';
import classic from 'ember-classic-decorator';
import { task } from 'ember-concurrency';

@classic
export default class SystemService extends Service {
@service token;
@service store;

@computed('activeRegion')
get leader() {
const token = this.token;

return PromiseObject.create({
promise: token
.authorizedRequest(`/${namespace}/status/leader`)
.then((res) => res.json())
.then((rpcAddr) => ({ rpcAddr }))
.then((leader) => {
// Dirty self so leader can be used as a dependent key
this.notifyPropertyChange('leader.rpcAddr');
return leader;
}),
});
/**
* Iterates over all regions and returns a list of leaders' rpcAddrs
*/
@computed('regions.[]')
get leaders() {
return Promise.all(
this.regions.map((region) => {
return this.token
.authorizedRequest(`/${namespace}/status/leader?region=${region}`)
.then((res) => res.json());
})
);
}

@computed
Expand Down
3 changes: 2 additions & 1 deletion ui/app/styles/core/table.scss
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,8 @@
white-space: nowrap;
}

&.node-status-badges {
&.node-status-badges,
&.server-status-badges {
.hds-badge__text {
white-space: nowrap;
}
Expand Down
26 changes: 17 additions & 9 deletions ui/app/templates/components/server-agent-row.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
~}}

<td data-test-server-name
{{keyboard-shortcut
{{keyboard-shortcut
enumerated=true
action=(action this.goToAgent)
}}
Expand All @@ -16,14 +16,22 @@
@size="large"
/>
</span></td>
<td data-test-server-is-leader>

<Hds::Badge
@text={{if this.agent.isLeader "True" "False"}}
@icon={{if this.agent.isLeader "check-circle" ""}}
@color={{if this.agent.isLeader "success" "neutral"}}
@size="large"
/>
<td data-test-server-is-leader class="server-status-badges">
<Hds::Badge
@text={{if
this.agent.isLeader
(if
this.agent.system.shouldShowRegions
(concat "True" " (" this.agent.region ")")
"True"
)
"False"
}}
@icon={{if this.agent.isLeader "check-circle" ""}}
@color={{if this.agent.isLeader "success" "neutral"}}
@size="large"
class="no-wrap"
/>
</td>
<td data-test-server-address class="is-200px is-truncatable">{{this.agent.address}}</td>
<td data-test-server-port>{{this.agent.serfPort}}</td>
Expand Down
15 changes: 11 additions & 4 deletions ui/mirage/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,14 @@ import { copy } from 'ember-copy';
import formatHost from 'nomad-ui/utils/format-host';
import faker from 'nomad-ui/mirage/faker';

export function findLeader(schema) {
const agent = schema.agents.first();
export function findLeader(schema, region = null) {
let agent;
let agents = schema.agents.all().models;
if (region) {
agent = agents.find((agent) => agent.member?.Tags?.region === region);
} else {
agent = agents[0];
}
return formatHost(agent.member.Address, agent.member.Tags.port);
}

Expand Down Expand Up @@ -741,8 +747,9 @@ export default function () {
return logEncode(logFrames, logFrames.length - 1);
});

this.get('/status/leader', function (schema) {
return JSON.stringify(findLeader(schema));
this.get('/status/leader', function (schema, { queryParams: { region } }) {
let leader = JSON.stringify(findLeader(schema, region));
return leader;
});

this.get('/acl/tokens', function ({ tokens }, req) {
Expand Down
1 change: 1 addition & 0 deletions ui/mirage/factories/agent.js
Original file line number Diff line number Diff line change
Expand Up @@ -90,5 +90,6 @@ function generateTags(serfPort) {
rpcPortCandidate === serfPort ? rpcPortCandidate + 1 : rpcPortCandidate,
dc: faker.helpers.randomize(DATACENTERS),
build: faker.helpers.randomize(AGENT_BUILDS),
region: 'global',
};
}
3 changes: 3 additions & 0 deletions ui/mirage/scenarios/default.js
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,9 @@ function smallCluster(server) {
server.create('feature', { name: 'Dynamic Application Sizing' });
server.create('feature', { name: 'Sentinel Policies' });
server.createList('agent', 3, 'withConsulLink', 'withVaultLink');
if (withRegions) {
server.db.agents[0].member.Tags.region = server.db.regions[0].id;
}
server.createList('node-pool', 2);
server.createList('node', 5);
server.create(
Expand Down
32 changes: 31 additions & 1 deletion ui/tests/acceptance/servers-list-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ module('Acceptance | servers list', function (hooks) {
setupApplicationTest(hooks);
setupMirage(hooks);

hooks.beforeEach(function () {
server.create('region', { id: 'global' });
});

test('it passes an accessibility audit', async function (assert) {
minimumSetup();
await ServersList.visit();
Expand All @@ -51,7 +55,6 @@ module('Acceptance | servers list', function (hooks) {
const sortedAgents = server.db.agents.sort(agentSort(leader)).reverse();

await ServersList.visit();

await percySnapshot(assert);

assert.equal(
Expand Down Expand Up @@ -116,4 +119,31 @@ module('Acceptance | servers list', function (hooks) {
await ServersList.error.seekHelp();
assert.equal(currentURL(), '/settings/tokens');
});

test('multiple regions should each show leadership values', async function (assert) {
server.createList('node-pool', 1);
server.createList('node', 1);
server.create('region', { id: 'global' });
server.create('region', { id: 'galactic' });
server.createList('agent', 3);
server.db.agents[0].member.Tags.region = 'global';
server.db.agents[1].member.Tags.region = 'galactic';
server.db.agents[2].member.Tags.region = 'galactic';
await ServersList.visit();
assert.equal(
ServersList.servers.objectAt(0).leader,
'True (galactic)',
'Leadership is shown for the galactic region'
);
assert.equal(
ServersList.servers.objectAt(1).leader,
'True (global)',
'Leadership is shown for the global region'
);
assert.equal(
ServersList.servers.objectAt(2).leader,
'False',
'Non-leader servers are shown'
);
});
});

0 comments on commit 834875d

Please sign in to comment.