monitor: see unikernel VMs + use canonical container naming
Two drift-reporting bugs: 1. The monitor listed only the podman runtime, so unikernel VMs always showed observed=unknown (false drift). It now takes a ContainerLister and the agent passes a merged lister (containers + VMs), mirroring listAllContainers. 2. The monitor computed the lookup name as service+"-"+component, which is wrong when component==service (the name collapses to just the service, e.g. "uktest"/"mc-proxy"). It now uses the canonical naming.ContainerNameFor — extracted to a shared package so the agent and monitor can't disagree. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -78,7 +78,7 @@ func Run(cfg *config.AgentConfig, version string) error {
|
||||
uk = qemu
|
||||
}
|
||||
|
||||
mon := monitor.New(db, rt, cfg.Monitor, cfg.Agent.NodeName, logger)
|
||||
mon := monitor.New(db, mergedLister{primary: rt, extra: uk, logger: logger}, cfg.Monitor, cfg.Agent.NodeName, logger)
|
||||
|
||||
proxy, err := NewProxyRouter(cfg.MCProxy.Socket, cfg.MCProxy.CertDir, logger)
|
||||
if err != nil {
|
||||
|
||||
@@ -1,34 +1,14 @@
|
||||
package agent
|
||||
|
||||
import "strings"
|
||||
import "git.wntrmute.dev/mc/mcp/internal/naming"
|
||||
|
||||
// ContainerNameFor returns the expected container name for a service and
|
||||
// component. For single-component services where the component name equals
|
||||
// the service name, the container name is just the service name (e.g.,
|
||||
// "mc-proxy" not "mc-proxy-mc-proxy").
|
||||
// ContainerNameFor is a convenience alias for naming.ContainerNameFor (the
|
||||
// canonical convention, shared with the monitor).
|
||||
func ContainerNameFor(service, component string) string {
|
||||
if service == component {
|
||||
return service
|
||||
}
|
||||
return service + "-" + component
|
||||
return naming.ContainerNameFor(service, component)
|
||||
}
|
||||
|
||||
// SplitContainerName splits a container name into service and component parts.
|
||||
// It checks known service names first to handle names like "mc-proxy" where a
|
||||
// naive split on "-" would produce the wrong result. If no known service
|
||||
// matches, it falls back to splitting on the first "-".
|
||||
// SplitContainerName is a convenience alias for naming.SplitContainerName.
|
||||
func SplitContainerName(name string, knownServices map[string]bool) (service, component string) {
|
||||
if knownServices[name] {
|
||||
return name, name
|
||||
}
|
||||
for svc := range knownServices {
|
||||
prefix := svc + "-"
|
||||
if strings.HasPrefix(name, prefix) && len(name) > len(prefix) {
|
||||
return svc, name[len(prefix):]
|
||||
}
|
||||
}
|
||||
if i := strings.Index(name, "-"); i >= 0 {
|
||||
return name[:i], name[i+1:]
|
||||
}
|
||||
return name, name
|
||||
return naming.SplitContainerName(name, knownServices)
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package agent
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log/slog"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
@@ -54,21 +55,38 @@ func (a *Agent) runtimeFor(rt string) runtime.Runtime {
|
||||
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)
|
||||
// mergedLister lists observed containers across the container runtime and
|
||||
// (optionally) the unikernel runtime, so reconciliation, status, drift
|
||||
// detection, and the monitor see VMs and containers uniformly. It satisfies
|
||||
// the small lister interface the monitor consumes.
|
||||
type mergedLister struct {
|
||||
primary runtime.Runtime
|
||||
extra runtime.Runtime // unikernel runtime; may be nil
|
||||
logger *slog.Logger
|
||||
}
|
||||
|
||||
// List returns containers from the primary runtime plus, when configured,
|
||||
// unikernel VMs. A failure to list VMs is logged but not fatal — the
|
||||
// container view still reconciles.
|
||||
func (m mergedLister) List(ctx context.Context) ([]runtime.ContainerInfo, error) {
|
||||
infos, err := m.primary.List(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if a.Unikernel != nil {
|
||||
vms, vmErr := a.Unikernel.List(ctx)
|
||||
if m.extra != nil {
|
||||
vms, vmErr := m.extra.List(ctx)
|
||||
if vmErr == nil {
|
||||
infos = append(infos, vms...)
|
||||
} else if a.Logger != nil {
|
||||
a.Logger.Warn("list unikernel VMs failed", "err", vmErr)
|
||||
} else if m.logger != nil {
|
||||
m.logger.Warn("list unikernel VMs failed", "err", vmErr)
|
||||
}
|
||||
}
|
||||
return infos, nil
|
||||
}
|
||||
|
||||
// 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) {
|
||||
return mergedLister{primary: a.Runtime, extra: a.Unikernel, logger: a.Logger}.List(ctx)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user