cli: update amtool to use apiv2

Includes godoc improvements

Signed-off-by: Paul Gier <pgier@redhat.com>
This commit is contained in:
Paul Gier 2019-03-13 11:01:08 -05:00
parent 89b0ff0574
commit 74fa2236f7
19 changed files with 283 additions and 225 deletions

View File

@ -529,7 +529,7 @@ var (
// then by end time or start time depending on the state.
// active silences should show the next to expire first
// pending silences are ordered based on which one starts next
// expired are ordered base on which one expired most recently
// expired are ordered based on which one expired most recently
func sortSilences(sils open_api_models.GettableSilences) {
sort.Slice(sils, func(i, j int) bool {
state1 := types.SilenceState(*sils[i].Status.State)

View File

@ -19,9 +19,10 @@ import (
"fmt"
"time"
"github.com/prometheus/alertmanager/client"
"github.com/prometheus/client_golang/api"
"gopkg.in/alecthomas/kingpin.v2"
"github.com/go-openapi/strfmt"
"github.com/prometheus/alertmanager/api/v2/client/alert"
"github.com/prometheus/alertmanager/api/v2/models"
kingpin "gopkg.in/alecthomas/kingpin.v2"
)
type alertAddCmd struct {
@ -69,11 +70,6 @@ func configureAddAlertCmd(cc *kingpin.CmdClause) {
}
func (a *alertAddCmd) addAlert(ctx context.Context, _ *kingpin.ParseContext) error {
c, err := api.NewClient(api.Config{Address: alertmanagerURL.String()})
if err != nil {
return err
}
alertAPI := client.NewAlertAPI(c)
if len(a.labels) > 0 {
// Allow the alertname label to be defined implicitly as the first argument rather
@ -107,11 +103,20 @@ func (a *alertAddCmd) addAlert(ctx context.Context, _ *kingpin.ParseContext) err
}
}
return alertAPI.Push(ctx, client.Alert{
Labels: labels,
Annotations: annotations,
StartsAt: startsAt,
EndsAt: endsAt,
GeneratorURL: a.generatorURL,
})
pa := &models.PostableAlert{
Alert: models.Alert{
GeneratorURL: strfmt.URI(a.generatorURL),
Labels: labels,
},
Annotations: annotations,
StartsAt: strfmt.DateTime(startsAt),
EndsAt: strfmt.DateTime(endsAt),
}
alertParams := alert.NewPostAlertsParams().WithContext(ctx).
WithAlerts(models.PostableAlerts{pa})
amclient := NewAlertmanagerClient(alertmanagerURL)
_, err = amclient.Alert.PostAlerts(alertParams)
return err
}

View File

@ -17,13 +17,11 @@ import (
"context"
"errors"
"fmt"
"strings"
"github.com/prometheus/client_golang/api"
"gopkg.in/alecthomas/kingpin.v2"
kingpin "gopkg.in/alecthomas/kingpin.v2"
"github.com/prometheus/alertmanager/api/v2/client/alert"
"github.com/prometheus/alertmanager/cli/format"
"github.com/prometheus/alertmanager/client"
"github.com/prometheus/alertmanager/pkg/parse"
)
@ -76,7 +74,7 @@ func configureQueryAlertsCmd(cc *kingpin.CmdClause) {
}
func (a *alertQueryCmd) queryAlerts(ctx context.Context, _ *kingpin.ParseContext) error {
var filterString = ""
filter := []string{}
if len(a.matcherGroups) > 0 {
// Attempt to parse the first argument. If the parser fails
// then we likely don't have a (=|=~|!=|!~) so lets assume that
@ -87,19 +85,25 @@ func (a *alertQueryCmd) queryAlerts(ctx context.Context, _ *kingpin.ParseContext
if err != nil {
a.matcherGroups[0] = fmt.Sprintf("alertname=%s", m)
}
filterString = fmt.Sprintf("{%s}", strings.Join(a.matcherGroups, ","))
filter = append(filter, a.matcherGroups[0])
}
c, err := api.NewClient(api.Config{Address: alertmanagerURL.String()})
if err != nil {
return err
}
alertAPI := client.NewAlertAPI(c)
// If no selector was passed, default to showing active alerts.
if !a.silenced && !a.inhibited && !a.active && !a.unprocessed {
a.active = true
}
fetchedAlerts, err := alertAPI.List(ctx, filterString, a.receiver, a.silenced, a.inhibited, a.active, a.unprocessed)
alertParams := alert.NewGetAlertsParams().WithContext(ctx)
alertParams.Active = &a.active
alertParams.Inhibited = &a.inhibited
alertParams.Silenced = &a.silenced
alertParams.Unprocessed = &a.unprocessed
alertParams.Filter = filter
amclient := NewAlertmanagerClient(alertmanagerURL)
getOk, err := amclient.Alert.GetAlerts(alertParams)
if err != nil {
return err
}
@ -108,5 +112,5 @@ func (a *alertQueryCmd) queryAlerts(ctx context.Context, _ *kingpin.ParseContext
if !found {
return errors.New("unknown output formatter")
}
return formatter.FormatAlerts(fetchedAlerts)
return formatter.FormatAlerts(getOk.Payload)
}

View File

@ -17,7 +17,7 @@ import (
"context"
"errors"
"gopkg.in/alecthomas/kingpin.v2"
kingpin "gopkg.in/alecthomas/kingpin.v2"
"github.com/prometheus/alertmanager/cli/format"
)

View File

@ -17,10 +17,10 @@ import (
"io"
"time"
"gopkg.in/alecthomas/kingpin.v2"
kingpin "gopkg.in/alecthomas/kingpin.v2"
"github.com/prometheus/alertmanager/client"
"github.com/prometheus/alertmanager/types"
"github.com/go-openapi/strfmt"
"github.com/prometheus/alertmanager/api/v2/models"
)
const DefaultDateFormat = "2006-01-02 15:04:05 MST"
@ -36,14 +36,18 @@ func InitFormatFlags(app *kingpin.Application) {
// Formatter needs to be implemented for each new output formatter.
type Formatter interface {
SetOutput(io.Writer)
FormatSilences([]types.Silence) error
FormatAlerts([]*client.ExtendedAlert) error
FormatConfig(*client.ServerStatus) error
FormatSilences([]models.GettableSilence) error
FormatAlerts([]*models.GettableAlert) error
FormatConfig(*models.AlertmanagerStatus) error
}
// Formatters is a map of cli argument names to formatter interface object.
var Formatters = map[string]Formatter{}
func FormatDateTime(input strfmt.DateTime) string {
return FormatDate(time.Time(input))
}
func FormatDate(input time.Time) string {
return input.Format(*dateFormat)
}

View File

@ -20,9 +20,9 @@ import (
"sort"
"strings"
"text/tabwriter"
"time"
"github.com/prometheus/alertmanager/client"
"github.com/prometheus/alertmanager/types"
"github.com/prometheus/alertmanager/api/v2/models"
)
type ExtendedFormatter struct {
@ -37,7 +37,8 @@ func (formatter *ExtendedFormatter) SetOutput(writer io.Writer) {
formatter.writer = writer
}
func (formatter *ExtendedFormatter) FormatSilences(silences []types.Silence) error {
// FormatSilences formats the silences into a readable string
func (formatter *ExtendedFormatter) FormatSilences(silences []models.GettableSilence) error {
w := tabwriter.NewWriter(formatter.writer, 0, 0, 2, ' ', 0)
sort.Sort(ByEndAt(silences))
fmt.Fprintln(w, "ID\tMatchers\tStarts At\tEnds At\tUpdated At\tCreated By\tComment\t")
@ -45,19 +46,20 @@ func (formatter *ExtendedFormatter) FormatSilences(silences []types.Silence) err
fmt.Fprintf(
w,
"%s\t%s\t%s\t%s\t%s\t%s\t%s\t\n",
silence.ID,
*silence.ID,
extendedFormatMatchers(silence.Matchers),
FormatDate(silence.StartsAt),
FormatDate(silence.EndsAt),
FormatDate(silence.UpdatedAt),
silence.CreatedBy,
silence.Comment,
FormatDateTime(*silence.Silence.StartsAt),
FormatDateTime(*silence.Silence.EndsAt),
FormatDateTime(*silence.UpdatedAt),
*silence.CreatedBy,
*silence.Comment,
)
}
return w.Flush()
}
func (formatter *ExtendedFormatter) FormatAlerts(alerts []*client.ExtendedAlert) error {
// FormatAlerts formats the alerts into a readable string
func (formatter *ExtendedFormatter) FormatAlerts(alerts []*models.GettableAlert) error {
w := tabwriter.NewWriter(formatter.writer, 0, 0, 2, ' ', 0)
sort.Sort(ByStartsAt(alerts))
fmt.Fprintln(w, "Labels\tAnnotations\tStarts At\tEnds At\tGenerator URL\t")
@ -67,27 +69,28 @@ func (formatter *ExtendedFormatter) FormatAlerts(alerts []*client.ExtendedAlert)
"%s\t%s\t%s\t%s\t%s\t\n",
extendedFormatLabels(alert.Labels),
extendedFormatAnnotations(alert.Annotations),
FormatDate(alert.StartsAt),
FormatDate(alert.EndsAt),
FormatDate(time.Time(*alert.StartsAt)),
FormatDate(time.Time(*alert.EndsAt)),
alert.GeneratorURL,
)
}
return w.Flush()
}
func (formatter *ExtendedFormatter) FormatConfig(status *client.ServerStatus) error {
fmt.Fprintln(formatter.writer, status.ConfigYAML)
fmt.Fprintln(formatter.writer, "buildUser", status.VersionInfo["buildUser"])
fmt.Fprintln(formatter.writer, "goVersion", status.VersionInfo["goVersion"])
fmt.Fprintln(formatter.writer, "revision", status.VersionInfo["revision"])
fmt.Fprintln(formatter.writer, "version", status.VersionInfo["version"])
fmt.Fprintln(formatter.writer, "branch", status.VersionInfo["branch"])
fmt.Fprintln(formatter.writer, "buildDate", status.VersionInfo["buildDate"])
// FormatConfig formats the alertmanager status information into a readable string
func (formatter *ExtendedFormatter) FormatConfig(status *models.AlertmanagerStatus) error {
fmt.Fprintln(formatter.writer, status.Config.Original)
fmt.Fprintln(formatter.writer, "buildUser", status.VersionInfo.BuildUser)
fmt.Fprintln(formatter.writer, "goVersion", status.VersionInfo.GoVersion)
fmt.Fprintln(formatter.writer, "revision", status.VersionInfo.Revision)
fmt.Fprintln(formatter.writer, "version", status.VersionInfo.Version)
fmt.Fprintln(formatter.writer, "branch", status.VersionInfo.Branch)
fmt.Fprintln(formatter.writer, "buildDate", status.VersionInfo.BuildDate)
fmt.Fprintln(formatter.writer, "uptime", status.Uptime)
return nil
}
func extendedFormatLabels(labels client.LabelSet) string {
func extendedFormatLabels(labels models.LabelSet) string {
output := []string{}
for name, value := range labels {
output = append(output, fmt.Sprintf("%s=\"%s\"", name, value))
@ -96,7 +99,7 @@ func extendedFormatLabels(labels client.LabelSet) string {
return strings.Join(output, " ")
}
func extendedFormatAnnotations(labels client.LabelSet) string {
func extendedFormatAnnotations(labels models.LabelSet) string {
output := []string{}
for name, value := range labels {
output = append(output, fmt.Sprintf("%s=\"%s\"", name, value))
@ -105,7 +108,7 @@ func extendedFormatAnnotations(labels client.LabelSet) string {
return strings.Join(output, " ")
}
func extendedFormatMatchers(matchers types.Matchers) string {
func extendedFormatMatchers(matchers models.Matchers) string {
output := []string{}
for _, matcher := range matchers {
output = append(output, extendedFormatMatcher(*matcher))
@ -113,9 +116,9 @@ func extendedFormatMatchers(matchers types.Matchers) string {
return strings.Join(output, " ")
}
func extendedFormatMatcher(matcher types.Matcher) string {
if matcher.IsRegex {
return fmt.Sprintf("%s~=%s", matcher.Name, matcher.Value)
func extendedFormatMatcher(matcher models.Matcher) string {
if *matcher.IsRegex {
return fmt.Sprintf("%s~=%s", *matcher.Name, *matcher.Value)
}
return fmt.Sprintf("%s=%s", matcher.Name, matcher.Value)
return fmt.Sprintf("%s=%s", *matcher.Name, *matcher.Value)
}

View File

@ -18,8 +18,7 @@ import (
"io"
"os"
"github.com/prometheus/alertmanager/client"
"github.com/prometheus/alertmanager/types"
"github.com/prometheus/alertmanager/api/v2/models"
)
type JSONFormatter struct {
@ -34,17 +33,17 @@ func (formatter *JSONFormatter) SetOutput(writer io.Writer) {
formatter.writer = writer
}
func (formatter *JSONFormatter) FormatSilences(silences []types.Silence) error {
func (formatter *JSONFormatter) FormatSilences(silences []models.GettableSilence) error {
enc := json.NewEncoder(formatter.writer)
return enc.Encode(silences)
}
func (formatter *JSONFormatter) FormatAlerts(alerts []*client.ExtendedAlert) error {
func (formatter *JSONFormatter) FormatAlerts(alerts []*models.GettableAlert) error {
enc := json.NewEncoder(formatter.writer)
return enc.Encode(alerts)
}
func (formatter *JSONFormatter) FormatConfig(status *client.ServerStatus) error {
func (formatter *JSONFormatter) FormatConfig(status *models.AlertmanagerStatus) error {
enc := json.NewEncoder(formatter.writer)
return enc.Encode(status)
}

View File

@ -20,9 +20,9 @@ import (
"sort"
"strings"
"text/tabwriter"
"time"
"github.com/prometheus/alertmanager/client"
"github.com/prometheus/alertmanager/types"
"github.com/prometheus/alertmanager/api/v2/models"
)
type SimpleFormatter struct {
@ -37,7 +37,7 @@ func (formatter *SimpleFormatter) SetOutput(writer io.Writer) {
formatter.writer = writer
}
func (formatter *SimpleFormatter) FormatSilences(silences []types.Silence) error {
func (formatter *SimpleFormatter) FormatSilences(silences []models.GettableSilence) error {
w := tabwriter.NewWriter(formatter.writer, 0, 0, 2, ' ', 0)
sort.Sort(ByEndAt(silences))
fmt.Fprintln(w, "ID\tMatchers\tEnds At\tCreated By\tComment\t")
@ -45,17 +45,17 @@ func (formatter *SimpleFormatter) FormatSilences(silences []types.Silence) error
fmt.Fprintf(
w,
"%s\t%s\t%s\t%s\t%s\t\n",
silence.ID,
*silence.ID,
simpleFormatMatchers(silence.Matchers),
FormatDate(silence.EndsAt),
silence.CreatedBy,
silence.Comment,
FormatDateTime(*silence.EndsAt),
*silence.CreatedBy,
*silence.Comment,
)
}
return w.Flush()
}
func (formatter *SimpleFormatter) FormatAlerts(alerts []*client.ExtendedAlert) error {
func (formatter *SimpleFormatter) FormatAlerts(alerts []*models.GettableAlert) error {
w := tabwriter.NewWriter(formatter.writer, 0, 0, 2, ' ', 0)
sort.Sort(ByStartsAt(alerts))
fmt.Fprintln(w, "Alertname\tStarts At\tSummary\t")
@ -64,19 +64,19 @@ func (formatter *SimpleFormatter) FormatAlerts(alerts []*client.ExtendedAlert) e
w,
"%s\t%s\t%s\t\n",
alert.Labels["alertname"],
FormatDate(alert.StartsAt),
FormatDate(time.Time(*alert.StartsAt)),
alert.Annotations["summary"],
)
}
return w.Flush()
}
func (formatter *SimpleFormatter) FormatConfig(status *client.ServerStatus) error {
fmt.Fprintln(formatter.writer, status.ConfigYAML)
func (formatter *SimpleFormatter) FormatConfig(status *models.AlertmanagerStatus) error {
fmt.Fprintln(formatter.writer, *status)
return nil
}
func simpleFormatMatchers(matchers types.Matchers) string {
func simpleFormatMatchers(matchers models.Matchers) string {
output := []string{}
for _, matcher := range matchers {
output = append(output, simpleFormatMatcher(*matcher))
@ -84,9 +84,9 @@ func simpleFormatMatchers(matchers types.Matchers) string {
return strings.Join(output, " ")
}
func simpleFormatMatcher(matcher types.Matcher) string {
if matcher.IsRegex {
return fmt.Sprintf("%s=~%s", matcher.Name, matcher.Value)
func simpleFormatMatcher(matcher models.Matcher) string {
if *matcher.IsRegex {
return fmt.Sprintf("%s=~%s", *matcher.Name, *matcher.Value)
}
return fmt.Sprintf("%s=%s", matcher.Name, matcher.Value)
return fmt.Sprintf("%s=%s", *matcher.Name, *matcher.Value)
}

View File

@ -14,18 +14,23 @@
package format
import (
"github.com/prometheus/alertmanager/client"
"github.com/prometheus/alertmanager/types"
"time"
"github.com/prometheus/alertmanager/api/v2/models"
)
type ByEndAt []types.Silence
type ByEndAt []models.GettableSilence
func (s ByEndAt) Len() int { return len(s) }
func (s ByEndAt) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
func (s ByEndAt) Less(i, j int) bool { return s[i].EndsAt.Before(s[j].EndsAt) }
func (s ByEndAt) Len() int { return len(s) }
func (s ByEndAt) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
func (s ByEndAt) Less(i, j int) bool {
return time.Time(*s[i].Silence.EndsAt).Before(time.Time(*s[j].Silence.EndsAt))
}
type ByStartsAt []*client.ExtendedAlert
type ByStartsAt []*models.GettableAlert
func (s ByStartsAt) Len() int { return len(s) }
func (s ByStartsAt) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
func (s ByStartsAt) Less(i, j int) bool { return s[i].StartsAt.Before(s[j].StartsAt) }
func (s ByStartsAt) Len() int { return len(s) }
func (s ByStartsAt) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
func (s ByStartsAt) Less(i, j int) bool {
return time.Time(*s[i].StartsAt).Before(time.Time(*s[j].StartsAt))
}

View File

@ -18,9 +18,11 @@ import (
"os"
"time"
"github.com/go-openapi/strfmt"
"github.com/prometheus/common/version"
"gopkg.in/alecthomas/kingpin.v2"
kingpin "gopkg.in/alecthomas/kingpin.v2"
"github.com/prometheus/alertmanager/api/v2/client"
"github.com/prometheus/alertmanager/cli/config"
"github.com/prometheus/alertmanager/cli/format"
)
@ -53,6 +55,26 @@ func requireAlertManagerURL(pc *kingpin.ParseContext) error {
return nil
}
const (
defaultAmHost = "localhost"
defaultAmPort = "9093"
defaultAmApiv2path = "/api/v2"
)
// NewAlertmanagerClient initializes an alertmanager client with the given URL
func NewAlertmanagerClient(amURL *url.URL) *client.Alertmanager {
transportConfig := client.DefaultTransportConfig()
transportConfig.BasePath = defaultAmApiv2path
if amURL.Host == "" {
transportConfig.Host = defaultAmHost + ":" + defaultAmPort
} else {
transportConfig.Host = amURL.Host
}
return client.NewHTTPClientWithConfig(strfmt.Default, transportConfig)
}
// Execute is the main function for the amtool command
func Execute() {
var (
app = kingpin.New("amtool", helpRoot).DefaultEnvars()

View File

@ -20,9 +20,9 @@ import (
"github.com/xlab/treeprint"
"github.com/prometheus/alertmanager/client"
"github.com/prometheus/alertmanager/api/v2/models"
"github.com/prometheus/alertmanager/dispatch"
"gopkg.in/alecthomas/kingpin.v2"
kingpin "gopkg.in/alecthomas/kingpin.v2"
)
type routingShow struct {
@ -61,7 +61,7 @@ func configureRoutingCmd(app *kingpin.CmdClause) {
}
func (c *routingShow) routingShowAction(ctx context.Context, _ *kingpin.ParseContext) error {
// Load configuration form file or URL.
// Load configuration from file or URL.
cfg, err := loadAlertmanagerConfig(ctx, alertmanagerURL, c.configFile)
if err != nil {
kingpin.Fatalf("%s", err)
@ -101,7 +101,7 @@ func convertRouteToTree(route *dispatch.Route, tree treeprint.Tree) {
}
}
func getMatchingTree(route *dispatch.Route, tree treeprint.Tree, lset client.LabelSet) {
func getMatchingTree(route *dispatch.Route, tree treeprint.Tree, lset models.LabelSet) {
final := true
branch := tree.AddBranch(getRouteTreeSlug(route, false, false))
for _, r := range route.Routes {

View File

@ -20,12 +20,12 @@ import (
"os/user"
"time"
"github.com/prometheus/client_golang/api"
"github.com/go-openapi/strfmt"
"github.com/prometheus/common/model"
"gopkg.in/alecthomas/kingpin.v2"
kingpin "gopkg.in/alecthomas/kingpin.v2"
"github.com/prometheus/alertmanager/client"
"github.com/prometheus/alertmanager/types"
"github.com/prometheus/alertmanager/api/v2/client/silence"
"github.com/prometheus/alertmanager/api/v2/models"
)
func username() string {
@ -149,24 +149,26 @@ func (c *silenceAddCmd) add(ctx context.Context, _ *kingpin.ParseContext) error
return err
}
silence := types.Silence{
Matchers: typeMatchers,
StartsAt: startsAt,
EndsAt: endsAt,
CreatedBy: c.author,
Comment: c.comment,
start := strfmt.DateTime(startsAt)
end := strfmt.DateTime(endsAt)
ps := &models.PostableSilence{
Silence: models.Silence{
Matchers: typeMatchers,
StartsAt: &start,
EndsAt: &end,
CreatedBy: &c.author,
Comment: &c.comment,
},
}
silenceParams := silence.NewPostSilencesParams().WithContext(ctx).
WithSilence(ps)
apiClient, err := api.NewClient(api.Config{Address: alertmanagerURL.String()})
amclient := NewAlertmanagerClient(alertmanagerURL)
postOk, err := amclient.Silence.PostSilences(silenceParams)
if err != nil {
return err
}
silenceAPI := client.NewSilenceAPI(apiClient)
silenceID, err := silenceAPI.Set(ctx, silence)
if err != nil {
return err
}
_, err = fmt.Println(silenceID)
fmt.Println(*postOk.Payload)
return err
}

View File

@ -17,10 +17,9 @@ import (
"context"
"errors"
"github.com/prometheus/client_golang/api"
"gopkg.in/alecthomas/kingpin.v2"
"github.com/prometheus/alertmanager/client"
"github.com/go-openapi/strfmt"
"github.com/prometheus/alertmanager/api/v2/client/silence"
kingpin "gopkg.in/alecthomas/kingpin.v2"
)
type silenceExpireCmd struct {
@ -41,14 +40,12 @@ func (c *silenceExpireCmd) expire(ctx context.Context, _ *kingpin.ParseContext)
return errors.New("no silence IDs specified")
}
apiClient, err := api.NewClient(api.Config{Address: alertmanagerURL.String()})
if err != nil {
return err
}
silenceAPI := client.NewSilenceAPI(apiClient)
amclient := NewAlertmanagerClient(alertmanagerURL)
for _, id := range c.ids {
err := silenceAPI.Expire(ctx, id)
params := silence.NewDeleteSilenceParams().WithContext(ctx)
params.SilenceID = strfmt.UUID(id)
_, err := amclient.Silence.DeleteSilence(params)
if err != nil {
return err
}

View File

@ -22,11 +22,10 @@ import (
"sync"
"github.com/pkg/errors"
"github.com/prometheus/client_golang/api"
"gopkg.in/alecthomas/kingpin.v2"
kingpin "gopkg.in/alecthomas/kingpin.v2"
"github.com/prometheus/alertmanager/client"
"github.com/prometheus/alertmanager/types"
"github.com/prometheus/alertmanager/api/v2/client/silence"
"github.com/prometheus/alertmanager/api/v2/models"
)
type silenceImportCmd struct {
@ -59,20 +58,21 @@ func configureSilenceImportCmd(cc *kingpin.CmdClause) {
importCmd.Action(execWithTimeout(c.bulkImport))
}
func addSilenceWorker(ctx context.Context, sclient client.SilenceAPI, silencec <-chan *types.Silence, errc chan<- error) {
func addSilenceWorker(ctx context.Context, sclient *silence.Client, silencec <-chan *models.PostableSilence, errc chan<- error) {
for s := range silencec {
silenceID, err := sclient.Set(ctx, *s)
sid := s.ID
params := silence.NewPostSilencesParams().WithContext(ctx)
params.Silence = s
postOk, err := sclient.PostSilences(params)
if err != nil && strings.Contains(err.Error(), "not found") {
// silence doesn't exists yet, retry to create as a new one
s.ID = ""
silenceID, err = sclient.Set(ctx, *s)
params.Silence.ID = ""
postOk, _ = sclient.PostSilences(params)
}
if err != nil {
fmt.Fprintf(os.Stderr, "Error adding silence id='%v': %v\n", sid, err)
fmt.Fprintf(os.Stderr, "Error adding silence id='%v': %v\n", s.ID, err)
} else {
fmt.Println(silenceID)
fmt.Println(postOk.Payload.SilenceID)
}
errc <- err
}
@ -96,18 +96,14 @@ func (c *silenceImportCmd) bulkImport(ctx context.Context, _ *kingpin.ParseConte
return errors.Wrap(err, "couldn't unmarshal input data, is it JSON?")
}
apiClient, err := api.NewClient(api.Config{Address: alertmanagerURL.String()})
if err != nil {
return err
}
silenceAPI := client.NewSilenceAPI(apiClient)
silencec := make(chan *types.Silence, 100)
amclient := NewAlertmanagerClient(alertmanagerURL)
silencec := make(chan *models.PostableSilence, 100)
errc := make(chan error, 100)
var wg sync.WaitGroup
for w := 0; w < c.workers; w++ {
wg.Add(1)
go func() {
addSilenceWorker(ctx, silenceAPI, silencec, errc)
addSilenceWorker(ctx, amclient.Silence, silencec, errc)
wg.Done()
}()
}
@ -123,7 +119,7 @@ func (c *silenceImportCmd) bulkImport(ctx context.Context, _ *kingpin.ParseConte
count := 0
for dec.More() {
var s types.Silence
var s models.PostableSilence
err := dec.Decode(&s)
if err != nil {
return errors.Wrap(err, "couldn't unmarshal input data, is it JSON?")

View File

@ -17,16 +17,14 @@ import (
"context"
"errors"
"fmt"
"strings"
"time"
"github.com/prometheus/client_golang/api"
"gopkg.in/alecthomas/kingpin.v2"
kingpin "gopkg.in/alecthomas/kingpin.v2"
"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/client"
"github.com/prometheus/alertmanager/pkg/parse"
"github.com/prometheus/alertmanager/types"
)
type silenceQueryCmd struct {
@ -92,7 +90,7 @@ func configureSilenceQueryCmd(cc *kingpin.CmdClause) {
}
func (c *silenceQueryCmd) query(ctx context.Context, _ *kingpin.ParseContext) error {
var filterString = ""
filter := []string{}
if len(c.matchers) > 0 {
// If the parser fails then we likely don't have a (=|=~|!=|!~) so lets
// assume that the user wants alertname=<arg> and prepend `alertname=`
@ -101,35 +99,35 @@ func (c *silenceQueryCmd) query(ctx context.Context, _ *kingpin.ParseContext) er
if err != nil {
c.matchers[0] = fmt.Sprintf("alertname=%s", c.matchers[0])
}
filterString = fmt.Sprintf("{%s}", strings.Join(c.matchers, ","))
filter = append(filter, c.matchers[0])
}
apiClient, err := api.NewClient(api.Config{Address: alertmanagerURL.String()})
if err != nil {
return err
}
silenceAPI := client.NewSilenceAPI(apiClient)
fetchedSilences, err := silenceAPI.List(ctx, filterString)
silenceParams := silence.NewGetSilencesParams().WithContext(ctx)
silenceParams.Filter = filter
amclient := NewAlertmanagerClient(alertmanagerURL)
getOk, err := amclient.Silence.GetSilences(silenceParams)
if err != nil {
return err
}
displaySilences := []types.Silence{}
for _, silence := range fetchedSilences {
displaySilences := []models.GettableSilence{}
for _, silence := range getOk.Payload {
// skip expired silences if --expired is not set
if !c.expired && silence.EndsAt.Before(time.Now()) {
if !c.expired && time.Time(*silence.EndsAt).Before(time.Now()) {
continue
}
// skip active silences if --expired is set
if c.expired && silence.EndsAt.After(time.Now()) {
if c.expired && time.Time(*silence.EndsAt).After(time.Now()) {
continue
}
// skip active silences expiring after "--within"
if !c.expired && int64(c.within) > 0 && silence.EndsAt.After(time.Now().UTC().Add(c.within)) {
if !c.expired && int64(c.within) > 0 && time.Time(*silence.EndsAt).After(time.Now().UTC().Add(c.within)) {
continue
}
// skip silences that expired before "--within"
if c.expired && int64(c.within) > 0 && silence.EndsAt.Before(time.Now().UTC().Add(-c.within)) {
if c.expired && int64(c.within) > 0 && time.Time(*silence.EndsAt).Before(time.Now().UTC().Add(-c.within)) {
continue
}

View File

@ -19,12 +19,12 @@ import (
"fmt"
"time"
"github.com/prometheus/client_golang/api"
"gopkg.in/alecthomas/kingpin.v2"
kingpin "gopkg.in/alecthomas/kingpin.v2"
"github.com/go-openapi/strfmt"
"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/client"
"github.com/prometheus/alertmanager/types"
"github.com/prometheus/common/model"
)
@ -57,30 +57,33 @@ func (c *silenceUpdateCmd) update(ctx context.Context, _ *kingpin.ParseContext)
return fmt.Errorf("no silence IDs specified")
}
apiClient, err := api.NewClient(api.Config{Address: alertmanagerURL.String()})
if err != nil {
return err
}
silenceAPI := client.NewSilenceAPI(apiClient)
amclient := NewAlertmanagerClient(alertmanagerURL)
var updatedSilences []types.Silence
var updatedSilences []models.GettableSilence
for _, silenceID := range c.ids {
silence, err := silenceAPI.Get(ctx, silenceID)
params := silence.NewGetSilenceParams()
params.SilenceID = strfmt.UUID(silenceID)
response, err := amclient.Silence.GetSilence(params)
sil := response.Payload
if err != nil {
return err
}
if c.start != "" {
silence.StartsAt, err = time.Parse(time.RFC3339, c.start)
startsAtTime, err := time.Parse(time.RFC3339, c.start)
if err != nil {
return err
}
startsAt := strfmt.DateTime(startsAtTime)
sil.StartsAt = &startsAt
}
if c.end != "" {
silence.EndsAt, err = time.Parse(time.RFC3339, c.end)
endsAtTime, err := time.Parse(time.RFC3339, c.end)
if err != nil {
return err
}
endsAt := strfmt.DateTime(endsAtTime)
sil.EndsAt = &endsAt
} else if c.duration != "" {
d, err := model.ParseDuration(c.duration)
if err != nil {
@ -89,24 +92,35 @@ func (c *silenceUpdateCmd) update(ctx context.Context, _ *kingpin.ParseContext)
if d == 0 {
return fmt.Errorf("silence duration must be greater than 0")
}
silence.EndsAt = silence.StartsAt.UTC().Add(time.Duration(d))
endsAt := strfmt.DateTime(time.Time(*sil.StartsAt).UTC().Add(time.Duration(d)))
sil.EndsAt = &endsAt
}
if silence.StartsAt.After(silence.EndsAt) {
if time.Time(*sil.StartsAt).After(time.Time(*sil.EndsAt)) {
return errors.New("silence cannot start after it ends")
}
if c.comment != "" {
silence.Comment = c.comment
sil.Comment = &c.comment
}
newID, err := silenceAPI.Set(ctx, *silence)
ps := &models.PostableSilence{
ID: *sil.ID,
Silence: sil.Silence,
}
silenceParams := silence.NewPostSilencesParams().WithContext(ctx)
silenceParams.Silence = ps
amclient := NewAlertmanagerClient(alertmanagerURL)
postOk, err := amclient.Silence.PostSilences(silenceParams)
if err != nil {
return err
}
silence.ID = newID
updatedSilences = append(updatedSilences, *silence)
sil.ID = &postOk.Payload.SilenceID
updatedSilences = append(updatedSilences, *sil)
}
if c.quiet {

View File

@ -19,10 +19,10 @@ import (
"os"
"strings"
"github.com/prometheus/alertmanager/client"
"github.com/prometheus/alertmanager/api/v2/models"
"github.com/prometheus/alertmanager/dispatch"
"github.com/xlab/treeprint"
"gopkg.in/alecthomas/kingpin.v2"
kingpin "gopkg.in/alecthomas/kingpin.v2"
)
const routingTestHelp = `Test alert routing
@ -49,7 +49,7 @@ func configureRoutingTestCmd(cc *kingpin.CmdClause, c *routingShow) {
}
// resolveAlertReceivers returns list of receiver names which given LabelSet resolves to.
func resolveAlertReceivers(mainRoute *dispatch.Route, labels *client.LabelSet) ([]string, error) {
func resolveAlertReceivers(mainRoute *dispatch.Route, labels *models.LabelSet) ([]string, error) {
var (
finalRoutes []*dispatch.Route
receivers []string
@ -61,7 +61,7 @@ func resolveAlertReceivers(mainRoute *dispatch.Route, labels *client.LabelSet) (
return receivers, nil
}
func printMatchingTree(mainRoute *dispatch.Route, ls client.LabelSet) {
func printMatchingTree(mainRoute *dispatch.Route, ls models.LabelSet) {
tree := treeprint.New()
getMatchingTree(mainRoute, tree, ls)
fmt.Println("Matching routes:")

View File

@ -19,18 +19,18 @@ import (
"strings"
"testing"
"github.com/prometheus/alertmanager/client"
"github.com/prometheus/alertmanager/api/v2/models"
"github.com/prometheus/alertmanager/config"
"github.com/prometheus/alertmanager/dispatch"
)
type routingTestDefinition struct {
alert client.LabelSet
alert models.LabelSet
expectedReceivers []string
configFile string
}
func checkResolvedReceivers(mainRoute *dispatch.Route, ls client.LabelSet, expectedReceivers []string) error {
func checkResolvedReceivers(mainRoute *dispatch.Route, ls models.LabelSet, expectedReceivers []string) error {
resolvedReceivers, err := resolveAlertReceivers(mainRoute, &ls)
if err != nil {
return err
@ -43,10 +43,10 @@ func checkResolvedReceivers(mainRoute *dispatch.Route, ls client.LabelSet, expec
func TestRoutingTest(t *testing.T) {
tests := []*routingTestDefinition{
&routingTestDefinition{configFile: "testdata/conf.routing.yml", alert: client.LabelSet{"test": "1"}, expectedReceivers: []string{"test1"}},
&routingTestDefinition{configFile: "testdata/conf.routing.yml", alert: client.LabelSet{"test": "2"}, expectedReceivers: []string{"test1", "test2"}},
&routingTestDefinition{configFile: "testdata/conf.routing-reverted.yml", alert: client.LabelSet{"test": "2"}, expectedReceivers: []string{"test2", "test1"}},
&routingTestDefinition{configFile: "testdata/conf.routing.yml", alert: client.LabelSet{"test": "volovina"}, expectedReceivers: []string{"default"}},
&routingTestDefinition{configFile: "testdata/conf.routing.yml", alert: models.LabelSet{"test": "1"}, expectedReceivers: []string{"test1"}},
&routingTestDefinition{configFile: "testdata/conf.routing.yml", alert: models.LabelSet{"test": "2"}, expectedReceivers: []string{"test1", "test2"}},
&routingTestDefinition{configFile: "testdata/conf.routing-reverted.yml", alert: models.LabelSet{"test": "2"}, expectedReceivers: []string{"test2", "test1"}},
&routingTestDefinition{configFile: "testdata/conf.routing.yml", alert: models.LabelSet{"test": "volovina"}, expectedReceivers: []string{"default"}},
}
for _, test := range tests {

View File

@ -21,13 +21,13 @@ import (
"os"
"path"
"github.com/prometheus/alertmanager/client"
"github.com/prometheus/alertmanager/api/v2/client/general"
"github.com/prometheus/alertmanager/api/v2/models"
"github.com/prometheus/alertmanager/config"
amconfig "github.com/prometheus/alertmanager/config"
"github.com/prometheus/client_golang/api"
kingpin "gopkg.in/alecthomas/kingpin.v2"
"github.com/prometheus/alertmanager/pkg/parse"
"github.com/prometheus/alertmanager/types"
"github.com/prometheus/common/model"
"github.com/prometheus/prometheus/pkg/labels"
)
@ -74,17 +74,15 @@ func parseMatchers(inputMatchers []string) ([]labels.Matcher, error) {
}
// getRemoteAlertmanagerConfigStatus returns status responsecontaining configuration from remote Alertmanager
func getRemoteAlertmanagerConfigStatus(ctx context.Context, alertmanagerURL *url.URL) (*client.ServerStatus, error) {
c, err := api.NewClient(api.Config{Address: alertmanagerURL.String()})
func getRemoteAlertmanagerConfigStatus(ctx context.Context, alertmanagerURL *url.URL) (*models.AlertmanagerStatus, error) {
amclient := NewAlertmanagerClient(alertmanagerURL)
params := general.NewGetStatusParams().WithContext(ctx)
getOk, err := amclient.General.GetStatus(params)
if err != nil {
return nil, err
}
statusAPI := client.NewStatusAPI(c)
status, err := statusAPI.Get(ctx)
if err != nil {
return nil, err
}
return status, nil
return getOk.Payload, nil
}
func checkRoutingConfigInputFlags(alertmanagerURL *url.URL, configFile string) {
@ -106,17 +104,21 @@ func loadAlertmanagerConfig(ctx context.Context, alertmanagerURL *url.URL, confi
return cfg, nil
}
if alertmanagerURL != nil {
status, err := getRemoteAlertmanagerConfigStatus(ctx, alertmanagerURL)
configStatus, err := getRemoteAlertmanagerConfigStatus(ctx, alertmanagerURL)
if err != nil {
return nil, err
}
return status.ConfigJSON, nil
conf, err := config.Load(*configStatus.Config.Original)
if err != nil {
return nil, err
}
return conf, nil
}
return nil, errors.New("failed to get Alertmanager configuration")
}
// convertClientToCommonLabelSet converts client.LabelSet to model.Labelset
func convertClientToCommonLabelSet(cls client.LabelSet) model.LabelSet {
func convertClientToCommonLabelSet(cls models.LabelSet) model.LabelSet {
mls := make(model.LabelSet, len(cls))
for ln, lv := range cls {
mls[model.LabelName(ln)] = model.LabelValue(lv)
@ -125,51 +127,58 @@ func convertClientToCommonLabelSet(cls client.LabelSet) model.LabelSet {
}
// Parse a list of labels (cli arguments)
func parseLabels(inputLabels []string) (client.LabelSet, error) {
labelSet := make(client.LabelSet, len(inputLabels))
func parseLabels(inputLabels []string) (models.LabelSet, error) {
labelSet := make(models.LabelSet, len(inputLabels))
for _, l := range inputLabels {
name, value, matchType, err := parse.Input(l)
if err != nil {
return client.LabelSet{}, err
return models.LabelSet{}, err
}
if matchType != labels.MatchEqual {
return client.LabelSet{}, errors.New("labels must be specified as key=value pairs")
return models.LabelSet{}, errors.New("labels must be specified as key=value pairs")
}
labelSet[client.LabelName(name)] = client.LabelValue(value)
labelSet[name] = value
}
return labelSet, nil
}
// Only valid for when you are going to add a silence
func TypeMatchers(matchers []labels.Matcher) (types.Matchers, error) {
typeMatchers := types.Matchers{}
// TypeMatchers Only valid for when you are going to add a silence
func TypeMatchers(matchers []labels.Matcher) (models.Matchers, error) {
typeMatchers := models.Matchers{}
for _, matcher := range matchers {
typeMatcher, err := TypeMatcher(matcher)
if err != nil {
return types.Matchers{}, err
return models.Matchers{}, err
}
typeMatchers = append(typeMatchers, &typeMatcher)
}
return typeMatchers, nil
}
// Only valid for when you are going to add a silence
// TypeMatcher Only valid for when you are going to add a silence
// Doesn't allow negative operators
func TypeMatcher(matcher labels.Matcher) (types.Matcher, error) {
typeMatcher := types.NewMatcher(model.LabelName(matcher.Name), matcher.Value)
func TypeMatcher(matcher labels.Matcher) (models.Matcher, error) {
name := matcher.Name
value := matcher.Value
typeMatcher := models.Matcher{
Name: &name,
Value: &value,
}
isRegex := false
switch matcher.Type {
case labels.MatchEqual:
typeMatcher.IsRegex = false
isRegex = false
case labels.MatchRegexp:
typeMatcher.IsRegex = true
isRegex = true
default:
return types.Matcher{}, fmt.Errorf("invalid match type for creation operation: %s", matcher.Type)
return models.Matcher{}, fmt.Errorf("invalid match type for creation operation: %s", matcher.Type)
}
return *typeMatcher, nil
typeMatcher.IsRegex = &isRegex
return typeMatcher, nil
}
// Helper function for adding the ctx with timeout into an action.