@@ -25,6 +25,7 @@ import (
25
25
"strings"
26
26
27
27
"github.com/GoogleCloudPlatform/k8s-cloud-provider/pkg/cloud/meta"
28
+ "github.com/googleapis/gax-go/v2/apierror"
28
29
"google.golang.org/api/googleapi"
29
30
"google.golang.org/grpc/codes"
30
31
"google.golang.org/grpc/status"
@@ -336,7 +337,6 @@ func CodeForError(sourceError error) codes.Code {
336
337
if sourceError == nil {
337
338
return codes .Internal
338
339
}
339
-
340
340
if code , err := isUserMultiAttachError (sourceError ); err == nil {
341
341
return code
342
342
}
@@ -349,12 +349,7 @@ func CodeForError(sourceError error) codes.Code {
349
349
if code , err := isConnectionResetError (sourceError ); err == nil {
350
350
return code
351
351
}
352
-
353
- var apiErr * googleapi.Error
354
- if ! errors .As (sourceError , & apiErr ) {
355
- return codes .Internal
356
- }
357
- if code , ok := userErrorCodeMap [apiErr .Code ]; ok {
352
+ if code , err := isGoogleAPIError (sourceError ); err == nil {
358
353
return code
359
354
}
360
355
@@ -405,16 +400,64 @@ func isUserMultiAttachError(err error) (codes.Code, error) {
405
400
return codes .Unknown , fmt .Errorf ("Not a user multiattach error: %w" , err )
406
401
}
407
402
403
+ // existingErrorCode returns the existing gRPC Status error code for the given error, if one exists,
404
+ // or an error if one doesn't exist. Since github.com/googleapis/gax-go/v2/apierror now wraps googleapi
405
+ // errors (returned from GCE API calls), and sets their status error code to Unknown, we now have to
406
+ // make sure we only return existing error codes from errors that are either TemporaryErrors, or errors
407
+ // that do not wrap googleAPI errors. Otherwise, we will return Unknown for all GCE API calls that
408
+ // return googleapi errors.
408
409
func existingErrorCode (err error ) (codes.Code , error ) {
409
410
if err == nil {
410
411
return codes .Unknown , fmt .Errorf ("null error" )
411
412
}
412
- if status , ok := status .FromError (err ); ok {
413
- return status .Code (), nil
413
+ var tmpError * TemporaryError
414
+ // This explicitly checks our error is a temporary error before extracting its
415
+ // status, as there can be other errors that can qualify as statusable
416
+ // while not necessarily being temporary.
417
+ if errors .As (err , & tmpError ) {
418
+ if status , ok := status .FromError (err ); ok {
419
+ return status .Code (), nil
420
+ }
421
+ }
422
+ // We want to make sure we catch other error types that are statusable.
423
+ // (eg. grpc-go/internal/status/status.go Error struct that wraps a status)
424
+ var googleErr * googleapi.Error
425
+ if ! errors .As (err , & googleErr ) {
426
+ if status , ok := status .FromError (err ); ok {
427
+ return status .Code (), nil
428
+ }
414
429
}
430
+
415
431
return codes .Unknown , fmt .Errorf ("no existing error code for %w" , err )
416
432
}
417
433
434
+ // isGoogleAPIError returns the gRPC status code for the given googleapi error by mapping
435
+ // the googleapi error's HTTP code to the corresponding gRPC error code. If the error is
436
+ // wrapped in an APIError (github.com/googleapis/gax-go/v2/apierror), it maps the wrapped
437
+ // googleAPI error's HTTP code to the corresponding gRPC error code. Returns an error if
438
+ // the given error is not a googleapi error.
439
+ func isGoogleAPIError (err error ) (codes.Code , error ) {
440
+ var googleErr * googleapi.Error
441
+ if ! errors .As (err , & googleErr ) {
442
+ return codes .Unknown , fmt .Errorf ("error %w is not a googleapi.Error" , err )
443
+ }
444
+ var sourceCode int
445
+ var apiErr * apierror.APIError
446
+ if errors .As (err , & apiErr ) {
447
+ // When googleapi.Err is used as a wrapper, we return the error code of the wrapped contents.
448
+ sourceCode = apiErr .HTTPCode ()
449
+ } else {
450
+ // Rely on error code in googleapi.Err when it is our primary error.
451
+ sourceCode = googleErr .Code
452
+ }
453
+ // Map API error code to user error code.
454
+ if code , ok := userErrorCodeMap [sourceCode ]; ok {
455
+ return code , nil
456
+ }
457
+
458
+ return codes .Unknown , fmt .Errorf ("googleapi.Error %w does not map to any known errors" , err )
459
+ }
460
+
418
461
func LoggedError (msg string , err error ) error {
419
462
klog .Errorf (msg + "%v" , err .Error ())
420
463
return status .Errorf (CodeForError (err ), msg + "%v" , err .Error ())
0 commit comments