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