feat(alerts): wildcard forms in docker ignored-container patterns

Bare entries keep their historical prefix semantics. Entries may now
also use the wildcard forms already established by the PBS datastore
excluder, so *-dev matches a suffix, *staging* a substring, and
runner-* an explicit prefix. Wildcard-only entries are skipped, that
job belongs to DisableAllDockerContainers.

Suffix matching is what the reporter on #1601 was approximating with
hundreds of per-container disable toggles, which is also what pushed
their config past the old request body cap.

Refs #1601

Contract-Neutral: extend docker ignored-prefix matching with wildcard forms; no schema or payload changes
This commit is contained in:
rcourtman
2026-08-06 17:18:07 +01:00
parent 38434a513a
commit b5fa6a9afd
2 changed files with 38 additions and 6 deletions
+10
View File
@@ -3639,6 +3639,16 @@ func TestMatchesDockerIgnoredPrefix(t *testing.T) {
{name: "empty name matches id", containerName: "", containerID: "runner-123", prefixes: []string{"runner-"}, want: true},
{name: "empty id matches name", containerName: "runner-job", containerID: "", prefixes: []string{"runner-"}, want: true},
{name: "both empty no match", containerName: "", containerID: "", prefixes: []string{"runner-"}, want: false},
{name: "suffix wildcard matches name", containerName: "worker-dev", containerID: "abc", prefixes: []string{"*-dev"}, want: true},
{name: "suffix wildcard rejects prefix position", containerName: "dev-worker", containerID: "abc", prefixes: []string{"*-dev"}, want: false},
{name: "suffix wildcard case insensitive", containerName: "Worker-DEV", containerID: "abc", prefixes: []string{"*-dev"}, want: true},
{name: "contains wildcard matches middle", containerName: "app-staging-eu", containerID: "abc", prefixes: []string{"*staging*"}, want: true},
{name: "contains wildcard no match", containerName: "app-prod-eu", containerID: "abc", prefixes: []string{"*staging*"}, want: false},
{name: "explicit prefix wildcard", containerName: "runner-job", containerID: "abc", prefixes: []string{"runner-*"}, want: true},
{name: "bare token still prefix only", containerName: "job-runner", containerID: "abc", prefixes: []string{"runner"}, want: false},
{name: "suffix wildcard matches id", containerName: "app", containerID: "abc123-dev", prefixes: []string{"*-dev"}, want: true},
{name: "lone star ignored", containerName: "anything", containerID: "abc", prefixes: []string{"*"}, want: false},
{name: "double star ignored", containerName: "anything", containerID: "abc", prefixes: []string{"**"}, want: false},
}
for _, tc := range tests {
+28 -6
View File
@@ -164,6 +164,11 @@ func dockerServiceResourceID(hostID, serviceID, serviceName string) string {
return fmt.Sprintf("docker:%s/service/%s", hostID, normalizedServiceID)
}
// matchesDockerIgnoredPrefix reports whether a container name or ID matches
// any entry in the ignore list. A bare entry keeps its historical
// prefix-match semantics. Entries may also use the wildcard forms shared
// with the other ignore lists: "*token" matches a suffix, "*token*" a
// substring, "token*" an explicit prefix.
func matchesDockerIgnoredPrefix(name, id string, prefixes []string) bool {
if len(prefixes) == 0 {
return false
@@ -173,14 +178,13 @@ func matchesDockerIgnoredPrefix(name, id string, prefixes []string) bool {
id = strings.ToLower(strings.TrimSpace(id))
for _, raw := range prefixes {
prefix := strings.ToLower(strings.TrimSpace(raw))
if prefix == "" {
pattern := strings.ToLower(strings.TrimSpace(raw))
// A pattern that is nothing but wildcards would ignore every
// container, which is what DisableAllDockerContainers is for.
if pattern == "" || strings.Trim(pattern, "*") == "" {
continue
}
if name != "" && strings.HasPrefix(name, prefix) {
return true
}
if id != "" && strings.HasPrefix(id, prefix) {
if matchesIgnoredContainerPattern(name, pattern) || matchesIgnoredContainerPattern(id, pattern) {
return true
}
}
@@ -188,6 +192,24 @@ func matchesDockerIgnoredPrefix(name, id string, prefixes []string) bool {
return false
}
func matchesIgnoredContainerPattern(value, pattern string) bool {
if value == "" {
return false
}
leading := strings.HasPrefix(pattern, "*")
trailing := strings.HasSuffix(pattern, "*")
switch {
case leading && trailing:
return strings.Contains(value, pattern[1:len(pattern)-1])
case leading:
return strings.HasSuffix(value, pattern[1:])
case trailing:
return strings.HasPrefix(value, pattern[:len(pattern)-1])
default:
return strings.HasPrefix(value, pattern)
}
}
// CheckDockerHost evaluates Docker host telemetry and container metrics for alerts.
func (m *Manager) CheckDockerHost(host models.DockerHost) {
if host.ID == "" {