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