@@ -26,6 +26,7 @@ import (
26
26
"time"
27
27
28
28
"github.com/GoogleCloudPlatform/k8s-cloud-provider/pkg/cloud/meta"
29
+ "github.com/googleapis/gax-go/v2/apierror"
29
30
"golang.org/x/time/rate"
30
31
"google.golang.org/api/googleapi"
31
32
"google.golang.org/grpc/codes"
@@ -423,7 +424,6 @@ func CodeForError(sourceError error) codes.Code {
423
424
if sourceError == nil {
424
425
return codes .Internal
425
426
}
426
-
427
427
if code , err := isUserMultiAttachError (sourceError ); err == nil {
428
428
return code
429
429
}
@@ -436,12 +436,7 @@ func CodeForError(sourceError error) codes.Code {
436
436
if code , err := isConnectionResetError (sourceError ); err == nil {
437
437
return code
438
438
}
439
-
440
- var apiErr * googleapi.Error
441
- if ! errors .As (sourceError , & apiErr ) {
442
- return codes .Internal
443
- }
444
- if code , ok := userErrorCodeMap [apiErr .Code ]; ok {
439
+ if code , err := isGoogleAPIError (sourceError ); err == nil {
445
440
return code
446
441
}
447
442
@@ -492,16 +487,64 @@ func isUserMultiAttachError(err error) (codes.Code, error) {
492
487
return codes .Unknown , fmt .Errorf ("Not a user multiattach error: %w" , err )
493
488
}
494
489
490
+ // existingErrorCode returns the existing gRPC Status error code for the given error, if one exists,
491
+ // or an error if one doesn't exist. Since github.com/googleapis/gax-go/v2/apierror now wraps googleapi
492
+ // errors (returned from GCE API calls), and sets their status error code to Unknown, we now have to
493
+ // make sure we only return existing error codes from errors that are either TemporaryErrors, or errors
494
+ // that do not wrap googleAPI errors. Otherwise, we will return Unknown for all GCE API calls that
495
+ // return googleapi errors.
495
496
func existingErrorCode (err error ) (codes.Code , error ) {
496
497
if err == nil {
497
498
return codes .Unknown , fmt .Errorf ("null error" )
498
499
}
499
- if status , ok := status .FromError (err ); ok {
500
- return status .Code (), nil
500
+ var tmpError * TemporaryError
501
+ // This explicitly checks our error is a temporary error before extracting its
502
+ // status, as there can be other errors that can qualify as statusable
503
+ // while not necessarily being temporary.
504
+ if errors .As (err , & tmpError ) {
505
+ if status , ok := status .FromError (err ); ok {
506
+ return status .Code (), nil
507
+ }
508
+ }
509
+ // We want to make sure we catch other error types that are statusable.
510
+ // (eg. grpc-go/internal/status/status.go Error struct that wraps a status)
511
+ var googleErr * googleapi.Error
512
+ if ! errors .As (err , & googleErr ) {
513
+ if status , ok := status .FromError (err ); ok {
514
+ return status .Code (), nil
515
+ }
501
516
}
517
+
502
518
return codes .Unknown , fmt .Errorf ("no existing error code for %w" , err )
503
519
}
504
520
521
+ // isGoogleAPIError returns the gRPC status code for the given googleapi error by mapping
522
+ // the googleapi error's HTTP code to the corresponding gRPC error code. If the error is
523
+ // wrapped in an APIError (github.com/googleapis/gax-go/v2/apierror), it maps the wrapped
524
+ // googleAPI error's HTTP code to the corresponding gRPC error code. Returns an error if
525
+ // the given error is not a googleapi error.
526
+ func isGoogleAPIError (err error ) (codes.Code , error ) {
527
+ var googleErr * googleapi.Error
528
+ if ! errors .As (err , & googleErr ) {
529
+ return codes .Unknown , fmt .Errorf ("error %w is not a googleapi.Error" , err )
530
+ }
531
+ var sourceCode int
532
+ var apiErr * apierror.APIError
533
+ if errors .As (err , & apiErr ) {
534
+ // When googleapi.Err is used as a wrapper, we return the error code of the wrapped contents.
535
+ sourceCode = apiErr .HTTPCode ()
536
+ } else {
537
+ // Rely on error code in googleapi.Err when it is our primary error.
538
+ sourceCode = googleErr .Code
539
+ }
540
+ // Map API error code to user error code.
541
+ if code , ok := userErrorCodeMap [sourceCode ]; ok {
542
+ return code , nil
543
+ }
544
+
545
+ return codes .Unknown , fmt .Errorf ("googleapi.Error %w does not map to any known errors" , err )
546
+ }
547
+
505
548
func LoggedError (msg string , err error ) error {
506
549
klog .Errorf (msg + "%v" , err .Error ())
507
550
return status .Errorf (CodeForError (err ), msg + "%v" , err .Error ())
0 commit comments