diff --git a/alerts.go b/alerts.go index 3315863a7..483d02488 100644 --- a/alerts.go +++ b/alerts.go @@ -55,6 +55,7 @@ func getUpstreams() models.AlertmanagerAPISummary { PublicURI: upstream.PublicURI(), Error: upstream.Error(), Version: upstream.Version(), + Cluster: upstream.ClusterID(), ClusterMembers: members, } summary.Instances = append(summary.Instances, u) diff --git a/api_test.go b/api_test.go index 3b883c19d..b3e4163a3 100644 --- a/api_test.go +++ b/api_test.go @@ -867,9 +867,9 @@ func TestVerifyAllGroups(t *testing.T) { } } - am, foundAM := ur.Silences["default"] + am, foundAM := ur.Silences["843c4a11660fe38ea61e6960a29d4f4796da6488"] if !foundAM { - t.Errorf("[%s] Alertmanager 'default' missing from silences", version) + t.Errorf("[%s] Alertmanager cluster '843c4a11660fe38ea61e6960a29d4f4796da6488' (default) missing from silences", version) } else if len(am) == 0 { t.Errorf("[%s] Silences mismatch, expected >0 but got %d", version, len(am)) } diff --git a/internal/alertmanager/models.go b/internal/alertmanager/models.go index c0f5b6ce9..4b584dec8 100644 --- a/internal/alertmanager/models.go +++ b/internal/alertmanager/models.go @@ -284,6 +284,7 @@ func (am *Alertmanager) pullAlerts(version string) error { alert.Alertmanager = []models.AlertmanagerInstance{ models.AlertmanagerInstance{ Name: am.Name, + Cluster: am.ClusterID(), State: alert.State, StartsAt: alert.StartsAt, EndsAt: alert.EndsAt, @@ -503,3 +504,15 @@ func (am *Alertmanager) ClusterMemberNames() []string { sort.Strings(members) return members } + +// ClusterID returns the ID (sha1) of the cluster this Alertmanager instance +// belongs to +func (am *Alertmanager) ClusterID() string { + members := am.ClusterMemberNames() + id, err := slices.StringSliceToSHA1(members) + if err != nil { + log.Errorf("slices.StringSliceToSHA1 error: %s", err) + return am.Name + } + return id +} diff --git a/internal/models/alertmanager.go b/internal/models/alertmanager.go index 6c7596d44..913e26efb 100644 --- a/internal/models/alertmanager.go +++ b/internal/models/alertmanager.go @@ -5,7 +5,8 @@ import "time" // AlertmanagerInstance describes the Alertmanager instance alert was collected // from type AlertmanagerInstance struct { - Name string `json:"name"` + Name string `json:"name"` + Cluster string `json:"cluster"` // per instance alert state State string `json:"state"` // timestamp collected from this instance, those on the alert itself @@ -32,6 +33,7 @@ type AlertmanagerAPIStatus struct { PublicURI string `json:"publicURI"` Error string `json:"error"` Version string `json:"version"` + Cluster string `json:"cluster"` ClusterMembers []string `json:"clusterMembers"` } diff --git a/views.go b/views.go index f961dd382..dbb6b90be 100644 --- a/views.go +++ b/views.go @@ -111,9 +111,15 @@ func alerts(c *gin.Context) { dedupedAlerts := alertmanager.DedupAlerts() dedupedColors := alertmanager.DedupColors() + amNameToCluster := map[string]string{} silences := map[string]map[string]models.Silence{} for _, am := range alertmanager.GetAlertmanagers() { - silences[am.Name] = map[string]models.Silence{} + key := am.ClusterID() + amNameToCluster[am.Name] = key + _, found := silences[key] + if !found { + silences[key] = map[string]models.Silence{} + } } var matches int @@ -189,8 +195,12 @@ func alerts(c *gin.Context) { for _, alert := range agCopy.Alerts { if alert.IsSilenced() { for _, am := range alert.Alertmanager { + key := amNameToCluster[am.Name] for _, silence := range am.Silences { - silences[am.Name][silence.ID] = *silence + _, found := silences[key][silence.ID] + if !found { + silences[key][silence.ID] = *silence + } } } }