Updates the differ service to support calling and configuring multiple differs. The differs are configured as an ordered list of differs which will each be attempting until a supported differ is called. Additionally a not supported error type was added to allow differs to be selective of whether the differ arguments are supported by the differ. This error type corresponds to the GRPC unimplemented error. Signed-off-by: Derek McGowan <derek@mcgstyle.net>
111 lines
2.6 KiB
Go
111 lines
2.6 KiB
Go
package errdefs
|
|
|
|
import (
|
|
"strings"
|
|
|
|
"github.com/pkg/errors"
|
|
"google.golang.org/grpc"
|
|
"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 grpc.Errorf(codes.InvalidArgument, err.Error())
|
|
case IsNotFound(err):
|
|
return grpc.Errorf(codes.NotFound, err.Error())
|
|
case IsAlreadyExists(err):
|
|
return grpc.Errorf(codes.AlreadyExists, err.Error())
|
|
case IsFailedPrecondition(err):
|
|
return grpc.Errorf(codes.FailedPrecondition, err.Error())
|
|
case IsUnavailable(err):
|
|
return grpc.Errorf(codes.Unavailable, err.Error())
|
|
case IsNotSupported(err):
|
|
return grpc.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...))
|
|
}
|
|
|
|
func FromGRPC(err error) error {
|
|
if err == nil {
|
|
return nil
|
|
}
|
|
|
|
var cls error // divide these into error classes, becomes the cause
|
|
|
|
switch grpc.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 = ErrNotSupported
|
|
default:
|
|
cls = ErrUnknown
|
|
}
|
|
|
|
if cls != nil {
|
|
msg := rebaseMessage(cls, err)
|
|
if msg != "" {
|
|
err = errors.Wrapf(cls, msg)
|
|
} else {
|
|
err = 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 := grpc.ErrorDesc(err)
|
|
clss := cls.Error()
|
|
if desc == clss {
|
|
return ""
|
|
}
|
|
|
|
return strings.TrimSuffix(desc, ": "+clss)
|
|
}
|
|
|
|
func isGRPCError(err error) bool {
|
|
_, ok := status.FromError(err)
|
|
return ok
|
|
}
|