123 lines
		
	
	
		
			2.9 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			123 lines
		
	
	
		
			2.9 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package errdefs
 | |
| 
 | |
| import (
 | |
| 	"strings"
 | |
| 
 | |
| 	"github.com/pkg/errors"
 | |
| 	"google.golang.org/grpc/codes"
 | |
| 	"google.golang.org/grpc/status"
 | |
| )
 | |
| 
 | |
| // ToGRPC will attempt to map the backend containerd error into a grpc error,
 | |
| // using the original error message as a description.
 | |
| //
 | |
| // Further information may be extracted from certain errors depending on their
 | |
| // type.
 | |
| //
 | |
| // If the error is unmapped, the original error will be returned to be handled
 | |
| // by the regular grpc error handling stack.
 | |
| func ToGRPC(err error) error {
 | |
| 	if err == nil {
 | |
| 		return nil
 | |
| 	}
 | |
| 
 | |
| 	if isGRPCError(err) {
 | |
| 		// error has already been mapped to grpc
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	switch {
 | |
| 	case IsInvalidArgument(err):
 | |
| 		return status.Errorf(codes.InvalidArgument, err.Error())
 | |
| 	case IsNotFound(err):
 | |
| 		return status.Errorf(codes.NotFound, err.Error())
 | |
| 	case IsAlreadyExists(err):
 | |
| 		return status.Errorf(codes.AlreadyExists, err.Error())
 | |
| 	case IsFailedPrecondition(err):
 | |
| 		return status.Errorf(codes.FailedPrecondition, err.Error())
 | |
| 	case IsUnavailable(err):
 | |
| 		return status.Errorf(codes.Unavailable, err.Error())
 | |
| 	case IsNotImplemented(err):
 | |
| 		return status.Errorf(codes.Unimplemented, err.Error())
 | |
| 	}
 | |
| 
 | |
| 	return err
 | |
| }
 | |
| 
 | |
| // ToGRPCf maps the error to grpc error codes, assembling the formatting string
 | |
| // and combining it with the target error string.
 | |
| //
 | |
| // This is equivalent to errors.ToGRPC(errors.Wrapf(err, format, args...))
 | |
| func ToGRPCf(err error, format string, args ...interface{}) error {
 | |
| 	return ToGRPC(errors.Wrapf(err, format, args...))
 | |
| }
 | |
| 
 | |
| // FromGRPC returns the underlying error from a grpc service based on the grpc error code
 | |
| func FromGRPC(err error) error {
 | |
| 	if err == nil {
 | |
| 		return nil
 | |
| 	}
 | |
| 
 | |
| 	var cls error // divide these into error classes, becomes the cause
 | |
| 
 | |
| 	switch code(err) {
 | |
| 	case codes.InvalidArgument:
 | |
| 		cls = ErrInvalidArgument
 | |
| 	case codes.AlreadyExists:
 | |
| 		cls = ErrAlreadyExists
 | |
| 	case codes.NotFound:
 | |
| 		cls = ErrNotFound
 | |
| 	case codes.Unavailable:
 | |
| 		cls = ErrUnavailable
 | |
| 	case codes.FailedPrecondition:
 | |
| 		cls = ErrFailedPrecondition
 | |
| 	case codes.Unimplemented:
 | |
| 		cls = ErrNotImplemented
 | |
| 	default:
 | |
| 		cls = ErrUnknown
 | |
| 	}
 | |
| 
 | |
| 	msg := rebaseMessage(cls, err)
 | |
| 	if msg != "" {
 | |
| 		err = errors.Wrapf(cls, msg)
 | |
| 	} else {
 | |
| 		err = errors.WithStack(cls)
 | |
| 	}
 | |
| 
 | |
| 	return err
 | |
| }
 | |
| 
 | |
| // rebaseMessage removes the repeats for an error at the end of an error
 | |
| // string. This will happen when taking an error over grpc then remapping it.
 | |
| //
 | |
| // Effectively, we just remove the string of cls from the end of err if it
 | |
| // appears there.
 | |
| func rebaseMessage(cls error, err error) string {
 | |
| 	desc := errDesc(err)
 | |
| 	clss := cls.Error()
 | |
| 	if desc == clss {
 | |
| 		return ""
 | |
| 	}
 | |
| 
 | |
| 	return strings.TrimSuffix(desc, ": "+clss)
 | |
| }
 | |
| 
 | |
| func isGRPCError(err error) bool {
 | |
| 	_, ok := status.FromError(err)
 | |
| 	return ok
 | |
| }
 | |
| 
 | |
| func code(err error) codes.Code {
 | |
| 	if s, ok := status.FromError(err); ok {
 | |
| 		return s.Code()
 | |
| 	}
 | |
| 	return codes.Unknown
 | |
| }
 | |
| 
 | |
| func errDesc(err error) string {
 | |
| 	if s, ok := status.FromError(err); ok {
 | |
| 		return s.Message()
 | |
| 	}
 | |
| 	return err.Error()
 | |
| }
 | 
