|
|
|
@ -2,16 +2,19 @@ package notifier |
|
|
|
|
|
|
|
|
|
import ( |
|
|
|
|
"context" |
|
|
|
|
"encoding/json" |
|
|
|
|
"errors" |
|
|
|
|
"fmt" |
|
|
|
|
"time" |
|
|
|
|
|
|
|
|
|
"github.com/go-openapi/strfmt" |
|
|
|
|
"k8s.io/apimachinery/pkg/util/sets" |
|
|
|
|
|
|
|
|
|
"github.com/grafana/grafana/pkg/apimachinery/errutil" |
|
|
|
|
"github.com/grafana/grafana/pkg/services/featuremgmt" |
|
|
|
|
"github.com/grafana/grafana/pkg/services/ngalert/api/tooling/definitions" |
|
|
|
|
"github.com/grafana/grafana/pkg/services/ngalert/models" |
|
|
|
|
"github.com/grafana/grafana/pkg/services/ngalert/notifier/legacy_storage" |
|
|
|
|
"github.com/grafana/grafana/pkg/services/ngalert/store" |
|
|
|
|
"github.com/grafana/grafana/pkg/util" |
|
|
|
|
) |
|
|
|
@ -58,10 +61,32 @@ func (moa *MultiOrgAlertmanager) SaveAndApplyDefaultConfig(ctx context.Context, |
|
|
|
|
return err |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
previousConfig, cleanPermissionsErr := moa.configStore.GetLatestAlertmanagerConfiguration(ctx, orgId) |
|
|
|
|
|
|
|
|
|
err = orgAM.SaveAndApplyDefaultConfig(ctx) |
|
|
|
|
if err != nil { |
|
|
|
|
return err |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Attempt to cleanup permissions for receivers that are no longer defined and add defaults for new receivers.
|
|
|
|
|
// Failure should not prevent the default config from being applied.
|
|
|
|
|
if cleanPermissionsErr == nil { |
|
|
|
|
cleanPermissionsErr = func() error { |
|
|
|
|
defaultedConfig, err := moa.configStore.GetLatestAlertmanagerConfiguration(ctx, orgId) |
|
|
|
|
if err != nil { |
|
|
|
|
return err |
|
|
|
|
} |
|
|
|
|
newReceiverNames, err := extractReceiverNames(defaultedConfig.AlertmanagerConfiguration) |
|
|
|
|
if err != nil { |
|
|
|
|
return err |
|
|
|
|
} |
|
|
|
|
return moa.cleanPermissions(ctx, orgId, previousConfig, newReceiverNames) |
|
|
|
|
}() |
|
|
|
|
} |
|
|
|
|
if cleanPermissionsErr != nil { |
|
|
|
|
moa.logger.Error("Failed to clean permissions for receivers", "error", cleanPermissionsErr) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return nil |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -130,12 +155,29 @@ func (moa *MultiOrgAlertmanager) ActivateHistoricalConfiguration(ctx context.Con |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
previousConfig, cleanPermissionsErr := moa.configStore.GetLatestAlertmanagerConfiguration(ctx, orgId) |
|
|
|
|
|
|
|
|
|
if err := am.SaveAndApplyConfig(ctx, cfg); err != nil { |
|
|
|
|
moa.logger.Error("Unable to save and apply historical alertmanager configuration", "error", err, "org", orgId, "id", id) |
|
|
|
|
return AlertmanagerConfigRejectedError{err} |
|
|
|
|
} |
|
|
|
|
moa.logger.Info("Applied historical alertmanager configuration", "org", orgId, "id", id) |
|
|
|
|
|
|
|
|
|
// Attempt to cleanup permissions for receivers that are no longer defined and add defaults for new receivers.
|
|
|
|
|
// Failure should not prevent the default config from being applied.
|
|
|
|
|
if cleanPermissionsErr == nil { |
|
|
|
|
cleanPermissionsErr = func() error { |
|
|
|
|
newReceiverNames, err := extractReceiverNames(config.AlertmanagerConfiguration) |
|
|
|
|
if err != nil { |
|
|
|
|
return err |
|
|
|
|
} |
|
|
|
|
return moa.cleanPermissions(ctx, orgId, previousConfig, newReceiverNames) |
|
|
|
|
}() |
|
|
|
|
} |
|
|
|
|
if cleanPermissionsErr != nil { |
|
|
|
|
moa.logger.Error("Failed to clean permissions for receivers", "error", cleanPermissionsErr) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return nil |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -231,13 +273,14 @@ func (moa *MultiOrgAlertmanager) SaveAndApplyAlertmanagerConfiguration(ctx conte |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Get the last known working configuration
|
|
|
|
|
_, err := moa.configStore.GetLatestAlertmanagerConfiguration(ctx, org) |
|
|
|
|
previousConfig, err := moa.configStore.GetLatestAlertmanagerConfiguration(ctx, org) |
|
|
|
|
if err != nil { |
|
|
|
|
// If we don't have a configuration there's nothing for us to know and we should just continue saving the new one
|
|
|
|
|
if !errors.Is(err, store.ErrNoAlertmanagerConfiguration) { |
|
|
|
|
return fmt.Errorf("failed to get latest configuration %w", err) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
cleanPermissionsErr := err |
|
|
|
|
|
|
|
|
|
if err := moa.Crypto.ProcessSecureSettings(ctx, org, config.AlertmanagerConfig.Receivers); err != nil { |
|
|
|
|
return fmt.Errorf("failed to post process Alertmanager configuration: %w", err) |
|
|
|
@ -268,6 +311,21 @@ func (moa *MultiOrgAlertmanager) SaveAndApplyAlertmanagerConfiguration(ctx conte |
|
|
|
|
return AlertmanagerConfigRejectedError{err} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Attempt to cleanup permissions for receivers that are no longer defined and add defaults for new receivers.
|
|
|
|
|
// Failure should not prevent the default config from being applied.
|
|
|
|
|
if cleanPermissionsErr == nil { |
|
|
|
|
cleanPermissionsErr = func() error { |
|
|
|
|
newReceiverNames := make(sets.Set[string], len(config.AlertmanagerConfig.Receivers)) |
|
|
|
|
for _, r := range config.AlertmanagerConfig.Receivers { |
|
|
|
|
newReceiverNames.Insert(r.Name) |
|
|
|
|
} |
|
|
|
|
return moa.cleanPermissions(ctx, org, previousConfig, newReceiverNames) |
|
|
|
|
}() |
|
|
|
|
} |
|
|
|
|
if cleanPermissionsErr != nil { |
|
|
|
|
moa.logger.Error("Failed to clean permissions for receivers", "error", cleanPermissionsErr) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return nil |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -352,3 +410,51 @@ func (moa *MultiOrgAlertmanager) mergeProvenance(ctx context.Context, config def |
|
|
|
|
|
|
|
|
|
return config, nil |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// cleanPermissions will remove permissions for receivers that are no longer defined in the new configuration and
|
|
|
|
|
// set default permissions for new receivers.
|
|
|
|
|
func (moa *MultiOrgAlertmanager) cleanPermissions(ctx context.Context, orgID int64, previousConfig *models.AlertConfiguration, newReceiverNames sets.Set[string]) error { |
|
|
|
|
previousReceiverNames, err := extractReceiverNames(previousConfig.AlertmanagerConfiguration) |
|
|
|
|
if err != nil { |
|
|
|
|
return fmt.Errorf("failed to extract receiver names from previous configuration: %w", err) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
var errs []error |
|
|
|
|
for receiverName := range previousReceiverNames.Difference(newReceiverNames) { // Deleted receivers.
|
|
|
|
|
if err := moa.receiverResourcePermissions.DeleteResourcePermissions(ctx, orgID, legacy_storage.NameToUid(receiverName)); err != nil { |
|
|
|
|
errs = append(errs, fmt.Errorf("failed to delete permissions for receiver %s: %w", receiverName, err)) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
for receiverName := range newReceiverNames.Difference(previousReceiverNames) { // Added receivers.
|
|
|
|
|
moa.receiverResourcePermissions.SetDefaultPermissions(ctx, orgID, nil, legacy_storage.NameToUid(receiverName)) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return errors.Join(errs...) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// extractReceiverNames extracts receiver names from the raw Alertmanager configuration. Unmarshalling ignores fields
|
|
|
|
|
// unrelated to receiver names, making it more resilient to invalid configurations.
|
|
|
|
|
func extractReceiverNames(rawConfig string) (sets.Set[string], error) { |
|
|
|
|
// Slimmed down version of the Alertmanager configuration to extract receiver names. This is more resilient to
|
|
|
|
|
// invalid configurations when all we are interested in is the receiver names.
|
|
|
|
|
type receiverUserConfig struct { |
|
|
|
|
AlertmanagerConfig struct { |
|
|
|
|
Receivers []struct { |
|
|
|
|
Name string `yaml:"name" json:"name"` |
|
|
|
|
} `yaml:"receivers,omitempty" json:"receivers,omitempty"` |
|
|
|
|
} `yaml:"alertmanager_config" json:"alertmanager_config"` |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
cfg := &receiverUserConfig{} |
|
|
|
|
if err := json.Unmarshal([]byte(rawConfig), cfg); err != nil { |
|
|
|
|
return nil, fmt.Errorf("unable to parse Alertmanager configuration: %w", err) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
receiverNames := make(sets.Set[string], len(cfg.AlertmanagerConfig.Receivers)) |
|
|
|
|
for _, r := range cfg.AlertmanagerConfig.Receivers { |
|
|
|
|
receiverNames[r.Name] = struct{}{} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return receiverNames, nil |
|
|
|
|
} |
|
|
|
|