mirror of
https://github.com/mulgadc/spinifex.git
synced 2026-10-22 12:16:52 +00:00
111 lines
3.8 KiB
Go
111 lines
3.8 KiB
Go
//go:build e2e
|
|
|
|
package harness
|
|
|
|
import (
|
|
"fmt"
|
|
"os/exec"
|
|
"testing"
|
|
|
|
"github.com/mulgadc/spinifex/spinifex/network/host"
|
|
)
|
|
|
|
// DumpIMDSDatapathDiagnostics emits a triage bundle for an IMDS reachability
|
|
// failure. Captures OVN port-binding state, per-subnet netns veth/route/neigh,
|
|
// conntrack, and br-int flows for both request and reply paths.
|
|
// Non-fatal — best-effort diagnostics; skips if OVN tooling or sudo unavailable.
|
|
func DumpIMDSDatapathDiagnostics(t *testing.T, subnetID, guestIP, artifactDir string) {
|
|
t.Helper()
|
|
fmt.Printf("\n%s%s── DIAGNOSTICS: IMDS datapath (subnet=%s guest=%s) ──%s\n",
|
|
colorBold, colorCyan, subnetID, guestIP, colorReset)
|
|
defer fmt.Printf("%s%s── END DIAGNOSTICS ──%s\n\n", colorBold, colorCyan, colorReset)
|
|
|
|
if _, err := exec.LookPath("ovn-nbctl"); err != nil {
|
|
fmt.Printf(" ovn-nbctl unavailable (%v); skipping IMDS datapath dump\n", err)
|
|
return
|
|
}
|
|
if err := exec.Command("sudo", "-n", "true").Run(); err != nil {
|
|
fmt.Printf(" passwordless sudo unavailable (%v); skipping IMDS datapath dump\n", err)
|
|
return
|
|
}
|
|
|
|
imdsPort := "imds-port-" + subnetID
|
|
subnetSwitch := "subnet-" + subnetID
|
|
hostEnd := host.IMDSHostVethName(subnetID)
|
|
ovsEnd := host.IMDSOVSPortName(subnetID)
|
|
netns := host.IMDSNetnsName(subnetID)
|
|
const imdsIP = "169.254.169.254"
|
|
|
|
// nsExec wraps an argv to run inside the per-subnet netns, where the host veth
|
|
// end and the IMDS listener now live.
|
|
nsExec := func(argv ...string) []string {
|
|
return append([]string{"ip", "netns", "exec", netns}, argv...)
|
|
}
|
|
|
|
runHostCaptures(t, artifactDir, []hostCapture{
|
|
{
|
|
filename: "imds-portbinding.txt",
|
|
label: "ovn-sbctl Port_Binding imds-port (chassis,up)",
|
|
argv: []string{"ovn-sbctl", "--bare", "--columns=logical_port,chassis,up,mac",
|
|
"find", "Port_Binding", "logical_port=" + imdsPort},
|
|
},
|
|
{
|
|
filename: "imds-lsp-nb.txt",
|
|
label: "ovn-nbctl imds-port LSP (type,addresses,options)",
|
|
argv: []string{"ovn-nbctl", "--bare", "--columns=name,type,addresses,options",
|
|
"find", "Logical_Switch_Port", "name=" + imdsPort},
|
|
},
|
|
{
|
|
filename: "imds-subnet-ports.txt",
|
|
label: "ovn-nbctl lsp-list subnet switch (localport present on the guest's switch?)",
|
|
argv: []string{"ovn-nbctl", "lsp-list", subnetSwitch},
|
|
grepFor: []string{imdsPort},
|
|
},
|
|
{
|
|
filename: "imds-netns.txt",
|
|
label: "ip netns list (per-subnet IMDS netns present?)",
|
|
argv: []string{"ip", "netns", "list"},
|
|
grepFor: []string{netns},
|
|
},
|
|
{
|
|
filename: "imds-host-veth-addr.txt",
|
|
label: "ip -d addr show imds-h in netns (expect 169.254.169.254/30 + subnet CIDR on-link)",
|
|
argv: nsExec("ip", "-d", "addr", "show", "dev", hostEnd),
|
|
},
|
|
{
|
|
filename: "imds-host-route-to-guest.txt",
|
|
label: "ip route get <guest> in netns (expect on-link dev imds-h, no gateway hop)",
|
|
argv: nsExec("ip", "route", "get", guestIP),
|
|
},
|
|
{
|
|
filename: "imds-host-neigh.txt",
|
|
label: "ip neigh show in netns (expect a resolved entry for the guest IP)",
|
|
argv: nsExec("ip", "neigh", "show"),
|
|
},
|
|
{
|
|
filename: "imds-listener.txt",
|
|
label: "ss -ltnp in netns (IMDS listener bound?)",
|
|
argv: nsExec("ss", "-ltnp"),
|
|
grepFor: []string{imdsIP, ":80"},
|
|
},
|
|
{
|
|
filename: "imds-conntrack.txt",
|
|
label: "conntrack -L in netns (169.254.169.254 — SYN_RECV = reply lost)",
|
|
argv: nsExec("conntrack", "-L"),
|
|
grepFor: []string{imdsIP},
|
|
},
|
|
{
|
|
filename: "imds-ovs-flows.txt",
|
|
label: "ovs-ofctl dump-flows br-int (IMDS + guest, filtered)",
|
|
argv: []string{"ovs-ofctl", "dump-flows", "br-int"},
|
|
grepFor: []string{imdsIP, guestIP},
|
|
},
|
|
{
|
|
filename: "imds-ovs-iface.txt",
|
|
label: "ovs-vsctl Interface imds-o (iface-id binding, ofport)",
|
|
argv: []string{"ovs-vsctl", "--columns=name,external_ids,ofport",
|
|
"list", "Interface", ovsEnd},
|
|
},
|
|
})
|
|
}
|