diff --git a/pkg/graphviz/traceflow_test.go b/pkg/graphviz/traceflow_test.go index 349f69cade3..e864f9ea557 100644 --- a/pkg/graphviz/traceflow_test.go +++ b/pkg/graphviz/traceflow_test.go @@ -54,6 +54,17 @@ func TestGenGraph(t *testing.T) { Protocol: 1, TTL: 63, }, + TransportHeader: crdv1alpha1.TransportHeader{ + ICMP: &crdv1alpha1.ICMPEchoRequestHeader{ + ID: 123, + Sequence: 1, + }, + TCP: &crdv1alpha1.TCPHeader{ + SrcPort: 123, + DstPort: 1, + Flags: 2, + }, + }, Length: 84, SrcIP: "10.10.1.4", }, @@ -181,6 +192,143 @@ func TestGenGraph(t *testing.T) { }, } + liveTfWithSourceIPTwoNodes := crdv1alpha1.Traceflow{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-live-traceflow-source-ip-two-nodes", + }, + Spec: crdv1alpha1.TraceflowSpec{ + LiveTraffic: true, + Packet: crdv1alpha1.Packet{ + IPHeader: crdv1alpha1.IPHeader{ + Protocol: 1, + }, + TransportHeader: crdv1alpha1.TransportHeader{ + ICMP: &crdv1alpha1.ICMPEchoRequestHeader{ + ID: 123, + Sequence: 1, + }, + }, + }, + Source: crdv1alpha1.Source{ + IP: "192.168.225.5", + }, + }, + Status: crdv1alpha1.TraceflowStatus{ + CapturedPacket: &crdv1alpha1.Packet{ + DstIP: "10.10.0.2", + IPHeader: crdv1alpha1.IPHeader{ + Flags: 2, + Protocol: 1, + TTL: 63, + }, + TransportHeader: crdv1alpha1.TransportHeader{ + UDP: &crdv1alpha1.UDPHeader{ + SrcPort: 68, + DstPort: 80, + }, + }, + Length: 84, + SrcIP: "10.10.1.4", + }, + Phase: crdv1alpha1.Succeeded, + Results: []crdv1alpha1.NodeResult{ + { + Node: "k8s-node-worker-1", + Observations: []crdv1alpha1.Observation{ + { + Action: crdv1alpha1.ActionForwarded, + Component: crdv1alpha1.ComponentSpoofGuard, + }, + { + Action: crdv1alpha1.ActionForwarded, + Component: crdv1alpha1.ComponentForwarding, + ComponentInfo: "Output", + TunnelDstIP: "192.168.77.100", + }, + }, + }, + { + Node: "k8s-node-control-plane", + Observations: []crdv1alpha1.Observation{ + { + Action: crdv1alpha1.ActionReceived, + Component: crdv1alpha1.ComponentForwarding, + ComponentInfo: "Classification", + }, + { + Action: crdv1alpha1.ActionForwarded, + Component: crdv1alpha1.ComponentForwarding, + ComponentInfo: "Output", + }, + }, + }, + }, + }, + } + + nonliveTf := crdv1alpha1.Traceflow{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-non-live-traceflow", + }, + Spec: crdv1alpha1.TraceflowSpec{ + LiveTraffic: false, + Packet: crdv1alpha1.Packet{ + IPHeader: crdv1alpha1.IPHeader{ + Protocol: 1, + }, + TransportHeader: crdv1alpha1.TransportHeader{ + ICMP: &crdv1alpha1.ICMPEchoRequestHeader{ + ID: 123, + Sequence: 1, + }, + }, + }, + Source: crdv1alpha1.Source{ + Namespace: "default", + Pod: "pod-1", + }, + Destination: crdv1alpha1.Destination{ + Namespace: "default", + Pod: "pod-2", + }, + }, + Status: crdv1alpha1.TraceflowStatus{ + Phase: crdv1alpha1.Succeeded, + Results: []crdv1alpha1.NodeResult{ + { + Node: "k8s-node-worker-1", + Observations: []crdv1alpha1.Observation{ + { + Action: crdv1alpha1.ActionForwarded, + Component: crdv1alpha1.ComponentSpoofGuard, + }, + { + Action: crdv1alpha1.ActionForwarded, + Component: crdv1alpha1.ComponentForwarding, + ComponentInfo: "Output", + TunnelDstIP: "192.168.77.100", + }, + }, + }, + { + Node: "k8s-node-control-plane", + Observations: []crdv1alpha1.Observation{ + { + Action: crdv1alpha1.ActionReceived, + Component: crdv1alpha1.ComponentForwarding, + ComponentInfo: "Classification", + }, + { + Action: crdv1alpha1.ActionDropped, + Component: crdv1alpha1.ComponentNetworkPolicy, + ComponentInfo: "IngressRule", + }, + }, + }, + }, + }, + } + tfEgressFromLocalNode := crdv1alpha1.Traceflow{ ObjectMeta: metav1.ObjectMeta{ Name: "test-traceflow-egress-local-node", @@ -257,7 +405,7 @@ Tunnel Destination IP : 192.168.77.100", shape=box, style="rounded,filled,solid" labeljust=r; style="filled,bold"; "10.10.0.2" [ color="#808080", fillcolor="#C8C8C8", style="filled,bold" ]; - capturedPacket [ color="#696969", label="Captured Packet:\lSource IP: 10.10.1.4\lDestination IP: 10.10.0.2\lLength: 84\lIPv4 Header: \l Flags: 2\l Protocol: 1\l TTL: 63\l", shape=note, style="rounded,filled,solid" ]; + capturedPacket [ color="#696969", label="Captured Packet:\lSource IP: 10.10.1.4\lDestination IP: 10.10.0.2\lLength: 84\lIPv4 Header: \l Flags: 2\l Protocol: 1\l TTL: 63\lTransport Header: \l TCP: \l Source Port: 123\l Destination Port: 1\l ICMP: \l ID: 123\l Sequence: 1\l", shape=note, style="rounded,filled,solid" ]; cluster_destination_1 [ color="#696969", fillcolor="#DCDCDC", label="Forwarding Output Delivered", shape=box, style="rounded,filled,solid" ]; @@ -339,6 +487,93 @@ Delivered", shape=box, style="rounded,filled,solid" ]; } ; +} +` + + expectedOutputWithSourceIPTwoNodes := `digraph G { + center=true; + label="test-live-traceflow-source-ip-two-nodes"; + labelloc=t; + "192.168.225.5"->cluster_source_1[ color="#C0C0C0", dir=forward, minlen=1, penwidth=2.0 ]; + cluster_source_1->cluster_source_2[ color="#C0C0C0", dir=forward, minlen=1, penwidth=2.0 ]; + "10.10.0.2"->cluster_destination_1[ color="#C0C0C0", dir=back, minlen=1, penwidth=2.0 ]; + cluster_destination_1->cluster_destination_2[ color="#C0C0C0", dir=back, minlen=1, penwidth=2.0 ]; + cluster_source_2->cluster_destination_2[ color="#C0C0C0", constraint=false, dir=forward, penwidth=2.0 ]; + subgraph cluster_source { + bgcolor="#F8F8FF"; + label="k8s-node-worker-1"; + labeljust=l; + style="filled,bold"; + "192.168.225.5" [ color="#808080", fillcolor="#C8C8C8", style="filled,bold" ]; + cluster_source_1 [ color="#696969", fillcolor="#DCDCDC", label="SpoofGuard +Forwarded", shape=box, style="rounded,filled,solid" ]; + cluster_source_2 [ color="#696969", fillcolor="#DCDCDC", label="Forwarding +Output +Forwarded +Tunnel Destination IP : 192.168.77.100", shape=box, style="rounded,filled,solid" ]; + +} +; + subgraph cluster_destination { + bgcolor="#F8F8FF"; + label="k8s-node-control-plane"; + labeljust=r; + style="filled,bold"; + "10.10.0.2" [ color="#808080", fillcolor="#C8C8C8", style="filled,bold" ]; + capturedPacket [ color="#696969", label="Captured Packet:\lSource IP: 10.10.1.4\lDestination IP: 10.10.0.2\lLength: 84\lIPv4 Header: \l Flags: 2\l Protocol: 1\l TTL: 63\lTransport Header: \l UDP: \l Source Port: 68\l Destination Port: 80\l", shape=note, style="rounded,filled,solid" ]; + cluster_destination_1 [ color="#696969", fillcolor="#DCDCDC", label="Forwarding +Output +Forwarded", shape=box, style="rounded,filled,solid" ]; + cluster_destination_2 [ color="#696969", fillcolor="#DCDCDC", label="Forwarding +Classification +Received", shape=box, style="rounded,filled,solid" ]; + +} +; + +} +` + + expectedOutputWithNonliveTf := `digraph G { + center=true; + label="test-non-live-traceflow"; + labelloc=t; + "default/pod-1"->cluster_source_1[ color="#C0C0C0", dir=forward, minlen=1, penwidth=2.0 ]; + cluster_source_1->cluster_source_2[ color="#C0C0C0", dir=forward, minlen=1, penwidth=2.0 ]; + "default/pod-2"->cluster_destination_1[ color="#C0C0C0", dir=back, minlen=1, penwidth=2.0, style="invis" ]; + cluster_destination_1->cluster_destination_2[ color="#C0C0C0", dir=back, minlen=1, penwidth=2.0 ]; + cluster_source_2->cluster_destination_2[ color="#C0C0C0", constraint=false, dir=forward, penwidth=2.0 ]; + subgraph cluster_source { + bgcolor="#F8F8FF"; + label="k8s-node-worker-1"; + labeljust=l; + style="filled,bold"; + "default/pod-1" [ color="#808080", fillcolor="#C8C8C8", style="filled,bold" ]; + cluster_source_1 [ color="#696969", fillcolor="#DCDCDC", label="SpoofGuard +Forwarded", shape=box, style="rounded,filled,solid" ]; + cluster_source_2 [ color="#696969", fillcolor="#DCDCDC", label="Forwarding +Output +Forwarded +Tunnel Destination IP : 192.168.77.100", shape=box, style="rounded,filled,solid" ]; + +} +; + subgraph cluster_destination { + bgcolor="#F8F8FF"; + label="k8s-node-control-plane"; + labeljust=r; + style="filled,bold"; + "default/pod-2" [ color="#808080", fillcolor="#C8C8C8", style="filled,bold" ]; + cluster_destination_1 [ color="#B22222", fillcolor="#EDD5D5", label="NetworkPolicy +IngressRule +Dropped", shape=box, style="rounded,filled,solid" ]; + cluster_destination_2 [ color="#696969", fillcolor="#DCDCDC", label="Forwarding +Classification +Received", shape=box, style="rounded,filled,solid" ]; + +} +; + } ` @@ -391,6 +626,16 @@ ForwardedOutOfOverlay", shape=box, style="rounded,filled,solid" ]; traceflow: tfInOneNode, expectedOutput: expectedOutputInOneNode, }, + { + name: "live traceflow with source IP two Nodes", + traceflow: liveTfWithSourceIPTwoNodes, + expectedOutput: expectedOutputWithSourceIPTwoNodes, + }, + { + name: "live traceflow set to false", + traceflow: nonliveTf, + expectedOutput: expectedOutputWithNonliveTf, + }, { name: "traceflow egress from local Node", traceflow: tfEgressFromLocalNode, @@ -450,3 +695,80 @@ func TestGetTraceflowStatusMessage(t *testing.T) { }) } } + +func TestFindClusterString(t *testing.T) { + testCases := []struct { + name string + graphStr string + clusterName string + startIndex int + endIndex int + }{ + { + name: "Graph with cluster", + graphStr: `center=true; + label="test-traceflow-one-node"; + labelloc=t; + "default/pod-1"->cluster_source_1[ color="#C0C0C0", dir=forward, minlen=1, penwidth=2.0 ]; + cluster_source_1->cluster_source_2[ color="#C0C0C0", dir=forward, minlen=1, penwidth=2.0 ]; + cluster_source_2->"default/pod-2"[ color="#C0C0C0", dir=forward, penwidth=2.0 ]; + subgraph cluster_source { + bgcolor="#F8F8FF"; + label="k8s-node-1"; + labeljust=l; + style="filled,bold"; + "default/pod-1" [ color="#808080", fillcolor="#C8C8C8", style="filled,bold" ]; + "default/pod-2" [ color="#808080", fillcolor="#C8C8C8", style="filled,bold" ]; + cluster_source_1 [ color="#696969", fillcolor="#DCDCDC", label="SpoofGuard + Forwarded", shape=box, style="rounded,filled,solid" ]; + cluster_source_2 [ color="#696969", fillcolor="#DCDCDC", label="Forwarding + Output + Delivered", shape=box, style="rounded,filled,solid" ]; + + } + ; + + } + `, + clusterName: "cluster_source", + startIndex: 394, + endIndex: 1048, + }, + { + name: "Graph with no cluster", + graphStr: `center=true; + label="test-traceflow-one-node"; + labelloc=t; + "default/pod-1"->cluster_source_1[ color="#C0C0C0", dir=forward, minlen=1, penwidth=2.0 ]; + cluster_source_1->cluster_source_2[ color="#C0C0C0", dir=forward, minlen=1, penwidth=2.0 ]; + cluster_source_2->"default/pod-2"[ color="#C0C0C0", dir=forward, penwidth=2.0 ]; + subgraph cluster_source { + bgcolor="#F8F8FF"; + label="k8s-node-1"; + labeljust=l; + style="filled,bold"; + "default/pod-1" [ color="#808080", fillcolor="#C8C8C8", style="filled,bold" ]; + "default/pod-2" [ color="#808080", fillcolor="#C8C8C8", style="filled,bold" ]; + cluster_source_1 [ color="#696969", fillcolor="#DCDCDC", label="SpoofGuard + Forwarded", shape=box, style="rounded,filled,solid" ]; + cluster_source_2 [ color="#696969", fillcolor="#DCDCDC", label="Forwarding + Output + Delivered", shape=box, style="rounded,filled,solid" ]; + + } + ; + + } + `, + clusterName: "cluster_destination", + endIndex: 1, + }, + } + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + gotStartIndex, gotEndIndex := findClusterString(tc.graphStr, tc.clusterName) + assert.Equal(t, tc.startIndex, gotStartIndex) + assert.Equal(t, tc.endIndex, gotEndIndex) + }) + } +}