From 4e2fc81edd9ca5fa4a96f874ec669af5737b4999 Mon Sep 17 00:00:00 2001 From: Maksym Pavlenko Date: Wed, 10 Jul 2019 12:10:14 -0700 Subject: [PATCH 1/4] Add aliases to namespaces subcommand Signed-off-by: Maksym Pavlenko --- cmd/ctr/commands/namespaces/namespaces.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cmd/ctr/commands/namespaces/namespaces.go b/cmd/ctr/commands/namespaces/namespaces.go index 81ce3dc0a..93455b14c 100644 --- a/cmd/ctr/commands/namespaces/namespaces.go +++ b/cmd/ctr/commands/namespaces/namespaces.go @@ -33,7 +33,7 @@ import ( // Command is the cli command for managing namespaces var Command = cli.Command{ Name: "namespaces", - Aliases: []string{"namespace"}, + Aliases: []string{"namespace", "ns"}, Usage: "manage namespaces", Subcommands: cli.Commands{ createCommand, @@ -45,6 +45,7 @@ var Command = cli.Command{ var createCommand = cli.Command{ Name: "create", + Aliases: []string{"c"}, Usage: "create a new namespace", ArgsUsage: " [= Date: Wed, 10 Jul 2019 12:15:08 -0700 Subject: [PATCH 2/4] Improve default label handling Signed-off-by: Maksym Pavlenko --- client.go | 54 +++++++++++++++++++++++++++++++++++------------------- 1 file changed, 35 insertions(+), 19 deletions(-) diff --git a/client.go b/client.go index 2d255c0e1..0317c8afc 100644 --- a/client.go +++ b/client.go @@ -87,13 +87,15 @@ func New(address string, opts ...ClientOpt) (*Client, error) { if copts.timeout == 0 { copts.timeout = 10 * time.Second } - rt := fmt.Sprintf("%s.%s", plugin.RuntimePlugin, runtime.GOOS) + + c := &Client{} + if copts.defaultRuntime != "" { - rt = copts.defaultRuntime - } - c := &Client{ - runtime: rt, + c.runtime = copts.defaultRuntime + } else { + c.runtime = fmt.Sprintf("%s.%s", plugin.RuntimePlugin, runtime.GOOS) } + if copts.services != nil { c.services = *copts.services } @@ -140,13 +142,8 @@ func New(address string, opts ...ClientOpt) (*Client, error) { // check namespace labels for default runtime if copts.defaultRuntime == "" && copts.defaultns != "" { - namespaces := c.NamespaceService() - ctx := context.Background() - if labels, err := namespaces.Labels(ctx, copts.defaultns); err == nil { - if defaultRuntime, ok := labels[defaults.DefaultRuntimeNSLabel]; ok { - c.runtime = defaultRuntime - } - } else { + ctx := namespaces.WithNamespace(context.Background(), copts.defaultns) + if err := c.GetLabel(ctx, defaults.DefaultRuntimeNSLabel, &c.runtime, ""); err != nil { return nil, err } } @@ -170,13 +167,8 @@ func NewWithConn(conn *grpc.ClientConn, opts ...ClientOpt) (*Client, error) { // check namespace labels for default runtime if copts.defaultRuntime == "" && copts.defaultns != "" { - namespaces := c.NamespaceService() - ctx := context.Background() - if labels, err := namespaces.Labels(ctx, copts.defaultns); err == nil { - if defaultRuntime, ok := labels[defaults.DefaultRuntimeNSLabel]; ok { - c.runtime = defaultRuntime - } - } else { + ctx := namespaces.WithNamespace(context.Background(), copts.defaultns) + if err := c.GetLabel(ctx, defaults.DefaultRuntimeNSLabel, &c.runtime, ""); err != nil { return nil, err } } @@ -491,6 +483,30 @@ func writeIndex(ctx context.Context, index *ocispec.Index, client *Client, ref s return writeContent(ctx, client.ContentStore(), ocispec.MediaTypeImageIndex, ref, bytes.NewReader(data), content.WithLabels(labels)) } +// GetLabel gets a label value from namespace store and saves it in 'out' variable. +// If there is no value, a fallback value will be used instead. +func (c *Client) GetLabel(ctx context.Context, label string, out *string, fallback string) error { + ns, err := namespaces.NamespaceRequired(ctx) + if err != nil { + return err + } + + srv := c.NamespaceService() + labels, err := srv.Labels(ctx, ns) + if err != nil { + return err + } + + value, ok := labels[label] + if ok { + *out = value + } else { + *out = fallback + } + + return nil +} + // Subscribe to events that match one or more of the provided filters. // // Callers should listen on both the envelope and errs channels. If the errs From 1918ee4d11abd3b9dc27bb3b12e4e878ac4fa165 Mon Sep 17 00:00:00 2001 From: Maksym Pavlenko Date: Wed, 10 Jul 2019 12:16:43 -0700 Subject: [PATCH 3/4] Respect default snapshotter label Signed-off-by: Maksym Pavlenko --- client.go | 9 +++++++-- cmd/ctr/commands/commands.go | 2 -- container.go | 2 +- container_opts.go | 30 ++++++------------------------ container_opts_unix.go | 4 +--- image.go | 4 ++-- 6 files changed, 17 insertions(+), 34 deletions(-) diff --git a/client.go b/client.go index 0317c8afc..82505889e 100644 --- a/client.go +++ b/client.go @@ -332,7 +332,6 @@ func defaultRemoteContext() *RemoteContext { Resolver: docker.NewResolver(docker.ResolverOptions{ Client: http.DefaultClient, }), - Snapshotter: DefaultSnapshotter, } } @@ -672,7 +671,13 @@ func (c *Client) Version(ctx context.Context) (Version, error) { }, nil } -func (c *Client) getSnapshotter(name string) (snapshots.Snapshotter, error) { +func (c *Client) getSnapshotter(ctx context.Context, name string) (snapshots.Snapshotter, error) { + if name == "" { + if err := c.GetLabel(ctx, defaults.DefaultSnapshotterNSLabel, &name, DefaultSnapshotter); err != nil { + return nil, err + } + } + s := c.SnapshotService(name) if s == nil { return nil, errors.Wrapf(errdefs.ErrNotFound, "snapshotter %s was not found", name) diff --git a/cmd/ctr/commands/commands.go b/cmd/ctr/commands/commands.go index 6d9fb5488..234971d35 100644 --- a/cmd/ctr/commands/commands.go +++ b/cmd/ctr/commands/commands.go @@ -24,7 +24,6 @@ import ( "runtime" "strings" - "github.com/containerd/containerd" "github.com/urfave/cli" ) @@ -34,7 +33,6 @@ var ( cli.StringFlag{ Name: "snapshotter", Usage: "snapshotter name. Empty value stands for the default value.", - Value: containerd.DefaultSnapshotter, EnvVar: "CONTAINERD_SNAPSHOTTER", }, } diff --git a/container.go b/container.go index e060303e8..46d51ecd9 100644 --- a/container.go +++ b/container.go @@ -233,7 +233,7 @@ func (c *container) NewTask(ctx context.Context, ioCreate cio.Creator, opts ...N } // get the rootfs from the snapshotter and add it to the request - s, err := c.client.getSnapshotter(r.Snapshotter) + s, err := c.client.getSnapshotter(ctx, r.Snapshotter) if err != nil { return nil, err } diff --git a/container_opts.go b/container_opts.go index deb078db6..c8a0933b7 100644 --- a/container_opts.go +++ b/container_opts.go @@ -20,9 +20,7 @@ import ( "context" "github.com/containerd/containerd/containers" - "github.com/containerd/containerd/defaults" "github.com/containerd/containerd/errdefs" - "github.com/containerd/containerd/namespaces" "github.com/containerd/containerd/oci" "github.com/containerd/containerd/platforms" "github.com/containerd/containerd/snapshots" @@ -118,9 +116,8 @@ func WithSnapshotter(name string) NewContainerOpts { // WithSnapshot uses an existing root filesystem for the container func WithSnapshot(id string) NewContainerOpts { return func(ctx context.Context, client *Client, c *containers.Container) error { - setSnapshotterIfEmpty(ctx, client, c) // check that the snapshot exists, if not, fail on creation - s, err := client.getSnapshotter(c.Snapshotter) + s, err := client.getSnapshotter(ctx, c.Snapshotter) if err != nil { return err } @@ -140,9 +137,9 @@ func WithNewSnapshot(id string, i Image, opts ...snapshots.Opt) NewContainerOpts if err != nil { return err } - setSnapshotterIfEmpty(ctx, client, c) + parent := identity.ChainID(diffIDs).String() - s, err := client.getSnapshotter(c.Snapshotter) + s, err := client.getSnapshotter(ctx, c.Snapshotter) if err != nil { return err } @@ -161,7 +158,7 @@ func WithSnapshotCleanup(ctx context.Context, client *Client, c containers.Conta if c.Snapshotter == "" { return errors.Wrapf(errdefs.ErrInvalidArgument, "container.Snapshotter must be set to cleanup rootfs snapshot") } - s, err := client.getSnapshotter(c.Snapshotter) + s, err := client.getSnapshotter(ctx, c.Snapshotter) if err != nil { return err } @@ -178,9 +175,9 @@ func WithNewSnapshotView(id string, i Image, opts ...snapshots.Opt) NewContainer if err != nil { return err } - setSnapshotterIfEmpty(ctx, client, c) + parent := identity.ChainID(diffIDs).String() - s, err := client.getSnapshotter(c.Snapshotter) + s, err := client.getSnapshotter(ctx, c.Snapshotter) if err != nil { return err } @@ -193,21 +190,6 @@ func WithNewSnapshotView(id string, i Image, opts ...snapshots.Opt) NewContainer } } -func setSnapshotterIfEmpty(ctx context.Context, client *Client, c *containers.Container) { - if c.Snapshotter == "" { - defaultSnapshotter := DefaultSnapshotter - namespaceService := client.NamespaceService() - if ns, err := namespaces.NamespaceRequired(ctx); err == nil { - if labels, err := namespaceService.Labels(ctx, ns); err == nil { - if snapshotLabel, ok := labels[defaults.DefaultSnapshotterNSLabel]; ok { - defaultSnapshotter = snapshotLabel - } - } - } - c.Snapshotter = defaultSnapshotter - } -} - // WithContainerExtension appends extension data to the container object. // Use this to decorate the container object with additional data for the client // integration. diff --git a/container_opts_unix.go b/container_opts_unix.go index 39f09bb55..c8b6247b5 100644 --- a/container_opts_unix.go +++ b/container_opts_unix.go @@ -50,13 +50,11 @@ func withRemappedSnapshotBase(id string, i Image, uid, gid uint32, readonly bool return err } - setSnapshotterIfEmpty(ctx, client, c) - var ( parent = identity.ChainID(diffIDs).String() usernsID = fmt.Sprintf("%s-%d-%d", parent, uid, gid) ) - snapshotter, err := client.getSnapshotter(c.Snapshotter) + snapshotter, err := client.getSnapshotter(ctx, c.Snapshotter) if err != nil { return err } diff --git a/image.go b/image.go index c13d3869a..3c820840c 100644 --- a/image.go +++ b/image.go @@ -108,7 +108,7 @@ func (i *image) Config(ctx context.Context) (ocispec.Descriptor, error) { } func (i *image) IsUnpacked(ctx context.Context, snapshotterName string) (bool, error) { - sn, err := i.client.getSnapshotter(snapshotterName) + sn, err := i.client.getSnapshotter(ctx, snapshotterName) if err != nil { return false, err } @@ -149,7 +149,7 @@ func (i *image) Unpack(ctx context.Context, snapshotterName string) error { chain []digest.Digest unpacked bool ) - sn, err := i.client.getSnapshotter(snapshotterName) + sn, err := i.client.getSnapshotter(ctx, snapshotterName) if err != nil { return err } From 550a6f1d733ad4960ecbe8247c6cb2a545d7dd66 Mon Sep 17 00:00:00 2001 From: Maksym Pavlenko Date: Thu, 11 Jul 2019 11:54:48 -0700 Subject: [PATCH 4/4] Fix integration tests Signed-off-by: Maksym Pavlenko --- client.go | 51 +++++++++++++++++++++++++++--------------- container_opts.go | 13 +++++++++++ container_opts_unix.go | 4 ++++ image.go | 6 ++++- 4 files changed, 55 insertions(+), 19 deletions(-) diff --git a/client.go b/client.go index 82505889e..9b0888c79 100644 --- a/client.go +++ b/client.go @@ -143,8 +143,10 @@ func New(address string, opts ...ClientOpt) (*Client, error) { // check namespace labels for default runtime if copts.defaultRuntime == "" && copts.defaultns != "" { ctx := namespaces.WithNamespace(context.Background(), copts.defaultns) - if err := c.GetLabel(ctx, defaults.DefaultRuntimeNSLabel, &c.runtime, ""); err != nil { + if label, err := c.GetLabel(ctx, defaults.DefaultRuntimeNSLabel); err != nil { return nil, err + } else if label != "" { + c.runtime = label } } @@ -168,8 +170,10 @@ func NewWithConn(conn *grpc.ClientConn, opts ...ClientOpt) (*Client, error) { // check namespace labels for default runtime if copts.defaultRuntime == "" && copts.defaultns != "" { ctx := namespaces.WithNamespace(context.Background(), copts.defaultns) - if err := c.GetLabel(ctx, defaults.DefaultRuntimeNSLabel, &c.runtime, ""); err != nil { + if label, err := c.GetLabel(ctx, defaults.DefaultRuntimeNSLabel); err != nil { return nil, err + } else if label != "" { + c.runtime = label } } @@ -482,28 +486,22 @@ func writeIndex(ctx context.Context, index *ocispec.Index, client *Client, ref s return writeContent(ctx, client.ContentStore(), ocispec.MediaTypeImageIndex, ref, bytes.NewReader(data), content.WithLabels(labels)) } -// GetLabel gets a label value from namespace store and saves it in 'out' variable. -// If there is no value, a fallback value will be used instead. -func (c *Client) GetLabel(ctx context.Context, label string, out *string, fallback string) error { +// GetLabel gets a label value from namespace store +// If there is no default label, an empty string returned with nil error +func (c *Client) GetLabel(ctx context.Context, label string) (string, error) { ns, err := namespaces.NamespaceRequired(ctx) if err != nil { - return err + return "", err } srv := c.NamespaceService() labels, err := srv.Labels(ctx, ns) if err != nil { - return err + return "", err } - value, ok := labels[label] - if ok { - *out = value - } else { - *out = fallback - } - - return nil + value := labels[label] + return value, nil } // Subscribe to events that match one or more of the provided filters. @@ -671,17 +669,34 @@ func (c *Client) Version(ctx context.Context) (Version, error) { }, nil } -func (c *Client) getSnapshotter(ctx context.Context, name string) (snapshots.Snapshotter, error) { +func (c *Client) resolveSnapshotterName(ctx context.Context, name string) (string, error) { if name == "" { - if err := c.GetLabel(ctx, defaults.DefaultSnapshotterNSLabel, &name, DefaultSnapshotter); err != nil { - return nil, err + label, err := c.GetLabel(ctx, defaults.DefaultSnapshotterNSLabel) + if err != nil { + return "", err } + + if label != "" { + name = label + } else { + name = DefaultSnapshotter + } + } + + return name, nil +} + +func (c *Client) getSnapshotter(ctx context.Context, name string) (snapshots.Snapshotter, error) { + name, err := c.resolveSnapshotterName(ctx, name) + if err != nil { + return nil, err } s := c.SnapshotService(name) if s == nil { return nil, errors.Wrapf(errdefs.ErrNotFound, "snapshotter %s was not found", name) } + return s, nil } diff --git a/container_opts.go b/container_opts.go index c8a0933b7..4c8a40489 100644 --- a/container_opts.go +++ b/container_opts.go @@ -117,6 +117,11 @@ func WithSnapshotter(name string) NewContainerOpts { func WithSnapshot(id string) NewContainerOpts { return func(ctx context.Context, client *Client, c *containers.Container) error { // check that the snapshot exists, if not, fail on creation + var err error + c.Snapshotter, err = client.resolveSnapshotterName(ctx, c.Snapshotter) + if err != nil { + return err + } s, err := client.getSnapshotter(ctx, c.Snapshotter) if err != nil { return err @@ -139,6 +144,10 @@ func WithNewSnapshot(id string, i Image, opts ...snapshots.Opt) NewContainerOpts } parent := identity.ChainID(diffIDs).String() + c.Snapshotter, err = client.resolveSnapshotterName(ctx, c.Snapshotter) + if err != nil { + return err + } s, err := client.getSnapshotter(ctx, c.Snapshotter) if err != nil { return err @@ -177,6 +186,10 @@ func WithNewSnapshotView(id string, i Image, opts ...snapshots.Opt) NewContainer } parent := identity.ChainID(diffIDs).String() + c.Snapshotter, err = client.resolveSnapshotterName(ctx, c.Snapshotter) + if err != nil { + return err + } s, err := client.getSnapshotter(ctx, c.Snapshotter) if err != nil { return err diff --git a/container_opts_unix.go b/container_opts_unix.go index c8b6247b5..af52d0422 100644 --- a/container_opts_unix.go +++ b/container_opts_unix.go @@ -54,6 +54,10 @@ func withRemappedSnapshotBase(id string, i Image, uid, gid uint32, readonly bool parent = identity.ChainID(diffIDs).String() usernsID = fmt.Sprintf("%s-%d-%d", parent, uid, gid) ) + c.Snapshotter, err = client.resolveSnapshotterName(ctx, c.Snapshotter) + if err != nil { + return err + } snapshotter, err := client.getSnapshotter(ctx, c.Snapshotter) if err != nil { return err diff --git a/image.go b/image.go index 3c820840c..77c95eaa4 100644 --- a/image.go +++ b/image.go @@ -25,7 +25,7 @@ import ( "github.com/containerd/containerd/images" "github.com/containerd/containerd/platforms" "github.com/containerd/containerd/rootfs" - digest "github.com/opencontainers/go-digest" + "github.com/opencontainers/go-digest" "github.com/opencontainers/image-spec/identity" ocispec "github.com/opencontainers/image-spec/specs-go/v1" "github.com/pkg/errors" @@ -149,6 +149,10 @@ func (i *image) Unpack(ctx context.Context, snapshotterName string) error { chain []digest.Digest unpacked bool ) + snapshotterName, err = i.client.resolveSnapshotterName(ctx, snapshotterName) + if err != nil { + return err + } sn, err := i.client.getSnapshotter(ctx, snapshotterName) if err != nil { return err