Skip to content

Commit c92ed69

Browse files
simonpasquierstuartnelson3
authored andcommitted
Split cli package (prometheus#1314)
* cli: move commands to cli/cmd * cli: use StatusAPI interface for config command * cli: use SilenceAPI interface for silence commands * cli: use AlertAPI for alert command * cli: move back commands to cli package And move API client code to its own package. * cli: remove unused structs
1 parent 510e67e commit c92ed69

16 files changed

+182
-405
lines changed

cli/alert.go

Lines changed: 14 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,24 @@
11
package cli
22

33
import (
4-
"encoding/json"
4+
"context"
55
"errors"
66
"fmt"
7-
"net/http"
8-
"net/url"
97
"strings"
10-
"time"
118

129
"github.com/alecthomas/kingpin"
10+
"github.com/prometheus/client_golang/api"
11+
1312
"github.com/prometheus/alertmanager/cli/format"
14-
"github.com/prometheus/alertmanager/dispatch"
13+
"github.com/prometheus/alertmanager/client"
1514
"github.com/prometheus/alertmanager/pkg/parse"
16-
"github.com/prometheus/alertmanager/types"
17-
"github.com/prometheus/common/model"
1815
)
1916

20-
type alertmanagerAlertResponse struct {
21-
Status string `json:"status"`
22-
Data []*alertGroup `json:"data,omitempty"`
23-
ErrorType string `json:"errorType,omitempty"`
24-
Error string `json:"error,omitempty"`
25-
}
26-
27-
type alertGroup struct {
28-
Labels model.LabelSet `json:"labels"`
29-
GroupKey string `json:"groupKey"`
30-
Blocks []*alertBlock `json:"blocks"`
31-
}
32-
33-
type alertBlock struct {
34-
RouteOpts interface{} `json:"routeOpts"`
35-
Alerts []*dispatch.APIAlert `json:"alerts"`
36-
}
37-
3817
var (
3918
alertCmd = app.Command("alert", "View and search through current alerts")
4019
alertQueryCmd = alertCmd.Command("query", "View and search through current alerts").Default()
4120
expired = alertQueryCmd.Flag("expired", "Show expired alerts as well as active").Bool()
42-
showSilenced = alertQueryCmd.Flag("silenced", "Show silenced alerts").Short('s').Bool()
21+
silenced = alertQueryCmd.Flag("silenced", "Show silenced alerts").Short('s').Bool()
4322
alertQuery = alertQueryCmd.Arg("matcher-groups", "Query filter").Strings()
4423
)
4524

@@ -70,47 +49,12 @@ amtool alert query 'alertname=~foo.*'
7049
longHelpText["alert query"] = longHelpText["alert"]
7150
}
7251

