diff --git a/src/pxl_scripts/px/dx_evidence_graph/dx_evidence_graph.pxl b/src/pxl_scripts/px/dx_evidence_graph/dx_evidence_graph.pxl index 9c4231000c9..e45322a4ac6 100644 --- a/src/pxl_scripts/px/dx_evidence_graph/dx_evidence_graph.pxl +++ b/src/pxl_scripts/px/dx_evidence_graph/dx_evidence_graph.pxl @@ -19,7 +19,19 @@ import px def dx_attack_graph(start_time: str, clickhouse_dsn: str, table: str): df = px.DataFrame(table, clickhouse_dsn=clickhouse_dsn, start_time=start_time) - return df[['requestor_pod', 'responder_pod', + # Node identity: pod, else service, else IP. Edges whose peer is an IP or a + # non-pod entity (the k8s API server, an external endpoint, a consulted + # socket) have an empty *_pod; keying the graph on *_pod alone collapses ALL + # of them into one bogus "" node. Coalesce so each distinct peer is its own + # node — same idiom Pixie's net_flow_graph uses (px.select(src=='', src_ip, src)). + df.requestor = px.select(df.requestor_pod == '', + px.select(df.requestor_service == '', df.requestor_ip, df.requestor_service), + df.requestor_pod) + df.responder = px.select(df.responder_pod == '', + px.select(df.responder_service == '', df.responder_ip, df.responder_service), + df.responder_pod) + return df[['requestor', 'responder', + 'requestor_pod', 'responder_pod', 'requestor_service', 'responder_service', 'requestor_ip', 'responder_ip', 'weight', 'max_severity', 'confidence', diff --git a/src/pxl_scripts/px/dx_evidence_graph/vis.json b/src/pxl_scripts/px/dx_evidence_graph/vis.json index 9ed713b424b..facd8eacd19 100644 --- a/src/pxl_scripts/px/dx_evidence_graph/vis.json +++ b/src/pxl_scripts/px/dx_evidence_graph/vis.json @@ -40,8 +40,8 @@ "displaySpec": { "@type": "types.px.dev/px.vispb.Graph", "adjacencyList": { - "fromColumn": "requestor_pod", - "toColumn": "responder_pod" + "fromColumn": "requestor", + "toColumn": "responder" }, "edgeWeightColumn": "weight", "edgeColorColumn": "max_severity",