From 24c10b4fb9d1f5848ca4e4b312f8e4e614842b35 Mon Sep 17 00:00:00 2001 From: Yuri Tseretyan Date: Thu, 25 Sep 2025 16:09:54 -0400 Subject: [PATCH] Alerting: Remove usages of ReceiverType (#111508) * remove usages of ReceiverType --- apps/iam/go.mod | 2 +- apps/iam/go.sum | 4 +- go.mod | 2 +- go.sum | 4 +- go.work.sum | 6 +- .../ngalert/api/forking_alertmanager.go | 6 +- .../api/tooling/definitions/alertmanager.go | 62 +-------- .../ngalert/notifier/alertmanager_config.go | 30 ++--- pkg/services/ngalert/notifier/crypto.go | 126 +++++++++--------- 9 files changed, 93 insertions(+), 149 deletions(-) diff --git a/apps/iam/go.mod b/apps/iam/go.mod index 8455f3e0f0b..64c5a52c1a8 100644 --- a/apps/iam/go.mod +++ b/apps/iam/go.mod @@ -204,7 +204,7 @@ require ( github.com/googleapis/enterprise-certificate-proxy v0.3.6 // indirect github.com/googleapis/gax-go/v2 v2.14.2 // indirect github.com/gorilla/mux v1.8.1 // indirect - github.com/grafana/alerting v0.0.0-20250915130141-a8ee25091876 // indirect + github.com/grafana/alerting v0.0.0-20250925193206-bd061d3d9185 // indirect github.com/grafana/authlib/types v0.0.0-20250917093142-83a502239781 // indirect github.com/grafana/dataplane/sdata v0.0.9 // indirect github.com/grafana/dskit v0.0.0-20250908063411-6b6da59b5cc4 // indirect diff --git a/apps/iam/go.sum b/apps/iam/go.sum index e6336bf9235..b93048ed57a 100644 --- a/apps/iam/go.sum +++ b/apps/iam/go.sum @@ -721,8 +721,8 @@ github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 h1:JeSE6pjso5THxAzdVpqr6/geYxZytqFMBCOtn/ujyeo= github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674/go.mod h1:r4w70xmWCQKmi1ONH4KIaBptdivuRPyosB9RmPlGEwA= -github.com/grafana/alerting v0.0.0-20250915130141-a8ee25091876 h1:BzoGpzARwRCNOHcqQdYPAFp2LS1pqnkLWhIuDdq1zho= -github.com/grafana/alerting v0.0.0-20250915130141-a8ee25091876/go.mod h1:T5sitas9VhVj8/S9LeRLy6H75kTBdh/sCCqHo7gaQI8= +github.com/grafana/alerting v0.0.0-20250925193206-bd061d3d9185 h1:R494uXJOz7glN76hJXKjbwu+VBYFsT0CFprsXmdHla0= +github.com/grafana/alerting v0.0.0-20250925193206-bd061d3d9185/go.mod h1:T5sitas9VhVj8/S9LeRLy6H75kTBdh/sCCqHo7gaQI8= github.com/grafana/authlib v0.0.0-20250924100039-ea07223cdb6c h1:8GIMe1KclDdfogaeRsiU69Ev2zTF9kmjqjQqqZMzerc= github.com/grafana/authlib v0.0.0-20250924100039-ea07223cdb6c/go.mod h1:C6CmTG6vfiqebjJswKsc6zes+1F/OtTCi6aAtL5Um6A= github.com/grafana/authlib/types v0.0.0-20250917093142-83a502239781 h1:jymmOFIWnW26DeUjFgYEoltI170KeT5r1rI8a/dUf0E= diff --git a/go.mod b/go.mod index 5a66ee070ad..5a986999c43 100644 --- a/go.mod +++ b/go.mod @@ -86,7 +86,7 @@ require ( github.com/googleapis/gax-go/v2 v2.14.2 // @grafana/grafana-backend-group github.com/gorilla/mux v1.8.1 // @grafana/grafana-backend-group github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 // @grafana/grafana-app-platform-squad - github.com/grafana/alerting v0.0.0-20250915130141-a8ee25091876 // @grafana/alerting-backend + github.com/grafana/alerting v0.0.0-20250925193206-bd061d3d9185 // @grafana/alerting-backend github.com/grafana/authlib v0.0.0-20250924100039-ea07223cdb6c // @grafana/identity-access-team github.com/grafana/authlib/types v0.0.0-20250917093142-83a502239781 // @grafana/identity-access-team github.com/grafana/dataplane/examples v0.0.1 // @grafana/observability-metrics diff --git a/go.sum b/go.sum index 53c44fc95a0..b444408d771 100644 --- a/go.sum +++ b/go.sum @@ -1585,8 +1585,8 @@ github.com/gorilla/sessions v1.2.1 h1:DHd3rPN5lE3Ts3D8rKkQ8x/0kqfeNmBAaiSi+o7Fsg github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 h1:JeSE6pjso5THxAzdVpqr6/geYxZytqFMBCOtn/ujyeo= github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674/go.mod h1:r4w70xmWCQKmi1ONH4KIaBptdivuRPyosB9RmPlGEwA= -github.com/grafana/alerting v0.0.0-20250915130141-a8ee25091876 h1:BzoGpzARwRCNOHcqQdYPAFp2LS1pqnkLWhIuDdq1zho= -github.com/grafana/alerting v0.0.0-20250915130141-a8ee25091876/go.mod h1:T5sitas9VhVj8/S9LeRLy6H75kTBdh/sCCqHo7gaQI8= +github.com/grafana/alerting v0.0.0-20250925193206-bd061d3d9185 h1:R494uXJOz7glN76hJXKjbwu+VBYFsT0CFprsXmdHla0= +github.com/grafana/alerting v0.0.0-20250925193206-bd061d3d9185/go.mod h1:T5sitas9VhVj8/S9LeRLy6H75kTBdh/sCCqHo7gaQI8= github.com/grafana/authlib v0.0.0-20250924100039-ea07223cdb6c h1:8GIMe1KclDdfogaeRsiU69Ev2zTF9kmjqjQqqZMzerc= github.com/grafana/authlib v0.0.0-20250924100039-ea07223cdb6c/go.mod h1:C6CmTG6vfiqebjJswKsc6zes+1F/OtTCi6aAtL5Um6A= github.com/grafana/authlib/types v0.0.0-20250917093142-83a502239781 h1:jymmOFIWnW26DeUjFgYEoltI170KeT5r1rI8a/dUf0E= diff --git a/go.work.sum b/go.work.sum index d9a860898d1..e1eb4ee0513 100644 --- a/go.work.sum +++ b/go.work.sum @@ -1040,6 +1040,10 @@ github.com/grafana/alerting v0.0.0-20250701210250-cea2d1683945 h1:3imTbxFpZSVI6I github.com/grafana/alerting v0.0.0-20250701210250-cea2d1683945/go.mod h1:gtR7agmxVfJOmNKV/n2ZULgOYTYNL+PDKYB5N48tQ7Q= github.com/grafana/alerting v0.0.0-20250709204613-c5c6f9c1653d/go.mod h1:gtR7agmxVfJOmNKV/n2ZULgOYTYNL+PDKYB5N48tQ7Q= github.com/grafana/alerting v0.0.0-20250911172908-2b26ef8f17eb/go.mod h1:XWqj/rlsy4OV/E9XNNyFn+a7U4GNsSugPb2rDBj9+58= +github.com/grafana/alerting v0.0.0-20250923203439-adb598e7d509 h1:8JMtYCClxrxRXsF5jc64GTURZFHJHFK/kzC7joRNTtI= +github.com/grafana/alerting v0.0.0-20250923203439-adb598e7d509/go.mod h1:T5sitas9VhVj8/S9LeRLy6H75kTBdh/sCCqHo7gaQI8= +github.com/grafana/alerting v0.0.0-20250925193206-bd061d3d9185 h1:R494uXJOz7glN76hJXKjbwu+VBYFsT0CFprsXmdHla0= +github.com/grafana/alerting v0.0.0-20250925193206-bd061d3d9185/go.mod h1:T5sitas9VhVj8/S9LeRLy6H75kTBdh/sCCqHo7gaQI8= github.com/grafana/authlib v0.0.0-20250123104008-e99947858901/go.mod h1:/gYfphsNu9v1qYWXxpv1NSvMEMSwvdf8qb8YlgwIRl8= github.com/grafana/authlib v0.0.0-20250909101823-1b466dbd19a1/go.mod h1:C6CmTG6vfiqebjJswKsc6zes+1F/OtTCi6aAtL5Um6A= github.com/grafana/authlib/types v0.0.0-20250120144156-d6737a7dc8f5/go.mod h1:qYjSd1tmJiuVoSICp7Py9/zD54O9uQQA3wuM6Gg4DFM= @@ -1074,8 +1078,6 @@ github.com/grafana/grafana-aws-sdk v0.38.2/go.mod h1:j3vi+cXYHEFqjhBGrI6/lw1TNM+ github.com/grafana/grafana-aws-sdk v1.0.2 h1:98eBuHYFmgvH0xO9kKf4RBsEsgQRp8EOA/9yhDIpkss= github.com/grafana/grafana-aws-sdk v1.0.2/go.mod h1:hO7q7yWV+t6dmiyJjMa3IbuYnYkBua+G/IAlOPVIYKE= github.com/grafana/grafana-azure-sdk-go/v2 v2.1.6/go.mod h1:V7y2BmsWxS3A9Ohebwn4OiSfJJqi//4JQydQ8fHTduo= -github.com/grafana/grafana-google-sdk-go v0.4.2 h1:F44hQF1y6UVJhlJPi+Mz+GCJsioVgezEgPMMEQbUZRo= -github.com/grafana/grafana-google-sdk-go v0.4.2/go.mod h1:U73+w9DlbEtUonhQUzERwlXnzWTtfRoyrtKH8d3VY40= github.com/grafana/grafana-plugin-sdk-go v0.263.0/go.mod h1:U43Cnrj/9DNYyvFcNdeUWNjMXTKNB0jcTcQGpWKd2gw= github.com/grafana/grafana-plugin-sdk-go v0.267.0/go.mod h1:OuwS4c/JYgn0rr/w5zhJBpLo4gKm/vw15RsfpYAvK9Q= github.com/grafana/grafana-plugin-sdk-go v0.269.1/go.mod h1:yv2KbO4mlr9WuDK2f+2gHAMTwwLmLuqaEnrPXTRU+OI= diff --git a/pkg/services/ngalert/api/forking_alertmanager.go b/pkg/services/ngalert/api/forking_alertmanager.go index 96e295fc68f..349fba06936 100644 --- a/pkg/services/ngalert/api/forking_alertmanager.go +++ b/pkg/services/ngalert/api/forking_alertmanager.go @@ -206,8 +206,10 @@ func (f *AlertmanagerApiHandler) handleRoutePostAlertingConfig(ctx *contextmodel if err != nil { return errorToResponse(err) } - if !body.AlertmanagerConfig.ReceiverType().Can(apimodels.AlertmanagerReceiverType) { - return errorToResponse(backendTypeDoesNotMatchPayloadTypeError(apimodels.AlertmanagerBackend, body.AlertmanagerConfig.ReceiverType().String())) + for _, p := range body.AlertmanagerConfig.Receivers { + if p.HasGrafanaIntegrations() { + return errorToResponse(backendTypeDoesNotMatchPayloadTypeError(apimodels.AlertmanagerBackend, apimodels.GrafanaBackend.String())) + } } return s.RoutePostAlertingConfig(ctx, body) } diff --git a/pkg/services/ngalert/api/tooling/definitions/alertmanager.go b/pkg/services/ngalert/api/tooling/definitions/alertmanager.go index 0c034514319..5c33ad658fe 100644 --- a/pkg/services/ngalert/api/tooling/definitions/alertmanager.go +++ b/pkg/services/ngalert/api/tooling/definitions/alertmanager.go @@ -267,7 +267,6 @@ type ( ObjectMatchers = definition.ObjectMatchers PostableApiReceiver = definition.PostableApiReceiver PostableGrafanaReceivers = definition.PostableGrafanaReceivers - ReceiverType = definition.ReceiverType ) type MergeResult definition.MergeResult @@ -295,9 +294,6 @@ func (m MergeResult) LogContext() []any { } const ( - GrafanaReceiverType = definition.GrafanaReceiverType - AlertmanagerReceiverType = definition.AlertmanagerReceiverType - errInvalidExtraConfigurationMsg = "Invalid Alertmanager configuration: {{.Public.Error}}" ) @@ -870,12 +866,8 @@ func (c *PostableUserConfig) validate() error { func (c *PostableUserConfig) GetGrafanaReceiverMap() map[string]*PostableGrafanaReceiver { UIDs := make(map[string]*PostableGrafanaReceiver) for _, r := range c.AlertmanagerConfig.Receivers { - switch r.Type() { - case GrafanaReceiverType: - for _, gr := range r.GrafanaManagedReceivers { - UIDs[gr.UID] = gr - } - default: + for _, gr := range r.GrafanaManagedReceivers { + UIDs[gr.UID] = gr } } return UIDs @@ -975,12 +967,8 @@ func (c *GettableUserConfig) MarshalJSON() ([]byte, error) { func (c *GettableUserConfig) GetGrafanaReceiverMap() map[string]*GettableGrafanaReceiver { UIDs := make(map[string]*GettableGrafanaReceiver) for _, r := range c.AlertmanagerConfig.Receivers { - switch r.Type() { - case GrafanaReceiverType: - for _, gr := range r.GrafanaManagedReceivers { - UIDs[gr.UID] = gr - } - default: + for _, gr := range r.GrafanaManagedReceivers { + UIDs[gr.UID] = gr } } return UIDs @@ -1097,47 +1085,7 @@ type GettableApiReceiver struct { func (r *GettableApiReceiver) UnmarshalJSON(b []byte) error { type plain GettableApiReceiver - if err := json.Unmarshal(b, (*plain)(r)); err != nil { - return err - } - - hasGrafanaReceivers := len(r.GrafanaManagedReceivers) > 0 - - if hasGrafanaReceivers { - if len(r.EmailConfigs) > 0 { - return fmt.Errorf("cannot have both Alertmanager EmailConfigs & Grafana receivers together") - } - if len(r.PagerdutyConfigs) > 0 { - return fmt.Errorf("cannot have both Alertmanager PagerdutyConfigs & Grafana receivers together") - } - if len(r.SlackConfigs) > 0 { - return fmt.Errorf("cannot have both Alertmanager SlackConfigs & Grafana receivers together") - } - if len(r.WebhookConfigs) > 0 { - return fmt.Errorf("cannot have both Alertmanager WebhookConfigs & Grafana receivers together") - } - if len(r.OpsGenieConfigs) > 0 { - return fmt.Errorf("cannot have both Alertmanager OpsGenieConfigs & Grafana receivers together") - } - if len(r.WechatConfigs) > 0 { - return fmt.Errorf("cannot have both Alertmanager WechatConfigs & Grafana receivers together") - } - if len(r.PushoverConfigs) > 0 { - return fmt.Errorf("cannot have both Alertmanager PushoverConfigs & Grafana receivers together") - } - if len(r.VictorOpsConfigs) > 0 { - return fmt.Errorf("cannot have both Alertmanager VictorOpsConfigs & Grafana receivers together") - } - } - - return nil -} - -func (r *GettableApiReceiver) Type() ReceiverType { - if len(r.GrafanaManagedReceivers) > 0 { - return GrafanaReceiverType - } - return AlertmanagerReceiverType + return json.Unmarshal(b, (*plain)(r)) } func (r *GettableApiReceiver) GetName() string { diff --git a/pkg/services/ngalert/notifier/alertmanager_config.go b/pkg/services/ngalert/notifier/alertmanager_config.go index 3d4ebba01f9..25a24cb5441 100644 --- a/pkg/services/ngalert/notifier/alertmanager_config.go +++ b/pkg/services/ngalert/notifier/alertmanager_config.go @@ -452,26 +452,22 @@ func assignReceiverConfigsUIDs(c []*definitions.PostableApiReceiver) error { seenUIDs := make(map[string]struct{}) // encrypt secure settings for storing them in DB for _, r := range c { - switch r.Type() { - case definitions.GrafanaReceiverType: - for _, gr := range r.GrafanaManagedReceivers { - if gr.UID == "" { - retries := 5 - for i := 0; i < retries; i++ { - gen := util.GenerateShortUID() - _, ok := seenUIDs[gen] - if !ok { - gr.UID = gen - break - } - } - if gr.UID == "" { - return fmt.Errorf("all %d attempts to generate UID for receiver have failed; please retry", retries) + for _, gr := range r.GrafanaManagedReceivers { + if gr.UID == "" { + retries := 5 + for i := 0; i < retries; i++ { + gen := util.GenerateShortUID() + _, ok := seenUIDs[gen] + if !ok { + gr.UID = gen + break } } - seenUIDs[gr.UID] = struct{}{} + if gr.UID == "" { + return fmt.Errorf("all %d attempts to generate UID for receiver have failed; please retry", retries) + } } - default: + seenUIDs[gr.UID] = struct{}{} } } return nil diff --git a/pkg/services/ngalert/notifier/crypto.go b/pkg/services/ngalert/notifier/crypto.go index a44ff34af88..c147fa4cec2 100644 --- a/pkg/services/ngalert/notifier/crypto.go +++ b/pkg/services/ngalert/notifier/crypto.go @@ -87,81 +87,77 @@ func EncryptReceiverConfigSettings(c []*definitions.PostableApiReceiver, encrypt func encryptReceiverConfigs(c []*definitions.PostableApiReceiver, encrypt definitions.EncryptFn, encryptExisting bool) error { // encrypt secure settings for storing them in DB for _, r := range c { - switch r.Type() { - case definitions.GrafanaReceiverType: - for _, gr := range r.GrafanaManagedReceivers { - if encryptExisting { - for k, v := range gr.SecureSettings { - encryptedData, err := encrypt(context.Background(), []byte(v)) + for _, gr := range r.GrafanaManagedReceivers { + if encryptExisting { + for k, v := range gr.SecureSettings { + encryptedData, err := encrypt(context.Background(), []byte(v)) + if err != nil { + return fmt.Errorf("failed to encrypt secure settings: %w", err) + } + gr.SecureSettings[k] = base64.StdEncoding.EncodeToString(encryptedData) + } + } + + if len(gr.Settings) > 0 { + // We need to parse the settings to check for secret keys. If we find any, we encrypt them and + // store them in SecureSettings. This can happen from incorrect configuration or when an integration + // definition is updated to make a field secure. + settings := make(map[string]any) + if err := json.Unmarshal(gr.Settings, &settings); err != nil { + return fmt.Errorf("integration '%s' of receiver '%s' has settings that cannot be parsed as JSON: %w", gr.Type, gr.Name, err) + } + + secretKeys, err := channels_config.GetSecretKeysForContactPointType(gr.Type, channels_config.V1) + if err != nil { + return fmt.Errorf("failed to get secret keys for contact point type %s: %w", gr.Type, err) + } + + secureSettings := gr.SecureSettings + if secureSettings == nil { + secureSettings = make(map[string]string) + } + + settingsChanged := false + secureSettingsChanged := false + for _, secretKey := range secretKeys { + settingsValue, ok := settings[secretKey] + if !ok { + continue + } + + // Secrets should not be stored in settings regardless. + delete(settings, secretKey) + settingsChanged = true + + // If the secret is already encrypted, we don't need to encrypt it again. + if _, ok := secureSettings[secretKey]; ok { + continue + } + + if strVal, isString := settingsValue.(string); isString { + encrypted, err := encrypt(context.Background(), []byte(strVal)) if err != nil { return fmt.Errorf("failed to encrypt secure settings: %w", err) } - gr.SecureSettings[k] = base64.StdEncoding.EncodeToString(encryptedData) + secureSettings[secretKey] = base64.StdEncoding.EncodeToString(encrypted) + secureSettingsChanged = true } } - if len(gr.Settings) > 0 { - // We need to parse the settings to check for secret keys. If we find any, we encrypt them and - // store them in SecureSettings. This can happen from incorrect configuration or when an integration - // definition is updated to make a field secure. - settings := make(map[string]any) - if err := json.Unmarshal(gr.Settings, &settings); err != nil { - return fmt.Errorf("integration '%s' of receiver '%s' has settings that cannot be parsed as JSON: %w", gr.Type, gr.Name, err) - } - - secretKeys, err := channels_config.GetSecretKeysForContactPointType(gr.Type, channels_config.V1) + // Defensive checks to limit the risk of unintentional edge case changes in this legacy API. + if settingsChanged { + // If we removed any secret keys from settings, we need to save the updated settings. + jsonBytes, err := json.Marshal(settings) if err != nil { - return fmt.Errorf("failed to get secret keys for contact point type %s: %w", gr.Type, err) - } - - secureSettings := gr.SecureSettings - if secureSettings == nil { - secureSettings = make(map[string]string) - } - - settingsChanged := false - secureSettingsChanged := false - for _, secretKey := range secretKeys { - settingsValue, ok := settings[secretKey] - if !ok { - continue - } - - // Secrets should not be stored in settings regardless. - delete(settings, secretKey) - settingsChanged = true - - // If the secret is already encrypted, we don't need to encrypt it again. - if _, ok := secureSettings[secretKey]; ok { - continue - } - - if strVal, isString := settingsValue.(string); isString { - encrypted, err := encrypt(context.Background(), []byte(strVal)) - if err != nil { - return fmt.Errorf("failed to encrypt secure settings: %w", err) - } - secureSettings[secretKey] = base64.StdEncoding.EncodeToString(encrypted) - secureSettingsChanged = true - } - } - - // Defensive checks to limit the risk of unintentional edge case changes in this legacy API. - if settingsChanged { - // If we removed any secret keys from settings, we need to save the updated settings. - jsonBytes, err := json.Marshal(settings) - if err != nil { - return err - } - gr.Settings = jsonBytes - } - if secureSettingsChanged { - // If we added any secure settings, we need to save the updated secure settings. - gr.SecureSettings = secureSettings + return err } + gr.Settings = jsonBytes + } + if secureSettingsChanged { + // If we added any secure settings, we need to save the updated secure settings. + gr.SecureSettings = secureSettings } } - default: } } return nil