From 389c6d00434b95271c78abedbd542e27f578563f Mon Sep 17 00:00:00 2001 From: Frederic Branczyk Date: Fri, 13 Jan 2017 10:20:11 +0100 Subject: [PATCH 1/2] web/api: add alertmanager api --- web/api/v1/api.go | 40 +++++++++++++++++++++++++++++++++------- web/api/v1/api_test.go | 28 ++++++++++++++++++++++++---- web/web.go | 2 +- 3 files changed, 58 insertions(+), 12 deletions(-) diff --git a/web/api/v1/api.go b/web/api/v1/api.go index 152091aab..907aae549 100644 --- a/web/api/v1/api.go +++ b/web/api/v1/api.go @@ -71,6 +71,10 @@ type targetRetriever interface { Targets() []*retrieval.Target } +type alertmanagerRetriever interface { + Alertmanagers() []string +} + type response struct { Status status `json:"status"` Data interface{} `json:"data,omitempty"` @@ -93,20 +97,22 @@ type API struct { Storage local.Storage QueryEngine *promql.Engine - targetRetriever targetRetriever + targetRetriever targetRetriever + alertmanagerRetriever alertmanagerRetriever context func(r *http.Request) context.Context now func() model.Time } // NewAPI returns an initialized API type. -func NewAPI(qe *promql.Engine, st local.Storage, tr targetRetriever) *API { +func NewAPI(qe *promql.Engine, st local.Storage, tr targetRetriever, ar alertmanagerRetriever) *API { return &API{ - QueryEngine: qe, - Storage: st, - targetRetriever: tr, - context: route.Context, - now: model.Now, + QueryEngine: qe, + Storage: st, + targetRetriever: tr, + alertmanagerRetriever: ar, + context: route.Context, + now: model.Now, } } @@ -139,6 +145,7 @@ func (api *API) Register(r *route.Router) { r.Del("/series", instr("drop_series", api.dropSeries)) r.Get("/targets", instr("targets", api.targets)) + r.Get("/alertmanagers", instr("alertmanagers", api.alertmanagers)) } type queryData struct { @@ -375,6 +382,25 @@ func (api *API) targets(r *http.Request) (interface{}, *apiError) { return res, nil } +type AlertmanagerDiscovery struct { + ActiveAlertmanagers []*AlertmanagerTarget `json:"activeAlertmanagers"` +} + +type AlertmanagerTarget struct { + URL string `json:"url"` +} + +func (api *API) alertmanagers(r *http.Request) (interface{}, *apiError) { + urls := api.alertmanagerRetriever.Alertmanagers() + ams := &AlertmanagerDiscovery{ActiveAlertmanagers: make([]*AlertmanagerTarget, len(urls))} + + for i := range urls { + ams.ActiveAlertmanagers[i] = &AlertmanagerTarget{URL: urls[i]} + } + + return ams, nil +} + func respond(w http.ResponseWriter, data interface{}) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) diff --git a/web/api/v1/api_test.go b/web/api/v1/api_test.go index 27343edb6..f7d46895b 100644 --- a/web/api/v1/api_test.go +++ b/web/api/v1/api_test.go @@ -39,6 +39,12 @@ func (f targetRetrieverFunc) Targets() []*retrieval.Target { return f() } +type alertmanagerRetrieverFunc func() []string + +func (f alertmanagerRetrieverFunc) Alertmanagers() []string { + return f() +} + func TestEndpoints(t *testing.T) { suite, err := promql.NewTest(t, ` load 1m @@ -71,11 +77,16 @@ func TestEndpoints(t *testing.T) { } }) + ar := alertmanagerRetrieverFunc(func() []string { + return []string{"http://alertmanager.example.com:8080/api/v1/alerts"} + }) + api := &API{ - Storage: suite.Storage(), - QueryEngine: suite.QueryEngine(), - targetRetriever: tr, - now: func() model.Time { return now }, + Storage: suite.Storage(), + QueryEngine: suite.QueryEngine(), + targetRetriever: tr, + alertmanagerRetriever: ar, + now: func() model.Time { return now }, } start := model.Time(0) @@ -437,6 +448,15 @@ func TestEndpoints(t *testing.T) { Health: "unknown", }, }, + }, { + endpoint: api.alertmanagers, + response: &AlertmanagerDiscovery{ + ActiveAlertmanagers: []*AlertmanagerTarget{ + &AlertmanagerTarget{ + URL: "http://alertmanager.example.com:8080/api/v1/alerts", + }, + }, + }, }, } diff --git a/web/web.go b/web/web.go index 2469c27c7..a7495ab7e 100644 --- a/web/web.go +++ b/web/web.go @@ -155,7 +155,7 @@ func New(o *Options) *Handler { storage: o.Storage, notifier: o.Notifier, - apiV1: api_v1.NewAPI(o.QueryEngine, o.Storage, o.TargetManager), + apiV1: api_v1.NewAPI(o.QueryEngine, o.Storage, o.TargetManager, o.Notifier), now: model.Now, } From bd92571bdd881b171c1ea2a2c0ff9c842bb997f7 Mon Sep 17 00:00:00 2001 From: Frederic Branczyk Date: Fri, 13 Jan 2017 17:15:04 +0100 Subject: [PATCH 2/2] web/api: make target and alertmanager api responses consistent --- web/api/v1/api.go | 12 ++++++++---- web/api/v1/api_test.go | 14 ++++++++------ 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/web/api/v1/api.go b/web/api/v1/api.go index 907aae549..9a2e2361b 100644 --- a/web/api/v1/api.go +++ b/web/api/v1/api.go @@ -351,16 +351,20 @@ type Target struct { // Any labels that are added to this target and its metrics. Labels model.LabelSet `json:"labels"` - ScrapeUrl string `json:"scrapeUrl"` + ScrapeURL string `json:"scrapeUrl"` LastError string `json:"lastError"` LastScrape time.Time `json:"lastScrape"` Health retrieval.TargetHealth `json:"health"` } +type TargetDiscovery struct { + ActiveTargets []*Target `json:"activeTargets"` +} + func (api *API) targets(r *http.Request) (interface{}, *apiError) { targets := api.targetRetriever.Targets() - res := make([]*Target, len(targets)) + res := &TargetDiscovery{ActiveTargets: make([]*Target, len(targets))} for i, t := range targets { lastErrStr := "" @@ -369,10 +373,10 @@ func (api *API) targets(r *http.Request) (interface{}, *apiError) { lastErrStr = lastErr.Error() } - res[i] = &Target{ + res.ActiveTargets[i] = &Target{ DiscoveredLabels: t.DiscoveredLabels(), Labels: t.Labels(), - ScrapeUrl: t.URL().String(), + ScrapeURL: t.URL().String(), LastError: lastErrStr, LastScrape: t.LastScrape(), Health: t.Health(), diff --git a/web/api/v1/api_test.go b/web/api/v1/api_test.go index f7d46895b..07f371069 100644 --- a/web/api/v1/api_test.go +++ b/web/api/v1/api_test.go @@ -440,12 +440,14 @@ func TestEndpoints(t *testing.T) { }{2}, }, { endpoint: api.targets, - response: []*Target{ - &Target{ - DiscoveredLabels: model.LabelSet{}, - Labels: model.LabelSet{}, - ScrapeUrl: "http://example.com:8080/metrics", - Health: "unknown", + response: &TargetDiscovery{ + ActiveTargets: []*Target{ + &Target{ + DiscoveredLabels: model.LabelSet{}, + Labels: model.LabelSet{}, + ScrapeURL: "http://example.com:8080/metrics", + Health: "unknown", + }, }, }, }, {