mirror of https://github.com/status-im/consul.git
add StatusError to api package (#11054)
* add require http codes in api and use in operator_autopilot health check * add StatusError type in api package Signed-off-by: FFMMM <FFMMM@users.noreply.github.com>
This commit is contained in:
parent
9592990773
commit
377c3a9b0b
31
api/api.go
31
api/api.go
|
@ -82,6 +82,15 @@ const (
|
|||
HTTPPartitionEnvName = "CONSUL_PARTITION"
|
||||
)
|
||||
|
||||
type StatusError struct {
|
||||
Code int
|
||||
Body string
|
||||
}
|
||||
|
||||
func (e StatusError) Error() string {
|
||||
return fmt.Sprintf("Unexpected response code: %d (%s)", e.Code, e.Body)
|
||||
}
|
||||
|
||||
// QueryOptions are used to parameterize a query
|
||||
type QueryOptions struct {
|
||||
// Namespace overrides the `default` namespace
|
||||
|
@ -972,7 +981,7 @@ func (c *Client) doRequest(r *request) (time.Duration, *http.Response, error) {
|
|||
func (c *Client) query(endpoint string, out interface{}, q *QueryOptions) (*QueryMeta, error) {
|
||||
r := c.newRequest("GET", endpoint)
|
||||
r.setQueryOptions(q)
|
||||
rtt, resp, err := c.doRequest(r)
|
||||
rtt, resp, err := requireOK(c.doRequest(r))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -1090,16 +1099,28 @@ func encodeBody(obj interface{}) (io.Reader, error) {
|
|||
|
||||
// requireOK is used to wrap doRequest and check for a 200
|
||||
func requireOK(d time.Duration, resp *http.Response, e error) (time.Duration, *http.Response, error) {
|
||||
return requireHttpCodes(d, resp, e, 200)
|
||||
}
|
||||
|
||||
// requireHttpCodes checks for the "allowable" http codes for a response
|
||||
func requireHttpCodes(d time.Duration, resp *http.Response, e error, httpCodes ...int) (time.Duration, *http.Response, error) {
|
||||
if e != nil {
|
||||
if resp != nil {
|
||||
closeResponseBody(resp)
|
||||
}
|
||||
return d, nil, e
|
||||
}
|
||||
if resp.StatusCode != 200 {
|
||||
return d, nil, generateUnexpectedResponseCodeError(resp)
|
||||
|
||||
// if there is an http code that we require, return w no error
|
||||
for _, httpCode := range httpCodes {
|
||||
if resp.StatusCode == httpCode {
|
||||
return d, resp, nil
|
||||
}
|
||||
}
|
||||
return d, resp, nil
|
||||
|
||||
// if we reached here, then none of the http codes in resp matched any that we expected
|
||||
// so err out
|
||||
return d, nil, generateUnexpectedResponseCodeError(resp)
|
||||
}
|
||||
|
||||
// closeResponseBody reads resp.Body until EOF, and then closes it. The read
|
||||
|
@ -1127,7 +1148,7 @@ func generateUnexpectedResponseCodeError(resp *http.Response) error {
|
|||
closeResponseBody(resp)
|
||||
|
||||
trimmed := strings.TrimSpace(string(buf.Bytes()))
|
||||
return fmt.Errorf("Unexpected response code: %d (%s)", resp.StatusCode, trimmed)
|
||||
return StatusError{Code: resp.StatusCode, Body: trimmed}
|
||||
}
|
||||
|
||||
func requireNotFoundOrOK(d time.Duration, resp *http.Response, e error) (bool, time.Duration, *http.Response, error) {
|
||||
|
|
|
@ -352,9 +352,10 @@ func (op *Operator) AutopilotServerHealth(q *QueryOptions) (*OperatorHealthReply
|
|||
r := op.c.newRequest("GET", "/v1/operator/autopilot/health")
|
||||
r.setQueryOptions(q)
|
||||
|
||||
// we cannot just use requireOK because this endpoint might use a 429 status to indicate
|
||||
// that unhealthiness
|
||||
_, resp, err := op.c.doRequest(r)
|
||||
// we use 429 status to indicate unhealthiness
|
||||
d, resp, err := op.c.doRequest(r)
|
||||
_, resp, err = requireHttpCodes(d, resp, err, 200, 429)
|
||||
|
||||
if err != nil {
|
||||
if resp != nil {
|
||||
closeResponseBody(resp)
|
||||
|
@ -362,12 +363,6 @@ func (op *Operator) AutopilotServerHealth(q *QueryOptions) (*OperatorHealthReply
|
|||
return nil, err
|
||||
}
|
||||
|
||||
// these are the only 2 status codes that would indicate that we should
|
||||
// expect the body to contain the right format.
|
||||
if resp.StatusCode != 200 && resp.StatusCode != 429 {
|
||||
return nil, generateUnexpectedResponseCodeError(resp)
|
||||
}
|
||||
|
||||
defer closeResponseBody(resp)
|
||||
|
||||
var out OperatorHealthReply
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package api
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
|
@ -181,4 +182,15 @@ func TestAPI_OperatorAutopilotServerHealth_429(t *testing.T) {
|
|||
out, err := client.Operator().AutopilotServerHealth(nil)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, &reply, out)
|
||||
|
||||
mapi.withReply("GET", "/v1/operator/autopilot/health", nil, 500, nil).Once()
|
||||
_, err = client.Operator().AutopilotServerHealth(nil)
|
||||
|
||||
var statusE StatusError
|
||||
if errors.As(err, &statusE) {
|
||||
require.Equal(t, 500, statusE.Code)
|
||||
} else {
|
||||
t.Error("Failed to unwrap error as StatusError")
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue