From e7189a25c30791232dfcf38ca1eee544ebd7f801 Mon Sep 17 00:00:00 2001 From: Tim Allclair Date: Tue, 4 Sep 2018 15:29:35 -0700 Subject: [PATCH] Add RuntimeHandler support Signed-off-by: Tim Allclair --- cri.go | 16 +++++++++ docs/config.md | 18 +++++++++++ pkg/config/config.go | 15 ++++++++- pkg/server/sandbox_run.go | 32 ++++++++++++------ pkg/server/sandbox_run_test.go | 59 +++++++++++++++++++++++++++++++++- 5 files changed, 128 insertions(+), 12 deletions(-) diff --git a/cri.go b/cri.go index ba94ebc4e..c06b050e6 100644 --- a/cri.go +++ b/cri.go @@ -71,6 +71,10 @@ func initCRIService(ic *plugin.InitContext) (interface{}, error) { } log.G(ctx).Infof("Start cri plugin with config %+v", c) + if err := validateConfig(&c); err != nil { + return nil, errors.Wrap(err, "invalid config") + } + if err := setGLogLevel(); err != nil { return nil, errors.Wrap(err, "failed to set glog level") } @@ -104,6 +108,18 @@ func initCRIService(ic *plugin.InitContext) (interface{}, error) { return s, nil } +// validateConfig validates the given configuration. +func validateConfig(c *criconfig.Config) error { + // It is an error to provide both an UntrustedWorkloadRuntime & define an 'untrusted' runtime. + if _, ok := c.ContainerdConfig.Runtimes[criconfig.RuntimeUntrusted]; ok { + if c.ContainerdConfig.UntrustedWorkloadRuntime.Type != "" { + return errors.New("conflicting definitions: configuration includes untrusted_workload_runtime and runtimes['untrusted']") + } + } + + return nil +} + // getServicesOpts get service options from plugin context. func getServicesOpts(ic *plugin.InitContext) ([]containerd.ServicesOpt, error) { plugins, err := ic.GetByType(plugin.ServicePlugin) diff --git a/docs/config.md b/docs/config.md index 0b8798bc9..f005c13cd 100644 --- a/docs/config.md +++ b/docs/config.md @@ -61,6 +61,11 @@ The explanation and default value of each configuration item are as follows: runtime_root = "" # "plugins.cri.containerd.untrusted_workload_runtime" is a runtime to run untrusted workloads on it. + + # DEPRECATED: use plugins.cri.runtimes instead. If provided, this runtime is mapped to the + # runtime handler named 'untrusted'. It is a configuration error to provide both the (now + # deprecated) UntrustedWorkloadRuntime and a handler in the Runtimes handler map (below) for + # 'untrusted' workloads at the same time. Please provide one or the other. [plugins.cri.containerd.untrusted_workload_runtime] # runtime_type is the runtime type to use in containerd e.g. io.containerd.runtime.v1.linux runtime_type = "" @@ -71,6 +76,19 @@ The explanation and default value of each configuration item are as follows: # runtime_root is the directory used by containerd for runtime state. runtime_root = "" + # plugins.cri.containerd.runtimes is a map from CRI RuntimeHandler strings, which specify types + # of runtime configurations, to the matching configurations. In this example, + # 'runtime_handler_name' is the RuntimeHandler string to match. + [plugins.cri.containerd.runtimes.runtime_handler_name] + # runtime_type is the runtime type to use in containerd e.g. io.containerd.runtime.v1.linux + runtime_type = "" + + # runtime_engine is the name of the runtime engine used by containerd. + runtime_engine = "" + + # runtime_root is the directory used by containerd for runtime state. + runtime_root = "" + # "plugins.cri.cni" contains config related to cni [plugins.cri.cni] # bin_dir is the directory in which the binaries for the plugin is kept. diff --git a/pkg/config/config.go b/pkg/config/config.go index 49288b59a..7fa993c85 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -33,10 +33,18 @@ type Runtime struct { type ContainerdConfig struct { // Snapshotter is the snapshotter used by containerd. Snapshotter string `toml:"snapshotter" json:"snapshotter"` - // DefaultRuntime is the runtime to use in containerd. + // DefaultRuntime is the default runtime to use in containerd. + // This runtime is used when no runtime handler (or the empty string) is provided. DefaultRuntime Runtime `toml:"default_runtime" json:"defaultRuntime"` // UntrustedWorkloadRuntime is a runtime to run untrusted workloads on it. + // DEPRECATED: use Runtimes instead. If provided, this runtime is mapped to the runtime handler + // named 'untrusted'. It is a configuration error to provide both the (now deprecated) + // UntrustedWorkloadRuntime and a handler in the Runtimes handler map (below) for 'untrusted' + // workloads at the same time. Please provide one or the other. UntrustedWorkloadRuntime Runtime `toml:"untrusted_workload_runtime" json:"untrustedWorkloadRuntime"` + // Runtimes is a map from CRI RuntimeHandler strings, which specify types of runtime + // configurations, to the matching configurations. + Runtimes map[string]Runtime `toml:"runtimes" json:"runtimes"` // NoPivot disables pivot-root (linux only), required when running a container in a RamDisk with runc NoPivot bool `toml:"no_pivot" json:"noPivot"` } @@ -183,3 +191,8 @@ func DefaultConfig() PluginConfig { }, } } + +const ( + // RuntimeUntrusted is the implicit runtime defined for ContainerdConfig.UntrustedWorkloadRuntime + RuntimeUntrusted = "untrusted" +) diff --git a/pkg/server/sandbox_run.go b/pkg/server/sandbox_run.go index 38f763223..0562f1aa5 100644 --- a/pkg/server/sandbox_run.go +++ b/pkg/server/sandbox_run.go @@ -131,7 +131,7 @@ func (c *criService) RunPodSandbox(ctx context.Context, r *runtime.RunPodSandbox }() } - ociRuntime, err := c.getSandboxRuntime(config) + ociRuntime, err := c.getSandboxRuntime(config, r.GetRuntimeHandler()) if err != nil { return nil, errors.Wrap(err, "failed to get sandbox runtime") } @@ -601,9 +601,13 @@ func hostAccessingSandbox(config *runtime.PodSandboxConfig) bool { // getSandboxRuntime returns the runtime configuration for sandbox. // If the sandbox contains untrusted workload, runtime for untrusted workload will be returned, // or else default runtime will be returned. -func (c *criService) getSandboxRuntime(config *runtime.PodSandboxConfig) (criconfig.Runtime, error) { - untrusted := false +func (c *criService) getSandboxRuntime(config *runtime.PodSandboxConfig, runtimeHandler string) (criconfig.Runtime, error) { if untrustedWorkload(config) { + // If the untrusted annotation is provided, runtimeHandler MUST be empty. + if runtimeHandler != "" && runtimeHandler != criconfig.RuntimeUntrusted { + return criconfig.Runtime{}, errors.New("untrusted workload with explicit runtime handler is not allowed") + } + // If the untrusted workload is requesting access to the host/node, this request will fail. // // Note: If the workload is marked untrusted but requests privileged, this can be granted, as the @@ -612,14 +616,22 @@ func (c *criService) getSandboxRuntime(config *runtime.PodSandboxConfig) (cricon if hostAccessingSandbox(config) { return criconfig.Runtime{}, errors.New("untrusted workload with host access is not allowed") } - untrusted = true + + // Handle the deprecated UntrustedWorkloadRuntime. + if c.config.ContainerdConfig.UntrustedWorkloadRuntime.Type != "" { + return c.config.ContainerdConfig.UntrustedWorkloadRuntime, nil + } + + runtimeHandler = criconfig.RuntimeUntrusted } - if untrusted { - if c.config.ContainerdConfig.UntrustedWorkloadRuntime.Type == "" { - return criconfig.Runtime{}, errors.New("no runtime for untrusted workload is configured") - } - return c.config.ContainerdConfig.UntrustedWorkloadRuntime, nil + if runtimeHandler == "" { + return c.config.ContainerdConfig.DefaultRuntime, nil } - return c.config.ContainerdConfig.DefaultRuntime, nil + + handler, ok := c.config.ContainerdConfig.Runtimes[runtimeHandler] + if !ok { + return criconfig.Runtime{}, errors.Errorf("no runtime for %q is configured", runtimeHandler) + } + return handler, nil } diff --git a/pkg/server/sandbox_run_test.go b/pkg/server/sandbox_run_test.go index 56120de83..b729f3042 100644 --- a/pkg/server/sandbox_run_test.go +++ b/pkg/server/sandbox_run_test.go @@ -533,10 +533,18 @@ func TestGetSandboxRuntime(t *testing.T) { Root: "", } + fooRuntime := criconfig.Runtime{ + Type: "io.containerd.runtime.v1.linux", + Engine: "foo-bar", + Root: "", + } + for desc, test := range map[string]struct { sandboxConfig *runtime.PodSandboxConfig + runtimeHandler string defaultRuntime criconfig.Runtime untrustedWorkloadRuntime criconfig.Runtime + runtimes map[string]criconfig.Runtime expectErr bool expectedRuntime criconfig.Runtime }{ @@ -595,6 +603,54 @@ func TestGetSandboxRuntime(t *testing.T) { defaultRuntime: defaultRuntime, expectErr: true, }, + "should use 'untrusted' runtime for untrusted workload": { + sandboxConfig: &runtime.PodSandboxConfig{ + Annotations: map[string]string{ + annotations.UntrustedWorkload: "true", + }, + }, + defaultRuntime: defaultRuntime, + runtimes: map[string]criconfig.Runtime{criconfig.RuntimeUntrusted: untrustedWorkloadRuntime}, + expectedRuntime: untrustedWorkloadRuntime, + }, + "should use 'untrusted' runtime for untrusted workload & handler": { + sandboxConfig: &runtime.PodSandboxConfig{ + Annotations: map[string]string{ + annotations.UntrustedWorkload: "true", + }, + }, + runtimeHandler: "untrusted", + defaultRuntime: defaultRuntime, + runtimes: map[string]criconfig.Runtime{criconfig.RuntimeUntrusted: untrustedWorkloadRuntime}, + expectedRuntime: untrustedWorkloadRuntime, + }, + "should return an error if untrusted annotation with conflicting handler": { + sandboxConfig: &runtime.PodSandboxConfig{ + Annotations: map[string]string{ + annotations.UntrustedWorkload: "true", + }, + }, + runtimeHandler: "foo", + defaultRuntime: defaultRuntime, + untrustedWorkloadRuntime: untrustedWorkloadRuntime, + runtimes: map[string]criconfig.Runtime{"foo": fooRuntime}, + expectErr: true, + }, + "should use correct runtime for a runtime handler": { + sandboxConfig: &runtime.PodSandboxConfig{}, + runtimeHandler: "foo", + defaultRuntime: defaultRuntime, + untrustedWorkloadRuntime: untrustedWorkloadRuntime, + runtimes: map[string]criconfig.Runtime{"foo": fooRuntime}, + expectedRuntime: fooRuntime, + }, + "should return error if runtime handler is required but not configured": { + sandboxConfig: &runtime.PodSandboxConfig{}, + runtimeHandler: "bar", + defaultRuntime: defaultRuntime, + runtimes: map[string]criconfig.Runtime{"foo": fooRuntime}, + expectErr: true, + }, } { t.Run(desc, func(t *testing.T) { cri := newTestCRIService() @@ -603,7 +659,8 @@ func TestGetSandboxRuntime(t *testing.T) { } cri.config.ContainerdConfig.DefaultRuntime = test.defaultRuntime cri.config.ContainerdConfig.UntrustedWorkloadRuntime = test.untrustedWorkloadRuntime - r, err := cri.getSandboxRuntime(test.sandboxConfig) + cri.config.ContainerdConfig.Runtimes = test.runtimes + r, err := cri.getSandboxRuntime(test.sandboxConfig, test.runtimeHandler) assert.Equal(t, test.expectErr, err != nil) assert.Equal(t, test.expectedRuntime, r) })