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  }