From 5393573c7369bd8aa3c5a42721c247e2ff6073e4 Mon Sep 17 00:00:00 2001 From: Bob Shannon Date: Tue, 10 Apr 2018 07:21:25 -0700 Subject: [PATCH 1/5] Implement AlertManager, Status, and Target methods Signed-off-by: Bob Shannon --- api/prometheus/v1/api.go | 282 ++++++++++++++++++++++++++++------ api/prometheus/v1/api_test.go | 221 ++++++++++++++++++++++++-- 2 files changed, 440 insertions(+), 63 deletions(-) diff --git a/api/prometheus/v1/api.go b/api/prometheus/v1/api.go index a9b9ce4..3fc58d8 100644 --- a/api/prometheus/v1/api.go +++ b/api/prometheus/v1/api.go @@ -20,13 +20,16 @@ package v1 import ( "context" "encoding/json" + "errors" "fmt" "net/http" + "net/url" "strconv" "time" "github.com/prometheus/client_golang/api" "github.com/prometheus/common/model" + "github.com/prometheus/prometheus/scrape" ) const ( @@ -34,13 +37,17 @@ const ( apiPrefix = "/api/v1" + epAlertManagers = apiPrefix + "/alertmanagers" epQuery = apiPrefix + "/query" epQueryRange = apiPrefix + "/query_range" epLabelValues = apiPrefix + "/label/:name/values" epSeries = apiPrefix + "/series" + epTargets = apiPrefix + "/targets" epSnapshot = apiPrefix + "/admin/tsdb/snapshot" epDeleteSeries = apiPrefix + "/admin/tsdb/delete_series" epCleanTombstones = apiPrefix + "/admin/tsdb/clean_tombstones" + epConfig = apiPrefix + "/status/config" + epFlags = apiPrefix + "/status/flags" ) // ErrorType models the different API error types. @@ -75,21 +82,79 @@ type Range struct { // API provides bindings for Prometheus's v1 API. type API interface { + // AlertManagers returns an overview of the current state of the Prometheus alert manager discovery. + AlertManagers(ctx context.Context) (AlertManagersResult, error) + // CleanTombstones removes the deleted data from disk and cleans up the existing tombstones. + CleanTombstones(ctx context.Context) error + // Config returns the current Prometheus configuration. + Config(ctx context.Context) (ConfigResult, error) + // DeleteSeries deletes data for a selection of series in a time range. + DeleteSeries(ctx context.Context, matches []string, startTime time.Time, endTime time.Time) error + // Flags returns the flag values that Prometheus was launched with. + Flags(ctx context.Context) (FlagsResult, error) + // LabelValues performs a query for the values of the given label. + LabelValues(ctx context.Context, label string) (model.LabelValues, error) // Query performs a query for the given time. Query(ctx context.Context, query string, ts time.Time) (model.Value, error) // QueryRange performs a query for the given range. QueryRange(ctx context.Context, query string, r Range) (model.Value, error) - // LabelValues performs a query for the values of the given label. - LabelValues(ctx context.Context, label string) (model.LabelValues, error) // Series finds series by label matchers. Series(ctx context.Context, matches []string, startTime time.Time, endTime time.Time) ([]model.LabelSet, error) // Snapshot creates a snapshot of all current data into snapshots/- // under the TSDB's data directory and returns the directory as response. Snapshot(ctx context.Context, skipHead bool) (SnapshotResult, error) - // DeleteSeries deletes data for a selection of series in a time range. - DeleteSeries(ctx context.Context, matches []string, startTime time.Time, endTime time.Time) error - // CleanTombstones removes the deleted data from disk and cleans up the existing tombstones. - CleanTombstones(ctx context.Context) error + // Targets returns an overview of the current state of the Prometheus target discovery. + Targets(ctx context.Context) (TargetsResult, error) +} + +// AlertManagersResult contains the result from querying the alertmanagers endpoint. +type AlertManagersResult struct { + Active []AlertManager `json:"activeAlertManagers"` + Dropped []AlertManager `json:"droppedAlertManagers"` +} + +// AlertManager models a configured Alert Manager. +type AlertManager struct { + URL *url.URL `json:"url"` +} + +// ConfigResult contains the result from querying the config endpoint. +type ConfigResult struct { + YAML string `json:"yaml"` +} + +// FlagsResult contains the result from querying the flag endpoint. +type FlagsResult struct { + Flags Flags +} + +// Flags models a set of flags that Prometheus is configured with. +type Flags map[string]string + +// SnapshotResult contains the result from querying the snapshot endpoint. +type SnapshotResult struct { + Name string `json:"name"` +} + +// TargetsResult contains the result from querying the targets endpoint. +type TargetsResult struct { + Active []ActiveTarget `json:"activeTargets"` + Dropped []DroppedTarget `json:"droppedTargets"` +} + +// ActiveTarget models an active Prometheus scrape target. +type ActiveTarget struct { + DiscoveredLabels model.LabelSet `json:"discoveredLabels"` + Labels model.LabelSet `json:"labels"` + ScrapeURL *url.URL `json:"scrapeUrl"` + LastError error `json:"lastError"` + LastScrape time.Time `json:"lastScrape"` + Health scrape.TargetHealth `json:"health"` +} + +// DroppedTarget models a dropped Prometheus scrape target. +type DroppedTarget struct { + DiscoveredLabels model.LabelSet `json:"discoveredLabels"` } // queryResult contains result data for a query. @@ -101,9 +166,56 @@ type queryResult struct { v model.Value } -// SnapshotResult contains result data for a snapshot. -type SnapshotResult struct { - Name string +func (a *ActiveTarget) UnmarshalJSON(b []byte) error { + v := struct { + DiscoveredLabels model.LabelSet `json:"discoveredLabels"` + Labels model.LabelSet `json:"labels"` + ScrapeURL string `json:"scrapeUrl"` + LastError string `json:"lastError"` + LastScrape time.Time `json:"lastScrape"` + Health scrape.TargetHealth `json:"health"` + }{} + + err := json.Unmarshal(b, &v) + if err != nil { + return err + } + + url, err := url.Parse(v.ScrapeURL) + + a.DiscoveredLabels = v.DiscoveredLabels + a.Labels = v.Labels + a.ScrapeURL = url + a.LastScrape = v.LastScrape + a.Health = v.Health + if v.LastError != "" { + a.LastError = errors.New(v.LastError) + } else { + a.LastError = nil + } + + return err +} + +func (a *AlertManager) UnmarshalJSON(b []byte) error { + var v map[string]string + + err := json.Unmarshal(b, &v) + if err != nil { + return err + } + + url, err := url.Parse(v["url"]) + a.URL = url + return err +} + +func (f *FlagsResult) UnmarshalJSON(b []byte) error { + var v map[string]string + + err := json.Unmarshal(b, &v) + f.Flags = v + return err } func (qr *queryResult) UnmarshalJSON(b []byte) error { @@ -150,6 +262,109 @@ type httpAPI struct { client api.Client } +func (h *httpAPI) AlertManagers(ctx context.Context) (AlertManagersResult, error) { + u := h.client.URL(epAlertManagers, nil) + + req, err := http.NewRequest(http.MethodGet, u.String(), nil) + if err != nil { + return AlertManagersResult{}, err + } + + _, body, err := h.client.Do(ctx, req) + if err != nil { + return AlertManagersResult{}, err + } + + var res AlertManagersResult + err = json.Unmarshal(body, &res) + return res, err +} + +func (h *httpAPI) CleanTombstones(ctx context.Context) error { + u := h.client.URL(epCleanTombstones, nil) + + req, err := http.NewRequest(http.MethodPost, u.String(), nil) + if err != nil { + return err + } + + _, _, err = h.client.Do(ctx, req) + return err +} + +func (h *httpAPI) Config(ctx context.Context) (ConfigResult, error) { + u := h.client.URL(epConfig, nil) + + req, err := http.NewRequest(http.MethodGet, u.String(), nil) + if err != nil { + return ConfigResult{}, err + } + + _, body, err := h.client.Do(ctx, req) + if err != nil { + return ConfigResult{}, err + } + + var res ConfigResult + err = json.Unmarshal(body, &res) + return res, err +} + +func (h *httpAPI) DeleteSeries(ctx context.Context, matches []string, startTime time.Time, endTime time.Time) error { + u := h.client.URL(epDeleteSeries, nil) + q := u.Query() + + for _, m := range matches { + q.Add("match[]", m) + } + + q.Set("start", startTime.Format(time.RFC3339Nano)) + q.Set("end", endTime.Format(time.RFC3339Nano)) + + u.RawQuery = q.Encode() + + req, err := http.NewRequest(http.MethodPost, u.String(), nil) + if err != nil { + return err + } + + _, _, err = h.client.Do(ctx, req) + return err +} + +func (h *httpAPI) Flags(ctx context.Context) (FlagsResult, error) { + u := h.client.URL(epFlags, nil) + + req, err := http.NewRequest(http.MethodGet, u.String(), nil) + if err != nil { + return FlagsResult{}, err + } + + _, body, err := h.client.Do(ctx, req) + if err != nil { + return FlagsResult{}, err + } + + var res FlagsResult + err = json.Unmarshal(body, &res) + return res, err +} + +func (h *httpAPI) LabelValues(ctx context.Context, label string) (model.LabelValues, error) { + u := h.client.URL(epLabelValues, map[string]string{"name": label}) + req, err := http.NewRequest(http.MethodGet, u.String(), nil) + if err != nil { + return nil, err + } + _, body, err := h.client.Do(ctx, req) + if err != nil { + return nil, err + } + var labelValues model.LabelValues + err = json.Unmarshal(body, &labelValues) + return labelValues, err +} + func (h *httpAPI) Query(ctx context.Context, query string, ts time.Time) (model.Value, error) { u := h.client.URL(epQuery, nil) q := u.Query() @@ -210,21 +425,6 @@ func (h *httpAPI) QueryRange(ctx context.Context, query string, r Range) (model. return model.Value(qres.v), err } -func (h *httpAPI) LabelValues(ctx context.Context, label string) (model.LabelValues, error) { - u := h.client.URL(epLabelValues, map[string]string{"name": label}) - req, err := http.NewRequest(http.MethodGet, u.String(), nil) - if err != nil { - return nil, err - } - _, body, err := h.client.Do(ctx, req) - if err != nil { - return nil, err - } - var labelValues model.LabelValues - err = json.Unmarshal(body, &labelValues) - return labelValues, err -} - func (h *httpAPI) Series(ctx context.Context, matches []string, startTime time.Time, endTime time.Time) ([]model.LabelSet, error) { u := h.client.URL(epSeries, nil) q := u.Query() @@ -276,38 +476,22 @@ func (h *httpAPI) Snapshot(ctx context.Context, skipHead bool) (SnapshotResult, return res, err } -func (h *httpAPI) DeleteSeries(ctx context.Context, matches []string, startTime time.Time, endTime time.Time) error { - u := h.client.URL(epDeleteSeries, nil) - q := u.Query() +func (h *httpAPI) Targets(ctx context.Context) (TargetsResult, error) { + u := h.client.URL(epTargets, nil) - for _, m := range matches { - q.Add("match[]", m) - } - - q.Set("start", startTime.Format(time.RFC3339Nano)) - q.Set("end", endTime.Format(time.RFC3339Nano)) - - u.RawQuery = q.Encode() - - req, err := http.NewRequest(http.MethodPost, u.String(), nil) + req, err := http.NewRequest(http.MethodGet, u.String(), nil) if err != nil { - return err + return TargetsResult{}, err } - _, _, err = h.client.Do(ctx, req) - return err -} - -func (h *httpAPI) CleanTombstones(ctx context.Context) error { - u := h.client.URL(epCleanTombstones, nil) - - req, err := http.NewRequest(http.MethodPost, u.String(), nil) + _, body, err := h.client.Do(ctx, req) if err != nil { - return err + return TargetsResult{}, err } - _, _, err = h.client.Do(ctx, req) - return err + var res TargetsResult + err = json.Unmarshal(body, &res) + return res, err } // apiClient wraps a regular client and processes successful API responses. diff --git a/api/prometheus/v1/api_test.go b/api/prometheus/v1/api_test.go index 5c1402b..7a42e17 100644 --- a/api/prometheus/v1/api_test.go +++ b/api/prometheus/v1/api_test.go @@ -18,6 +18,7 @@ package v1 import ( "context" "encoding/json" + "errors" "fmt" "net/http" "net/url" @@ -27,6 +28,7 @@ import ( "time" "github.com/prometheus/common/model" + "github.com/prometheus/prometheus/scrape" ) type apiTest struct { @@ -88,12 +90,53 @@ func TestAPIs(t *testing.T) { testTime := time.Now() + testURL, err := url.Parse("http://127.0.0.1:9090/api/v1/alerts") + if err != nil { + t.Errorf("Failed to initialize test URL.") + } + client := &apiTestClient{T: t} promAPI := &httpAPI{ client: client, } + doAlertManagers := func() func() (interface{}, error) { + return func() (interface{}, error) { + return promAPI.AlertManagers(context.Background()) + } + } + + doCleanTombstones := func() func() (interface{}, error) { + return func() (interface{}, error) { + return nil, promAPI.CleanTombstones(context.Background()) + } + } + + doConfig := func() func() (interface{}, error) { + return func() (interface{}, error) { + return promAPI.Config(context.Background()) + } + } + + doDeleteSeries := func(matcher string, startTime time.Time, endTime time.Time) func() (interface{}, error) { + return func() (interface{}, error) { + return nil, promAPI.DeleteSeries(context.Background(), []string{matcher}, startTime, endTime) + } + } + + doFlags := func() func() (interface{}, error) { + return func() (interface{}, error) { + return promAPI.Flags(context.Background()) + } + } + + doLabelValues := func(label string) func() (interface{}, error) { + return func() (interface{}, error) { + return promAPI.LabelValues(context.Background(), label) + } + } + doQuery := func(q string, ts time.Time) func() (interface{}, error) { return func() (interface{}, error) { return promAPI.Query(context.Background(), q, ts) @@ -106,12 +149,6 @@ func TestAPIs(t *testing.T) { } } - doLabelValues := func(label string) func() (interface{}, error) { - return func() (interface{}, error) { - return promAPI.LabelValues(context.Background(), label) - } - } - doSeries := func(matcher string, startTime time.Time, endTime time.Time) func() (interface{}, error) { return func() (interface{}, error) { return promAPI.Series(context.Background(), []string{matcher}, startTime, endTime) @@ -124,15 +161,9 @@ func TestAPIs(t *testing.T) { } } - doCleanTombstones := func() func() (interface{}, error) { + doTargets := func() func() (interface{}, error) { return func() (interface{}, error) { - return nil, promAPI.CleanTombstones(context.Background()) - } - } - - doDeleteSeries := func(matcher string, startTime time.Time, endTime time.Time) func() (interface{}, error) { - return func() (interface{}, error) { - return nil, promAPI.DeleteSeries(context.Background(), []string{matcher}, startTime, endTime) + return promAPI.Targets(context.Background()) } } @@ -309,6 +340,168 @@ func TestAPIs(t *testing.T) { }, err: fmt.Errorf("some error"), }, + + { + do: doConfig(), + reqMethod: "GET", + reqPath: "/api/v1/status/config", + inRes: map[string]string{ + "yaml": "", + }, + res: ConfigResult{ + YAML: "", + }, + }, + + { + do: doConfig(), + reqMethod: "GET", + reqPath: "/api/v1/status/config", + inErr: fmt.Errorf("some error"), + err: fmt.Errorf("some error"), + }, + + { + do: doFlags(), + reqMethod: "GET", + reqPath: "/api/v1/status/flags", + inRes: map[string]string{ + "alertmanager.notification-queue-capacity": "10000", + "alertmanager.timeout": "10s", + "log.level": "info", + "query.lookback-delta": "5m", + "query.max-concurrency": "20", + }, + res: FlagsResult{ + Flags{ + "alertmanager.notification-queue-capacity": "10000", + "alertmanager.timeout": "10s", + "log.level": "info", + "query.lookback-delta": "5m", + "query.max-concurrency": "20", + }, + }, + }, + + { + do: doFlags(), + reqMethod: "GET", + reqPath: "/api/v1/status/flags", + inErr: fmt.Errorf("some error"), + err: fmt.Errorf("some error"), + }, + + { + do: doAlertManagers(), + reqMethod: "GET", + reqPath: "/api/v1/alertmanagers", + inRes: map[string]interface{}{ + "activeAlertManagers": []map[string]string{ + { + "url": testURL.String(), + }, + }, + "droppedAlertManagers": []map[string]string{ + { + "url": testURL.String(), + }, + }, + }, + res: AlertManagersResult{ + Active: []AlertManager{ + { + URL: testURL, + }, + }, + Dropped: []AlertManager{ + { + URL: testURL, + }, + }, + }, + }, + + { + do: doAlertManagers(), + reqMethod: "GET", + reqPath: "/api/v1/alertmanagers", + inErr: fmt.Errorf("some error"), + err: fmt.Errorf("some error"), + }, + + { + do: doTargets(), + reqMethod: "GET", + reqPath: "/api/v1/targets", + inRes: map[string]interface{}{ + "activeTargets": []map[string]interface{}{ + { + "discoveredLabels": map[string]string{ + "__address__": "127.0.0.1:9090", + "__metrics_path__": "/metrics", + "__scheme__": "http", + "job": "prometheus", + }, + "labels": map[string]string{ + "instance": "127.0.0.1:9090", + "job": "prometheus", + }, + "scrapeUrl": testURL.String(), + "lastError": "error while scraping target", + "lastScrape": testTime.Format(time.RFC3339Nano), + "health": "up", + }, + }, + "droppedTargets": []map[string]interface{}{ + { + "discoveredLabels": map[string]string{ + "__address__": "127.0.0.1:9100", + "__metrics_path__": "/metrics", + "__scheme__": "http", + "job": "node", + }, + }, + }, + }, + res: TargetsResult{ + Active: []ActiveTarget{ + { + DiscoveredLabels: model.LabelSet{ + "__address__": "127.0.0.1:9090", + "__metrics_path__": "/metrics", + "__scheme__": "http", + "job": "prometheus", + }, + Labels: model.LabelSet{ + "instance": "127.0.0.1:9090", + "job": "prometheus", + }, + ScrapeURL: testURL, + LastError: errors.New("error while scraping target"), + LastScrape: testTime.Round(0), + Health: scrape.HealthGood, + }, + }, + Dropped: []DroppedTarget{ + { + DiscoveredLabels: model.LabelSet{ + "__address__": "127.0.0.1:9100", + "__metrics_path__": "/metrics", + "__scheme__": "http", + "job": "node", + }, + }, + }, + }, + }, + + { + do: doTargets(), + reqMethod: "GET", + reqPath: "/api/v1/targets", + inErr: fmt.Errorf("some error"), + err: fmt.Errorf("some error"), + }, } var tests []apiTest From e035b26e30d2c25a51347130ac8e9770894052a8 Mon Sep 17 00:00:00 2001 From: Bob Shannon Date: Tue, 10 Apr 2018 18:37:17 -0700 Subject: [PATCH 2/5] Bump go version used in build Signed-off-by: Bob Shannon --- .travis.yml | 5 ++--- api/prometheus/v1/api.go | 9 ++------- api/prometheus/v1/api_test.go | 3 +-- 3 files changed, 5 insertions(+), 12 deletions(-) diff --git a/.travis.yml b/.travis.yml index e9bca4e..1d18e98 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,9 +2,8 @@ sudo: false language: go go: - - 1.7.x - - 1.8.x - - 1.9.x + - 1.10.x + - 1.x script: - go test -short ./... diff --git a/api/prometheus/v1/api.go b/api/prometheus/v1/api.go index 3fc58d8..5261dc6 100644 --- a/api/prometheus/v1/api.go +++ b/api/prometheus/v1/api.go @@ -20,7 +20,6 @@ package v1 import ( "context" "encoding/json" - "errors" "fmt" "net/http" "net/url" @@ -147,7 +146,7 @@ type ActiveTarget struct { DiscoveredLabels model.LabelSet `json:"discoveredLabels"` Labels model.LabelSet `json:"labels"` ScrapeURL *url.URL `json:"scrapeUrl"` - LastError error `json:"lastError"` + LastError string `json:"lastError"` LastScrape time.Time `json:"lastScrape"` Health scrape.TargetHealth `json:"health"` } @@ -188,11 +187,7 @@ func (a *ActiveTarget) UnmarshalJSON(b []byte) error { a.ScrapeURL = url a.LastScrape = v.LastScrape a.Health = v.Health - if v.LastError != "" { - a.LastError = errors.New(v.LastError) - } else { - a.LastError = nil - } + a.LastError = v.LastError return err } diff --git a/api/prometheus/v1/api_test.go b/api/prometheus/v1/api_test.go index 7a42e17..29a2910 100644 --- a/api/prometheus/v1/api_test.go +++ b/api/prometheus/v1/api_test.go @@ -18,7 +18,6 @@ package v1 import ( "context" "encoding/json" - "errors" "fmt" "net/http" "net/url" @@ -477,7 +476,7 @@ func TestAPIs(t *testing.T) { "job": "prometheus", }, ScrapeURL: testURL, - LastError: errors.New("error while scraping target"), + LastError: "error while scraping target", LastScrape: testTime.Round(0), Health: scrape.HealthGood, }, From fc258df5b504b90400565cf56cb59e022cba077f Mon Sep 17 00:00:00 2001 From: Bob Shannon Date: Tue, 10 Apr 2018 19:16:08 -0700 Subject: [PATCH 3/5] Fix deep equal comparison for time.Time Signed-off-by: Bob Shannon --- api/prometheus/v1/api_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/api/prometheus/v1/api_test.go b/api/prometheus/v1/api_test.go index 29a2910..5e66076 100644 --- a/api/prometheus/v1/api_test.go +++ b/api/prometheus/v1/api_test.go @@ -447,7 +447,7 @@ func TestAPIs(t *testing.T) { }, "scrapeUrl": testURL.String(), "lastError": "error while scraping target", - "lastScrape": testTime.Format(time.RFC3339Nano), + "lastScrape": testTime.UTC().Format(time.RFC3339Nano), "health": "up", }, }, @@ -477,7 +477,7 @@ func TestAPIs(t *testing.T) { }, ScrapeURL: testURL, LastError: "error while scraping target", - LastScrape: testTime.Round(0), + LastScrape: testTime.UTC(), Health: scrape.HealthGood, }, }, From e3e66d0bb9be9559b06e6c30ce90bedd6ca3d6c6 Mon Sep 17 00:00:00 2001 From: Bob Shannon Date: Wed, 11 Apr 2018 07:38:10 -0700 Subject: [PATCH 4/5] PR comments Signed-off-by: Bob Shannon --- .travis.yml | 5 ++- api/prometheus/v1/api.go | 78 ++++++++--------------------------- api/prometheus/v1/api_test.go | 32 ++++++-------- 3 files changed, 32 insertions(+), 83 deletions(-) diff --git a/.travis.yml b/.travis.yml index 1d18e98..3ff54ea 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,8 +2,9 @@ sudo: false language: go go: - - 1.10.x - - 1.x +- 1.7.x +- 1.8.x +- 1.9.x script: - go test -short ./... diff --git a/api/prometheus/v1/api.go b/api/prometheus/v1/api.go index 5261dc6..3d37437 100644 --- a/api/prometheus/v1/api.go +++ b/api/prometheus/v1/api.go @@ -22,13 +22,11 @@ import ( "encoding/json" "fmt" "net/http" - "net/url" "strconv" "time" "github.com/prometheus/client_golang/api" "github.com/prometheus/common/model" - "github.com/prometheus/prometheus/scrape" ) const ( @@ -52,13 +50,21 @@ const ( // ErrorType models the different API error types. type ErrorType string -// Possible values for ErrorType. +// HealthStatus models the health status of a scrape target. +type HealthStatus string + const ( + // Possible values for ErrorType. ErrBadData ErrorType = "bad_data" ErrTimeout = "timeout" ErrCanceled = "canceled" ErrExec = "execution" ErrBadResponse = "bad_response" + + // Possible values for HealthStatus. + HealthGood HealthStatus = "up" + HealthUnknown HealthStatus = "unknown" + HealthBad HealthStatus = "down" ) // Error is an error returned by the API. @@ -114,7 +120,7 @@ type AlertManagersResult struct { // AlertManager models a configured Alert Manager. type AlertManager struct { - URL *url.URL `json:"url"` + URL string `json:"url"` } // ConfigResult contains the result from querying the config endpoint. @@ -123,9 +129,7 @@ type ConfigResult struct { } // FlagsResult contains the result from querying the flag endpoint. -type FlagsResult struct { - Flags Flags -} +type FlagsResult map[string]string // Flags models a set of flags that Prometheus is configured with. type Flags map[string]string @@ -143,12 +147,12 @@ type TargetsResult struct { // ActiveTarget models an active Prometheus scrape target. type ActiveTarget struct { - DiscoveredLabels model.LabelSet `json:"discoveredLabels"` - Labels model.LabelSet `json:"labels"` - ScrapeURL *url.URL `json:"scrapeUrl"` - LastError string `json:"lastError"` - LastScrape time.Time `json:"lastScrape"` - Health scrape.TargetHealth `json:"health"` + DiscoveredLabels model.LabelSet `json:"discoveredLabels"` + Labels model.LabelSet `json:"labels"` + ScrapeURL string `json:"scrapeUrl"` + LastError string `json:"lastError"` + LastScrape time.Time `json:"lastScrape"` + Health HealthStatus `json:"health"` } // DroppedTarget models a dropped Prometheus scrape target. @@ -165,54 +169,6 @@ type queryResult struct { v model.Value } -func (a *ActiveTarget) UnmarshalJSON(b []byte) error { - v := struct { - DiscoveredLabels model.LabelSet `json:"discoveredLabels"` - Labels model.LabelSet `json:"labels"` - ScrapeURL string `json:"scrapeUrl"` - LastError string `json:"lastError"` - LastScrape time.Time `json:"lastScrape"` - Health scrape.TargetHealth `json:"health"` - }{} - - err := json.Unmarshal(b, &v) - if err != nil { - return err - } - - url, err := url.Parse(v.ScrapeURL) - - a.DiscoveredLabels = v.DiscoveredLabels - a.Labels = v.Labels - a.ScrapeURL = url - a.LastScrape = v.LastScrape - a.Health = v.Health - a.LastError = v.LastError - - return err -} - -func (a *AlertManager) UnmarshalJSON(b []byte) error { - var v map[string]string - - err := json.Unmarshal(b, &v) - if err != nil { - return err - } - - url, err := url.Parse(v["url"]) - a.URL = url - return err -} - -func (f *FlagsResult) UnmarshalJSON(b []byte) error { - var v map[string]string - - err := json.Unmarshal(b, &v) - f.Flags = v - return err -} - func (qr *queryResult) UnmarshalJSON(b []byte) error { v := struct { Type model.ValueType `json:"resultType"` diff --git a/api/prometheus/v1/api_test.go b/api/prometheus/v1/api_test.go index 5e66076..2fe6044 100644 --- a/api/prometheus/v1/api_test.go +++ b/api/prometheus/v1/api_test.go @@ -27,7 +27,6 @@ import ( "time" "github.com/prometheus/common/model" - "github.com/prometheus/prometheus/scrape" ) type apiTest struct { @@ -89,11 +88,6 @@ func TestAPIs(t *testing.T) { testTime := time.Now() - testURL, err := url.Parse("http://127.0.0.1:9090/api/v1/alerts") - if err != nil { - t.Errorf("Failed to initialize test URL.") - } - client := &apiTestClient{T: t} promAPI := &httpAPI{ @@ -372,13 +366,11 @@ func TestAPIs(t *testing.T) { "query.max-concurrency": "20", }, res: FlagsResult{ - Flags{ - "alertmanager.notification-queue-capacity": "10000", - "alertmanager.timeout": "10s", - "log.level": "info", - "query.lookback-delta": "5m", - "query.max-concurrency": "20", - }, + "alertmanager.notification-queue-capacity": "10000", + "alertmanager.timeout": "10s", + "log.level": "info", + "query.lookback-delta": "5m", + "query.max-concurrency": "20", }, }, @@ -397,24 +389,24 @@ func TestAPIs(t *testing.T) { inRes: map[string]interface{}{ "activeAlertManagers": []map[string]string{ { - "url": testURL.String(), + "url": "http://127.0.0.1:9091/api/v1/alerts", }, }, "droppedAlertManagers": []map[string]string{ { - "url": testURL.String(), + "url": "http://127.0.0.1:9092/api/v1/alerts", }, }, }, res: AlertManagersResult{ Active: []AlertManager{ { - URL: testURL, + URL: "http://127.0.0.1:9091/api/v1/alerts", }, }, Dropped: []AlertManager{ { - URL: testURL, + URL: "http://127.0.0.1:9092/api/v1/alerts", }, }, }, @@ -445,7 +437,7 @@ func TestAPIs(t *testing.T) { "instance": "127.0.0.1:9090", "job": "prometheus", }, - "scrapeUrl": testURL.String(), + "scrapeUrl": "http://127.0.0.1:9090", "lastError": "error while scraping target", "lastScrape": testTime.UTC().Format(time.RFC3339Nano), "health": "up", @@ -475,10 +467,10 @@ func TestAPIs(t *testing.T) { "instance": "127.0.0.1:9090", "job": "prometheus", }, - ScrapeURL: testURL, + ScrapeURL: "http://127.0.0.1:9090", LastError: "error while scraping target", LastScrape: testTime.UTC(), - Health: scrape.HealthGood, + Health: HealthGood, }, }, Dropped: []DroppedTarget{ From 335dadb61a49a461ab223e54937fb52262091b60 Mon Sep 17 00:00:00 2001 From: Bob Shannon Date: Thu, 12 Apr 2018 06:35:47 -0700 Subject: [PATCH 5/5] PR comments Signed-off-by: Bob Shannon --- .travis.yml | 6 +++--- api/prometheus/v1/api.go | 3 --- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/.travis.yml b/.travis.yml index 3ff54ea..e9bca4e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,9 +2,9 @@ sudo: false language: go go: -- 1.7.x -- 1.8.x -- 1.9.x + - 1.7.x + - 1.8.x + - 1.9.x script: - go test -short ./... diff --git a/api/prometheus/v1/api.go b/api/prometheus/v1/api.go index 3d37437..c41c0cf 100644 --- a/api/prometheus/v1/api.go +++ b/api/prometheus/v1/api.go @@ -131,9 +131,6 @@ type ConfigResult struct { // FlagsResult contains the result from querying the flag endpoint. type FlagsResult map[string]string -// Flags models a set of flags that Prometheus is configured with. -type Flags map[string]string - // SnapshotResult contains the result from querying the snapshot endpoint. type SnapshotResult struct { Name string `json:"name"`