@@ -25,6 +25,7 @@ import (
2525 "strings"
2626
2727 "github.com/GoogleCloudPlatform/k8s-cloud-provider/pkg/cloud/meta"
28+ "github.com/googleapis/gax-go/v2/apierror"
2829 "google.golang.org/api/googleapi"
2930 "google.golang.org/grpc/codes"
3031 "google.golang.org/grpc/status"
@@ -334,7 +335,6 @@ func CodeForError(sourceError error) codes.Code {
334335 if sourceError == nil {
335336 return codes .Internal
336337 }
337-
338338 if code , err := isUserMultiAttachError (sourceError ); err == nil {
339339 return code
340340 }
@@ -347,12 +347,7 @@ func CodeForError(sourceError error) codes.Code {
347347 if code , err := isConnectionResetError (sourceError ); err == nil {
348348 return code
349349 }
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 {
356351 return code
357352 }
358353
@@ -403,16 +398,64 @@ func isUserMultiAttachError(err error) (codes.Code, error) {
403398 return codes .Unknown , fmt .Errorf ("Not a user multiattach error: %w" , err )
404399}
405400
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.
406407func existingErrorCode (err error ) (codes.Code , error ) {
407408 if err == nil {
408409 return codes .Unknown , fmt .Errorf ("null error" )
409410 }
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+ }
412427 }
428+
413429 return codes .Unknown , fmt .Errorf ("no existing error code for %w" , err )
414430}
415431
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+
416459func LoggedError (msg string , err error ) error {
417460 klog .Errorf (msg + "%v" , err .Error ())
418461 return status .Errorf (CodeForError (err ), msg + "%v" , err .Error ())
0 commit comments