From 59432aaecf22f8037c6f59b36d00854b945b05ab Mon Sep 17 00:00:00 2001 From: Nikhil Soni Date: Sun, 2 Sep 2018 23:33:58 +0530 Subject: [PATCH 1/4] Take default runtime and snapshotter from namespace labels Signed-off-by: Nikhil Soni --- client.go | 16 ++++++++++++++++ client_test.go | 25 +++++++++++++++++++++++++ container_opts.go | 20 +++++++++++++++----- container_opts_unix.go | 2 +- 4 files changed, 57 insertions(+), 6 deletions(-) diff --git a/client.go b/client.go index eefeb4e94..60552e91a 100644 --- a/client.go +++ b/client.go @@ -138,6 +138,22 @@ func New(address string, opts ...ClientOpt) (*Client, error) { if copts.services == nil && c.conn == nil { return nil, errors.New("no grpc connection or services is available") } + + // check namespace labels for default runtime + defaultns := "default" + if copts.defaultns != "" { + defaultns = copts.defaultns + } + namespaces := c.NamespaceService() + ctx := context.Background() + if labels, err := namespaces.Labels(ctx, defaultns); err == nil { + if defaultRuntime, ok := labels["runtime"]; ok { + c.runtime = defaultRuntime + } + } else { + return nil, err + } + return c, nil } diff --git a/client_test.go b/client_test.go index 83081a6c9..2ed367b85 100644 --- a/client_test.go +++ b/client_test.go @@ -393,3 +393,28 @@ func createShimDebugConfig() string { return f.Name() } + +func TestDefaultRuntimeWithNamespaceLabels(t *testing.T) { + client, err := newClient(t, address) + if err != nil { + t.Fatal(err) + } + defer client.Close() + + ctx, cancel := testContext() + defer cancel() + namespaces := client.NamespaceService() + testRuntime := "testRuntime" + if err := namespaces.SetLabel(ctx, testNamespace, "runtime", testRuntime); err != nil { + t.Fatal(err) + } + + testClient, err := newClient(t, address, WithDefaultNamespace(testNamespace)) + if err != nil { + t.Fatal(err) + } + defer testClient.Close() + if testClient.runtime != testRuntime { + t.Error("failed to set default runtime from namespace labels") + } +} diff --git a/container_opts.go b/container_opts.go index ca4bf6748..8f086a729 100644 --- a/container_opts.go +++ b/container_opts.go @@ -21,6 +21,7 @@ import ( "github.com/containerd/containerd/containers" "github.com/containerd/containerd/errdefs" + "github.com/containerd/containerd/namespaces" "github.com/containerd/containerd/oci" "github.com/containerd/containerd/platforms" "github.com/containerd/typeurl" @@ -106,7 +107,7 @@ 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(c) + setSnapshotterIfEmpty(ctx, client, c) // check that the snapshot exists, if not, fail on creation if _, err := client.SnapshotService(c.Snapshotter).Mounts(ctx, id); err != nil { return err @@ -124,7 +125,7 @@ func WithNewSnapshot(id string, i Image) NewContainerOpts { if err != nil { return err } - setSnapshotterIfEmpty(c) + setSnapshotterIfEmpty(ctx, client, c) parent := identity.ChainID(diffIDs).String() if _, err := client.SnapshotService(c.Snapshotter).Prepare(ctx, id, parent); err != nil { return err @@ -154,7 +155,7 @@ func WithNewSnapshotView(id string, i Image) NewContainerOpts { if err != nil { return err } - setSnapshotterIfEmpty(c) + setSnapshotterIfEmpty(ctx, client, c) parent := identity.ChainID(diffIDs).String() if _, err := client.SnapshotService(c.Snapshotter).View(ctx, id, parent); err != nil { return err @@ -165,9 +166,18 @@ func WithNewSnapshotView(id string, i Image) NewContainerOpts { } } -func setSnapshotterIfEmpty(c *containers.Container) { +func setSnapshotterIfEmpty(ctx context.Context, client *Client, c *containers.Container) { if c.Snapshotter == "" { - c.Snapshotter = DefaultSnapshotter + 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["snapshotter"]; ok { + defaultSnapshotter = snapshotLabel + } + } + } + c.Snapshotter = defaultSnapshotter } } diff --git a/container_opts_unix.go b/container_opts_unix.go index 9e013f1a4..340a91857 100644 --- a/container_opts_unix.go +++ b/container_opts_unix.go @@ -50,7 +50,7 @@ func withRemappedSnapshotBase(id string, i Image, uid, gid uint32, readonly bool return err } - setSnapshotterIfEmpty(c) + setSnapshotterIfEmpty(ctx, client, c) var ( snapshotter = client.SnapshotService(c.Snapshotter) From 34323985a130d853a269f13d4199be31a908ca9e Mon Sep 17 00:00:00 2001 From: Nikhil Soni Date: Tue, 18 Sep 2018 02:41:47 +0530 Subject: [PATCH 2/4] Use labels only when default namespace is provided and prefer given options. Implements same approach of setting defaults for `NewWithConn`. Signed-off-by: Nikhil Soni --- client.go | 34 +++++++++++++++++++++++----------- client_test.go | 5 +++-- container_opts.go | 2 +- 3 files changed, 27 insertions(+), 14 deletions(-) diff --git a/client.go b/client.go index 60552e91a..386d07aa0 100644 --- a/client.go +++ b/client.go @@ -140,18 +140,16 @@ func New(address string, opts ...ClientOpt) (*Client, error) { } // check namespace labels for default runtime - defaultns := "default" - if copts.defaultns != "" { - defaultns = copts.defaultns - } - namespaces := c.NamespaceService() - ctx := context.Background() - if labels, err := namespaces.Labels(ctx, defaultns); err == nil { - if defaultRuntime, ok := labels["runtime"]; ok { - c.runtime = defaultRuntime + 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["containerd.io/defaults/runtime"]; ok { + c.runtime = defaultRuntime + } + } else { + return nil, err } - } else { - return nil, err } return c, nil @@ -170,6 +168,20 @@ func NewWithConn(conn *grpc.ClientConn, opts ...ClientOpt) (*Client, error) { conn: conn, runtime: fmt.Sprintf("%s.%s", plugin.RuntimePlugin, runtime.GOOS), } + + // 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["containerd.io/defaults/runtime"]; ok { + c.runtime = defaultRuntime + } + } else { + return nil, err + } + } + if copts.services != nil { c.services = *copts.services } diff --git a/client_test.go b/client_test.go index 2ed367b85..742140839 100644 --- a/client_test.go +++ b/client_test.go @@ -405,11 +405,12 @@ func TestDefaultRuntimeWithNamespaceLabels(t *testing.T) { defer cancel() namespaces := client.NamespaceService() testRuntime := "testRuntime" - if err := namespaces.SetLabel(ctx, testNamespace, "runtime", testRuntime); err != nil { + runtimeLabel := "containerd.io/defaults/runtime" + if err := namespaces.SetLabel(ctx, testNamespace, runtimeLabel, testRuntime); err != nil { t.Fatal(err) } - testClient, err := newClient(t, address, WithDefaultNamespace(testNamespace)) + testClient, err := New(address, WithDefaultNamespace(testNamespace)) if err != nil { t.Fatal(err) } diff --git a/container_opts.go b/container_opts.go index 8f086a729..c04bd2387 100644 --- a/container_opts.go +++ b/container_opts.go @@ -172,7 +172,7 @@ func setSnapshotterIfEmpty(ctx context.Context, client *Client, c *containers.Co namespaceService := client.NamespaceService() if ns, err := namespaces.NamespaceRequired(ctx); err == nil { if labels, err := namespaceService.Labels(ctx, ns); err == nil { - if snapshotLabel, ok := labels["snapshotter"]; ok { + if snapshotLabel, ok := labels["containerd.io/defaults/snapshotter"]; ok { defaultSnapshotter = snapshotLabel } } From da2ab865e04f64e6591e9a7dac5fc56eb2e881f2 Mon Sep 17 00:00:00 2001 From: Nikhil Soni Date: Fri, 1 Feb 2019 23:14:33 +0530 Subject: [PATCH 3/4] Add documentation for using namespace labels for configuring defaults. Signed-off-by: Nikhil Soni --- docs/namespaces.md | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/docs/namespaces.md b/docs/namespaces.md index 5f2fcdddf..ff939b1d0 100644 --- a/docs/namespaces.md +++ b/docs/namespaces.md @@ -34,9 +34,7 @@ Filesystem paths, IDs, and other system level resources must be namespaced for a Simply create a new `context` and set your application's namespace on the `context`. Make sure to use a unique namespace for applications that does not conflict with existing namespaces. The namespaces -API, or the `ctr namespaces` client command, can be used to query/list and create new namespaces. Note that namespaces -can have a list of labels associated with the namespace. This can be useful for associating metadata with a particular -namespace. +API, or the `ctr namespaces` client command, can be used to query/list and create new namespaces. ```go ctx := context.Background() @@ -49,6 +47,19 @@ var ( ) ``` +## Namespace Labels + +Namespaces can have a list of labels associated with the namespace. This can be useful for associating metadata with a particular namespace. +Labels can also be used to configure the defaults for containerd, for example: + +```bash +> sudo ctr namespaces label k8s.io containerd.io/defaults/snapshotter=btrfs +> sudo ctr namespaces label k8s.io containerd.io/defaults/runtime=testRuntime +``` + +This will set the default snapshotter as `btrfs` and runtime as `testRuntime`. +Note that currently only these two labels are used to configure the defaults and labels of `default` namespace are not considered for the same. + ## Inspecting Namespaces If we need to inspect containers, images, or other resources in various namespaces the `ctr` tool allows you to do this. From 6a21728fb6b499ee1a71b0bbd5acc8a7a332902b Mon Sep 17 00:00:00 2001 From: Nikhil Soni Date: Tue, 12 Feb 2019 00:23:57 +0530 Subject: [PATCH 4/4] Use defaults package for listing namespace labels Labels that are used for configuring defaults are moved to defaults package Signed-off-by: Nikhil Soni --- client.go | 4 ++-- client_test.go | 3 ++- container_opts.go | 3 ++- defaults/defaults.go | 6 ++++++ 4 files changed, 12 insertions(+), 4 deletions(-) diff --git a/client.go b/client.go index 386d07aa0..a8946991d 100644 --- a/client.go +++ b/client.go @@ -144,7 +144,7 @@ func New(address string, opts ...ClientOpt) (*Client, error) { namespaces := c.NamespaceService() ctx := context.Background() if labels, err := namespaces.Labels(ctx, copts.defaultns); err == nil { - if defaultRuntime, ok := labels["containerd.io/defaults/runtime"]; ok { + if defaultRuntime, ok := labels[defaults.DefaultRuntimeNSLabel]; ok { c.runtime = defaultRuntime } } else { @@ -174,7 +174,7 @@ func NewWithConn(conn *grpc.ClientConn, opts ...ClientOpt) (*Client, error) { namespaces := c.NamespaceService() ctx := context.Background() if labels, err := namespaces.Labels(ctx, copts.defaultns); err == nil { - if defaultRuntime, ok := labels["containerd.io/defaults/runtime"]; ok { + if defaultRuntime, ok := labels[defaults.DefaultRuntimeNSLabel]; ok { c.runtime = defaultRuntime } } else { diff --git a/client_test.go b/client_test.go index 742140839..d022ac1c2 100644 --- a/client_test.go +++ b/client_test.go @@ -28,6 +28,7 @@ import ( "testing" "time" + "github.com/containerd/containerd/defaults" "github.com/containerd/containerd/images" "github.com/containerd/containerd/log" "github.com/containerd/containerd/namespaces" @@ -405,7 +406,7 @@ func TestDefaultRuntimeWithNamespaceLabels(t *testing.T) { defer cancel() namespaces := client.NamespaceService() testRuntime := "testRuntime" - runtimeLabel := "containerd.io/defaults/runtime" + runtimeLabel := defaults.DefaultRuntimeNSLabel if err := namespaces.SetLabel(ctx, testNamespace, runtimeLabel, testRuntime); err != nil { t.Fatal(err) } diff --git a/container_opts.go b/container_opts.go index c04bd2387..855931959 100644 --- a/container_opts.go +++ b/container_opts.go @@ -20,6 +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" @@ -172,7 +173,7 @@ func setSnapshotterIfEmpty(ctx context.Context, client *Client, c *containers.Co namespaceService := client.NamespaceService() if ns, err := namespaces.NamespaceRequired(ctx); err == nil { if labels, err := namespaceService.Labels(ctx, ns); err == nil { - if snapshotLabel, ok := labels["containerd.io/defaults/snapshotter"]; ok { + if snapshotLabel, ok := labels[defaults.DefaultSnapshotterNSLabel]; ok { defaultSnapshotter = snapshotLabel } } diff --git a/defaults/defaults.go b/defaults/defaults.go index 7040f5b85..3a748e4e8 100644 --- a/defaults/defaults.go +++ b/defaults/defaults.go @@ -23,4 +23,10 @@ const ( // DefaultMaxSendMsgSize defines the default maximum message size for // sending protobufs passed over the GRPC API. DefaultMaxSendMsgSize = 16 << 20 + // DefaultRuntimeNSLabel defines the namespace label to check for + // default runtime + DefaultRuntimeNSLabel = "containerd.io/defaults/runtime" + // DefaultSnapshotterNSLabel defines the namespances label to check for + // default snapshotter + DefaultSnapshotterNSLabel = "containerd.io/defaults/snapshotter" )