From 91c8170433aff676dd8f580b646fca0c60f63db6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Mierzwa?= Date: Fri, 12 Jun 2020 10:34:22 +0100 Subject: [PATCH] fix(backend): add ClusterName() method --- cmd/karma/alerts.go | 35 +---------------------------- cmd/karma/views.go | 14 +++++++++++- cmd/karma/views_test.go | 15 +++++++++---- internal/alertmanager/cluster.go | 18 +++++++++++++++ internal/alertmanager/dedup_test.go | 3 ++- internal/alertmanager/models.go | 30 ++++++++++++++++++++++++- 6 files changed, 74 insertions(+), 41 deletions(-) create mode 100644 internal/alertmanager/cluster.go diff --git a/cmd/karma/alerts.go b/cmd/karma/alerts.go index 870fdce14..05722b1b5 100644 --- a/cmd/karma/alerts.go +++ b/cmd/karma/alerts.go @@ -4,7 +4,6 @@ import ( "fmt" "math" "sort" - "strings" "github.com/gin-gonic/gin" "vbom.ml/util/sortorder" @@ -13,7 +12,6 @@ import ( "github.com/prymitive/karma/internal/config" "github.com/prymitive/karma/internal/filters" "github.com/prymitive/karma/internal/models" - "github.com/prymitive/karma/internal/slices" "github.com/prymitive/karma/internal/uri" ) @@ -88,23 +86,6 @@ func countersToLabelStats(counters map[string]map[string]int) models.LabelNameSt return data } -func clusterMembersFromConfig(am *alertmanager.Alertmanager) []string { - members := []string{} - - upstreams := alertmanager.GetAlertmanagers() - for _, upstream := range upstreams { - if upstream.Cluster == am.Cluster { - members = append(members, upstream.Name) - } - } - - return members -} - -func clusterMembersFromAPI(am *alertmanager.Alertmanager) []string { - return am.ClusterMemberNames() -} - func getUpstreams() models.AlertmanagerAPISummary { summary := models.AlertmanagerAPISummary{} @@ -112,21 +93,7 @@ func getUpstreams() models.AlertmanagerAPISummary { upstreams := alertmanager.GetAlertmanagers() for _, upstream := range upstreams { members := upstream.ClusterMemberNames() - - var clusterName string - if upstream.Cluster != "" { - configPeers := clusterMembersFromConfig(upstream) - apiPeers := clusterMembersFromAPI(upstream) - missing, extra := slices.StringSliceDiff(configPeers, apiPeers) - - if len(missing) == 0 && len(extra) == 0 { - clusterName = upstream.Cluster - } else { - clusterName = fmt.Sprintf("%s @ %s", strings.Join(members, " | "), upstream.Cluster) - } - } else { - clusterName = strings.Join(members, " | ") - } + clusterName := upstream.ClusterName() if _, found := clusters[clusterName]; !found { clusters[clusterName] = members diff --git a/cmd/karma/views.go b/cmd/karma/views.go index 19ece0d85..6025829cd 100644 --- a/cmd/karma/views.go +++ b/cmd/karma/views.go @@ -130,12 +130,14 @@ func alerts(c *gin.Context) { username = c.MustGet(gin.AuthUserKey).(string) } + upstreams := getUpstreams() + // initialize response object, set fields that don't require any locking resp := models.AlertsResponse{} resp.Status = "success" resp.Timestamp = string(ts) resp.Version = version - resp.Upstreams = getUpstreams() + resp.Upstreams = upstreams resp.Settings = models.Settings{ Sorting: models.SortSettings{ Grid: models.GridSettings{ @@ -260,6 +262,16 @@ func alerts(c *gin.Context) { for _, am := range alert.Alertmanager { alertGridLabelValues = append(alertGridLabelValues, am.Name) } + case "@cluster": + alertGridLabelValues = make([]string, 0, len(alert.Alertmanager)) + for _, am := range alert.Alertmanager { + for _, upstream := range upstreams.Instances { + if am.Name == upstream.Name { + alertGridLabelValues = append(alertGridLabelValues, upstream.Cluster) + } + break + } + } default: alertGridLabelValues = []string{alert.Labels[gridLabel]} } diff --git a/cmd/karma/views_test.go b/cmd/karma/views_test.go index 8ea64ce3b..25a86123c 100644 --- a/cmd/karma/views_test.go +++ b/cmd/karma/views_test.go @@ -277,6 +277,13 @@ func TestGrids(t *testing.T) { {labelValue: "default", alertGroupCount: 10}, }, }, + { + gridLabel: "@cluster", + requestQuery: "", + grids: []testCaseGridT{ + {labelValue: "default", alertGroupCount: 10}, + }, + }, { gridLabel: "@receiver", requestQuery: "", @@ -1426,7 +1433,7 @@ func TestUpstreamStatus(t *testing.T) { CORSCredentials: "omit", Error: "", Version: "0.20.0", - Cluster: "ha1 @ Broken HA", + Cluster: "ha1", ClusterMembers: []string{"ha1"}, }, { @@ -1438,13 +1445,13 @@ func TestUpstreamStatus(t *testing.T) { CORSCredentials: "omit", Error: "", Version: "0.19.0", - Cluster: "ha2 @ Broken HA", + Cluster: "ha2", ClusterMembers: []string{"ha2"}, }, }, Clusters: map[string][]string{ - "ha1 @ Broken HA": {"ha1"}, - "ha2 @ Broken HA": {"ha2"}, + "ha1": {"ha1"}, + "ha2": {"ha2"}, }, }, }, diff --git a/internal/alertmanager/cluster.go b/internal/alertmanager/cluster.go new file mode 100644 index 000000000..ba314be7e --- /dev/null +++ b/internal/alertmanager/cluster.go @@ -0,0 +1,18 @@ +package alertmanager + +func clusterMembersFromConfig(am *Alertmanager) []string { + members := []string{} + + upstreams := GetAlertmanagers() + for _, upstream := range upstreams { + if upstream.Cluster == am.Cluster { + members = append(members, upstream.Name) + } + } + + return members +} + +func clusterMembersFromAPI(am *Alertmanager) []string { + return am.ClusterMemberNames() +} diff --git a/internal/alertmanager/dedup_test.go b/internal/alertmanager/dedup_test.go index 7372407d1..90840cd25 100644 --- a/internal/alertmanager/dedup_test.go +++ b/internal/alertmanager/dedup_test.go @@ -118,9 +118,10 @@ func TestDedupAutocomplete(t *testing.T) { // 74 hints for everything except @alertmanager and @silence_id // 4 hints for @silence_id 1 and 2 // 2 hints per @alertmanager + // 2 hits per @cluster // 6 hints for silences in for each alertmanager // silence id might get duplicated so this check isn't very strict - expected := 74 + 4 + mockCount*2 + mockCount*6 + expected := 74 + 4 + mockCount*2 + mockCount*2 + mockCount*6 if len(ac) <= int(float64(expected)*0.8) || len(ac) > expected { t.Errorf("Expected %d autocomplete hints, got %d", expected, len(ac)) } diff --git a/internal/alertmanager/models.go b/internal/alertmanager/models.go index 7faebac07..01c259abb 100644 --- a/internal/alertmanager/models.go +++ b/internal/alertmanager/models.go @@ -56,6 +56,7 @@ type Alertmanager struct { knownLabels []string lastError string status models.AlertmanagerStatus + clusterName string // metrics tracked per alertmanager instance Metrics alertmanagerMetrics // headers to send with each AlertManager request @@ -247,7 +248,7 @@ func (am *Alertmanager) pullAlerts(version string) error { alert.Alertmanager = []models.AlertmanagerInstance{ { Name: am.Name, - Cluster: am.ClusterID(), + Cluster: am.ClusterName(), State: alert.State, StartsAt: alert.StartsAt, Source: alert.GeneratorURL, @@ -336,6 +337,7 @@ func (am *Alertmanager) Pull() error { am.lock.Lock() am.status = *status am.lastError = "" + am.clusterName = "" am.lock.Unlock() return nil @@ -487,3 +489,29 @@ func (am *Alertmanager) ClusterID() string { } return id } + +func (am *Alertmanager) ClusterName() string { + am.lock.RLock() + if am.clusterName != "" { + am.lock.RUnlock() + return am.clusterName + } + am.lock.RUnlock() + + var clusterName string + if am.Cluster != "" { + configPeers := clusterMembersFromConfig(am) + apiPeers := clusterMembersFromAPI(am) + missing, extra := slices.StringSliceDiff(configPeers, apiPeers) + + if len(missing) == 0 && len(extra) == 0 { + clusterName = am.Cluster + } else { + clusterName = strings.Join(am.ClusterMemberNames(), " | ") + } + } else { + clusterName = strings.Join(am.ClusterMemberNames(), " | ") + } + am.clusterName = clusterName + return clusterName +}