Resolve docker alert resource IDs in Patrol scope resolution

Have Patrol investigate on a Docker container or host alert returned
patrol_scope_unresolved because alerts publish docker:<host>/<container>
and docker:<host> identities while patrol runtime records only carried
unified IDs, raw container IDs, and names. Register the alert-form
identities as known scope aliases on docker host and container records,
exporting the alerts helper so the format cannot drift between the two
subsystems. The automatic alert-fired patrol path sends the same
identity, so scoped runs it triggered for docker alerts were failing
resolution the same way.

Refs discussion #1699

Contract-Neutral: behavioral bug fix refs discussion 1699: patrol scope resolution could not resolve docker alert resource IDs; no public contract delta
This commit is contained in:
rcourtman
2026-08-14 06:26:15 +01:00
parent ff8479157f
commit ec8b88fe27
8 changed files with 91 additions and 49 deletions
+27
View File
@@ -7,6 +7,7 @@ import (
"time"
"github.com/prometheus/client_golang/prometheus/testutil"
"github.com/rcourtman/pulse-go-rewrite/internal/alerts"
"github.com/rcourtman/pulse-go-rewrite/internal/models"
"github.com/rcourtman/pulse-go-rewrite/internal/unifiedresources"
)
@@ -85,6 +86,32 @@ func TestResolvePatrolScopeCanonicalIDOutranksAliasCollision(t *testing.T) {
}
}
func TestResolvePatrolScopeResolvesDockerAlertResourceIDs(t *testing.T) {
snapshot := models.StateSnapshot{DockerHosts: []models.DockerHost{{
ID: "nas", Hostname: "nas",
Containers: []models.DockerContainer{{ID: "abc123def456", Name: "dockhand-hawser-updater-nas", State: "exited"}},
}}}
containerAlertID := alerts.DockerResourceID("nas", "abc123def456")
hostAlertID := alerts.DockerResourceID("nas", "")
snapshotState := newPatrolRuntimeState(snapshot)
registry := unifiedresources.NewRegistry(nil)
registry.IngestSnapshot(snapshot)
readState := newPatrolRuntimeStateWithProviders(snapshot, registry, unifiedresources.NewUnifiedAIAdapter(registry))
for _, state := range []patrolRuntimeState{snapshotState, readState} {
for _, requested := range []string{containerAlertID, hostAlertID} {
resolved, resolution := resolvePatrolScopeState(state, PatrolScope{ResourceIDs: []string{requested}})
if len(resolution.UnmatchedResourceIDs) != 0 || len(resolution.AmbiguousResourceIDs) != 0 {
t.Fatalf("alert resource ID %q did not resolve exactly: %+v", requested, resolution)
}
if len(resolved.ResourceIDs) == 0 {
t.Fatalf("alert resource ID %q resolved to an empty scope", requested)
}
}
}
}
func TestRunScopedPatrolPersistsZeroMatchFailure(t *testing.T) {
ps := NewPatrolService(nil, &mockStateProvider{state: models.StateSnapshot{
Nodes: []models.Node{{ID: "node-1", Name: "pve-1"}},
+17 -4
View File
@@ -4,10 +4,23 @@ import (
"sort"
"strings"
"github.com/rcourtman/pulse-go-rewrite/internal/alerts"
"github.com/rcourtman/pulse-go-rewrite/internal/models"
"github.com/rcourtman/pulse-go-rewrite/internal/unifiedresources"
)
// dockerAlertScopeAlias mirrors the alert subsystem's docker resource IDs
// ("docker:<host>" and "docker:<host>/<container>") so an alert's resource ID
// resolves to the patrol runtime record for that host or container (#1699).
// Returns "" without a host part rather than the shared "docker:unknown"
// fallback, which would alias unrelated records together.
func dockerAlertScopeAlias(hostID, containerID string) string {
if strings.TrimSpace(hostID) == "" {
return ""
}
return alerts.DockerResourceID(hostID, containerID)
}
type patrolRuntimeResourceKind string
const (
@@ -187,12 +200,12 @@ func patrolVisitRuntimeResources(s patrolRuntimeState, visit func(patrolRuntimeR
}
}
for _, dh := range rs.DockerHosts() {
if !emit(patrolRuntimeResourceDockerHost, []string{dh.ID(), dh.HostSourceID()}, dh.Name(), dh.Hostname()) {
if !emit(patrolRuntimeResourceDockerHost, []string{dh.ID(), dh.HostSourceID()}, dh.Name(), dh.Hostname(), dockerAlertScopeAlias(dh.HostSourceID(), "")) {
return
}
}
for _, dc := range rs.DockerContainers() {
if !emit(patrolRuntimeResourceDockerItem, []string{dc.ID(), dc.ContainerID()}, dc.Name()) {
if !emit(patrolRuntimeResourceDockerItem, []string{dc.ID(), dc.ContainerID()}, dc.Name(), dockerAlertScopeAlias(dc.HostSourceID(), dc.ContainerID())) {
return
}
}
@@ -238,11 +251,11 @@ func patrolVisitRuntimeResources(s patrolRuntimeState, visit func(patrolRuntimeR
}
}
for _, dh := range s.DockerHosts {
if !emit(patrolRuntimeResourceDockerHost, []string{dh.ID}, dh.DisplayName, dh.CustomDisplayName, dh.Hostname) {
if !emit(patrolRuntimeResourceDockerHost, []string{dh.ID}, dh.DisplayName, dh.CustomDisplayName, dh.Hostname, dockerAlertScopeAlias(dh.ID, "")) {
return
}
for _, dc := range dh.Containers {
if !emit(patrolRuntimeResourceDockerItem, []string{dc.ID}, dc.Name) {
if !emit(patrolRuntimeResourceDockerItem, []string{dc.ID}, dc.Name, dockerAlertScopeAlias(dh.ID, dc.ID)) {
return
}
}
+34 -34
View File
@@ -2478,7 +2478,7 @@ func TestCheckDockerHostIgnoresContainersByPrefix(t *testing.T) {
Containers: []models.DockerContainer{container},
}
resourceID := dockerResourceID(host.ID, container.ID)
resourceID := DockerResourceID(host.ID, container.ID)
alertID := fmt.Sprintf("docker-container-state-%s", resourceID)
// Run twice to satisfy the confirmation threshold when not ignored
@@ -2517,7 +2517,7 @@ func TestCheckDockerHostContainerCPUUsesCapacityNormalizedPercent(t *testing.T)
CPUPercent: 240,
}},
}
alertID := canonicalMetricStateID(dockerResourceID(host.ID, "container-1"), "cpu")
alertID := canonicalMetricStateID(DockerResourceID(host.ID, "container-1"), "cpu")
m.CheckDockerHost(host)
m.mu.RLock()
@@ -2816,7 +2816,7 @@ func TestDockerContainerStateUsesDockerDefaults(t *testing.T) {
m.CheckDockerHost(host)
m.CheckDockerHost(host)
resourceID := dockerResourceID(host.ID, container.ID)
resourceID := DockerResourceID(host.ID, container.ID)
alertID := fmt.Sprintf("docker-container-state-%s", resourceID)
alert, exists := testLookupActiveAlert(t, m, alertID)
if !exists {
@@ -2849,7 +2849,7 @@ func TestDockerContainerStateRespectsDisableDefault(t *testing.T) {
m.CheckDockerHost(host)
m.CheckDockerHost(host)
resourceID := dockerResourceID(host.ID, container.ID)
resourceID := DockerResourceID(host.ID, container.ID)
alertID := fmt.Sprintf("docker-container-state-%s", resourceID)
if testHasActiveAlert(t, m, alertID) {
t.Fatalf("did not expect docker container state alert when defaults disable connectivity")
@@ -2879,7 +2879,7 @@ func TestDockerContainerMemoryLimitHysteresis(t *testing.T) {
m.CheckDockerHost(hostHigh)
resourceID := dockerResourceID(hostID, containerID)
resourceID := DockerResourceID(hostID, containerID)
alertID := fmt.Sprintf("docker-container-memory-limit-%s", resourceID)
alert, exists := testLookupActiveAlert(t, m, alertID)
if !exists {
@@ -2948,7 +2948,7 @@ func TestDockerContainerDiskUsageAlert(t *testing.T) {
m.CheckDockerHost(host)
resourceID := dockerResourceID(host.ID, host.Containers[0].ID)
resourceID := DockerResourceID(host.ID, host.Containers[0].ID)
alertID := canonicalMetricStateID(resourceID, "disk")
alert, exists := testLookupActiveAlert(t, m, alertID)
if !exists {
@@ -3540,7 +3540,7 @@ func TestCheckDockerHostIgnoredPrefixClearsExistingAlerts(t *testing.T) {
Hostname: "docker-host.local",
Containers: []models.DockerContainer{container},
}
resourceID := dockerResourceID(host.ID, container.ID)
resourceID := DockerResourceID(host.ID, container.ID)
stateAlertID := fmt.Sprintf("docker-container-state-%s", resourceID)
healthAlertID := fmt.Sprintf("docker-container-health-%s", resourceID)
restartAlertID := fmt.Sprintf("docker-container-restart-loop-%s", resourceID)
@@ -3734,8 +3734,8 @@ func TestDockerResourceID(t *testing.T) {
t.Run(tc.name, func(t *testing.T) {
// t.Parallel()
if got := dockerResourceID(tc.hostID, tc.containerID); got != tc.want {
t.Fatalf("dockerResourceID(%q, %q) = %q, want %q", tc.hostID, tc.containerID, got, tc.want)
if got := DockerResourceID(tc.hostID, tc.containerID); got != tc.want {
t.Fatalf("DockerResourceID(%q, %q) = %q, want %q", tc.hostID, tc.containerID, got, tc.want)
}
})
}
@@ -12862,7 +12862,7 @@ func TestDockerContainerHealthAlert(t *testing.T) {
m.CheckDockerHost(host)
resourceID := dockerResourceID(host.ID, host.Containers[0].ID)
resourceID := DockerResourceID(host.ID, host.Containers[0].ID)
alertID := fmt.Sprintf("docker-container-health-%s", resourceID)
if testHasActiveAlert(t, m, alertID) {
t.Fatal("expected no health alert for healthy container")
@@ -12889,7 +12889,7 @@ func TestDockerContainerHealthAlert(t *testing.T) {
m.CheckDockerHost(host)
resourceID := dockerResourceID(host.ID, host.Containers[0].ID)
resourceID := DockerResourceID(host.ID, host.Containers[0].ID)
alertID := fmt.Sprintf("docker-container-health-%s", resourceID)
if testHasActiveAlert(t, m, alertID) {
t.Fatal("expected no health alert for container with empty health")
@@ -12916,7 +12916,7 @@ func TestDockerContainerHealthAlert(t *testing.T) {
m.CheckDockerHost(host)
resourceID := dockerResourceID(host.ID, host.Containers[0].ID)
resourceID := DockerResourceID(host.ID, host.Containers[0].ID)
alertID := fmt.Sprintf("docker-container-health-%s", resourceID)
if testHasActiveAlert(t, m, alertID) {
t.Fatal("expected no health alert for container with none health")
@@ -12943,7 +12943,7 @@ func TestDockerContainerHealthAlert(t *testing.T) {
m.CheckDockerHost(host)
resourceID := dockerResourceID(host.ID, host.Containers[0].ID)
resourceID := DockerResourceID(host.ID, host.Containers[0].ID)
alertID := fmt.Sprintf("docker-container-health-%s", resourceID)
if testHasActiveAlert(t, m, alertID) {
t.Fatal("expected no health alert for starting container")
@@ -12970,7 +12970,7 @@ func TestDockerContainerHealthAlert(t *testing.T) {
m.CheckDockerHost(host)
resourceID := dockerResourceID(host.ID, host.Containers[0].ID)
resourceID := DockerResourceID(host.ID, host.Containers[0].ID)
alertID := fmt.Sprintf("docker-container-health-%s", resourceID)
alert, exists := testLookupActiveAlert(t, m, alertID)
if !exists {
@@ -13010,7 +13010,7 @@ func TestDockerContainerHealthAlert(t *testing.T) {
m.CheckDockerHost(host)
resourceID := dockerResourceID(host.ID, host.Containers[0].ID)
resourceID := DockerResourceID(host.ID, host.Containers[0].ID)
alertID := fmt.Sprintf("docker-container-health-%s", resourceID)
alert, exists := testLookupActiveAlert(t, m, alertID)
if !exists {
@@ -13045,7 +13045,7 @@ func TestDockerContainerHealthAlert(t *testing.T) {
m.CheckDockerHost(hostUnhealthy)
resourceID := dockerResourceID(hostID, containerID)
resourceID := DockerResourceID(hostID, containerID)
alertID := fmt.Sprintf("docker-container-health-%s", resourceID)
if !testHasActiveAlert(t, m, alertID) {
t.Fatal("expected health alert to be raised")
@@ -13096,7 +13096,7 @@ func TestDockerContainerOOMKillAlert(t *testing.T) {
m.CheckDockerHost(host)
resourceID := dockerResourceID(host.ID, host.Containers[0].ID)
resourceID := DockerResourceID(host.ID, host.Containers[0].ID)
alertID := fmt.Sprintf("docker-container-oom-%s", resourceID)
if testHasActiveAlert(t, m, alertID) {
t.Fatal("expected no OOM alert for running container")
@@ -13123,7 +13123,7 @@ func TestDockerContainerOOMKillAlert(t *testing.T) {
m.CheckDockerHost(host)
resourceID := dockerResourceID(host.ID, host.Containers[0].ID)
resourceID := DockerResourceID(host.ID, host.Containers[0].ID)
alertID := fmt.Sprintf("docker-container-oom-%s", resourceID)
if testHasActiveAlert(t, m, alertID) {
t.Fatal("expected no OOM alert for container with exit code 1")
@@ -13147,7 +13147,7 @@ func TestDockerContainerOOMKillAlert(t *testing.T) {
m.CheckDockerHost(host)
resourceID := dockerResourceID(host.ID, host.Containers[0].ID)
resourceID := DockerResourceID(host.ID, host.Containers[0].ID)
if testHasActiveAlert(t, m, fmt.Sprintf("docker-container-oom-%s", resourceID)) {
t.Fatal("exit code 137 alone must not create an OOM alert")
}
@@ -13177,7 +13177,7 @@ func TestDockerContainerOOMKillAlert(t *testing.T) {
m.CheckDockerHost(host)
resourceID := dockerResourceID(host.ID, host.Containers[0].ID)
resourceID := DockerResourceID(host.ID, host.Containers[0].ID)
alertID := fmt.Sprintf("docker-container-oom-%s", resourceID)
alert, exists := testLookupActiveAlert(t, m, alertID)
if !exists {
@@ -13221,7 +13221,7 @@ func TestDockerContainerOOMKillAlert(t *testing.T) {
m.CheckDockerHost(host)
resourceID := dockerResourceID(host.ID, host.Containers[0].ID)
resourceID := DockerResourceID(host.ID, host.Containers[0].ID)
alertID := fmt.Sprintf("docker-container-oom-%s", resourceID)
alert, exists := testLookupActiveAlert(t, m, alertID)
if !exists {
@@ -13257,7 +13257,7 @@ func TestDockerContainerOOMKillAlert(t *testing.T) {
// First check - should create alert
m.CheckDockerHost(host)
resourceID := dockerResourceID(hostID, containerID)
resourceID := DockerResourceID(hostID, containerID)
alertID := fmt.Sprintf("docker-container-oom-%s", resourceID)
alert1, exists := testLookupActiveAlert(t, m, alertID)
if !exists {
@@ -13302,7 +13302,7 @@ func TestDockerContainerOOMKillAlert(t *testing.T) {
m.CheckDockerHost(hostOOM)
resourceID := dockerResourceID(hostID, containerID)
resourceID := DockerResourceID(hostID, containerID)
alertID := fmt.Sprintf("docker-container-oom-%s", resourceID)
if !testHasActiveAlert(t, m, alertID) {
t.Fatal("expected OOM alert to be raised")
@@ -13356,7 +13356,7 @@ func TestDockerContainerOOMKillAlert(t *testing.T) {
m.CheckDockerHost(hostOOM)
resourceID := dockerResourceID(hostID, containerID)
resourceID := DockerResourceID(hostID, containerID)
alertID := fmt.Sprintf("docker-container-oom-%s", resourceID)
if !testHasActiveAlert(t, m, alertID) {
t.Fatal("expected OOM alert to be raised")
@@ -13407,7 +13407,7 @@ func TestDockerContainerRestartLoopAlert(t *testing.T) {
m.CheckDockerHost(host)
resourceID := dockerResourceID(host.ID, host.Containers[0].ID)
resourceID := DockerResourceID(host.ID, host.Containers[0].ID)
alertID := fmt.Sprintf("docker-container-restart-loop-%s", resourceID)
if testHasActiveAlert(t, m, alertID) {
t.Fatal("expected no restart loop alert on first check (just initializes tracking)")
@@ -13455,7 +13455,7 @@ func TestDockerContainerRestartLoopAlert(t *testing.T) {
// Third check - still same restart count
m.CheckDockerHost(host)
resourceID := dockerResourceID(hostID, containerID)
resourceID := DockerResourceID(hostID, containerID)
alertID := fmt.Sprintf("docker-container-restart-loop-%s", resourceID)
if testHasActiveAlert(t, m, alertID) {
t.Fatal("expected no restart loop alert for stable container")
@@ -13496,7 +13496,7 @@ func TestDockerContainerRestartLoopAlert(t *testing.T) {
host.Containers[0].RestartCount = 3
m.CheckDockerHost(host)
resourceID := dockerResourceID(hostID, containerID)
resourceID := DockerResourceID(hostID, containerID)
alertID := fmt.Sprintf("docker-container-restart-loop-%s", resourceID)
if testHasActiveAlert(t, m, alertID) {
t.Fatal("expected no restart loop alert when restarts <= threshold")
@@ -13542,7 +13542,7 @@ func TestDockerContainerRestartLoopAlert(t *testing.T) {
host.Containers[0].RestartCount = 4
m.CheckDockerHost(host)
resourceID := dockerResourceID(hostID, containerID)
resourceID := DockerResourceID(hostID, containerID)
alertID := fmt.Sprintf("docker-container-restart-loop-%s", resourceID)
alert, exists := testLookupActiveAlert(t, m, alertID)
if !exists {
@@ -13578,7 +13578,7 @@ func TestDockerContainerRestartLoopAlert(t *testing.T) {
hostID := "host-restart-5"
containerID := "container-5"
resourceID := dockerResourceID(hostID, containerID)
resourceID := DockerResourceID(hostID, containerID)
// Manually set up a restart loop state
m.mu.Lock()
@@ -13658,7 +13658,7 @@ func TestDockerContainerRestartLoopAlert(t *testing.T) {
// First check - initializes
m.CheckDockerHost(host)
resourceID := dockerResourceID(hostID, containerID)
resourceID := DockerResourceID(hostID, containerID)
alertID := fmt.Sprintf("docker-container-restart-loop-%s", resourceID)
// Restart 1
@@ -13711,7 +13711,7 @@ func TestDockerContainerRestartLoopAlert(t *testing.T) {
host.Containers[0].RestartCount = 5
m.CheckDockerHost(host)
resourceID := dockerResourceID(hostID, containerID)
resourceID := DockerResourceID(hostID, containerID)
alertID := fmt.Sprintf("docker-container-restart-loop-%s", resourceID)
alert1, exists := testLookupActiveAlert(t, m, alertID)
if !exists {
@@ -19891,7 +19891,7 @@ func TestDockerContainerOverrideSurvivesContainerRecreate(t *testing.T) {
}
}
stateAlertID := func(hostID, containerID string) string {
return fmt.Sprintf("docker-container-state-%s", dockerResourceID(hostID, containerID))
return fmt.Sprintf("docker-container-state-%s", DockerResourceID(hostID, containerID))
}
// Subtests keep the two managers in separate lifetimes: newTestManager
@@ -19943,13 +19943,13 @@ func TestDockerContainerOverrideLegacyIDKeyStillHonoured(t *testing.T) {
}
m.mu.Lock()
m.config.Overrides[dockerResourceID(host.ID, container.ID)] = ThresholdConfig{Disabled: true}
m.config.Overrides[DockerResourceID(host.ID, container.ID)] = ThresholdConfig{Disabled: true}
m.mu.Unlock()
m.CheckDockerHost(host)
m.CheckDockerHost(host)
alertID := fmt.Sprintf("docker-container-state-%s", dockerResourceID(host.ID, container.ID))
alertID := fmt.Sprintf("docker-container-state-%s", DockerResourceID(host.ID, container.ID))
if testHasActiveAlert(t, m, alertID) {
t.Fatalf("expected legacy ID-keyed override to still disable container alerts")
}
+1 -1
View File
@@ -267,7 +267,7 @@ func (m *Manager) applyGlobalOfflineSettingsLocked() {
}
// dockerAlertResourcePath returns the portion of the alert's resource ID after
// the "docker:" scheme, matching the IDs built by dockerResourceID and
// the "docker:" scheme, matching the IDs built by DockerResourceID and
// dockerServiceResourceID. Canonical alerts are stored under
// "<resourceID>::<specID>" state IDs, so the legacy "docker-container-" /
// "docker-service-" alert-ID prefixes never match them.
+5 -3
View File
@@ -79,8 +79,10 @@ func (m *Manager) lookupDockerContainerOverrideNoLock(hostID, containerName, leg
return ThresholdConfig{}, false
}
// dockerResourceID builds a stable identifier for Docker container alerts.
func dockerResourceID(hostID, containerID string) string {
// DockerResourceID builds a stable identifier for Docker container alerts.
// Patrol scope resolution registers these forms as known aliases so an
// alert's resource ID resolves to the collected container or host.
func DockerResourceID(hostID, containerID string) string {
hostID = strings.TrimSpace(hostID)
containerID = strings.TrimSpace(containerID)
if containerID == "" {
@@ -267,7 +269,7 @@ func (m *Manager) CheckDockerHost(host models.DockerHost) {
seenUpdateTracking := make(map[string]struct{}, len(host.Containers))
for _, container := range host.Containers {
containerName := dockerContainerDisplayName(container)
resourceID := dockerResourceID(host.ID, container.ID)
resourceID := DockerResourceID(host.ID, container.ID)
updateTrackingKey := dockerUpdateTrackingKey(host, container)
if matchesDockerIgnoredPrefix(containerName, container.ID, ignoredPrefixes) {
+1 -1
View File
@@ -75,7 +75,7 @@ func MigrateDockerContainerOverrideKeys(config *AlertConfig, resources []unified
legacyKey := ""
if containerID := strings.TrimSpace(resource.Docker.ContainerID); containerID != "" {
legacyKey = dockerResourceID(hostID, containerID)
legacyKey = DockerResourceID(hostID, containerID)
live[legacyKey] = struct{}{}
}
if legacyKey != "" && legacyKey != stableKey {
+1 -1
View File
@@ -1257,7 +1257,7 @@ func TestCheckDockerContainerStateAnnotatesCanonicalSpecMetadata(t *testing.T) {
m.CheckDockerHost(host)
m.CheckDockerHost(host)
resourceID := dockerResourceID(host.ID, "container-1")
resourceID := DockerResourceID(host.ID, "container-1")
alert := activeAlert(t, m, "docker-container-state-"+resourceID)
if got := alert.Metadata["canonicalAlertKind"]; got != "discrete-state" {
t.Fatalf("canonicalAlertKind = %v, want discrete-state", got)
+5 -5
View File
@@ -398,7 +398,7 @@ func TestCheckDockerContainerImageUpdatePreservesDelayAcrossHostIDChange(t *test
newHost.ID = "docker-host-new"
newHost.DisplayName = "New Docker Host"
oldResourceID := dockerResourceID(oldHost.ID, container.ID)
oldResourceID := DockerResourceID(oldHost.ID, container.ID)
m.checkDockerContainerImageUpdate(oldHost, container, oldResourceID, "web", "docker-instance", "docker.local")
firstSeen := time.Now().Add(-25 * time.Hour)
@@ -408,7 +408,7 @@ func TestCheckDockerContainerImageUpdatePreservesDelayAcrossHostIDChange(t *test
m.dockerUpdateFirstSeenByIdentity[trackingKey] = firstSeen
m.mu.Unlock()
newResourceID := dockerResourceID(newHost.ID, container.ID)
newResourceID := DockerResourceID(newHost.ID, container.ID)
m.checkDockerContainerImageUpdate(newHost, container, newResourceID, "web", "docker-instance", "docker.local")
alertID := "docker-container-update-" + newResourceID
@@ -568,7 +568,7 @@ func TestUpdateConfigClearsDockerContainerUpdateAlertsWhenDisabled(t *testing.T)
Name: "/frontend",
Image: "nginx:latest",
}
resourceID := dockerResourceID(host.ID, container.ID)
resourceID := DockerResourceID(host.ID, container.ID)
firstSeen := time.Now().Add(-48 * time.Hour)
_, canonicalAlertID, trackingKey := seedDockerUpdateAlert(t, m, host, container, resourceID, firstSeen)
@@ -606,7 +606,7 @@ func TestUpdateConfigKeepsDockerContainerUpdateAlertsWhenStillEnabled(t *testing
Name: "/api",
Image: "ghcr.io/example/api:latest",
}
resourceID := dockerResourceID(host.ID, container.ID)
resourceID := DockerResourceID(host.ID, container.ID)
firstSeen := time.Now().Add(-30 * time.Hour)
_, canonicalAlertID, trackingKey := seedDockerUpdateAlert(t, m, host, container, resourceID, firstSeen)
@@ -652,7 +652,7 @@ func TestEvaluateDockerContainerClearsUpdateAlertWhenOverrideDisabled(t *testing
Name: "/worker",
Image: "ghcr.io/example/worker:latest",
}
resourceID := dockerResourceID(host.ID, container.ID)
resourceID := DockerResourceID(host.ID, container.ID)
firstSeen := time.Now().Add(-36 * time.Hour)
alertID, canonicalAlertID, trackingKey := seedDockerUpdateAlert(t, m, host, container, resourceID, firstSeen)