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
4 changes: 3 additions & 1 deletion web/locales/en/plugin__netobserv-plugin.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@
"View alert details": "View alert details",
"View health dashboard": "View health dashboard",
"Name": "Name",
"Subnet label": "Subnet label",
"IP": "IP",
"No information available for this content. Change scope to get more details.": "No information available for this content. Change scope to get more details.",
"No information available for this content. Decrease scope aggregation to get more details.": "No information available for this content. Decrease scope aggregation to get more details.",
"You may also configure subnet labels in the FlowCollector resource (spec.processor.subnetLabels) to identify IP ranges that are external to the cluster.": "You may also configure subnet labels in the FlowCollector resource (spec.processor.subnetLabels) to identify IP ranges that are external to the cluster.",
"Cluster name": "Cluster name",
"UDN": "UDN",
"Can't find metrics for this element. Check your capture filters to ensure we can monitor it. Else it probably means there is no traffic here.": "Can't find metrics for this element. Check your capture filters to ensure we can monitor it. Else it probably means there is no traffic here.",
Expand Down
2 changes: 2 additions & 0 deletions web/src/api/ipfix.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ export interface Flow {
DstK8S_Zone?: string;
SrcK8S_NetworkName?: string;
DstK8S_NetworkName?: string;
SrcSubnetLabel?: string;
DstSubnetLabel?: string;
K8S_ClusterName?: string;
Proto?: number;
Interfaces?: string[];
Expand Down
3 changes: 2 additions & 1 deletion web/src/api/loki.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,12 +68,13 @@ export interface TopologyMetricPeer {
resourceKind?: string;
isAmbiguous: boolean;
getDisplayName: (inclNamespace: boolean, disambiguate: boolean) => string | undefined;
// any FlowScope can appear here as optionnal field
// any FlowScope can appear here as optional field
[name: string]: unknown;
namespace?: string;
host?: string;
cluster?: string;
udn?: string;
subnetLabel?: string;
}

export type GenericMetric = {
Expand Down
20 changes: 19 additions & 1 deletion web/src/components/drawer/element/element-fields.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,20 @@ export const ElementFields: React.FC<ElementFieldsProps> = ({
forceLabel = forceAsText = undefined;
}
});
if (data.peer.subnetLabel) {
fragments.push(
<ElementField
id={id + '-subnet-label'}
key={id + '-subnet-label'}
label={t('Subnet label')}
activeFilters={activeFilters}
filterType={'resource'}
peer={createPeer({ subnetLabel: data.peer.subnetLabel })}
setFilters={setFilters}
filterDefinitions={filterDefinitions}
/>
);
}
if (data.peer.addr) {
fragments.push(
<ElementField
Expand All @@ -104,7 +118,11 @@ export const ElementFields: React.FC<ElementFieldsProps> = ({
<TextContent id={id + '-no-infos'} className="record-field-container">
{
<Text component={TextVariants.p}>
{t('No information available for this content. Change scope to get more details.')}
{t('No information available for this content. Decrease scope aggregation to get more details.')}
<br />
{t(
'You may also configure subnet labels in the FlowCollector resource (spec.processor.subnetLabels) to identify IP ranges that are external to the cluster.'
)}
</Text>
}
</TextContent>
Expand Down
7 changes: 4 additions & 3 deletions web/src/components/drawer/element/element-panel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -72,10 +72,11 @@ export const ElementPanel: React.FC<ElementPanelProps> = ({
return <Text component={TextVariants.h2}>{t('Edge')}</Text>;
} else {
const data = element.getData();
if (data?.nodeType === 'unknown') {
return <Text component={TextVariants.h2}>{t('Unknown')}</Text>;
const name = data?.peer.getDisplayName(false, false);
if (data && name) {
return <PeerResourceLink peer={data.peer} />;
}
return <>{data && <PeerResourceLink peer={data.peer} />}</>;
return <Text component={TextVariants.h2}>{t('Unknown')}</Text>;
}
}, [element, t]);

Expand Down
14 changes: 9 additions & 5 deletions web/src/components/tabs/netflow-topology/2d/styles/styleNode.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import {
ClusterIcon,
CubeIcon,
CubesIcon,
ExternalLinkAltIcon,
NetworkIcon,
OutlinedHddIcon,
QuestionCircleIcon,
Expand All @@ -27,6 +28,7 @@ import {
import useDetailsLevel from '@patternfly/react-topology/dist/esm/hooks/useDetailsLevel';
import * as _ from 'lodash';
import * as React from 'react';
import { TopologyMetricPeer } from '../../../../../api/loki';
import { Decorated, NodeData } from '../../../../../model/topology';
import DefaultNode from '../components/node';
import { NodeDecorators } from './styleDecorators';
Expand All @@ -50,8 +52,8 @@ type StyleNodeProps = {
WithSelectionProps;

// eslint-disable-next-line @typescript-eslint/no-explicit-any
const getTypeIcon = (resourceKind?: string): React.ComponentClass<any, any> => {
switch (resourceKind) {
const getTypeIcon = (peer: TopologyMetricPeer): React.ComponentClass<any, any> => {
switch (peer.resourceKind) {
case 'Service':
return ServiceIcon;
case 'Pod':
Expand All @@ -72,9 +74,11 @@ const getTypeIcon = (resourceKind?: string): React.ComponentClass<any, any> => {
case 'StatefulSet':
case 'Job':
return CubesIcon;
default:
return QuestionCircleIcon;
}
if (peer.addr || peer.subnetLabel) {
return ExternalLinkAltIcon;
}
return QuestionCircleIcon;
};

const renderIcon = (data: Decorated<NodeData>, element: NodePeer): React.ReactNode => {
Expand All @@ -83,7 +87,7 @@ const renderIcon = (data: Decorated<NodeData>, element: NodePeer): React.ReactNo
const iconSize =
(shape === NodeShape.trapezoid ? width : Math.min(width, height)) -
(shape === NodeShape.stadium ? 5 : iconPadding) * 2;
const Component = getTypeIcon(data.peer.resourceKind);
const Component = getTypeIcon(data.peer);

return (
<g transform={`translate(${(width - iconSize) / 2}, ${(height - iconSize) / 2})`}>
Expand Down
2 changes: 2 additions & 0 deletions web/src/utils/ids.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ export const getPeerId = (fields: Partial<TopologyMetricPeer>): string => {
parts.push('r=' + fields.resource.type + '.' + fields.resource.name);
} else if (fields.addr) {
parts.push('a=' + fields.addr);
} else if (fields.subnetLabel) {
parts.push('sl=' + fields.subnetLabel);
}
return parts.length > 0 ? parts.join(',') : idUnknown;
};
Expand Down
19 changes: 14 additions & 5 deletions web/src/utils/metrics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ export const createPeer = (fields: Partial<TopologyMetricPeer>): TopologyMetricP
addr: fields.addr,
resource: fields.resource,
owner: fields.owner,
subnetLabel: fields.subnetLabel,
isAmbiguous: false,
getDisplayName: () => undefined
};
Expand Down Expand Up @@ -146,9 +147,15 @@ export const createPeer = (fields: Partial<TopologyMetricPeer>): TopologyMetricP
}
});

// fallback on address if nothing else available
if (!newPeer.resourceKind && fields.addr) {
newPeer.getDisplayName = () => fields.addr;
// fallback on address and/or subnet label if nothing else available
if (!newPeer.resourceKind) {
if (fields.subnetLabel && fields.addr) {
newPeer.getDisplayName = () => `${fields.subnetLabel} (${fields.addr})`;
} else if (fields.subnetLabel) {
newPeer.getDisplayName = () => fields.subnetLabel;
} else if (fields.addr) {
newPeer.getDisplayName = () => fields.addr;
}
}
return newPeer;
};
Expand All @@ -173,15 +180,17 @@ const parseTopologyMetric = (
owner:
raw.metric.SrcK8S_Type !== raw.metric.SrcK8S_OwnerType
? nameAndType(raw.metric.SrcK8S_OwnerName, raw.metric.SrcK8S_OwnerType)
: undefined
: undefined,
subnetLabel: raw.metric.SrcSubnetLabel
};
const destFields: Partial<TopologyMetricPeer> = {
addr: raw.metric.DstAddr,
resource: nameAndType(raw.metric.DstK8S_Name, raw.metric.DstK8S_Type),
owner:
raw.metric.DstK8S_Type !== raw.metric.DstK8S_OwnerType
? nameAndType(raw.metric.DstK8S_OwnerName, raw.metric.DstK8S_OwnerType)
: undefined
: undefined,
subnetLabel: raw.metric.DstSubnetLabel
};
getCustomScopes().forEach(sc => {
if (!sc.labels.length) {
Expand Down