package agent import ( "context" "os" "os/exec" "path/filepath" "git.wntrmute.dev/mc/mcp/internal/config" "git.wntrmute.dev/mc/mcp/internal/runtime" ) // unikernelSupported reports whether this node can run Nanos unikernels: // it needs KVM (/dev/kvm) and the `ops` toolchain on PATH. func unikernelSupported() bool { if _, err := os.Stat("/dev/kvm"); err != nil { return false } if _, err := exec.LookPath("ops"); err != nil { return false } return true } // homeDir returns the agent's working directory (where images/ and vm/ live), // derived from the registry database path (e.g. /srv/mcp/mcp.db -> /srv/mcp). func homeDir(cfg *config.AgentConfig) string { if cfg != nil && cfg.Database.Path != "" { return filepath.Dir(cfg.Database.Path) } if h := os.Getenv("HOME"); h != "" { return h } return "/srv/mcp" } // runtimeFor selects the runtime backend for a component's declared runtime. // Unknown or empty runtimes fall back to the container runtime. If a service // requests "unikernel" but this node lacks the unikernel runtime, it falls // back to the container runtime (the master should not place it here). func (a *Agent) runtimeFor(rt string) runtime.Runtime { if rt == "unikernel" && a.Unikernel != nil { return a.Unikernel } return a.Runtime } // listAllContainers returns the observed state across every configured // runtime (containers + unikernel VMs) so reconciliation, status, and drift // detection see the whole picture. func (a *Agent) listAllContainers(ctx context.Context) ([]runtime.ContainerInfo, error) { infos, err := a.Runtime.List(ctx) if err != nil { return nil, err } if a.Unikernel != nil { vms, vmErr := a.Unikernel.List(ctx) if vmErr == nil { infos = append(infos, vms...) } else if a.Logger != nil { a.Logger.Warn("list unikernel VMs failed", "err", vmErr) } } return infos, nil }