Skip to content

Commit

Permalink
Alerting: Use a struct when sending a Grafana AM configuration to the…
Browse files Browse the repository at this point in the history
… remote Alertmanager (grafana#86451)

* Alerting: Use a struct when sending a Grafana AM configuration to the remote Alertmanager

* remove '-distroless' from mimir image name
  • Loading branch information
santihernandezc authored Apr 19, 2024
1 parent 65afe90 commit a2ce8fe
Show file tree
Hide file tree
Showing 7 changed files with 47 additions and 29 deletions.
14 changes: 7 additions & 7 deletions .drone.yml
Original file line number Diff line number Diff line change
Expand Up @@ -879,7 +879,7 @@ services:
- commands:
- /bin/mimir -target=backend -alertmanager.grafana-alertmanager-compatibility-enabled
environment: {}
image: us.gcr.io/kubernetes-dev/mimir:santihernandezc-remove_id_from_grafana_config-d3826b4f8-WIP
image: us.gcr.io/kubernetes-dev/mimir:santihernandezc-validate_grafana_am_config-1e903e462-WIP
name: mimir_backend
- environment: {}
image: redis:6.2.11-alpine
Expand Down Expand Up @@ -1327,7 +1327,7 @@ services:
- commands:
- /bin/mimir -target=backend -alertmanager.grafana-alertmanager-compatibility-enabled
environment: {}
image: us.gcr.io/kubernetes-dev/mimir:santihernandezc-remove_id_from_grafana_config-d3826b4f8-WIP
image: us.gcr.io/kubernetes-dev/mimir:santihernandezc-validate_grafana_am_config-1e903e462-WIP
name: mimir_backend
- environment: {}
image: redis:6.2.11-alpine
Expand Down Expand Up @@ -2329,7 +2329,7 @@ services:
- commands:
- /bin/mimir -target=backend -alertmanager.grafana-alertmanager-compatibility-enabled
environment: {}
image: us.gcr.io/kubernetes-dev/mimir:santihernandezc-remove_id_from_grafana_config-d3826b4f8-WIP
image: us.gcr.io/kubernetes-dev/mimir:santihernandezc-validate_grafana_am_config-1e903e462-WIP
name: mimir_backend
- environment: {}
image: redis:6.2.11-alpine
Expand Down Expand Up @@ -4127,7 +4127,7 @@ services:
- commands:
- /bin/mimir -target=backend -alertmanager.grafana-alertmanager-compatibility-enabled
environment: {}
image: us.gcr.io/kubernetes-dev/mimir:santihernandezc-remove_id_from_grafana_config-d3826b4f8-WIP
image: us.gcr.io/kubernetes-dev/mimir:santihernandezc-validate_grafana_am_config-1e903e462-WIP
name: mimir_backend
- environment: {}
image: redis:6.2.11-alpine
Expand Down Expand Up @@ -4646,7 +4646,7 @@ steps:
- trivy --exit-code 0 --severity UNKNOWN,LOW,MEDIUM plugins/slack
- trivy --exit-code 0 --severity UNKNOWN,LOW,MEDIUM python:3.8
- trivy --exit-code 0 --severity UNKNOWN,LOW,MEDIUM postgres:12.3-alpine
- trivy --exit-code 0 --severity UNKNOWN,LOW,MEDIUM us.gcr.io/kubernetes-dev/mimir:santihernandezc-remove_id_from_grafana_config-d3826b4f8-WIP
- trivy --exit-code 0 --severity UNKNOWN,LOW,MEDIUM us.gcr.io/kubernetes-dev/mimir:santihernandezc-validate_grafana_am_config-1e903e462-WIP
- trivy --exit-code 0 --severity UNKNOWN,LOW,MEDIUM mysql:5.7.39
- trivy --exit-code 0 --severity UNKNOWN,LOW,MEDIUM mysql:8.0.32
- trivy --exit-code 0 --severity UNKNOWN,LOW,MEDIUM redis:6.2.11-alpine
Expand Down Expand Up @@ -4681,7 +4681,7 @@ steps:
- trivy --exit-code 1 --severity HIGH,CRITICAL plugins/slack
- trivy --exit-code 1 --severity HIGH,CRITICAL python:3.8
- trivy --exit-code 1 --severity HIGH,CRITICAL postgres:12.3-alpine
- trivy --exit-code 1 --severity HIGH,CRITICAL us.gcr.io/kubernetes-dev/mimir:santihernandezc-remove_id_from_grafana_config-d3826b4f8-WIP
- trivy --exit-code 1 --severity HIGH,CRITICAL us.gcr.io/kubernetes-dev/mimir:santihernandezc-validate_grafana_am_config-1e903e462-WIP
- trivy --exit-code 1 --severity HIGH,CRITICAL mysql:5.7.39
- trivy --exit-code 1 --severity HIGH,CRITICAL mysql:8.0.32
- trivy --exit-code 1 --severity HIGH,CRITICAL redis:6.2.11-alpine
Expand Down Expand Up @@ -4925,6 +4925,6 @@ kind: secret
name: gcr_credentials
---
kind: signature
hmac: 958ed40ca0620498c01fa867b05a1d6c3bcd908067fbb34be691923e95cfc77b
hmac: e67367689de11270bb3139f25a7cabf54e2b980460fd55ad410c590722d122b8

...
2 changes: 1 addition & 1 deletion devenv/docker/blocks/mimir_backend/docker-compose.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
mimir_backend:
image: us.gcr.io/kubernetes-dev/mimir:santihernandezc-remove_id_from_grafana_config-d3826b4f8-WIP
image: us.gcr.io/kubernetes-dev/mimir:santihernandezc-validate_grafana_am_config-1e903e462-WIP
container_name: mimir_backend
command:
- -target=backend
Expand Down
25 changes: 15 additions & 10 deletions pkg/services/ngalert/remote/alertmanager.go
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,6 @@ func (am *Alertmanager) ApplyConfig(ctx context.Context, config *models.AlertCon
am.log.Error("Unable to upload the state to the remote Alertmanager", "err", err)
}
am.log.Debug("Completed state upload to remote Alertmanager", "url", am.url)

return nil
}

