diff --git a/pkg/common/utils.go b/pkg/common/utils.go index 5f35abfa4..b004f9d6c 100644 --- a/pkg/common/utils.go +++ b/pkg/common/utils.go @@ -337,6 +337,9 @@ func CodeForError(sourceError error) codes.Code { return codes.Internal } + if code, err := isUserMultiAttachError(sourceError); err == nil { + return code + } if code, err := existingErrorCode(sourceError); err == nil { return code } @@ -374,6 +377,17 @@ func isContextError(err error) (codes.Code, error) { return codes.Unknown, fmt.Errorf("Not a context error: %w", err) } +// isUserMultiAttachError returns an InvalidArgument if the error is +// multi-attach detected from the API server. If we get this error from the API +// server, it means that the kubelet doesn't know about the multiattch so it is +// due to user configuration. +func isUserMultiAttachError(err error) (codes.Code, error) { + if strings.Contains(err.Error(), "The disk resource") && strings.Contains(err.Error(), "is already being used") { + return codes.InvalidArgument, nil + } + return codes.Unknown, fmt.Errorf("Not a user multiattach error: %w", err) +} + func existingErrorCode(err error) (codes.Code, error) { if err == nil { return codes.Unknown, fmt.Errorf("null error") diff --git a/pkg/common/utils_test.go b/pkg/common/utils_test.go index 5d7d541df..de7d27ba3 100644 --- a/pkg/common/utils_test.go +++ b/pkg/common/utils_test.go @@ -1016,6 +1016,11 @@ func TestCodeForError(t *testing.T) { inputErr: nil, expCode: codes.Internal, }, + { + name: "user multiattach error", + inputErr: fmt.Errorf("The disk resource 'projects/foo/disk/bar' is already being used by 'projects/foo/instances/1'"), + expCode: codes.InvalidArgument, + }, } for _, tc := range testCases { @@ -1077,6 +1082,34 @@ func TestIsContextError(t *testing.T) { } } +func TestIsUserMultiAttachError(t *testing.T) { + cases := []struct { + errorString string + expectedCode codes.Code + expectCode bool + }{ + { + errorString: "The disk resource 'projects/foo/disk/bar' is already being used by 'projects/foo/instance/biz'", + expectedCode: codes.InvalidArgument, + expectCode: true, + }, + { + errorString: "The disk resource is ok!", + expectCode: false, + }, + } + for _, test := range cases { + code, err := isUserMultiAttachError(fmt.Errorf(test.errorString)) + if test.expectCode { + if err != nil || code != test.expectedCode { + t.Errorf("Failed with non-nil error %v or bad code %v: %s", err, code, test.errorString) + } + } else if err == nil { + t.Errorf("Expected error for test but got none: %s", test.errorString) + } + } +} + func TestIsValidDiskEncryptionKmsKey(t *testing.T) { cases := []struct { diskEncryptionKmsKey string