diff --git a/daemon/daemon.go b/daemon/daemon.go index 3e86ab5c87..66df2fc98a 100644 --- a/daemon/daemon.go +++ b/daemon/daemon.go @@ -965,8 +965,12 @@ func NewDaemon(ctx context.Context, config *config.Config, pluginStore *plugin.S } var rt types.Runtime - if runtime := config.GetRuntime(config.GetDefaultRuntimeName()); runtime != nil { - rt = *runtime + if runtime.GOOS != "windows" { + rtPtr, err := d.getRuntime(config.GetDefaultRuntimeName()) + if err != nil { + return nil, err + } + rt = *rtPtr } return pluginexec.New(ctx, getPluginExecRoot(config.Root), pluginCli, config.ContainerdPluginNamespace, m, rt) } diff --git a/daemon/runtime_unix.go b/daemon/runtime_unix.go index 2f2011f2e3..6c57e2455b 100644 --- a/daemon/runtime_unix.go +++ b/daemon/runtime_unix.go @@ -10,10 +10,12 @@ import ( "path/filepath" "strings" + "github.com/containerd/cgroups" "github.com/containerd/containerd/runtime/linux/runctypes" v2runcoptions "github.com/containerd/containerd/runtime/v2/runc/options" "github.com/docker/docker/api/types" "github.com/docker/docker/daemon/config" + "github.com/docker/docker/errdefs" "github.com/docker/docker/pkg/ioutils" "github.com/pkg/errors" "github.com/sirupsen/logrus" @@ -96,14 +98,15 @@ func (daemon *Daemon) initRuntimes(runtimes map[string]types.Runtime) (err error }() for name, rt := range runtimes { - if len(rt.Args) == 0 { - continue + if len(rt.Args) > 0 { + script := filepath.Join(tmpDir, name) + content := fmt.Sprintf("#!/bin/sh\n%s %s $@\n", rt.Path, strings.Join(rt.Args, " ")) + if err := ioutil.WriteFile(script, []byte(content), 0700); err != nil { + return err + } } - - script := filepath.Join(tmpDir, name) - content := fmt.Sprintf("#!/bin/sh\n%s %s $@\n", rt.Path, strings.Join(rt.Args, " ")) - if err := ioutil.WriteFile(script, []byte(content), 0700); err != nil { - return err + if rt.Shim == nil { + rt.Shim = defaultV2ShimConfig(daemon.configStore, rt.Path) } } return nil @@ -124,3 +127,32 @@ func (daemon *Daemon) rewriteRuntimePath(name, p string, args []string) (string, return filepath.Join(daemon.configStore.Root, "runtimes", name), nil } + +func (daemon *Daemon) getRuntime(name string) (*types.Runtime, error) { + rt := daemon.configStore.GetRuntime(name) + if rt == nil { + return nil, errdefs.InvalidParameter(errors.Errorf("runtime not found in config: %s", name)) + } + + if len(rt.Args) > 0 { + p, err := daemon.rewriteRuntimePath(name, rt.Path, rt.Args) + if err != nil { + return nil, err + } + rt.Path = p + rt.Args = nil + } + + if rt.Shim == nil { + rt.Shim = defaultV2ShimConfig(daemon.configStore, rt.Path) + } + + if rt.Shim.Binary == linuxShimV1 { + if cgroups.Mode() == cgroups.Unified { + return nil, errdefs.InvalidParameter(errors.Errorf("runtime %q is not supported while cgroups v2 (unified hierarchy) is being used", name)) + } + logrus.Warnf("Configured runtime %q is deprecated and will be removed in the next release", name) + } + + return rt, nil +} diff --git a/daemon/runtime_windows.go b/daemon/runtime_windows.go new file mode 100644 index 0000000000..0787cb1155 --- /dev/null +++ b/daemon/runtime_windows.go @@ -0,0 +1,10 @@ +package daemon + +import ( + "github.com/docker/docker/api/types" + "github.com/pkg/errors" +) + +func (daemon *Daemon) getRuntime(name string) (*types.Runtime, error) { + return nil, errors.New("not implemented") +} diff --git a/daemon/start_unix.go b/daemon/start_unix.go index 7b70451162..2b4dc95106 100644 --- a/daemon/start_unix.go +++ b/daemon/start_unix.go @@ -3,11 +3,7 @@ package daemon // import "github.com/docker/docker/daemon" import ( - "github.com/containerd/cgroups" "github.com/docker/docker/container" - "github.com/docker/docker/errdefs" - "github.com/pkg/errors" - "github.com/sirupsen/logrus" ) // getLibcontainerdCreateOptions callers must hold a lock on the container @@ -18,19 +14,9 @@ func (daemon *Daemon) getLibcontainerdCreateOptions(container *container.Contain container.CheckpointTo(daemon.containersReplica) } - rt := daemon.configStore.GetRuntime(container.HostConfig.Runtime) - if rt.Shim == nil { - p, err := daemon.rewriteRuntimePath(container.HostConfig.Runtime, rt.Path, rt.Args) - if err != nil { - return "", nil, translateContainerdStartErr(container.Path, container.SetExitCode, err) - } - rt.Shim = defaultV2ShimConfig(daemon.configStore, p) - } - if rt.Shim.Binary == linuxShimV1 { - if cgroups.Mode() == cgroups.Unified { - return "", nil, errdefs.InvalidParameter(errors.Errorf("runtime %q is not supported while cgroups v2 (unified hierarchy) is being used", container.HostConfig.Runtime)) - } - logrus.Warnf("Configured runtime %q is deprecated and will be removed in the next release", container.HostConfig.Runtime) + rt, err := daemon.getRuntime(container.HostConfig.Runtime) + if err != nil { + return "", nil, translateContainerdStartErr(container.Path, container.SetExitCode, err) } return rt.Shim.Binary, rt.Shim.Opts, nil diff --git a/integration/plugin/common/plugin_test.go b/integration/plugin/common/plugin_test.go index b2c824e8c4..055381dcfb 100644 --- a/integration/plugin/common/plugin_test.go +++ b/integration/plugin/common/plugin_test.go @@ -4,11 +4,14 @@ import ( "context" "encoding/base64" "encoding/json" + "fmt" "io" "io/ioutil" "net" "net/http" + "os" "path" + "path/filepath" "strings" "testing" @@ -157,3 +160,66 @@ func TestPluginInstall(t *testing.T) { }) // TODO: test insecure registry with https } + +func TestPluginsWithRuntimes(t *testing.T) { + skip.If(t, testEnv.IsRemoteDaemon, "cannot run daemon when remote daemon") + skip.If(t, testEnv.IsRootless, "Test not supported on rootless due to buggy daemon setup in rootless mode due to daemon restart") + skip.If(t, testEnv.OSType == "windows") + + dir, err := ioutil.TempDir("", t.Name()) + assert.NilError(t, err) + defer os.RemoveAll(dir) + + d := daemon.New(t) + defer d.Cleanup(t) + + d.Start(t) + defer d.Stop(t) + + ctx := context.Background() + client := d.NewClientT(t) + + assert.NilError(t, plugin.Create(ctx, client, "test:latest")) + defer client.PluginRemove(ctx, "test:latest", types.PluginRemoveOptions{Force: true}) + + assert.NilError(t, client.PluginEnable(ctx, "test:latest", types.PluginEnableOptions{Timeout: 30})) + + p := filepath.Join(dir, "myrt") + script := fmt.Sprintf(`#!/bin/sh + file="%s/success" + if [ "$1" = "someArg" ]; then + shift + file="${file}_someArg" + fi + + touch $file + exec runc $@ + `, dir) + + assert.NilError(t, ioutil.WriteFile(p, []byte(script), 0777)) + + type config struct { + Runtimes map[string]types.Runtime `json:"runtimes"` + } + + cfg, err := json.Marshal(config{ + Runtimes: map[string]types.Runtime{ + "myrt": {Path: p}, + "myrtArgs": {Path: p, Args: []string{"someArg"}}, + }, + }) + configPath := filepath.Join(dir, "config.json") + ioutil.WriteFile(configPath, cfg, 0644) + + t.Run("No Args", func(t *testing.T) { + d.Restart(t, "--default-runtime=myrt", "--config-file="+configPath) + _, err = os.Stat(filepath.Join(dir, "success")) + assert.NilError(t, err) + }) + + t.Run("With Args", func(t *testing.T) { + d.Restart(t, "--default-runtime=myrtArgs", "--config-file="+configPath) + _, err = os.Stat(filepath.Join(dir, "success_someArg")) + assert.NilError(t, err) + }) +}