From a39256e9bf9c692eec703685d54b2c8a454140b6 Mon Sep 17 00:00:00 2001 From: Akihiro Suda Date: Tue, 23 Jan 2018 11:21:15 +0900 Subject: [PATCH] update containerd (binary: v1.0.1, library: Jan 23, 2018) Signed-off-by: Akihiro Suda --- README.md | 2 +- examples/buildkit0/buildkit.go | 2 +- examples/buildkit1/buildkit.go | 2 +- examples/buildkit2/buildkit.go | 2 +- examples/buildkit3/buildkit.go | 2 +- hack/dockerfiles/test.Dockerfile | 2 +- vendor.conf | 4 +- .../containerd/containerd/archive/tar.go | 11 ++ .../containerd/containerd/cio/io.go | 18 ++- .../containerd/containerd/client.go | 6 +- .../containerd/defaults/defaults_unix.go | 19 +++ .../containerd/defaults/defaults_windows.go | 27 ++++ .../containerd/containerd/defaults/doc.go | 3 + .../containerd/containerd/dialer/dialer.go | 2 +- .../containerd/containerd/fs/copy_linux.go | 15 ++- .../containerd/containerd/fs/copy_unix.go | 15 ++- .../containerd/containerd/log/context.go | 41 ------ .../containerd/containerd/metadata/buckets.go | 13 +- .../containerd/containerd/metadata/images.go | 125 ++++++++++++------ .../containerd/metadata/namespaces.go | 49 ++++--- .../containerd/containerd/oci/spec_opts.go | 57 ++++++++ .../containerd/oci/spec_opts_unix.go | 122 ++++++++++------- .../containerd/containerd/plugin/context.go | 3 +- 23 files changed, 365 insertions(+), 177 deletions(-) create mode 100644 vendor/github.com/containerd/containerd/defaults/defaults_unix.go create mode 100644 vendor/github.com/containerd/containerd/defaults/defaults_windows.go create mode 100644 vendor/github.com/containerd/containerd/defaults/doc.go diff --git a/README.md b/README.md index fbe1f5f73..9217f0f28 100644 --- a/README.md +++ b/README.md @@ -211,7 +211,7 @@ export JAEGER_TRACE=0.0.0.0:6831 ### Supported runc version -During development, BuildKit is tested with the version of runc that is being used by the containerd repository. Please refer to [runc.md](https://github.com/containerd/containerd/blob/v1.0.1-rc.0/RUNC.md) for more information. +During development, BuildKit is tested with the version of runc that is being used by the containerd repository. Please refer to [runc.md](https://github.com/containerd/containerd/blob/v1.0.1/RUNC.md) for more information. ### Contributing diff --git a/examples/buildkit0/buildkit.go b/examples/buildkit0/buildkit.go index 186c03ea4..646f03a0a 100644 --- a/examples/buildkit0/buildkit.go +++ b/examples/buildkit0/buildkit.go @@ -17,7 +17,7 @@ type buildOpt struct { func main() { var opt buildOpt flag.BoolVar(&opt.withContainerd, "with-containerd", true, "enable containerd worker") - flag.StringVar(&opt.containerd, "containerd", "v1.0.1-rc.0", "containerd version") + flag.StringVar(&opt.containerd, "containerd", "v1.0.1", "containerd version") flag.StringVar(&opt.runc, "runc", "7f24b40cc5423969b4554ef04ba0b00e2b4ba010", "runc version") flag.Parse() diff --git a/examples/buildkit1/buildkit.go b/examples/buildkit1/buildkit.go index 841b366e0..b8e943dd5 100644 --- a/examples/buildkit1/buildkit.go +++ b/examples/buildkit1/buildkit.go @@ -17,7 +17,7 @@ type buildOpt struct { func main() { var opt buildOpt flag.BoolVar(&opt.withContainerd, "with-containerd", true, "enable containerd worker") - flag.StringVar(&opt.containerd, "containerd", "v1.0.1-rc.0", "containerd version") + flag.StringVar(&opt.containerd, "containerd", "v1.0.1", "containerd version") flag.StringVar(&opt.runc, "runc", "7f24b40cc5423969b4554ef04ba0b00e2b4ba010", "runc version") flag.Parse() diff --git a/examples/buildkit2/buildkit.go b/examples/buildkit2/buildkit.go index 524f3c6b9..953da7452 100644 --- a/examples/buildkit2/buildkit.go +++ b/examples/buildkit2/buildkit.go @@ -17,7 +17,7 @@ type buildOpt struct { func main() { var opt buildOpt flag.BoolVar(&opt.withContainerd, "with-containerd", true, "enable containerd worker") - flag.StringVar(&opt.containerd, "containerd", "v1.0.1-rc.0", "containerd version") + flag.StringVar(&opt.containerd, "containerd", "v1.0.1", "containerd version") flag.StringVar(&opt.runc, "runc", "7f24b40cc5423969b4554ef04ba0b00e2b4ba010", "runc version") flag.Parse() diff --git a/examples/buildkit3/buildkit.go b/examples/buildkit3/buildkit.go index dc7b0f4da..6ba79e096 100644 --- a/examples/buildkit3/buildkit.go +++ b/examples/buildkit3/buildkit.go @@ -18,7 +18,7 @@ type buildOpt struct { func main() { var opt buildOpt flag.BoolVar(&opt.withContainerd, "with-containerd", true, "enable containerd worker") - flag.StringVar(&opt.containerd, "containerd", "v1.0.1-rc.0", "containerd version") + flag.StringVar(&opt.containerd, "containerd", "v1.0.1", "containerd version") flag.StringVar(&opt.runc, "runc", "7f24b40cc5423969b4554ef04ba0b00e2b4ba010", "runc version") flag.StringVar(&opt.buildkit, "buildkit", "master", "buildkit version") flag.Parse() diff --git a/hack/dockerfiles/test.Dockerfile b/hack/dockerfiles/test.Dockerfile index 200b28af1..fce94ca47 100644 --- a/hack/dockerfiles/test.Dockerfile +++ b/hack/dockerfiles/test.Dockerfile @@ -1,5 +1,5 @@ ARG RUNC_VERSION=7f24b40cc5423969b4554ef04ba0b00e2b4ba010 -ARG CONTAINERD_VERSION=v1.0.1-rc.0 +ARG CONTAINERD_VERSION=v1.0.1 # available targets: buildkitd, buildkitd.oci_only, buildkitd.containerd_only ARG BUILDKIT_TARGET=buildkitd ARG REGISTRY_VERSION=2.6 diff --git a/vendor.conf b/vendor.conf index 3a89b7e8d..9c0b928b7 100644 --- a/vendor.conf +++ b/vendor.conf @@ -6,7 +6,7 @@ github.com/davecgh/go-spew v1.1.0 github.com/pmezard/go-difflib v1.0.0 golang.org/x/sys 9aade4d3a3b7e6d876cd3823ad20ec45fc035402 # update to 7ddbeae9ae08c6a06a59597f0c9edbc5ff2444ce wiht pkg/signal change -github.com/containerd/containerd 90553efdef0678b2609aed74926a487f8ff58d1a +github.com/containerd/containerd dc5964ccc2a3c5dddeef806efaab0d905aec96ed github.com/containerd/typeurl f6943554a7e7e88b3c14aad190bf05932da84788 golang.org/x/sync 450f422ab23cf9881c94e2db30cac0eb1b7cf80c github.com/sirupsen/logrus v1.0.0 @@ -57,4 +57,4 @@ github.com/apache/thrift b2a4d4ae21c789b689dd162deb819665567f481c github.com/uber/jaeger-lib c48167d9cae5887393dd5e61efd06a4a48b7fbb3 github.com/codahale/hdrhistogram f8ad88b59a584afeee9d334eff879b104439117b -github.com/opentracing-contrib/go-stdlib b1a47cfbdd7543e70e9ef3e73d0802ad306cc1cc \ No newline at end of file +github.com/opentracing-contrib/go-stdlib b1a47cfbdd7543e70e9ef3e73d0802ad306cc1cc diff --git a/vendor/github.com/containerd/containerd/archive/tar.go b/vendor/github.com/containerd/containerd/archive/tar.go index 99cfc35fc..0e32d7105 100644 --- a/vendor/github.com/containerd/containerd/archive/tar.go +++ b/vendor/github.com/containerd/containerd/archive/tar.go @@ -26,6 +26,8 @@ var bufferPool = &sync.Pool{ }, } +var errInvalidArchive = errors.New("invalid archive") + // Diff returns a tar stream of the computed filesystem // difference between the provided directories. // @@ -231,6 +233,15 @@ func applyNaive(ctx context.Context, root string, tr *tar.Reader, options ApplyO originalBase := base[len(whiteoutPrefix):] originalPath := filepath.Join(dir, originalBase) + + // Ensure originalPath is under dir + if dir[len(dir)-1] != filepath.Separator { + dir += string(filepath.Separator) + } + if !strings.HasPrefix(originalPath, dir) { + return 0, errors.Wrapf(errInvalidArchive, "invalid whiteout name: %v", base) + } + if err := os.RemoveAll(originalPath); err != nil { return 0, err } diff --git a/vendor/github.com/containerd/containerd/cio/io.go b/vendor/github.com/containerd/containerd/cio/io.go index 1b4a4dc25..e337c5870 100644 --- a/vendor/github.com/containerd/containerd/cio/io.go +++ b/vendor/github.com/containerd/containerd/cio/io.go @@ -6,6 +6,8 @@ import ( "io" "os" "sync" + + "github.com/containerd/containerd/defaults" ) // Config holds the IO configurations. @@ -68,6 +70,7 @@ type Streams struct { Stdout io.Writer Stderr io.Writer Terminal bool + FIFODir string } // Opt customize options for creating a Creator or Attach @@ -92,16 +95,25 @@ func WithStreams(stdin io.Reader, stdout, stderr io.Writer) Opt { } } +// WithFIFODir sets the fifo directory. +// e.g. "/run/containerd/fifo", "/run/users/1001/containerd/fifo" +func WithFIFODir(dir string) Opt { + return func(opt *Streams) { + opt.FIFODir = dir + } +} + // NewCreator returns an IO creator from the options func NewCreator(opts ...Opt) Creator { streams := &Streams{} for _, opt := range opts { opt(streams) } + if streams.FIFODir == "" { + streams.FIFODir = defaults.DefaultFIFODir + } return func(id string) (IO, error) { - // TODO: accept root as a param - root := "/run/containerd/fifo" - fifos, err := NewFIFOSetInDir(root, id, streams.Terminal) + fifos, err := NewFIFOSetInDir(streams.FIFODir, id, streams.Terminal) if err != nil { return nil, err } diff --git a/vendor/github.com/containerd/containerd/client.go b/vendor/github.com/containerd/containerd/client.go index 39547f589..8b02c73ee 100644 --- a/vendor/github.com/containerd/containerd/client.go +++ b/vendor/github.com/containerd/containerd/client.go @@ -222,11 +222,11 @@ func (c *Client) Pull(ctx context.Context, ref string, opts ...RemoteOpt) (Image name, desc, err := pullCtx.Resolver.Resolve(ctx, ref) if err != nil { - return nil, err + return nil, errors.Wrapf(err, "failed to resolve reference %q", ref) } fetcher, err := pullCtx.Resolver.Fetcher(ctx, name) if err != nil { - return nil, err + return nil, errors.Wrapf(err, "failed to get fetcher for %q", name) } var ( @@ -281,7 +281,7 @@ func (c *Client) Pull(ctx context.Context, ref string, opts ...RemoteOpt) (Image } if pullCtx.Unpack { if err := img.Unpack(ctx, pullCtx.Snapshotter); err != nil { - return nil, err + errors.Wrapf(err, "failed to unpack image on snapshotter %s", pullCtx.Snapshotter) } } return img, nil diff --git a/vendor/github.com/containerd/containerd/defaults/defaults_unix.go b/vendor/github.com/containerd/containerd/defaults/defaults_unix.go new file mode 100644 index 000000000..1a76d569f --- /dev/null +++ b/vendor/github.com/containerd/containerd/defaults/defaults_unix.go @@ -0,0 +1,19 @@ +// +build !windows + +package defaults + +const ( + // DefaultRootDir is the default location used by containerd to store + // persistent data + DefaultRootDir = "/var/lib/containerd" + // DefaultStateDir is the default location used by containerd to store + // transient data + DefaultStateDir = "/run/containerd" + // DefaultAddress is the default unix socket address + DefaultAddress = "/run/containerd/containerd.sock" + // DefaultDebugAddress is the default unix socket address for pprof data + DefaultDebugAddress = "/run/containerd/debug.sock" + // DefaultFIFODir is the default location used by client-side cio library + // to store FIFOs. + DefaultFIFODir = "/run/containerd/fifo" +) diff --git a/vendor/github.com/containerd/containerd/defaults/defaults_windows.go b/vendor/github.com/containerd/containerd/defaults/defaults_windows.go new file mode 100644 index 000000000..7d74d22e4 --- /dev/null +++ b/vendor/github.com/containerd/containerd/defaults/defaults_windows.go @@ -0,0 +1,27 @@ +// +build windows + +package defaults + +import ( + "os" + "path/filepath" +) + +var ( + // DefaultRootDir is the default location used by containerd to store + // persistent data + DefaultRootDir = filepath.Join(os.Getenv("programfiles"), "containerd", "root") + // DefaultStateDir is the default location used by containerd to store + // transient data + DefaultStateDir = filepath.Join(os.Getenv("programfiles"), "containerd", "state") +) + +const ( + // DefaultAddress is the default winpipe address + DefaultAddress = `\\.\pipe\containerd-containerd` + // DefaultDebugAddress is the default winpipe address for pprof data + DefaultDebugAddress = `\\.\pipe\containerd-debug` + // DefaultFIFODir is the default location used by client-side cio library + // to store FIFOs. Unused on Windows. + DefaultFIFODir = "" +) diff --git a/vendor/github.com/containerd/containerd/defaults/doc.go b/vendor/github.com/containerd/containerd/defaults/doc.go new file mode 100644 index 000000000..2c6e39f55 --- /dev/null +++ b/vendor/github.com/containerd/containerd/defaults/doc.go @@ -0,0 +1,3 @@ +// Package defaults provides several common defaults for interacting wtih +// containerd. These can be used on the client-side or server-side. +package defaults diff --git a/vendor/github.com/containerd/containerd/dialer/dialer.go b/vendor/github.com/containerd/containerd/dialer/dialer.go index 65af69f9b..1ad4ab718 100644 --- a/vendor/github.com/containerd/containerd/dialer/dialer.go +++ b/vendor/github.com/containerd/containerd/dialer/dialer.go @@ -42,7 +42,7 @@ func Dialer(address string, timeout time.Duration) (net.Conn, error) { close(stopC) go func() { dr := <-synC - if dr != nil { + if dr != nil && dr.c != nil { dr.c.Close() } }() diff --git a/vendor/github.com/containerd/containerd/fs/copy_linux.go b/vendor/github.com/containerd/containerd/fs/copy_linux.go index c1fb2d1c4..47272963b 100644 --- a/vendor/github.com/containerd/containerd/fs/copy_linux.go +++ b/vendor/github.com/containerd/containerd/fs/copy_linux.go @@ -14,7 +14,20 @@ import ( func copyFileInfo(fi os.FileInfo, name string) error { st := fi.Sys().(*syscall.Stat_t) if err := os.Lchown(name, int(st.Uid), int(st.Gid)); err != nil { - return errors.Wrapf(err, "failed to chown %s", name) + if os.IsPermission(err) { + // Normally if uid/gid are the same this would be a no-op, but some + // filesystems may still return EPERM... for instance NFS does this. + // In such a case, this is not an error. + if dstStat, err2 := os.Lstat(name); err2 == nil { + st2 := dstStat.Sys().(*syscall.Stat_t) + if st.Uid == st2.Uid && st.Gid == st2.Gid { + err = nil + } + } + } + if err != nil { + return errors.Wrapf(err, "failed to chown %s", name) + } } if (fi.Mode() & os.ModeSymlink) != os.ModeSymlink { diff --git a/vendor/github.com/containerd/containerd/fs/copy_unix.go b/vendor/github.com/containerd/containerd/fs/copy_unix.go index b31a14fcd..fceb0e63a 100644 --- a/vendor/github.com/containerd/containerd/fs/copy_unix.go +++ b/vendor/github.com/containerd/containerd/fs/copy_unix.go @@ -16,7 +16,20 @@ import ( func copyFileInfo(fi os.FileInfo, name string) error { st := fi.Sys().(*syscall.Stat_t) if err := os.Lchown(name, int(st.Uid), int(st.Gid)); err != nil { - return errors.Wrapf(err, "failed to chown %s", name) + if os.IsPermission(err) { + // Normally if uid/gid are the same this would be a no-op, but some + // filesystems may still return EPERM... for instance NFS does this. + // In such a case, this is not an error. + if dstStat, err2 := os.Lstat(name); err2 == nil { + st2 := dstStat.Sys().(*syscall.Stat_t) + if st.Uid == st2.Uid && st.Gid == st2.Gid { + err = nil + } + } + } + if err != nil { + return errors.Wrapf(err, "failed to chown %s", name) + } } if (fi.Mode() & os.ModeSymlink) != os.ModeSymlink { diff --git a/vendor/github.com/containerd/containerd/log/context.go b/vendor/github.com/containerd/containerd/log/context.go index 1081719c1..471c35270 100644 --- a/vendor/github.com/containerd/containerd/log/context.go +++ b/vendor/github.com/containerd/containerd/log/context.go @@ -2,7 +2,6 @@ package log import ( "context" - "path" "github.com/sirupsen/logrus" ) @@ -20,7 +19,6 @@ var ( type ( loggerKey struct{} - moduleKey struct{} ) // WithLogger returns a new context with the provided logger. Use in @@ -40,42 +38,3 @@ func GetLogger(ctx context.Context) *logrus.Entry { return logger.(*logrus.Entry) } - -// WithModule adds the module to the context, appending it with a slash if a -// module already exists. A module is just an roughly correlated defined by the -// call tree for a given context. -// -// As an example, we might have a "node" module already part of a context. If -// this function is called with "tls", the new value of module will be -// "node/tls". -// -// Modules represent the call path. If the new module and last module are the -// same, a new module entry will not be created. If the new module and old -// older module are the same but separated by other modules, the cycle will be -// represented by the module path. -func WithModule(ctx context.Context, module string) context.Context { - parent := GetModulePath(ctx) - - if parent != "" { - // don't re-append module when module is the same. - if path.Base(parent) == module { - return ctx - } - - module = path.Join(parent, module) - } - - ctx = WithLogger(ctx, GetLogger(ctx).WithField("module", module)) - return context.WithValue(ctx, moduleKey{}, module) -} - -// GetModulePath returns the module path for the provided context. If no module -// is set, an empty string is returned. -func GetModulePath(ctx context.Context) string { - module := ctx.Value(moduleKey{}) - if module == nil { - return "" - } - - return module.(string) -} diff --git a/vendor/github.com/containerd/containerd/metadata/buckets.go b/vendor/github.com/containerd/containerd/metadata/buckets.go index 9325f1698..45309724f 100644 --- a/vendor/github.com/containerd/containerd/metadata/buckets.go +++ b/vendor/github.com/containerd/containerd/metadata/buckets.go @@ -106,13 +106,8 @@ func imagesBucketPath(namespace string) [][]byte { return [][]byte{bucketKeyVersion, []byte(namespace), bucketKeyObjectImages} } -func withImagesBucket(tx *bolt.Tx, namespace string, fn func(bkt *bolt.Bucket) error) error { - bkt, err := createBucketIfNotExists(tx, imagesBucketPath(namespace)...) - if err != nil { - return err - } - - return fn(bkt) +func createImagesBucket(tx *bolt.Tx, namespace string) (*bolt.Bucket, error) { + return createBucketIfNotExists(tx, imagesBucketPath(namespace)...) } func getImagesBucket(tx *bolt.Tx, namespace string) *bolt.Bucket { @@ -143,6 +138,10 @@ func createSnapshotterBucket(tx *bolt.Tx, namespace, snapshotter string) (*bolt. return bkt, nil } +func getSnapshottersBucket(tx *bolt.Tx, namespace string) *bolt.Bucket { + return getBucket(tx, bucketKeyVersion, []byte(namespace), bucketKeyObjectSnapshots) +} + func getSnapshotterBucket(tx *bolt.Tx, namespace, snapshotter string) *bolt.Bucket { return getBucket(tx, bucketKeyVersion, []byte(namespace), bucketKeyObjectSnapshots, []byte(snapshotter)) } diff --git a/vendor/github.com/containerd/containerd/metadata/images.go b/vendor/github.com/containerd/containerd/metadata/images.go index 8bf0c6173..cf0b2bc28 100644 --- a/vendor/github.com/containerd/containerd/metadata/images.go +++ b/vendor/github.com/containerd/containerd/metadata/images.go @@ -20,12 +20,12 @@ import ( ) type imageStore struct { - tx *bolt.Tx + db *DB } // NewImageStore returns a store backed by a bolt DB -func NewImageStore(tx *bolt.Tx) images.Store { - return &imageStore{tx: tx} +func NewImageStore(db *DB) images.Store { + return &imageStore{db: db} } func (s *imageStore) Get(ctx context.Context, name string) (images.Image, error) { @@ -36,19 +36,25 @@ func (s *imageStore) Get(ctx context.Context, name string) (images.Image, error) return images.Image{}, err } - bkt := getImagesBucket(s.tx, namespace) - if bkt == nil { - return images.Image{}, errors.Wrapf(errdefs.ErrNotFound, "image %q", name) - } + if err := view(ctx, s.db, func(tx *bolt.Tx) error { + bkt := getImagesBucket(tx, namespace) + if bkt == nil { + return errors.Wrapf(errdefs.ErrNotFound, "image %q", name) + } - ibkt := bkt.Bucket([]byte(name)) - if ibkt == nil { - return images.Image{}, errors.Wrapf(errdefs.ErrNotFound, "image %q", name) - } + ibkt := bkt.Bucket([]byte(name)) + if ibkt == nil { + return errors.Wrapf(errdefs.ErrNotFound, "image %q", name) + } - image.Name = name - if err := readImage(&image, ibkt); err != nil { - return images.Image{}, errors.Wrapf(err, "image %q", name) + image.Name = name + if err := readImage(&image, ibkt); err != nil { + return errors.Wrapf(err, "image %q", name) + } + + return nil + }); err != nil { + return images.Image{}, err } return image, nil @@ -65,28 +71,30 @@ func (s *imageStore) List(ctx context.Context, fs ...string) ([]images.Image, er return nil, errors.Wrapf(errdefs.ErrInvalidArgument, err.Error()) } - bkt := getImagesBucket(s.tx, namespace) - if bkt == nil { - return nil, nil // empty store - } - var m []images.Image - if err := bkt.ForEach(func(k, v []byte) error { - var ( - image = images.Image{ - Name: string(k), + if err := view(ctx, s.db, func(tx *bolt.Tx) error { + bkt := getImagesBucket(tx, namespace) + if bkt == nil { + return nil // empty store + } + + return bkt.ForEach(func(k, v []byte) error { + var ( + image = images.Image{ + Name: string(k), + } + kbkt = bkt.Bucket(k) + ) + + if err := readImage(&image, kbkt); err != nil { + return err } - kbkt = bkt.Bucket(k) - ) - if err := readImage(&image, kbkt); err != nil { - return err - } - - if filter.Match(adaptImage(image)) { - m = append(m, image) - } - return nil + if filter.Match(adaptImage(image)) { + m = append(m, image) + } + return nil + }) }); err != nil { return nil, err } @@ -100,11 +108,16 @@ func (s *imageStore) Create(ctx context.Context, image images.Image) (images.Ima return images.Image{}, err } - if err := validateImage(&image); err != nil { - return images.Image{}, err - } + if err := update(ctx, s.db, func(tx *bolt.Tx) error { + if err := validateImage(&image); err != nil { + return err + } + + bkt, err := createImagesBucket(tx, namespace) + if err != nil { + return err + } - return image, withImagesBucket(s.tx, namespace, func(bkt *bolt.Bucket) error { ibkt, err := bkt.CreateBucket([]byte(image.Name)) if err != nil { if err != bolt.ErrBucketExists { @@ -117,7 +130,11 @@ func (s *imageStore) Create(ctx context.Context, image images.Image) (images.Ima image.CreatedAt = time.Now().UTC() image.UpdatedAt = image.CreatedAt return writeImage(ibkt, &image) - }) + }); err != nil { + return images.Image{}, err + } + + return image, nil } func (s *imageStore) Update(ctx context.Context, image images.Image, fieldpaths ...string) (images.Image, error) { @@ -131,7 +148,13 @@ func (s *imageStore) Update(ctx context.Context, image images.Image, fieldpaths } var updated images.Image - return updated, withImagesBucket(s.tx, namespace, func(bkt *bolt.Bucket) error { + + if err := update(ctx, s.db, func(tx *bolt.Tx) error { + bkt, err := createImagesBucket(tx, namespace) + if err != nil { + return err + } + ibkt := bkt.Bucket([]byte(image.Name)) if ibkt == nil { return errors.Wrapf(errdefs.ErrNotFound, "image %q", image.Name) @@ -180,7 +203,12 @@ func (s *imageStore) Update(ctx context.Context, image images.Image, fieldpaths updated.CreatedAt = createdat updated.UpdatedAt = time.Now().UTC() return writeImage(ibkt, &updated) - }) + }); err != nil { + return images.Image{}, err + } + + return updated, nil + } func (s *imageStore) Delete(ctx context.Context, name string, opts ...images.DeleteOpt) error { @@ -189,11 +217,24 @@ func (s *imageStore) Delete(ctx context.Context, name string, opts ...images.Del return err } - return withImagesBucket(s.tx, namespace, func(bkt *bolt.Bucket) error { - err := bkt.DeleteBucket([]byte(name)) + return update(ctx, s.db, func(tx *bolt.Tx) error { + bkt := getImagesBucket(tx, namespace) + if bkt == nil { + return errors.Wrapf(errdefs.ErrNotFound, "image %q", name) + } + + err = bkt.DeleteBucket([]byte(name)) if err == bolt.ErrBucketNotFound { return errors.Wrapf(errdefs.ErrNotFound, "image %q", name) } + + // A reference to a piece of content has been removed, + // mark content store as dirty for triggering garbage + // collection + s.db.dirtyL.Lock() + s.db.dirtyCS = true + s.db.dirtyL.Unlock() + return err }) } diff --git a/vendor/github.com/containerd/containerd/metadata/namespaces.go b/vendor/github.com/containerd/containerd/metadata/namespaces.go index 4b4c4e5fe..4f84051d3 100644 --- a/vendor/github.com/containerd/containerd/metadata/namespaces.go +++ b/vendor/github.com/containerd/containerd/metadata/namespaces.go @@ -133,31 +133,38 @@ func (s *namespaceStore) Delete(ctx context.Context, namespace string) error { } func (s *namespaceStore) namespaceEmpty(ctx context.Context, namespace string) (bool, error) { - ctx = namespaces.WithNamespace(ctx, namespace) - - // need to check the various object stores. - - imageStore := NewImageStore(s.tx) - images, err := imageStore.List(ctx) - if err != nil { - return false, err + // Get all data buckets + buckets := []*bolt.Bucket{ + getImagesBucket(s.tx, namespace), + getBlobsBucket(s.tx, namespace), + getContainersBucket(s.tx, namespace), } - if len(images) > 0 { - return false, nil + if snbkt := getSnapshottersBucket(s.tx, namespace); snbkt != nil { + if err := snbkt.ForEach(func(k, v []byte) error { + if v == nil { + buckets = append(buckets, snbkt.Bucket(k)) + } + return nil + }); err != nil { + return false, err + } } - containerStore := NewContainerStore(s.tx) - containers, err := containerStore.List(ctx) - if err != nil { - return false, err + // Ensure data buckets are empty + for _, bkt := range buckets { + if !isBucketEmpty(bkt) { + return false, nil + } } - if len(containers) > 0 { - return false, nil - } - - // TODO(stevvooe): Need to add check for content store, as well. Still need - // to make content store namespace aware. - return true, nil } + +func isBucketEmpty(bkt *bolt.Bucket) bool { + if bkt == nil { + return true + } + + k, _ := bkt.Cursor().First() + return k == nil +} diff --git a/vendor/github.com/containerd/containerd/oci/spec_opts.go b/vendor/github.com/containerd/containerd/oci/spec_opts.go index c940c7aab..19126b22f 100644 --- a/vendor/github.com/containerd/containerd/oci/spec_opts.go +++ b/vendor/github.com/containerd/containerd/oci/spec_opts.go @@ -2,6 +2,7 @@ package oci import ( "context" + "strings" "github.com/containerd/containerd/containers" specs "github.com/opencontainers/runtime-spec/specs-go" @@ -33,3 +34,59 @@ func WithHostname(name string) SpecOpts { return nil } } + +// WithEnv appends environment variables +func WithEnv(environmnetVariables []string) SpecOpts { + return func(_ context.Context, _ Client, _ *containers.Container, s *specs.Spec) error { + if len(environmnetVariables) > 0 { + s.Process.Env = replaceOrAppendEnvValues(s.Process.Env, environmnetVariables) + } + return nil + } +} + +// WithMounts appends mounts +func WithMounts(mounts []specs.Mount) SpecOpts { + return func(_ context.Context, _ Client, _ *containers.Container, s *specs.Spec) error { + s.Mounts = append(s.Mounts, mounts...) + return nil + } +} + +// replaceOrAppendEnvValues returns the defaults with the overrides either +// replaced by env key or appended to the list +func replaceOrAppendEnvValues(defaults, overrides []string) []string { + cache := make(map[string]int, len(defaults)) + for i, e := range defaults { + parts := strings.SplitN(e, "=", 2) + cache[parts[0]] = i + } + + for _, value := range overrides { + // Values w/o = means they want this env to be removed/unset. + if !strings.Contains(value, "=") { + if i, exists := cache[value]; exists { + defaults[i] = "" // Used to indicate it should be removed + } + continue + } + + // Just do a normal set/update + parts := strings.SplitN(value, "=", 2) + if i, exists := cache[parts[0]]; exists { + defaults[i] = value + } else { + defaults = append(defaults, value) + } + } + + // Now remove all entries that we want to "unset" + for i := 0; i < len(defaults); i++ { + if defaults[i] == "" { + defaults = append(defaults[:i], defaults[i+1:]...) + i-- + } + } + + return defaults +} diff --git a/vendor/github.com/containerd/containerd/oci/spec_opts_unix.go b/vendor/github.com/containerd/containerd/oci/spec_opts_unix.go index ebc423d3e..2c31b35c3 100644 --- a/vendor/github.com/containerd/containerd/oci/spec_opts_unix.go +++ b/vendor/github.com/containerd/containerd/oci/spec_opts_unix.go @@ -95,22 +95,25 @@ func WithImageConfig(image Image) SpecOpts { s.Process.Env = append(s.Process.Env, config.Env...) cmd := config.Cmd s.Process.Args = append(config.Entrypoint, cmd...) + cwd := config.WorkingDir + if cwd == "" { + cwd = "/" + } + s.Process.Cwd = cwd if config.User != "" { + // According to OCI Image Spec v1.0.0, the following are valid for Linux: + // user, uid, user:group, uid:gid, uid:group, user:gid parts := strings.Split(config.User, ":") switch len(parts) { case 1: v, err := strconv.Atoi(parts[0]) if err != nil { // if we cannot parse as a uint they try to see if it is a username - if err := WithUsername(config.User)(ctx, client, c, s); err != nil { - return err - } - return err - } - if err := WithUserID(uint32(v))(ctx, client, c, s); err != nil { - return err + return WithUsername(config.User)(ctx, client, c, s) } + return WithUserID(uint32(v))(ctx, client, c, s) case 2: + // TODO: support username and groupname v, err := strconv.Atoi(parts[0]) if err != nil { return errors.Wrapf(err, "parse uid %s", parts[0]) @@ -125,11 +128,6 @@ func WithImageConfig(image Image) SpecOpts { return fmt.Errorf("invalid USER value %s", config.User) } } - cwd := config.WorkingDir - if cwd == "" { - cwd = "/" - } - s.Process.Cwd = cwd return nil } } @@ -259,6 +257,24 @@ func WithUIDGID(uid, gid uint32) SpecOpts { // uid, and not returns error. func WithUserID(uid uint32) SpecOpts { return func(ctx context.Context, client Client, c *containers.Container, s *specs.Spec) (err error) { + if c.Snapshotter == "" && c.SnapshotKey == "" { + if !isRootfsAbs(s.Root.Path) { + return errors.Errorf("rootfs absolute path is required") + } + uuid, ugid, err := getUIDGIDFromPath(s.Root.Path, func(u user.User) bool { + return u.Uid == int(uid) + }) + if err != nil { + if os.IsNotExist(err) || err == errNoUsersFound { + s.Process.User.UID, s.Process.User.GID = uid, uid + return nil + } + return err + } + s.Process.User.UID, s.Process.User.GID = uuid, ugid + return nil + + } if c.Snapshotter == "" { return errors.Errorf("no snapshotter set for container") } @@ -270,33 +286,18 @@ func WithUserID(uid uint32) SpecOpts { if err != nil { return err } - return mount.WithTempMount(ctx, mounts, func(root string) error { - ppath, err := fs.RootPath(root, "/etc/passwd") + uuid, ugid, err := getUIDGIDFromPath(root, func(u user.User) bool { + return u.Uid == int(uid) + }) if err != nil { - return err - } - f, err := os.Open(ppath) - if err != nil { - if os.IsNotExist(err) { + if os.IsNotExist(err) || err == errNoUsersFound { s.Process.User.UID, s.Process.User.GID = uid, uid return nil } return err } - defer f.Close() - users, err := user.ParsePasswdFilter(f, func(u user.User) bool { - return u.Uid == int(uid) - }) - if err != nil { - return err - } - if len(users) == 0 { - s.Process.User.UID, s.Process.User.GID = uid, uid - return nil - } - u := users[0] - s.Process.User.UID, s.Process.User.GID = uint32(u.Uid), uint32(u.Gid) + s.Process.User.UID, s.Process.User.GID = uuid, ugid return nil }) } @@ -308,6 +309,19 @@ func WithUserID(uid uint32) SpecOpts { // it returns error. func WithUsername(username string) SpecOpts { return func(ctx context.Context, client Client, c *containers.Container, s *specs.Spec) (err error) { + if c.Snapshotter == "" && c.SnapshotKey == "" { + if !isRootfsAbs(s.Root.Path) { + return errors.Errorf("rootfs absolute path is required") + } + uid, gid, err := getUIDGIDFromPath(s.Root.Path, func(u user.User) bool { + return u.Name == username + }) + if err != nil { + return err + } + s.Process.User.UID, s.Process.User.GID = uid, gid + return nil + } if c.Snapshotter == "" { return errors.Errorf("no snapshotter set for container") } @@ -320,27 +334,41 @@ func WithUsername(username string) SpecOpts { return err } return mount.WithTempMount(ctx, mounts, func(root string) error { - ppath, err := fs.RootPath(root, "/etc/passwd") - if err != nil { - return err - } - f, err := os.Open(ppath) - if err != nil { - return err - } - defer f.Close() - users, err := user.ParsePasswdFilter(f, func(u user.User) bool { + uid, gid, err := getUIDGIDFromPath(root, func(u user.User) bool { return u.Name == username }) if err != nil { return err } - if len(users) == 0 { - return errors.Errorf("no users found for %s", username) - } - u := users[0] - s.Process.User.UID, s.Process.User.GID = uint32(u.Uid), uint32(u.Gid) + s.Process.User.UID, s.Process.User.GID = uid, gid return nil }) } } + +var errNoUsersFound = errors.New("no users found") + +func getUIDGIDFromPath(root string, filter func(user.User) bool) (uid, gid uint32, err error) { + ppath, err := fs.RootPath(root, "/etc/passwd") + if err != nil { + return 0, 0, err + } + f, err := os.Open(ppath) + if err != nil { + return 0, 0, err + } + defer f.Close() + users, err := user.ParsePasswdFilter(f, filter) + if err != nil { + return 0, 0, err + } + if len(users) == 0 { + return 0, 0, errNoUsersFound + } + u := users[0] + return uint32(u.Uid), uint32(u.Gid), nil +} + +func isRootfsAbs(root string) bool { + return filepath.IsAbs(root) +} diff --git a/vendor/github.com/containerd/containerd/plugin/context.go b/vendor/github.com/containerd/containerd/plugin/context.go index 87e53b84f..eca4a0204 100644 --- a/vendor/github.com/containerd/containerd/plugin/context.go +++ b/vendor/github.com/containerd/containerd/plugin/context.go @@ -6,7 +6,6 @@ import ( "github.com/containerd/containerd/errdefs" "github.com/containerd/containerd/events/exchange" - "github.com/containerd/containerd/log" ocispec "github.com/opencontainers/image-spec/specs-go/v1" "github.com/pkg/errors" ) @@ -28,7 +27,7 @@ type InitContext struct { // NewContext returns a new plugin InitContext func NewContext(ctx context.Context, r *Registration, plugins *Set, root, state string) *InitContext { return &InitContext{ - Context: log.WithModule(ctx, r.URI()), + Context: ctx, Root: filepath.Join(root, r.URI()), State: filepath.Join(state, r.URI()), Meta: &Meta{