Skip to content

Commit e9f75ce

Browse files
authored
Merge pull request #1232 from amacaskill/code-for-error
Use errors.As so we can detect wrapped errors, and check for existing error codes in CodesForError
2 parents 6f45863 + 0295029 commit e9f75ce

File tree

5 files changed

+125
-7
lines changed

5 files changed

+125
-7
lines changed

pkg/gce-cloud-provider/compute/gce.go

+3-2
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ package gcecloudprovider
1616

1717
import (
1818
"context"
19+
"errors"
1920
"fmt"
2021
"net/http"
2122
"os"
@@ -248,8 +249,8 @@ func getProjectAndZone(config *ConfigFile) (string, string, error) {
248249
// isGCEError returns true if given error is a googleapi.Error with given
249250
// reason (e.g. "resourceInUseByAnotherResource")
250251
func IsGCEError(err error, reason string) bool {
251-
apiErr, ok := err.(*googleapi.Error)
252-
if !ok {
252+
var apiErr *googleapi.Error
253+
if !errors.As(err, &apiErr) {
253254
return false
254255
}
255256

+86
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
/*
2+
Copyright 2023 The Kubernetes Authors.
3+
4+
5+
Licensed under the Apache License, Version 2.0 (the "License");
6+
you may not use this file except in compliance with the License.
7+
You may obtain a copy of the License at
8+
9+
http://www.apache.org/licenses/LICENSE-2.0
10+
11+
Unless required by applicable law or agreed to in writing, software
12+
distributed under the License is distributed on an "AS IS" BASIS,
13+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
See the License for the specific language governing permissions and
15+
limitations under the License.
16+
*/
17+
18+
package gcecloudprovider
19+
20+
import (
21+
"errors"
22+
"fmt"
23+
"net/http"
24+
"testing"
25+
26+
"google.golang.org/api/googleapi"
27+
)
28+
29+
func TestIsGCEError(t *testing.T) {
30+
testCases := []struct {
31+
name string
32+
inputErr error
33+
reason string
34+
expIsGCEError bool
35+
}{
36+
{
37+
name: "Not googleapi.Error",
38+
inputErr: errors.New("I am not a googleapi.Error"),
39+
reason: "notFound",
40+
expIsGCEError: false,
41+
},
42+
{
43+
name: "googleapi.Error not found error",
44+
inputErr: &googleapi.Error{
45+
Code: http.StatusNotFound,
46+
Errors: []googleapi.ErrorItem{
47+
{
48+
Reason: "notFound",
49+
},
50+
},
51+
Message: "Not found",
52+
},
53+
reason: "notFound",
54+
expIsGCEError: true,
55+
},
56+
{
57+
name: "wrapped googleapi.Error",
58+
inputErr: fmt.Errorf("encountered not found: %w", &googleapi.Error{
59+
Code: http.StatusNotFound,
60+
Errors: []googleapi.ErrorItem{
61+
{
62+
Reason: "notFound",
63+
},
64+
},
65+
Message: "Not found",
66+
},
67+
),
68+
reason: "notFound",
69+
expIsGCEError: true,
70+
},
71+
{
72+
name: "nil error",
73+
inputErr: nil,
74+
reason: "notFound",
75+
expIsGCEError: false,
76+
},
77+
}
78+
79+
for _, tc := range testCases {
80+
t.Logf("Running test: %v", tc.name)
81+
isGCEError := IsGCEError(tc.inputErr, tc.reason)
82+
if tc.expIsGCEError != isGCEError {
83+
t.Fatalf("Got isGCEError '%t', expected '%t'", isGCEError, tc.expIsGCEError)
84+
}
85+
}
86+
}

pkg/gce-pd-csi-driver/utils.go

+17
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,13 @@ func containsZone(zones []string, zone string) bool {
231231
// (1) "context deadline exceeded", returns grpc DeadlineExceeded,
232232
// (2) "context canceled", returns grpc Canceled
233233
func CodeForError(err error) *codes.Code {
234+
if err == nil {
235+
return nil
236+
}
237+
238+
if errCode := existingErrorCode(err); errCode != nil {
239+
return errCode
240+
}
234241
if code := isContextError(err); code != nil {
235242
return code
236243
}
@@ -255,6 +262,16 @@ func CodeForError(err error) *codes.Code {
255262
return &internalErrorCode
256263
}
257264

265+
func existingErrorCode(err error) *codes.Code {
266+
if err == nil {
267+
return nil
268+
}
269+
if status, ok := status.FromError(err); ok {
270+
return errCodePtr(status.Code())
271+
}
272+
return nil
273+
}
274+
258275
// isContextError returns a pointer to the grpc error code DeadlineExceeded
259276
// if the passed in error contains the "context deadline exceeded" string and returns
260277
// the grpc error code Canceled if the error contains the "context canceled" string.

pkg/gce-pd-csi-driver/utils_test.go

+17-3
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import (
2727
csi "github.com/container-storage-interface/spec/lib/go/csi"
2828
"google.golang.org/api/googleapi"
2929
"google.golang.org/grpc/codes"
30+
"google.golang.org/grpc/status"
3031
)
3132

3233
var (
@@ -331,13 +332,26 @@ func TestCodeForError(t *testing.T) {
331332
inputErr: context.DeadlineExceeded,
332333
expCode: errCodePtr(codes.DeadlineExceeded),
333334
},
335+
{
336+
name: "status error with Aborted error code",
337+
inputErr: status.Error(codes.Aborted, "aborted error"),
338+
expCode: errCodePtr(codes.Aborted),
339+
},
340+
{
341+
name: "nil error",
342+
inputErr: nil,
343+
expCode: nil,
344+
},
334345
}
335346

336347
for _, tc := range testCases {
337348
t.Logf("Running test: %v", tc.name)
338-
actualCode := *CodeForError(tc.inputErr)
339-
if *tc.expCode != actualCode {
340-
t.Fatalf("Expected error code '%v' but got '%v'", tc.expCode, actualCode)
349+
errCode := CodeForError(tc.inputErr)
350+
if (tc.expCode == nil) != (errCode == nil) {
351+
t.Errorf("test %v failed: got %v, expected %v", tc.name, errCode, tc.expCode)
352+
}
353+
if tc.expCode != nil && *errCode != *tc.expCode {
354+
t.Errorf("test %v failed: got %v, expected %v", tc.name, errCode, tc.expCode)
341355
}
342356
}
343357
}

test/remote/instance.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -415,8 +415,8 @@ func generateMetadataWithPublicKey(pubKeyFile string) (*compute.Metadata, error)
415415
// isGCEError returns true if given error is a googleapi.Error with given
416416
// reason (e.g. "resourceInUseByAnotherResource")
417417
func isGCEError(err error, reason string) bool {
418-
apiErr, ok := err.(*googleapi.Error)
419-
if !ok {
418+
var apiErr *googleapi.Error
419+
if !errors.As(err, &apiErr) {
420420
return false
421421
}
422422

0 commit comments

Comments
 (0)