Merge pull request #1115 from stevvooe/consolidate-errors
errdefs: centralize error handling
This commit is contained in:
commit
eedcbc64cc
@ -8,8 +8,8 @@ import (
|
||||
"strings"
|
||||
"text/tabwriter"
|
||||
|
||||
"github.com/containerd/containerd/errdefs"
|
||||
"github.com/containerd/containerd/log"
|
||||
"github.com/containerd/containerd/metadata"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
@ -183,7 +183,7 @@ var namespacesRemoveCommand = cli.Command{
|
||||
|
||||
for _, target := range clicontext.Args() {
|
||||
if err := namespaces.Delete(ctx, target); err != nil {
|
||||
if !metadata.IsNotFound(err) {
|
||||
if !errdefs.IsNotFound(err) {
|
||||
if exitErr == nil {
|
||||
exitErr = errors.Wrapf(err, "unable to delete %v", target)
|
||||
}
|
||||
|
4
cmd/dist/delete.go
vendored
4
cmd/dist/delete.go
vendored
@ -3,7 +3,7 @@ package main
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/containerd/containerd/content"
|
||||
"github.com/containerd/containerd/errdefs"
|
||||
"github.com/containerd/containerd/log"
|
||||
digest "github.com/opencontainers/go-digest"
|
||||
"github.com/urfave/cli"
|
||||
@ -43,7 +43,7 @@ var deleteCommand = cli.Command{
|
||||
}
|
||||
|
||||
if err := cs.Delete(ctx, dgst); err != nil {
|
||||
if !content.IsNotFound(err) {
|
||||
if !errdefs.IsNotFound(err) {
|
||||
if exitError == nil {
|
||||
exitError = err
|
||||
}
|
||||
|
3
cmd/dist/fetch.go
vendored
3
cmd/dist/fetch.go
vendored
@ -11,6 +11,7 @@ import (
|
||||
|
||||
"github.com/containerd/containerd"
|
||||
"github.com/containerd/containerd/content"
|
||||
"github.com/containerd/containerd/errdefs"
|
||||
"github.com/containerd/containerd/images"
|
||||
"github.com/containerd/containerd/log"
|
||||
"github.com/containerd/containerd/progress"
|
||||
@ -153,7 +154,7 @@ outer:
|
||||
if !done && (!ok || status.Status == "downloading") {
|
||||
info, err := cs.Info(ctx, j.Digest)
|
||||
if err != nil {
|
||||
if !content.IsNotFound(err) {
|
||||
if !errdefs.IsNotFound(err) {
|
||||
log.G(ctx).WithError(err).Errorf("failed to get content info")
|
||||
continue outer
|
||||
} else {
|
||||
|
4
cmd/dist/images.go
vendored
4
cmd/dist/images.go
vendored
@ -5,8 +5,8 @@ import (
|
||||
"os"
|
||||
"text/tabwriter"
|
||||
|
||||
"github.com/containerd/containerd/errdefs"
|
||||
"github.com/containerd/containerd/log"
|
||||
"github.com/containerd/containerd/metadata"
|
||||
"github.com/containerd/containerd/progress"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/urfave/cli"
|
||||
@ -83,7 +83,7 @@ var imageRemoveCommand = cli.Command{
|
||||
|
||||
for _, target := range clicontext.Args() {
|
||||
if err := imageStore.Delete(ctx, target); err != nil {
|
||||
if !metadata.IsNotFound(err) {
|
||||
if !errdefs.IsNotFound(err) {
|
||||
if exitErr == nil {
|
||||
exitErr = errors.Wrapf(err, "unable to delete %v", target)
|
||||
}
|
||||
|
@ -12,8 +12,8 @@ import (
|
||||
"github.com/containerd/containerd/api/services/tasks/v1"
|
||||
"github.com/containerd/containerd/api/types"
|
||||
"github.com/containerd/containerd/content"
|
||||
"github.com/containerd/containerd/errdefs"
|
||||
"github.com/containerd/containerd/images"
|
||||
"github.com/containerd/containerd/snapshot"
|
||||
protobuf "github.com/gogo/protobuf/types"
|
||||
digest "github.com/opencontainers/go-digest"
|
||||
"github.com/opencontainers/image-spec/identity"
|
||||
@ -46,7 +46,7 @@ func WithCheckpoint(desc v1.Descriptor, rootfsID string) NewContainerOpts {
|
||||
return err
|
||||
}
|
||||
if _, err := client.SnapshotService().Prepare(ctx, rootfsID, identity.ChainID(diffIDs).String()); err != nil {
|
||||
if !snapshot.IsExist(err) {
|
||||
if !errdefs.IsAlreadyExists(err) {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
@ -1,98 +0,0 @@
|
||||
package content
|
||||
|
||||
import "github.com/pkg/errors"
|
||||
|
||||
type contentExistsErr struct {
|
||||
desc string
|
||||
}
|
||||
|
||||
type contentNotFoundErr struct {
|
||||
desc string
|
||||
}
|
||||
|
||||
type contentLockedErr struct {
|
||||
desc string
|
||||
}
|
||||
|
||||
// ErrExists is returned when something exists when it may not be expected.
|
||||
func ErrExists(msg string) error {
|
||||
if msg == "" {
|
||||
msg = "content: exists"
|
||||
}
|
||||
return errors.WithStack(contentExistsErr{
|
||||
desc: msg,
|
||||
})
|
||||
}
|
||||
|
||||
// ErrNotFound is returned when an item is not found.
|
||||
func ErrNotFound(msg string) error {
|
||||
if msg == "" {
|
||||
msg = "content: not found"
|
||||
}
|
||||
return errors.WithStack(contentNotFoundErr{
|
||||
desc: msg,
|
||||
})
|
||||
}
|
||||
|
||||
// ErrLocked is returned when content is actively being uploaded, this
|
||||
// indicates that another process is attempting to upload the same content.
|
||||
func ErrLocked(msg string) error {
|
||||
if msg == "" {
|
||||
msg = "content: locked"
|
||||
}
|
||||
return errors.WithStack(contentLockedErr{
|
||||
desc: msg,
|
||||
})
|
||||
}
|
||||
|
||||
func (c contentExistsErr) Error() string {
|
||||
return c.desc
|
||||
}
|
||||
func (c contentNotFoundErr) Error() string {
|
||||
return c.desc
|
||||
}
|
||||
func (c contentLockedErr) Error() string {
|
||||
return c.desc
|
||||
}
|
||||
|
||||
func (c contentExistsErr) Exists() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (c contentNotFoundErr) NotFound() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (c contentLockedErr) Locked() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// IsNotFound returns true if the error is due to a not found content item
|
||||
func IsNotFound(err error) bool {
|
||||
if err, ok := errors.Cause(err).(interface {
|
||||
NotFound() bool
|
||||
}); ok {
|
||||
return err.NotFound()
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// IsExists returns true if the error is due to an already existing content item
|
||||
func IsExists(err error) bool {
|
||||
if err, ok := errors.Cause(err).(interface {
|
||||
Exists() bool
|
||||
}); ok {
|
||||
return err.Exists()
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// IsLocked returns true if the error is due to a currently locked content item
|
||||
func IsLocked(err error) bool {
|
||||
if err, ok := errors.Cause(err).(interface {
|
||||
Locked() bool
|
||||
}); ok {
|
||||
return err.Locked()
|
||||
}
|
||||
return false
|
||||
}
|
@ -6,6 +6,7 @@ import (
|
||||
"io"
|
||||
"io/ioutil"
|
||||
|
||||
"github.com/containerd/containerd/errdefs"
|
||||
"github.com/opencontainers/go-digest"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
@ -33,7 +34,7 @@ func ReadBlob(ctx context.Context, provider Provider, dgst digest.Digest) ([]byt
|
||||
func WriteBlob(ctx context.Context, cs Ingester, ref string, r io.Reader, size int64, expected digest.Digest) error {
|
||||
cw, err := cs.Writer(ctx, ref, size, expected)
|
||||
if err != nil {
|
||||
if !IsExists(err) {
|
||||
if !errdefs.IsAlreadyExists(err) {
|
||||
return err
|
||||
}
|
||||
|
||||
@ -79,7 +80,7 @@ func Copy(cw Writer, r io.Reader, size int64, expected digest.Digest) error {
|
||||
}
|
||||
|
||||
if err := cw.Commit(size, expected); err != nil {
|
||||
if !IsExists(err) {
|
||||
if !errdefs.IsAlreadyExists(err) {
|
||||
return errors.Wrapf(err, "failed commit on ref %q", ws.Ref)
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,10 @@
|
||||
package content
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
|
||||
"github.com/containerd/containerd/errdefs"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// Handles locking references
|
||||
@ -19,7 +21,7 @@ func tryLock(ref string) error {
|
||||
defer locksMu.Unlock()
|
||||
|
||||
if _, ok := locks[ref]; ok {
|
||||
return ErrLocked(fmt.Sprintf("key %s is locked", ref))
|
||||
return errors.Wrapf(errdefs.ErrUnavailable, "ref %s locked", ref)
|
||||
}
|
||||
|
||||
locks[ref] = struct{}{}
|
||||
|
@ -11,6 +11,7 @@ import (
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/containerd/containerd/errdefs"
|
||||
"github.com/containerd/containerd/log"
|
||||
digest "github.com/opencontainers/go-digest"
|
||||
"github.com/pkg/errors"
|
||||
@ -40,7 +41,7 @@ func (s *store) Info(ctx context.Context, dgst digest.Digest) (Info, error) {
|
||||
fi, err := os.Stat(p)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
err = ErrNotFound("")
|
||||
err = errors.Wrapf(errdefs.ErrNotFound, "content %v", dgst)
|
||||
}
|
||||
|
||||
return Info{}, err
|
||||
@ -62,7 +63,7 @@ func (s *store) Reader(ctx context.Context, dgst digest.Digest) (io.ReadCloser,
|
||||
fp, err := os.Open(s.blobPath(dgst))
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
err = ErrNotFound("")
|
||||
err = errors.Wrapf(errdefs.ErrNotFound, "content %v", dgst)
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
@ -85,7 +86,7 @@ func (cs *store) Delete(ctx context.Context, dgst digest.Digest) error {
|
||||
return err
|
||||
}
|
||||
|
||||
return ErrNotFound("")
|
||||
return errors.Wrapf(errdefs.ErrNotFound, "content %v", dgst)
|
||||
}
|
||||
|
||||
return nil
|
||||
@ -232,7 +233,7 @@ func (s *store) Writer(ctx context.Context, ref string, total int64, expected di
|
||||
if expected != "" {
|
||||
p := s.blobPath(expected)
|
||||
if _, err := os.Stat(p); err == nil {
|
||||
return nil, ErrExists("")
|
||||
return nil, errors.Wrapf(errdefs.ErrAlreadyExists, "content %v", expected)
|
||||
}
|
||||
}
|
||||
|
||||
@ -329,7 +330,7 @@ func (s *store) Abort(ctx context.Context, ref string) error {
|
||||
root := s.ingestRoot(ref)
|
||||
if err := os.RemoveAll(root); err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
return ErrNotFound("")
|
||||
return errors.Wrapf(errdefs.ErrNotFound, "ingest ref %q", ref)
|
||||
}
|
||||
|
||||
return err
|
||||
|
@ -5,6 +5,7 @@ import (
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
"github.com/containerd/containerd/errdefs"
|
||||
"github.com/opencontainers/go-digest"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
@ -99,7 +100,7 @@ func (w *writer) Commit(size int64, expected digest.Digest) error {
|
||||
if err := os.Rename(ingest, target); err != nil {
|
||||
if os.IsExist(err) {
|
||||
// collision with the target file!
|
||||
return ErrExists("")
|
||||
return errors.Wrapf(errdefs.ErrAlreadyExists, "content %v", dgst)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
54
errdefs/errors.go
Normal file
54
errdefs/errors.go
Normal file
@ -0,0 +1,54 @@
|
||||
// Package errdefs defines the common errors used throughout containerd
|
||||
// packages.
|
||||
//
|
||||
// Use with errors.Wrap and error.Wrapf to add context to an error.
|
||||
//
|
||||
// To detect an error class, use the IsXXX functions to tell whether an error
|
||||
// is of a certain type.
|
||||
//
|
||||
// The functions ToGRPC and FromGRPC can be used to map server-side and
|
||||
// client-side errors to the correct types.
|
||||
package errdefs
|
||||
|
||||
import "github.com/pkg/errors"
|
||||
|
||||
// Definitions of common error types used throughout containerd. All containerd
|
||||
// errors returned by most packages will map into one of these errors classes.
|
||||
// Packages should return errors of these types when they want to instruct a
|
||||
// client to take a particular action.
|
||||
//
|
||||
// For the most part, we just try to provide local grpc errors. Most conditions
|
||||
// map very well to those defined by grpc.
|
||||
var (
|
||||
ErrUnknown = errors.New("unknown") // used internally to represent a missed mapping.
|
||||
ErrInvalidArgument = errors.New("invalid")
|
||||
ErrNotFound = errors.New("not found")
|
||||
ErrAlreadyExists = errors.New("already exists")
|
||||
ErrFailedPrecondition = errors.New("failed precondition")
|
||||
ErrUnavailable = errors.New("unavailable")
|
||||
)
|
||||
|
||||
func IsInvalidArgument(err error) bool {
|
||||
return errors.Cause(err) == ErrInvalidArgument
|
||||
}
|
||||
|
||||
// IsNotFound returns true if the error is due to a missing object
|
||||
func IsNotFound(err error) bool {
|
||||
return errors.Cause(err) == ErrNotFound
|
||||
}
|
||||
|
||||
// IsAlreadyExists returns true if the error is due to an already existing
|
||||
// metadata item
|
||||
func IsAlreadyExists(err error) bool {
|
||||
return errors.Cause(err) == ErrAlreadyExists
|
||||
}
|
||||
|
||||
// IsFailedPrecondition returns true if an operation could not proceed to the
|
||||
// lack of a particular condition.
|
||||
func IsFailedPrecondition(err error) bool {
|
||||
return errors.Cause(err) == ErrFailedPrecondition
|
||||
}
|
||||
|
||||
func IsUnavailable(err error) bool {
|
||||
return errors.Cause(err) == ErrUnavailable
|
||||
}
|
106
errdefs/grpc.go
Normal file
106
errdefs/grpc.go
Normal file
@ -0,0 +1,106 @@
|
||||
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())
|
||||
}
|
||||
|
||||
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
|
||||
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
|
||||
}
|
@ -17,6 +17,7 @@ package identifiers
|
||||
import (
|
||||
"regexp"
|
||||
|
||||
"github.com/containerd/containerd/errdefs"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
@ -32,15 +33,8 @@ var (
|
||||
// Rules for domains, defined in RFC 1035, section 2.3.1, are used for
|
||||
// identifiers.
|
||||
identifierRe = regexp.MustCompile(reAnchor(label + reGroup("[.]"+reGroup(label)) + "*"))
|
||||
|
||||
errIdentifierInvalid = errors.New("invalid identifier")
|
||||
)
|
||||
|
||||
// IsInvalid return true if the error was due to an invalid identifer.
|
||||
func IsInvalid(err error) bool {
|
||||
return errors.Cause(err) == errIdentifierInvalid
|
||||
}
|
||||
|
||||
// Validate return nil if the string s is a valid identifier.
|
||||
//
|
||||
// identifiers must be valid domain identifiers according to RFC 1035, section 2.3.1. To
|
||||
@ -50,11 +44,11 @@ func IsInvalid(err error) bool {
|
||||
// a domain identifier or filesystem path component.
|
||||
func Validate(s string) error {
|
||||
if len(s) > maxLength {
|
||||
return errors.Wrapf(errIdentifierInvalid, "identifier %q greater than maximum length (%d characters)", s, maxLength)
|
||||
return errors.Wrapf(errdefs.ErrInvalidArgument, "identifier %q greater than maximum length (%d characters)", s, maxLength)
|
||||
}
|
||||
|
||||
if !identifierRe.MatchString(s) {
|
||||
return errors.Wrapf(errIdentifierInvalid, "identifier %q must match %v", s, identifierRe)
|
||||
return errors.Wrapf(errdefs.ErrInvalidArgument, "identifier %q must match %v", s, identifierRe)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -3,6 +3,8 @@ package identifiers
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/containerd/containerd/errdefs"
|
||||
)
|
||||
|
||||
func TestValidIdentifiers(t *testing.T) {
|
||||
@ -44,7 +46,7 @@ func TestInvalidIdentifiers(t *testing.T) {
|
||||
t.Run(input, func(t *testing.T) {
|
||||
if err := Validate(input); err == nil {
|
||||
t.Fatal("expected invalid error")
|
||||
} else if !IsInvalid(err) {
|
||||
} else if !errdefs.IsInvalidArgument(err) {
|
||||
t.Fatal("error should be an invalid identifier error")
|
||||
}
|
||||
})
|
||||
|
@ -6,6 +6,7 @@ import (
|
||||
|
||||
"github.com/boltdb/bolt"
|
||||
"github.com/containerd/containerd/containers"
|
||||
"github.com/containerd/containerd/errdefs"
|
||||
"github.com/containerd/containerd/identifiers"
|
||||
"github.com/containerd/containerd/namespaces"
|
||||
"github.com/pkg/errors"
|
||||
@ -29,12 +30,12 @@ func (s *containerStore) Get(ctx context.Context, id string) (containers.Contain
|
||||
|
||||
bkt := getContainerBucket(s.tx, namespace, id)
|
||||
if bkt == nil {
|
||||
return containers.Container{}, ErrNotFound("bucket does not exist")
|
||||
return containers.Container{}, errors.Wrapf(errdefs.ErrNotFound, "bucket name %q")
|
||||
}
|
||||
|
||||
container := containers.Container{ID: id}
|
||||
if err := readContainer(&container, bkt); err != nil {
|
||||
return containers.Container{}, errors.Wrap(err, "failed to read container")
|
||||
return containers.Container{}, errors.Wrapf(err, "failed to read container %v", id)
|
||||
}
|
||||
|
||||
return container, nil
|
||||
@ -90,7 +91,7 @@ func (s *containerStore) Create(ctx context.Context, container containers.Contai
|
||||
cbkt, err := bkt.CreateBucket([]byte(container.ID))
|
||||
if err != nil {
|
||||
if err == bolt.ErrBucketExists {
|
||||
err = ErrExists("content for id already exists")
|
||||
err = errors.Wrapf(errdefs.ErrAlreadyExists, "content %q")
|
||||
}
|
||||
return containers.Container{}, err
|
||||
}
|
||||
@ -110,14 +111,18 @@ func (s *containerStore) Update(ctx context.Context, container containers.Contai
|
||||
return containers.Container{}, err
|
||||
}
|
||||
|
||||
if container.ID == "" {
|
||||
return containers.Container{}, errors.Wrapf(errdefs.ErrInvalidArgument, "must specify a container id")
|
||||
}
|
||||
|
||||
bkt := getContainersBucket(s.tx, namespace)
|
||||
if bkt == nil {
|
||||
return containers.Container{}, ErrNotFound("no containers")
|
||||
return containers.Container{}, errors.Wrapf(errdefs.ErrNotFound, "container %q", container.ID)
|
||||
}
|
||||
|
||||
cbkt := bkt.Bucket([]byte(container.ID))
|
||||
if cbkt == nil {
|
||||
return containers.Container{}, ErrNotFound("no content for id")
|
||||
return containers.Container{}, errors.Wrapf(errdefs.ErrNotFound, "container %q", container.ID)
|
||||
}
|
||||
|
||||
container.UpdatedAt = time.Now()
|
||||
@ -136,11 +141,11 @@ func (s *containerStore) Delete(ctx context.Context, id string) error {
|
||||
|
||||
bkt := getContainersBucket(s.tx, namespace)
|
||||
if bkt == nil {
|
||||
return ErrNotFound("no containers")
|
||||
return errors.Wrapf(errdefs.ErrNotFound, "cannot delete container %v, bucket not present", id)
|
||||
}
|
||||
|
||||
if err := bkt.DeleteBucket([]byte(id)); err == bolt.ErrBucketNotFound {
|
||||
return ErrNotFound("no content for id")
|
||||
return errors.Wrapf(errdefs.ErrNotFound, "container %v", id)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
@ -1,95 +0,0 @@
|
||||
package metadata
|
||||
|
||||
import "github.com/pkg/errors"
|
||||
|
||||
type metadataExistsErr struct {
|
||||
desc string
|
||||
}
|
||||
type metadataNotFoundErr struct {
|
||||
desc string
|
||||
}
|
||||
type metadataNotEmptyErr struct {
|
||||
desc string
|
||||
}
|
||||
|
||||
// ErrExists is returned when an item already exists in metadata
|
||||
func ErrExists(msg string) error {
|
||||
if msg == "" {
|
||||
msg = "metadata: exists"
|
||||
}
|
||||
return errors.WithStack(metadataExistsErr{
|
||||
desc: msg,
|
||||
})
|
||||
}
|
||||
|
||||
// ErrNotFound is returned when an item cannot be found in metadata
|
||||
func ErrNotFound(msg string) error {
|
||||
if msg == "" {
|
||||
msg = "metadata: not found"
|
||||
}
|
||||
return errors.WithStack(metadataNotFoundErr{
|
||||
desc: msg,
|
||||
})
|
||||
}
|
||||
|
||||
// ErrNotEmpty is returned when a metadata item can't be deleted because it is not empty
|
||||
func ErrNotEmpty(msg string) error {
|
||||
if msg == "" {
|
||||
msg = "metadata: namespace not empty"
|
||||
}
|
||||
return errors.WithStack(metadataNotEmptyErr{
|
||||
desc: msg,
|
||||
})
|
||||
}
|
||||
|
||||
func (m metadataExistsErr) Error() string {
|
||||
return m.desc
|
||||
}
|
||||
func (m metadataNotFoundErr) Error() string {
|
||||
return m.desc
|
||||
}
|
||||
func (m metadataNotEmptyErr) Error() string {
|
||||
return m.desc
|
||||
}
|
||||
|
||||
func (m metadataExistsErr) Exists() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (m metadataNotFoundErr) NotFound() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (m metadataNotEmptyErr) NotEmpty() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// IsNotFound returns true if the error is due to a missing metadata item
|
||||
func IsNotFound(err error) bool {
|
||||
if err, ok := errors.Cause(err).(interface {
|
||||
NotFound() bool
|
||||
}); ok {
|
||||
return err.NotFound()
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// IsExists returns true if the error is due to an already existing metadata item
|
||||
func IsExists(err error) bool {
|
||||
if err, ok := errors.Cause(err).(interface {
|
||||
Exists() bool
|
||||
}); ok {
|
||||
return err.Exists()
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// IsNotEmpty returns true if the error is due to delete request of a non-empty metadata item
|
||||
func IsNotEmpty(err error) bool {
|
||||
if err, ok := errors.Cause(err).(interface {
|
||||
NotEmpty() bool
|
||||
}); ok {
|
||||
return err.NotEmpty()
|
||||
}
|
||||
return false
|
||||
}
|
@ -6,10 +6,12 @@ import (
|
||||
"fmt"
|
||||
|
||||
"github.com/boltdb/bolt"
|
||||
"github.com/containerd/containerd/errdefs"
|
||||
"github.com/containerd/containerd/images"
|
||||
"github.com/containerd/containerd/namespaces"
|
||||
digest "github.com/opencontainers/go-digest"
|
||||
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
type imageStore struct {
|
||||
@ -30,12 +32,12 @@ func (s *imageStore) Get(ctx context.Context, name string) (images.Image, error)
|
||||
|
||||
bkt := getImagesBucket(s.tx, namespace)
|
||||
if bkt == nil {
|
||||
return images.Image{}, ErrNotFound("")
|
||||
return images.Image{}, errors.Wrapf(errdefs.ErrNotFound, "image %q", name)
|
||||
}
|
||||
|
||||
ibkt := bkt.Bucket([]byte(name))
|
||||
if ibkt == nil {
|
||||
return images.Image{}, ErrNotFound("")
|
||||
return images.Image{}, errors.Wrapf(errdefs.ErrNotFound, "image %q", name)
|
||||
}
|
||||
|
||||
image.Name = name
|
||||
@ -124,7 +126,7 @@ func (s *imageStore) Delete(ctx context.Context, name string) error {
|
||||
return withImagesBucket(s.tx, namespace, func(bkt *bolt.Bucket) error {
|
||||
err := bkt.DeleteBucket([]byte(name))
|
||||
if err == bolt.ErrBucketNotFound {
|
||||
return ErrNotFound("")
|
||||
return errors.Wrapf(errdefs.ErrNotFound, "image %q", name)
|
||||
}
|
||||
return err
|
||||
})
|
||||
|
@ -4,8 +4,10 @@ import (
|
||||
"context"
|
||||
|
||||
"github.com/boltdb/bolt"
|
||||
"github.com/containerd/containerd/errdefs"
|
||||
"github.com/containerd/containerd/identifiers"
|
||||
"github.com/containerd/containerd/namespaces"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
type namespaceStore struct {
|
||||
@ -30,7 +32,7 @@ func (s *namespaceStore) Create(ctx context.Context, namespace string, labels ma
|
||||
bkt, err := topbkt.CreateBucket([]byte(namespace))
|
||||
if err != nil {
|
||||
if err == bolt.ErrBucketExists {
|
||||
return ErrExists("")
|
||||
return errors.Wrapf(errdefs.ErrAlreadyExists, "namespace %q")
|
||||
}
|
||||
|
||||
return err
|
||||
@ -105,12 +107,12 @@ func (s *namespaceStore) Delete(ctx context.Context, namespace string) error {
|
||||
if empty, err := s.namespaceEmpty(ctx, namespace); err != nil {
|
||||
return err
|
||||
} else if !empty {
|
||||
return ErrNotEmpty("")
|
||||
return errors.Wrapf(errdefs.ErrFailedPrecondition, "namespace %q must be empty", namespace)
|
||||
}
|
||||
|
||||
if err := bkt.DeleteBucket([]byte(namespace)); err != nil {
|
||||
if err == bolt.ErrBucketNotFound {
|
||||
return ErrNotFound("")
|
||||
return errors.Wrapf(errdefs.ErrNotFound, "namespace %q", namespace)
|
||||
}
|
||||
|
||||
return err
|
||||
|
@ -3,6 +3,7 @@ package namespaces
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/containerd/containerd/errdefs"
|
||||
"github.com/containerd/containerd/identifiers"
|
||||
"github.com/pkg/errors"
|
||||
"golang.org/x/net/context"
|
||||
@ -13,10 +14,6 @@ const (
|
||||
Default = "default"
|
||||
)
|
||||
|
||||
var (
|
||||
errNamespaceRequired = errors.New("namespace is required")
|
||||
)
|
||||
|
||||
type namespaceKey struct{}
|
||||
|
||||
// WithNamespace sets a given namespace on the context
|
||||
@ -50,16 +47,11 @@ func Namespace(ctx context.Context) (string, bool) {
|
||||
return namespace, ok
|
||||
}
|
||||
|
||||
// IsNamespaceRequired returns whether an error is caused by a missing namespace
|
||||
func IsNamespaceRequired(err error) bool {
|
||||
return errors.Cause(err) == errNamespaceRequired
|
||||
}
|
||||
|
||||
// NamespaceRequired returns the valid namepace from the context or an error.
|
||||
func NamespaceRequired(ctx context.Context) (string, error) {
|
||||
namespace, ok := Namespace(ctx)
|
||||
if !ok || namespace == "" {
|
||||
return "", errNamespaceRequired
|
||||
return "", errors.Wrapf(errdefs.ErrFailedPrecondition, "namespace is required")
|
||||
}
|
||||
|
||||
if err := identifiers.Validate(namespace); err != nil {
|
||||
|
@ -10,6 +10,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/containerd/containerd/content"
|
||||
"github.com/containerd/containerd/errdefs"
|
||||
"github.com/containerd/containerd/images"
|
||||
"github.com/containerd/containerd/log"
|
||||
"github.com/containerd/containerd/remotes"
|
||||
@ -31,10 +32,10 @@ func (p dockerPusher) Push(ctx context.Context, desc ocispec.Descriptor) (conten
|
||||
status, err := p.tracker.GetStatus(ref)
|
||||
if err == nil {
|
||||
if status.Offset == status.Total {
|
||||
return nil, content.ErrExists("")
|
||||
return nil, errors.Wrapf(errdefs.ErrAlreadyExists, "ref %v already exists", ref)
|
||||
}
|
||||
// TODO: Handle incomplete status
|
||||
} else if !content.IsNotFound(err) {
|
||||
} else if !errdefs.IsNotFound(err) {
|
||||
return nil, errors.Wrap(err, "failed to get status")
|
||||
}
|
||||
|
||||
@ -72,7 +73,7 @@ func (p dockerPusher) Push(ctx context.Context, desc ocispec.Descriptor) (conten
|
||||
// TODO: Set updated time?
|
||||
},
|
||||
})
|
||||
return nil, content.ErrExists("")
|
||||
return nil, errors.Wrapf(errdefs.ErrAlreadyExists, "content %v on remote", desc.Digest)
|
||||
}
|
||||
if resp.StatusCode != http.StatusNotFound {
|
||||
// TODO: log error
|
||||
|
@ -16,6 +16,7 @@ import (
|
||||
"golang.org/x/sync/errgroup"
|
||||
|
||||
"github.com/containerd/containerd/content"
|
||||
"github.com/containerd/containerd/errdefs"
|
||||
"github.com/containerd/containerd/images"
|
||||
"github.com/containerd/containerd/log"
|
||||
"github.com/containerd/containerd/remotes"
|
||||
@ -202,7 +203,7 @@ func (c *Converter) fetchBlob(ctx context.Context, desc ocispec.Descriptor) erro
|
||||
|
||||
cw, err := c.contentStore.Writer(ctx, ref, desc.Size, desc.Digest)
|
||||
if err != nil {
|
||||
if !content.IsExists(err) {
|
||||
if !errdefs.IsAlreadyExists(err) {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -4,6 +4,8 @@ import (
|
||||
"sync"
|
||||
|
||||
"github.com/containerd/containerd/content"
|
||||
"github.com/containerd/containerd/errdefs"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
type Status struct {
|
||||
@ -34,7 +36,7 @@ func (t *memoryStatusTracker) GetStatus(ref string) (Status, error) {
|
||||
defer t.m.Unlock()
|
||||
status, ok := t.statuses[ref]
|
||||
if !ok {
|
||||
return Status{}, content.ErrNotFound("")
|
||||
return Status{}, errors.Wrapf(errdefs.ErrNotFound, "status for ref %v", ref)
|
||||
}
|
||||
return status, nil
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ import (
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/containerd/containerd/content"
|
||||
"github.com/containerd/containerd/errdefs"
|
||||
"github.com/containerd/containerd/images"
|
||||
"github.com/containerd/containerd/log"
|
||||
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
@ -69,9 +70,9 @@ func fetch(ctx context.Context, ingester content.Ingester, fetcher Fetcher, desc
|
||||
for {
|
||||
cw, err = ingester.Writer(ctx, ref, desc.Size, desc.Digest)
|
||||
if err != nil {
|
||||
if content.IsExists(err) {
|
||||
if errdefs.IsAlreadyExists(err) {
|
||||
return nil
|
||||
} else if !content.IsLocked(err) {
|
||||
} else if !errdefs.IsUnavailable(err) {
|
||||
return err
|
||||
}
|
||||
|
||||
@ -122,7 +123,7 @@ func push(ctx context.Context, provider content.Provider, pusher Pusher, desc oc
|
||||
|
||||
cw, err := pusher.Push(ctx, desc)
|
||||
if err != nil {
|
||||
if !content.IsExists(err) {
|
||||
if !errdefs.IsAlreadyExists(err) {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -3,6 +3,7 @@ package rootfs
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/containerd/containerd/errdefs"
|
||||
"github.com/containerd/containerd/log"
|
||||
"github.com/containerd/containerd/mount"
|
||||
"github.com/containerd/containerd/snapshot"
|
||||
@ -46,7 +47,7 @@ func applyLayer(ctx context.Context, layer Layer, chain []digest.Digest, sn snap
|
||||
if err == nil {
|
||||
log.G(ctx).Debugf("Extraction not needed, layer snapshot exists")
|
||||
return nil
|
||||
} else if !snapshot.IsNotExist(err) {
|
||||
} else if !errdefs.IsNotFound(err) {
|
||||
return errors.Wrap(err, "failed to stat snapshot")
|
||||
}
|
||||
|
||||
|
@ -3,13 +3,8 @@ package containers
|
||||
import (
|
||||
api "github.com/containerd/containerd/api/services/containers/v1"
|
||||
"github.com/containerd/containerd/containers"
|
||||
"github.com/containerd/containerd/identifiers"
|
||||
"github.com/containerd/containerd/metadata"
|
||||
"github.com/containerd/containerd/namespaces"
|
||||
"github.com/gogo/protobuf/types"
|
||||
specs "github.com/opencontainers/runtime-spec/specs-go"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/codes"
|
||||
)
|
||||
|
||||
func containersToProto(containers []containers.Container) []api.Container {
|
||||
@ -52,18 +47,3 @@ func containerFromProto(containerpb *api.Container) containers.Container {
|
||||
RootFS: containerpb.RootFS,
|
||||
}
|
||||
}
|
||||
|
||||
func mapGRPCError(err error, id string) error {
|
||||
switch {
|
||||
case metadata.IsNotFound(err):
|
||||
return grpc.Errorf(codes.NotFound, "container %v not found", id)
|
||||
case metadata.IsExists(err):
|
||||
return grpc.Errorf(codes.AlreadyExists, "container %v already exists", id)
|
||||
case namespaces.IsNamespaceRequired(err):
|
||||
return grpc.Errorf(codes.InvalidArgument, "namespace required, please set %q header", namespaces.GRPCHeader)
|
||||
case identifiers.IsInvalid(err):
|
||||
return grpc.Errorf(codes.InvalidArgument, err.Error())
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ import (
|
||||
api "github.com/containerd/containerd/api/services/containers/v1"
|
||||
eventsapi "github.com/containerd/containerd/api/services/events/v1"
|
||||
"github.com/containerd/containerd/containers"
|
||||
"github.com/containerd/containerd/errdefs"
|
||||
"github.com/containerd/containerd/events"
|
||||
"github.com/containerd/containerd/metadata"
|
||||
"github.com/containerd/containerd/plugin"
|
||||
@ -49,31 +50,30 @@ func (s *Service) Register(server *grpc.Server) error {
|
||||
func (s *Service) Get(ctx context.Context, req *api.GetContainerRequest) (*api.GetContainerResponse, error) {
|
||||
var resp api.GetContainerResponse
|
||||
|
||||
return &resp, s.withStoreView(ctx, func(ctx context.Context, store containers.Store) error {
|
||||
return &resp, errdefs.ToGRPC(s.withStoreView(ctx, func(ctx context.Context, store containers.Store) error {
|
||||
container, err := store.Get(ctx, req.ID)
|
||||
if err != nil {
|
||||
return mapGRPCError(err, req.ID)
|
||||
return err
|
||||
}
|
||||
containerpb := containerToProto(&container)
|
||||
resp.Container = containerpb
|
||||
|
||||
return nil
|
||||
})
|
||||
}))
|
||||
}
|
||||
|
||||
func (s *Service) List(ctx context.Context, req *api.ListContainersRequest) (*api.ListContainersResponse, error) {
|
||||
var resp api.ListContainersResponse
|
||||
|
||||
return &resp, s.withStoreView(ctx, func(ctx context.Context, store containers.Store) error {
|
||||
return &resp, errdefs.ToGRPC(s.withStoreView(ctx, func(ctx context.Context, store containers.Store) error {
|
||||
containers, err := store.List(ctx, req.Filter)
|
||||
if err != nil {
|
||||
return mapGRPCError(err, "")
|
||||
return err
|
||||
}
|
||||
|
||||
resp.Containers = containersToProto(containers)
|
||||
return nil
|
||||
})
|
||||
|
||||
}))
|
||||
}
|
||||
|
||||
func (s *Service) Create(ctx context.Context, req *api.CreateContainerRequest) (*api.CreateContainerResponse, error) {
|
||||
@ -84,14 +84,14 @@ func (s *Service) Create(ctx context.Context, req *api.CreateContainerRequest) (
|
||||
|
||||
created, err := store.Create(ctx, container)
|
||||
if err != nil {
|
||||
return mapGRPCError(err, req.Container.ID)
|
||||
return err
|
||||
}
|
||||
|
||||
resp.Container = containerToProto(&created)
|
||||
|
||||
return nil
|
||||
}); err != nil {
|
||||
return &resp, err
|
||||
return &resp, errdefs.ToGRPC(err)
|
||||
}
|
||||
if err := s.emit(ctx, "/containers/create", &eventsapi.ContainerCreate{
|
||||
ContainerID: resp.Container.ID,
|
||||
@ -115,7 +115,7 @@ func (s *Service) Update(ctx context.Context, req *api.UpdateContainerRequest) (
|
||||
|
||||
current, err := store.Get(ctx, container.ID)
|
||||
if err != nil {
|
||||
return mapGRPCError(err, container.ID)
|
||||
return err
|
||||
}
|
||||
|
||||
if current.ID != container.ID {
|
||||
@ -150,14 +150,14 @@ func (s *Service) Update(ctx context.Context, req *api.UpdateContainerRequest) (
|
||||
|
||||
created, err := store.Update(ctx, container)
|
||||
if err != nil {
|
||||
return mapGRPCError(err, req.Container.ID)
|
||||
return err
|
||||
}
|
||||
|
||||
resp.Container = containerToProto(&created)
|
||||
|
||||
return nil
|
||||
}); err != nil {
|
||||
return &resp, err
|
||||
return &resp, errdefs.ToGRPC(err)
|
||||
}
|
||||
|
||||
if err := s.emit(ctx, "/containers/update", &eventsapi.ContainerUpdate{
|
||||
@ -174,9 +174,9 @@ func (s *Service) Update(ctx context.Context, req *api.UpdateContainerRequest) (
|
||||
|
||||
func (s *Service) Delete(ctx context.Context, req *api.DeleteContainerRequest) (*empty.Empty, error) {
|
||||
if err := s.withStoreUpdate(ctx, func(ctx context.Context, store containers.Store) error {
|
||||
return mapGRPCError(store.Delete(ctx, req.ID), req.ID)
|
||||
return store.Delete(ctx, req.ID)
|
||||
}); err != nil {
|
||||
return &empty.Empty{}, mapGRPCError(err, req.ID)
|
||||
return &empty.Empty{}, errdefs.ToGRPC(err)
|
||||
}
|
||||
|
||||
if err := s.emit(ctx, "/containers/delete", &eventsapi.ContainerDelete{
|
||||
|
@ -1,33 +0,0 @@
|
||||
package content
|
||||
|
||||
import (
|
||||
"github.com/containerd/containerd/content"
|
||||
"github.com/pkg/errors"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/codes"
|
||||
)
|
||||
|
||||
func rewriteGRPCError(err error) error {
|
||||
switch grpc.Code(errors.Cause(err)) {
|
||||
case codes.AlreadyExists:
|
||||
return content.ErrExists(grpc.ErrorDesc(err))
|
||||
case codes.NotFound:
|
||||
return content.ErrNotFound(grpc.ErrorDesc(err))
|
||||
case codes.Unavailable:
|
||||
return content.ErrLocked(grpc.ErrorDesc(err))
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func serverErrorToGRPC(err error, id string) error {
|
||||
switch {
|
||||
case content.IsNotFound(err):
|
||||
return grpc.Errorf(codes.NotFound, "%v: not found", id)
|
||||
case content.IsExists(err):
|
||||
return grpc.Errorf(codes.AlreadyExists, "%v: exists", id)
|
||||
case content.IsLocked(err):
|
||||
return grpc.Errorf(codes.Unavailable, "%v: locked", id)
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
@ -8,6 +8,7 @@ import (
|
||||
api "github.com/containerd/containerd/api/services/content/v1"
|
||||
eventsapi "github.com/containerd/containerd/api/services/events/v1"
|
||||
"github.com/containerd/containerd/content"
|
||||
"github.com/containerd/containerd/errdefs"
|
||||
"github.com/containerd/containerd/events"
|
||||
"github.com/containerd/containerd/log"
|
||||
"github.com/containerd/containerd/plugin"
|
||||
@ -66,7 +67,7 @@ func (s *Service) Info(ctx context.Context, req *api.InfoRequest) (*api.InfoResp
|
||||
|
||||
bi, err := s.store.Info(ctx, req.Digest)
|
||||
if err != nil {
|
||||
return nil, serverErrorToGRPC(err, req.Digest.String())
|
||||
return nil, errdefs.ToGRPC(err)
|
||||
}
|
||||
|
||||
return &api.InfoResponse{
|
||||
@ -125,7 +126,7 @@ func (s *Service) Delete(ctx context.Context, req *api.DeleteContentRequest) (*e
|
||||
}
|
||||
|
||||
if err := s.store.Delete(ctx, req.Digest); err != nil {
|
||||
return nil, serverErrorToGRPC(err, req.Digest.String())
|
||||
return nil, errdefs.ToGRPC(err)
|
||||
}
|
||||
|
||||
if err := s.emit(ctx, "/content/delete", &eventsapi.ContentDelete{
|
||||
@ -144,12 +145,12 @@ func (s *Service) Read(req *api.ReadContentRequest, session api.Content_ReadServ
|
||||
|
||||
oi, err := s.store.Info(session.Context(), req.Digest)
|
||||
if err != nil {
|
||||
return serverErrorToGRPC(err, req.Digest.String())
|
||||
return errdefs.ToGRPC(err)
|
||||
}
|
||||
|
||||
rc, err := s.store.Reader(session.Context(), req.Digest)
|
||||
if err != nil {
|
||||
return serverErrorToGRPC(err, req.Digest.String())
|
||||
return errdefs.ToGRPC(err)
|
||||
}
|
||||
defer rc.Close() // TODO(stevvooe): Cache these file descriptors for performance.
|
||||
|
||||
@ -217,7 +218,7 @@ func (rw *readResponseWriter) Write(p []byte) (n int, err error) {
|
||||
func (s *Service) Status(ctx context.Context, req *api.StatusRequest) (*api.StatusResponse, error) {
|
||||
statuses, err := s.store.Status(ctx, req.Filter)
|
||||
if err != nil {
|
||||
return nil, serverErrorToGRPC(err, req.Filter)
|
||||
return nil, errdefs.ToGRPCf(err, "could not get status for filter %q", req.Filter)
|
||||
}
|
||||
|
||||
var resp api.StatusResponse
|
||||
@ -295,7 +296,7 @@ func (s *Service) Write(session api.Content_WriteServer) (err error) {
|
||||
// this action locks the writer for the session.
|
||||
wr, err := s.store.Writer(ctx, ref, total, expected)
|
||||
if err != nil {
|
||||
return serverErrorToGRPC(err, ref)
|
||||
return errdefs.ToGRPC(err)
|
||||
}
|
||||
defer wr.Close()
|
||||
|
||||
@ -303,7 +304,7 @@ func (s *Service) Write(session api.Content_WriteServer) (err error) {
|
||||
msg.Action = req.Action
|
||||
ws, err := wr.Status()
|
||||
if err != nil {
|
||||
return serverErrorToGRPC(err, ref)
|
||||
return errdefs.ToGRPC(err)
|
||||
}
|
||||
|
||||
msg.Offset = ws.Offset // always set the offset.
|
||||
@ -414,7 +415,7 @@ func (s *Service) Write(session api.Content_WriteServer) (err error) {
|
||||
|
||||
func (s *Service) Abort(ctx context.Context, req *api.AbortRequest) (*empty.Empty, error) {
|
||||
if err := s.store.Abort(ctx, req.Ref); err != nil {
|
||||
return nil, serverErrorToGRPC(err, req.Ref)
|
||||
return nil, errdefs.ToGRPC(err)
|
||||
}
|
||||
|
||||
return &empty.Empty{}, nil
|
||||
|
@ -6,6 +6,7 @@ import (
|
||||
|
||||
contentapi "github.com/containerd/containerd/api/services/content/v1"
|
||||
"github.com/containerd/containerd/content"
|
||||
"github.com/containerd/containerd/errdefs"
|
||||
digest "github.com/opencontainers/go-digest"
|
||||
)
|
||||
|
||||
@ -24,7 +25,7 @@ func (rs *remoteStore) Info(ctx context.Context, dgst digest.Digest) (content.In
|
||||
Digest: dgst,
|
||||
})
|
||||
if err != nil {
|
||||
return content.Info{}, rewriteGRPCError(err)
|
||||
return content.Info{}, errdefs.FromGRPC(err)
|
||||
}
|
||||
|
||||
return content.Info{
|
||||
@ -37,14 +38,14 @@ func (rs *remoteStore) Info(ctx context.Context, dgst digest.Digest) (content.In
|
||||
func (rs *remoteStore) Walk(ctx context.Context, fn content.WalkFunc) error {
|
||||
session, err := rs.client.List(ctx, &contentapi.ListContentRequest{})
|
||||
if err != nil {
|
||||
return rewriteGRPCError(err)
|
||||
return errdefs.FromGRPC(err)
|
||||
}
|
||||
|
||||
for {
|
||||
msg, err := session.Recv()
|
||||
if err != nil {
|
||||
if err != io.EOF {
|
||||
return rewriteGRPCError(err)
|
||||
return errdefs.FromGRPC(err)
|
||||
}
|
||||
|
||||
break
|
||||
@ -68,7 +69,7 @@ func (rs *remoteStore) Delete(ctx context.Context, dgst digest.Digest) error {
|
||||
if _, err := rs.client.Delete(ctx, &contentapi.DeleteContentRequest{
|
||||
Digest: dgst,
|
||||
}); err != nil {
|
||||
return rewriteGRPCError(err)
|
||||
return errdefs.FromGRPC(err)
|
||||
}
|
||||
|
||||
return nil
|
||||
@ -98,7 +99,7 @@ func (rs *remoteStore) Status(ctx context.Context, filter string) ([]content.Sta
|
||||
Filter: filter,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, rewriteGRPCError(err)
|
||||
return nil, errdefs.FromGRPC(err)
|
||||
}
|
||||
|
||||
var statuses []content.Status
|
||||
@ -119,7 +120,7 @@ func (rs *remoteStore) Status(ctx context.Context, filter string) ([]content.Sta
|
||||
func (rs *remoteStore) Writer(ctx context.Context, ref string, size int64, expected digest.Digest) (content.Writer, error) {
|
||||
wrclient, offset, err := rs.negotiate(ctx, ref, size, expected)
|
||||
if err != nil {
|
||||
return nil, rewriteGRPCError(err)
|
||||
return nil, errdefs.FromGRPC(err)
|
||||
}
|
||||
|
||||
return &remoteWriter{
|
||||
@ -134,7 +135,7 @@ func (rs *remoteStore) Abort(ctx context.Context, ref string) error {
|
||||
if _, err := rs.client.Abort(ctx, &contentapi.AbortRequest{
|
||||
Ref: ref,
|
||||
}); err != nil {
|
||||
return rewriteGRPCError(err)
|
||||
return errdefs.FromGRPC(err)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
@ -5,6 +5,7 @@ import (
|
||||
|
||||
contentapi "github.com/containerd/containerd/api/services/content/v1"
|
||||
"github.com/containerd/containerd/content"
|
||||
"github.com/containerd/containerd/errdefs"
|
||||
digest "github.com/opencontainers/go-digest"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
@ -86,7 +87,7 @@ func (rw *remoteWriter) Commit(size int64, expected digest.Digest) error {
|
||||
Expected: expected,
|
||||
})
|
||||
if err != nil {
|
||||
return rewriteGRPCError(err)
|
||||
return errdefs.FromGRPC(err)
|
||||
}
|
||||
|
||||
if size != 0 && resp.Offset != size {
|
||||
|
@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
|
||||
imagesapi "github.com/containerd/containerd/api/services/images/v1"
|
||||
"github.com/containerd/containerd/errdefs"
|
||||
"github.com/containerd/containerd/images"
|
||||
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
)
|
||||
@ -28,7 +29,7 @@ func (s *remoteStore) Update(ctx context.Context, name string, desc ocispec.Desc
|
||||
},
|
||||
})
|
||||
|
||||
return rewriteGRPCError(err)
|
||||
return errdefs.FromGRPC(err)
|
||||
}
|
||||
|
||||
func (s *remoteStore) Get(ctx context.Context, name string) (images.Image, error) {
|
||||
@ -36,7 +37,7 @@ func (s *remoteStore) Get(ctx context.Context, name string) (images.Image, error
|
||||
Name: name,
|
||||
})
|
||||
if err != nil {
|
||||
return images.Image{}, rewriteGRPCError(err)
|
||||
return images.Image{}, errdefs.FromGRPC(err)
|
||||
}
|
||||
|
||||
return imageFromProto(resp.Image), nil
|
||||
@ -45,7 +46,7 @@ func (s *remoteStore) Get(ctx context.Context, name string) (images.Image, error
|
||||
func (s *remoteStore) List(ctx context.Context) ([]images.Image, error) {
|
||||
resp, err := s.client.List(ctx, &imagesapi.ListImagesRequest{})
|
||||
if err != nil {
|
||||
return nil, rewriteGRPCError(err)
|
||||
return nil, errdefs.FromGRPC(err)
|
||||
}
|
||||
|
||||
return imagesFromProto(resp.Images), nil
|
||||
@ -56,5 +57,5 @@ func (s *remoteStore) Delete(ctx context.Context, name string) error {
|
||||
Name: name,
|
||||
})
|
||||
|
||||
return rewriteGRPCError(err)
|
||||
return errdefs.FromGRPC(err)
|
||||
}
|
||||
|
@ -3,14 +3,8 @@ package images
|
||||
import (
|
||||
imagesapi "github.com/containerd/containerd/api/services/images/v1"
|
||||
"github.com/containerd/containerd/api/types"
|
||||
"github.com/containerd/containerd/identifiers"
|
||||
"github.com/containerd/containerd/images"
|
||||
"github.com/containerd/containerd/metadata"
|
||||
"github.com/containerd/containerd/namespaces"
|
||||
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
"github.com/pkg/errors"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/codes"
|
||||
)
|
||||
|
||||
func imagesToProto(images []images.Image) []imagesapi.Image {
|
||||
@ -62,33 +56,3 @@ func descToProto(desc *ocispec.Descriptor) types.Descriptor {
|
||||
Digest: desc.Digest,
|
||||
}
|
||||
}
|
||||
|
||||
func rewriteGRPCError(err error) error {
|
||||
if err == nil {
|
||||
return err
|
||||
}
|
||||
|
||||
switch grpc.Code(errors.Cause(err)) {
|
||||
case codes.AlreadyExists:
|
||||
return metadata.ErrExists(grpc.ErrorDesc(err))
|
||||
case codes.NotFound:
|
||||
return metadata.ErrNotFound(grpc.ErrorDesc(err))
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func mapGRPCError(err error, id string) error {
|
||||
switch {
|
||||
case metadata.IsNotFound(err):
|
||||
return grpc.Errorf(codes.NotFound, "image %v not found", id)
|
||||
case metadata.IsExists(err):
|
||||
return grpc.Errorf(codes.AlreadyExists, "image %v already exists", id)
|
||||
case namespaces.IsNamespaceRequired(err):
|
||||
return grpc.Errorf(codes.InvalidArgument, "namespace required, please set %q header", namespaces.GRPCHeader)
|
||||
case identifiers.IsInvalid(err):
|
||||
return grpc.Errorf(codes.InvalidArgument, err.Error())
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ import (
|
||||
"github.com/boltdb/bolt"
|
||||
eventsapi "github.com/containerd/containerd/api/services/events/v1"
|
||||
imagesapi "github.com/containerd/containerd/api/services/images/v1"
|
||||
"github.com/containerd/containerd/errdefs"
|
||||
"github.com/containerd/containerd/events"
|
||||
"github.com/containerd/containerd/images"
|
||||
"github.com/containerd/containerd/metadata"
|
||||
@ -51,22 +52,22 @@ func (s *Service) Register(server *grpc.Server) error {
|
||||
func (s *Service) Get(ctx context.Context, req *imagesapi.GetImageRequest) (*imagesapi.GetImageResponse, error) {
|
||||
var resp imagesapi.GetImageResponse
|
||||
|
||||
return &resp, s.withStoreView(ctx, func(ctx context.Context, store images.Store) error {
|
||||
return &resp, errdefs.ToGRPC(s.withStoreView(ctx, func(ctx context.Context, store images.Store) error {
|
||||
image, err := store.Get(ctx, req.Name)
|
||||
if err != nil {
|
||||
return mapGRPCError(err, req.Name)
|
||||
return err
|
||||
}
|
||||
imagepb := imageToProto(&image)
|
||||
resp.Image = &imagepb
|
||||
return nil
|
||||
})
|
||||
}))
|
||||
}
|
||||
|
||||
func (s *Service) Update(ctx context.Context, req *imagesapi.UpdateImageRequest) (*imagesapi.UpdateImageResponse, error) {
|
||||
if err := s.withStoreUpdate(ctx, func(ctx context.Context, store images.Store) error {
|
||||
return mapGRPCError(store.Update(ctx, req.Image.Name, descFromProto(&req.Image.Target)), req.Image.Name)
|
||||
return store.Update(ctx, req.Image.Name, descFromProto(&req.Image.Target))
|
||||
}); err != nil {
|
||||
return nil, err
|
||||
return nil, errdefs.ToGRPC(err)
|
||||
}
|
||||
|
||||
if err := s.emit(ctx, "/images/update", &eventsapi.ImageUpdate{
|
||||
@ -88,7 +89,7 @@ func (s *Service) List(ctx context.Context, _ *imagesapi.ListImagesRequest) (*im
|
||||
return &resp, s.withStoreView(ctx, func(ctx context.Context, store images.Store) error {
|
||||
images, err := store.List(ctx)
|
||||
if err != nil {
|
||||
return mapGRPCError(err, "")
|
||||
return errdefs.ToGRPC(err)
|
||||
}
|
||||
|
||||
resp.Images = imagesToProto(images)
|
||||
@ -98,7 +99,7 @@ func (s *Service) List(ctx context.Context, _ *imagesapi.ListImagesRequest) (*im
|
||||
|
||||
func (s *Service) Delete(ctx context.Context, req *imagesapi.DeleteImageRequest) (*empty.Empty, error) {
|
||||
if err := s.withStoreUpdate(ctx, func(ctx context.Context, store images.Store) error {
|
||||
return mapGRPCError(store.Delete(ctx, req.Name), req.Name)
|
||||
return errdefs.ToGRPC(store.Delete(ctx, req.Name))
|
||||
}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ import (
|
||||
"strings"
|
||||
|
||||
api "github.com/containerd/containerd/api/services/namespaces/v1"
|
||||
"github.com/containerd/containerd/errdefs"
|
||||
"github.com/containerd/containerd/namespaces"
|
||||
"github.com/gogo/protobuf/types"
|
||||
)
|
||||
@ -27,7 +28,7 @@ func (r *remote) Create(ctx context.Context, namespace string, labels map[string
|
||||
|
||||
_, err := r.client.Create(ctx, &req)
|
||||
if err != nil {
|
||||
return rewriteGRPCError(err)
|
||||
return errdefs.FromGRPC(err)
|
||||
}
|
||||
|
||||
return nil
|
||||
@ -39,7 +40,7 @@ func (r *remote) Labels(ctx context.Context, namespace string) (map[string]strin
|
||||
|
||||
resp, err := r.client.Get(ctx, &req)
|
||||
if err != nil {
|
||||
return nil, rewriteGRPCError(err)
|
||||
return nil, errdefs.FromGRPC(err)
|
||||
}
|
||||
|
||||
return resp.Namespace.Labels, nil
|
||||
@ -59,7 +60,7 @@ func (r *remote) SetLabel(ctx context.Context, namespace, key, value string) err
|
||||
|
||||
_, err := r.client.Update(ctx, &req)
|
||||
if err != nil {
|
||||
return rewriteGRPCError(err)
|
||||
return errdefs.FromGRPC(err)
|
||||
}
|
||||
|
||||
return nil
|
||||
@ -70,7 +71,7 @@ func (r *remote) List(ctx context.Context) ([]string, error) {
|
||||
|
||||
resp, err := r.client.List(ctx, &req)
|
||||
if err != nil {
|
||||
return nil, rewriteGRPCError(err)
|
||||
return nil, errdefs.FromGRPC(err)
|
||||
}
|
||||
|
||||
var namespaces []string
|
||||
@ -88,7 +89,7 @@ func (r *remote) Delete(ctx context.Context, namespace string) error {
|
||||
req.Name = namespace
|
||||
_, err := r.client.Delete(ctx, &req)
|
||||
if err != nil {
|
||||
return rewriteGRPCError(err)
|
||||
return errdefs.FromGRPC(err)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
@ -1,36 +0,0 @@
|
||||
package namespaces
|
||||
|
||||
import (
|
||||
"github.com/containerd/containerd/metadata"
|
||||
"github.com/pkg/errors"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/codes"
|
||||
)
|
||||
|
||||
func mapGRPCError(err error, id string) error {
|
||||
switch {
|
||||
case metadata.IsNotFound(err):
|
||||
return grpc.Errorf(codes.NotFound, "namespace %v not found", id)
|
||||
case metadata.IsExists(err):
|
||||
return grpc.Errorf(codes.AlreadyExists, "namespace %v already exists", id)
|
||||
case metadata.IsNotEmpty(err):
|
||||
return grpc.Errorf(codes.FailedPrecondition, "namespace %v must be empty", id)
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func rewriteGRPCError(err error) error {
|
||||
if err == nil {
|
||||
return err
|
||||
}
|
||||
|
||||
switch grpc.Code(errors.Cause(err)) {
|
||||
case codes.AlreadyExists:
|
||||
return metadata.ErrExists(grpc.ErrorDesc(err))
|
||||
case codes.NotFound:
|
||||
return metadata.ErrNotFound(grpc.ErrorDesc(err))
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
@ -6,6 +6,7 @@ import (
|
||||
"github.com/boltdb/bolt"
|
||||
eventsapi "github.com/containerd/containerd/api/services/events/v1"
|
||||
api "github.com/containerd/containerd/api/services/namespaces/v1"
|
||||
"github.com/containerd/containerd/errdefs"
|
||||
"github.com/containerd/containerd/events"
|
||||
"github.com/containerd/containerd/metadata"
|
||||
"github.com/containerd/containerd/namespaces"
|
||||
@ -59,7 +60,7 @@ func (s *Service) Get(ctx context.Context, req *api.GetNamespaceRequest) (*api.G
|
||||
return &resp, s.withStoreView(ctx, func(ctx context.Context, store namespaces.Store) error {
|
||||
labels, err := store.Labels(ctx, req.Name)
|
||||
if err != nil {
|
||||
return mapGRPCError(err, req.Name)
|
||||
return errdefs.ToGRPC(err)
|
||||
}
|
||||
|
||||
resp.Namespace = api.Namespace{
|
||||
@ -85,7 +86,7 @@ func (s *Service) List(ctx context.Context, req *api.ListNamespacesRequest) (*ap
|
||||
if err != nil {
|
||||
// In general, this should be unlikely, since we are holding a
|
||||
// transaction to service this request.
|
||||
return mapGRPCError(err, namespace)
|
||||
return errdefs.ToGRPC(err)
|
||||
}
|
||||
|
||||
resp.Namespaces = append(resp.Namespaces, api.Namespace{
|
||||
@ -103,7 +104,7 @@ func (s *Service) Create(ctx context.Context, req *api.CreateNamespaceRequest) (
|
||||
|
||||
if err := s.withStoreUpdate(ctx, func(ctx context.Context, store namespaces.Store) error {
|
||||
if err := store.Create(ctx, req.Namespace.Name, req.Namespace.Labels); err != nil {
|
||||
return mapGRPCError(err, req.Namespace.Name)
|
||||
return errdefs.ToGRPC(err)
|
||||
}
|
||||
|
||||
for k, v := range req.Namespace.Labels {
|
||||
@ -149,7 +150,7 @@ func (s *Service) Update(ctx context.Context, req *api.UpdateNamespaceRequest) (
|
||||
// get current set of labels
|
||||
labels, err := store.Labels(ctx, req.Namespace.Name)
|
||||
if err != nil {
|
||||
return mapGRPCError(err, req.Namespace.Name)
|
||||
return errdefs.ToGRPC(err)
|
||||
}
|
||||
|
||||
for k := range labels {
|
||||
@ -183,7 +184,7 @@ func (s *Service) Update(ctx context.Context, req *api.UpdateNamespaceRequest) (
|
||||
|
||||
func (s *Service) Delete(ctx context.Context, req *api.DeleteNamespaceRequest) (*empty.Empty, error) {
|
||||
if err := s.withStoreUpdate(ctx, func(ctx context.Context, store namespaces.Store) error {
|
||||
return mapGRPCError(store.Delete(ctx, req.Name), req.Name)
|
||||
return errdefs.ToGRPC(store.Delete(ctx, req.Name))
|
||||
}); err != nil {
|
||||
return &empty.Empty{}, err
|
||||
}
|
||||
|
@ -3,16 +3,12 @@ package snapshot
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"strings"
|
||||
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/codes"
|
||||
|
||||
snapshotapi "github.com/containerd/containerd/api/services/snapshot/v1"
|
||||
"github.com/containerd/containerd/api/types"
|
||||
"github.com/containerd/containerd/errdefs"
|
||||
"github.com/containerd/containerd/mount"
|
||||
"github.com/containerd/containerd/snapshot"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// NewSnapshotterFromClient returns a new Snapshotter which communicates
|
||||
@ -30,7 +26,7 @@ type remoteSnapshotter struct {
|
||||
func (r *remoteSnapshotter) Stat(ctx context.Context, key string) (snapshot.Info, error) {
|
||||
resp, err := r.client.Stat(ctx, &snapshotapi.StatSnapshotRequest{Key: key})
|
||||
if err != nil {
|
||||
return snapshot.Info{}, rewriteGRPCError(err)
|
||||
return snapshot.Info{}, errdefs.FromGRPC(err)
|
||||
}
|
||||
return toInfo(resp.Info), nil
|
||||
}
|
||||
@ -38,7 +34,7 @@ func (r *remoteSnapshotter) Stat(ctx context.Context, key string) (snapshot.Info
|
||||
func (r *remoteSnapshotter) Usage(ctx context.Context, key string) (snapshot.Usage, error) {
|
||||
resp, err := r.client.Usage(ctx, &snapshotapi.UsageRequest{Key: key})
|
||||
if err != nil {
|
||||
return snapshot.Usage{}, rewriteGRPCError(err)
|
||||
return snapshot.Usage{}, errdefs.FromGRPC(err)
|
||||
}
|
||||
return toUsage(resp), nil
|
||||
}
|
||||
@ -46,7 +42,7 @@ func (r *remoteSnapshotter) Usage(ctx context.Context, key string) (snapshot.Usa
|
||||
func (r *remoteSnapshotter) Mounts(ctx context.Context, key string) ([]mount.Mount, error) {
|
||||
resp, err := r.client.Mounts(ctx, &snapshotapi.MountsRequest{Key: key})
|
||||
if err != nil {
|
||||
return nil, rewriteGRPCError(err)
|
||||
return nil, errdefs.FromGRPC(err)
|
||||
}
|
||||
return toMounts(resp.Mounts), nil
|
||||
}
|
||||
@ -54,7 +50,7 @@ func (r *remoteSnapshotter) Mounts(ctx context.Context, key string) ([]mount.Mou
|
||||
func (r *remoteSnapshotter) Prepare(ctx context.Context, key, parent string) ([]mount.Mount, error) {
|
||||
resp, err := r.client.Prepare(ctx, &snapshotapi.PrepareSnapshotRequest{Key: key, Parent: parent})
|
||||
if err != nil {
|
||||
return nil, rewriteGRPCError(err)
|
||||
return nil, errdefs.FromGRPC(err)
|
||||
}
|
||||
return toMounts(resp.Mounts), nil
|
||||
}
|
||||
@ -62,7 +58,7 @@ func (r *remoteSnapshotter) Prepare(ctx context.Context, key, parent string) ([]
|
||||
func (r *remoteSnapshotter) View(ctx context.Context, key, parent string) ([]mount.Mount, error) {
|
||||
resp, err := r.client.View(ctx, &snapshotapi.ViewSnapshotRequest{Key: key, Parent: parent})
|
||||
if err != nil {
|
||||
return nil, rewriteGRPCError(err)
|
||||
return nil, errdefs.FromGRPC(err)
|
||||
}
|
||||
return toMounts(resp.Mounts), nil
|
||||
}
|
||||
@ -72,18 +68,18 @@ func (r *remoteSnapshotter) Commit(ctx context.Context, name, key string) error
|
||||
Name: name,
|
||||
Key: key,
|
||||
})
|
||||
return rewriteGRPCError(err)
|
||||
return errdefs.FromGRPC(err)
|
||||
}
|
||||
|
||||
func (r *remoteSnapshotter) Remove(ctx context.Context, key string) error {
|
||||
_, err := r.client.Remove(ctx, &snapshotapi.RemoveSnapshotRequest{Key: key})
|
||||
return rewriteGRPCError(err)
|
||||
return errdefs.FromGRPC(err)
|
||||
}
|
||||
|
||||
func (r *remoteSnapshotter) Walk(ctx context.Context, fn func(context.Context, snapshot.Info) error) error {
|
||||
sc, err := r.client.List(ctx, &snapshotapi.ListSnapshotsRequest{})
|
||||
if err != nil {
|
||||
rewriteGRPCError(err)
|
||||
errdefs.FromGRPC(err)
|
||||
}
|
||||
for {
|
||||
resp, err := sc.Recv()
|
||||
@ -91,7 +87,7 @@ func (r *remoteSnapshotter) Walk(ctx context.Context, fn func(context.Context, s
|
||||
if err == io.EOF {
|
||||
return nil
|
||||
}
|
||||
return rewriteGRPCError(err)
|
||||
return errdefs.FromGRPC(err)
|
||||
}
|
||||
if resp == nil {
|
||||
return nil
|
||||
@ -104,25 +100,6 @@ func (r *remoteSnapshotter) Walk(ctx context.Context, fn func(context.Context, s
|
||||
}
|
||||
}
|
||||
|
||||
func rewriteGRPCError(err error) error {
|
||||
switch grpc.Code(errors.Cause(err)) {
|
||||
case codes.AlreadyExists:
|
||||
return snapshot.ErrSnapshotExist
|
||||
case codes.NotFound:
|
||||
return snapshot.ErrSnapshotNotExist
|
||||
case codes.FailedPrecondition:
|
||||
desc := grpc.ErrorDesc(errors.Cause(err))
|
||||
if strings.Contains(desc, snapshot.ErrSnapshotNotActive.Error()) {
|
||||
return snapshot.ErrSnapshotNotActive
|
||||
}
|
||||
if strings.Contains(desc, snapshot.ErrSnapshotNotCommitted.Error()) {
|
||||
return snapshot.ErrSnapshotNotCommitted
|
||||
}
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func toKind(kind snapshotapi.Kind) snapshot.Kind {
|
||||
if kind == snapshotapi.KindActive {
|
||||
return snapshot.KindActive
|
||||
|
@ -6,6 +6,7 @@ import (
|
||||
eventsapi "github.com/containerd/containerd/api/services/events/v1"
|
||||
snapshotapi "github.com/containerd/containerd/api/services/snapshot/v1"
|
||||
"github.com/containerd/containerd/api/types"
|
||||
"github.com/containerd/containerd/errdefs"
|
||||
"github.com/containerd/containerd/events"
|
||||
"github.com/containerd/containerd/log"
|
||||
"github.com/containerd/containerd/mount"
|
||||
@ -14,7 +15,6 @@ import (
|
||||
protoempty "github.com/golang/protobuf/ptypes/empty"
|
||||
"golang.org/x/net/context"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/codes"
|
||||
)
|
||||
|
||||
func init() {
|
||||
@ -60,7 +60,7 @@ func (s *service) Prepare(ctx context.Context, pr *snapshotapi.PrepareSnapshotRe
|
||||
// TODO: Lookup snapshot id from metadata store
|
||||
mounts, err := s.snapshotter.Prepare(ctx, pr.Key, pr.Parent)
|
||||
if err != nil {
|
||||
return nil, grpcError(err)
|
||||
return nil, errdefs.ToGRPC(err)
|
||||
}
|
||||
|
||||
if err := s.emit(ctx, "/snapshot/prepare", &eventsapi.SnapshotPrepare{
|
||||
@ -80,7 +80,7 @@ func (s *service) View(ctx context.Context, pr *snapshotapi.ViewSnapshotRequest)
|
||||
// TODO: Lookup snapshot id from metadata store
|
||||
mounts, err := s.snapshotter.View(ctx, pr.Key, pr.Parent)
|
||||
if err != nil {
|
||||
return nil, grpcError(err)
|
||||
return nil, errdefs.ToGRPC(err)
|
||||
}
|
||||
return &snapshotapi.ViewSnapshotResponse{
|
||||
Mounts: fromMounts(mounts),
|
||||
@ -93,7 +93,7 @@ func (s *service) Mounts(ctx context.Context, mr *snapshotapi.MountsRequest) (*s
|
||||
// TODO: Lookup snapshot id from metadata store
|
||||
mounts, err := s.snapshotter.Mounts(ctx, mr.Key)
|
||||
if err != nil {
|
||||
return nil, grpcError(err)
|
||||
return nil, errdefs.ToGRPC(err)
|
||||
}
|
||||
return &snapshotapi.MountsResponse{
|
||||
Mounts: fromMounts(mounts),
|
||||
@ -105,7 +105,7 @@ func (s *service) Commit(ctx context.Context, cr *snapshotapi.CommitSnapshotRequ
|
||||
// TODO: Apply namespace
|
||||
// TODO: Lookup snapshot id from metadata store
|
||||
if err := s.snapshotter.Commit(ctx, cr.Name, cr.Key); err != nil {
|
||||
return nil, grpcError(err)
|
||||
return nil, errdefs.ToGRPC(err)
|
||||
}
|
||||
|
||||
if err := s.emit(ctx, "/snapshot/commit", &eventsapi.SnapshotCommit{
|
||||
@ -122,7 +122,7 @@ func (s *service) Remove(ctx context.Context, rr *snapshotapi.RemoveSnapshotRequ
|
||||
// TODO: Apply namespace
|
||||
// TODO: Lookup snapshot id from metadata store
|
||||
if err := s.snapshotter.Remove(ctx, rr.Key); err != nil {
|
||||
return nil, grpcError(err)
|
||||
return nil, errdefs.ToGRPC(err)
|
||||
}
|
||||
|
||||
if err := s.emit(ctx, "/snapshot/remove", &eventsapi.SnapshotRemove{
|
||||
@ -138,7 +138,7 @@ func (s *service) Stat(ctx context.Context, sr *snapshotapi.StatSnapshotRequest)
|
||||
// TODO: Apply namespace
|
||||
info, err := s.snapshotter.Stat(ctx, sr.Key)
|
||||
if err != nil {
|
||||
return nil, grpcError(err)
|
||||
return nil, errdefs.ToGRPC(err)
|
||||
}
|
||||
|
||||
return &snapshotapi.StatSnapshotResponse{Info: fromInfo(info)}, nil
|
||||
@ -184,26 +184,12 @@ func (s *service) Usage(ctx context.Context, ur *snapshotapi.UsageRequest) (*sna
|
||||
// TODO: Apply namespace
|
||||
usage, err := s.snapshotter.Usage(ctx, ur.Key)
|
||||
if err != nil {
|
||||
return nil, grpcError(err)
|
||||
return nil, errdefs.ToGRPC(err)
|
||||
}
|
||||
|
||||
return fromUsage(usage), nil
|
||||
}
|
||||
|
||||
func grpcError(err error) error {
|
||||
if snapshot.IsNotExist(err) {
|
||||
return grpc.Errorf(codes.NotFound, err.Error())
|
||||
}
|
||||
if snapshot.IsExist(err) {
|
||||
return grpc.Errorf(codes.AlreadyExists, err.Error())
|
||||
}
|
||||
if snapshot.IsNotActive(err) || snapshot.IsNotCommitted(err) {
|
||||
return grpc.Errorf(codes.FailedPrecondition, err.Error())
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func fromKind(kind snapshot.Kind) snapshotapi.Kind {
|
||||
if kind == snapshot.KindActive {
|
||||
return snapshotapi.KindActive
|
||||
|
@ -16,6 +16,7 @@ import (
|
||||
"github.com/containerd/containerd/archive"
|
||||
"github.com/containerd/containerd/containers"
|
||||
"github.com/containerd/containerd/content"
|
||||
"github.com/containerd/containerd/errdefs"
|
||||
"github.com/containerd/containerd/events"
|
||||
"github.com/containerd/containerd/images"
|
||||
"github.com/containerd/containerd/log"
|
||||
@ -37,6 +38,9 @@ var (
|
||||
empty = &google_protobuf.Empty{}
|
||||
)
|
||||
|
||||
// TODO(stevvooe): Clean up error mapping to avoid double mapping certain
|
||||
// errors within helper methods.
|
||||
|
||||
func init() {
|
||||
plugin.Register(&plugin.Registration{
|
||||
Type: plugin.GRPCPlugin,
|
||||
@ -115,14 +119,7 @@ func (s *Service) Create(ctx context.Context, r *api.CreateTaskRequest) (*api.Cr
|
||||
|
||||
container, err := s.getContainer(ctx, r.ContainerID)
|
||||
if err != nil {
|
||||
switch {
|
||||
case metadata.IsNotFound(err):
|
||||
return nil, grpc.Errorf(codes.NotFound, "container %v not found", r.ContainerID)
|
||||
case metadata.IsExists(err):
|
||||
return nil, grpc.Errorf(codes.AlreadyExists, "container %v already exists", r.ContainerID)
|
||||
}
|
||||
|
||||
return nil, err
|
||||
return nil, errdefs.ToGRPC(err)
|
||||
}
|
||||
|
||||
opts := runtime.CreateOpts{
|
||||
@ -484,7 +481,7 @@ func (s *Service) getContainer(ctx context.Context, id string) (containers.Conta
|
||||
container, err = store.Get(ctx, id)
|
||||
return err
|
||||
}); err != nil {
|
||||
return containers.Container{}, err
|
||||
return containers.Container{}, errdefs.ToGRPC(err)
|
||||
}
|
||||
|
||||
return container, nil
|
||||
@ -493,12 +490,12 @@ func (s *Service) getContainer(ctx context.Context, id string) (containers.Conta
|
||||
func (s *Service) getTask(ctx context.Context, id string) (runtime.Task, error) {
|
||||
container, err := s.getContainer(ctx, id)
|
||||
if err != nil {
|
||||
return nil, grpc.Errorf(codes.InvalidArgument, "task %v not found: %s", id, err.Error())
|
||||
return nil, err
|
||||
}
|
||||
|
||||
runtime, err := s.getRuntime(container.Runtime.Name)
|
||||
if err != nil {
|
||||
return nil, grpc.Errorf(codes.NotFound, "task %v not found: %s", id, err.Error())
|
||||
return nil, errdefs.ToGRPCf(err, "runtime for task %v", id)
|
||||
}
|
||||
|
||||
t, err := runtime.Get(ctx, id)
|
||||
@ -512,7 +509,7 @@ func (s *Service) getTask(ctx context.Context, id string) (runtime.Task, error)
|
||||
func (s *Service) getRuntime(name string) (runtime.Runtime, error) {
|
||||
runtime, ok := s.runtimes[name]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("unknown runtime %q", name)
|
||||
return nil, grpc.Errorf(codes.NotFound, "unknown runtime %q", name)
|
||||
}
|
||||
return runtime, nil
|
||||
}
|
||||
|
@ -1,44 +0,0 @@
|
||||
package snapshot
|
||||
|
||||
import "github.com/pkg/errors"
|
||||
|
||||
var (
|
||||
// ErrSnapshotNotExist is returned when a snapshot cannot be found
|
||||
ErrSnapshotNotExist = errors.New("snapshot does not exist")
|
||||
|
||||
// ErrSnapshotExist is returned when an operation to create a snapshot
|
||||
// encounters a snapshot with the same key
|
||||
ErrSnapshotExist = errors.New("snapshot already exists")
|
||||
|
||||
// ErrSnapshotNotActive is returned when a request which requires an
|
||||
// active snapshot encounters a non-active snapshot.
|
||||
ErrSnapshotNotActive = errors.New("snapshot is not active")
|
||||
|
||||
// ErrSnapshotNotCommitted is returned when a request which requires a
|
||||
// committed snapshot encounters a non-committed snapshot.
|
||||
ErrSnapshotNotCommitted = errors.New("snapshot is not committed")
|
||||
)
|
||||
|
||||
// IsNotExist returns whether the error represents that a snapshot
|
||||
// was not found.
|
||||
func IsNotExist(err error) bool {
|
||||
return errors.Cause(err) == ErrSnapshotNotExist
|
||||
}
|
||||
|
||||
// IsExist returns whether the error represents whether a snapshot
|
||||
// already exists using a provided key.
|
||||
func IsExist(err error) bool {
|
||||
return errors.Cause(err) == ErrSnapshotExist
|
||||
}
|
||||
|
||||
// IsNotActive returns whether the error represents a request
|
||||
// for a non active snapshot when an active snapshot is expected.
|
||||
func IsNotActive(err error) bool {
|
||||
return errors.Cause(err) == ErrSnapshotNotActive
|
||||
}
|
||||
|
||||
// IsNotCommitted returns whether the error represents a request
|
||||
// for a non committed snapshot when a committed snapshot is expected.
|
||||
func IsNotCommitted(err error) bool {
|
||||
return errors.Cause(err) == ErrSnapshotNotCommitted
|
||||
}
|
@ -6,6 +6,7 @@ import (
|
||||
"fmt"
|
||||
|
||||
"github.com/boltdb/bolt"
|
||||
"github.com/containerd/containerd/errdefs"
|
||||
"github.com/containerd/containerd/namespaces"
|
||||
"github.com/containerd/containerd/snapshot"
|
||||
db "github.com/containerd/containerd/snapshot/storage/proto"
|
||||
@ -129,12 +130,12 @@ func CreateActive(ctx context.Context, key, parent string, readonly bool) (a Act
|
||||
}
|
||||
|
||||
if parentS.Kind != db.KindCommitted {
|
||||
return errors.Wrap(snapshot.ErrSnapshotNotCommitted, "parent is not committed snapshot")
|
||||
return errors.Wrap(errdefs.ErrInvalidArgument, "parent is not committed snapshot")
|
||||
}
|
||||
}
|
||||
b := bkt.Get([]byte(key))
|
||||
if len(b) != 0 {
|
||||
return snapshot.ErrSnapshotExist
|
||||
return errors.Wrapf(errdefs.ErrAlreadyExists, "snapshot %v", key)
|
||||
}
|
||||
|
||||
id, err := nextSequence(ctx)
|
||||
@ -183,7 +184,7 @@ func GetActive(ctx context.Context, key string) (a Active, err error) {
|
||||
err = withBucket(ctx, func(ctx context.Context, bkt, pbkt *bolt.Bucket) error {
|
||||
b := bkt.Get([]byte(key))
|
||||
if len(b) == 0 {
|
||||
return snapshot.ErrSnapshotNotExist
|
||||
return errors.Wrapf(errdefs.ErrNotFound, "snapshot %v", key)
|
||||
}
|
||||
|
||||
var ss db.Snapshot
|
||||
@ -191,7 +192,7 @@ func GetActive(ctx context.Context, key string) (a Active, err error) {
|
||||
return errors.Wrap(err, "failed to unmarshal snapshot")
|
||||
}
|
||||
if ss.Kind != db.KindActive {
|
||||
return snapshot.ErrSnapshotNotActive
|
||||
return errors.Wrapf(errdefs.ErrFailedPrecondition, "requested snapshot %v not active", key)
|
||||
}
|
||||
|
||||
a.ID = fmt.Sprintf("%d", ss.ID)
|
||||
@ -225,7 +226,7 @@ func Remove(ctx context.Context, key string) (id string, k snapshot.Kind, err er
|
||||
var ss db.Snapshot
|
||||
b := bkt.Get([]byte(key))
|
||||
if len(b) == 0 {
|
||||
return snapshot.ErrSnapshotNotExist
|
||||
return errors.Wrapf(errdefs.ErrNotFound, "snapshot %v", key)
|
||||
}
|
||||
|
||||
if err := proto.Unmarshal(b, &ss); err != nil {
|
||||
@ -273,7 +274,7 @@ func CommitActive(ctx context.Context, key, name string, usage snapshot.Usage) (
|
||||
err = withBucket(ctx, func(ctx context.Context, bkt, pbkt *bolt.Bucket) error {
|
||||
b := bkt.Get([]byte(name))
|
||||
if len(b) != 0 {
|
||||
return errors.Wrap(snapshot.ErrSnapshotExist, "committed name already exists")
|
||||
return errors.Wrapf(errdefs.ErrAlreadyExists, "committed snapshot %v", name)
|
||||
}
|
||||
|
||||
var ss db.Snapshot
|
||||
@ -281,7 +282,7 @@ func CommitActive(ctx context.Context, key, name string, usage snapshot.Usage) (
|
||||
return errors.Wrap(err, "failed to get active snapshot")
|
||||
}
|
||||
if ss.Kind != db.KindActive {
|
||||
return snapshot.ErrSnapshotNotActive
|
||||
return errors.Wrapf(errdefs.ErrFailedPrecondition, "snapshot %v is not active", name)
|
||||
}
|
||||
if ss.Readonly {
|
||||
return errors.Errorf("active snapshot is readonly")
|
||||
@ -340,12 +341,12 @@ func withBucket(ctx context.Context, fn func(context.Context, *bolt.Bucket, *bol
|
||||
}
|
||||
nbkt := t.tx.Bucket(bucketKeyStorageVersion)
|
||||
if nbkt == nil {
|
||||
return errors.Wrap(snapshot.ErrSnapshotNotExist, "bucket does not exist")
|
||||
return errors.Wrapf(errdefs.ErrNotFound, "bucket does not exist")
|
||||
}
|
||||
|
||||
bkt := nbkt.Bucket([]byte(namespace))
|
||||
if bkt == nil {
|
||||
return errors.Wrap(snapshot.ErrSnapshotNotExist, "namespace not available in snapshotter")
|
||||
return errors.Wrapf(errdefs.ErrNotFound, "namespace not available in snapshotter")
|
||||
}
|
||||
|
||||
return fn(ctx, bkt.Bucket(bucketKeySnapshot), bkt.Bucket(bucketKeyParents))
|
||||
@ -409,7 +410,7 @@ func parents(bkt *bolt.Bucket, parent *db.Snapshot) (parents []string, err error
|
||||
func getSnapshot(bkt *bolt.Bucket, key string, ss *db.Snapshot) error {
|
||||
b := bkt.Get([]byte(key))
|
||||
if len(b) == 0 {
|
||||
return snapshot.ErrSnapshotNotExist
|
||||
return errors.Wrapf(errdefs.ErrNotFound, "snapshot %v", key)
|
||||
}
|
||||
if err := proto.Unmarshal(b, ss); err != nil {
|
||||
return errors.Wrap(err, "failed to unmarshal snapshot")
|
||||
|
@ -6,6 +6,7 @@ import (
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/containerd/containerd/errdefs"
|
||||
"github.com/containerd/containerd/namespaces"
|
||||
"github.com/containerd/containerd/snapshot"
|
||||
"github.com/pkg/errors"
|
||||
@ -205,7 +206,7 @@ func assertNotExist(t *testing.T, err error) {
|
||||
if err == nil {
|
||||
t.Fatal("Expected not exist error")
|
||||
}
|
||||
if !snapshot.IsNotExist(err) {
|
||||
if !errdefs.IsNotFound(err) {
|
||||
t.Fatalf("Expected not exist error, got %+v", err)
|
||||
}
|
||||
}
|
||||
@ -214,7 +215,7 @@ func assertNotActive(t *testing.T, err error) {
|
||||
if err == nil {
|
||||
t.Fatal("Expected not active error")
|
||||
}
|
||||
if !snapshot.IsNotActive(err) {
|
||||
if !errdefs.IsFailedPrecondition(err) {
|
||||
t.Fatalf("Expected not active error, got %+v", err)
|
||||
}
|
||||
}
|
||||
@ -223,7 +224,7 @@ func assertNotCommitted(t *testing.T, err error) {
|
||||
if err == nil {
|
||||
t.Fatal("Expected active error")
|
||||
}
|
||||
if !snapshot.IsNotCommitted(err) {
|
||||
if !errdefs.IsInvalidArgument(err) {
|
||||
t.Fatalf("Expected active error, got %+v", err)
|
||||
}
|
||||
}
|
||||
@ -232,7 +233,7 @@ func assertExist(t *testing.T, err error) {
|
||||
if err == nil {
|
||||
t.Fatal("Expected exist error")
|
||||
}
|
||||
if !snapshot.IsExist(err) {
|
||||
if !errdefs.IsAlreadyExists(err) {
|
||||
t.Fatalf("Expected exist error, got %+v", err)
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user