package cmd import ( "fmt" "log/slog" "time" "github.com/portainer/kubesolo-os/update/pkg/health" ) // Healthcheck performs post-boot health verification. // If all checks pass, it marks the boot as successful in GRUB. // This should be run after every boot (typically via a systemd unit or // init script) to confirm the system is healthy. func Healthcheck(args []string) error { opts := parseOpts(args) env := opts.NewBootEnv() // Check if already marked successful success, err := env.BootSuccess() if err != nil { slog.Warn("could not read boot_success", "error", err) } if success { fmt.Println("Boot already marked successful") return nil } timeout := time.Duration(opts.TimeoutSecs) * time.Second checker := health.NewChecker("", "", timeout) slog.Info("running post-boot health checks", "timeout", timeout) status, err := checker.WaitForHealthy() if err != nil { fmt.Printf("Health check FAILED: %s\n", status.Message) fmt.Printf(" containerd: %v\n", status.Containerd) fmt.Printf(" apiserver: %v\n", status.APIServer) fmt.Printf(" node_ready: %v\n", status.NodeReady) fmt.Println("\nBoot NOT marked successful — system may roll back on next reboot") return err } // Mark boot as successful if err := env.MarkBootSuccess(); err != nil { return fmt.Errorf("marking boot success: %w", err) } fmt.Println("Health check PASSED — boot marked successful") fmt.Printf(" containerd: %v\n", status.Containerd) fmt.Printf(" apiserver: %v\n", status.APIServer) fmt.Printf(" node_ready: %v\n", status.NodeReady) return nil }