Add storage.Warnings to client
Signed-off-by: Thomas Jackson <jacksontj.89@gmail.com> Fixes #560
This commit is contained in:
parent
af332dff97
commit
d5f3c8d55d
|
@ -25,6 +25,42 @@ import (
|
|||
"time"
|
||||
)
|
||||
|
||||
func NewErrorAPI(err error, warnings []string) Error {
|
||||
if err == nil && warnings == nil {
|
||||
return nil
|
||||
}
|
||||
return &ErrorAPI{err, warnings}
|
||||
}
|
||||
|
||||
type ErrorAPI struct {
|
||||
err error
|
||||
warnings []string
|
||||
}
|
||||
|
||||
func (w *ErrorAPI) Err() error {
|
||||
return w.err
|
||||
}
|
||||
|
||||
func (w *ErrorAPI) Error() string {
|
||||
if w.err != nil {
|
||||
return w.err.Error()
|
||||
}
|
||||
return "Warnings: " + strings.Join(w.warnings, " , ")
|
||||
}
|
||||
|
||||
func (w *ErrorAPI) Warnings() []string {
|
||||
return w.warnings
|
||||
}
|
||||
|
||||
// Error encapsulates an error + warning
|
||||
type Error interface {
|
||||
error
|
||||
// Err returns the underlying error.
|
||||
Err() error
|
||||
// Warnings returns a list of warnings.
|
||||
Warnings() []string
|
||||
}
|
||||
|
||||
// DefaultRoundTripper is used if no RoundTripper is set in Config.
|
||||
var DefaultRoundTripper http.RoundTripper = &http.Transport{
|
||||
Proxy: http.ProxyFromEnvironment,
|
||||
|
@ -55,14 +91,14 @@ func (cfg *Config) roundTripper() http.RoundTripper {
|
|||
// Client is the interface for an API client.
|
||||
type Client interface {
|
||||
URL(ep string, args map[string]string) *url.URL
|
||||
Do(context.Context, *http.Request) (*http.Response, []byte, error)
|
||||
Do(context.Context, *http.Request) (*http.Response, []byte, Error)
|
||||
}
|
||||
|
||||
// DoGetFallback will attempt to do the request as-is, and on a 405 it will fallback to a GET request.
|
||||
func DoGetFallback(c Client, ctx context.Context, u *url.URL, args url.Values) (*http.Response, []byte, error) {
|
||||
func DoGetFallback(c Client, ctx context.Context, u *url.URL, args url.Values) (*http.Response, []byte, Error) {
|
||||
req, err := http.NewRequest(http.MethodPost, u.String(), strings.NewReader(args.Encode()))
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
return nil, nil, NewErrorAPI(err, nil)
|
||||
}
|
||||
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||
|
||||
|
@ -71,11 +107,14 @@ func DoGetFallback(c Client, ctx context.Context, u *url.URL, args url.Values) (
|
|||
u.RawQuery = args.Encode()
|
||||
req, err = http.NewRequest(http.MethodGet, u.String(), nil)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
return nil, nil, NewErrorAPI(err, nil)
|
||||
}
|
||||
|
||||
} else {
|
||||
return resp, body, err
|
||||
if err != nil {
|
||||
return resp, body, NewErrorAPI(err, nil)
|
||||
}
|
||||
return resp, body, nil
|
||||
}
|
||||
return c.Do(ctx, req)
|
||||
}
|
||||
|
@ -115,7 +154,7 @@ func (c *httpClient) URL(ep string, args map[string]string) *url.URL {
|
|||
return &u
|
||||
}
|
||||
|
||||
func (c *httpClient) Do(ctx context.Context, req *http.Request) (*http.Response, []byte, error) {
|
||||
func (c *httpClient) Do(ctx context.Context, req *http.Request) (*http.Response, []byte, Error) {
|
||||
if ctx != nil {
|
||||
req = req.WithContext(ctx)
|
||||
}
|
||||
|
@ -127,7 +166,7 @@ func (c *httpClient) Do(ctx context.Context, req *http.Request) (*http.Response,
|
|||
}()
|
||||
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
return nil, nil, NewErrorAPI(err, nil)
|
||||
}
|
||||
|
||||
var body []byte
|
||||
|
@ -147,5 +186,5 @@ func (c *httpClient) Do(ctx context.Context, req *http.Request) (*http.Response,
|
|||
case <-done:
|
||||
}
|
||||
|
||||
return resp, body, err
|
||||
return resp, body, NewErrorAPI(err, nil)
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@ import (
|
|||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/prometheus/client_golang/api"
|
||||
|
@ -95,13 +96,26 @@ const (
|
|||
|
||||
// Error is an error returned by the API.
|
||||
type Error struct {
|
||||
Type ErrorType
|
||||
Msg string
|
||||
Detail string
|
||||
Type ErrorType
|
||||
Msg string
|
||||
Detail string
|
||||
warnings []string
|
||||
}
|
||||
|
||||
func (e *Error) Error() string {
|
||||
return fmt.Sprintf("%s: %s", e.Type, e.Msg)
|
||||
if e.Type != "" || e.Msg != "" {
|
||||
return fmt.Sprintf("%s: %s", e.Type, e.Msg)
|
||||
}
|
||||
|
||||
return "Warnings: " + strings.Join(e.warnings, " , ")
|
||||
}
|
||||
|
||||
func (w *Error) Err() error {
|
||||
return w
|
||||
}
|
||||
|
||||
func (w *Error) Warnings() []string {
|
||||
return w.warnings
|
||||
}
|
||||
|
||||
// Range represents a sliced time range.
|
||||
|
@ -115,32 +129,32 @@ type Range struct {
|
|||
// API provides bindings for Prometheus's v1 API.
|
||||
type API interface {
|
||||
// Alerts returns a list of all active alerts.
|
||||
Alerts(ctx context.Context) (AlertsResult, error)
|
||||
Alerts(ctx context.Context) (AlertsResult, api.Error)
|
||||
// AlertManagers returns an overview of the current state of the Prometheus alert manager discovery.
|
||||
AlertManagers(ctx context.Context) (AlertManagersResult, error)
|
||||
AlertManagers(ctx context.Context) (AlertManagersResult, api.Error)
|
||||
// CleanTombstones removes the deleted data from disk and cleans up the existing tombstones.
|
||||
CleanTombstones(ctx context.Context) error
|
||||
CleanTombstones(ctx context.Context) api.Error
|
||||
// Config returns the current Prometheus configuration.
|
||||
Config(ctx context.Context) (ConfigResult, error)
|
||||
Config(ctx context.Context) (ConfigResult, api.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
|
||||
DeleteSeries(ctx context.Context, matches []string, startTime time.Time, endTime time.Time) api.Error
|
||||
// Flags returns the flag values that Prometheus was launched with.
|
||||
Flags(ctx context.Context) (FlagsResult, error)
|
||||
Flags(ctx context.Context) (FlagsResult, api.Error)
|
||||
// LabelValues performs a query for the values of the given label.
|
||||
LabelValues(ctx context.Context, label string) (model.LabelValues, error)
|
||||
LabelValues(ctx context.Context, label string) (model.LabelValues, api.Error)
|
||||
// Query performs a query for the given time.
|
||||
Query(ctx context.Context, query string, ts time.Time) (model.Value, error)
|
||||
Query(ctx context.Context, query string, ts time.Time) (model.Value, api.Error)
|
||||
// QueryRange performs a query for the given range.
|
||||
QueryRange(ctx context.Context, query string, r Range) (model.Value, error)
|
||||
QueryRange(ctx context.Context, query string, r Range) (model.Value, api.Error)
|
||||
// Series finds series by label matchers.
|
||||
Series(ctx context.Context, matches []string, startTime time.Time, endTime time.Time) ([]model.LabelSet, error)
|
||||
Series(ctx context.Context, matches []string, startTime time.Time, endTime time.Time) ([]model.LabelSet, api.Error)
|
||||
// Snapshot creates a snapshot of all current data into snapshots/<datetime>-<rand>
|
||||
// under the TSDB's data directory and returns the directory as response.
|
||||
Snapshot(ctx context.Context, skipHead bool) (SnapshotResult, error)
|
||||
Snapshot(ctx context.Context, skipHead bool) (SnapshotResult, api.Error)
|
||||
// Rules returns a list of alerting and recording rules that are currently loaded.
|
||||
Rules(ctx context.Context) (RulesResult, error)
|
||||
Rules(ctx context.Context) (RulesResult, api.Error)
|
||||
// Targets returns an overview of the current state of the Prometheus target discovery.
|
||||
Targets(ctx context.Context) (TargetsResult, error)
|
||||
Targets(ctx context.Context) (TargetsResult, api.Error)
|
||||
}
|
||||
|
||||
// AlertsResult contains the result from querying the alerts endpoint.
|
||||
|
@ -408,73 +422,73 @@ type httpAPI struct {
|
|||
client api.Client
|
||||
}
|
||||
|
||||
func (h *httpAPI) Alerts(ctx context.Context) (AlertsResult, error) {
|
||||
func (h *httpAPI) Alerts(ctx context.Context) (AlertsResult, api.Error) {
|
||||
u := h.client.URL(epAlerts, nil)
|
||||
|
||||
req, err := http.NewRequest(http.MethodGet, u.String(), nil)
|
||||
if err != nil {
|
||||
return AlertsResult{}, err
|
||||
return AlertsResult{}, api.NewErrorAPI(err, nil)
|
||||
}
|
||||
|
||||
_, body, err := h.client.Do(ctx, req)
|
||||
if err != nil {
|
||||
return AlertsResult{}, err
|
||||
_, body, apiErr := h.client.Do(ctx, req)
|
||||
if apiErr != nil {
|
||||
return AlertsResult{}, apiErr
|
||||
}
|
||||
|
||||
var res AlertsResult
|
||||
err = json.Unmarshal(body, &res)
|
||||
return res, err
|
||||
return res, api.NewErrorAPI(err, nil)
|
||||
}
|
||||
|
||||
func (h *httpAPI) AlertManagers(ctx context.Context) (AlertManagersResult, error) {
|
||||
func (h *httpAPI) AlertManagers(ctx context.Context) (AlertManagersResult, api.Error) {
|
||||
u := h.client.URL(epAlertManagers, nil)
|
||||
|
||||
req, err := http.NewRequest(http.MethodGet, u.String(), nil)
|
||||
if err != nil {
|
||||
return AlertManagersResult{}, err
|
||||
return AlertManagersResult{}, api.NewErrorAPI(err, nil)
|
||||
}
|
||||
|
||||
_, body, err := h.client.Do(ctx, req)
|
||||
if err != nil {
|
||||
return AlertManagersResult{}, err
|
||||
_, body, apiErr := h.client.Do(ctx, req)
|
||||
if apiErr != nil {
|
||||
return AlertManagersResult{}, apiErr
|
||||
}
|
||||
|
||||
var res AlertManagersResult
|
||||
err = json.Unmarshal(body, &res)
|
||||
return res, err
|
||||
return res, api.NewErrorAPI(err, nil)
|
||||
}
|
||||
|
||||
func (h *httpAPI) CleanTombstones(ctx context.Context) error {
|
||||
func (h *httpAPI) CleanTombstones(ctx context.Context) api.Error {
|
||||
u := h.client.URL(epCleanTombstones, nil)
|
||||
|
||||
req, err := http.NewRequest(http.MethodPost, u.String(), nil)
|
||||
if err != nil {
|
||||
return err
|
||||
return api.NewErrorAPI(err, nil)
|
||||
}
|
||||
|
||||
_, _, err = h.client.Do(ctx, req)
|
||||
return err
|
||||
_, _, apiErr := h.client.Do(ctx, req)
|
||||
return apiErr
|
||||
}
|
||||
|
||||
func (h *httpAPI) Config(ctx context.Context) (ConfigResult, error) {
|
||||
func (h *httpAPI) Config(ctx context.Context) (ConfigResult, api.Error) {
|
||||
u := h.client.URL(epConfig, nil)
|
||||
|
||||
req, err := http.NewRequest(http.MethodGet, u.String(), nil)
|
||||
if err != nil {
|
||||
return ConfigResult{}, err
|
||||
return ConfigResult{}, api.NewErrorAPI(err, nil)
|
||||
}
|
||||
|
||||
_, body, err := h.client.Do(ctx, req)
|
||||
if err != nil {
|
||||
return ConfigResult{}, err
|
||||
_, body, apiErr := h.client.Do(ctx, req)
|
||||
if apiErr != nil {
|
||||
return ConfigResult{}, apiErr
|
||||
}
|
||||
|
||||
var res ConfigResult
|
||||
err = json.Unmarshal(body, &res)
|
||||
return res, err
|
||||
return res, api.NewErrorAPI(err, nil)
|
||||
}
|
||||
|
||||
func (h *httpAPI) DeleteSeries(ctx context.Context, matches []string, startTime time.Time, endTime time.Time) error {
|
||||
func (h *httpAPI) DeleteSeries(ctx context.Context, matches []string, startTime time.Time, endTime time.Time) api.Error {
|
||||
u := h.client.URL(epDeleteSeries, nil)
|
||||
q := u.Query()
|
||||
|
||||
|
@ -489,47 +503,47 @@ func (h *httpAPI) DeleteSeries(ctx context.Context, matches []string, startTime
|
|||
|
||||
req, err := http.NewRequest(http.MethodPost, u.String(), nil)
|
||||
if err != nil {
|
||||
return err
|
||||
return api.NewErrorAPI(err, nil)
|
||||
}
|
||||
|
||||
_, _, err = h.client.Do(ctx, req)
|
||||
return err
|
||||
_, _, apiErr := h.client.Do(ctx, req)
|
||||
return apiErr
|
||||
}
|
||||
|
||||
func (h *httpAPI) Flags(ctx context.Context) (FlagsResult, error) {
|
||||
func (h *httpAPI) Flags(ctx context.Context) (FlagsResult, api.Error) {
|
||||
u := h.client.URL(epFlags, nil)
|
||||
|
||||
req, err := http.NewRequest(http.MethodGet, u.String(), nil)
|
||||
if err != nil {
|
||||
return FlagsResult{}, err
|
||||
return FlagsResult{}, api.NewErrorAPI(err, nil)
|
||||
}
|
||||
|
||||
_, body, err := h.client.Do(ctx, req)
|
||||
if err != nil {
|
||||
return FlagsResult{}, err
|
||||
_, body, apiErr := h.client.Do(ctx, req)
|
||||
if apiErr != nil {
|
||||
return FlagsResult{}, apiErr
|
||||
}
|
||||
|
||||
var res FlagsResult
|
||||
err = json.Unmarshal(body, &res)
|
||||
return res, err
|
||||
return res, api.NewErrorAPI(err, nil)
|
||||
}
|
||||
|
||||
func (h *httpAPI) LabelValues(ctx context.Context, label string) (model.LabelValues, error) {
|
||||
func (h *httpAPI) LabelValues(ctx context.Context, label string) (model.LabelValues, api.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
|
||||
return nil, api.NewErrorAPI(err, nil)
|
||||
}
|
||||
_, body, err := h.client.Do(ctx, req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
_, body, apiErr := h.client.Do(ctx, req)
|
||||
if apiErr != nil {
|
||||
return nil, apiErr
|
||||
}
|
||||
var labelValues model.LabelValues
|
||||
err = json.Unmarshal(body, &labelValues)
|
||||
return labelValues, err
|
||||
return labelValues, api.NewErrorAPI(err, nil)
|
||||
}
|
||||
|
||||
func (h *httpAPI) Query(ctx context.Context, query string, ts time.Time) (model.Value, error) {
|
||||
func (h *httpAPI) Query(ctx context.Context, query string, ts time.Time) (model.Value, api.Error) {
|
||||
u := h.client.URL(epQuery, nil)
|
||||
q := u.Query()
|
||||
|
||||
|
@ -538,18 +552,16 @@ func (h *httpAPI) Query(ctx context.Context, query string, ts time.Time) (model.
|
|||
q.Set("time", ts.Format(time.RFC3339Nano))
|
||||
}
|
||||
|
||||
_, body, err := api.DoGetFallback(h.client, ctx, u, q)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
_, body, apiErr := api.DoGetFallback(h.client, ctx, u, q)
|
||||
if apiErr != nil {
|
||||
return nil, apiErr
|
||||
}
|
||||
|
||||
var qres queryResult
|
||||
err = json.Unmarshal(body, &qres)
|
||||
|
||||
return model.Value(qres.v), err
|
||||
return model.Value(qres.v), api.NewErrorAPI(json.Unmarshal(body, &qres), nil)
|
||||
}
|
||||
|
||||
func (h *httpAPI) QueryRange(ctx context.Context, query string, r Range) (model.Value, error) {
|
||||
func (h *httpAPI) QueryRange(ctx context.Context, query string, r Range) (model.Value, api.Error) {
|
||||
u := h.client.URL(epQueryRange, nil)
|
||||
q := u.Query()
|
||||
|
||||
|
@ -564,18 +576,17 @@ func (h *httpAPI) QueryRange(ctx context.Context, query string, r Range) (model.
|
|||
q.Set("end", end)
|
||||
q.Set("step", step)
|
||||
|
||||
_, body, err := api.DoGetFallback(h.client, ctx, u, q)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
_, body, apiErr := api.DoGetFallback(h.client, ctx, u, q)
|
||||
if apiErr != nil {
|
||||
return nil, apiErr
|
||||
}
|
||||
|
||||
var qres queryResult
|
||||
err = json.Unmarshal(body, &qres)
|
||||
|
||||
return model.Value(qres.v), err
|
||||
return model.Value(qres.v), api.NewErrorAPI(json.Unmarshal(body, &qres), nil)
|
||||
}
|
||||
|
||||
func (h *httpAPI) Series(ctx context.Context, matches []string, startTime time.Time, endTime time.Time) ([]model.LabelSet, error) {
|
||||
func (h *httpAPI) Series(ctx context.Context, matches []string, startTime time.Time, endTime time.Time) ([]model.LabelSet, api.Error) {
|
||||
u := h.client.URL(epSeries, nil)
|
||||
q := u.Query()
|
||||
|
||||
|
@ -590,20 +601,20 @@ func (h *httpAPI) Series(ctx context.Context, matches []string, startTime time.T
|
|||
|
||||
req, err := http.NewRequest(http.MethodGet, u.String(), nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, api.NewErrorAPI(err, nil)
|
||||
}
|
||||
|
||||
_, body, err := h.client.Do(ctx, req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
_, body, apiErr := h.client.Do(ctx, req)
|
||||
if apiErr != nil {
|
||||
return nil, apiErr
|
||||
}
|
||||
|
||||
var mset []model.LabelSet
|
||||
err = json.Unmarshal(body, &mset)
|
||||
return mset, err
|
||||
return mset, api.NewErrorAPI(err, nil)
|
||||
}
|
||||
|
||||
func (h *httpAPI) Snapshot(ctx context.Context, skipHead bool) (SnapshotResult, error) {
|
||||
func (h *httpAPI) Snapshot(ctx context.Context, skipHead bool) (SnapshotResult, api.Error) {
|
||||
u := h.client.URL(epSnapshot, nil)
|
||||
q := u.Query()
|
||||
|
||||
|
@ -613,53 +624,53 @@ func (h *httpAPI) Snapshot(ctx context.Context, skipHead bool) (SnapshotResult,
|
|||
|
||||
req, err := http.NewRequest(http.MethodPost, u.String(), nil)
|
||||
if err != nil {
|
||||
return SnapshotResult{}, err
|
||||
return SnapshotResult{}, api.NewErrorAPI(err, nil)
|
||||
}
|
||||
|
||||
_, body, err := h.client.Do(ctx, req)
|
||||
if err != nil {
|
||||
return SnapshotResult{}, err
|
||||
_, body, apiErr := h.client.Do(ctx, req)
|
||||
if apiErr != nil {
|
||||
return SnapshotResult{}, apiErr
|
||||
}
|
||||
|
||||
var res SnapshotResult
|
||||
err = json.Unmarshal(body, &res)
|
||||
return res, err
|
||||
return res, api.NewErrorAPI(err, nil)
|
||||
}
|
||||
|
||||
func (h *httpAPI) Rules(ctx context.Context) (RulesResult, error) {
|
||||
func (h *httpAPI) Rules(ctx context.Context) (RulesResult, api.Error) {
|
||||
u := h.client.URL(epRules, nil)
|
||||
|
||||
req, err := http.NewRequest(http.MethodGet, u.String(), nil)
|
||||
if err != nil {
|
||||
return RulesResult{}, err
|
||||
return RulesResult{}, api.NewErrorAPI(err, nil)
|
||||
}
|
||||
|
||||
_, body, err := h.client.Do(ctx, req)
|
||||
if err != nil {
|
||||
return RulesResult{}, err
|
||||
_, body, apiErr := h.client.Do(ctx, req)
|
||||
if apiErr != nil {
|
||||
return RulesResult{}, apiErr
|
||||
}
|
||||
|
||||
var res RulesResult
|
||||
err = json.Unmarshal(body, &res)
|
||||
return res, err
|
||||
return res, api.NewErrorAPI(err, nil)
|
||||
}
|
||||
|
||||
func (h *httpAPI) Targets(ctx context.Context) (TargetsResult, error) {
|
||||
func (h *httpAPI) Targets(ctx context.Context) (TargetsResult, api.Error) {
|
||||
u := h.client.URL(epTargets, nil)
|
||||
|
||||
req, err := http.NewRequest(http.MethodGet, u.String(), nil)
|
||||
if err != nil {
|
||||
return TargetsResult{}, err
|
||||
return TargetsResult{}, api.NewErrorAPI(err, nil)
|
||||
}
|
||||
|
||||
_, body, err := h.client.Do(ctx, req)
|
||||
if err != nil {
|
||||
return TargetsResult{}, err
|
||||
_, body, apiErr := h.client.Do(ctx, req)
|
||||
if apiErr != nil {
|
||||
return TargetsResult{}, apiErr
|
||||
}
|
||||
|
||||
var res TargetsResult
|
||||
err = json.Unmarshal(body, &res)
|
||||
return res, err
|
||||
return res, api.NewErrorAPI(err, nil)
|
||||
}
|
||||
|
||||
// apiClient wraps a regular client and processes successful API responses.
|
||||
|
@ -673,6 +684,7 @@ type apiResponse struct {
|
|||
Data json.RawMessage `json:"data"`
|
||||
ErrorType ErrorType `json:"errorType"`
|
||||
Error string `json:"error"`
|
||||
Warnings []string `json:"warnings,omitempty"`
|
||||
}
|
||||
|
||||
func apiError(code int) bool {
|
||||
|
@ -690,14 +702,16 @@ func errorTypeAndMsgFor(resp *http.Response) (ErrorType, string) {
|
|||
return ErrBadResponse, fmt.Sprintf("bad response code %d", resp.StatusCode)
|
||||
}
|
||||
|
||||
func (c apiClient) Do(ctx context.Context, req *http.Request) (*http.Response, []byte, error) {
|
||||
resp, body, err := c.Client.Do(ctx, req)
|
||||
if err != nil {
|
||||
return resp, body, err
|
||||
func (c apiClient) Do(ctx context.Context, req *http.Request) (*http.Response, []byte, api.Error) {
|
||||
resp, body, apiErr := c.Client.Do(ctx, req)
|
||||
if apiErr != nil {
|
||||
return resp, body, apiErr
|
||||
}
|
||||
|
||||
code := resp.StatusCode
|
||||
|
||||
var err api.Error
|
||||
|
||||
if code/100 != 2 && !apiError(code) {
|
||||
errorType, errorMsg := errorTypeAndMsgFor(resp)
|
||||
return resp, body, &Error{
|
||||
|
@ -710,27 +724,30 @@ func (c apiClient) Do(ctx context.Context, req *http.Request) (*http.Response, [
|
|||
var result apiResponse
|
||||
|
||||
if http.StatusNoContent != code {
|
||||
if err = json.Unmarshal(body, &result); err != nil {
|
||||
if jsonErr := json.Unmarshal(body, &result); jsonErr != nil {
|
||||
return resp, body, &Error{
|
||||
Type: ErrBadResponse,
|
||||
Msg: err.Error(),
|
||||
Msg: jsonErr.Error(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if apiError(code) != (result.Status == "error") {
|
||||
err = &Error{
|
||||
Type: ErrBadResponse,
|
||||
Msg: "inconsistent body for response code",
|
||||
Type: ErrBadResponse,
|
||||
Msg: "inconsistent body for response code",
|
||||
warnings: result.Warnings,
|
||||
}
|
||||
}
|
||||
|
||||
if apiError(code) && result.Status == "error" {
|
||||
err = &Error{
|
||||
Type: result.ErrorType,
|
||||
Msg: result.Error,
|
||||
Type: result.ErrorType,
|
||||
Msg: result.Error,
|
||||
warnings: result.Warnings,
|
||||
}
|
||||
}
|
||||
|
||||
return resp, []byte(result.Data), err
|
||||
|
||||
}
|
||||
|
|
|
@ -25,11 +25,14 @@ import (
|
|||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/prometheus/client_golang/api"
|
||||
"github.com/prometheus/common/model"
|
||||
"github.com/prometheus/tsdb/testutil"
|
||||
)
|
||||
|
||||
type apiTest struct {
|
||||
do func() (interface{}, error)
|
||||
do func() (interface{}, api.Error)
|
||||
inWarnings []string
|
||||
inErr error
|
||||
inStatusCode int
|
||||
inRes interface{}
|
||||
|
@ -58,7 +61,7 @@ func (c *apiTestClient) URL(ep string, args map[string]string) *url.URL {
|
|||
return u
|
||||
}
|
||||
|
||||
func (c *apiTestClient) Do(ctx context.Context, req *http.Request) (*http.Response, []byte, error) {
|
||||
func (c *apiTestClient) Do(ctx context.Context, req *http.Request) (*http.Response, []byte, api.Error) {
|
||||
|
||||
test := c.curTest
|
||||
|
||||
|
@ -83,7 +86,7 @@ func (c *apiTestClient) Do(ctx context.Context, req *http.Request) (*http.Respon
|
|||
resp.StatusCode = http.StatusOK
|
||||
}
|
||||
|
||||
return resp, b, test.inErr
|
||||
return resp, b, api.NewErrorAPI(test.inErr, test.inWarnings)
|
||||
}
|
||||
|
||||
func TestAPIs(t *testing.T) {
|
||||
|
@ -96,74 +99,74 @@ func TestAPIs(t *testing.T) {
|
|||
client: client,
|
||||
}
|
||||
|
||||
doAlertManagers := func() func() (interface{}, error) {
|
||||
return func() (interface{}, error) {
|
||||
doAlertManagers := func() func() (interface{}, api.Error) {
|
||||
return func() (interface{}, api.Error) {
|
||||
return promAPI.AlertManagers(context.Background())
|
||||
}
|
||||
}
|
||||
|
||||
doCleanTombstones := func() func() (interface{}, error) {
|
||||
return func() (interface{}, error) {
|
||||
doCleanTombstones := func() func() (interface{}, api.Error) {
|
||||
return func() (interface{}, api.Error) {
|
||||
return nil, promAPI.CleanTombstones(context.Background())
|
||||
}
|
||||
}
|
||||
|
||||
doConfig := func() func() (interface{}, error) {
|
||||
return func() (interface{}, error) {
|
||||
doConfig := func() func() (interface{}, api.Error) {
|
||||
return func() (interface{}, api.Error) {
|
||||
return promAPI.Config(context.Background())
|
||||
}
|
||||
}
|
||||
|
||||
doDeleteSeries := func(matcher string, startTime time.Time, endTime time.Time) func() (interface{}, error) {
|
||||
return func() (interface{}, error) {
|
||||
doDeleteSeries := func(matcher string, startTime time.Time, endTime time.Time) func() (interface{}, api.Error) {
|
||||
return func() (interface{}, api.Error) {
|
||||
return nil, promAPI.DeleteSeries(context.Background(), []string{matcher}, startTime, endTime)
|
||||
}
|
||||
}
|
||||
|
||||
doFlags := func() func() (interface{}, error) {
|
||||
return func() (interface{}, error) {
|
||||
doFlags := func() func() (interface{}, api.Error) {
|
||||
return func() (interface{}, api.Error) {
|
||||
return promAPI.Flags(context.Background())
|
||||
}
|
||||
}
|
||||
|
||||
doLabelValues := func(label string) func() (interface{}, error) {
|
||||
return func() (interface{}, error) {
|
||||
doLabelValues := func(label string) func() (interface{}, api.Error) {
|
||||
return func() (interface{}, api.Error) {
|
||||
return promAPI.LabelValues(context.Background(), label)
|
||||
}
|
||||
}
|
||||
|
||||
doQuery := func(q string, ts time.Time) func() (interface{}, error) {
|
||||
return func() (interface{}, error) {
|
||||
doQuery := func(q string, ts time.Time) func() (interface{}, api.Error) {
|
||||
return func() (interface{}, api.Error) {
|
||||
return promAPI.Query(context.Background(), q, ts)
|
||||
}
|
||||
}
|
||||
|
||||
doQueryRange := func(q string, rng Range) func() (interface{}, error) {
|
||||
return func() (interface{}, error) {
|
||||
doQueryRange := func(q string, rng Range) func() (interface{}, api.Error) {
|
||||
return func() (interface{}, api.Error) {
|
||||
return promAPI.QueryRange(context.Background(), q, rng)
|
||||
}
|
||||
}
|
||||
|
||||
doSeries := func(matcher string, startTime time.Time, endTime time.Time) func() (interface{}, error) {
|
||||
return func() (interface{}, error) {
|
||||
doSeries := func(matcher string, startTime time.Time, endTime time.Time) func() (interface{}, api.Error) {
|
||||
return func() (interface{}, api.Error) {
|
||||
return promAPI.Series(context.Background(), []string{matcher}, startTime, endTime)
|
||||
}
|
||||
}
|
||||
|
||||
doSnapshot := func(skipHead bool) func() (interface{}, error) {
|
||||
return func() (interface{}, error) {
|
||||
doSnapshot := func(skipHead bool) func() (interface{}, api.Error) {
|
||||
return func() (interface{}, api.Error) {
|
||||
return promAPI.Snapshot(context.Background(), skipHead)
|
||||
}
|
||||
}
|
||||
|
||||
doRules := func() func() (interface{}, error) {
|
||||
return func() (interface{}, error) {
|
||||
doRules := func() func() (interface{}, api.Error) {
|
||||
return func() (interface{}, api.Error) {
|
||||
return promAPI.Rules(context.Background())
|
||||
}
|
||||
}
|
||||
|
||||
doTargets := func() func() (interface{}, error) {
|
||||
return func() (interface{}, error) {
|
||||
doTargets := func() func() (interface{}, api.Error) {
|
||||
return func() (interface{}, api.Error) {
|
||||
return promAPI.Targets(context.Background())
|
||||
}
|
||||
}
|
||||
|
@ -693,7 +696,7 @@ func (c *testClient) URL(ep string, args map[string]string) *url.URL {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (c *testClient) Do(ctx context.Context, req *http.Request) (*http.Response, []byte, error) {
|
||||
func (c *testClient) Do(ctx context.Context, req *http.Request) (*http.Response, []byte, api.Error) {
|
||||
if ctx == nil {
|
||||
c.Fatalf("context was not passed down")
|
||||
}
|
||||
|
@ -829,6 +832,21 @@ func TestAPIClientDo(t *testing.T) {
|
|||
Msg: "inconsistent body for response code",
|
||||
},
|
||||
},
|
||||
{
|
||||
code: http.StatusOK,
|
||||
response: &apiResponse{
|
||||
Status: "error",
|
||||
Data: json.RawMessage(`"test"`),
|
||||
ErrorType: ErrTimeout,
|
||||
Error: "timed out",
|
||||
Warnings: []string{"a"},
|
||||
},
|
||||
expectedErr: &Error{
|
||||
Type: ErrBadResponse,
|
||||
Msg: "inconsistent body for response code",
|
||||
warnings: []string{"a"},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
tc := &testClient{
|
||||
|
@ -846,28 +864,20 @@ func TestAPIClientDo(t *testing.T) {
|
|||
_, body, err := client.Do(context.Background(), tc.req)
|
||||
|
||||
if test.expectedErr != nil {
|
||||
if err == nil {
|
||||
t.Fatalf("expected error %q but got none", test.expectedErr)
|
||||
}
|
||||
if test.expectedErr.Error() != err.Error() {
|
||||
t.Errorf("unexpected error: want %q, got %q", test.expectedErr, err)
|
||||
}
|
||||
testutil.NotOk(t, err)
|
||||
testutil.Equals(t, test.expectedErr.Error(), err.Error())
|
||||
|
||||
if test.expectedErr.Detail != "" {
|
||||
apiErr := err.(*Error)
|
||||
if apiErr.Detail != test.expectedErr.Detail {
|
||||
t.Errorf("unexpected error details: want %q, got %q", test.expectedErr.Detail, apiErr.Detail)
|
||||
}
|
||||
testutil.Equals(t, apiErr.Detail, test.expectedErr.Detail)
|
||||
}
|
||||
|
||||
testutil.Equals(t, test.expectedErr.Warnings(), err.Warnings())
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("unexpeceted error %s", err)
|
||||
}
|
||||
testutil.Ok(t, err)
|
||||
|
||||
want, got := test.expectedBody, string(body)
|
||||
if want != got {
|
||||
t.Errorf("unexpected body: want %q, got %q", want, got)
|
||||
}
|
||||
testutil.Equals(t, test.expectedBody, string(body))
|
||||
})
|
||||
|
||||
}
|
||||
|
|
6
go.sum
6
go.sum
|
@ -1,3 +1,4 @@
|
|||
github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE=
|
||||
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
|
@ -5,7 +6,9 @@ github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973 h1:xJ4a3vCFaGF/jqvzLM
|
|||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||
github.com/beorn7/perks v1.0.0 h1:HWo1m869IqiPhD389kmkxeTalrjNbbJTC8LXupb+sl0=
|
||||
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
|
||||
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
|
||||
github.com/go-kit/kit v0.8.0 h1:Wz+5lgoB0kkuqLEc6NVmwRknTKP6dTGbSqvhZtBI/j0=
|
||||
|
@ -28,6 +31,7 @@ github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5
|
|||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
|
||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910 h1:idejC8f05m9MGOsuEi1ATq9shN03HrxNkD/luQvxCv8=
|
||||
|
@ -43,8 +47,10 @@ github.com/prometheus/procfs v0.0.0-20190412120340-e22ddced7142/go.mod h1:TjEm7z
|
|||
github.com/prometheus/tsdb v0.7.1 h1:YZcsG11NqnK4czYLrWd9mpEuAJIHVQLwdrleYfszMAA=
|
||||
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
|
||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72 h1:qLC7fQah7D6K1B0ujays3HV9gkFtllcxhzImRR7ArPQ=
|
||||
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
|
|
Loading…
Reference in New Issue