fix: Allow OCI detection for stopped containers
- Refactored enrichContainerMetadata to not return early when container is stopped - Status API calls are still skipped for stopped containers (as expected) - Config fetch now runs regardless of status, enabling OCI detection - Added test for OCI detection on stopped containers Discovered: Proxmox 9.1 requires VM.Config.Options permission to read OCI container configs (not just VM.Audit). Document this in setup guides.
This commit is contained in:
parent
2226bdacf8
commit
689f229c72
2 changed files with 172 additions and 97 deletions
65
internal/monitoring/enrich_container_metadata_test.go
Normal file
65
internal/monitoring/enrich_container_metadata_test.go
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
package monitoring
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/rcourtman/pulse-go-rewrite/internal/models"
|
||||
"github.com/rcourtman/pulse-go-rewrite/pkg/proxmox"
|
||||
)
|
||||
|
||||
type stubPVEClientContainerMetadata struct {
|
||||
stubPVEClient
|
||||
|
||||
config map[string]interface{}
|
||||
|
||||
configCalls int
|
||||
statusCalls int
|
||||
}
|
||||
|
||||
func (s *stubPVEClientContainerMetadata) GetContainerConfig(ctx context.Context, node string, vmid int) (map[string]interface{}, error) {
|
||||
s.configCalls++
|
||||
return s.config, nil
|
||||
}
|
||||
|
||||
func (s *stubPVEClientContainerMetadata) GetContainerStatus(ctx context.Context, node string, vmid int) (*proxmox.Container, error) {
|
||||
s.statusCalls++
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func TestEnrichContainerMetadata_DetectsOCIForStoppedContainer(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
monitor := &Monitor{}
|
||||
client := &stubPVEClientContainerMetadata{
|
||||
config: map[string]interface{}{
|
||||
"entrypoint": "/bin/sh",
|
||||
"ostype": "unmanaged",
|
||||
"cmode": "console",
|
||||
"lxc": "lxc.signal.halt: SIGTERM",
|
||||
},
|
||||
}
|
||||
|
||||
container := &models.Container{
|
||||
VMID: 300,
|
||||
Name: "oci-alpine",
|
||||
Status: "stopped",
|
||||
Type: "lxc",
|
||||
}
|
||||
|
||||
monitor.enrichContainerMetadata(context.Background(), client, "delly", "delly", container)
|
||||
|
||||
if client.configCalls != 1 {
|
||||
t.Fatalf("expected 1 config call, got %d", client.configCalls)
|
||||
}
|
||||
if client.statusCalls != 0 {
|
||||
t.Fatalf("expected 0 status calls for stopped container, got %d", client.statusCalls)
|
||||
}
|
||||
if !container.IsOCI {
|
||||
t.Fatalf("expected container.IsOCI true, got false")
|
||||
}
|
||||
if container.Type != "oci" {
|
||||
t.Fatalf("expected container.Type oci, got %q", container.Type)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2358,12 +2358,16 @@ func (m *Monitor) enrichContainerMetadata(ctx context.Context, client PVEClientI
|
|||
|
||||
ensureContainerRootDiskEntry(container)
|
||||
|
||||
if client == nil || container.Status != "running" {
|
||||
if client == nil {
|
||||
return
|
||||
}
|
||||
|
||||
isRunning := container.Status == "running"
|
||||
|
||||
var status *proxmox.Container
|
||||
if isRunning {
|
||||
statusCtx, cancel := context.WithTimeout(ctx, 5*time.Second)
|
||||
status, err := client.GetContainerStatus(statusCtx, nodeName, container.VMID)
|
||||
statusResp, err := client.GetContainerStatus(statusCtx, nodeName, container.VMID)
|
||||
cancel()
|
||||
if err != nil {
|
||||
log.Debug().
|
||||
|
|
@ -2373,10 +2377,9 @@ func (m *Monitor) enrichContainerMetadata(ctx context.Context, client PVEClientI
|
|||
Str("container", container.Name).
|
||||
Int("vmid", container.VMID).
|
||||
Msg("Container status metadata unavailable")
|
||||
return
|
||||
} else {
|
||||
status = statusResp
|
||||
}
|
||||
if status == nil {
|
||||
return
|
||||
}
|
||||
|
||||
rootDeviceHint := ""
|
||||
|
|
@ -2396,6 +2399,7 @@ func (m *Monitor) enrichContainerMetadata(ctx context.Context, client PVEClientI
|
|||
addressOrder = append(addressOrder, addr)
|
||||
}
|
||||
|
||||
if status != nil {
|
||||
for _, addr := range sanitizeGuestAddressStrings(status.IP) {
|
||||
addAddress(addr)
|
||||
}
|
||||
|
|
@ -2408,8 +2412,11 @@ func (m *Monitor) enrichContainerMetadata(ctx context.Context, client PVEClientI
|
|||
for _, addr := range parseContainerRawIPs(status.IPv6) {
|
||||
addAddress(addr)
|
||||
}
|
||||
}
|
||||
|
||||
networkIfaces := make([]models.GuestNetworkInterface, 0, len(status.Network))
|
||||
networkIfaces := make([]models.GuestNetworkInterface, 0, 4)
|
||||
if status != nil {
|
||||
networkIfaces = make([]models.GuestNetworkInterface, 0, len(status.Network))
|
||||
for rawName, cfg := range status.Network {
|
||||
if cfg == (proxmox.ContainerNetworkConfig{}) {
|
||||
continue
|
||||
|
|
@ -2447,6 +2454,7 @@ func (m *Monitor) enrichContainerMetadata(ctx context.Context, client PVEClientI
|
|||
networkIfaces = append(networkIfaces, iface)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
configCtx, cancelConfig := context.WithTimeout(ctx, 5*time.Second)
|
||||
configData, configErr := client.GetContainerConfig(configCtx, nodeName, container.VMID)
|
||||
|
|
@ -2510,6 +2518,7 @@ func (m *Monitor) enrichContainerMetadata(ctx context.Context, client PVEClientI
|
|||
}
|
||||
|
||||
if len(addressOrder) == 0 {
|
||||
if isRunning {
|
||||
interfacesCtx, cancelInterfaces := context.WithTimeout(ctx, 5*time.Second)
|
||||
ifaceDetails, ifaceErr := client.GetContainerInterfaces(interfacesCtx, nodeName, container.VMID)
|
||||
cancelInterfaces()
|
||||
|
|
@ -2566,6 +2575,7 @@ func (m *Monitor) enrichContainerMetadata(ctx context.Context, client PVEClientI
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(networkIfaces) > 1 {
|
||||
sort.SliceStable(networkIfaces, func(i, j int) bool {
|
||||
|
|
|
|||
Loading…
Reference in a new issue