ui: Adds basic support for the Routing tab viz with partitions (#11679)

This commit is contained in:
John Cowen 2021-12-06 10:22:09 +00:00 committed by GitHub
parent ca7e087e57
commit 7775773979
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 107 additions and 55 deletions

3
.changelog/11679.txt Normal file
View File

@ -0,0 +1,3 @@
```release-note:feature
ui: Adds support for partitions to the Routing visualization.
```

View File

@ -0,0 +1,18 @@
---
type: ember
state: needs-love
---
# Consul::DiscoveryChain
Mainly presentational component to visualize a discovery-chain.
```hbs preview-template
<DataSource @src={{uri '/partition/default/dc-1/discovery-chain/service-name'}} as |source|>
{{#if source.data}}
<Consul::DiscoveryChain
@chain={{source.data.Chain}}
/>
{{/if}}
</DataSource>
```

View File

@ -44,8 +44,8 @@ export default Component.extend({
!routes.find(item => typeof item.Definition === 'undefined')
) {
let nextNode;
const resolverID = `resolver:${this.chain.ServiceName}.${this.chain.Namespace}.${this.chain.Datacenter}`;
const splitterID = `splitter:${this.chain.ServiceName}.${this.chain.Namespace}`;
const resolverID = `resolver:${this.chain.ServiceName}.${this.chain.Namespace}.${this.chain.Partition}.${this.chain.Datacenter}`;
const splitterID = `splitter:${this.chain.ServiceName}.${this.chain.Namespace}.${this.chain.Partition}`;
// The default router should look for a splitter first,
// if there isn't one try the default resolver
if (typeof this.chain.Nodes[splitterID] !== 'undefined') {
@ -106,6 +106,7 @@ export default Component.extend({
resolvers: computed('chain.{Nodes,Targets}', function() {
return getResolvers(
this.chain.Datacenter,
this.chain.Partition,
this.chain.Namespace,
get(this, 'chain.Targets'),
get(this, 'chain.Nodes')

View File

@ -1,10 +1,10 @@
const getNodesByType = function(nodes = {}, type) {
return Object.values(nodes).filter(item => item.Type === type);
};
const findResolver = function(resolvers, service, nspace = 'default', dc) {
const findResolver = function(resolvers, service, nspace = 'default', partition = 'default', dc) {
if (typeof resolvers[service] === 'undefined') {
resolvers[service] = {
ID: `${service}.${nspace}.${dc}`,
ID: `${service}.${nspace}.${partition}.${dc}`,
Name: service,
Children: [],
};
@ -19,7 +19,7 @@ export const getAlternateServices = function(targets, a) {
// we might have more data from the endpoint so we don't have to guess
// right now the backend also doesn't support dots in service names
const [aRev, bRev] = [a, b].map(item => item.split('.').reverse());
const types = ['Datacenter', 'Namespace', 'Service', 'Subset'];
const types = ['Datacenter', 'Partition', 'Namespace', 'Service', 'Subset'];
return bRev.find(function(item, i) {
const res = item !== aRev[i];
if (res) {
@ -61,7 +61,13 @@ export const getRoutes = function(nodes, uid) {
);
}, []);
};
export const getResolvers = function(dc, nspace = 'default', targets = {}, nodes = {}) {
export const getResolvers = function(
dc,
partition = 'default',
nspace = 'default',
targets = {},
nodes = {}
) {
const resolvers = {};
// make all our resolver nodes
Object.values(nodes)
@ -70,7 +76,7 @@ export const getResolvers = function(dc, nspace = 'default', targets = {}, nodes
const parts = item.Name.split('.');
let subset;
// this will leave behind the service.name.nspace.dc even if the service name contains a dot
if (parts.length > 3) {
if (parts.length > 4) {
subset = parts.shift();
}
parts.reverse();
@ -79,10 +85,12 @@ export const getResolvers = function(dc, nspace = 'default', targets = {}, nodes
parts.shift();
// const nodeNspace =
parts.shift();
// const nodePartition =
parts.shift();
// if it does contain a dot put it back to the correct order
parts.reverse();
const service = parts.join('.');
const resolver = findResolver(resolvers, service, nspace, dc);
const resolver = findResolver(resolvers, service, nspace, partition, dc);
let failovers;
if (typeof item.Resolver.Failover !== 'undefined') {
// figure out what type of failover this is
@ -108,12 +116,12 @@ export const getResolvers = function(dc, nspace = 'default', targets = {}, nodes
// Failovers don't have a specific node
if (typeof nodes[`resolver:${target.ID}`] !== 'undefined') {
// We use this to figure out whether this target is a redirect target
const alternate = getAlternateServices([target.ID], `service.${nspace}.${dc}`);
const alternate = getAlternateServices([target.ID], `service.${nspace}.${partition}.${dc}`);
// as Failovers don't make it here, we know anything that has alternateServices
// must be a redirect
if (alternate.Type !== 'Service') {
// find the already created resolver
const resolver = findResolver(resolvers, target.Service, nspace, dc);
const resolver = findResolver(resolvers, target.Service, nspace, partition, dc);
// and add the redirect as a child, redirects are always children
const child = {
Redirect: true,

View File

@ -2,7 +2,9 @@ ${
[1].map(() => {
const namespaces = ['default'];
const partitions = ['default'];
const ns = location.search.ns || 'default';
const partition = location.search.partition || 'default';
const dc = location.search.dc;
const service = location.pathname.get(2);
@ -75,7 +77,7 @@ ${
const service = fake.hacker.noun().split(' ').join('-');
return {
ServiceName: service,
Name: `${service}.${ns}.${dc}`,
Name: `${service}.${ns}.${partition}.${dc}`,
Subsets: range(
env(
'CONSUL_SUBSET_COUNT',
@ -96,7 +98,7 @@ ${
const service = resolvers[i].ServiceName;
return {
ServiceName: service,
Name: `${service}.${ns}.redirect-${dc}`,
Name: `${service}.${ns}.${partition}.redirect-${dc}`,
Subsets: []
};
});
@ -129,7 +131,7 @@ ${
const splitters = range(
splitterCount
).map(() => ({
Name: `${service}-${fake.hacker.noun()}.${ns}`,
Name: `${service}-${fake.hacker.noun()}.${ns}.${partition}`,
Splits: range(
splitCount
).map((item, i, arr) => ({
@ -151,6 +153,7 @@ ${
"Chain": {
"ServiceName": "${service}",
"Namespace": "${ns}",
"Partition": "${partition}",
"Datacenter": "${dc}",
"Protocol": "http",
"StartNode": "router:${service}",
@ -247,7 +250,8 @@ ${resolvers.map((resolver) => {
);
const failover = ({
Datacenter: `${resolver.Name.replace(`.${dc}`, `.fail-${dc}`).replace(`.redirect-${dc}`, `.fail-${dc}`)}`,
Namespace: `${resolver.Name.replace(`.${ns}.`, `.fail-${ns}.`).replace(`.redirect-${ns}.`, `.fail-${ns}.`)}`,
Partition: `${resolver.Name.replace(`${ns}.${partition}.`, `${ns}.fail-${partition}.`).replace(`${ns}.redirect-${partition}.`, `${ns}.fail-${partition}.`)}`,
Namespace: `${resolver.Name.replace(`.${ns}.${partition}`, `.fail-${ns}.${partition}`).replace(`.redirect-${ns}.${partition}`, `.fail-${ns}.${partition}`)}`,
})[env('CONSUL_FAILOVER_TYPE', 'Datacenter')];
return `
@ -272,7 +276,8 @@ ${resolver.Subsets.map((subset) => {
const id = `${subset}.${resolver.Name}`;
const failover = ({
Datacenter: `${subset}.${resolver.Name.replace(`.${dc}`, `.fail-${dc}`)}`,
Namespace: `${subset}.${resolver.Name.replace(`.${ns}.`, `.fail-${ns}.`)}`,
Partition: `${subset}.${resolver.Name.replace(`${ns}.${partition}.`, `${ns}.fail-${partition}.`)}`,
Namespace: `${subset}.${resolver.Name.replace(`.${ns}.${partition}`, `.fail-${ns}.${partition}`)}`,
})[env('CONSUL_FAILOVER_TYPE', 'Datacenter')];
return `
@ -321,6 +326,7 @@ ${resolvers.map(item => {
"ID": "${item.Name}",
"Service": "${item.ServiceName}",
"Namespace": "${ns}",
"Partition": "${partition}",
"Datacenter": "${dc}",
"MeshGateway": {},
"SNI": "${name}",
@ -335,6 +341,7 @@ ${item.Subsets.map(ktem => {
"Service": "${item.ServiceName}",
"ServiceSubset": "${ktem}",
"Namespace": "${ns}",
"Partition": "${partition}",
"Datacenter": "${dc}",
"MeshGateway": {
},

View File

@ -45,6 +45,9 @@ ${[0].map(
"Name":"${name}",
${typeof location.search.ns !== 'undefined' ? `
"Namespace": "${location.search.ns}",
` : ``}
${typeof location.search.partition !== 'undefined' ? `
"Partition": "${location.search.ns}",
` : ``}
"Tags": [
${

View File

@ -8,8 +8,8 @@ module('Unit | Component | consul/discovery-chain/get-alternative-services', fun
Targets: ['different-ns', 'different-ns2'],
};
const actual = getAlternateServices(
['service.different-ns.dc', 'service.different-ns2.dc'],
'service.namespace.dc'
['service.different-ns.partition.dc', 'service.different-ns2.partition.dc'],
'service.namespace.partition.dc'
);
assert.equal(actual.Type, expected.Type);
assert.deepEqual(actual.Targets, expected.Targets);
@ -20,8 +20,8 @@ module('Unit | Component | consul/discovery-chain/get-alternative-services', fun
Targets: ['dc1', 'dc2'],
};
const actual = getAlternateServices(
['service.namespace.dc1', 'service.namespace.dc2'],
'service.namespace.dc'
['service.namespace.partition.dc1', 'service.namespace.partition.dc2'],
'service.namespace.partition.dc'
);
assert.equal(actual.Type, expected.Type);
assert.deepEqual(actual.Targets, expected.Targets);
@ -32,8 +32,8 @@ module('Unit | Component | consul/discovery-chain/get-alternative-services', fun
Targets: ['service-2', 'service-3'],
};
const actual = getAlternateServices(
['service-2.namespace.dc', 'service-3.namespace.dc'],
'service.namespace.dc'
['service-2.namespace.partition.dc', 'service-3.namespace.partition.dc'],
'service.namespace.partition.dc'
);
assert.equal(actual.Type, expected.Type);
assert.deepEqual(actual.Targets, expected.Targets);
@ -44,8 +44,8 @@ module('Unit | Component | consul/discovery-chain/get-alternative-services', fun
Targets: ['v3', 'v2'],
};
const actual = getAlternateServices(
['v3.service.namespace.dc', 'v2.service.namespace.dc'],
'v1.service.namespace.dc'
['v3.service.namespace.partition.dc', 'v2.service.namespace.partition.dc'],
'v1.service.namespace.partition.dc'
);
assert.equal(actual.Type, expected.Type);
assert.deepEqual(actual.Targets, expected.Targets);

View File

@ -4,6 +4,7 @@ import { get } from 'consul-ui/tests/helpers/api';
const dc = 'dc-1';
const nspace = 'default';
const partition = 'default';
const request = {
url: `/v1/discovery-chain/service-name?dc=${dc}`,
};
@ -19,7 +20,7 @@ module('Unit | Component | consul/discovery-chain/get-resolvers', function() {
},
},
}).then(function({ Chain }) {
const actual = getResolvers(dc, nspace, Chain.Targets, Chain.Nodes);
const actual = getResolvers(dc, partition, nspace, Chain.Targets, Chain.Nodes);
const childId = Object.keys(Chain.Targets)[1];
const target = Chain.Targets[`${childId}`];
const firstChild = actual[0].Children[0];
@ -39,7 +40,7 @@ module('Unit | Component | consul/discovery-chain/get-resolvers', function() {
},
},
}).then(function({ Chain }) {
const actual = getResolvers(dc, nspace, Chain.Targets, Chain.Nodes);
const actual = getResolvers(dc, partition, nspace, Chain.Targets, Chain.Nodes);
const childId = Object.keys(Chain.Targets)[1];
const target = Chain.Targets[`${childId}`];
const firstChild = actual[0].Children[0];
@ -61,7 +62,7 @@ module('Unit | Component | consul/discovery-chain/get-resolvers', function() {
},
},
}).then(function({ Chain }) {
const actual = getResolvers(dc, nspace, Chain.Targets, Chain.Nodes);
const actual = getResolvers(dc, partition, nspace, Chain.Targets, Chain.Nodes);
const actualSubset = actual[0].Children[0];
assert.equal(actualSubset.Subset, true);
assert.equal(actualSubset.Failover.Type, failoverType);
@ -71,7 +72,7 @@ module('Unit | Component | consul/discovery-chain/get-resolvers', function() {
});
test('it assigns Failovers correctly', function(assert) {
return Promise.all(
['Datacenter', 'Namespace'].map(function(failoverType, i) {
['Datacenter', 'Partition', 'Namespace'].map(function(failoverType, i) {
return get(request.url, {
headers: {
cookie: {
@ -83,7 +84,7 @@ module('Unit | Component | consul/discovery-chain/get-resolvers', function() {
},
},
}).then(function({ Chain }) {
const actual = getResolvers(dc, nspace, Chain.Targets, Chain.Nodes);
const actual = getResolvers(dc, partition, nspace, Chain.Targets, Chain.Nodes);
const node = Chain.Nodes[`resolver:${Object.keys(Chain.Targets)[0]}`];
const expected = node.Resolver.Failover.Targets.map(item => item.split('.').reverse()[i]);
assert.equal(actual[0].Failover.Type, failoverType);
@ -101,31 +102,36 @@ module('Unit | Component | consul/discovery-chain/get-resolvers', function() {
Protocol: 'http',
StartNode: '',
Nodes: {
'resolver:v2.dc-failover.default.dc-1': {
'resolver:v2.dc-failover.default.default.dc-1': {
Type: 'resolver',
Name: 'v2.dc-failover.default.dc-1',
Name: 'v2.dc-failover.default.default.dc-1',
Resolver: {
Target: 'v2.dc-failover.default.dc-1',
Target: 'v2.dc-failover.default.default.dc-1',
Failover: {
Targets: ['v2.dc-failover.default.dc-5', 'v2.dc-failover.default.dc-6'],
Targets: [
'v2.dc-failover.default.default.dc-5',
'v2.dc-failover.default.default.dc-6',
],
},
},
},
},
Targets: {
'v2.dc-failover.default.dc-1': {
ID: 'v2.dc-failover.default.dc-1',
'v2.dc-failover.default.default.dc-1': {
ID: 'v2.dc-failover.default.default.dc-1',
Service: 'dc-failover',
Namespace: 'default',
Partition: 'default',
Datacenter: 'dc-1',
Subset: {
Filter: '',
},
},
'v2.dc-failover.default.dc-6': {
ID: 'v2.dc-failover.default.dc-6',
'v2.dc-failover.default.default.dc-6': {
ID: 'v2.dc-failover.default.default.dc-6',
Service: 'dc-failover',
Namespace: 'default',
Partition: 'default',
Datacenter: 'dc-6',
Subset: {
Filter: '',
@ -134,14 +140,14 @@ module('Unit | Component | consul/discovery-chain/get-resolvers', function() {
},
},
}).then(function({ Chain }) {
const actual = getResolvers(dc, nspace, Chain.Targets, Chain.Nodes);
const actual = getResolvers(dc, partition, nspace, Chain.Targets, Chain.Nodes);
const expected = {
ID: 'dc-failover.default.dc-1',
ID: 'dc-failover.default.default.dc-1',
Name: 'dc-failover',
Children: [
{
Subset: true,
ID: 'v2.dc-failover.default.dc-1',
ID: 'v2.dc-failover.default.default.dc-1',
Name: 'v2',
Failover: {
Type: 'Datacenter',
@ -162,30 +168,31 @@ module('Unit | Component | consul/discovery-chain/get-resolvers', function() {
Protocol: 'http',
StartNode: '',
Nodes: {
'resolver:dc-failover.default.dc-1': {
'resolver:dc-failover.default.default.dc-1': {
Type: 'resolver',
Name: 'dc-failover.default.dc-1',
Name: 'dc-failover.default.default.dc-1',
Resolver: {
Target: 'dc-failover.default.dc-1',
Target: 'dc-failover.default.default.dc-1',
Failover: {
Targets: ['dc-failover.default.dc-5', 'dc-failover.default.dc-6'],
Targets: ['dc-failover.default.default.dc-5', 'dc-failover.default.default.dc-6'],
},
},
},
},
Targets: {
'dc-failover.default.dc-1': {
ID: 'dc-failover.default.dc-1',
'dc-failover.default.default.dc-1': {
ID: 'dc-failover.default.default.dc-1',
Service: 'dc-failover',
Namespace: 'default',
Partition: 'default',
Datacenter: 'dc-1',
},
},
},
}).then(function({ Chain }) {
const actual = getResolvers(dc, nspace, Chain.Targets, Chain.Nodes);
const actual = getResolvers(dc, partition, nspace, Chain.Targets, Chain.Nodes);
const expected = {
ID: 'dc-failover.default.dc-1',
ID: 'dc-failover.default.default.dc-1',
Name: 'dc-failover',
Children: [],
Failover: {
@ -201,37 +208,42 @@ module('Unit | Component | consul/discovery-chain/get-resolvers', function() {
Chain: {
ServiceName: 'service-name',
Namespace: 'default',
Partition: 'default',
Datacenter: 'dc-1',
Protocol: 'http',
StartNode: '',
Nodes: {
'resolver:dc-failover.default.redirect-dc-1': {
'resolver:dc-failover.default.default.redirect-dc-1': {
Type: 'resolver',
Name: 'dc-failover.default.redirect-dc-1',
Name: 'dc-failover.default.default.redirect-dc-1',
Resolver: {
Target: 'dc-failover.default.redirect-dc-1',
Target: 'dc-failover.default.default.redirect-dc-1',
Failover: {
Targets: ['dc-failover.default.redirect-dc-5', 'dc-failover.default.redirect-dc-6'],
Targets: [
'dc-failover.default.default.redirect-dc-5',
'dc-failover.default.default.redirect-dc-6',
],
},
},
},
},
Targets: {
'dc-failover.default.redirect-dc-1': {
ID: 'dc-failover.default.redirect-dc-1',
ID: 'dc-failover.default.default.redirect-dc-1',
Service: 'dc-failover',
Namespace: 'default',
Partition: 'default',
Datacenter: 'redirect-dc-1',
},
},
},
}).then(function({ Chain }) {
const actual = getResolvers(dc, nspace, Chain.Targets, Chain.Nodes);
const actual = getResolvers(dc, partition, nspace, Chain.Targets, Chain.Nodes);
// Both the parent and the child should have a Failover property
// as in order for a redirect to have failovers it must redirect to a
// service that already has failovers
const expected = {
ID: 'dc-failover.default.dc-1',
ID: 'dc-failover.default.default.dc-1',
Name: 'dc-failover',
Failover: {
Targets: ['redirect-dc-5', 'redirect-dc-6'],
@ -243,7 +255,7 @@ module('Unit | Component | consul/discovery-chain/get-resolvers', function() {
Targets: ['redirect-dc-5', 'redirect-dc-6'],
Type: 'Datacenter',
},
ID: 'dc-failover.default.redirect-dc-1',
ID: 'dc-failover.default.default.redirect-dc-1',
Name: 'redirect-dc-1',
Redirect: true,
},