Skip to content

Commit

Permalink
Fix sending invalid Alertmanager configuration (#205)
Browse files Browse the repository at this point in the history
* Set alertmanager controller name
  • Loading branch information
TheoBrigitte authored Dec 17, 2024
1 parent c273356 commit ae3a611
Show file tree
Hide file tree
Showing 2 changed files with 9 additions and 11 deletions.
1 change: 1 addition & 0 deletions internal/controller/alertmanager_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
19 changes: 8 additions & 11 deletions pkg/alertmanager/alertmanager.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,8 @@ import (
"context"
"fmt"
"io"
"maps"
"net/http"
"path"
"slices"
"strings"

"github.com/pkg/errors"
Expand Down Expand Up @@ -89,40 +87,39 @@ 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 <redacted>.
_, 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))
if err != nil {
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 {
Expand Down

0 comments on commit ae3a611

Please sign in to comment.