mirror of
https://github.com/mulgadc/spinifex.git
synced 2026-10-21 19:56:33 +00:00
fix: localSystemID + discoverChassis use Output() to skip sudo PAM noise
Follow-up to d509df7. The sudo PAM audit bug exists in two more vpcd call
sites beyond portToBr: localSystemID() and discoverChassis().
When vpcd.service's AmbientCapabilities trip sudo's PAM, stderr carries
"sudo: unable to send audit message: Operation not permitted". CombinedOutput
merges that into stdout and corrupts the parsed value:
localSystemID → localID="sudo: ...\n\"add0104e-..."
discoverChassis → tries to parse the stderr banner as chassis name/hostname
Downstream effect: discoverChassis skips the real local chassis as "stale",
vpcd falls back to cfg.ChassisNames (e.g. "chassis-josh-banksia") which no
chassis in SBDB actually uses, so every gateway_chassis row points at a
phantom chassis. cr-gw* chassisredirect ports never bind → no proxy-ARP
for EIPs → external ping fails with ARP timeout.
Switch both to Output() + exec.ExitError.Stderr, matching d509df7's pattern.
Found during mulga-998.b reboot drill while verifying external reachability:
chassis discovery log showed `localID="sudo: unable to send audit message...`,
`cr-gw-vpc-* chassis=[]`, and host ping to EIP returned Destination Host
Unreachable. With this fix applied, discoverChassis returns the real system-id
and (after stale gateway_chassis rows are cleared) cr-gw binds, proxy-ARP
responds, and EIP ping succeeds end-to-end.
Note: existing gateway_chassis rows written pre-fix still carry the phantom
chassis_name. Cleanup is one-shot — delete those rows and trigger an IGW
detach+attach, or run reset-dev-env.sh. vpcd does not reconcile existing
rows on startup (potential future retrofit, similar to Fix 3's
RetrofitAllExternalLocalnetOptions).
This commit is contained in:
@@ -183,10 +183,22 @@ var checkOVNController = func() error {
|
||||
|
||||
// localSystemID returns the OVS external-ids:system-id, which is the chassis
|
||||
// name that the local ovn-controller registers in the Southbound DB.
|
||||
//
|
||||
// Uses Output() (stdout only) for the same reason as portToBr: vpcd.service's
|
||||
// AmbientCapabilities trips sudo's PAM into emitting audit warnings on stderr,
|
||||
// which CombinedOutput would merge into stdout and poison the system-id.
|
||||
// A corrupted localID causes discoverChassis to skip the live chassis as
|
||||
// "stale", leaving gateway_chassis pointing at a fallback name that no real
|
||||
// chassis owns → cr-gw* chassisredirect ports stay unbound → no proxy-ARP
|
||||
// for EIPs.
|
||||
var localSystemID = func() (string, error) {
|
||||
out, err := sudoCommand("ovs-vsctl", "get", "open_vswitch", ".", "external-ids:system-id").CombinedOutput()
|
||||
out, err := sudoCommand("ovs-vsctl", "get", "open_vswitch", ".", "external-ids:system-id").Output()
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("ovs-vsctl get system-id: %s: %w", strings.TrimSpace(string(out)), err)
|
||||
var stderr string
|
||||
if exitErr, ok := err.(*exec.ExitError); ok {
|
||||
stderr = strings.TrimSpace(string(exitErr.Stderr))
|
||||
}
|
||||
return "", fmt.Errorf("ovs-vsctl get system-id: %s: %w", stderr, err)
|
||||
}
|
||||
// ovs-vsctl wraps the value in quotes
|
||||
return strings.Trim(strings.TrimSpace(string(out)), "\""), nil
|
||||
@@ -211,9 +223,15 @@ var discoverChassis = func(sbAddr string) ([]string, error) {
|
||||
// OVN 25.03+ removed the "list-chassis" convenience command.
|
||||
// Use "--columns=name,hostname list Chassis" which works on all versions.
|
||||
args = append(args, "--bare", "--columns=name,hostname", "list", "Chassis")
|
||||
out, err := sudoCommand("ovn-sbctl", args...).CombinedOutput()
|
||||
// Output() not CombinedOutput(): sudo PAM audit noise on stderr would
|
||||
// otherwise be parsed as chassis name/hostname pairs.
|
||||
out, err := sudoCommand("ovn-sbctl", args...).Output()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("ovn-sbctl list Chassis: %s: %w", strings.TrimSpace(string(out)), err)
|
||||
var stderr string
|
||||
if exitErr, ok := err.(*exec.ExitError); ok {
|
||||
stderr = strings.TrimSpace(string(exitErr.Stderr))
|
||||
}
|
||||
return nil, fmt.Errorf("ovn-sbctl list Chassis: %s: %w", stderr, err)
|
||||
}
|
||||
|
||||
return parseChassisList(string(out), localID, localHostname), nil
|
||||
|
||||
Reference in New Issue
Block a user