ui: Adds basic support for the Routing tab viz with partitions (#11679)
This commit is contained in:
parent
ca7e087e57
commit
7775773979
|
@ -0,0 +1,3 @@
|
|||
```release-note:feature
|
||||
ui: Adds support for partitions to the Routing visualization.
|
||||
```
|
|
@ -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>
|
||||
```
|
||||
|
|
@ -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')
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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": {
|
||||
},
|
||||
|
|
|
@ -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": [
|
||||
${
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
},
|
||||
|
|
Loading…
Reference in New Issue