mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-10-21 03:05:44 +00:00
Use authoritative Docker OOM evidence
This commit is contained in:
@@ -2162,6 +2162,7 @@ func resourceFromDockerContainer(ct models.DockerContainer, host models.DockerHo
|
||||
Health: ct.Health,
|
||||
RestartCount: ct.RestartCount,
|
||||
ExitCode: ct.ExitCode,
|
||||
OOMKilled: cloneBoolPtr(ct.OOMKilled),
|
||||
CPURawPercent: ct.CPUPercent,
|
||||
CPUCapacityPercent: models.DockerContainerCPUCapacityPercent(ct, host.CPUs),
|
||||
CPUCapacityCores: host.CPUs,
|
||||
|
||||
@@ -581,6 +581,7 @@ func TestResourceFromDockerHostOmitsStandaloneInactiveSwarm(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestResourceFromDockerContainerIncludesContainerID(t *testing.T) {
|
||||
oomKilled := false
|
||||
container := models.DockerContainer{
|
||||
ID: "aurora-3-abcdef123456",
|
||||
Name: "web",
|
||||
@@ -589,6 +590,7 @@ func TestResourceFromDockerContainerIncludesContainerID(t *testing.T) {
|
||||
ImageDigest: "sha256:current",
|
||||
UptimeSeconds: 1234,
|
||||
CPUPercent: 12.5,
|
||||
OOMKilled: &oomKilled,
|
||||
}
|
||||
|
||||
host := models.DockerHost{
|
||||
@@ -616,6 +618,13 @@ func TestResourceFromDockerContainerIncludesContainerID(t *testing.T) {
|
||||
if got, want := resource.Docker.ImageID, container.ImageDigest; got != want {
|
||||
t.Fatalf("imageId = %q, want %q", got, want)
|
||||
}
|
||||
if resource.Docker.OOMKilled == nil || *resource.Docker.OOMKilled {
|
||||
t.Fatalf("oomKilled = %v, want explicit false", resource.Docker.OOMKilled)
|
||||
}
|
||||
oomKilled = true
|
||||
if *resource.Docker.OOMKilled {
|
||||
t.Fatal("unified resource must own an independent OOM evidence value")
|
||||
}
|
||||
}
|
||||
|
||||
func TestResourceFromDockerContainerPreservesRuntimeMetadata(t *testing.T) {
|
||||
|
||||
@@ -225,6 +225,7 @@ func cloneDockerData(in *DockerData) *DockerData {
|
||||
return nil
|
||||
}
|
||||
out := *in
|
||||
out.OOMKilled = cloneBoolPtr(in.OOMKilled)
|
||||
out.Temperature = cloneFloat64Ptr(in.Temperature)
|
||||
out.LoadAverage = cloneFloat64Slice(in.LoadAverage)
|
||||
out.TokenLastUsedAt = cloneTimePtr(in.TokenLastUsedAt)
|
||||
|
||||
@@ -177,6 +177,38 @@ func TestOperationReceiptProtocolRemainsInternalToIngestAndRuntime(t *testing.T)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDockerOOMEvidenceRemainsAuthoritativeAcrossCanonicalIngest(t *testing.T) {
|
||||
monitorSource, err := os.ReadFile(filepath.Join("..", "monitoring", "monitor_agents.go"))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !regexp.MustCompile(`OOMKilled:\s+cloneReportBoolPtr\(payload\.OOMKilled\)`).Match(monitorSource) {
|
||||
t.Fatal("Docker report ingest must preserve and clone nullable runtime OOM evidence")
|
||||
}
|
||||
|
||||
oomKilled := false
|
||||
resource, _ := resourceFromDockerContainer(models.DockerContainer{
|
||||
ID: "container-oom-contract",
|
||||
Name: "contract-container",
|
||||
State: "exited",
|
||||
ExitCode: 137,
|
||||
OOMKilled: &oomKilled,
|
||||
}, models.DockerHost{ID: "docker-host-contract"})
|
||||
if resource.Docker == nil || resource.Docker.OOMKilled == nil || *resource.Docker.OOMKilled {
|
||||
t.Fatalf("canonical DockerData lost explicit non-OOM evidence: %+v", resource.Docker)
|
||||
}
|
||||
|
||||
oomKilled = true
|
||||
viewEvidence := NewDockerContainerView(&resource).OOMKilled()
|
||||
if viewEvidence == nil || *viewEvidence {
|
||||
t.Fatalf("typed Docker view aliased its source evidence: %v", viewEvidence)
|
||||
}
|
||||
*viewEvidence = true
|
||||
if got := NewDockerContainerView(&resource).OOMKilled(); got == nil || *got {
|
||||
t.Fatalf("typed Docker view must return an independent OOM evidence value: %v", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestProductionActionLifecycleDoesNotUseRecordActionAuditAsUpsert(t *testing.T) {
|
||||
paths := []string{"../actionlifecycle/service.go", "../ai/tools/action_audit.go", "../api/patrol_action_broker.go"}
|
||||
for _, path := range paths {
|
||||
|
||||
@@ -1009,6 +1009,7 @@ type DockerData struct {
|
||||
Health string `json:"health,omitempty"`
|
||||
RestartCount int `json:"restartCount,omitempty"`
|
||||
ExitCode int `json:"exitCode,omitempty"`
|
||||
OOMKilled *bool `json:"oomKilled,omitempty"`
|
||||
CPURawPercent float64 `json:"cpuRawPercent,omitempty"`
|
||||
CPUCapacityPercent float64 `json:"cpuCapacityPercent,omitempty"`
|
||||
CPUCapacityCores int `json:"cpuCapacityCores,omitempty"`
|
||||
|
||||
@@ -3812,6 +3812,13 @@ func (v DockerContainerView) ExitCode() int {
|
||||
return v.r.Docker.ExitCode
|
||||
}
|
||||
|
||||
func (v DockerContainerView) OOMKilled() *bool {
|
||||
if v.r == nil || v.r.Docker == nil {
|
||||
return nil
|
||||
}
|
||||
return cloneBoolPtr(v.r.Docker.OOMKilled)
|
||||
}
|
||||
|
||||
func (v DockerContainerView) CPUPercent() float64 {
|
||||
if v.r == nil {
|
||||
return 0
|
||||
|
||||
@@ -1186,6 +1186,7 @@ func TestView_StoragePoolViewUsesCanonicalMetricsTargetAndGenericNodeHints(t *te
|
||||
func TestView_DockerContainerViewMetricsTargetAccessor(t *testing.T) {
|
||||
now := time.Date(2026, 3, 31, 12, 0, 0, 0, time.UTC)
|
||||
parentID := "host-1"
|
||||
oomKilled := false
|
||||
r := &Resource{
|
||||
ID: "app-1",
|
||||
Type: ResourceTypeAppContainer,
|
||||
@@ -1201,6 +1202,7 @@ func TestView_DockerContainerViewMetricsTargetAccessor(t *testing.T) {
|
||||
ContainerID: "nextcloud",
|
||||
Image: "docker.io/library/nextcloud:29.0.7",
|
||||
ContainerState: "running",
|
||||
OOMKilled: &oomKilled,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -1221,6 +1223,15 @@ func TestView_DockerContainerViewMetricsTargetAccessor(t *testing.T) {
|
||||
if got := v.MetricsTarget(); got == nil || got.ResourceID != "nextcloud-web-1" {
|
||||
t.Fatalf("expected cloned docker container metrics target, got %+v", got)
|
||||
}
|
||||
|
||||
oom := v.OOMKilled()
|
||||
if oom == nil || *oom {
|
||||
t.Fatalf("expected explicit non-OOM view state, got %v", oom)
|
||||
}
|
||||
*oom = true
|
||||
if got := v.OOMKilled(); got == nil || *got {
|
||||
t.Fatalf("expected cloned OOM evidence, got %v", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestView_PBSAndPMGInstanceViewAccessors(t *testing.T) {
|
||||
|
||||
Reference in New Issue
Block a user