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>
| ... | ... |
@@ -965,8 +965,12 @@ func NewDaemon(ctx context.Context, config *config.Config, pluginStore *plugin.S |
| 965 | 965 |
} |
| 966 | 966 |
|
| 967 | 967 |
var rt types.Runtime |
| 968 |
- if runtime := config.GetRuntime(config.GetDefaultRuntimeName()); runtime != nil {
|
|
| 969 |
- rt = *runtime |
|
| 968 |
+ if runtime.GOOS != "windows" {
|
|
| 969 |
+ rtPtr, err := d.getRuntime(config.GetDefaultRuntimeName()) |
|
| 970 |
+ if err != nil {
|
|
| 971 |
+ return nil, err |
|
| 972 |
+ } |
|
| 973 |
+ rt = *rtPtr |
|
| 970 | 974 |
} |
| 971 | 975 |
return pluginexec.New(ctx, getPluginExecRoot(config.Root), pluginCli, config.ContainerdPluginNamespace, m, rt) |
| 972 | 976 |
} |
| ... | ... |
@@ -10,10 +10,12 @@ import ( |
| 10 | 10 |
"path/filepath" |
| 11 | 11 |
"strings" |
| 12 | 12 |
|
| 13 |
+ "github.com/containerd/cgroups" |
|
| 13 | 14 |
"github.com/containerd/containerd/runtime/linux/runctypes" |
| 14 | 15 |
v2runcoptions "github.com/containerd/containerd/runtime/v2/runc/options" |
| 15 | 16 |
"github.com/docker/docker/api/types" |
| 16 | 17 |
"github.com/docker/docker/daemon/config" |
| 18 |
+ "github.com/docker/docker/errdefs" |
|
| 17 | 19 |
"github.com/docker/docker/pkg/ioutils" |
| 18 | 20 |
"github.com/pkg/errors" |
| 19 | 21 |
"github.com/sirupsen/logrus" |
| ... | ... |
@@ -96,14 +98,15 @@ func (daemon *Daemon) initRuntimes(runtimes map[string]types.Runtime) (err error |
| 96 | 96 |
}() |
| 97 | 97 |
|
| 98 | 98 |
for name, rt := range runtimes {
|
| 99 |
- if len(rt.Args) == 0 {
|
|
| 100 |
- continue |
|
| 99 |
+ if len(rt.Args) > 0 {
|
|
| 100 |
+ script := filepath.Join(tmpDir, name) |
|
| 101 |
+ content := fmt.Sprintf("#!/bin/sh\n%s %s $@\n", rt.Path, strings.Join(rt.Args, " "))
|
|
| 102 |
+ if err := ioutil.WriteFile(script, []byte(content), 0700); err != nil {
|
|
| 103 |
+ return err |
|
| 104 |
+ } |
|
| 101 | 105 |
} |
| 102 |
- |
|
| 103 |
- script := filepath.Join(tmpDir, name) |
|
| 104 |
- content := fmt.Sprintf("#!/bin/sh\n%s %s $@\n", rt.Path, strings.Join(rt.Args, " "))
|
|
| 105 |
- if err := ioutil.WriteFile(script, []byte(content), 0700); err != nil {
|
|
| 106 |
- return err |
|
| 106 |
+ if rt.Shim == nil {
|
|
| 107 |
+ rt.Shim = defaultV2ShimConfig(daemon.configStore, rt.Path) |
|
| 107 | 108 |
} |
| 108 | 109 |
} |
| 109 | 110 |
return nil |
| ... | ... |
@@ -124,3 +127,32 @@ func (daemon *Daemon) rewriteRuntimePath(name, p string, args []string) (string, |
| 124 | 124 |
|
| 125 | 125 |
return filepath.Join(daemon.configStore.Root, "runtimes", name), nil |
| 126 | 126 |
} |
| 127 |
+ |
|
| 128 |
+func (daemon *Daemon) getRuntime(name string) (*types.Runtime, error) {
|
|
| 129 |
+ rt := daemon.configStore.GetRuntime(name) |
|
| 130 |
+ if rt == nil {
|
|
| 131 |
+ return nil, errdefs.InvalidParameter(errors.Errorf("runtime not found in config: %s", name))
|
|
| 132 |
+ } |
|
| 133 |
+ |
|
| 134 |
+ if len(rt.Args) > 0 {
|
|
| 135 |
+ p, err := daemon.rewriteRuntimePath(name, rt.Path, rt.Args) |
|
| 136 |
+ if err != nil {
|
|
| 137 |
+ return nil, err |
|
| 138 |
+ } |
|
| 139 |
+ rt.Path = p |
|
| 140 |
+ rt.Args = nil |
|
| 141 |
+ } |
|
| 142 |
+ |
|
| 143 |
+ if rt.Shim == nil {
|
|
| 144 |
+ rt.Shim = defaultV2ShimConfig(daemon.configStore, rt.Path) |
|
| 145 |
+ } |
|
| 146 |
+ |
|
| 147 |
+ if rt.Shim.Binary == linuxShimV1 {
|
|
| 148 |
+ if cgroups.Mode() == cgroups.Unified {
|
|
| 149 |
+ return nil, errdefs.InvalidParameter(errors.Errorf("runtime %q is not supported while cgroups v2 (unified hierarchy) is being used", name))
|
|
| 150 |
+ } |
|
| 151 |
+ logrus.Warnf("Configured runtime %q is deprecated and will be removed in the next release", name)
|
|
| 152 |
+ } |
|
| 153 |
+ |
|
| 154 |
+ return rt, nil |
|
| 155 |
+} |
| ... | ... |
@@ -3,11 +3,7 @@ |
| 3 | 3 |
package daemon // import "github.com/docker/docker/daemon" |
| 4 | 4 |
|
| 5 | 5 |
import ( |
| 6 |
- "github.com/containerd/cgroups" |
|
| 7 | 6 |
"github.com/docker/docker/container" |
| 8 |
- "github.com/docker/docker/errdefs" |
|
| 9 |
- "github.com/pkg/errors" |
|
| 10 |
- "github.com/sirupsen/logrus" |
|
| 11 | 7 |
) |
| 12 | 8 |
|
| 13 | 9 |
// getLibcontainerdCreateOptions callers must hold a lock on the container |
| ... | ... |
@@ -18,19 +14,9 @@ func (daemon *Daemon) getLibcontainerdCreateOptions(container *container.Contain |
| 18 | 18 |
container.CheckpointTo(daemon.containersReplica) |
| 19 | 19 |
} |
| 20 | 20 |
|
| 21 |
- rt := daemon.configStore.GetRuntime(container.HostConfig.Runtime) |
|
| 22 |
- if rt.Shim == nil {
|
|
| 23 |
- p, err := daemon.rewriteRuntimePath(container.HostConfig.Runtime, rt.Path, rt.Args) |
|
| 24 |
- if err != nil {
|
|
| 25 |
- return "", nil, translateContainerdStartErr(container.Path, container.SetExitCode, err) |
|
| 26 |
- } |
|
| 27 |
- rt.Shim = defaultV2ShimConfig(daemon.configStore, p) |
|
| 28 |
- } |
|
| 29 |
- if rt.Shim.Binary == linuxShimV1 {
|
|
| 30 |
- if cgroups.Mode() == cgroups.Unified {
|
|
| 31 |
- return "", nil, errdefs.InvalidParameter(errors.Errorf("runtime %q is not supported while cgroups v2 (unified hierarchy) is being used", container.HostConfig.Runtime))
|
|
| 32 |
- } |
|
| 33 |
- logrus.Warnf("Configured runtime %q is deprecated and will be removed in the next release", container.HostConfig.Runtime)
|
|
| 21 |
+ rt, err := daemon.getRuntime(container.HostConfig.Runtime) |
|
| 22 |
+ if err != nil {
|
|
| 23 |
+ return "", nil, translateContainerdStartErr(container.Path, container.SetExitCode, err) |
|
| 34 | 24 |
} |
| 35 | 25 |
|
| 36 | 26 |
return rt.Shim.Binary, rt.Shim.Opts, nil |
| ... | ... |
@@ -4,11 +4,14 @@ import ( |
| 4 | 4 |
"context" |
| 5 | 5 |
"encoding/base64" |
| 6 | 6 |
"encoding/json" |
| 7 |
+ "fmt" |
|
| 7 | 8 |
"io" |
| 8 | 9 |
"io/ioutil" |
| 9 | 10 |
"net" |
| 10 | 11 |
"net/http" |
| 12 |
+ "os" |
|
| 11 | 13 |
"path" |
| 14 |
+ "path/filepath" |
|
| 12 | 15 |
"strings" |
| 13 | 16 |
"testing" |
| 14 | 17 |
|
| ... | ... |
@@ -157,3 +160,66 @@ func TestPluginInstall(t *testing.T) {
|
| 157 | 157 |
}) |
| 158 | 158 |
// TODO: test insecure registry with https |
| 159 | 159 |
} |
| 160 |
+ |
|
| 161 |
+func TestPluginsWithRuntimes(t *testing.T) {
|
|
| 162 |
+ skip.If(t, testEnv.IsRemoteDaemon, "cannot run daemon when remote daemon") |
|
| 163 |
+ skip.If(t, testEnv.IsRootless, "Test not supported on rootless due to buggy daemon setup in rootless mode due to daemon restart") |
|
| 164 |
+ skip.If(t, testEnv.OSType == "windows") |
|
| 165 |
+ |
|
| 166 |
+ dir, err := ioutil.TempDir("", t.Name())
|
|
| 167 |
+ assert.NilError(t, err) |
|
| 168 |
+ defer os.RemoveAll(dir) |
|
| 169 |
+ |
|
| 170 |
+ d := daemon.New(t) |
|
| 171 |
+ defer d.Cleanup(t) |
|
| 172 |
+ |
|
| 173 |
+ d.Start(t) |
|
| 174 |
+ defer d.Stop(t) |
|
| 175 |
+ |
|
| 176 |
+ ctx := context.Background() |
|
| 177 |
+ client := d.NewClientT(t) |
|
| 178 |
+ |
|
| 179 |
+ assert.NilError(t, plugin.Create(ctx, client, "test:latest")) |
|
| 180 |
+ defer client.PluginRemove(ctx, "test:latest", types.PluginRemoveOptions{Force: true})
|
|
| 181 |
+ |
|
| 182 |
+ assert.NilError(t, client.PluginEnable(ctx, "test:latest", types.PluginEnableOptions{Timeout: 30}))
|
|
| 183 |
+ |
|
| 184 |
+ p := filepath.Join(dir, "myrt") |
|
| 185 |
+ script := fmt.Sprintf(`#!/bin/sh |
|
| 186 |
+ file="%s/success" |
|
| 187 |
+ if [ "$1" = "someArg" ]; then |
|
| 188 |
+ shift |
|
| 189 |
+ file="${file}_someArg"
|
|
| 190 |
+ fi |
|
| 191 |
+ |
|
| 192 |
+ touch $file |
|
| 193 |
+ exec runc $@ |
|
| 194 |
+ `, dir) |
|
| 195 |
+ |
|
| 196 |
+ assert.NilError(t, ioutil.WriteFile(p, []byte(script), 0777)) |
|
| 197 |
+ |
|
| 198 |
+ type config struct {
|
|
| 199 |
+ Runtimes map[string]types.Runtime `json:"runtimes"` |
|
| 200 |
+ } |
|
| 201 |
+ |
|
| 202 |
+ cfg, err := json.Marshal(config{
|
|
| 203 |
+ Runtimes: map[string]types.Runtime{
|
|
| 204 |
+ "myrt": {Path: p},
|
|
| 205 |
+ "myrtArgs": {Path: p, Args: []string{"someArg"}},
|
|
| 206 |
+ }, |
|
| 207 |
+ }) |
|
| 208 |
+ configPath := filepath.Join(dir, "config.json") |
|
| 209 |
+ ioutil.WriteFile(configPath, cfg, 0644) |
|
| 210 |
+ |
|
| 211 |
+ t.Run("No Args", func(t *testing.T) {
|
|
| 212 |
+ d.Restart(t, "--default-runtime=myrt", "--config-file="+configPath) |
|
| 213 |
+ _, err = os.Stat(filepath.Join(dir, "success")) |
|
| 214 |
+ assert.NilError(t, err) |
|
| 215 |
+ }) |
|
| 216 |
+ |
|
| 217 |
+ t.Run("With Args", func(t *testing.T) {
|
|
| 218 |
+ d.Restart(t, "--default-runtime=myrtArgs", "--config-file="+configPath) |
|
| 219 |
+ _, err = os.Stat(filepath.Join(dir, "success_someArg")) |
|
| 220 |
+ assert.NilError(t, err) |
|
| 221 |
+ }) |
|
| 222 |
+} |