mirror of
https://github.com/prometheus/alertmanager
synced 2025-02-22 05:46:53 +00:00
Add timeout support to amtool commands (#1471)
Signed-off-by: stuart nelson <stuartnelson3@gmail.com>
This commit is contained in:
parent
50e271678d
commit
bd6100793f
@ -17,10 +17,11 @@ import (
|
||||
"context"
|
||||
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/prometheus/alertmanager/client"
|
||||
"github.com/prometheus/client_golang/api"
|
||||
"gopkg.in/alecthomas/kingpin.v2"
|
||||
"time"
|
||||
)
|
||||
|
||||
type alertAddCmd struct {
|
||||
@ -64,10 +65,10 @@ func configureAddAlertCmd(cc *kingpin.CmdClause) {
|
||||
addCmd.Flag("start", "Set when the alert should start. RFC3339 format 2006-01-02T15:04:05Z07:00").StringVar(&a.start)
|
||||
addCmd.Flag("end", "Set when the alert should should end. RFC3339 format 2006-01-02T15:04:05Z07:00").StringVar(&a.end)
|
||||
addCmd.Flag("annotation", "Set an annotation to be included with the alert").StringsVar(&a.annotations)
|
||||
addCmd.Action(a.addAlert)
|
||||
addCmd.Action(execWithTimeout(a.addAlert))
|
||||
}
|
||||
|
||||
func (a *alertAddCmd) addAlert(ctx *kingpin.ParseContext) error {
|
||||
func (a *alertAddCmd) addAlert(ctx context.Context, _ *kingpin.ParseContext) error {
|
||||
c, err := api.NewClient(api.Config{Address: alertmanagerURL.String()})
|
||||
if err != nil {
|
||||
return err
|
||||
@ -106,7 +107,7 @@ func (a *alertAddCmd) addAlert(ctx *kingpin.ParseContext) error {
|
||||
}
|
||||
}
|
||||
|
||||
return alertAPI.Push(context.Background(), client.Alert{
|
||||
return alertAPI.Push(ctx, client.Alert{
|
||||
Labels: labels,
|
||||
Annotations: annotations,
|
||||
StartsAt: startsAt,
|
||||
|
@ -72,10 +72,10 @@ func configureQueryAlertsCmd(cc *kingpin.CmdClause) {
|
||||
queryCmd.Flag("unprocessed", "Show unprocessed alerts").Short('u').BoolVar(&a.unprocessed)
|
||||
queryCmd.Flag("receiver", "Show alerts matching receiver (Supports regex syntax)").Short('r').StringVar(&a.receiver)
|
||||
queryCmd.Arg("matcher-groups", "Query filter").StringsVar(&a.matcherGroups)
|
||||
queryCmd.Action(a.queryAlerts)
|
||||
queryCmd.Action(execWithTimeout(a.queryAlerts))
|
||||
}
|
||||
|
||||
func (a *alertQueryCmd) queryAlerts(ctx *kingpin.ParseContext) error {
|
||||
func (a *alertQueryCmd) queryAlerts(ctx context.Context, _ *kingpin.ParseContext) error {
|
||||
var filterString = ""
|
||||
if len(a.matcherGroups) == 1 {
|
||||
// If the parser fails then we likely don't have a (=|=~|!=|!~) so lets
|
||||
@ -100,7 +100,7 @@ func (a *alertQueryCmd) queryAlerts(ctx *kingpin.ParseContext) error {
|
||||
if !a.silenced && !a.inhibited && !a.active && !a.unprocessed {
|
||||
a.active = true
|
||||
}
|
||||
fetchedAlerts, err := alertAPI.List(context.Background(), filterString, a.receiver, a.silenced, a.inhibited, a.active, a.unprocessed)
|
||||
fetchedAlerts, err := alertAPI.List(ctx, filterString, a.receiver, a.silenced, a.inhibited, a.active, a.unprocessed)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -34,17 +34,17 @@ The amount of output is controlled by the output selection flag:
|
||||
|
||||
// configCmd represents the config command
|
||||
func configureConfigCmd(app *kingpin.Application) {
|
||||
app.Command("config", configHelp).Action(queryConfig).PreAction(requireAlertManagerURL)
|
||||
app.Command("config", configHelp).Action(execWithTimeout(queryConfig)).PreAction(requireAlertManagerURL)
|
||||
|
||||
}
|
||||
|
||||
func queryConfig(ctx *kingpin.ParseContext) error {
|
||||
func queryConfig(ctx context.Context, _ *kingpin.ParseContext) error {
|
||||
c, err := api.NewClient(api.Config{Address: alertmanagerURL.String()})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
statusAPI := client.NewStatusAPI(c)
|
||||
status, err := statusAPI.Get(context.Background())
|
||||
status, err := statusAPI.Get(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -16,6 +16,7 @@ package cli
|
||||
import (
|
||||
"net/url"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/prometheus/common/version"
|
||||
"gopkg.in/alecthomas/kingpin.v2"
|
||||
@ -28,6 +29,7 @@ var (
|
||||
verbose bool
|
||||
alertmanagerURL *url.URL
|
||||
output string
|
||||
timeout time.Duration
|
||||
|
||||
configFiles = []string{os.ExpandEnv("$HOME/.config/amtool/config.yml"), "/etc/amtool/config.yml"}
|
||||
legacyFlags = map[string]string{"comment_required": "require-comment"}
|
||||
@ -61,6 +63,8 @@ func Execute() {
|
||||
app.Flag("verbose", "Verbose running information").Short('v').BoolVar(&verbose)
|
||||
app.Flag("alertmanager.url", "Alertmanager to talk to").URLVar(&alertmanagerURL)
|
||||
app.Flag("output", "Output formatter (simple, extended, json)").Short('o').Default("simple").EnumVar(&output, "simple", "extended", "json")
|
||||
app.Flag("timeout", "Timeout for the executed command").Default("30s").DurationVar(&timeout)
|
||||
|
||||
app.Version(version.Print("amtool"))
|
||||
app.GetFlag("help").Short('h')
|
||||
app.UsageTemplate(kingpin.CompactUsageTemplate)
|
||||
|
@ -13,7 +13,9 @@
|
||||
|
||||
package cli
|
||||
|
||||
import "gopkg.in/alecthomas/kingpin.v2"
|
||||
import (
|
||||
"gopkg.in/alecthomas/kingpin.v2"
|
||||
)
|
||||
|
||||
// silenceCmd represents the silence command
|
||||
func configureSilenceCmd(app *kingpin.Application) {
|
||||
|
@ -82,11 +82,11 @@ func configureSilenceAddCmd(cc *kingpin.CmdClause) {
|
||||
addCmd.Flag("end", "Set when the silence should end (overwrites duration). RFC3339 format 2006-01-02T15:04:05Z07:00").StringVar(&c.end)
|
||||
addCmd.Flag("comment", "A comment to help describe the silence").Short('c').StringVar(&c.comment)
|
||||
addCmd.Arg("matcher-groups", "Query filter").StringsVar(&c.matchers)
|
||||
addCmd.Action(c.add)
|
||||
addCmd.Action(execWithTimeout(c.add))
|
||||
|
||||
}
|
||||
|
||||
func (c *silenceAddCmd) add(ctx *kingpin.ParseContext) error {
|
||||
func (c *silenceAddCmd) add(ctx context.Context, _ *kingpin.ParseContext) error {
|
||||
var err error
|
||||
|
||||
matchers, err := parseMatchers(c.matchers)
|
||||
@ -152,7 +152,7 @@ func (c *silenceAddCmd) add(ctx *kingpin.ParseContext) error {
|
||||
return err
|
||||
}
|
||||
silenceAPI := client.NewSilenceAPI(apiClient)
|
||||
silenceID, err := silenceAPI.Set(context.Background(), silence)
|
||||
silenceID, err := silenceAPI.Set(ctx, silence)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -33,10 +33,10 @@ func configureSilenceExpireCmd(cc *kingpin.CmdClause) {
|
||||
expireCmd = cc.Command("expire", "expire an alertmanager silence")
|
||||
)
|
||||
expireCmd.Arg("silence-ids", "Ids of silences to expire").StringsVar(&c.ids)
|
||||
expireCmd.Action(c.expire)
|
||||
expireCmd.Action(execWithTimeout(c.expire))
|
||||
}
|
||||
|
||||
func (c *silenceExpireCmd) expire(ctx *kingpin.ParseContext) error {
|
||||
func (c *silenceExpireCmd) expire(ctx context.Context, _ *kingpin.ParseContext) error {
|
||||
if len(c.ids) < 1 {
|
||||
return errors.New("no silence IDs specified")
|
||||
}
|
||||
@ -48,7 +48,7 @@ func (c *silenceExpireCmd) expire(ctx *kingpin.ParseContext) error {
|
||||
silenceAPI := client.NewSilenceAPI(apiClient)
|
||||
|
||||
for _, id := range c.ids {
|
||||
err := silenceAPI.Expire(context.Background(), id)
|
||||
err := silenceAPI.Expire(ctx, id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -56,17 +56,17 @@ func configureSilenceImportCmd(cc *kingpin.CmdClause) {
|
||||
importCmd.Flag("force", "Force adding new silences even if it already exists").Short('f').BoolVar(&c.force)
|
||||
importCmd.Flag("worker", "Number of concurrent workers to use for import").Short('w').Default("8").IntVar(&c.workers)
|
||||
importCmd.Arg("input-file", "JSON file with silences").ExistingFileVar(&c.file)
|
||||
importCmd.Action(c.bulkImport)
|
||||
importCmd.Action(execWithTimeout(c.bulkImport))
|
||||
}
|
||||
|
||||
func addSilenceWorker(sclient client.SilenceAPI, silencec <-chan *types.Silence, errc chan<- error) {
|
||||
func addSilenceWorker(ctx context.Context, sclient client.SilenceAPI, silencec <-chan *types.Silence, errc chan<- error) {
|
||||
for s := range silencec {
|
||||
silenceID, err := sclient.Set(context.Background(), *s)
|
||||
silenceID, err := sclient.Set(ctx, *s)
|
||||
sid := s.ID
|
||||
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(context.Background(), *s)
|
||||
silenceID, err = sclient.Set(ctx, *s)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
@ -78,7 +78,7 @@ func addSilenceWorker(sclient client.SilenceAPI, silencec <-chan *types.Silence,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *silenceImportCmd) bulkImport(ctx *kingpin.ParseContext) error {
|
||||
func (c *silenceImportCmd) bulkImport(ctx context.Context, _ *kingpin.ParseContext) error {
|
||||
input := os.Stdin
|
||||
var err error
|
||||
if c.file != "" {
|
||||
@ -107,7 +107,7 @@ func (c *silenceImportCmd) bulkImport(ctx *kingpin.ParseContext) error {
|
||||
for w := 0; w < c.workers; w++ {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
addSilenceWorker(silenceAPI, silencec, errc)
|
||||
addSilenceWorker(ctx, silenceAPI, silencec, errc)
|
||||
wg.Done()
|
||||
}()
|
||||
}
|
||||
|
@ -88,10 +88,10 @@ func configureSilenceQueryCmd(cc *kingpin.CmdClause) {
|
||||
queryCmd.Flag("quiet", "Only show silence ids").Short('q').BoolVar(&c.quiet)
|
||||
queryCmd.Arg("matcher-groups", "Query filter").StringsVar(&c.matchers)
|
||||
queryCmd.Flag("within", "Show silences that will expire or have expired within a duration").DurationVar(&c.within)
|
||||
queryCmd.Action(c.query)
|
||||
queryCmd.Action(execWithTimeout(c.query))
|
||||
}
|
||||
|
||||
func (c *silenceQueryCmd) query(ctx *kingpin.ParseContext) error {
|
||||
func (c *silenceQueryCmd) query(ctx context.Context, _ *kingpin.ParseContext) error {
|
||||
var filterString = ""
|
||||
if len(c.matchers) == 1 {
|
||||
// If the parser fails then we likely don't have a (=|=~|!=|!~) so lets
|
||||
@ -112,7 +112,7 @@ func (c *silenceQueryCmd) query(ctx *kingpin.ParseContext) error {
|
||||
return err
|
||||
}
|
||||
silenceAPI := client.NewSilenceAPI(apiClient)
|
||||
fetchedSilences, err := silenceAPI.List(context.Background(), filterString)
|
||||
fetchedSilences, err := silenceAPI.List(ctx, filterString)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -49,10 +49,10 @@ func configureSilenceUpdateCmd(cc *kingpin.CmdClause) {
|
||||
updateCmd.Flag("comment", "A comment to help describe the silence").Short('c').StringVar(&c.comment)
|
||||
updateCmd.Arg("update-ids", "Silence IDs to update").StringsVar(&c.ids)
|
||||
|
||||
updateCmd.Action(c.update)
|
||||
updateCmd.Action(execWithTimeout(c.update))
|
||||
}
|
||||
|
||||
func (c *silenceUpdateCmd) update(ctx *kingpin.ParseContext) error {
|
||||
func (c *silenceUpdateCmd) update(ctx context.Context, _ *kingpin.ParseContext) error {
|
||||
if len(c.ids) < 1 {
|
||||
return fmt.Errorf("no silence IDs specified")
|
||||
}
|
||||
@ -65,7 +65,7 @@ func (c *silenceUpdateCmd) update(ctx *kingpin.ParseContext) error {
|
||||
|
||||
var updatedSilences []types.Silence
|
||||
for _, silenceID := range c.ids {
|
||||
silence, err := silenceAPI.Get(context.Background(), silenceID)
|
||||
silence, err := silenceAPI.Get(ctx, silenceID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -100,7 +100,7 @@ func (c *silenceUpdateCmd) update(ctx *kingpin.ParseContext) error {
|
||||
silence.Comment = c.comment
|
||||
}
|
||||
|
||||
newID, err := silenceAPI.Set(context.Background(), *silence)
|
||||
newID, err := silenceAPI.Set(ctx, *silence)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
12
cli/utils.go
12
cli/utils.go
@ -14,12 +14,15 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"path"
|
||||
|
||||
"github.com/prometheus/alertmanager/client"
|
||||
kingpin "gopkg.in/alecthomas/kingpin.v2"
|
||||
|
||||
"github.com/prometheus/alertmanager/pkg/parse"
|
||||
"github.com/prometheus/alertmanager/types"
|
||||
"github.com/prometheus/common/model"
|
||||
@ -114,3 +117,12 @@ func TypeMatcher(matcher labels.Matcher) (types.Matcher, error) {
|
||||
}
|
||||
return *typeMatcher, nil
|
||||
}
|
||||
|
||||
// Helper function for adding the ctx with timeout into an action.
|
||||
func execWithTimeout(fn func(context.Context, *kingpin.ParseContext) error) func(*kingpin.ParseContext) error {
|
||||
return func(x *kingpin.ParseContext) error {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||
defer cancel()
|
||||
return fn(ctx, x)
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user