From aba73615486396ab1aa63e37b99ffbd0fc9dd676 Mon Sep 17 00:00:00 2001 From: Julien Pinsonneau Date: Tue, 17 Sep 2024 16:45:16 +0200 Subject: [PATCH 1/5] add cypress checks on fields --- config/sample-config.yaml | 139 +++++++++++++++++- mocks/loki/flow_records.json | 24 +-- web/cypress/e2e/table/fields.spec.ts | 60 ++++++++ web/cypress/support/commands.ts | 10 ++ .../tabs/netflow-table/netflow-table-row.tsx | 3 + .../tabs/netflow-table/netflow-table.tsx | 1 + web/src/utils/icmp.ts | 2 +- 7 files changed, 224 insertions(+), 15 deletions(-) create mode 100644 web/cypress/e2e/table/fields.spec.ts diff --git a/config/sample-config.yaml b/config/sample-config.yaml index 80870395c..73dea1a88 100644 --- a/config/sample-config.yaml +++ b/config/sample-config.yaml @@ -155,13 +155,15 @@ frontend: columns: - id: StartTime name: Start Time - tooltip: Time of the first packet observed. Unlike End Time, it is not used in queries to select records in an interval. + tooltip: Time of the first packet observed. Unlike End Time, it is not used in queries + to select records in an interval. field: TimeFlowStartMs default: false width: 15 - id: EndTime name: End Time - tooltip: Time of the last packet observed. This is what is used in queries to select records in an interval. + tooltip: Time of the last packet observed. This is what is used in queries to select + records in an interval. field: TimeFlowEndMs default: true width: 15 @@ -305,6 +307,14 @@ frontend: default: false width: 15 feature: zones + - id: SrcSubnetLabel + group: Source + name: Subnet Label + field: SrcSubnetLabel + filter: src_subnet_label + default: false + width: 10 + feature: subnetLabels - id: DstK8S_Name group: Destination name: Name @@ -425,6 +435,14 @@ frontend: default: false width: 15 feature: zones + - id: DstSubnetLabel + group: Destination + name: Subnet Label + field: DstSubnetLabel + filter: dst_subnet_label + default: false + width: 10 + feature: subnetLabels - id: K8S_Name name: Names calculated: getSrcOrDstValue(SrcK8S_Name,DstK8S_Name) @@ -517,6 +535,9 @@ frontend: name: Type tooltip: The type of the ICMP message field: IcmpType + fields: + - Proto + - IcmpType filter: icmp_type default: false width: 10 @@ -525,9 +546,20 @@ frontend: name: Code tooltip: The code of the ICMP message field: IcmpCode + fields: + - Proto + - IcmpType + - IcmpCode filter: icmp_code default: false width: 10 + - id: TCPFlags + name: TCP Flags + tooltip: Logical OR combination of unique TCP flags comprised in the flow, as per RFC-9293, with additional custom values. + field: Flags + filter: tcp_flags + default: false + width: 10 - id: FlowDirection name: Node Direction tooltip: The interpreted direction of the flow observed at the Node observation point. @@ -635,6 +667,14 @@ frontend: default: true width: 5 feature: flowRTT + - id: NetworkEvents + name: Network Events + tooltip: Network events flow monitor + field: NetworkEvents + filter: network_events + default: true + width: 15 + feature: networkEvents filters: - id: cluster_name name: Cluster @@ -754,6 +794,16 @@ frontend: component: autocomplete category: destination hint: Specify a single zone. + - id: src_subnet_label + name: Subnet Label + component: autocomplete + category: source + hint: Specify a subnet label, or an empty string to get unmatched sources. + - id: dst_subnet_label + name: Subnet Label + component: autocomplete + category: destination + hint: Specify a subnet label, or an empty string to get unmatched destinations. - id: src_resource name: Resource component: autocomplete @@ -912,6 +962,24 @@ frontend: name: ICMP code component: number hint: Specify an ICMP code value as integer number. + - id: tcp_flags + name: TCP flags + component: autocomplete + hint: Specify a TCP flags value as integer number. + examples: |- + Logical OR combination of unique TCP flags comprised in the flow, as per RFC-9293, with additional custom flags + users can specify either numeric value or string representation of the flags as follows : + - FIN or 1, + - SYN or 2, + - RST or 4, + - PSH or 8, + - ACK or 16, + - URG or 32, + - ECE or 64, + - CWR or 128, + - SYN_ACK or 256, + - FIN_ACK or 512, + - RST_ACK or 1024, - id: node_direction name: Node Direction component: autocomplete @@ -982,109 +1050,152 @@ frontend: name: Flow RTT component: number hint: Specify a TCP smoothed Round Trip Time in nanoseconds. + - id: network_events + name: Network events flow monitoring + component: text + hint: Specify a single network event. fields: - name: TimeFlowStartMs type: number description: Start timestamp of this flow, in milliseconds + cardinalityWarn: avoid - name: TimeFlowEndMs type: number description: End timestamp of this flow, in milliseconds + cardinalityWarn: avoid - name: TimeReceived type: number description: Timestamp when this flow was received and processed by the flow collector, in seconds + cardinalityWarn: avoid - name: SrcK8S_Name type: string description: Name of the source Kubernetes object, such as Pod name, Service name or Node name. + cardinalityWarn: careful - name: SrcK8S_Type type: string description: Kind of the source Kubernetes object, such as Pod, Service or Node. lokiLabel: true + cardinalityWarn: fine - name: SrcK8S_OwnerName type: string description: Name of the source owner, such as Deployment name, StatefulSet name, etc. lokiLabel: true + cardinalityWarn: fine - name: SrcK8S_OwnerType type: string description: Kind of the source owner, such as Deployment, StatefulSet, etc. + cardinalityWarn: fine - name: SrcK8S_Namespace type: string description: Source namespace lokiLabel: true + cardinalityWarn: fine - name: SrcAddr type: string description: Source IP address (ipv4 or ipv6) + cardinalityWarn: avoid - name: SrcPort type: number description: Source port + cardinalityWarn: careful - name: SrcMac type: string description: Source MAC address + cardinalityWarn: avoid - name: SrcK8S_HostIP type: string description: Source node IP + cardinalityWarn: fine - name: SrcK8S_HostName type: string description: Source node name + cardinalityWarn: fine - name: SrcK8S_Zone type: string description: Source availability zone lokiLabel: true + cardinalityWarn: fine + - name: SrcSubnetLabel + type: string + description: Source subnet label + cardinalityWarn: fine - name: DstK8S_Name type: string description: Name of the destination Kubernetes object, such as Pod name, Service name or Node name. + cardinalityWarn: careful - name: DstK8S_Type type: string description: Kind of the destination Kubernetes object, such as Pod, Service or Node. lokiLabel: true + cardinalityWarn: fine - name: DstK8S_OwnerName type: string description: Name of the destination owner, such as Deployment name, StatefulSet name, etc. lokiLabel: true + cardinalityWarn: fine - name: DstK8S_OwnerType type: string description: Kind of the destination owner, such as Deployment, StatefulSet, etc. + cardinalityWarn: fine - name: DstK8S_Namespace type: string description: Destination namespace lokiLabel: true + cardinalityWarn: fine - name: DstAddr type: string description: Destination IP address (ipv4 or ipv6) + cardinalityWarn: avoid - name: DstPort type: number description: Destination port + cardinalityWarn: careful - name: DstMac type: string description: Destination MAC address + cardinalityWarn: avoid - name: DstK8S_HostIP type: string description: Destination node IP + cardinalityWarn: fine - name: DstK8S_HostName type: string description: Destination node name + cardinalityWarn: fine - name: DstK8S_Zone type: string description: Destination availability zone lokiLabel: true + cardinalityWarn: fine + - name: DstSubnetLabel + type: string + description: Destination subnet label + cardinalityWarn: fine - name: K8S_FlowLayer type: string description: "Flow layer: 'app' or 'infra'" + cardinalityWarn: fine - name: Proto type: number description: L4 protocol + cardinalityWarn: fine - name: Dscp type: number description: Differentiated Services Code Point (DSCP) value + cardinalityWarn: fine - name: IcmpType type: number description: ICMP type + cardinalityWarn: fine - name: IcmpCode type: number description: ICMP code + cardinalityWarn: fine - name: Duplicate type: boolean description: Indicates if this flow was also captured from another interface on the same host lokiLabel: true + cardinalityWarn: fine - name: FlowDirection type: number description: | @@ -1093,15 +1204,18 @@ frontend: - 1: Egress (outgoing traffic, from the node observation point) + - 2: Inner (with the same source and destination node) lokiLabel: true + cardinalityWarn: fine - name: IfDirections type: number description: | Flow directions from the network interface observation point. Can be one of: + - 0: Ingress (interface incoming traffic) + - 1: Egress (interface outgoing traffic) + cardinalityWarn: fine - name: Interfaces type: string description: Network interfaces + cardinalityWarn: careful - name: Flags type: number description: | @@ -1109,55 +1223,76 @@ frontend: - SYN+ACK (0x100) + - FIN+ACK (0x200) + - RST+ACK (0x400) + cardinalityWarn: fine - name: Bytes type: number description: Number of bytes + cardinalityWarn: avoid - name: Packets type: number description: Number of packets + cardinalityWarn: avoid - name: PktDropBytes type: number description: Number of bytes dropped by the kernel + cardinalityWarn: avoid - name: PktDropPackets type: number description: Number of packets dropped by the kernel + cardinalityWarn: avoid - name: PktDropLatestState type: string description: TCP state on last dropped packet filter: pkt_drop_state # couldn't guess from config + cardinalityWarn: fine - name: PktDropLatestDropCause type: string description: Latest drop cause filter: pkt_drop_cause # couldn't guess from config + cardinalityWarn: fine - name: PktDropLatestFlags type: number description: TCP flags on last dropped packet + cardinalityWarn: fine - name: DnsId type: number description: DNS record id + cardinalityWarn: avoid - name: DnsLatencyMs type: number description: Time between a DNS request and response, in milliseconds + cardinalityWarn: avoid - name: DnsFlags type: number description: DNS flags for DNS record + cardinalityWarn: fine - name: DnsFlagsResponseCode type: string description: Parsed DNS header RCODEs name + cardinalityWarn: fine - name: DnsErrno type: number description: Error number returned from DNS tracker ebpf hook function + cardinalityWarn: fine - name: TimeFlowRttNs type: number description: TCP Smoothed Round Trip Time (SRTT), in nanoseconds + cardinalityWarn: avoid + - name: NetworkEvents + type: string + description: Network events flow monitoring + cardinalityWarn: avoid - name: K8S_ClusterName type: string description: Cluster name or identifier lokiLabel: true + cardinalityWarn: fine - name: _RecordType type: string description: "Type of record: 'flowLog' for regular flow logs, or 'newConnection', 'heartbeat', 'endConnection' for conversation tracking" lokiLabel: true + cardinalityWarn: fine - name: _HashId type: string description: In conversation tracking, the conversation identifier + cardinalityWarn: avoid \ No newline at end of file diff --git a/mocks/loki/flow_records.json b/mocks/loki/flow_records.json index c61dc8c55..df48a59dd 100644 --- a/mocks/loki/flow_records.json +++ b/mocks/loki/flow_records.json @@ -14,27 +14,27 @@ "values": [ [ "1708011867120999936", - "{\"SrcK8S_Name\":\"ip-10-0-1-7.ec2.internal\",\"Bytes\":66,\"TimeFlowRttNs\":10000,\"Packets\":1,\"Interfaces\":[\"br-ex\",\"test\"],\"SrcMac\":\"02:27:A1:A8:84:B9\",\"Proto\":6,\"SrcK8S_HostIP\":\"10.0.1.7\",\"SrcK8S_HostName\":\"ip-10-0-1-7.ec2.internal\",\"Flags\":16,\"DnsErrno\":0,\"TimeFlowStartMs\":1708011867121,\"TimeReceived\":1708011867,\"DstAddr\":\"10.0.1.140\",\"Etype\":2048,\"SrcPort\":50104,\"AgentIP\":\"10.0.1.7\",\"SrcK8S_OwnerType\":\"Node\",\"Dscp\":0,\"TimeFlowEndMs\":1708011867121,\"IfDirections\":[\"1\",\"0\"],\"SrcAddr\":\"10.0.1.7\",\"Duplicate\":false,\"DstMac\":\"02:7B:32:68:BE:65\",\"DstPort\":443,\"IcmpType\":1,\"IcmpCode\":1}" + "{\"SrcK8S_Name\":\"ip-10-0-1-7.ec2.internal\",\"Bytes\":66,\"TimeFlowRttNs\":10000,\"Packets\":1,\"Interfaces\":[\"br-ex\",\"test\"],\"SrcMac\":\"02:27:A1:A8:84:B9\",\"Proto\":1,\"SrcK8S_HostIP\":\"10.0.1.7\",\"SrcK8S_HostName\":\"ip-10-0-1-7.ec2.internal\",\"Flags\":16,\"DnsErrno\":0,\"TimeFlowStartMs\":1708011867121,\"TimeReceived\":1708011867,\"DstAddr\":\"10.0.1.140\",\"Etype\":2048,\"SrcPort\":50104,\"AgentIP\":\"10.0.1.7\",\"SrcK8S_OwnerType\":\"Node\",\"Dscp\":0,\"TimeFlowEndMs\":1708011867121,\"IfDirections\":[\"1\",\"0\"],\"SrcAddr\":\"10.0.1.7\",\"Duplicate\":false,\"DstMac\":\"02:7B:32:68:BE:65\",\"DstPort\":443,\"IcmpType\":3,\"IcmpCode\":0}" ], [ "1708011867120999936", - "{\"Flags\":16,\"AgentIP\":\"10.0.1.7\",\"Proto\":6,\"TimeFlowRttNs\":10000,\"DstAddr\":\"10.0.1.140\",\"SrcMac\":\"02:27:A1:A8:84:B9\",\"Packets\":1,\"Interface\":\"eth0\",\"SrcK8S_Name\":\"ip-10-0-1-7.ec2.internal\",\"Etype\":2048,\"SrcK8S_HostIP\":\"10.0.1.7\",\"DnsErrno\":0,\"Dscp\":0,\"TimeFlowStartMs\":1708011867121,\"TimeFlowEndMs\":1708011867121,\"IfDirection\":1,\"SrcK8S_HostName\":\"ip-10-0-1-7.ec2.internal\",\"SrcK8S_OwnerType\":\"Node\",\"Bytes\":66,\"SrcAddr\":\"10.0.1.7\",\"SrcPort\":50104,\"DstMac\":\"02:7B:32:68:BE:65\",\"Duplicate\":true,\"TimeReceived\":1708011867,\"DstPort\":443}" + "{\"Flags\":16,\"AgentIP\":\"10.0.1.7\",\"Proto\":1,\"TimeFlowRttNs\":10000,\"DstAddr\":\"10.0.1.140\",\"SrcMac\":\"02:27:A1:A8:84:B9\",\"Packets\":1,\"Interface\":\"eth0\",\"SrcK8S_Name\":\"ip-10-0-1-7.ec2.internal\",\"Etype\":2048,\"SrcK8S_HostIP\":\"10.0.1.7\",\"DnsErrno\":0,\"Dscp\":0,\"TimeFlowStartMs\":1708011867121,\"TimeFlowEndMs\":1708011867121,\"IfDirection\":1,\"SrcK8S_HostName\":\"ip-10-0-1-7.ec2.internal\",\"SrcK8S_OwnerType\":\"Node\",\"Bytes\":66,\"SrcAddr\":\"10.0.1.7\",\"SrcPort\":50104,\"DstMac\":\"02:7B:32:68:BE:65\",\"Duplicate\":true,\"TimeReceived\":1708011867,\"DstPort\":443,\"IcmpType\":3,\"IcmpCode\":0}" ], [ "1708011867087000064", - "{\"DstAddr\":\"10.0.1.140\",\"DstMac\":\"02:7B:32:68:BE:65\",\"SrcK8S_HostName\":\"ip-10-0-1-7.ec2.internal\",\"DstPort\":443,\"Flags\":16,\"TimeFlowStartMs\":1708011867087,\"SrcK8S_OwnerType\":\"Node\",\"TimeReceived\":1708011867,\"Dscp\":0,\"IfDirection\":1,\"SrcMac\":\"02:27:A1:A8:84:B9\",\"Etype\":2048,\"SrcAddr\":\"10.0.1.7\",\"SrcK8S_HostIP\":\"10.0.1.7\",\"DnsErrno\":0,\"SrcPort\":35228,\"Packets\":1,\"Bytes\":66,\"AgentIP\":\"10.0.1.7\",\"Proto\":6,\"TimeFlowRttNs\":10000,\"Duplicate\":true,\"Interface\":\"br-ex\",\"TimeFlowEndMs\":1708011867087,\"SrcK8S_Name\":\"ip-10-0-1-7.ec2.internal\"}" + "{\"DstAddr\":\"10.0.1.140\",\"DstMac\":\"02:7B:32:68:BE:65\",\"SrcK8S_HostName\":\"ip-10-0-1-7.ec2.internal\",\"DstPort\":443,\"Flags\":16,\"TimeFlowStartMs\":1708011867087,\"SrcK8S_OwnerType\":\"Node\",\"TimeReceived\":1708011867,\"Dscp\":0,\"IfDirection\":1,\"SrcMac\":\"02:27:A1:A8:84:B9\",\"Etype\":2048,\"SrcAddr\":\"10.0.1.7\",\"SrcK8S_HostIP\":\"10.0.1.7\",\"DnsErrno\":0,\"SrcPort\":35228,\"Packets\":1,\"Bytes\":66,\"AgentIP\":\"10.0.1.7\",\"Proto\":1,\"TimeFlowRttNs\":10000,\"Duplicate\":true,\"Interface\":\"br-ex\",\"TimeFlowEndMs\":1708011867087,\"SrcK8S_Name\":\"ip-10-0-1-7.ec2.internal\",\"IcmpType\":3,\"IcmpCode\":0}" ], [ "1708011867087000064", - "{\"TimeFlowRttNs\":10000,\"Duplicate\":false,\"DstMac\":\"02:7B:32:68:BE:65\",\"IfDirection\":1,\"Dscp\":0,\"Proto\":6,\"SrcAddr\":\"10.0.1.7\",\"TimeFlowStartMs\":1708011867087,\"Packets\":1,\"SrcK8S_OwnerType\":\"Node\",\"TimeReceived\":1708011867,\"TimeFlowEndMs\":1708011867087,\"Flags\":16,\"DstAddr\":\"10.0.1.140\",\"SrcMac\":\"02:27:A1:A8:84:B9\",\"Etype\":2048,\"DstPort\":443,\"AgentIP\":\"10.0.1.7\",\"SrcK8S_HostName\":\"ip-10-0-1-7.ec2.internal\",\"DnsErrno\":0,\"Interface\":\"eth0\",\"SrcPort\":35228,\"SrcK8S_HostIP\":\"10.0.1.7\",\"Bytes\":66,\"SrcK8S_Name\":\"ip-10-0-1-7.ec2.internal\"}" + "{\"TimeFlowRttNs\":10000,\"Duplicate\":false,\"DstMac\":\"02:7B:32:68:BE:65\",\"IfDirection\":1,\"Dscp\":0,\"Proto\":1,\"SrcAddr\":\"10.0.1.7\",\"TimeFlowStartMs\":1708011867087,\"Packets\":1,\"SrcK8S_OwnerType\":\"Node\",\"TimeReceived\":1708011867,\"TimeFlowEndMs\":1708011867087,\"Flags\":16,\"DstAddr\":\"10.0.1.140\",\"SrcMac\":\"02:27:A1:A8:84:B9\",\"Etype\":2048,\"DstPort\":443,\"AgentIP\":\"10.0.1.7\",\"SrcK8S_HostName\":\"ip-10-0-1-7.ec2.internal\",\"DnsErrno\":0,\"Interface\":\"eth0\",\"SrcPort\":35228,\"SrcK8S_HostIP\":\"10.0.1.7\",\"Bytes\":66,\"SrcK8S_Name\":\"ip-10-0-1-7.ec2.internal\",\"IcmpType\":3,\"IcmpCode\":0}" ], [ "1708011867038000128", - "{\"SrcK8S_HostIP\":\"10.0.1.7\",\"DnsErrno\":0,\"Flags\":16,\"TimeReceived\":1708011867,\"DstAddr\":\"10.0.1.140\",\"Dscp\":0,\"AgentIP\":\"10.0.1.7\",\"Duplicate\":false,\"TimeFlowEndMs\":1708011867038,\"Etype\":2048,\"TimeFlowRttNs\":10000,\"SrcK8S_OwnerType\":\"Node\",\"SrcK8S_HostName\":\"ip-10-0-1-7.ec2.internal\",\"Packets\":28,\"DstPort\":443,\"DstMac\":\"02:7B:32:68:BE:65\",\"Proto\":6,\"SrcK8S_Name\":\"ip-10-0-1-7.ec2.internal\",\"IfDirection\":1,\"SrcMac\":\"02:27:A1:A8:84:B9\",\"Bytes\":2980,\"SrcPort\":41224,\"Interface\":\"eth0\",\"TimeFlowStartMs\":1708011862288,\"SrcAddr\":\"10.0.1.7\"}" + "{\"SrcK8S_HostIP\":\"10.0.1.7\",\"DnsErrno\":0,\"Flags\":16,\"TimeReceived\":1708011867,\"DstAddr\":\"10.0.1.140\",\"Dscp\":0,\"AgentIP\":\"10.0.1.7\",\"Duplicate\":false,\"TimeFlowEndMs\":1708011867038,\"Etype\":2048,\"TimeFlowRttNs\":10000,\"SrcK8S_OwnerType\":\"Node\",\"SrcK8S_HostName\":\"ip-10-0-1-7.ec2.internal\",\"Packets\":28,\"DstPort\":443,\"DstMac\":\"02:7B:32:68:BE:65\",\"Proto\":1,\"SrcK8S_Name\":\"ip-10-0-1-7.ec2.internal\",\"IfDirection\":1,\"SrcMac\":\"02:27:A1:A8:84:B9\",\"Bytes\":2980,\"SrcPort\":41224,\"Interface\":\"eth0\",\"TimeFlowStartMs\":1708011862288,\"SrcAddr\":\"10.0.1.7\",\"IcmpType\":3,\"IcmpCode\":0}" ], [ "1708011867038000128", - "{\"Dscp\":0,\"DstAddr\":\"10.0.1.140\",\"Interface\":\"br-ex\",\"SrcK8S_HostName\":\"ip-10-0-1-7.ec2.internal\",\"SrcAddr\":\"10.0.1.7\",\"Etype\":2048,\"AgentIP\":\"10.0.1.7\",\"SrcK8S_Name\":\"ip-10-0-1-7.ec2.internal\",\"Bytes\":2980,\"Duplicate\":true,\"IfDirection\":1,\"SrcPort\":41224,\"Flags\":16,\"Packets\":28,\"DnsErrno\":0,\"SrcK8S_OwnerType\":\"Node\",\"DstPort\":443,\"TimeFlowEndMs\":1708011867038,\"TimeReceived\":1708011867,\"Proto\":6,\"TimeFlowRttNs\":10000,\"TimeFlowStartMs\":1708011862288,\"SrcK8S_HostIP\":\"10.0.1.7\",\"SrcMac\":\"02:27:A1:A8:84:B9\",\"DstMac\":\"02:7B:32:68:BE:65\"}" + "{\"Dscp\":0,\"DstAddr\":\"10.0.1.140\",\"Interface\":\"br-ex\",\"SrcK8S_HostName\":\"ip-10-0-1-7.ec2.internal\",\"SrcAddr\":\"10.0.1.7\",\"Etype\":2048,\"AgentIP\":\"10.0.1.7\",\"SrcK8S_Name\":\"ip-10-0-1-7.ec2.internal\",\"Bytes\":2980,\"Duplicate\":true,\"IfDirection\":1,\"SrcPort\":41224,\"Flags\":16,\"Packets\":28,\"DnsErrno\":0,\"SrcK8S_OwnerType\":\"Node\",\"DstPort\":443,\"TimeFlowEndMs\":1708011867038,\"TimeReceived\":1708011867,\"Proto\":1,\"TimeFlowRttNs\":10000,\"TimeFlowStartMs\":1708011862288,\"SrcK8S_HostIP\":\"10.0.1.7\",\"SrcMac\":\"02:27:A1:A8:84:B9\",\"DstMac\":\"02:7B:32:68:BE:65\",\"IcmpType\":3,\"IcmpCode\":0}" ] ] }, @@ -65,27 +65,27 @@ "values": [ [ "1708011867120999936", - "{\"TimeFlowRttNs\":7114000,\"DstPort\":50104,\"TimeFlowStartMs\":1708011867121,\"Proto\":6,\"AgentIP\":\"10.0.1.7\",\"Etype\":2048,\"Bytes\":226,\"DstK8S_Name\":\"ip-10-0-1-7.ec2.internal\",\"DstAddr\":\"10.0.1.7\",\"DstK8S_HostName\":\"ip-10-0-1-7.ec2.internal\",\"DstK8S_OwnerType\":\"Node\",\"SrcAddr\":\"10.0.1.140\",\"Packets\":1,\"TimeFlowEndMs\":1708011867121,\"DstK8S_HostIP\":\"10.0.1.7\",\"Duplicate\":true,\"TimeReceived\":1708011867,\"SrcPort\":443,\"Flags\":16,\"IfDirection\":0,\"DnsErrno\":0,\"SrcMac\":\"02:7B:32:68:BE:65\",\"Interface\":\"br-ex\",\"Dscp\":0,\"DstMac\":\"02:27:A1:A8:84:B9\"}" + "{\"TimeFlowRttNs\":7114000,\"DstPort\":50104,\"TimeFlowStartMs\":1708011867121,\"Proto\":1,\"AgentIP\":\"10.0.1.7\",\"Etype\":2048,\"Bytes\":226,\"DstK8S_Name\":\"ip-10-0-1-7.ec2.internal\",\"DstAddr\":\"10.0.1.7\",\"DstK8S_HostName\":\"ip-10-0-1-7.ec2.internal\",\"DstK8S_OwnerType\":\"Node\",\"SrcAddr\":\"10.0.1.140\",\"Packets\":1,\"TimeFlowEndMs\":1708011867121,\"DstK8S_HostIP\":\"10.0.1.7\",\"Duplicate\":true,\"TimeReceived\":1708011867,\"SrcPort\":443,\"Flags\":16,\"IfDirection\":0,\"DnsErrno\":0,\"SrcMac\":\"02:7B:32:68:BE:65\",\"Interface\":\"br-ex\",\"Dscp\":0,\"DstMac\":\"02:27:A1:A8:84:B9\",\"IcmpType\":3,\"IcmpCode\":0}" ], [ "1708011867120999936", - "{\"DstPort\":50104,\"TimeReceived\":1708011867,\"DnsErrno\":0,\"Dscp\":0,\"TimeFlowRttNs\":10000,\"Duplicate\":false,\"DstK8S_OwnerType\":\"Node\",\"TimeFlowEndMs\":1708011867121,\"Packets\":1,\"Flags\":16,\"Etype\":2048,\"DstMac\":\"02:27:A1:A8:84:B9\",\"DstK8S_HostIP\":\"10.0.1.7\",\"IfDirection\":0,\"Bytes\":226,\"SrcAddr\":\"10.0.1.140\",\"Interface\":\"eth0\",\"DstAddr\":\"10.0.1.7\",\"AgentIP\":\"10.0.1.7\",\"SrcPort\":443,\"Proto\":6,\"SrcMac\":\"02:7B:32:68:BE:65\",\"TimeFlowStartMs\":1708011867121,\"DstK8S_HostName\":\"ip-10-0-1-7.ec2.internal\",\"DstK8S_Name\":\"ip-10-0-1-7.ec2.internal\"}" + "{\"DstPort\":50104,\"TimeReceived\":1708011867,\"DnsErrno\":0,\"Dscp\":0,\"TimeFlowRttNs\":10000,\"Duplicate\":false,\"DstK8S_OwnerType\":\"Node\",\"TimeFlowEndMs\":1708011867121,\"Packets\":1,\"Flags\":16,\"Etype\":2048,\"DstMac\":\"02:27:A1:A8:84:B9\",\"DstK8S_HostIP\":\"10.0.1.7\",\"IfDirection\":0,\"Bytes\":226,\"SrcAddr\":\"10.0.1.140\",\"Interface\":\"eth0\",\"DstAddr\":\"10.0.1.7\",\"AgentIP\":\"10.0.1.7\",\"SrcPort\":443,\"Proto\":1,\"SrcMac\":\"02:7B:32:68:BE:65\",\"TimeFlowStartMs\":1708011867121,\"DstK8S_HostName\":\"ip-10-0-1-7.ec2.internal\",\"DstK8S_Name\":\"ip-10-0-1-7.ec2.internal\",\"IcmpType\":3,\"IcmpCode\":0}" ], [ "1708011867087000064", - "{\"Proto\":6,\"Bytes\":216,\"SrcAddr\":\"10.0.1.140\",\"IfDirection\":0,\"Duplicate\":true,\"Etype\":2048,\"SrcMac\":\"02:7B:32:68:BE:65\",\"Dscp\":0,\"Flags\":16,\"AgentIP\":\"10.0.1.7\",\"DnsErrno\":0,\"TimeFlowStartMs\":1708011867087,\"Interface\":\"br-ex\",\"TimeFlowEndMs\":1708011867087,\"TimeFlowRttNs\":7951000,\"SrcPort\":443,\"DstK8S_HostIP\":\"10.0.1.7\",\"DstK8S_HostName\":\"ip-10-0-1-7.ec2.internal\",\"DstK8S_OwnerType\":\"Node\",\"DstPort\":35228,\"DstMac\":\"02:27:A1:A8:84:B9\",\"DstAddr\":\"10.0.1.7\",\"TimeReceived\":1708011867,\"Packets\":1,\"DstK8S_Name\":\"ip-10-0-1-7.ec2.internal\"}" + "{\"Proto\":1,\"Bytes\":216,\"SrcAddr\":\"10.0.1.140\",\"IfDirection\":0,\"Duplicate\":true,\"Etype\":2048,\"SrcMac\":\"02:7B:32:68:BE:65\",\"Dscp\":0,\"Flags\":16,\"AgentIP\":\"10.0.1.7\",\"DnsErrno\":0,\"TimeFlowStartMs\":1708011867087,\"Interface\":\"br-ex\",\"TimeFlowEndMs\":1708011867087,\"TimeFlowRttNs\":7951000,\"SrcPort\":443,\"DstK8S_HostIP\":\"10.0.1.7\",\"DstK8S_HostName\":\"ip-10-0-1-7.ec2.internal\",\"DstK8S_OwnerType\":\"Node\",\"DstPort\":35228,\"DstMac\":\"02:27:A1:A8:84:B9\",\"DstAddr\":\"10.0.1.7\",\"TimeReceived\":1708011867,\"Packets\":1,\"DstK8S_Name\":\"ip-10-0-1-7.ec2.internal\",\"IcmpType\":3,\"IcmpCode\":0}" ], [ "1708011867087000064", - "{\"SrcAddr\":\"10.0.1.140\",\"DnsErrno\":0,\"Dscp\":0,\"TimeFlowRttNs\":10000,\"Etype\":2048,\"TimeFlowEndMs\":1708011867087,\"Flags\":16,\"Duplicate\":false,\"TimeReceived\":1708011867,\"TimeFlowStartMs\":1708011867087,\"AgentIP\":\"10.0.1.7\",\"DstK8S_Name\":\"ip-10-0-1-7.ec2.internal\",\"DstAddr\":\"10.0.1.7\",\"Interface\":\"eth0\",\"DstPort\":35228,\"SrcPort\":443,\"DstK8S_OwnerType\":\"Node\",\"Proto\":6,\"SrcMac\":\"02:7B:32:68:BE:65\",\"DstK8S_HostIP\":\"10.0.1.7\",\"Bytes\":216,\"Packets\":1,\"DstK8S_HostName\":\"ip-10-0-1-7.ec2.internal\",\"IfDirection\":0,\"DstMac\":\"02:27:A1:A8:84:B9\"}" + "{\"SrcAddr\":\"10.0.1.140\",\"DnsErrno\":0,\"Dscp\":0,\"TimeFlowRttNs\":10000,\"Etype\":2048,\"TimeFlowEndMs\":1708011867087,\"Flags\":16,\"Duplicate\":false,\"TimeReceived\":1708011867,\"TimeFlowStartMs\":1708011867087,\"AgentIP\":\"10.0.1.7\",\"DstK8S_Name\":\"ip-10-0-1-7.ec2.internal\",\"DstAddr\":\"10.0.1.7\",\"Interface\":\"eth0\",\"DstPort\":35228,\"SrcPort\":443,\"DstK8S_OwnerType\":\"Node\",\"Proto\":1,\"SrcMac\":\"02:7B:32:68:BE:65\",\"DstK8S_HostIP\":\"10.0.1.7\",\"Bytes\":216,\"Packets\":1,\"DstK8S_HostName\":\"ip-10-0-1-7.ec2.internal\",\"IfDirection\":0,\"DstMac\":\"02:27:A1:A8:84:B9\",\"IcmpType\":3,\"IcmpCode\":0}" ], [ "1708011867038000128", - "{\"Duplicate\":true,\"DstK8S_OwnerType\":\"Node\",\"DstPort\":41224,\"DstAddr\":\"10.0.1.7\",\"TimeFlowStartMs\":1708011862288,\"TimeFlowEndMs\":1708011867038,\"DnsErrno\":0,\"Flags\":16,\"Proto\":6,\"DstK8S_Name\":\"ip-10-0-1-7.ec2.internal\",\"DstK8S_HostIP\":\"10.0.1.7\",\"SrcAddr\":\"10.0.1.140\",\"Bytes\":17622,\"Packets\":25,\"SrcPort\":443,\"DstK8S_HostName\":\"ip-10-0-1-7.ec2.internal\",\"TimeReceived\":1708011867,\"AgentIP\":\"10.0.1.7\",\"Dscp\":0,\"TimeFlowRttNs\":8917000,\"Etype\":2048,\"SrcMac\":\"02:7B:32:68:BE:65\",\"Interface\":\"br-ex\",\"IfDirection\":0,\"DstMac\":\"02:27:A1:A8:84:B9\"}" + "{\"Duplicate\":true,\"DstK8S_OwnerType\":\"Node\",\"DstPort\":41224,\"DstAddr\":\"10.0.1.7\",\"TimeFlowStartMs\":1708011862288,\"TimeFlowEndMs\":1708011867038,\"DnsErrno\":0,\"Flags\":16,\"Proto\":1,\"DstK8S_Name\":\"ip-10-0-1-7.ec2.internal\",\"DstK8S_HostIP\":\"10.0.1.7\",\"SrcAddr\":\"10.0.1.140\",\"Bytes\":17622,\"Packets\":25,\"SrcPort\":443,\"DstK8S_HostName\":\"ip-10-0-1-7.ec2.internal\",\"TimeReceived\":1708011867,\"AgentIP\":\"10.0.1.7\",\"Dscp\":0,\"TimeFlowRttNs\":8917000,\"Etype\":2048,\"SrcMac\":\"02:7B:32:68:BE:65\",\"Interface\":\"br-ex\",\"IfDirection\":0,\"DstMac\":\"02:27:A1:A8:84:B9\",\"IcmpType\":3,\"IcmpCode\":0}" ], [ "1708011867038000128", - "{\"TimeReceived\":1708011867,\"Interface\":\"eth0\",\"DstK8S_Name\":\"ip-10-0-1-7.ec2.internal\",\"Duplicate\":false,\"DstAddr\":\"10.0.1.7\",\"DstK8S_HostIP\":\"10.0.1.7\",\"SrcAddr\":\"10.0.1.140\",\"DstMac\":\"02:27:A1:A8:84:B9\",\"SrcMac\":\"02:7B:32:68:BE:65\",\"Bytes\":17622,\"AgentIP\":\"10.0.1.7\",\"DstK8S_HostName\":\"ip-10-0-1-7.ec2.internal\",\"TimeFlowRttNs\":10000,\"Packets\":25,\"DnsErrno\":0,\"Etype\":2048,\"Proto\":6,\"TimeFlowEndMs\":1708011867038,\"DstPort\":41224,\"Dscp\":0,\"TimeFlowStartMs\":1708011862288,\"DstK8S_OwnerType\":\"Node\",\"IfDirection\":0,\"Flags\":16,\"SrcPort\":443}" + "{\"TimeReceived\":1708011867,\"Interface\":\"eth0\",\"DstK8S_Name\":\"ip-10-0-1-7.ec2.internal\",\"Duplicate\":false,\"DstAddr\":\"10.0.1.7\",\"DstK8S_HostIP\":\"10.0.1.7\",\"SrcAddr\":\"10.0.1.140\",\"DstMac\":\"02:27:A1:A8:84:B9\",\"SrcMac\":\"02:7B:32:68:BE:65\",\"Bytes\":17622,\"AgentIP\":\"10.0.1.7\",\"DstK8S_HostName\":\"ip-10-0-1-7.ec2.internal\",\"TimeFlowRttNs\":10000,\"Packets\":25,\"DnsErrno\":0,\"Etype\":2048,\"Proto\":1,\"TimeFlowEndMs\":1708011867038,\"DstPort\":41224,\"Dscp\":0,\"TimeFlowStartMs\":1708011862288,\"DstK8S_OwnerType\":\"Node\",\"IfDirection\":0,\"Flags\":16,\"SrcPort\":443,\"IcmpType\":3,\"IcmpCode\":0}" ] ] }, diff --git a/web/cypress/e2e/table/fields.spec.ts b/web/cypress/e2e/table/fields.spec.ts new file mode 100644 index 000000000..9694b2e39 --- /dev/null +++ b/web/cypress/e2e/table/fields.spec.ts @@ -0,0 +1,60 @@ +/// + +import * as c from '../../support/const' + +describe('netflow-table', () => { + function reload(clearCache = true) { + cy.openNetflowTrafficPage(clearCache); + //move to table view + cy.get('.tableTabButton').click(); + //clear default app filters + if (clearCache === true) { + cy.get('#clear-all-filters-button').click(); + } + } + + beforeEach(() => { + reload(); + }); + + it('display content correctly', () => { + // select first row + cy.get('#netflow-table-row-0').click() + // check for side panel content + + // Dates + cy.checkRecordField('StartTime', 'Start Time', ['Feb 15, 2024', '4:44:27.121 PM']); + cy.checkRecordField('EndTime', 'End Time', ['Feb 15, 2024', '4:44:27.121 PM']); + + // Source accordion + cy.get('[data-test-id="group-2"]').contains("Source"); + cy.checkRecordField('SrcK8S_Name', 'Name', ['N', 'ip-10-0-1-7.ec2.internal']); + cy.checkRecordField('SrcK8S_Type', 'Kind', ['Node']); + cy.checkRecordField('SrcAddr', 'IP', ['10.0.1.7']); + cy.checkRecordField('SrcPort', 'Port', ['50104']); + cy.checkRecordField('SrcMac', 'MAC', ['02:27:A1:A8:84:B9']); + + // Destination accordion + cy.get('[data-test-id="group-3"]').contains("Destination"); + cy.checkRecordField('DstAddr', 'IP', ['10.0.1.140']); + cy.checkRecordField('DstPort', 'Port', ['https', '443']); + cy.checkRecordField('DstMac', 'MAC', ['02:7B:32:68:BE:65']); + + // others + cy.checkRecordField('K8S_FlowLayer', 'Flow layer', ['infra']); + + cy.get('[data-test-id="group-5"]').contains("L3 Layer"); + cy.checkRecordField('Proto', 'Protocol', ['ICMP']); + cy.checkRecordField('Dscp', 'DSCP', ['Standard']); + + cy.get('[data-test-id="group-6"]').contains("ICMP"); + cy.checkRecordField('IcmpType', 'Type', ['ICMP_DEST_UNREACH']); + cy.checkRecordField('IcmpCode', 'Code', ['ICMP_NET_UNREACH']); + + cy.checkRecordField('FlowDirection', 'Node Direction', ['Egress']); + cy.checkRecordField('FlowDirInts', 'Interfaces and Directions', ['br-ex', 'test', 'Egress', 'Ingress']); + + cy.checkRecordField('Bytes', 'Bytes', ['66 bytes sent']); + cy.checkRecordField('Packets', 'Packets', ['1 packets sent']); + }); +}) diff --git a/web/cypress/support/commands.ts b/web/cypress/support/commands.ts index 42438b89f..068d2def1 100644 --- a/web/cypress/support/commands.ts +++ b/web/cypress/support/commands.ts @@ -182,6 +182,15 @@ Cypress.Commands.add('changeMetricType', (name) => { cy.get('[data-layer-id="default"]').children().its('length').should('be.gte', 5); }); +Cypress.Commands.add('checkRecordField', (field, name, values) => { + cy.get(`[data-test-id="drawer-field-${field}"]`).contains(name); + values.forEach(v => { + cy.get(`[data-test-id="drawer-field-${field}"]`) + .children('.record-field-content,.record-field-flex-container') + .should('contain', v); + }); +}); + declare global { namespace Cypress { interface Chainable { @@ -202,6 +211,7 @@ declare global { changeTimeRange(name: string, topology?: boolean): Chainable changeMetricFunction(name: string): Chainable changeMetricType(name: string): Chainable + checkRecordField(field: string, name: string, values: string[]) } } } \ No newline at end of file diff --git a/web/src/components/tabs/netflow-table/netflow-table-row.tsx b/web/src/components/tabs/netflow-table/netflow-table-row.tsx index c5841e136..35763e9fd 100644 --- a/web/src/components/tabs/netflow-table/netflow-table-row.tsx +++ b/web/src/components/tabs/netflow-table/netflow-table-row.tsx @@ -8,6 +8,7 @@ import { Size } from '../../dropdowns/table-display-dropdown'; import './netflow-table-row.css'; export interface NetflowTableRowProps { + rowNumber?: number; allowPktDrops: boolean; lastRender?: string; flow: Record; @@ -23,6 +24,7 @@ export interface NetflowTableRowProps { } export const NetflowTableRow: React.FC = ({ + rowNumber, allowPktDrops, lastRender, flow, @@ -43,6 +45,7 @@ export const NetflowTableRow: React.FC = ({ return ( = React.forwardRef( return getSortedFlows().map((f, i) => ( { - if (!isValidICMPProto(p) || !t || !c) { + if (!isValidICMPProto(p) || t === undefined || c === undefined) { return undefined; } From 25d02eb3b17905113f09f78e02bc6f73e33b0a11 Mon Sep 17 00:00:00 2001 From: Julien Pinsonneau Date: Thu, 19 Sep 2024 14:38:18 +0200 Subject: [PATCH 2/5] fix columns count --- web/cypress/support/const.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/cypress/support/const.ts b/web/cypress/support/const.ts index f4e09c9c5..555c198cd 100644 --- a/web/cypress/support/const.ts +++ b/web/cypress/support/const.ts @@ -11,6 +11,6 @@ export const defaultPanelsCount = 2; // table specific config export const availableColumnGroupCount = 29; -export const availableColumnCount = 55; +export const availableColumnCount = 56; export const defaultColumnGroupCount = 6; export const defaultColumnCount = 11; \ No newline at end of file From ea9b9980ac9a4731bc6f9e34592781b854d7e950 Mon Sep 17 00:00:00 2001 From: Julien Pinsonneau Date: Thu, 19 Sep 2024 15:39:43 +0200 Subject: [PATCH 3/5] skip if not using mocks --- pkg/config/config.go | 2 ++ web/cypress/e2e/table/fields.spec.ts | 19 ++++++++++++++++++- web/src/model/config.ts | 2 ++ 3 files changed, 22 insertions(+), 1 deletion(-) diff --git a/pkg/config/config.go b/pkg/config/config.go index e64082a3e..3e34c7bb7 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -127,6 +127,7 @@ type Frontend struct { Deduper Deduper `yaml:"deduper" json:"deduper"` Fields []FieldConfig `yaml:"fields" json:"fields"` DataSources []string `yaml:"dataSources" json:"dataSources"` + LokiMocks bool `yaml:"lokiMocks,omitempty" json:"lokiMocks,omitempty"` PromLabels []string `yaml:"promLabels" json:"promLabels"` MaxChunkAgeMs int `yaml:"maxChunkAgeMs,omitempty" json:"maxChunkAgeMs,omitempty"` // populated at query time } @@ -196,6 +197,7 @@ func ReadFile(version, date, filename string) (*Config, error) { if cfg.IsLokiEnabled() { cfg.Frontend.DataSources = append(cfg.Frontend.DataSources, string(constants.DataSourceLoki)) + cfg.Frontend.LokiMocks = cfg.Loki.UseMocks } if cfg.IsPromEnabled() { diff --git a/web/cypress/e2e/table/fields.spec.ts b/web/cypress/e2e/table/fields.spec.ts index 9694b2e39..1169592aa 100644 --- a/web/cypress/e2e/table/fields.spec.ts +++ b/web/cypress/e2e/table/fields.spec.ts @@ -1,10 +1,22 @@ /// -import * as c from '../../support/const' +import * as c from '../../support/const'; + +let useMocks = false describe('netflow-table', () => { function reload(clearCache = true) { + cy.intercept({ + method: 'GET', + url: c.url + '/api/frontend-config', + }).as('frontend-config') + cy.openNetflowTrafficPage(clearCache); + + cy.wait('@frontend-config').then((interception) => { + useMocks = interception?.response.body.lokiMocks || false; + }) + //move to table view cy.get('.tableTabButton').click(); //clear default app filters @@ -18,6 +30,11 @@ describe('netflow-table', () => { }); it('display content correctly', () => { + if (!useMocks) { + it.skip("Skipping test since not using mocks"); + return + } + // select first row cy.get('#netflow-table-row-0').click() // check for side panel content diff --git a/web/src/model/config.ts b/web/src/model/config.ts index 071f961b0..ca8bf4ab1 100644 --- a/web/src/model/config.ts +++ b/web/src/model/config.ts @@ -29,6 +29,7 @@ export type Config = { deduper: Deduper; fields: FieldConfig[]; dataSources: string[]; + lokiMocks: boolean; promLabels: string[]; maxChunkAgeMs?: number; }; @@ -54,6 +55,7 @@ export const defaultConfig: Config = { }, fields: [], dataSources: ['loki', 'prom'], + lokiMocks: false, promLabels: [], maxChunkAgeMs: undefined }; From 75bb99998861b2bf65f923ad2aa98d9266fb3a30 Mon Sep 17 00:00:00 2001 From: Julien Pinsonneau Date: Thu, 19 Sep 2024 16:34:58 +0200 Subject: [PATCH 4/5] increase column group count --- web/cypress/support/const.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/cypress/support/const.ts b/web/cypress/support/const.ts index 555c198cd..c8de7ece0 100644 --- a/web/cypress/support/const.ts +++ b/web/cypress/support/const.ts @@ -10,7 +10,7 @@ export const availablePanelsCount = 4; export const defaultPanelsCount = 2; // table specific config -export const availableColumnGroupCount = 29; +export const availableColumnGroupCount = 30; export const availableColumnCount = 56; export const defaultColumnGroupCount = 6; export const defaultColumnCount = 11; \ No newline at end of file From 40f214e16158664de4b4f2fd08c777fb1383a654 Mon Sep 17 00:00:00 2001 From: Julien Pinsonneau Date: Thu, 19 Sep 2024 16:45:37 +0200 Subject: [PATCH 5/5] force mocks data --- web/cypress/e2e/table/fields.spec.ts | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/web/cypress/e2e/table/fields.spec.ts b/web/cypress/e2e/table/fields.spec.ts index 1169592aa..a397cc9fc 100644 --- a/web/cypress/e2e/table/fields.spec.ts +++ b/web/cypress/e2e/table/fields.spec.ts @@ -1,22 +1,19 @@ /// import * as c from '../../support/const'; - -let useMocks = false +import data from './../../../../mocks/loki/flow_records.json'; describe('netflow-table', () => { function reload(clearCache = true) { - cy.intercept({ - method: 'GET', - url: c.url + '/api/frontend-config', - }).as('frontend-config') + // this test bench only work with mocks + cy.intercept('GET', c.url + '/api/loki/flow/records?*', (req) => { + req.continue((res) => { + res.body = data; + }) + }); cy.openNetflowTrafficPage(clearCache); - cy.wait('@frontend-config').then((interception) => { - useMocks = interception?.response.body.lokiMocks || false; - }) - //move to table view cy.get('.tableTabButton').click(); //clear default app filters @@ -30,11 +27,6 @@ describe('netflow-table', () => { }); it('display content correctly', () => { - if (!useMocks) { - it.skip("Skipping test since not using mocks"); - return - } - // select first row cy.get('#netflow-table-row-0').click() // check for side panel content