Signed-off-by: Kenfe-Mickael Laventure <mickael.laventure@gmail.com>
Kenfe-Mickael Laventure authored on 2016/05/24 06:49:50... | ... |
@@ -55,7 +55,7 @@ func (cli *DockerCli) CmdInfo(args ...string) error { |
55 | 55 |
ioutils.FprintfIfNotEmpty(cli.out, "Logging Driver: %s\n", info.LoggingDriver) |
56 | 56 |
ioutils.FprintfIfNotEmpty(cli.out, "Cgroup Driver: %s\n", info.CgroupDriver) |
57 | 57 |
|
58 |
- fmt.Fprintf(cli.out, "Plugins: \n") |
|
58 |
+ fmt.Fprintf(cli.out, "Plugins:\n") |
|
59 | 59 |
fmt.Fprintf(cli.out, " Volume:") |
60 | 60 |
fmt.Fprintf(cli.out, " %s", strings.Join(info.Plugins.Volume, " ")) |
61 | 61 |
fmt.Fprintf(cli.out, "\n") |
... | ... |
@@ -84,6 +84,16 @@ func (cli *DockerCli) CmdInfo(args ...string) error { |
84 | 84 |
fmt.Fprintf(cli.out, " IsManager: No\n") |
85 | 85 |
} |
86 | 86 |
} |
87 |
+ |
|
88 |
+ if len(info.Runtimes) > 0 { |
|
89 |
+ fmt.Fprintf(cli.out, "Runtimes:") |
|
90 |
+ for name := range info.Runtimes { |
|
91 |
+ fmt.Fprintf(cli.out, " %s", name) |
|
92 |
+ } |
|
93 |
+ fmt.Fprint(cli.out, "\n") |
|
94 |
+ fmt.Fprintf(cli.out, "Default Runtime: %s\n", info.DefaultRuntime) |
|
95 |
+ } |
|
96 |
+ |
|
87 | 97 |
ioutils.FprintfIfNotEmpty(cli.out, "Kernel Version: %s\n", info.KernelVersion) |
88 | 98 |
ioutils.FprintfIfNotEmpty(cli.out, "Operating System: %s\n", info.OperatingSystem) |
89 | 99 |
ioutils.FprintfIfNotEmpty(cli.out, "OSType: %s\n", info.OSType) |
... | ... |
@@ -388,6 +388,10 @@ func loadDaemonCliConfig(config *daemon.Config, flags *flag.FlagSet, commonConfi |
388 | 388 |
} |
389 | 389 |
} |
390 | 390 |
|
391 |
+ if err := daemon.ValidateConfiguration(config); err != nil { |
|
392 |
+ return nil, err |
|
393 |
+ } |
|
394 |
+ |
|
391 | 395 |
// Regardless of whether the user sets it to true or false, if they |
392 | 396 |
// specify TLSVerify at all then we need to turn on TLS |
393 | 397 |
if config.IsValueSet(cliflags.TLSVerifyKey) { |
... | ... |
@@ -74,6 +74,7 @@ func (cli *DaemonCli) getPlatformRemoteOptions() []libcontainerd.RemoteOption { |
74 | 74 |
if cli.Config.LiveRestore { |
75 | 75 |
opts = append(opts, libcontainerd.WithLiveRestore(true)) |
76 | 76 |
} |
77 |
+ opts = append(opts, libcontainerd.WithRuntimePath(daemon.DefaultRuntimeBinary)) |
|
77 | 78 |
return opts |
78 | 79 |
} |
79 | 80 |
|
... | ... |
@@ -14,6 +14,7 @@ import ( |
14 | 14 |
"github.com/docker/docker/pkg/discovery" |
15 | 15 |
flag "github.com/docker/docker/pkg/mflag" |
16 | 16 |
"github.com/docker/docker/registry" |
17 |
+ "github.com/docker/engine-api/types" |
|
17 | 18 |
"github.com/imdario/mergo" |
18 | 19 |
) |
19 | 20 |
|
... | ... |
@@ -40,6 +41,7 @@ const ( |
40 | 40 |
var flatOptions = map[string]bool{ |
41 | 41 |
"cluster-store-opts": true, |
42 | 42 |
"log-opts": true, |
43 |
+ "runtimes": true, |
|
43 | 44 |
} |
44 | 45 |
|
45 | 46 |
// LogConfig represents the default log configuration. |
... | ... |
@@ -200,7 +202,7 @@ func ReloadConfiguration(configFile string, flags *flag.FlagSet, reload func(*Co |
200 | 200 |
return err |
201 | 201 |
} |
202 | 202 |
|
203 |
- if err := validateConfiguration(newConfig); err != nil { |
|
203 |
+ if err := ValidateConfiguration(newConfig); err != nil { |
|
204 | 204 |
return fmt.Errorf("file configuration validation failed (%v)", err) |
205 | 205 |
} |
206 | 206 |
|
... | ... |
@@ -224,7 +226,7 @@ func MergeDaemonConfigurations(flagsConfig *Config, flags *flag.FlagSet, configF |
224 | 224 |
return nil, err |
225 | 225 |
} |
226 | 226 |
|
227 |
- if err := validateConfiguration(fileConfig); err != nil { |
|
227 |
+ if err := ValidateConfiguration(fileConfig); err != nil { |
|
228 | 228 |
return nil, fmt.Errorf("file configuration validation failed (%v)", err) |
229 | 229 |
} |
230 | 230 |
|
... | ... |
@@ -233,6 +235,12 @@ func MergeDaemonConfigurations(flagsConfig *Config, flags *flag.FlagSet, configF |
233 | 233 |
return nil, err |
234 | 234 |
} |
235 | 235 |
|
236 |
+ // We need to validate again once both fileConfig and flagsConfig |
|
237 |
+ // have been merged |
|
238 |
+ if err := ValidateConfiguration(fileConfig); err != nil { |
|
239 |
+ return nil, fmt.Errorf("file configuration validation failed (%v)", err) |
|
240 |
+ } |
|
241 |
+ |
|
236 | 242 |
return fileConfig, nil |
237 | 243 |
} |
238 | 244 |
|
... | ... |
@@ -381,10 +389,10 @@ func findConfigurationConflicts(config map[string]interface{}, flags *flag.FlagS |
381 | 381 |
return nil |
382 | 382 |
} |
383 | 383 |
|
384 |
-// validateConfiguration validates some specific configs. |
|
384 |
+// ValidateConfiguration validates some specific configs. |
|
385 | 385 |
// such as config.DNS, config.Labels, config.DNSSearch, |
386 | 386 |
// as well as config.MaxConcurrentDownloads, config.MaxConcurrentUploads. |
387 |
-func validateConfiguration(config *Config) error { |
|
387 |
+func ValidateConfiguration(config *Config) error { |
|
388 | 388 |
// validate DNS |
389 | 389 |
for _, dns := range config.DNS { |
390 | 390 |
if _, err := opts.ValidateIPAddress(dns); err != nil { |
... | ... |
@@ -415,5 +423,20 @@ func validateConfiguration(config *Config) error { |
415 | 415 |
if config.IsValueSet("max-concurrent-uploads") && config.MaxConcurrentUploads != nil && *config.MaxConcurrentUploads < 0 { |
416 | 416 |
return fmt.Errorf("invalid max concurrent uploads: %d", *config.MaxConcurrentUploads) |
417 | 417 |
} |
418 |
+ |
|
419 |
+ // validate that "default" runtime is not reset |
|
420 |
+ if runtimes := config.GetAllRuntimes(); len(runtimes) > 0 { |
|
421 |
+ if _, ok := runtimes[types.DefaultRuntimeName]; ok { |
|
422 |
+ return fmt.Errorf("runtime name '%s' is reserved", types.DefaultRuntimeName) |
|
423 |
+ } |
|
424 |
+ } |
|
425 |
+ |
|
426 |
+ if defaultRuntime := config.GetDefaultRuntimeName(); defaultRuntime != "" && defaultRuntime != types.DefaultRuntimeName { |
|
427 |
+ runtimes := config.GetAllRuntimes() |
|
428 |
+ if _, ok := runtimes[defaultRuntime]; !ok { |
|
429 |
+ return fmt.Errorf("specified default runtime '%s' does not exist", defaultRuntime) |
|
430 |
+ } |
|
431 |
+ } |
|
432 |
+ |
|
418 | 433 |
return nil |
419 | 434 |
} |
... | ... |
@@ -216,7 +216,7 @@ func TestValidateConfiguration(t *testing.T) { |
216 | 216 |
}, |
217 | 217 |
} |
218 | 218 |
|
219 |
- err := validateConfiguration(c1) |
|
219 |
+ err := ValidateConfiguration(c1) |
|
220 | 220 |
if err == nil { |
221 | 221 |
t.Fatal("expected error, got nil") |
222 | 222 |
} |
... | ... |
@@ -227,7 +227,7 @@ func TestValidateConfiguration(t *testing.T) { |
227 | 227 |
}, |
228 | 228 |
} |
229 | 229 |
|
230 |
- err = validateConfiguration(c2) |
|
230 |
+ err = ValidateConfiguration(c2) |
|
231 | 231 |
if err != nil { |
232 | 232 |
t.Fatalf("expected no error, got error %v", err) |
233 | 233 |
} |
... | ... |
@@ -238,7 +238,7 @@ func TestValidateConfiguration(t *testing.T) { |
238 | 238 |
}, |
239 | 239 |
} |
240 | 240 |
|
241 |
- err = validateConfiguration(c3) |
|
241 |
+ err = ValidateConfiguration(c3) |
|
242 | 242 |
if err != nil { |
243 | 243 |
t.Fatalf("expected no error, got error %v", err) |
244 | 244 |
} |
... | ... |
@@ -249,7 +249,7 @@ func TestValidateConfiguration(t *testing.T) { |
249 | 249 |
}, |
250 | 250 |
} |
251 | 251 |
|
252 |
- err = validateConfiguration(c4) |
|
252 |
+ err = ValidateConfiguration(c4) |
|
253 | 253 |
if err == nil { |
254 | 254 |
t.Fatal("expected error, got nil") |
255 | 255 |
} |
... | ... |
@@ -260,7 +260,7 @@ func TestValidateConfiguration(t *testing.T) { |
260 | 260 |
}, |
261 | 261 |
} |
262 | 262 |
|
263 |
- err = validateConfiguration(c5) |
|
263 |
+ err = ValidateConfiguration(c5) |
|
264 | 264 |
if err != nil { |
265 | 265 |
t.Fatalf("expected no error, got error %v", err) |
266 | 266 |
} |
... | ... |
@@ -271,7 +271,7 @@ func TestValidateConfiguration(t *testing.T) { |
271 | 271 |
}, |
272 | 272 |
} |
273 | 273 |
|
274 |
- err = validateConfiguration(c6) |
|
274 |
+ err = ValidateConfiguration(c6) |
|
275 | 275 |
if err == nil { |
276 | 276 |
t.Fatal("expected error, got nil") |
277 | 277 |
} |
... | ... |
@@ -8,6 +8,7 @@ import ( |
8 | 8 |
"github.com/docker/docker/opts" |
9 | 9 |
flag "github.com/docker/docker/pkg/mflag" |
10 | 10 |
runconfigopts "github.com/docker/docker/runconfig/opts" |
11 |
+ "github.com/docker/engine-api/types" |
|
11 | 12 |
"github.com/docker/go-units" |
12 | 13 |
) |
13 | 14 |
|
... | ... |
@@ -30,6 +31,8 @@ type Config struct { |
30 | 30 |
ExecRoot string `json:"exec-root,omitempty"` |
31 | 31 |
RemappedRoot string `json:"userns-remap,omitempty"` |
32 | 32 |
Ulimits map[string]*units.Ulimit `json:"default-ulimits,omitempty"` |
33 |
+ Runtimes map[string]types.Runtime `json:"runtimes,omitempty"` |
|
34 |
+ DefaultRuntime string `json:"default-runtime,omitempty"` |
|
33 | 35 |
} |
34 | 36 |
|
35 | 37 |
// bridgeConfig stores all the bridge driver specific |
... | ... |
@@ -83,6 +86,37 @@ func (config *Config) InstallFlags(cmd *flag.FlagSet, usageFn func(string) strin |
83 | 83 |
cmd.StringVar(&config.RemappedRoot, []string{"-userns-remap"}, "", usageFn("User/Group setting for user namespaces")) |
84 | 84 |
cmd.StringVar(&config.ContainerdAddr, []string{"-containerd"}, "", usageFn("Path to containerd socket")) |
85 | 85 |
cmd.BoolVar(&config.LiveRestore, []string{"-live-restore"}, false, usageFn("Enable live restore of docker when containers are still running")) |
86 |
+ config.Runtimes = make(map[string]types.Runtime) |
|
87 |
+ cmd.Var(runconfigopts.NewNamedRuntimeOpt("runtimes", &config.Runtimes), []string{"-add-runtime"}, usageFn("Register an additional OCI compatible runtime")) |
|
88 |
+ cmd.StringVar(&config.DefaultRuntime, []string{"-default-runtime"}, types.DefaultRuntimeName, usageFn("Default OCI runtime to be used")) |
|
86 | 89 |
|
87 | 90 |
config.attachExperimentalFlags(cmd, usageFn) |
88 | 91 |
} |
92 |
+ |
|
93 |
+// GetRuntime returns the runtime path and arguments for a given |
|
94 |
+// runtime name |
|
95 |
+func (config *Config) GetRuntime(name string) *types.Runtime { |
|
96 |
+ config.reloadLock.Lock() |
|
97 |
+ defer config.reloadLock.Unlock() |
|
98 |
+ if rt, ok := config.Runtimes[name]; ok { |
|
99 |
+ return &rt |
|
100 |
+ } |
|
101 |
+ return nil |
|
102 |
+} |
|
103 |
+ |
|
104 |
+// GetDefaultRuntimeName returns the current default runtime |
|
105 |
+func (config *Config) GetDefaultRuntimeName() string { |
|
106 |
+ config.reloadLock.Lock() |
|
107 |
+ rt := config.DefaultRuntime |
|
108 |
+ config.reloadLock.Unlock() |
|
109 |
+ |
|
110 |
+ return rt |
|
111 |
+} |
|
112 |
+ |
|
113 |
+// GetAllRuntimes returns a copy of the runtimes map |
|
114 |
+func (config *Config) GetAllRuntimes() map[string]types.Runtime { |
|
115 |
+ config.reloadLock.Lock() |
|
116 |
+ rts := config.Runtimes |
|
117 |
+ config.reloadLock.Unlock() |
|
118 |
+ return rts |
|
119 |
+} |
... | ... |
@@ -4,6 +4,7 @@ import ( |
4 | 4 |
"os" |
5 | 5 |
|
6 | 6 |
flag "github.com/docker/docker/pkg/mflag" |
7 |
+ "github.com/docker/engine-api/types" |
|
7 | 8 |
) |
8 | 9 |
|
9 | 10 |
var ( |
... | ... |
@@ -40,3 +41,19 @@ func (config *Config) InstallFlags(cmd *flag.FlagSet, usageFn func(string) strin |
40 | 40 |
cmd.StringVar(&config.bridgeConfig.Iface, []string{"b", "-bridge"}, "", "Attach containers to a virtual switch") |
41 | 41 |
cmd.StringVar(&config.SocketGroup, []string{"G", "-group"}, "", usageFn("Users or groups that can access the named pipe")) |
42 | 42 |
} |
43 |
+ |
|
44 |
+// GetRuntime returns the runtime path and arguments for a given |
|
45 |
+// runtime name |
|
46 |
+func (config *Config) GetRuntime(name string) *types.Runtime { |
|
47 |
+ return nil |
|
48 |
+} |
|
49 |
+ |
|
50 |
+// GetDefaultRuntimeName returns the current default runtime |
|
51 |
+func (config *Config) GetDefaultRuntimeName() string { |
|
52 |
+ return types.DefaultRuntimeName |
|
53 |
+} |
|
54 |
+ |
|
55 |
+// GetAllRuntimes returns a copy of the runtimes map |
|
56 |
+func (config *Config) GetAllRuntimes() map[string]types.Runtime { |
|
57 |
+ return map[string]types.Runtime{} |
|
58 |
+} |
... | ... |
@@ -60,6 +60,10 @@ import ( |
60 | 60 |
) |
61 | 61 |
|
62 | 62 |
var ( |
63 |
+ // DefaultRuntimeBinary is the default runtime to be used by |
|
64 |
+ // containerd if none is specified |
|
65 |
+ DefaultRuntimeBinary = "docker-runc" |
|
66 |
+ |
|
63 | 67 |
errSystemNotSupported = fmt.Errorf("The Docker daemon is not supported on this platform.") |
64 | 68 |
) |
65 | 69 |
|
... | ... |
@@ -811,10 +815,24 @@ func (daemon *Daemon) initDiscovery(config *Config) error { |
811 | 811 |
// - Cluster discovery (reconfigure and restart). |
812 | 812 |
// - Daemon live restore |
813 | 813 |
func (daemon *Daemon) Reload(config *Config) error { |
814 |
+ var err error |
|
815 |
+ // used to hold reloaded changes |
|
816 |
+ attributes := map[string]string{} |
|
817 |
+ |
|
818 |
+ // We need defer here to ensure the lock is released as |
|
819 |
+ // daemon.SystemInfo() will try to get it too |
|
820 |
+ defer func() { |
|
821 |
+ if err == nil { |
|
822 |
+ daemon.LogDaemonEventWithAttributes("reload", attributes) |
|
823 |
+ } |
|
824 |
+ }() |
|
825 |
+ |
|
814 | 826 |
daemon.configStore.reloadLock.Lock() |
815 | 827 |
defer daemon.configStore.reloadLock.Unlock() |
816 | 828 |
|
817 |
- if err := daemon.reloadClusterDiscovery(config); err != nil { |
|
829 |
+ daemon.platformReload(config, &attributes) |
|
830 |
+ |
|
831 |
+ if err = daemon.reloadClusterDiscovery(config); err != nil { |
|
818 | 832 |
return err |
819 | 833 |
} |
820 | 834 |
|
... | ... |
@@ -859,7 +877,6 @@ func (daemon *Daemon) Reload(config *Config) error { |
859 | 859 |
} |
860 | 860 |
|
861 | 861 |
// We emit daemon reload event here with updatable configurations |
862 |
- attributes := map[string]string{} |
|
863 | 862 |
attributes["debug"] = fmt.Sprintf("%t", daemon.configStore.Debug) |
864 | 863 |
attributes["cluster-store"] = daemon.configStore.ClusterStore |
865 | 864 |
if daemon.configStore.ClusterOpts != nil { |
... | ... |
@@ -877,7 +894,6 @@ func (daemon *Daemon) Reload(config *Config) error { |
877 | 877 |
} |
878 | 878 |
attributes["max-concurrent-downloads"] = fmt.Sprintf("%d", *daemon.configStore.MaxConcurrentDownloads) |
879 | 879 |
attributes["max-concurrent-uploads"] = fmt.Sprintf("%d", *daemon.configStore.MaxConcurrentUploads) |
880 |
- daemon.LogDaemonEventWithAttributes("reload", attributes) |
|
881 | 880 |
|
882 | 881 |
return nil |
883 | 882 |
} |
... | ... |
@@ -73,6 +73,10 @@ func verifyPlatformContainerSettings(daemon *Daemon, hostConfig *containertypes. |
73 | 73 |
return warnings, nil |
74 | 74 |
} |
75 | 75 |
|
76 |
+// platformReload update configuration with platform specific options |
|
77 |
+func (daemon *Daemon) platformReload(config *Config, attributes *map[string]string) { |
|
78 |
+} |
|
79 |
+ |
|
76 | 80 |
// verifyDaemonSettings performs validation of daemon config struct |
77 | 81 |
func verifyDaemonSettings(config *Config) error { |
78 | 82 |
// checkSystem validates platform-specific requirements |
... | ... |
@@ -3,6 +3,7 @@ |
3 | 3 |
package daemon |
4 | 4 |
|
5 | 5 |
import ( |
6 |
+ "bytes" |
|
6 | 7 |
"fmt" |
7 | 8 |
"io/ioutil" |
8 | 9 |
"net" |
... | ... |
@@ -515,9 +516,42 @@ func verifyPlatformContainerSettings(daemon *Daemon, hostConfig *containertypes. |
515 | 515 |
return warnings, fmt.Errorf("cgroup-parent for systemd cgroup should be a valid slice named as \"xxx.slice\"") |
516 | 516 |
} |
517 | 517 |
} |
518 |
+ if hostConfig.Runtime == "" { |
|
519 |
+ hostConfig.Runtime = daemon.configStore.GetDefaultRuntimeName() |
|
520 |
+ } |
|
521 |
+ |
|
522 |
+ if rt := daemon.configStore.GetRuntime(hostConfig.Runtime); rt == nil { |
|
523 |
+ return warnings, fmt.Errorf("Unknown runtime specified %s", hostConfig.Runtime) |
|
524 |
+ } |
|
525 |
+ |
|
518 | 526 |
return warnings, nil |
519 | 527 |
} |
520 | 528 |
|
529 |
+// platformReload update configuration with platform specific options |
|
530 |
+func (daemon *Daemon) platformReload(config *Config, attributes *map[string]string) { |
|
531 |
+ if config.IsValueSet("runtimes") { |
|
532 |
+ daemon.configStore.Runtimes = config.Runtimes |
|
533 |
+ // Always set the default one |
|
534 |
+ daemon.configStore.Runtimes[types.DefaultRuntimeName] = types.Runtime{Path: DefaultRuntimeBinary} |
|
535 |
+ } |
|
536 |
+ |
|
537 |
+ if config.DefaultRuntime != "" { |
|
538 |
+ daemon.configStore.DefaultRuntime = config.DefaultRuntime |
|
539 |
+ } |
|
540 |
+ |
|
541 |
+ // Update attributes |
|
542 |
+ var runtimeList bytes.Buffer |
|
543 |
+ for name, rt := range daemon.configStore.Runtimes { |
|
544 |
+ if runtimeList.Len() > 0 { |
|
545 |
+ runtimeList.WriteRune(' ') |
|
546 |
+ } |
|
547 |
+ runtimeList.WriteString(fmt.Sprintf("%s:%s", name, rt)) |
|
548 |
+ } |
|
549 |
+ |
|
550 |
+ (*attributes)["runtimes"] = runtimeList.String() |
|
551 |
+ (*attributes)["default-runtime"] = daemon.configStore.DefaultRuntime |
|
552 |
+} |
|
553 |
+ |
|
521 | 554 |
// verifyDaemonSettings performs validation of daemon config struct |
522 | 555 |
func verifyDaemonSettings(config *Config) error { |
523 | 556 |
// Check for mutually incompatible config options |
... | ... |
@@ -538,6 +572,15 @@ func verifyDaemonSettings(config *Config) error { |
538 | 538 |
return fmt.Errorf("cgroup-parent for systemd cgroup should be a valid slice named as \"xxx.slice\"") |
539 | 539 |
} |
540 | 540 |
} |
541 |
+ |
|
542 |
+ if config.DefaultRuntime == "" { |
|
543 |
+ config.DefaultRuntime = types.DefaultRuntimeName |
|
544 |
+ } |
|
545 |
+ if config.Runtimes == nil { |
|
546 |
+ config.Runtimes = make(map[string]types.Runtime) |
|
547 |
+ } |
|
548 |
+ config.Runtimes[types.DefaultRuntimeName] = types.Runtime{Path: DefaultRuntimeBinary} |
|
549 |
+ |
|
541 | 550 |
return nil |
542 | 551 |
} |
543 | 552 |
|
... | ... |
@@ -156,6 +156,10 @@ func verifyPlatformContainerSettings(daemon *Daemon, hostConfig *containertypes. |
156 | 156 |
return warnings, nil |
157 | 157 |
} |
158 | 158 |
|
159 |
+// platformReload update configuration with platform specific options |
|
160 |
+func (daemon *Daemon) platformReload(config *Config, attributes *map[string]string) { |
|
161 |
+} |
|
162 |
+ |
|
159 | 163 |
// verifyDaemonSettings performs validation of daemon config struct |
160 | 164 |
func verifyDaemonSettings(config *Config) error { |
161 | 165 |
return nil |
... | ... |
@@ -131,6 +131,8 @@ func (daemon *Daemon) SystemInfo() (*types.Info, error) { |
131 | 131 |
v.CPUCfsQuota = sysInfo.CPUCfsQuota |
132 | 132 |
v.CPUShares = sysInfo.CPUShares |
133 | 133 |
v.CPUSet = sysInfo.Cpuset |
134 |
+ v.Runtimes = daemon.configStore.GetAllRuntimes() |
|
135 |
+ v.DefaultRuntime = daemon.configStore.GetDefaultRuntimeName() |
|
134 | 136 |
} |
135 | 137 |
|
136 | 138 |
hostname := "" |
... | ... |
@@ -132,15 +132,25 @@ func (daemon *Daemon) containerStart(container *container.Container) (err error) |
132 | 132 |
return err |
133 | 133 |
} |
134 | 134 |
|
135 |
- if err := daemon.containerd.Create(container.ID, *spec, libcontainerd.WithRestartManager(container.RestartManager(true))); err != nil { |
|
135 |
+ createOptions := []libcontainerd.CreateOption{libcontainerd.WithRestartManager(container.RestartManager(true))} |
|
136 |
+ copts, err := daemon.getLibcontainerdCreateOptions(container) |
|
137 |
+ if err != nil { |
|
138 |
+ return err |
|
139 |
+ } |
|
140 |
+ if copts != nil { |
|
141 |
+ createOptions = append(createOptions, *copts...) |
|
142 |
+ } |
|
143 |
+ |
|
144 |
+ if err := daemon.containerd.Create(container.ID, *spec, createOptions...); err != nil { |
|
136 | 145 |
errDesc := grpc.ErrorDesc(err) |
137 | 146 |
logrus.Errorf("Create container failed with error: %s", errDesc) |
138 | 147 |
// if we receive an internal error from the initial start of a container then lets |
139 | 148 |
// return it instead of entering the restart loop |
140 | 149 |
// set to 127 for container cmd not found/does not exist) |
141 |
- if strings.Contains(errDesc, "executable file not found") || |
|
142 |
- strings.Contains(errDesc, "no such file or directory") || |
|
143 |
- strings.Contains(errDesc, "system cannot find the file specified") { |
|
150 |
+ if strings.Contains(errDesc, container.Path) && |
|
151 |
+ (strings.Contains(errDesc, "executable file not found") || |
|
152 |
+ strings.Contains(errDesc, "no such file or directory") || |
|
153 |
+ strings.Contains(errDesc, "system cannot find the file specified")) { |
|
144 | 154 |
container.ExitCode = 127 |
145 | 155 |
} |
146 | 156 |
// set to 126 for container cmd can't be invoked errors |
147 | 157 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,20 @@ |
0 |
+package daemon |
|
1 |
+ |
|
2 |
+import ( |
|
3 |
+ "fmt" |
|
4 |
+ |
|
5 |
+ "github.com/docker/docker/container" |
|
6 |
+ "github.com/docker/docker/libcontainerd" |
|
7 |
+) |
|
8 |
+ |
|
9 |
+func (daemon *Daemon) getLibcontainerdCreateOptions(container *container.Container) (*[]libcontainerd.CreateOption, error) { |
|
10 |
+ createOptions := []libcontainerd.CreateOption{} |
|
11 |
+ |
|
12 |
+ rt := daemon.configStore.GetRuntime(container.HostConfig.Runtime) |
|
13 |
+ if rt == nil { |
|
14 |
+ return nil, fmt.Errorf("No such runtime '%s'", container.HostConfig.Runtime) |
|
15 |
+ } |
|
16 |
+ createOptions = append(createOptions, libcontainerd.WithRuntime(rt.Path, rt.Args)) |
|
17 |
+ |
|
18 |
+ return &createOptions, nil |
|
19 |
+} |
0 | 20 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,10 @@ |
0 |
+package daemon |
|
1 |
+ |
|
2 |
+import ( |
|
3 |
+ "github.com/docker/docker/container" |
|
4 |
+ "github.com/docker/docker/libcontainerd" |
|
5 |
+) |
|
6 |
+ |
|
7 |
+func (daemon *Daemon) getLibcontainerdCreateOptions(container *container.Container) (*[]libcontainerd.CreateOption, error) { |
|
8 |
+ return &[]libcontainerd.CreateOption{}, nil |
|
9 |
+} |
... | ... |
@@ -78,6 +78,7 @@ Creates a new container. |
78 | 78 |
--privileged Give extended privileges to this container |
79 | 79 |
--read-only Mount the container's root filesystem as read only |
80 | 80 |
--restart="no" Restart policy (no, on-failure[:max-retry], always, unless-stopped) |
81 |
+ --runtime="" Name of the runtime to be used for that container |
|
81 | 82 |
--security-opt=[] Security options |
82 | 83 |
--stop-signal="SIGTERM" Signal to stop a container |
83 | 84 |
--shm-size=[] Size of `/dev/shm`. The format is `<number><unit>`. `number` must be greater than `0`. Unit is optional and can be `b` (bytes), `k` (kilobytes), `m` (megabytes), or `g` (gigabytes). If you omit the unit, the system uses bytes. If you omit the size entirely, the system uses `64m`. |
... | ... |
@@ -60,6 +60,7 @@ weight = -1 |
60 | 60 |
-p, --pidfile="/var/run/docker.pid" Path to use for daemon PID file |
61 | 61 |
--raw-logs Full timestamps without ANSI coloring |
62 | 62 |
--registry-mirror=[] Preferred Docker registry mirror |
63 |
+ --add-runtime=[] Register an additional OCI compatible runtime |
|
63 | 64 |
-s, --storage-driver="" Storage driver to use |
64 | 65 |
--selinux-enabled Enable selinux support |
65 | 66 |
--storage-opt=[] Set storage driver options |
... | ... |
@@ -572,6 +573,31 @@ The Docker daemon relies on a |
572 | 572 |
(invoked via the `containerd` daemon) as its interface to the Linux |
573 | 573 |
kernel `namespaces`, `cgroups`, and `SELinux`. |
574 | 574 |
|
575 |
+Runtimes can be registered with the daemon either via the |
|
576 |
+configuration file or using the `--add-runtime` command line argument. |
|
577 |
+ |
|
578 |
+The following is an example adding 2 runtimes via the configuration: |
|
579 |
+```json |
|
580 |
+ "default-runtime": "runc", |
|
581 |
+ "runtimes": { |
|
582 |
+ "runc": { |
|
583 |
+ "path": "runc" |
|
584 |
+ }, |
|
585 |
+ "custom": { |
|
586 |
+ "path": "/usr/local/bin/my-runc-replacement", |
|
587 |
+ "runtimeArgs": [ |
|
588 |
+ "--debug" |
|
589 |
+ ] |
|
590 |
+ } |
|
591 |
+ } |
|
592 |
+``` |
|
593 |
+ |
|
594 |
+This is the same example via the command line: |
|
595 |
+ |
|
596 |
+ $ sudo dockerd --add-runtime runc=runc --add-runtime custom=/usr/local/bin/my-runc-replacement |
|
597 |
+ |
|
598 |
+**Note**: defining runtime arguments via the command line is not supported. |
|
599 |
+ |
|
575 | 600 |
## Options for the runtime |
576 | 601 |
|
577 | 602 |
You can configure the runtime using options specified |
... | ... |
@@ -1014,7 +1040,19 @@ This is a full example of the allowed configuration options in the file: |
1014 | 1014 |
"raw-logs": false, |
1015 | 1015 |
"registry-mirrors": [], |
1016 | 1016 |
"insecure-registries": [], |
1017 |
- "disable-legacy-registry": false |
|
1017 |
+ "disable-legacy-registry": false, |
|
1018 |
+ "default-runtime": "runc", |
|
1019 |
+ "runtimes": { |
|
1020 |
+ "runc": { |
|
1021 |
+ "path": "runc" |
|
1022 |
+ }, |
|
1023 |
+ "custom": { |
|
1024 |
+ "path": "/usr/local/bin/my-runc-replacement", |
|
1025 |
+ "runtimeArgs": [ |
|
1026 |
+ "--debug" |
|
1027 |
+ ] |
|
1028 |
+ } |
|
1029 |
+ } |
|
1018 | 1030 |
} |
1019 | 1031 |
``` |
1020 | 1032 |
|
... | ... |
@@ -1036,6 +1074,11 @@ The list of currently supported options that can be reconfigured is this: |
1036 | 1036 |
- `labels`: it replaces the daemon labels with a new set of labels. |
1037 | 1037 |
- `max-concurrent-downloads`: it updates the max concurrent downloads for each pull. |
1038 | 1038 |
- `max-concurrent-uploads`: it updates the max concurrent uploads for each push. |
1039 |
+- `default-runtime`: it updates the runtime to be used if not is |
|
1040 |
+ specified at container creation. It defaults to "default" which is |
|
1041 |
+ the runtime shipped with the official docker packages. |
|
1042 |
+- `runtimes`: it updates the list of available OCI runtimes that can |
|
1043 |
+ be used to run containers |
|
1039 | 1044 |
|
1040 | 1045 |
Updating and reloading the cluster configurations such as `--cluster-store`, |
1041 | 1046 |
`--cluster-advertise` and `--cluster-store-opts` will take effect only if |
... | ... |
@@ -89,6 +89,7 @@ parent = "smn_cli" |
89 | 89 |
--read-only Mount the container's root filesystem as read only |
90 | 90 |
--restart="no" Restart policy (no, on-failure[:max-retry], always, unless-stopped) |
91 | 91 |
--rm Automatically remove the container when it exits |
92 |
+ --runtime="" Name of the runtime to be used for that container |
|
92 | 93 |
--shm-size=[] Size of `/dev/shm`. The format is `<number><unit>`. `number` must be greater than `0`. Unit is optional and can be `b` (bytes), `k` (kilobytes), `m` (megabytes), or `g` (gigabytes). If you omit the unit, the system uses bytes. If you omit the size entirely, the system uses `64m`. |
93 | 94 |
--security-opt=[] Security Options |
94 | 95 |
--sig-proxy=true Proxy received signals to the process |
... | ... |
@@ -2378,3 +2378,183 @@ func (s *DockerDaemonSuite) TestDaemonDnsOptionsInHostMode(c *check.C) { |
2378 | 2378 |
out, _ := s.d.Cmd("run", "--net=host", "busybox", "cat", "/etc/resolv.conf") |
2379 | 2379 |
c.Assert(out, checker.Contains, expectedOutput, check.Commentf("Expected '%s', but got %q", expectedOutput, out)) |
2380 | 2380 |
} |
2381 |
+ |
|
2382 |
+func (s *DockerDaemonSuite) TestRunWithRuntimeFromConfigFile(c *check.C) { |
|
2383 |
+ conf, err := ioutil.TempFile("", "config-file-") |
|
2384 |
+ c.Assert(err, check.IsNil) |
|
2385 |
+ configName := conf.Name() |
|
2386 |
+ conf.Close() |
|
2387 |
+ defer os.Remove(configName) |
|
2388 |
+ |
|
2389 |
+ config := ` |
|
2390 |
+{ |
|
2391 |
+ "runtimes": { |
|
2392 |
+ "oci": { |
|
2393 |
+ "path": "docker-runc" |
|
2394 |
+ }, |
|
2395 |
+ "vm": { |
|
2396 |
+ "path": "/usr/local/bin/vm-manager", |
|
2397 |
+ "runtimeArgs": [ |
|
2398 |
+ "--debug" |
|
2399 |
+ ] |
|
2400 |
+ } |
|
2401 |
+ } |
|
2402 |
+} |
|
2403 |
+` |
|
2404 |
+ ioutil.WriteFile(configName, []byte(config), 0644) |
|
2405 |
+ err = s.d.Start("--config-file", configName) |
|
2406 |
+ c.Assert(err, check.IsNil) |
|
2407 |
+ |
|
2408 |
+ // Run with default runtime |
|
2409 |
+ out, err := s.d.Cmd("run", "--rm", "busybox", "ls") |
|
2410 |
+ c.Assert(err, check.IsNil, check.Commentf(out)) |
|
2411 |
+ |
|
2412 |
+ // Run with default runtime explicitely |
|
2413 |
+ out, err = s.d.Cmd("run", "--rm", "--runtime=default", "busybox", "ls") |
|
2414 |
+ c.Assert(err, check.IsNil, check.Commentf(out)) |
|
2415 |
+ |
|
2416 |
+ // Run with oci (same path as default) but keep it around |
|
2417 |
+ out, err = s.d.Cmd("run", "--name", "oci-runtime-ls", "--runtime=oci", "busybox", "ls") |
|
2418 |
+ c.Assert(err, check.IsNil, check.Commentf(out)) |
|
2419 |
+ |
|
2420 |
+ // Run with "vm" |
|
2421 |
+ out, err = s.d.Cmd("run", "--rm", "--runtime=vm", "busybox", "ls") |
|
2422 |
+ c.Assert(err, check.NotNil, check.Commentf(out)) |
|
2423 |
+ c.Assert(out, checker.Contains, "/usr/local/bin/vm-manager: no such file or directory") |
|
2424 |
+ |
|
2425 |
+ // Reset config to only have the default |
|
2426 |
+ config = ` |
|
2427 |
+{ |
|
2428 |
+ "runtimes": { |
|
2429 |
+ } |
|
2430 |
+} |
|
2431 |
+` |
|
2432 |
+ ioutil.WriteFile(configName, []byte(config), 0644) |
|
2433 |
+ syscall.Kill(s.d.cmd.Process.Pid, syscall.SIGHUP) |
|
2434 |
+ // Give daemon time to reload config |
|
2435 |
+ <-time.After(1 * time.Second) |
|
2436 |
+ |
|
2437 |
+ // Run with default runtime |
|
2438 |
+ out, err = s.d.Cmd("run", "--rm", "--runtime=default", "busybox", "ls") |
|
2439 |
+ c.Assert(err, check.IsNil, check.Commentf(out)) |
|
2440 |
+ |
|
2441 |
+ // Run with "oci" |
|
2442 |
+ out, err = s.d.Cmd("run", "--rm", "--runtime=oci", "busybox", "ls") |
|
2443 |
+ c.Assert(err, check.NotNil, check.Commentf(out)) |
|
2444 |
+ c.Assert(out, checker.Contains, "Unknown runtime specified oci") |
|
2445 |
+ |
|
2446 |
+ // Start previously created container with oci |
|
2447 |
+ out, err = s.d.Cmd("start", "oci-runtime-ls") |
|
2448 |
+ c.Assert(err, check.NotNil, check.Commentf(out)) |
|
2449 |
+ c.Assert(out, checker.Contains, "Unknown runtime specified oci") |
|
2450 |
+ |
|
2451 |
+ // Check that we can't override the default runtime |
|
2452 |
+ config = ` |
|
2453 |
+{ |
|
2454 |
+ "runtimes": { |
|
2455 |
+ "default": { |
|
2456 |
+ "path": "docker-runc" |
|
2457 |
+ } |
|
2458 |
+ } |
|
2459 |
+} |
|
2460 |
+` |
|
2461 |
+ ioutil.WriteFile(configName, []byte(config), 0644) |
|
2462 |
+ syscall.Kill(s.d.cmd.Process.Pid, syscall.SIGHUP) |
|
2463 |
+ // Give daemon time to reload config |
|
2464 |
+ <-time.After(1 * time.Second) |
|
2465 |
+ |
|
2466 |
+ content, _ := ioutil.ReadFile(s.d.logFile.Name()) |
|
2467 |
+ c.Assert(string(content), checker.Contains, `file configuration validation failed (runtime name 'default' is reserved)`) |
|
2468 |
+ |
|
2469 |
+ // Check that we can select a default runtime |
|
2470 |
+ config = ` |
|
2471 |
+{ |
|
2472 |
+ "default-runtime": "vm", |
|
2473 |
+ "runtimes": { |
|
2474 |
+ "oci": { |
|
2475 |
+ "path": "docker-runc" |
|
2476 |
+ }, |
|
2477 |
+ "vm": { |
|
2478 |
+ "path": "/usr/local/bin/vm-manager", |
|
2479 |
+ "runtimeArgs": [ |
|
2480 |
+ "--debug" |
|
2481 |
+ ] |
|
2482 |
+ } |
|
2483 |
+ } |
|
2484 |
+} |
|
2485 |
+` |
|
2486 |
+ ioutil.WriteFile(configName, []byte(config), 0644) |
|
2487 |
+ syscall.Kill(s.d.cmd.Process.Pid, syscall.SIGHUP) |
|
2488 |
+ // Give daemon time to reload config |
|
2489 |
+ <-time.After(1 * time.Second) |
|
2490 |
+ |
|
2491 |
+ out, err = s.d.Cmd("run", "--rm", "busybox", "ls") |
|
2492 |
+ c.Assert(err, check.NotNil, check.Commentf(out)) |
|
2493 |
+ c.Assert(out, checker.Contains, "/usr/local/bin/vm-manager: no such file or directory") |
|
2494 |
+ |
|
2495 |
+ // Run with default runtime explicitely |
|
2496 |
+ out, err = s.d.Cmd("run", "--rm", "--runtime=default", "busybox", "ls") |
|
2497 |
+ c.Assert(err, check.IsNil, check.Commentf(out)) |
|
2498 |
+} |
|
2499 |
+ |
|
2500 |
+func (s *DockerDaemonSuite) TestRunWithRuntimeFromCommandLine(c *check.C) { |
|
2501 |
+ err := s.d.Start("--add-runtime", "oci=docker-runc", "--add-runtime", "vm=/usr/local/bin/vm-manager") |
|
2502 |
+ c.Assert(err, check.IsNil) |
|
2503 |
+ |
|
2504 |
+ // Run with default runtime |
|
2505 |
+ out, err := s.d.Cmd("run", "--rm", "busybox", "ls") |
|
2506 |
+ c.Assert(err, check.IsNil, check.Commentf(out)) |
|
2507 |
+ |
|
2508 |
+ // Run with default runtime explicitely |
|
2509 |
+ out, err = s.d.Cmd("run", "--rm", "--runtime=default", "busybox", "ls") |
|
2510 |
+ c.Assert(err, check.IsNil, check.Commentf(out)) |
|
2511 |
+ |
|
2512 |
+ // Run with oci (same path as default) but keep it around |
|
2513 |
+ out, err = s.d.Cmd("run", "--name", "oci-runtime-ls", "--runtime=oci", "busybox", "ls") |
|
2514 |
+ c.Assert(err, check.IsNil, check.Commentf(out)) |
|
2515 |
+ |
|
2516 |
+ // Run with "vm" |
|
2517 |
+ out, err = s.d.Cmd("run", "--rm", "--runtime=vm", "busybox", "ls") |
|
2518 |
+ c.Assert(err, check.NotNil, check.Commentf(out)) |
|
2519 |
+ c.Assert(out, checker.Contains, "/usr/local/bin/vm-manager: no such file or directory") |
|
2520 |
+ |
|
2521 |
+ // Start a daemon without any extra runtimes |
|
2522 |
+ s.d.Stop() |
|
2523 |
+ err = s.d.Start() |
|
2524 |
+ c.Assert(err, check.IsNil) |
|
2525 |
+ |
|
2526 |
+ // Run with default runtime |
|
2527 |
+ out, err = s.d.Cmd("run", "--rm", "--runtime=default", "busybox", "ls") |
|
2528 |
+ c.Assert(err, check.IsNil, check.Commentf(out)) |
|
2529 |
+ |
|
2530 |
+ // Run with "oci" |
|
2531 |
+ out, err = s.d.Cmd("run", "--rm", "--runtime=oci", "busybox", "ls") |
|
2532 |
+ c.Assert(err, check.NotNil, check.Commentf(out)) |
|
2533 |
+ c.Assert(out, checker.Contains, "Unknown runtime specified oci") |
|
2534 |
+ |
|
2535 |
+ // Start previously created container with oci |
|
2536 |
+ out, err = s.d.Cmd("start", "oci-runtime-ls") |
|
2537 |
+ c.Assert(err, check.NotNil, check.Commentf(out)) |
|
2538 |
+ c.Assert(out, checker.Contains, "Unknown runtime specified oci") |
|
2539 |
+ |
|
2540 |
+ // Check that we can't override the default runtime |
|
2541 |
+ s.d.Stop() |
|
2542 |
+ err = s.d.Start("--add-runtime", "default=docker-runc") |
|
2543 |
+ c.Assert(err, check.NotNil) |
|
2544 |
+ |
|
2545 |
+ content, _ := ioutil.ReadFile(s.d.logFile.Name()) |
|
2546 |
+ c.Assert(string(content), checker.Contains, `runtime name 'default' is reserved`) |
|
2547 |
+ |
|
2548 |
+ // Check that we can select a default runtime |
|
2549 |
+ s.d.Stop() |
|
2550 |
+ err = s.d.Start("--default-runtime=vm", "--add-runtime", "oci=docker-runc", "--add-runtime", "vm=/usr/local/bin/vm-manager") |
|
2551 |
+ c.Assert(err, check.IsNil) |
|
2552 |
+ |
|
2553 |
+ out, err = s.d.Cmd("run", "--rm", "busybox", "ls") |
|
2554 |
+ c.Assert(err, check.NotNil, check.Commentf(out)) |
|
2555 |
+ c.Assert(out, checker.Contains, "/usr/local/bin/vm-manager: no such file or directory") |
|
2556 |
+ |
|
2557 |
+ // Run with default runtime explicitely |
|
2558 |
+ out, err = s.d.Cmd("run", "--rm", "--runtime=default", "busybox", "ls") |
|
2559 |
+ c.Assert(err, check.IsNil, check.Commentf(out)) |
|
2560 |
+} |
... | ... |
@@ -436,7 +436,8 @@ func (s *DockerDaemonSuite) TestDaemonEvents(c *check.C) { |
436 | 436 |
|
437 | 437 |
out, err = s.d.Cmd("events", "--since=0", "--until", daemonUnixTime(c)) |
438 | 438 |
c.Assert(err, checker.IsNil) |
439 |
- c.Assert(out, checker.Contains, fmt.Sprintf("daemon reload %s (cluster-advertise=, cluster-store=, cluster-store-opts={}, debug=true, labels=[\"bar=foo\"], max-concurrent-downloads=1, max-concurrent-uploads=5, name=%s)", daemonID, daemonName)) |
|
439 |
+ |
|
440 |
+ c.Assert(out, checker.Contains, fmt.Sprintf("daemon reload %s (cluster-advertise=, cluster-store=, cluster-store-opts={}, debug=true, default-runtime=default, labels=[\"bar=foo\"], max-concurrent-downloads=1, max-concurrent-uploads=5, name=%s, runtimes=default:{docker-runc []})", daemonID, daemonName)) |
|
440 | 441 |
} |
441 | 442 |
|
442 | 443 |
func (s *DockerDaemonSuite) TestDaemonEventsWithFilters(c *check.C) { |
... | ... |
@@ -34,6 +34,10 @@ func (s *DockerSuite) TestInfoEnsureSucceeds(c *check.C) { |
34 | 34 |
"Network:", |
35 | 35 |
} |
36 | 36 |
|
37 |
+ if DaemonIsLinux.Condition() { |
|
38 |
+ stringsToCheck = append(stringsToCheck, "Runtimes:", "Default Runtime: default") |
|
39 |
+ } |
|
40 |
+ |
|
37 | 41 |
if utils.ExperimentalBuild() { |
38 | 42 |
stringsToCheck = append(stringsToCheck, "Experimental: true") |
39 | 43 |
} |
... | ... |
@@ -21,7 +21,27 @@ type container struct { |
21 | 21 |
|
22 | 22 |
// Platform specific fields are below here. |
23 | 23 |
pauseMonitor |
24 |
- oom bool |
|
24 |
+ oom bool |
|
25 |
+ runtime string |
|
26 |
+ runtimeArgs []string |
|
27 |
+} |
|
28 |
+ |
|
29 |
+type runtime struct { |
|
30 |
+ path string |
|
31 |
+ args []string |
|
32 |
+} |
|
33 |
+ |
|
34 |
+// WithRuntime sets the runtime to be used for the created container |
|
35 |
+func WithRuntime(path string, args []string) CreateOption { |
|
36 |
+ return runtime{path, args} |
|
37 |
+} |
|
38 |
+ |
|
39 |
+func (rt runtime) Apply(p interface{}) error { |
|
40 |
+ if pr, ok := p.(*container); ok { |
|
41 |
+ pr.runtime = rt.path |
|
42 |
+ pr.runtimeArgs = rt.args |
|
43 |
+ } |
|
44 |
+ return nil |
|
25 | 45 |
} |
26 | 46 |
|
27 | 47 |
func (ctr *container) clean() error { |
... | ... |
@@ -84,6 +104,8 @@ func (ctr *container) start() error { |
84 | 84 |
Stderr: ctr.fifo(syscall.Stderr), |
85 | 85 |
// check to see if we are running in ramdisk to disable pivot root |
86 | 86 |
NoPivotRoot: os.Getenv("DOCKER_RAMDISK") != "", |
87 |
+ Runtime: ctr.runtime, |
|
88 |
+ RuntimeArgs: ctr.runtimeArgs, |
|
87 | 89 |
} |
88 | 90 |
ctr.client.appendContainer(ctr) |
89 | 91 |
|
... | ... |
@@ -50,6 +50,7 @@ type remote struct { |
50 | 50 |
clients []*client |
51 | 51 |
eventTsPath string |
52 | 52 |
pastEvents map[string]*containerd.Event |
53 |
+ runtime string |
|
53 | 54 |
runtimeArgs []string |
54 | 55 |
daemonWaitCh chan struct{} |
55 | 56 |
liveRestore bool |
... | ... |
@@ -366,11 +367,14 @@ func (r *remote) runContainerdDaemon() error { |
366 | 366 |
args := []string{ |
367 | 367 |
"-l", fmt.Sprintf("unix://%s", r.rpcAddr), |
368 | 368 |
"--shim", "docker-containerd-shim", |
369 |
- "--runtime", "docker-runc", |
|
370 | 369 |
"--metrics-interval=0", |
371 | 370 |
"--start-timeout", "2m", |
372 | 371 |
"--state-dir", filepath.Join(r.stateDir, containerdStateDir), |
373 | 372 |
} |
373 |
+ if r.runtime != "" { |
|
374 |
+ args = append(args, "--runtime") |
|
375 |
+ args = append(args, r.runtime) |
|
376 |
+ } |
|
374 | 377 |
if r.debugLog { |
375 | 378 |
args = append(args, "--debug") |
376 | 379 |
} |
... | ... |
@@ -428,6 +432,22 @@ func (a rpcAddr) Apply(r Remote) error { |
428 | 428 |
return fmt.Errorf("WithRemoteAddr option not supported for this remote") |
429 | 429 |
} |
430 | 430 |
|
431 |
+// WithRuntimePath sets the path of the runtime to be used as the |
|
432 |
+// default by containerd |
|
433 |
+func WithRuntimePath(rt string) RemoteOption { |
|
434 |
+ return runtimePath(rt) |
|
435 |
+} |
|
436 |
+ |
|
437 |
+type runtimePath string |
|
438 |
+ |
|
439 |
+func (rt runtimePath) Apply(r Remote) error { |
|
440 |
+ if remote, ok := r.(*remote); ok { |
|
441 |
+ remote.runtime = string(rt) |
|
442 |
+ return nil |
|
443 |
+ } |
|
444 |
+ return fmt.Errorf("WithRuntime option not supported for this remote") |
|
445 |
+} |
|
446 |
+ |
|
431 | 447 |
// WithRuntimeArgs sets the list of runtime args passed to containerd |
432 | 448 |
func WithRuntimeArgs(args []string) RemoteOption { |
433 | 449 |
return runtimeArgs(args) |
... | ... |
@@ -101,6 +101,7 @@ type ContainerOptions struct { |
101 | 101 |
flHealthInterval *time.Duration |
102 | 102 |
flHealthTimeout *time.Duration |
103 | 103 |
flHealthRetries *int |
104 |
+ flRuntime *string |
|
104 | 105 |
|
105 | 106 |
Image string |
106 | 107 |
Args []string |
... | ... |
@@ -189,6 +190,7 @@ func AddFlags(flags *pflag.FlagSet) *ContainerOptions { |
189 | 189 |
flHealthInterval: flags.Duration("health-interval", 0, "Time between running the check"), |
190 | 190 |
flHealthTimeout: flags.Duration("health-timeout", 0, "Maximum time to allow one check to run"), |
191 | 191 |
flHealthRetries: flags.Int("health-retries", 0, "Consecutive failures needed to report unhealthy"), |
192 |
+ flRuntime: flags.String("runtime", "", "Runtime to use for this container"), |
|
192 | 193 |
} |
193 | 194 |
|
194 | 195 |
flags.VarP(&copts.flAttach, "attach", "a", "Attach to STDIN, STDOUT or STDERR") |
... | ... |
@@ -229,7 +231,6 @@ func AddFlags(flags *pflag.FlagSet) *ContainerOptions { |
229 | 229 |
// a HostConfig and returns them with the specified command. |
230 | 230 |
// If the specified args are not valid, it will return an error. |
231 | 231 |
func Parse(flags *pflag.FlagSet, copts *ContainerOptions) (*container.Config, *container.HostConfig, *networktypes.NetworkingConfig, error) { |
232 |
- |
|
233 | 232 |
var ( |
234 | 233 |
attachStdin = copts.flAttach.Get("stdin") |
235 | 234 |
attachStdout = copts.flAttach.Get("stdout") |
... | ... |
@@ -564,6 +565,7 @@ func Parse(flags *pflag.FlagSet, copts *ContainerOptions) (*container.Config, *c |
564 | 564 |
Resources: resources, |
565 | 565 |
Tmpfs: tmpfs, |
566 | 566 |
Sysctls: copts.flSysctls.GetAll(), |
567 |
+ Runtime: *copts.flRuntime, |
|
567 | 568 |
} |
568 | 569 |
|
569 | 570 |
// When allocating stdin in attached mode, close stdin at client disconnect |
570 | 571 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,73 @@ |
0 |
+package opts |
|
1 |
+ |
|
2 |
+import ( |
|
3 |
+ "fmt" |
|
4 |
+ "strings" |
|
5 |
+ |
|
6 |
+ "github.com/docker/engine-api/types" |
|
7 |
+) |
|
8 |
+ |
|
9 |
+// RuntimeOpt defines a map of Runtimes |
|
10 |
+type RuntimeOpt struct { |
|
11 |
+ name string |
|
12 |
+ values *map[string]types.Runtime |
|
13 |
+} |
|
14 |
+ |
|
15 |
+// NewNamedRuntimeOpt creates a new RuntimeOpt |
|
16 |
+func NewNamedRuntimeOpt(name string, ref *map[string]types.Runtime) *RuntimeOpt { |
|
17 |
+ if ref == nil { |
|
18 |
+ ref = &map[string]types.Runtime{} |
|
19 |
+ } |
|
20 |
+ return &RuntimeOpt{name: name, values: ref} |
|
21 |
+} |
|
22 |
+ |
|
23 |
+// Name returns the name of the NamedListOpts in the configuration. |
|
24 |
+func (o *RuntimeOpt) Name() string { |
|
25 |
+ return o.name |
|
26 |
+} |
|
27 |
+ |
|
28 |
+// Set validates and updates the list of Runtimes |
|
29 |
+func (o *RuntimeOpt) Set(val string) error { |
|
30 |
+ parts := strings.SplitN(val, "=", 2) |
|
31 |
+ if len(parts) != 2 { |
|
32 |
+ return fmt.Errorf("invalid runtime argument: %s", val) |
|
33 |
+ } |
|
34 |
+ |
|
35 |
+ parts[0] = strings.TrimSpace(parts[0]) |
|
36 |
+ parts[1] = strings.TrimSpace(parts[1]) |
|
37 |
+ if parts[0] == "" || parts[1] == "" { |
|
38 |
+ return fmt.Errorf("invalid runtime argument: %s", val) |
|
39 |
+ } |
|
40 |
+ |
|
41 |
+ parts[0] = strings.ToLower(parts[0]) |
|
42 |
+ if parts[0] == types.DefaultRuntimeName { |
|
43 |
+ return fmt.Errorf("runtime name 'default' is reserved") |
|
44 |
+ } |
|
45 |
+ |
|
46 |
+ if _, ok := (*o.values)[parts[0]]; ok { |
|
47 |
+ return fmt.Errorf("runtime '%s' was already defined", parts[0]) |
|
48 |
+ } |
|
49 |
+ |
|
50 |
+ (*o.values)[parts[0]] = types.Runtime{Path: parts[1]} |
|
51 |
+ |
|
52 |
+ return nil |
|
53 |
+} |
|
54 |
+ |
|
55 |
+// String returns Runtime values as a string. |
|
56 |
+func (o *RuntimeOpt) String() string { |
|
57 |
+ var out []string |
|
58 |
+ for k := range *o.values { |
|
59 |
+ out = append(out, k) |
|
60 |
+ } |
|
61 |
+ |
|
62 |
+ return fmt.Sprintf("%v", out) |
|
63 |
+} |
|
64 |
+ |
|
65 |
+// GetMap returns a map of Runtimes (name: path) |
|
66 |
+func (o *RuntimeOpt) GetMap() map[string]types.Runtime { |
|
67 |
+ if o.values != nil { |
|
68 |
+ return *o.values |
|
69 |
+ } |
|
70 |
+ |
|
71 |
+ return map[string]types.Runtime{} |
|
72 |
+} |