Sfoglia il codice sorgente

Add shim config for custom runtimes for plugins

This fixes a panic when an admin specifies a custom default runtime,
when a plugin is started the shim config is nil.

Signed-off-by: Brian Goff <cpuguy83@gmail.com>
(cherry picked from commit 2903863a1d7313118255dc8cc0664cdfe3e6a379)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
Brian Goff 4 anni fa
parent
commit
df2a989769

+ 6 - 2
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)
 	}

+ 39 - 7
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
+}

+ 10 - 0
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")
+}

+ 3 - 17
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

+ 66 - 0
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)
+	})
+}