Skip to content

Clean TS flow format code; remove field/label distinction #950

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
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: 0 additions & 4 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -136,10 +136,6 @@ else
cd -
endif

.PHONY: generate-doc
generate-doc: ## Generate documentation of the flows JSON format
cd web && npm run generate-doc

.PHONY: update-config
update-config: ## Update sample config from operator repo
./scripts/update-config.sh
Expand Down
3 changes: 1 addition & 2 deletions web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,7 @@
"lint": "./node_modules/.bin/eslint \"./src/**/*.{ts,tsx}\"",
"format": "pretty-quick --branch main",
"format-all": "prettier --write \"./src/**/*.{ts,tsx}\" && npm run fix-imports",
"fix-imports": "eslint --no-eslintrc --no-inline-config --parser '@typescript-eslint/parser' --plugin 'unused-imports' --plugin 'react-hooks' --rule 'unused-imports/no-unused-imports:error' --fix \"./src/**/*.{ts,tsx}\"",
"generate-doc": "typedoc --sort source-order --categorizeByGroup false --githubPages false --readme none --disableSources --out docs src/api/ipfix.ts --hideBreadcrumbs true --hideInPageTOC true"
"fix-imports": "eslint --no-eslintrc --no-inline-config --parser '@typescript-eslint/parser' --plugin 'unused-imports' --plugin 'react-hooks' --rule 'unused-imports/no-unused-imports:error' --fix \"./src/**/*.{ts,tsx}\""
},
"devDependencies": {
"@babel/core": "^7.17.12",
Expand Down
148 changes: 35 additions & 113 deletions web/src/api/ipfix.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,195 +2,117 @@
import { TFunction } from 'i18next';
import { RecordType } from '../model/flow-query';

// Please keep this file documented: it is used in doc generation
// To regenerate doc, run `make generate-doc` - and also check this page:
// https://github.com/netobserv/network-observability-operator/blob/main/docs/GeneratingAsciidocAPI.md#generate-asciidoc-for-flows-json-format-reference

export interface Record {
labels: Labels;
labels: Flow;
key: number;
fields: Fields;
fields: Flow;
}

export const getRecordValue = (record: Record, fieldOrLabel: string, defaultValue?: string | number) => {
export const getRecordValue = (record: Record, field: Field, defaultValue?: string | number) => {
/* TODO: fix following behavior:
* Check if field exists first since /flow endpoint return fields as labels when using filters
* This is mandatory to ensure fields types
*/
if (record.fields[fieldOrLabel as keyof Fields] !== undefined) {
return record.fields[fieldOrLabel as keyof Fields];
if (record.fields[field] !== undefined) {
return record.fields[field];
}
// check if label exists
if (record.labels[fieldOrLabel as keyof Labels] !== undefined) {
return record.labels[fieldOrLabel as keyof Labels];
if (record.labels[field] !== undefined) {
return record.labels[field];
}
// fallback on default
return defaultValue;
};

export interface Labels {
/** Source namespace */
export type Field = keyof Flow;

export interface Flow {
SrcK8S_Namespace?: string;
/** Destination namespace */
DstK8S_Namespace?: string;
/** Source owner, such as Deployment, StatefulSet, etc. */
SrcK8S_OwnerName?: string;
/** Destination owner, such as Deployment, StatefulSet, etc. */
DstK8S_OwnerName?: string;
/** Kind of the source matched Kubernetes object, such as Pod, Service, etc. */
SrcK8S_Type?: string;
/** Kind of the destination matched Kubernetes object, such as Pod name, Service name, etc. */
DstK8S_Type?: string;
/** Flow direction from the node observation point*/
FlowDirection?: FlowDirection;
/** Type of record: 'flowLog' for regular flow logs, or 'allConnections',
* 'newConnection', 'heartbeat', 'endConnection' for conversation tracking */
_RecordType?: RecordType;
}

export enum FlowDirection {
/** Incoming traffic, from the node observation point */
Ingress = '0',
/** Outgoing traffic, from the node observation point */
Egress = '1',
/** Inner traffic, with the same source and destination node */
Inner = '2',
/** Both traffic (for Interface direction only), flow seen on both Ingress and Egress */
Both = '3'
}

export const getDirectionDisplayString = (value: FlowDirection, t: TFunction) => {
return value === FlowDirection.Ingress
? t('Ingress')
: value === FlowDirection.Egress
? t('Egress')
: value === FlowDirection.Inner
? t('Inner')
: value === FlowDirection.Both
? t('Both')
: t('n/a');
};

export enum IfDirection {
/** Incoming traffic, from the network interface observation point */
Ingress = '0',
/** Outgoing traffic, from the network interface observation point */
Egress = '1'
}

export interface Fields {
/** Source IP address (ipv4 or ipv6) */
SrcAddr?: string;
/** Destination IP address (ipv4 or ipv6) */
DstAddr?: string;
/** Source MAC address */
SrcMac?: string;
/** Destination MAC address */
DstMac?: string;
/** Name of the source matched Kubernetes object, such as Pod name, Service name, etc. */
SrcK8S_Name?: string;
/** Name of the destination matched Kubernetes object, such as Pod name, Service name, etc. */
DstK8S_Name?: string;
/** Source port */
SrcPort?: number;
/** Destination port */
DstPort?: number;
/** Kind of the source Kubernetes owner, such as Deployment, StatefulSet, etc. */
SrcK8S_OwnerName?: string;
DstK8S_OwnerName?: string;
SrcK8S_OwnerType?: string;
/** Kind of the destination Kubernetes owner, such as Deployment, StatefulSet, etc. */
DstK8S_OwnerType?: string;
/** Source node IP */
SrcK8S_HostIP?: string;
/** Destination node IP */
DstK8S_HostIP?: string;
/** Source node name */
SrcK8S_HostName?: string;
/** Destination node name */
DstK8S_HostName?: string;
/** Source zone */
SrcK8S_Zone?: string;
/** Destination zone */
DstK8S_Zone?: string;
/** Source network name (e.g. secondary networks or UDN) */
SrcK8S_NetworkName?: string;
/** Destination network name (e.g. secondary networks or UDN) */
DstK8S_NetworkName?: string;
/** Cluster name */
K8S_ClusterName?: string;
/** L4 protocol */
Proto?: number;
/** Network interface array */
Interfaces?: string[];
/** Flow direction array from the network interface observation point */
IfDirections?: IfDirection[];
/** UDNs labels array */
Udns?: string[];
/** Network Events */
NetworkEvents?: string[];
/** Logical OR combination of unique TCP flags comprised in the flow, as per RFC-9293, with additional custom flags to represent the following per-packet combinations: SYN+ACK (0x100), FIN+ACK (0x200) and RST+ACK (0x400). */
Flags?: string[];
/** Number of packets */
Packets?: number;
/** In conversation tracking, A to B packets counter per conversation */
Packets_AB?: number;
/** In conversation tracking, B to A packets counter per conversation */
Packets_BA?: number;
/** Number of bytes */
Bytes?: number;
/** In conversation tracking, A to B bytes counter per conversation */
Bytes_AB?: number;
/** In conversation tracking, B to A bytes counter per conversation */
Bytes_BA?: number;
/** Differentiated Services Code Point Value */
Dscp?: number;
/** ICMP type */
IcmpType?: number;
/** ICMP code */
IcmpCode?: number;
/** Pkt TCP state for drops */
PktDropLatestState?: string;
/** Pkt cause for drops */
PktDropLatestDropCause?: string;
/** Pkt TCP flags for drops */
PktDropLatestFlags?: number;
/** Number of packets dropped by the kernel */
PktDropPackets?: number;
/** In conversation tracking, A to B packets dropped counter per conversation */
PktDropPackets_AB?: number;
/** In conversation tracking, B to A packets dropped counter per conversation */
PktDropPackets_BA?: number;
/** Number of bytes dropped by the kernel */
PktDropBytes?: number;
/** In conversation tracking, A to B bytes dropped counter per conversation */
PktDropBytes_AB?: number;
/** In conversation tracking, B to A bytes dropped counter per conversation */
PktDropBytes_BA?: number;
/** DNS record id */
DnsId?: number;
/** DNS flags for DNS record */
DnsFlags?: number;
/** Parsed DNS header RCODEs name */
DnsFlagsResponseCode?: string;
/** Calculated time between response and request, in milliseconds */
DnsLatencyMs?: number;
/** Error number returned from DNS tracker ebpf hook function */
DnsErrno?: number;
/** Start timestamp of this flow, in milliseconds */
TimeFlowStartMs?: number;
/** End timestamp of this flow, in milliseconds */
TimeFlowEndMs?: number;
/** Timestamp when this flow was received and processed by the flow collector, in seconds */
TimeReceived?: number;
/** TCP smoothed Round Trip Time (sRTT) in nanoseconds */
TimeFlowRttNs?: number;
/** In conversation tracking, the conversation identifier */
_HashId?: string;
/** In conversation tracking, a flag identifying the first flow */
_IsFirst?: string;
/** In conversation tracking, a counter of flow logs per conversation */
numFlowLogs?: number;
/** User Defined Network identifier */
UdnId?: string;
}

export type Field = keyof Fields | keyof Labels;
export enum FlowDirection {
Ingress = '0',
Egress = '1',
Inner = '2',
Both = '3'
}

export const getDirectionDisplayString = (value: FlowDirection, t: TFunction) => {
return value === FlowDirection.Ingress
? t('Ingress')
: value === FlowDirection.Egress
? t('Egress')
: value === FlowDirection.Inner
? t('Inner')
: value === FlowDirection.Both
? t('Both')
: t('n/a');
};

export enum IfDirection {
Ingress = '0',
Egress = '1'
}
8 changes: 4 additions & 4 deletions web/src/api/loki.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { FlowScope, MetricType, StatFunction } from '../model/flow-query';
import { cyrb53 } from '../utils/hash';
import { getFunctionFromId, getRateFunctionFromId } from '../utils/overview-panels';
import { Field, Fields, Labels, Record } from './ipfix';
import { Field, Flow, Record } from './ipfix';

export interface AggregatedQueryResponse {
resultType: string;
Expand Down Expand Up @@ -39,16 +39,16 @@ export class GenericMetricsResult {

export const parseStream = (raw: StreamResult): Record[] => {
return raw.values.map(v => {
const fields = JSON.parse(v[1]) as Fields;
const fields = JSON.parse(v[1]) as Flow;
return {
labels: raw.stream as unknown as Labels,
labels: raw.stream as Flow,
key: cyrb53(v.join(',')),
fields: fields
};
});
};

export interface RawTopologyMetric extends Fields, Labels {}
export type RawTopologyMetric = Flow;

export interface RawTopologyMetrics {
metric: RawTopologyMetric;
Expand Down
30 changes: 15 additions & 15 deletions web/src/utils/__tests__/flows.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Fields, FlowDirection, IfDirection, Record } from '../../api/ipfix';
import { FlowDirection, IfDirection, Record } from '../../api/ipfix';
import { mergeFlowReporters } from '../flows';

describe('mergeFlowReporters', () => {
Expand All @@ -9,57 +9,57 @@ describe('mergeFlowReporters', () => {
const flows: Record[] = [
{
key: 1,
fields: { SrcAddr: '10.0.0.1', DstAddr: '10.0.0.2' } as Fields,
fields: { SrcAddr: '10.0.0.1', DstAddr: '10.0.0.2' },
labels: { FlowDirection: FlowDirection.Ingress }
},
{
key: 2,
fields: { SrcAddr: '10.0.0.1', DstAddr: '10.0.0.2' } as Fields,
fields: { SrcAddr: '10.0.0.1', DstAddr: '10.0.0.2' },
labels: { FlowDirection: FlowDirection.Egress }
},
{
key: 3,
fields: { SrcAddr: '10.0.0.2', DstAddr: '10.0.0.1' } as Fields,
fields: { SrcAddr: '10.0.0.2', DstAddr: '10.0.0.1' },
labels: { FlowDirection: FlowDirection.Ingress }
},
{
key: 4,
fields: { SrcAddr: '10.0.0.2', DstAddr: '10.0.0.1' } as Fields,
fields: { SrcAddr: '10.0.0.2', DstAddr: '10.0.0.1' },
labels: { FlowDirection: FlowDirection.Egress }
},
{
key: 5,
fields: { SrcAddr: '10.0.0.1', DstAddr: '10.0.0.2' } as Fields,
fields: { SrcAddr: '10.0.0.1', DstAddr: '10.0.0.2' },
labels: { FlowDirection: FlowDirection.Ingress }
},
{
key: 6,
fields: { SrcAddr: '10.0.0.1', DstAddr: '10.0.0.2' } as Fields,
fields: { SrcAddr: '10.0.0.1', DstAddr: '10.0.0.2' },
labels: { FlowDirection: FlowDirection.Egress }
},
{
key: 7,
fields: { SrcAddr: '10.0.0.1', DstAddr: '43.75.13.32' } as Fields,
fields: { SrcAddr: '10.0.0.1', DstAddr: '43.75.13.32' },
labels: { FlowDirection: FlowDirection.Egress }
},
{
key: 8,
fields: { SrcAddr: '43.75.13.32', DstAddr: '10.0.0.1' } as Fields,
fields: { SrcAddr: '43.75.13.32', DstAddr: '10.0.0.1' },
labels: { FlowDirection: FlowDirection.Ingress }
},
{
key: 9,
fields: { SrcAddr: '10.0.0.1', DstAddr: '43.75.13.32' } as Fields,
fields: { SrcAddr: '10.0.0.1', DstAddr: '43.75.13.32' },
labels: { FlowDirection: FlowDirection.Egress }
},
{
key: 10,
fields: { SrcAddr: '10.0.0.1', DstAddr: '10.0.0.2', SrcPort: 8080 } as Fields,
fields: { SrcAddr: '10.0.0.1', DstAddr: '10.0.0.2', SrcPort: 8080 },
labels: { FlowDirection: FlowDirection.Ingress }
},
{
key: 11,
fields: { SrcAddr: '10.0.0.1', DstAddr: '10.0.0.2', SrcPort: 8080 } as Fields,
fields: { SrcAddr: '10.0.0.1', DstAddr: '10.0.0.2', SrcPort: 8080 },
labels: { FlowDirection: FlowDirection.Egress }
}
];
Expand All @@ -78,7 +78,7 @@ describe('mergeFlowReporters', () => {
IfDirections: [IfDirection.Ingress, IfDirection.Egress],
Interfaces: ['eth0', 'abcd'],
Udns: ['udn1', 'udn2']
} as Fields,
},
labels: { FlowDirection: FlowDirection.Ingress }
},
{
Expand All @@ -89,7 +89,7 @@ describe('mergeFlowReporters', () => {
IfDirections: [IfDirection.Ingress],
Interfaces: ['genev'],
Udns: ['udn3']
} as Fields,
},
labels: { FlowDirection: FlowDirection.Egress }
}
];
Expand All @@ -103,7 +103,7 @@ describe('mergeFlowReporters', () => {
IfDirections: [IfDirection.Ingress, IfDirection.Egress, IfDirection.Ingress],
Interfaces: ['eth0', 'abcd', 'genev'],
Udns: ['udn1', 'udn2', 'udn3']
} as Fields,
},
labels: { FlowDirection: FlowDirection.Ingress }
});
});
Expand Down
4 changes: 2 additions & 2 deletions web/src/utils/column-parser.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { getRecordValue, Record } from '../api/ipfix';
import { Field, getRecordValue, Record } from '../api/ipfix';
import { Column, ColumnConfigDef, ColumnsId, ColValue } from './columns';
import { FieldConfig, FieldType } from './fields';

Expand All @@ -19,7 +19,7 @@ const getColumnOrRecordValue = (
}
return defaultValue;
}
return getRecordValue(record, arg, defaultValue);
return getRecordValue(record, arg as Field, defaultValue);
};

const funcs: { [name: string]: (columns: Column[], record: Record, args: string[]) => ColValue } = {
Expand Down
Loading
Loading