From 108784c58035189fc19346d2b7aedd784f9bdb80 Mon Sep 17 00:00:00 2001 From: Malte Poll <1780588+malt3@users.noreply.github.com> Date: Wed, 6 Mar 2024 13:20:42 +0100 Subject: [PATCH] openstack: improve error message on IMDS failures --- internal/cloud/openstack/imds.go | 7 +++-- internal/cloud/openstack/imds_test.go | 43 +++++++++++++++++++-------- 2 files changed, 35 insertions(+), 15 deletions(-) diff --git a/internal/cloud/openstack/imds.go b/internal/cloud/openstack/imds.go index c9e3332c8..e977558d9 100644 --- a/internal/cloud/openstack/imds.go +++ b/internal/cloud/openstack/imds.go @@ -211,7 +211,7 @@ func (c *imdsClient) update(ctx context.Context) error { } var metadataResp metadataResponse if err := json.Unmarshal(resp, &metadataResp); err != nil { - return err + return fmt.Errorf("unmarshalling IMDS metadata response %q: %w", string(resp), err) } c.cache = metadataResp c.cacheTime = time.Now() @@ -244,7 +244,10 @@ func httpGet(ctx context.Context, c httpClient, url string) ([]byte, error) { } resp, err := c.Do(req) if err != nil { - return nil, err + return nil, fmt.Errorf("querying the OpenStack IMDS api failed for %q: %w", url, err) + } + if resp.StatusCode < 200 || resp.StatusCode >= 300 { + return nil, fmt.Errorf("IMDS api might be broken for this server. Recreate the cluster if this issue persists. Querying the OpenStack IMDS api failed for %q with error code %d", url, resp.StatusCode) } defer resp.Body.Close() return io.ReadAll(resp.Body) diff --git a/internal/cloud/openstack/imds_test.go b/internal/cloud/openstack/imds_test.go index 57430bb8c..94caaa108 100644 --- a/internal/cloud/openstack/imds_test.go +++ b/internal/cloud/openstack/imds_test.go @@ -43,30 +43,30 @@ func TestProviderID(t *testing.T) { wantCall: false, }, "from http": { - newClient: newStubHTTPClientJSONFunc(mResp1, nil), + newClient: newStubHTTPClientJSONFunc(mResp1, 200, nil), wantResult: expect1, wantCall: true, }, "cache outdated": { cache: mResp1, cacheTime: time.Now().AddDate(0, 0, -1), - newClient: newStubHTTPClientJSONFunc(mResp2, nil), + newClient: newStubHTTPClientJSONFunc(mResp2, 200, nil), wantResult: expect2, wantCall: true, }, "cache empty": { cacheTime: time.Now(), - newClient: newStubHTTPClientJSONFunc(mResp1, nil), + newClient: newStubHTTPClientJSONFunc(mResp1, 200, nil), wantResult: expect1, wantCall: true, }, "http error": { - newClient: newStubHTTPClientJSONFunc(metadataResponse{}, someErr), + newClient: newStubHTTPClientJSONFunc(metadataResponse{}, 200, someErr), wantCall: true, wantErr: true, }, "http empty response": { - newClient: newStubHTTPClientJSONFunc(metadataResponse{}, nil), + newClient: newStubHTTPClientJSONFunc(metadataResponse{}, 200, nil), wantCall: true, wantErr: true, }, @@ -207,30 +207,35 @@ func TestRole(t *testing.T) { wantCall: false, }, "from http": { - newClient: newStubHTTPClientJSONFunc(mResp1, nil), + newClient: newStubHTTPClientJSONFunc(mResp1, 200, nil), wantResult: expect1, wantCall: true, }, "cache outdated": { cache: mResp1, cacheTime: time.Now().AddDate(0, 0, -1), - newClient: newStubHTTPClientJSONFunc(mResp2, nil), + newClient: newStubHTTPClientJSONFunc(mResp2, 200, nil), wantResult: expect2, wantCall: true, }, "cache empty": { cacheTime: time.Now(), - newClient: newStubHTTPClientJSONFunc(mResp1, nil), + newClient: newStubHTTPClientJSONFunc(mResp1, 200, nil), wantResult: expect1, wantCall: true, }, "http error": { - newClient: newStubHTTPClientJSONFunc(metadataResponse{}, someErr), + newClient: newStubHTTPClientJSONFunc(metadataResponse{}, 200, someErr), + wantCall: true, + wantErr: true, + }, + "http status code 500": { + newClient: newStubHTTPClientJSONFunc(metadataResponse{}, 500, nil), wantCall: true, wantErr: true, }, "http empty response": { - newClient: newStubHTTPClientJSONFunc(metadataResponse{}, nil), + newClient: newStubHTTPClientJSONFunc(metadataResponse{}, 200, nil), wantCall: true, wantErr: true, }, @@ -369,14 +374,16 @@ type httpClientJSONCreateFunc func(r *require.Assertions) *stubHTTPClientJSON type stubHTTPClientJSON struct { require *require.Assertions response metadataResponse + code int err error called bool } -func newStubHTTPClientJSONFunc(response metadataResponse, err error) httpClientJSONCreateFunc { +func newStubHTTPClientJSONFunc(response metadataResponse, statusCode int, err error) httpClientJSONCreateFunc { return func(r *require.Assertions) *stubHTTPClientJSON { return &stubHTTPClientJSON{ response: response, + code: statusCode, err: err, require: r, } @@ -387,16 +394,26 @@ func (c *stubHTTPClientJSON) Do(_ *http.Request) (*http.Response, error) { c.called = true body, err := json.Marshal(c.response) c.require.NoError(err) - return &http.Response{Body: io.NopCloser(bytes.NewReader(body))}, c.err + code := 200 + if c.code != 0 { + code = c.code + } + return &http.Response{StatusCode: code, Status: http.StatusText(code), Body: io.NopCloser(bytes.NewReader(body))}, c.err } type stubHTTPClient struct { response string + code int err error called bool } func (c *stubHTTPClient) Do(_ *http.Request) (*http.Response, error) { c.called = true - return &http.Response{Body: io.NopCloser(strings.NewReader(c.response))}, c.err + code := 200 + if c.code != 0 { + code = c.code + } + + return &http.Response{StatusCode: code, Status: http.StatusText(code), Body: io.NopCloser(strings.NewReader(c.response))}, c.err }