package api import ( "fmt" "time" "clicd/internal/config" "clicd/internal/kvm" "clicd/internal/lxc" ) // CaptureRuntimeRestoreState records which managed workloads are actually // running before the CLICD service exits. On the next host boot, only those // workloads are started again. func CaptureRuntimeRestoreState() { if config.AppConfig == nil { return } lxcManager := lxc.NewManager() kvmManager := kvm.NewManager() changed := false for i := range config.AppConfig.Containers { c := &config.AppConfig.Containers[i] status, err := runtimeStatus(*c, lxcManager, kvmManager) if err != nil { fmt.Printf("Warning: failed to capture runtime state for %s: %v\n", c.Name, err) continue } restore := status == "running" if c.RestoreOnHostBoot != restore { c.RestoreOnHostBoot = restore changed = true } if status != "" && c.Status != status { c.Status = status changed = true } } if changed { if err := config.SaveConfig(); err != nil { fmt.Printf("Warning: failed to save host boot restore state: %v\n", err) } } } func StartHostBootRestore() { go RestoreHostBootState() } func RestoreHostBootState() { if config.AppConfig == nil { return } time.Sleep(2 * time.Second) lxcManager := lxc.NewManager() kvmManager := kvm.NewManager() containers := append([]config.Container(nil), config.AppConfig.Containers...) for _, c := range containers { if !c.RestoreOnHostBoot { continue } if c.PolicyBlocked { fmt.Printf("Skipping host boot restore for %s: policy blocked\n", c.Name) continue } if lxc.IsExpired(c) { fmt.Printf("Skipping host boot restore for %s: expired at %s\n", c.Name, c.ExpiresAt) continue } status, err := runtimeStatus(c, lxcManager, kvmManager) if err == nil && status == "running" { config.UpdateContainerStatusAndRestore(c.ID, "running", true) if !c.IsKVM() { _ = lxcManager.ApplyPortMappings(c.ID) } else { _ = lxc.NewManager().ApplyPortMappings(c.ID) } continue } fmt.Printf("Restoring workload after host boot: %s (ID=%d)\n", c.Name, c.ID) if c.IsKVM() { if err := kvmManager.StartContainer(c.ID); err != nil { fmt.Printf("Warning: failed to restore KVM %s: %v\n", c.Name, err) } continue } if err := lxcManager.StartContainer(c.ID); err != nil { fmt.Printf("Warning: failed to restore LXC %s: %v\n", c.Name, err) } } lxc.EnsureAllRunningPortMappings() } func runtimeStatus(c config.Container, lxcManager *lxc.Manager, kvmManager *kvm.Manager) (string, error) { if c.IsKVM() { return kvmManager.GetContainerStatus(c.VirshName()) } return lxcManager.GetContainerStatus(c.LxcName()) }