diff --git a/cli/alert_add.go b/cli/alert_add.go index 035d5f58a0..6018b95654 100644 --- a/cli/alert_add.go +++ b/cli/alert_add.go @@ -15,6 +15,7 @@ package cli import ( "context" + "errors" "fmt" "strconv" "time" @@ -24,6 +25,8 @@ import ( "github.com/prometheus/alertmanager/api/v2/client/alert" "github.com/prometheus/alertmanager/api/v2/models" + "github.com/prometheus/alertmanager/matchers/compat" + "github.com/prometheus/alertmanager/pkg/labels" ) type alertAddCmd struct { @@ -74,29 +77,45 @@ func (a *alertAddCmd) addAlert(ctx context.Context, _ *kingpin.ParseContext) err if len(a.labels) > 0 { // Allow the alertname label to be defined implicitly as the first argument rather // than explicitly as a key=value pair. - if _, err := parseLabels([]string{a.labels[0]}); err != nil { + if _, err := compat.Matcher(a.labels[0]); err != nil { a.labels[0] = fmt.Sprintf("alertname=%s", strconv.Quote(a.labels[0])) } } - labels, err := parseLabels(a.labels) - if err != nil { - return err + ls := make(models.LabelSet, len(a.labels)) + for _, l := range a.labels { + matcher, err := compat.Matcher(l) + if err != nil { + return err + } + if matcher.Type != labels.MatchEqual { + return errors.New("labels must be specified as key=value pairs") + } + ls[matcher.Name] = matcher.Value } - annotations, err := parseLabels(a.annotations) - if err != nil { - return err + annotations := make(models.LabelSet, len(a.annotations)) + for _, a := range a.annotations { + matcher, err := compat.Matcher(a) + if err != nil { + return err + } + if matcher.Type != labels.MatchEqual { + return errors.New("annotations must be specified as key=value pairs") + } + annotations[matcher.Name] = matcher.Value } var startsAt, endsAt time.Time if a.start != "" { + var err error startsAt, err = time.Parse(time.RFC3339, a.start) if err != nil { return err } } if a.end != "" { + var err error endsAt, err = time.Parse(time.RFC3339, a.end) if err != nil { return err @@ -106,7 +125,7 @@ func (a *alertAddCmd) addAlert(ctx context.Context, _ *kingpin.ParseContext) err pa := &models.PostableAlert{ Alert: models.Alert{ GeneratorURL: strfmt.URI(a.generatorURL), - Labels: labels, + Labels: ls, }, Annotations: annotations, StartsAt: strfmt.DateTime(startsAt), @@ -117,6 +136,6 @@ func (a *alertAddCmd) addAlert(ctx context.Context, _ *kingpin.ParseContext) err amclient := NewAlertmanagerClient(alertmanagerURL) - _, err = amclient.Alert.PostAlerts(alertParams) + _, err := amclient.Alert.PostAlerts(alertParams) return err } diff --git a/cli/silence_add.go b/cli/silence_add.go index c50496743f..d30a523431 100644 --- a/cli/silence_add.go +++ b/cli/silence_add.go @@ -27,6 +27,8 @@ import ( "github.com/prometheus/alertmanager/api/v2/client/silence" "github.com/prometheus/alertmanager/api/v2/models" + "github.com/prometheus/alertmanager/matchers/compat" + "github.com/prometheus/alertmanager/pkg/labels" ) func username() string { @@ -93,17 +95,20 @@ func (c *silenceAddCmd) add(ctx context.Context, _ *kingpin.ParseContext) error // If the parser fails then we likely don't have a (=|=~|!=|!~) so lets // assume that the user wants alertname= and prepend `alertname=` // to the front. - _, err := parseMatchers([]string{c.matchers[0]}) + _, err := compat.Matcher(c.matchers[0]) if err != nil { c.matchers[0] = fmt.Sprintf("alertname=%s", strconv.Quote(c.matchers[0])) } } - matchers, err := parseMatchers(c.matchers) - if err != nil { - return err + matchers := make([]labels.Matcher, 0, len(c.matchers)) + for _, s := range c.matchers { + m, err := compat.Matcher(s) + if err != nil { + return err + } + matchers = append(matchers, *m) } - if len(matchers) < 1 { return fmt.Errorf("no matchers specified") } diff --git a/cli/silence_query.go b/cli/silence_query.go index 85540c82e7..ddffca3b3c 100644 --- a/cli/silence_query.go +++ b/cli/silence_query.go @@ -25,6 +25,7 @@ import ( "github.com/prometheus/alertmanager/api/v2/client/silence" "github.com/prometheus/alertmanager/api/v2/models" "github.com/prometheus/alertmanager/cli/format" + "github.com/prometheus/alertmanager/matchers/compat" ) type silenceQueryCmd struct { @@ -98,7 +99,7 @@ func (c *silenceQueryCmd) query(ctx context.Context, _ *kingpin.ParseContext) er // If the parser fails then we likely don't have a (=|=~|!=|!~) so lets // assume that the user wants alertname= and prepend `alertname=` // to the front. - _, err := parseMatchers([]string{c.matchers[0]}) + _, err := compat.Matcher(c.matchers[0]) if err != nil { c.matchers[0] = fmt.Sprintf("alertname=%s", strconv.Quote(c.matchers[0])) } diff --git a/cli/test_routing.go b/cli/test_routing.go index e93f40b7a1..85c29a7e2f 100644 --- a/cli/test_routing.go +++ b/cli/test_routing.go @@ -24,6 +24,8 @@ import ( "github.com/prometheus/alertmanager/api/v2/models" "github.com/prometheus/alertmanager/dispatch" + "github.com/prometheus/alertmanager/matchers/compat" + "github.com/prometheus/alertmanager/pkg/labels" ) const routingTestHelp = `Test alert routing @@ -80,9 +82,16 @@ func (c *routingShow) routingTestAction(ctx context.Context, _ *kingpin.ParseCon mainRoute := dispatch.NewRoute(cfg.Route, nil) // Parse labels to LabelSet. - ls, err := parseLabels(c.labels) - if err != nil { - kingpin.Fatalf("Failed to parse labels: %v\n", err) + ls := make(models.LabelSet, len(c.labels)) + for _, l := range c.labels { + matcher, err := compat.Matcher(l) + if err != nil { + kingpin.Fatalf("Failed to parse labels: %v\n", err) + } + if matcher.Type != labels.MatchEqual { + kingpin.Fatalf("%s\n", "Labels must be specified as key=value pairs") + } + ls[matcher.Name] = matcher.Value } if c.debugTree { diff --git a/cli/utils.go b/cli/utils.go index 3cb178fa6e..dfe39dd867 100644 --- a/cli/utils.go +++ b/cli/utils.go @@ -26,23 +26,9 @@ import ( "github.com/prometheus/alertmanager/api/v2/client/general" "github.com/prometheus/alertmanager/api/v2/models" "github.com/prometheus/alertmanager/config" - "github.com/prometheus/alertmanager/matchers/compat" "github.com/prometheus/alertmanager/pkg/labels" ) -// parseMatchers parses a list of matchers (cli arguments). -func parseMatchers(inputMatchers []string) ([]labels.Matcher, error) { - matchers := make([]labels.Matcher, 0, len(inputMatchers)) - for _, s := range inputMatchers { - matcher, err := compat.Matcher(s) - if err != nil { - return []labels.Matcher{}, err - } - matchers = append(matchers, *matcher) - } - return matchers, nil -} - // getRemoteAlertmanagerConfigStatus returns status responsecontaining configuration from remote Alertmanager func getRemoteAlertmanagerConfigStatus(ctx context.Context, alertmanagerURL *url.URL) (*models.AlertmanagerStatus, error) { amclient := NewAlertmanagerClient(alertmanagerURL) @@ -92,25 +78,6 @@ func convertClientToCommonLabelSet(cls models.LabelSet) model.LabelSet { return mls } -// parseLabels parses a list of labels (cli arguments). -func parseLabels(inputLabels []string) (models.LabelSet, error) { - labelSet := make(models.LabelSet, len(inputLabels)) - - for _, l := range inputLabels { - matcher, err := compat.Matcher(l) - if err != nil { - return models.LabelSet{}, err - } - if matcher.Type != labels.MatchEqual { - return models.LabelSet{}, errors.New("labels must be specified as key=value pairs") - } - - labelSet[matcher.Name] = matcher.Value - } - - return labelSet, nil -} - // TypeMatchers only valid for when you are going to add a silence func TypeMatchers(matchers []labels.Matcher) models.Matchers { typeMatchers := make(models.Matchers, len(matchers))