From 7b42bb0e2def7ce17f2b1cf56b38e80e5120c7af Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Thu, 13 May 2021 12:29:51 -0500 Subject: [PATCH] ui: Fix server list leader determination for IPv6 (#10530) This closes #10513, thanks to @bastelfreak for the report. GET /status/leader returns an IPv6 host with square brackets around the IP address as expected, but the rpcAddr property on the agent model does not. This fixes rpcAddr, updates the Mirage /status/leader mock to properly format an IPv6 host, and changes the agent factory to sometimes produce IPv6 addresses. I added a formatHost utility function to centralise the conditional square bracket-wrapping that would have otherwise been further scattered around. --- ui/app/models/agent.js | 3 ++- ui/app/utils/format-host.js | 13 +++++++++++++ ui/mirage/config.js | 3 ++- ui/mirage/factories/agent.js | 2 +- ui/tests/acceptance/allocation-detail-test.js | 7 ++----- ui/tests/acceptance/server-detail-test.js | 3 ++- ui/tests/acceptance/servers-list-test.js | 5 +++-- 7 files changed, 25 insertions(+), 11 deletions(-) create mode 100644 ui/app/utils/format-host.js diff --git a/ui/app/models/agent.js b/ui/app/models/agent.js index bc0be0971..be70e5467 100644 --- a/ui/app/models/agent.js +++ b/ui/app/models/agent.js @@ -3,6 +3,7 @@ import { computed } from '@ember/object'; import Model from '@ember-data/model'; import { attr } from '@ember-data/model'; import classic from 'ember-classic-decorator'; +import formatHost from 'nomad-ui/utils/format-host'; @classic export default class Agent extends Model { @@ -20,7 +21,7 @@ export default class Agent extends Model { @computed('address', 'port') get rpcAddr() { const { address, rpcPort } = this; - return address && rpcPort && `${address}:${rpcPort}`; + return formatHost(address, rpcPort); } @computed('rpcAddr', 'system.leader.rpcAddr') diff --git a/ui/app/utils/format-host.js b/ui/app/utils/format-host.js new file mode 100644 index 000000000..65916e26b --- /dev/null +++ b/ui/app/utils/format-host.js @@ -0,0 +1,13 @@ +import isIp from 'is-ip'; + +export default function formatHost(address, port) { + if (!address || !port) { + return undefined; + } + + if (isIp.v6(address)) { + return `[${address}]:${port}`; + } else { + return `${address}:${port}`; + } +} diff --git a/ui/mirage/config.js b/ui/mirage/config.js index 4013eeb3f..267d5ac50 100644 --- a/ui/mirage/config.js +++ b/ui/mirage/config.js @@ -5,10 +5,11 @@ import { logFrames, logEncode } from './data/logs'; import { generateDiff } from './factories/job-version'; import { generateTaskGroupFailures } from './factories/evaluation'; import { copy } from 'ember-copy'; +import formatHost from 'nomad-ui/utils/format-host'; export function findLeader(schema) { const agent = schema.agents.first(); - return `${agent.address}:${agent.tags.port}`; + return formatHost(agent.address, agent.tags.port); } export function filesForPath(allocFiles, filterPath) { diff --git a/ui/mirage/factories/agent.js b/ui/mirage/factories/agent.js index c57a12681..26fcc5b00 100644 --- a/ui/mirage/factories/agent.js +++ b/ui/mirage/factories/agent.js @@ -8,7 +8,7 @@ const AGENT_STATUSES = ['alive', 'leaving', 'left', 'failed']; export default Factory.extend({ id: i => (i / 100 >= 1 ? `${UUIDS[i]}-${i}` : UUIDS[i]), - name: () => `nomad@${faker.internet.ip()}`, + name: () => `nomad@${faker.random.boolean() ? faker.internet.ip() : faker.internet.ipv6()}`, status: () => faker.helpers.randomize(AGENT_STATUSES), serfPort: () => faker.random.number({ min: 4000, max: 4999 }), diff --git a/ui/tests/acceptance/allocation-detail-test.js b/ui/tests/acceptance/allocation-detail-test.js index 0fa549395..f3b5c0ed2 100644 --- a/ui/tests/acceptance/allocation-detail-test.js +++ b/ui/tests/acceptance/allocation-detail-test.js @@ -7,7 +7,7 @@ import { setupMirage } from 'ember-cli-mirage/test-support'; import a11yAudit from 'nomad-ui/tests/helpers/a11y-audit'; import Allocation from 'nomad-ui/tests/pages/allocations/detail'; import moment from 'moment'; -import isIp from 'is-ip'; +import formatHost from 'nomad-ui/utils/format-host'; let job; let node; @@ -223,10 +223,7 @@ module('Acceptance | allocation detail', function(hooks) { assert.equal(renderedPort.name, serverPort.Label); assert.equal(renderedPort.to, serverPort.To); - const expectedAddr = isIp.v6(serverPort.HostIP) - ? `[${serverPort.HostIP}]:${serverPort.Value}` - : `${serverPort.HostIP}:${serverPort.Value}`; - assert.equal(renderedPort.address, expectedAddr); + assert.equal(renderedPort.address, formatHost(serverPort.HostIP, serverPort.Value)); }); }); diff --git a/ui/tests/acceptance/server-detail-test.js b/ui/tests/acceptance/server-detail-test.js index 0715104c9..177b1bff4 100644 --- a/ui/tests/acceptance/server-detail-test.js +++ b/ui/tests/acceptance/server-detail-test.js @@ -4,6 +4,7 @@ import { setupApplicationTest } from 'ember-qunit'; import { setupMirage } from 'ember-cli-mirage/test-support'; import a11yAudit from 'nomad-ui/tests/helpers/a11y-audit'; import ServerDetail from 'nomad-ui/tests/pages/servers/detail'; +import formatHost from 'nomad-ui/utils/format-host'; let agent; @@ -33,7 +34,7 @@ module('Acceptance | server detail', function(hooks) { test('the details ribbon displays basic information about the server', async function(assert) { assert.ok(ServerDetail.serverStatus.includes(agent.status)); - assert.ok(ServerDetail.address.includes(`${agent.address}:${agent.tags.port}`)); + assert.ok(ServerDetail.address.includes(formatHost(agent.address, agent.tags.port))); assert.ok(ServerDetail.datacenter.includes(agent.tags.dc)); }); diff --git a/ui/tests/acceptance/servers-list-test.js b/ui/tests/acceptance/servers-list-test.js index e4ac8986c..1faded1e4 100644 --- a/ui/tests/acceptance/servers-list-test.js +++ b/ui/tests/acceptance/servers-list-test.js @@ -5,6 +5,7 @@ import { setupMirage } from 'ember-cli-mirage/test-support'; import a11yAudit from 'nomad-ui/tests/helpers/a11y-audit'; import { findLeader } from '../../mirage/config'; import ServersList from 'nomad-ui/tests/pages/servers/list'; +import formatHost from 'nomad-ui/utils/format-host'; const minimumSetup = () => { server.createList('node', 1); @@ -12,9 +13,9 @@ const minimumSetup = () => { }; const agentSort = leader => (a, b) => { - if (`${a.address}:${a.tags.port}` === leader) { + if (formatHost(a.address, a.tags.port) === leader) { return 1; - } else if (`${b.address}:${b.tags.port}` === leader) { + } else if (formatHost(b.address, b.tags.port) === leader) { return -1; } return 0;