github.com/lalkh/containerd@v1.4.3/errdefs/grpc.go (about) 1 /* 2 Copyright The containerd Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package errdefs 18 19 import ( 20 "context" 21 "strings" 22 23 "github.com/pkg/errors" 24 "google.golang.org/grpc/codes" 25 "google.golang.org/grpc/status" 26 ) 27 28 // ToGRPC will attempt to map the backend containerd error into a grpc error, 29 // using the original error message as a description. 30 // 31 // Further information may be extracted from certain errors depending on their 32 // type. 33 // 34 // If the error is unmapped, the original error will be returned to be handled 35 // by the regular grpc error handling stack. 36 func ToGRPC(err error) error { 37 if err == nil { 38 return nil 39 } 40 41 if isGRPCError(err) { 42 // error has already been mapped to grpc 43 return err 44 } 45 46 switch { 47 case IsInvalidArgument(err): 48 return status.Errorf(codes.InvalidArgument, err.Error()) 49 case IsNotFound(err): 50 return status.Errorf(codes.NotFound, err.Error()) 51 case IsAlreadyExists(err): 52 return status.Errorf(codes.AlreadyExists, err.Error()) 53 case IsFailedPrecondition(err): 54 return status.Errorf(codes.FailedPrecondition, err.Error()) 55 case IsUnavailable(err): 56 return status.Errorf(codes.Unavailable, err.Error()) 57 case IsNotImplemented(err): 58 return status.Errorf(codes.Unimplemented, err.Error()) 59 case IsCanceled(err): 60 return status.Errorf(codes.Canceled, err.Error()) 61 case IsDeadlineExceeded(err): 62 return status.Errorf(codes.DeadlineExceeded, err.Error()) 63 } 64 65 return err 66 } 67 68 // ToGRPCf maps the error to grpc error codes, assembling the formatting string 69 // and combining it with the target error string. 70 // 71 // This is equivalent to errors.ToGRPC(errors.Wrapf(err, format, args...)) 72 func ToGRPCf(err error, format string, args ...interface{}) error { 73 return ToGRPC(errors.Wrapf(err, format, args...)) 74 } 75 76 // FromGRPC returns the underlying error from a grpc service based on the grpc error code 77 func FromGRPC(err error) error { 78 if err == nil { 79 return nil 80 } 81 82 var cls error // divide these into error classes, becomes the cause 83 84 switch code(err) { 85 case codes.InvalidArgument: 86 cls = ErrInvalidArgument 87 case codes.AlreadyExists: 88 cls = ErrAlreadyExists 89 case codes.NotFound: 90 cls = ErrNotFound 91 case codes.Unavailable: 92 cls = ErrUnavailable 93 case codes.FailedPrecondition: 94 cls = ErrFailedPrecondition 95 case codes.Unimplemented: 96 cls = ErrNotImplemented 97 case codes.Canceled: 98 cls = context.Canceled 99 case codes.DeadlineExceeded: 100 cls = context.DeadlineExceeded 101 default: 102 cls = ErrUnknown 103 } 104 105 msg := rebaseMessage(cls, err) 106 if msg != "" { 107 err = errors.Wrap(cls, msg) 108 } else { 109 err = errors.WithStack(cls) 110 } 111 112 return err 113 } 114 115 // rebaseMessage removes the repeats for an error at the end of an error 116 // string. This will happen when taking an error over grpc then remapping it. 117 // 118 // Effectively, we just remove the string of cls from the end of err if it 119 // appears there. 120 func rebaseMessage(cls error, err error) string { 121 desc := errDesc(err) 122 clss := cls.Error() 123 if desc == clss { 124 return "" 125 } 126 127 return strings.TrimSuffix(desc, ": "+clss) 128 } 129 130 func isGRPCError(err error) bool { 131 _, ok := status.FromError(err) 132 return ok 133 } 134 135 func code(err error) codes.Code { 136 if s, ok := status.FromError(err); ok { 137 return s.Code() 138 } 139 return codes.Unknown 140 } 141 142 func errDesc(err error) string { 143 if s, ok := status.FromError(err); ok { 144 return s.Message() 145 } 146 return err.Error() 147 }