85ea64211f
* ui: Discovery-Chain: Cope with redirects that have failovers We found a few stranger configurations for discovery-chain, one of which was redirects that can then failover. We altered the parsing here to include 2 passes, one to organize the nodes into resolvers and children/subsets based on the nodes themselves, which includes adding the failovers to resolvers and subsets. We then do a second pass which can more reliably figure out whether a target is a redirect or a failover (target failovers don't have a corresponding node), this then adds the redirect children to the already exising resolver (from the first pass) and then checks if the redirect also has failovers and adds those if so. * ui: Check to see if we have a user configured default route or not ...if we don't add one so the visualization looks complete
135 lines
4.6 KiB
JavaScript
135 lines
4.6 KiB
JavaScript
const getNodesByType = function(nodes = {}, type) {
|
|
return Object.values(nodes).filter(item => item.Type === type);
|
|
};
|
|
const findResolver = function(resolvers, service, nspace = 'default', dc) {
|
|
if (typeof resolvers[service] === 'undefined') {
|
|
resolvers[service] = {
|
|
ID: `${service}.${nspace}.${dc}`,
|
|
Name: service,
|
|
Children: [],
|
|
};
|
|
}
|
|
return resolvers[service];
|
|
};
|
|
export const getAlternateServices = function(targets, a) {
|
|
let type;
|
|
const Targets = targets.map(function(b) {
|
|
// TODO: this isn't going to work past namespace for services
|
|
// with dots in the name, but by the time that becomes an issue
|
|
// 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'];
|
|
return bRev.find(function(item, i) {
|
|
const res = item !== aRev[i];
|
|
if (res) {
|
|
type = types[i];
|
|
}
|
|
return res;
|
|
});
|
|
});
|
|
return {
|
|
Type: type,
|
|
Targets: Targets,
|
|
};
|
|
};
|
|
|
|
export const getSplitters = function(nodes) {
|
|
return getNodesByType(nodes, 'splitter').map(function(item) {
|
|
// Splitters need IDs adding so we can find them in the DOM later
|
|
item.ID = `splitter:${item.Name}`;
|
|
return item;
|
|
});
|
|
};
|
|
export const getRoutes = function(nodes, uid) {
|
|
return getNodesByType(nodes, 'router').reduce(function(prev, item) {
|
|
return prev.concat(
|
|
item.Routes.map(function(route, i) {
|
|
// Routes also have IDs added via createRoute
|
|
return createRoute(route, item.Name, uid);
|
|
})
|
|
);
|
|
}, []);
|
|
};
|
|
export const getResolvers = function(dc, nspace = 'default', targets = {}, nodes = {}) {
|
|
const resolvers = {};
|
|
// make all our resolver nodes
|
|
Object.values(nodes)
|
|
.filter(item => item.Type === 'resolver')
|
|
.forEach(function(item) {
|
|
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) {
|
|
subset = parts.shift();
|
|
}
|
|
parts.reverse();
|
|
// slice off from dc.nspace onwards leaving the potentially dot containing service name
|
|
// const nodeDc =
|
|
parts.shift();
|
|
// const nodeNspace =
|
|
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);
|
|
let failovers;
|
|
if (typeof item.Resolver.Failover !== 'undefined') {
|
|
// figure out what type of failover this is
|
|
failovers = getAlternateServices(item.Resolver.Failover.Targets, item.Name);
|
|
}
|
|
if (subset) {
|
|
const child = {
|
|
Subset: true,
|
|
ID: item.Name,
|
|
Name: subset,
|
|
};
|
|
if (typeof failovers !== 'undefined') {
|
|
child.Failover = failovers;
|
|
}
|
|
resolver.Children.push(child);
|
|
} else {
|
|
if (typeof failovers !== 'undefined') {
|
|
resolver.Failover = failovers;
|
|
}
|
|
}
|
|
});
|
|
Object.values(targets).forEach(target => {
|
|
// 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}`);
|
|
// 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);
|
|
// and add the redirect as a child, redirects are always children
|
|
const child = {
|
|
Redirect: true,
|
|
ID: target.ID,
|
|
Name: target[alternate.Type],
|
|
};
|
|
// redirects can then also have failovers
|
|
// so it this one does, figure out what type they are and add them
|
|
// to the redirect
|
|
if (typeof nodes[`resolver:${target.ID}`].Resolver.Failover !== 'undefined') {
|
|
child.Failover = getAlternateServices(
|
|
nodes[`resolver:${target.ID}`].Resolver.Failover.Targets,
|
|
target.ID
|
|
);
|
|
}
|
|
resolver.Children.push(child);
|
|
}
|
|
}
|
|
});
|
|
return Object.values(resolvers);
|
|
};
|
|
export const createRoute = function(route, router, uid) {
|
|
return {
|
|
...route,
|
|
Default: typeof route.Definition.Match === 'undefined',
|
|
ID: `route:${router}-${uid(route.Definition)}`,
|
|
};
|
|
};
|