Expand Down Expand Up @@ -202,20 +201,16 @@ func (am *Alertmanager) CompareAndSendConfiguration(ctx context.Context, config
if err != nil {
return err
}
rawDecrypted, err := json.Marshal(decrypted)
if err != nil {
return err
}

// Send the configuration only if we need to.
if !am.shouldSendConfig(ctx, rawDecrypted) {
if !am.shouldSendConfig(ctx, &decrypted) {
return nil
}

am.metrics.ConfigSyncsTotal.Inc()
if err := am.mimirClient.CreateGrafanaAlertmanagerConfig(
ctx,
string(rawDecrypted),
&decrypted,
config.ConfigurationHash,
config.CreatedAt,
config.Default,
Expand Down Expand Up @@ -447,15 +442,25 @@ func (am *Alertmanager) getFullState(ctx context.Context) (string, error) {

// shouldSendConfig compares the remote Alertmanager configuration with our local one.
// It returns true if the configurations are different.
func (am *Alertmanager) shouldSendConfig(ctx context.Context, rawConfig []byte) bool {
func (am *Alertmanager) shouldSendConfig(ctx context.Context, config *apimodels.PostableUserConfig) bool {
rc, err := am.mimirClient.GetGrafanaAlertmanagerConfig(ctx)
if err != nil {
// Log the error and return true so we try to upload our config anyway.
am.log.Error("Unable to get the remote Alertmanager Configuration for comparison", "err", err)
am.log.Error("Unable to get the remote Alertmanager configuration for comparison", "err", err)
return true
}

return md5.Sum([]byte(rc.GrafanaAlertmanagerConfig)) != md5.Sum(rawConfig)
rawRemote, err := json.Marshal(rc.GrafanaAlertmanagerConfig)
if err != nil {
am.log.Error("Unable to marshal the remote Alertmanager configuration for comparison", "err", err)
return true
}
rawInternal, err := json.Marshal(config)
if err != nil {
am.log.Error("Unable to marshal the internal Alertmanager configuration for comparison", "err", err)
return true
}
return md5.Sum(rawRemote) != md5.Sum(rawInternal)
}

// shouldSendState compares the remote Alertmanager state with our local one.
Expand Down
18 changes: 14 additions & 4 deletions pkg/services/ngalert/remote/alertmanager_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,9 @@ func TestApplyConfig(t *testing.T) {
if r.Method == http.MethodPost && strings.Contains(r.URL.Path, "/config") {
var c client.UserGrafanaConfig
require.NoError(t, json.NewDecoder(r.Body).Decode(&c))
configSent = c.GrafanaAlertmanagerConfig
amCfg, err := json.Marshal(c.GrafanaAlertmanagerConfig)
require.NoError(t, err)
configSent = string(amCfg)
}

w.WriteHeader(http.StatusOK)
Expand Down Expand Up @@ -179,6 +181,8 @@ func TestApplyConfig(t *testing.T) {
}

func TestCompareAndSendConfiguration(t *testing.T) {
cfgWithSecret, err := notifier.Load([]byte(testGrafanaConfigWithSecret))
require.NoError(t, err)
testValue := []byte("test")
testErr := errors.New("test error")
decryptFn := func(_ context.Context, payload []byte) ([]byte, error) {
Expand Down Expand Up @@ -243,7 +247,7 @@ func TestCompareAndSendConfiguration(t *testing.T) {
"no error",
strings.Replace(testGrafanaConfigWithSecret, `"password":"test"`, fmt.Sprintf("%q:%q", "password", base64.StdEncoding.EncodeToString(testValue)), 1),
&client.UserGrafanaConfig{
GrafanaAlertmanagerConfig: testGrafanaConfigWithSecret,
GrafanaAlertmanagerConfig: cfgWithSecret,
},
"",
},
Expand Down Expand Up @@ -335,7 +339,10 @@ func TestIntegrationRemoteAlertmanagerApplyConfigOnlyUploadsOnce(t *testing.T) {
// Next, we need to verify that Mimir received both the configuration and state.
config, err := am.mimirClient.GetGrafanaAlertmanagerConfig(ctx)
require.NoError(t, err)
require.Equal(t, testGrafanaConfig, config.GrafanaAlertmanagerConfig)

rawCfg, err := json.Marshal(config.GrafanaAlertmanagerConfig)
require.NoError(t, err)
require.JSONEq(t, testGrafanaConfig, string(rawCfg))
require.Equal(t, fakeConfigHash, config.Hash)
require.Equal(t, fakeConfigCreatedAt, config.CreatedAt)
require.Equal(t, true, config.Default)
Expand All @@ -358,7 +365,10 @@ func TestIntegrationRemoteAlertmanagerApplyConfigOnlyUploadsOnce(t *testing.T) {
// Next, we need to verify that the config that was uploaded remains the same.
config, err := am.mimirClient.GetGrafanaAlertmanagerConfig(ctx)
require.NoError(t, err)
require.Equal(t, testGrafanaConfig, config.GrafanaAlertmanagerConfig)

rawCfg, err := json.Marshal(config.GrafanaAlertmanagerConfig)
require.NoError(t, err)
require.JSONEq(t, testGrafanaConfig, string(rawCfg))
require.Equal(t, fakeConfigHash, config.Hash)
require.Equal(t, fakeConfigCreatedAt, config.CreatedAt)
require.Equal(t, true, config.Default)
Expand Down
12 changes: 7 additions & 5 deletions pkg/services/ngalert/remote/client/alertmanager_configuration.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,19 @@ import (
"encoding/json"
"fmt"
"net/http"

apimodels "github.com/grafana/grafana/pkg/services/ngalert/api/tooling/definitions"
)

const (
grafanaAlertmanagerConfigPath = "/api/v1/grafana/config"
)

type UserGrafanaConfig struct {
GrafanaAlertmanagerConfig string `json:"configuration"`
Hash string `json:"configuration_hash"`
CreatedAt int64 `json:"created"`
Default bool `json:"default"`
GrafanaAlertmanagerConfig *apimodels.PostableUserConfig `json:"configuration"`
Hash string `json:"configuration_hash"`
CreatedAt int64 `json:"created"`
Default bool `json:"default"`
}

func (mc *Mimir) GetGrafanaAlertmanagerConfig(ctx context.Context) (*UserGrafanaConfig, error) {
Expand All @@ -38,7 +40,7 @@ func (mc *Mimir) GetGrafanaAlertmanagerConfig(ctx context.Context) (*UserGrafana
return gc, nil
}

func (mc *Mimir) CreateGrafanaAlertmanagerConfig(ctx context.Context, cfg, hash string, createdAt int64, isDefault bool) error {
func (mc *Mimir) CreateGrafanaAlertmanagerConfig(ctx context.Context, cfg *apimodels.PostableUserConfig, hash string, createdAt int64, isDefault bool) error {
payload, err := json.Marshal(&UserGrafanaConfig{
GrafanaAlertmanagerConfig: cfg,
Hash: hash,
Expand Down
3 changes: 2 additions & 1 deletion pkg/services/ngalert/remote/client/mimir.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"strings"

"github.com/grafana/grafana/pkg/infra/log"
apimodels "github.com/grafana/grafana/pkg/services/ngalert/api/tooling/definitions"
"github.com/grafana/grafana/pkg/services/ngalert/client"
"github.com/grafana/grafana/pkg/services/ngalert/metrics"
)
Expand All @@ -23,7 +24,7 @@ type MimirClient interface {
DeleteGrafanaAlertmanagerState(ctx context.Context) error

GetGrafanaAlertmanagerConfig(ctx context.Context) (*UserGrafanaConfig, error)
CreateGrafanaAlertmanagerConfig(ctx context.Context, configuration, hash string, createdAt int64, isDefault bool) error
CreateGrafanaAlertmanagerConfig(ctx context.Context, configuration *apimodels.PostableUserConfig, hash string, createdAt int64, isDefault bool) error
DeleteGrafanaAlertmanagerConfig(ctx context.Context) error
}

Expand Down
2 changes: 1 addition & 1 deletion scripts/drone/utils/images.star
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ images = {
"plugins_slack": "plugins/slack",
"python": "python:3.8",
"postgres_alpine": "postgres:12.3-alpine",
"mimir": "us.gcr.io/kubernetes-dev/mimir:santihernandezc-remove_id_from_grafana_config-d3826b4f8-WIP",
"mimir": "us.gcr.io/kubernetes-dev/mimir:santihernandezc-validate_grafana_am_config-1e903e462-WIP",
"mysql5": "mysql:5.7.39",
"mysql8": "mysql:8.0.32",
"redis_alpine": "redis:6.2.11-alpine",
Expand Down

0 comments on commit a2ce8fe

Please sign in to comment.