fix(backend): add ClusterName() method

This commit is contained in:
Łukasz Mierzwa
2020-06-12 10:34:22 +01:00
committed by Łukasz Mierzwa
parent 9d8aeaae7e
commit 91c8170433
6 changed files with 74 additions and 41 deletions

View File

@@ -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

View File

@@ -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]}
}

View File

@@ -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"},
},
},
},

View File

@@ -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()
}

View File

@@ -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))
}

View File

@@ -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
}