diff --git a/internal/controller/alertmanager_controller.go b/internal/controller/alertmanager_controller.go index 8799353b..d8efc62c 100644 --- a/internal/controller/alertmanager_controller.go +++ b/internal/controller/alertmanager_controller.go @@ -46,6 +46,7 @@ func SetupAlertmanagerReconciler(mgr ctrl.Manager, conf config.Config) error { // Setup the controller return ctrl.NewControllerManagedBy(mgr). + Named("alertmanager"). For(&v1.Secret{}, builder.WithPredicates(secretPredicate)). Watches(&v1.Pod{}, p, builder.WithPredicates(podPredicate)). Complete(r) diff --git a/pkg/alertmanager/alertmanager.go b/pkg/alertmanager/alertmanager.go index a2c71864..07ad4ca4 100644 --- a/pkg/alertmanager/alertmanager.go +++ b/pkg/alertmanager/alertmanager.go @@ -5,10 +5,8 @@ import ( "context" "fmt" "io" - "maps" "net/http" "path" - "slices" "strings" "github.com/pkg/errors" @@ -89,33 +87,31 @@ func (s Service) Configure(ctx context.Context, secret *v1.Secret) error { } // configure sends the configuration and templates to Mimir Alertmanager's API +// It is the caller responsibility to make sure templates names are valid (do not contain any path), and that templates are referenced in the configuration. // https://grafana.com/docs/mimir/latest/references/http-api/#set-alertmanager-configuration func (s Service) configure(ctx context.Context, alertmanagerConfigContent []byte, templates map[string]string, tenantID string) error { logger := log.FromContext(ctx) - // Load alertmanager configuration - alertmanagerConfig, err := config.Load(string(alertmanagerConfigContent)) + // Validate Alertmanager configuration + // The returned config is not used, as transforming it via String() would produce an invalid configuration with all secrets replaced with . + _, err := config.Load(string(alertmanagerConfigContent)) if err != nil { return errors.WithStack(fmt.Errorf("alertmanager: failed to load configuration: %w", err)) } - // Set template names - // Values set here must match the keys set in requestData.TemplateFiles - alertmanagerConfig.Templates = slices.Collect(maps.Keys(templates)) - alertmanagerConfigString := alertmanagerConfig.String() - // Prepare request for Alertmanager API requestData := configRequest{ - AlertmanagerConfig: alertmanagerConfigString, + AlertmanagerConfig: string(alertmanagerConfigContent), TemplateFiles: templates, } data, err := yaml.Marshal(requestData) if err != nil { return errors.WithStack(fmt.Errorf("alertmanager: failed to marshal yaml: %w", err)) } + dataLen := len(data) url := s.alertmanagerURL + alertmanagerAPIPath - logger.WithValues("url", url, "data_size", len(data), "config_size", len(alertmanagerConfigString), "templates_count", len(templates)).Info("Alertmanager: sending configuration") + logger.WithValues("url", url, "data_size", dataLen, "config_size", len(alertmanagerConfigContent), "templates_count", len(templates)).Info("Alertmanager: sending configuration") // Send request to Alertmanager's API req, err := http.NewRequest(http.MethodPost, url, bytes.NewBuffer(data)) @@ -123,6 +119,7 @@ func (s Service) configure(ctx context.Context, alertmanagerConfigContent []byte return errors.WithStack(fmt.Errorf("alertmanager: failed to create request: %w", err)) } req.Header.Set(common.OrgIDHeader, tenantID) + req.ContentLength = int64(dataLen) resp, err := http.DefaultClient.Do(req) if err != nil {