From a6c98d3e3cf1df5d2ad20561a526b137796d2e00 Mon Sep 17 00:00:00 2001 From: James Nesbitt Date: Thu, 30 Apr 2026 14:07:05 +0300 Subject: [PATCH] windows configurer: remove pre-delete race from Reboot() schtasks /run returns before shutdown.exe starts. The immediate schtasks /delete was cancelling the pending shutdown before it could fire, causing waitForHost to time out with 'still online'. Remove the pre-delete. The ONSTART task re-fires on next startup, which is safe: the post-reboot cleanup in InstallMCR deletes LaunchpadReboot once the host is back up. --- pkg/configurer/windows.go | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/pkg/configurer/windows.go b/pkg/configurer/windows.go index 77ebc024..f961d2a7 100644 --- a/pkg/configurer/windows.go +++ b/pkg/configurer/windows.go @@ -143,10 +143,8 @@ func isExitCode3010(err error) bool { // TODO: move this fix upstream into the k0sproject/rig Windows configurer. func (c WindowsConfigurer) Reboot(h os.Host) error { const taskName = "LaunchpadReboot" - // Create a SYSTEM-context ONSTART task that runs 'shutdown /r /f /t 5'. - // The 5-second delay gives us time to delete the task before the OS - // actually executes the reboot, preventing it from firing again on the - // next startup. + // The ONSTART trigger means the task will re-fire on the next startup, but + // the post-reboot cleanup in InstallMCR deletes it once the host is back up. create := fmt.Sprintf(`schtasks /create /tn "%s" /tr "shutdown /r /f /t 5" /sc onstart /f /ru SYSTEM`, taskName) if err := h.Exec(create); err != nil { return fmt.Errorf("failed to create reboot task: %w", err) @@ -160,14 +158,6 @@ func (c WindowsConfigurer) Reboot(h os.Host) error { return fmt.Errorf("failed to run reboot task: %w", err) } } - // Delete the task immediately while the 5-second shutdown timer is still - // counting down. This prevents it from re-firing on subsequent startups. - del := fmt.Sprintf(`schtasks /delete /tn "%s" /f`, taskName) - if err := h.Exec(del); err != nil { - // Best-effort: warn but don't fail — the post-reboot cleanup in - // InstallMCR will attempt deletion again once the host is back up. - log.Warnf("%v: failed to pre-delete reboot task (will retry after reboot): %s", h, err) - } // Allow Windows time to complete shutdown before waitForHost begins polling. time.Sleep(15 * time.Second) return nil