Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions web/src/components/netflow-traffic.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { Filters, getDisabledFiltersRecord, getEnabledFilters } from '../model/f
import { filtersToString, FlowQuery, MetricType } from '../model/flow-query';
import { netflowTrafficModel } from '../model/netflow-traffic';
import { parseQuickFilters } from '../model/quick-filters';
import { resolveGroupTypes } from '../model/scope';
import { getFetchFunctions as getBackAndForthFetch } from '../utils/back-and-forth';
import { ColumnsId, getDefaultColumns } from '../utils/columns';
import { loadConfig } from '../utils/config';
Expand Down Expand Up @@ -289,7 +290,9 @@ export const NetflowTraffic: React.FC<NetflowTrafficProps> = ({
query.aggregateBy = model.metricScope;
if (model.selectedViewId === 'topology') {
query.type = model.topologyMetricType;
query.groups = model.topologyOptions.groupTypes !== 'none' ? model.topologyOptions.groupTypes : undefined;
const scopes = getAvailableScopes();
const resolvedGroup = resolveGroupTypes(model.topologyOptions.groupTypes, model.metricScope, scopes);
query.groups = resolvedGroup !== 'none' ? resolvedGroup : undefined;
} else if (model.selectedViewId === 'overview') {
query.limit = topValues.includes(model.limit) ? model.limit : topValues[0];
query.groups = undefined;
Expand All @@ -309,7 +312,8 @@ export const NetflowTraffic: React.FC<NetflowTrafficProps> = ({
model.selectedViewId,
model.topologyMetricType,
model.metricScope,
model.topologyOptions.groupTypes
model.topologyOptions.groupTypes,
getAvailableScopes
]);

const getFetchFunctions = React.useCallback(() => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ export const TopologyContent: React.FC<TopologyContentProps> = ({

const onStepInto = React.useCallback(
(data: Decorated<ElementData>) => {
const groupTypes: TopologyGroupTypes = metricScope;
const groupTypes: TopologyGroupTypes = options.groupTypes === 'auto' ? 'auto' : metricScope;
const scope = getStepInto(
metricScope,
scopes.map(sc => sc.id)
Expand Down
24 changes: 21 additions & 3 deletions web/src/model/__tests__/topology.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { ScopeDefSample } from '../../components/__tests-data__/scopes';
import { ContextSingleton } from '../../utils/context';
import { getGroupName, getGroupsForScope, getStepInto } from '../scope';
import { getGroupName, getGroupsForScope, getStepInto, resolveGroupTypes } from '../scope';

describe('Check enabled groups', () => {
beforeEach(() => {
Expand All @@ -9,14 +9,15 @@ describe('Check enabled groups', () => {

it('should get group from scope', () => {
let groups = getGroupsForScope('cluster', ScopeDefSample);
expect(groups).toEqual(['none']);
expect(groups).toEqual(['none', 'auto']);

groups = getGroupsForScope('host', ScopeDefSample);
expect(groups).toEqual(['none', 'clusters', 'zones', 'clusters+zones']);
expect(groups).toEqual(['none', 'auto', 'clusters', 'zones', 'clusters+zones']);

groups = getGroupsForScope('owner', ScopeDefSample);
expect(groups).toEqual([
'none',
'auto',
'clusters',
'clusters+zones',
'clusters+hosts',
Expand All @@ -30,6 +31,23 @@ describe('Check enabled groups', () => {
]);
});

it('should resolve auto group', () => {
let group = resolveGroupTypes('auto', 'resource', ScopeDefSample);
expect(group).toEqual('namespaces');

group = resolveGroupTypes('auto', 'owner', ScopeDefSample);
expect(group).toEqual('namespaces');

group = resolveGroupTypes('auto', 'namespace', ScopeDefSample);
expect(group).toEqual('none');

group = resolveGroupTypes('auto', 'host', ScopeDefSample);
expect(group).toEqual('none');

group = resolveGroupTypes('hosts', 'resource', ScopeDefSample);
expect(group).toEqual('hosts');
});

it('should get group name', () => {
let name = getGroupName('hosts', ScopeDefSample, (s: string) => s);
expect(name).toEqual('Node');
Expand Down
2 changes: 1 addition & 1 deletion web/src/model/netflow-traffic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ export function netflowTrafficModel() {
// Invalidate groups if necessary, when metrics scope changed
const groups = getGroupsForScope(scope, config.scopes);
if (!groups.includes(topologyOptions.groupTypes)) {
setTopologyOptions({ ...topologyOptions, groupTypes: 'none' });
setTopologyOptions({ ...topologyOptions, groupTypes: 'auto' });
}
},
[setMetricScope, config.scopes, topologyOptions, setTopologyOptions]
Expand Down
24 changes: 21 additions & 3 deletions web/src/model/scope.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,18 +22,36 @@ export const getScopeName = (sc: ScopeConfigDef | undefined, t: (k: string) => s
return sc.name || sc.id;
};

export const getGroupsForScope = (scopeId: FlowScope, scopes: ScopeConfigDef[]) => {
export const getGroupsForScope = (scopeId: FlowScope, scopes: ScopeConfigDef[]): TopologyGroupTypes[] => {
const scope = scopes.find(sc => sc.id === scopeId);
if (scope?.groups?.length) {
const availableParts = scopes.map(sc => `${sc.id}s`);
return ['none', ...scope.groups.filter(gp => gp.split('+').every(part => availableParts.includes(part)))];
return ['none', 'auto', ...scope.groups.filter(gp => gp.split('+').every(part => availableParts.includes(part)))];
}
return ['none'];
return ['none', 'auto'];
};

export const resolveGroupTypes = (
inGroupTypes: TopologyGroupTypes,
scopeId: FlowScope,
scopes: ScopeConfigDef[]
): TopologyGroupTypes => {
if (inGroupTypes === 'auto') {
const groups = getGroupsForScope(scopeId, scopes);
if (groups.includes('namespaces')) {
return 'namespaces';
}
// More logic can be added here for more default behaviours
return 'none';
}
return inGroupTypes;
};

export const getGroupName = (group: TopologyGroupTypes, scopes: ScopeConfigDef[], t: (k: string) => string) => {
if (group === 'none') {
return t('None');
} else if (group === 'auto') {
return t('Auto');
} else if (group.includes('+')) {
return group
.split('+')
Expand Down
9 changes: 5 additions & 4 deletions web/src/model/topology.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import { createPeer, getFormattedValue } from '../utils/metrics';
import { defaultMetricFunction, defaultMetricType } from '../utils/router';
import { FlowScope, Groups, MetricFunction, MetricType, NodeType, StatFunction } from './flow-query';
import { getStat } from './metrics';
import { getStepInto, isDirectionnal, ScopeConfigDef } from './scope';
import { getStepInto, isDirectionnal, resolveGroupTypes, ScopeConfigDef } from './scope';

export enum LayoutName {
threeD = '3d',
Expand All @@ -40,7 +40,7 @@ export enum LayoutName {
grid = 'Grid'
}

export type TopologyGroupTypes = 'none' | Groups;
export type TopologyGroupTypes = 'none' | 'auto' | Groups;

export interface TopologyOptions {
maxEdgeStat: number;
Expand All @@ -66,7 +66,7 @@ export const DefaultOptions: TopologyOptions = {
startCollapsed: false,
truncateLength: TruncateLength.M,
layout: LayoutName.colaNoForce,
groupTypes: 'none',
groupTypes: 'auto',
lowScale: 0.3,
medScale: 0.5,
metricFunction: defaultMetricFunction,
Expand Down Expand Up @@ -537,11 +537,12 @@ export const generateDataModel = (
const addPossibleGroups = (peer: TopologyMetricPeer): NodeModel | undefined => {
// groups are all possible scopes except last one
const parentScopes = ContextSingleton.getScopes().slice(0, -1);
const resolvedGroups = resolveGroupTypes(options.groupTypes, metricScope, scopes);

// build parent tree from biggest to smallest group
let parent: NodeModel | undefined = undefined;
parentScopes.forEach(sc => {
if (options.groupTypes.includes(`${sc.id}s`) && !_.isEmpty(peer[sc.id])) {
if (resolvedGroups.includes(`${sc.id}s`) && !_.isEmpty(peer[sc.id])) {
parent = addGroup(
{ [sc.id]: peer[sc.id], namespace: ['namespace', 'owner'].includes(sc.id) ? peer.namespace : undefined },
sc.id,
Expand Down