mirror of
https://github.com/kemko/nomad.git
synced 2026-01-01 16:05:42 +03:00
[ui] Show ALL regions' leaders when viewing servers route (#24723)
* Looks up all regions' leaders when viewing servers route * Tests for multi-region leadership badges and css same-line fix
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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({
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -110,7 +110,8 @@
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
&.node-status-badges {
|
||||
&.node-status-badges,
|
||||
&.server-status-badges {
|
||||
.hds-badge__text {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
~}}
|
||||
|
||||
<td data-test-server-name
|
||||
{{keyboard-shortcut
|
||||
{{keyboard-shortcut
|
||||
enumerated=true
|
||||
action=(action this.goToAgent)
|
||||
}}
|
||||
@@ -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>
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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',
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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();
|
||||
@@ -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(
|
||||
@@ -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'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user