diff --git a/pkg/client/client.go b/pkg/client/client.go index 444fa65bb7c..a33dd85ff74 100644 --- a/pkg/client/client.go +++ b/pkg/client/client.go @@ -47,6 +47,16 @@ type ClientInterface interface { DeleteService(string) error } +// StatusErr might get returned from an api call if your request is still being processed +// and hence the expected return data is not available yet. +type StatusErr struct { + Status api.Status +} + +func (s *StatusErr) Error() string { + return fmt.Sprintf("Status: %v (%#v)", s.Status.Status, s) +} + // AuthInfo is used to store authorization information type AuthInfo struct { User string @@ -93,6 +103,13 @@ func (c *Client) doRequest(request *http.Request) ([]byte, error) { if response.StatusCode < http.StatusOK || response.StatusCode > http.StatusPartialContent { return nil, fmt.Errorf("request [%#v] failed (%d) %s: %s", request, response.StatusCode, response.Status, string(body)) } + if response.StatusCode == http.StatusAccepted { + var status api.Status + if err := api.DecodeInto(body, &status); err == nil { + return nil, &StatusErr{status} + } + // Sometimes the server returns 202 even though it completely handled the request. + } return body, err } diff --git a/pkg/client/client_test.go b/pkg/client/client_test.go index 41563790a37..51f7b4f353e 100644 --- a/pkg/client/client_test.go +++ b/pkg/client/client_test.go @@ -427,3 +427,37 @@ func TestDoRequest(t *testing.T) { } fakeHandler.ValidateRequest(t, "/foo/bar", "GET", nil) } + +func TestDoRequestAccepted(t *testing.T) { + status := api.Status{Status: api.StatusWorking} + expectedBody, _ := api.Encode(status) + fakeHandler := util.FakeHandler{ + StatusCode: 202, + ResponseBody: string(expectedBody), + T: t, + } + testServer := httptest.NewTLSServer(&fakeHandler) + request, _ := http.NewRequest("GET", testServer.URL+"/foo/bar", nil) + auth := AuthInfo{User: "user", Password: "pass"} + c := New(testServer.URL, &auth) + body, err := c.doRequest(request) + if request.Header["Authorization"] == nil { + t.Errorf("Request is missing authorization header: %#v", *request) + } + if err == nil { + t.Error("Unexpected non-error") + return + } + se, ok := err.(*StatusErr) + if !ok { + t.Errorf("Unexpected kind of error: %#v", err) + return + } + if !reflect.DeepEqual(se.Status, status) { + t.Errorf("Unexpected status: %#v", se.Status) + } + if body != nil { + t.Errorf("Expected nil body, but saw: '%s'", body) + } + fakeHandler.ValidateRequest(t, "/foo/bar", "GET", nil) +} diff --git a/pkg/client/request.go b/pkg/client/request.go index c75e13f7a6d..a8ad1da0bbc 100644 --- a/pkg/client/request.go +++ b/pkg/client/request.go @@ -166,6 +166,14 @@ func (r *Request) Do() Result { return Result{err: err} } respBody, err := r.c.doRequest(req) + if err != nil { + if statusErr, ok := err.(*StatusErr); ok { + // TODO: using the information in statusErr, + // loop querying the server to wait and retrieve + // the actual result. + _ = statusErr + } + } return Result{respBody, err} }