diff --git a/cri.go b/cri.go index f4462b8ab299..f375bdbcb5b5 100644 --- a/cri.go +++ b/cri.go @@ -30,7 +30,6 @@ import ( // TODO(random-liu): Use github.com/pkg/errors for our errors. // Register CRI service plugin func init() { - // TODO(random-liu): Make `containerd config default` print plugin default config. config := options.DefaultConfig().PluginConfig plugin.Register(&plugin.Registration{ // In fact, cri is not strictly a GRPC plugin now. diff --git a/hack/versions b/hack/versions index 6bd92e350cfd..2b09b46a0241 100644 --- a/hack/versions +++ b/hack/versions @@ -1,6 +1,6 @@ RUNC_VERSION=7f24b40cc5423969b4554ef04ba0b00e2b4ba010 CNI_VERSION=v0.6.0 -CONTAINERD_VERSION=90553efdef0678b2609aed74926a487f8ff58d1a +CONTAINERD_VERSION=4812f4be8ffa2b9558915a93cce5901004d27cb8 CONTAINERD_REPO= CRITOOL_VERSION=v1.0.0-alpha.0 KUBERNETES_VERSION=v1.9.0 diff --git a/vendor.conf b/vendor.conf index 3fa0584192bf..e163990dc520 100644 --- a/vendor.conf +++ b/vendor.conf @@ -1,7 +1,7 @@ github.com/blang/semver v3.1.0 github.com/BurntSushi/toml v0.2.0-21-g9906417 github.com/containerd/cgroups 29da22c6171a4316169f9205ab6c49f59b5b852f -github.com/containerd/containerd 90553efdef0678b2609aed74926a487f8ff58d1a +github.com/containerd/containerd 4812f4be8ffa2b9558915a93cce5901004d27cb8 github.com/containerd/continuity cf279e6ac893682272b4479d4c67fd3abf878b4e github.com/containerd/fifo fbfb6a11ec671efbe94ad1c12c2e98773f19e1e6 github.com/containerd/typeurl f6943554a7e7e88b3c14aad190bf05932da84788 diff --git a/vendor/github.com/containerd/containerd/client.go b/vendor/github.com/containerd/containerd/client.go index 39547f589a7c..8b02c73ee54d 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/dialer/dialer.go b/vendor/github.com/containerd/containerd/dialer/dialer.go index 65af69f9bcab..1ad4ab718304 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 c1fb2d1c40b3..47272963ba51 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 b31a14fcdb0a..fceb0e63a518 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 1081719c11f0..471c352704e1 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/oci/spec_opts_unix.go b/vendor/github.com/containerd/containerd/oci/spec_opts_unix.go index ebc423d3e370..2c31b35c34cd 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") - if err != nil { - return err - } - f, err := os.Open(ppath) + uuid, ugid, err := getUIDGIDFromPath(root, func(u user.User) bool { + return u.Uid == int(uid) + }) 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 87e53b84f2bf..eca4a0204def 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{