73-
func fetchAlerts(filter string) ([]*dispatch.APIAlert, error) {
74-
alertResponse := alertmanagerAlertResponse{}
75-
76-
u := GetAlertmanagerURL("/api/v1/alerts/groups")
77-
u.RawQuery = "filter=" + url.QueryEscape(filter)
78-
79-
res, err := http.Get(u.String())
80-
if err != nil {
81-
return []*dispatch.APIAlert{}, err
82-
}
83-
84-
defer res.Body.Close()
85-
86-
err = json.NewDecoder(res.Body).Decode(&alertResponse)
87-
if err != nil {
88-
return []*dispatch.APIAlert{}, fmt.Errorf("unable to decode json response: %s", err)
89-
}
90-
91-
if alertResponse.Status != "success" {
92-
return []*dispatch.APIAlert{}, fmt.Errorf("[%s] %s", alertResponse.ErrorType, alertResponse.Error)
93-
}
94-
95-
return flattenAlertOverview(alertResponse.Data), nil
96-
}
97-
98-
func flattenAlertOverview(overview []*alertGroup) []*dispatch.APIAlert {
99-
alerts := []*dispatch.APIAlert{}
100-
for _, group := range overview {
101-
for _, block := range group.Blocks {
102-
alerts = append(alerts, block.Alerts...)
103-
}
104-
}
105-
return alerts
106-
}
107-
10852
func queryAlerts(element *kingpin.ParseElement, ctx *kingpin.ParseContext) error {
10953
var filterString = ""
11054
if len(*alertQuery) == 1 {
111-
// If we only have one argument then it's possible that the user wants me to assume alertname=<arg>
112-
// Attempt to use the parser to pare the argument
113-
// If the parser fails then we likely don't have a (=|=~|!=|!~) so lets prepend `alertname=` to the front
55+
// If the parser fails then we likely don't have a (=|=~|!=|!~) so lets
56+
// assume that the user wants alertname=<arg> and prepend `alertname=`
57+
// to the front.
11458
_, err := parse.Matcher((*alertQuery)[0])
11559
if err != nil {
11660
filterString = fmt.Sprintf("{alertname=%s}", (*alertQuery)[0])
@@ -121,33 +65,19 @@ func queryAlerts(element *kingpin.ParseElement, ctx *kingpin.ParseContext) error
12165
filterString = fmt.Sprintf("{%s}", strings.Join(*alertQuery, ","))
12266
}
12367

124-
fetchedAlerts, err := fetchAlerts(filterString)
68+
c, err := api.NewClient(api.Config{Address: (*alertmanagerUrl).String()})
12569
if err != nil {
12670
return err
12771
}
128-
129-
displayAlerts := []*dispatch.APIAlert{}
130-
for _, alert := range fetchedAlerts {
131-
// If we are only returning current alerts and this one has already expired skip it
132-
if !*expired {
133-
if !alert.EndsAt.IsZero() && alert.EndsAt.Before(time.Now()) {
134-
continue
135-
}
136-
}
137-
138-
if !*showSilenced {
139-
// If any silence mutes this alert don't show it
140-
if alert.Status.State == types.AlertStateSuppressed && len(alert.Status.SilencedBy) > 0 {
141-
continue
142-
}
143-
}
144-
145-
displayAlerts = append(displayAlerts, alert)
72+
alertAPI := client.NewAlertAPI(c)
73+
fetchedAlerts, err := alertAPI.List(context.Background(), filterString, *expired, *silenced)
74+
if err != nil {
75+
return err
14676
}
14777

14878
formatter, found := format.Formatters[*output]
14979
if !found {
15080
return errors.New("unknown output formatter")
15181
}
152-
return formatter.FormatAlerts(displayAlerts)
82+
return formatter.FormatAlerts(fetchedAlerts)
15383
}

cli/config.go

Lines changed: 10 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,16 @@
11
package cli
22

33
import (
4-
"encoding/json"
4+
"context"
55
"errors"
6-
"fmt"
7-
"net/http"
8-
"time"
96

107
"github.com/alecthomas/kingpin"
8+
"github.com/prometheus/client_golang/api"
9+
1110
"github.com/prometheus/alertmanager/cli/format"
12-
"github.com/prometheus/alertmanager/config"
11+
"github.com/prometheus/alertmanager/client"
1312
)
1413

15-
// Config is the response type of alertmanager config endpoint
16-
// Duped in cli/format needs to be moved to common/model
17-
type Config struct {
18-
ConfigYAML string `json:"configYAML"`
19-
ConfigJSON config.Config `json:"configJSON"`
20-
MeshStatus map[string]interface{} `json:"meshStatus"`
21-
VersionInfo map[string]string `json:"versionInfo"`
22-
Uptime time.Time `json:"uptime"`
23-
}
24-
25-
type alertmanagerStatusResponse struct {
26-
Status string `json:"status"`
27-
Data Config `json:"data,omitempty"`
28-
ErrorType string `json:"errorType,omitempty"`
29-
Error string `json:"error,omitempty"`
30-
}
31-
3214
// configCmd represents the config command
3315
var configCmd = app.Command("config", "View the running config").Action(queryConfig)
3416

@@ -40,31 +22,13 @@ The amount of output is controlled by the output selection flag:
4022
- Json: Print entire config object as json`
4123
}
4224

43-
func fetchConfig() (Config, error) {
44-
configResponse := alertmanagerStatusResponse{}
45-
46-
u := GetAlertmanagerURL("/api/v1/status")
47-
res, err := http.Get(u.String())
48-
if err != nil {
49-
return Config{}, err
50-
}
51-
52-
defer res.Body.Close()
53-
54-
err = json.NewDecoder(res.Body).Decode(&configResponse)
25+
func queryConfig(element *kingpin.ParseElement, ctx *kingpin.ParseContext) error {
26+
c, err := api.NewClient(api.Config{Address: (*alertmanagerUrl).String()})
5527
if err != nil {
56-
return configResponse.Data, err
57-
}
58-
59-
if configResponse.Status != "success" {
60-
return Config{}, fmt.Errorf("[%s] %s", configResponse.ErrorType, configResponse.Error)
28+
return err
6129
}
62-
63-
return configResponse.Data, nil
64-
}
65-
66-
func queryConfig(element *kingpin.ParseElement, ctx *kingpin.ParseContext) error {
67-
config, err := fetchConfig()
30+
statusAPI := client.NewStatusAPI(c)
31+
status, err := statusAPI.Get(context.Background())
6832
if err != nil {
6933
return err
7034
}
@@ -74,7 +38,5 @@ func queryConfig(element *kingpin.ParseElement, ctx *kingpin.ParseContext) error
7438
return errors.New("unknown output formatter")
7539
}
7640

77-
c := format.Config(config)
78-
79-
return formatter.FormatConfig(c)
41+
return formatter.FormatConfig(status)
8042
}

cli/format/format.go

Lines changed: 6 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ import (
55
"time"
66

77
"github.com/alecthomas/kingpin"
8-
"github.com/prometheus/alertmanager/config"
9-
"github.com/prometheus/alertmanager/dispatch"
8+
9+
"github.com/prometheus/alertmanager/client"
1010
"github.com/prometheus/alertmanager/types"
1111
)
1212

@@ -20,37 +20,15 @@ func InitFormatFlags(app *kingpin.Application) {
2020
dateFormat = app.Flag("date.format", "Format of date output").Default(DefaultDateFormat).String()
2121
}
2222

23-
// Config representation
24-
// Need to get this moved to the prometheus/common/model repo having is duplicated here is smelly
25-
type Config struct {
26-
ConfigYAML string `json:"configYAML"`
27-
ConfigJSON config.Config `json:"configJSON"`
28-
MeshStatus map[string]interface{} `json:"meshStatus"`
29-
VersionInfo map[string]string `json:"versionInfo"`
30-
Uptime time.Time `json:"uptime"`
31-
}
32-
33-
type MeshStatus struct {
34-
Name string `json:"name"`
35-
NickName string `json:"nickName"`
36-
Peers []PeerStatus `json:"peerStatus"`
37-
}
38-
39-
type PeerStatus struct {
40-
Name string `json:"name"`
41-
NickName string `json:"nickName"`
42-
UID uint64 `uid`
43-
}
44-
45-
// Formatter needs to be implemented for each new output formatter
23+
// Formatter needs to be implemented for each new output formatter.
4624
type Formatter interface {
4725
SetOutput(io.Writer)
4826
FormatSilences([]types.Silence) error
49-
FormatAlerts([]*dispatch.APIAlert) error
50-
FormatConfig(Config) error
27+
FormatAlerts([]*client.ExtendedAlert) error
28+
FormatConfig(*client.ServerStatus) error
5129
}
5230

53-
// Formatters is a map of cli argument name to formatter inferface object
31+
// Formatters is a map of cli argument names to formatter interface object.
5432
var Formatters = map[string]Formatter{}
5533

5634
func FormatDate(input time.Time) string {

cli/format/format_extended.go

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,8 @@ import (
88
"strings"
99
"text/tabwriter"
1010

11-
"github.com/prometheus/alertmanager/dispatch"
11+
"github.com/prometheus/alertmanager/client"
1212
"github.com/prometheus/alertmanager/types"
13-
"github.com/prometheus/common/model"
1413
)
1514

1615
type ExtendedFormatter struct {
@@ -46,7 +45,7 @@ func (formatter *ExtendedFormatter) FormatSilences(silences []types.Silence) err
4645
return nil
4746
}
4847

49-
func (formatter *ExtendedFormatter) FormatAlerts(alerts []*dispatch.APIAlert) error {
48+
func (formatter *ExtendedFormatter) FormatAlerts(alerts []*client.ExtendedAlert) error {
5049
w := tabwriter.NewWriter(formatter.writer, 0, 0, 2, ' ', 0)
5150
sort.Sort(ByStartsAt(alerts))
5251
fmt.Fprintln(w, "Labels\tAnnotations\tStarts At\tEnds At\tGenerator URL\t")
@@ -65,19 +64,19 @@ func (formatter *ExtendedFormatter) FormatAlerts(alerts []*dispatch.APIAlert) er
6564
return nil
6665
}
6766

68-
func (formatter *ExtendedFormatter) FormatConfig(config Config) error {
69-
fmt.Fprintln(formatter.writer, config.ConfigYAML)
70-
fmt.Fprintln(formatter.writer, "buildUser", config.VersionInfo["buildUser"])
71-
fmt.Fprintln(formatter.writer, "goVersion", config.VersionInfo["goVersion"])
72-
fmt.Fprintln(formatter.writer, "revision", config.VersionInfo["revision"])
73-
fmt.Fprintln(formatter.writer, "version", config.VersionInfo["version"])
74-
fmt.Fprintln(formatter.writer, "branch", config.VersionInfo["branch"])
75-
fmt.Fprintln(formatter.writer, "buildDate", config.VersionInfo["buildDate"])
76-
fmt.Fprintln(formatter.writer, "uptime", config.Uptime)
67+
func (formatter *ExtendedFormatter) FormatConfig(status *client.ServerStatus) error {
68+
fmt.Fprintln(formatter.writer, status.ConfigYAML)
69+
fmt.Fprintln(formatter.writer, "buildUser", status.VersionInfo["buildUser"])
70+
fmt.Fprintln(formatter.writer, "goVersion", status.VersionInfo["goVersion"])
71+
fmt.Fprintln(formatter.writer, "revision", status.VersionInfo["revision"])
72+
fmt.Fprintln(formatter.writer, "version", status.VersionInfo["version"])
73+
fmt.Fprintln(formatter.writer, "branch", status.VersionInfo["branch"])
74+
fmt.Fprintln(formatter.writer, "buildDate", status.VersionInfo["buildDate"])
75+
fmt.Fprintln(formatter.writer, "uptime", status.Uptime)
7776
return nil
7877
}
7978

80-
func extendedFormatLabels(labels model.LabelSet) string {
79+
func extendedFormatLabels(labels client.LabelSet) string {
8180
output := []string{}
8281
for name, value := range labels {
8382
output = append(output, fmt.Sprintf("%s=\"%s\"", name, value))
@@ -86,7 +85,7 @@ func extendedFormatLabels(labels model.LabelSet) string {
8685
return strings.Join(output, " ")
8786
}
8887

89-
func extendedFormatAnnotations(labels model.LabelSet) string {
88+
func extendedFormatAnnotations(labels client.LabelSet) string {
9089
output := []string{}
9190
for name, value := range labels {
9291
output = append(output, fmt.Sprintf("%s=\"%s\"", name, value))

cli/format/format_json.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import (
55
"io"
66
"os"
77

8-
"github.com/prometheus/alertmanager/dispatch"
8+
"github.com/prometheus/alertmanager/client"
99
"github.com/prometheus/alertmanager/types"
1010
)
1111

@@ -26,12 +26,12 @@ func (formatter *JSONFormatter) FormatSilences(silences []types.Silence) error {
2626
return enc.Encode(silences)
2727
}
2828

29-
func (formatter *JSONFormatter) FormatAlerts(alerts []*dispatch.APIAlert) error {
29+
func (formatter *JSONFormatter) FormatAlerts(alerts []*client.ExtendedAlert) error {
3030
enc := json.NewEncoder(formatter.writer)
3131
return enc.Encode(alerts)
3232
}
3333

34-
func (formatter *JSONFormatter) FormatConfig(config Config) error {
34+
func (formatter *JSONFormatter) FormatConfig(status *client.ServerStatus) error {
3535
enc := json.NewEncoder(formatter.writer)
36-
return enc.Encode(config)
36+
return enc.Encode(status)
3737
}

cli/format/format_simple.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import (
88
"strings"
99
"text/tabwriter"
1010

11-
"github.com/prometheus/alertmanager/dispatch"
11+
"github.com/prometheus/alertmanager/client"
1212
"github.com/prometheus/alertmanager/types"
1313
)
1414

@@ -43,7 +43,7 @@ func (formatter *SimpleFormatter) FormatSilences(silences []types.Silence) error
4343
return nil
4444
}
4545

46-
func (formatter *SimpleFormatter) FormatAlerts(alerts []*dispatch.APIAlert) error {
46+
func (formatter *SimpleFormatter) FormatAlerts(alerts []*client.ExtendedAlert) error {
4747
w := tabwriter.NewWriter(formatter.writer, 0, 0, 2, ' ', 0)
4848
sort.Sort(ByStartsAt(alerts))
4949
fmt.Fprintln(w, "Alertname\tStarts At\tSummary\t")
@@ -60,8 +60,8 @@ func (formatter *SimpleFormatter) FormatAlerts(alerts []*dispatch.APIAlert) erro
6060
return nil
6161
}
6262

63-
func (formatter *SimpleFormatter) FormatConfig(config Config) error {
64-
fmt.Fprintln(formatter.writer, config.ConfigYAML)
63+
func (formatter *SimpleFormatter) FormatConfig(status *client.ServerStatus) error {
64+
fmt.Fprintln(formatter.writer, status.ConfigYAML)
6565
return nil
6666
}
6767

0 commit comments

Comments
 (0)