package hostmode import ( "context" "log" "os/exec" ) // cmdRebootForVetting is the Phase 2 command the orchestrator sends // when the operator clicked "Start vetting" and the host is actively // heartbeating — the agent redirects next boot to PXE and reboots // itself, obviating WoL. const cmdRebootForVetting = "reboot_for_vetting" // handleResponse dispatches on the heartbeat response. Phase 1 never // sees a non-empty Cmd (the server omits the field). Phase 2 adds // reboot_for_vetting handling. func handleResponse(ctx context.Context, resp *heartbeatResponse) { if resp == nil || resp.Cmd == "" { return } switch resp.Cmd { case cmdRebootForVetting: log.Printf("hostmode: orchestrator requested reboot_for_vetting (run=%d)", resp.RunID) rebootForVetting(ctx) default: log.Printf("hostmode: unknown cmd %q, ignoring", resp.Cmd) } } // rebootForVetting redirects next boot to PXE (best-effort on UEFI // via efibootmgr) and triggers a clean reboot. BIOS/legacy hosts // typically PXE-boot via DHCP chain on every boot, so efibootmgr // missing is non-fatal. func rebootForVetting(ctx context.Context) { setPXEBootNext(ctx) log.Printf("hostmode: executing systemctl reboot") if err := exec.CommandContext(ctx, "systemctl", "reboot").Run(); err != nil { log.Printf("hostmode: systemctl reboot failed: %v", err) } }