This also moves some cli specific in `cmd/dockerd` as it does not
really belong to the `daemon/config` package.
Signed-off-by: Vincent Demeester <vincent@sbr.pm>
1 | 1 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,52 @@ |
0 |
+package main |
|
1 |
+ |
|
2 |
+import ( |
|
3 |
+ "github.com/docker/docker/daemon/config" |
|
4 |
+ "github.com/docker/docker/opts" |
|
5 |
+ "github.com/spf13/pflag" |
|
6 |
+) |
|
7 |
+ |
|
8 |
+const ( |
|
9 |
+ // defaultShutdownTimeout is the default shutdown timeout for the daemon |
|
10 |
+ defaultShutdownTimeout = 15 |
|
11 |
+) |
|
12 |
+ |
|
13 |
+// installCommonConfigFlags adds flags to the pflag.FlagSet to configure the daemon |
|
14 |
+func installCommonConfigFlags(conf *config.Config, flags *pflag.FlagSet) { |
|
15 |
+ var maxConcurrentDownloads, maxConcurrentUploads int |
|
16 |
+ |
|
17 |
+ conf.ServiceOptions.InstallCliFlags(flags) |
|
18 |
+ |
|
19 |
+ flags.Var(opts.NewNamedListOptsRef("storage-opts", &conf.GraphOptions, nil), "storage-opt", "Storage driver options") |
|
20 |
+ flags.Var(opts.NewNamedListOptsRef("authorization-plugins", &conf.AuthorizationPlugins, nil), "authorization-plugin", "Authorization plugins to load") |
|
21 |
+ flags.Var(opts.NewNamedListOptsRef("exec-opts", &conf.ExecOptions, nil), "exec-opt", "Runtime execution options") |
|
22 |
+ flags.StringVarP(&conf.Pidfile, "pidfile", "p", defaultPidFile, "Path to use for daemon PID file") |
|
23 |
+ flags.StringVarP(&conf.Root, "graph", "g", defaultGraph, "Root of the Docker runtime") |
|
24 |
+ flags.BoolVarP(&conf.AutoRestart, "restart", "r", true, "--restart on the daemon has been deprecated in favor of --restart policies on docker run") |
|
25 |
+ flags.MarkDeprecated("restart", "Please use a restart policy on docker run") |
|
26 |
+ flags.StringVarP(&conf.GraphDriver, "storage-driver", "s", "", "Storage driver to use") |
|
27 |
+ flags.IntVar(&conf.Mtu, "mtu", 0, "Set the containers network MTU") |
|
28 |
+ flags.BoolVar(&conf.RawLogs, "raw-logs", false, "Full timestamps without ANSI coloring") |
|
29 |
+ // FIXME: why the inconsistency between "hosts" and "sockets"? |
|
30 |
+ flags.Var(opts.NewListOptsRef(&conf.DNS, opts.ValidateIPAddress), "dns", "DNS server to use") |
|
31 |
+ flags.Var(opts.NewNamedListOptsRef("dns-opts", &conf.DNSOptions, nil), "dns-opt", "DNS options to use") |
|
32 |
+ flags.Var(opts.NewListOptsRef(&conf.DNSSearch, opts.ValidateDNSSearch), "dns-search", "DNS search domains to use") |
|
33 |
+ flags.Var(opts.NewNamedListOptsRef("labels", &conf.Labels, opts.ValidateLabel), "label", "Set key=value labels to the daemon") |
|
34 |
+ flags.StringVar(&conf.LogConfig.Type, "log-driver", "json-file", "Default driver for container logs") |
|
35 |
+ flags.Var(opts.NewNamedMapOpts("log-opts", conf.LogConfig.Config, nil), "log-opt", "Default log driver options for containers") |
|
36 |
+ flags.StringVar(&conf.ClusterAdvertise, "cluster-advertise", "", "Address or interface name to advertise") |
|
37 |
+ flags.StringVar(&conf.ClusterStore, "cluster-store", "", "URL of the distributed storage backend") |
|
38 |
+ flags.Var(opts.NewNamedMapOpts("cluster-store-opts", conf.ClusterOpts, nil), "cluster-store-opt", "Set cluster store options") |
|
39 |
+ flags.StringVar(&conf.CorsHeaders, "api-cors-header", "", "Set CORS headers in the Engine API") |
|
40 |
+ flags.IntVar(&maxConcurrentDownloads, "max-concurrent-downloads", config.DefaultMaxConcurrentDownloads, "Set the max concurrent downloads for each pull") |
|
41 |
+ flags.IntVar(&maxConcurrentUploads, "max-concurrent-uploads", config.DefaultMaxConcurrentUploads, "Set the max concurrent uploads for each push") |
|
42 |
+ flags.IntVar(&conf.ShutdownTimeout, "shutdown-timeout", defaultShutdownTimeout, "Set the default shutdown timeout") |
|
43 |
+ |
|
44 |
+ flags.StringVar(&conf.SwarmDefaultAdvertiseAddr, "swarm-default-advertise-addr", "", "Set default address or interface for swarm advertised address") |
|
45 |
+ flags.BoolVar(&conf.Experimental, "experimental", false, "Enable experimental features") |
|
46 |
+ |
|
47 |
+ flags.StringVar(&conf.MetricsAddress, "metrics-addr", "", "Set default address and port to serve the metrics api on") |
|
48 |
+ |
|
49 |
+ conf.MaxConcurrentDownloads = &maxConcurrentDownloads |
|
50 |
+ conf.MaxConcurrentUploads = &maxConcurrentUploads |
|
51 |
+} |
0 | 52 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,34 @@ |
0 |
+// +build solaris linux freebsd |
|
1 |
+ |
|
2 |
+package main |
|
3 |
+ |
|
4 |
+import ( |
|
5 |
+ "github.com/docker/docker/api/types" |
|
6 |
+ "github.com/docker/docker/daemon/config" |
|
7 |
+ "github.com/docker/docker/opts" |
|
8 |
+ "github.com/spf13/pflag" |
|
9 |
+) |
|
10 |
+ |
|
11 |
+var ( |
|
12 |
+ defaultPidFile = "/var/run/docker.pid" |
|
13 |
+ defaultGraph = "/var/lib/docker" |
|
14 |
+ defaultExecRoot = "/var/run/docker" |
|
15 |
+) |
|
16 |
+ |
|
17 |
+// installUnixConfigFlags adds command-line options to the top-level flag parser for |
|
18 |
+// the current process that are common across Unix platforms. |
|
19 |
+func installUnixConfigFlags(conf *config.Config, flags *pflag.FlagSet) { |
|
20 |
+ conf.Runtimes = make(map[string]types.Runtime) |
|
21 |
+ |
|
22 |
+ flags.StringVarP(&conf.SocketGroup, "group", "G", "docker", "Group for the unix socket") |
|
23 |
+ flags.StringVar(&conf.BridgeConfig.IP, "bip", "", "Specify network bridge IP") |
|
24 |
+ flags.StringVarP(&conf.BridgeConfig.Iface, "bridge", "b", "", "Attach containers to a network bridge") |
|
25 |
+ flags.StringVar(&conf.BridgeConfig.FixedCIDR, "fixed-cidr", "", "IPv4 subnet for fixed IPs") |
|
26 |
+ flags.Var(opts.NewIPOpt(&conf.BridgeConfig.DefaultGatewayIPv4, ""), "default-gateway", "Container default gateway IPv4 address") |
|
27 |
+ flags.Var(opts.NewIPOpt(&conf.BridgeConfig.DefaultGatewayIPv6, ""), "default-gateway-v6", "Container default gateway IPv6 address") |
|
28 |
+ flags.BoolVar(&conf.BridgeConfig.InterContainerCommunication, "icc", true, "Enable inter-container communication") |
|
29 |
+ flags.Var(opts.NewIPOpt(&conf.BridgeConfig.DefaultIP, "0.0.0.0"), "ip", "Default IP when binding container ports") |
|
30 |
+ flags.Var(opts.NewNamedRuntimeOpt("runtimes", &conf.Runtimes, config.StockRuntimeName), "add-runtime", "Register an additional OCI compatible runtime") |
|
31 |
+ flags.StringVar(&conf.DefaultRuntime, "default-runtime", config.StockRuntimeName, "Default OCI runtime for containers") |
|
32 |
+ |
|
33 |
+} |
0 | 9 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,19 @@ |
0 |
+package main |
|
1 |
+ |
|
2 |
+import ( |
|
3 |
+ "github.com/docker/docker/daemon/config" |
|
4 |
+ runconfigopts "github.com/docker/docker/runconfig/opts" |
|
5 |
+ units "github.com/docker/go-units" |
|
6 |
+ "github.com/spf13/pflag" |
|
7 |
+) |
|
8 |
+ |
|
9 |
+// installConfigFlags adds flags to the pflag.FlagSet to configure the daemon |
|
10 |
+func installConfigFlags(conf *config.Config, flags *pflag.FlagSet) { |
|
11 |
+ // First handle install flags which are consistent cross-platform |
|
12 |
+ installCommonConfigFlags(conf, flags) |
|
13 |
+ |
|
14 |
+ // Then install flags common to unix platforms |
|
15 |
+ installUnixConfigFlags(conf, flags) |
|
16 |
+ |
|
17 |
+ attachExperimentalFlags(conf, flags) |
|
18 |
+} |
0 | 19 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,51 @@ |
0 |
+// +build linux,!solaris freebsd,!solaris |
|
1 |
+ |
|
2 |
+package main |
|
3 |
+ |
|
4 |
+import ( |
|
5 |
+ "github.com/docker/docker/daemon/config" |
|
6 |
+ "github.com/docker/docker/opts" |
|
7 |
+ units "github.com/docker/go-units" |
|
8 |
+ "github.com/spf13/pflag" |
|
9 |
+) |
|
10 |
+ |
|
11 |
+// installConfigFlags adds flags to the pflag.FlagSet to configure the daemon |
|
12 |
+func installConfigFlags(conf *config.Config, flags *pflag.FlagSet) { |
|
13 |
+ // First handle install flags which are consistent cross-platform |
|
14 |
+ installCommonConfigFlags(conf, flags) |
|
15 |
+ |
|
16 |
+ // Then install flags common to unix platforms |
|
17 |
+ installUnixConfigFlags(conf, flags) |
|
18 |
+ |
|
19 |
+ conf.Ulimits = make(map[string]*units.Ulimit) |
|
20 |
+ |
|
21 |
+ // Set default value for `--default-shm-size` |
|
22 |
+ conf.ShmSize = opts.MemBytes(config.DefaultShmSize) |
|
23 |
+ |
|
24 |
+ // Then platform-specific install flags |
|
25 |
+ flags.BoolVar(&conf.EnableSelinuxSupport, "selinux-enabled", false, "Enable selinux support") |
|
26 |
+ flags.Var(opts.NewUlimitOpt(&conf.Ulimits), "default-ulimit", "Default ulimits for containers") |
|
27 |
+ flags.BoolVar(&conf.BridgeConfig.EnableIPTables, "iptables", true, "Enable addition of iptables rules") |
|
28 |
+ flags.BoolVar(&conf.BridgeConfig.EnableIPForward, "ip-forward", true, "Enable net.ipv4.ip_forward") |
|
29 |
+ flags.BoolVar(&conf.BridgeConfig.EnableIPMasq, "ip-masq", true, "Enable IP masquerading") |
|
30 |
+ flags.BoolVar(&conf.BridgeConfig.EnableIPv6, "ipv6", false, "Enable IPv6 networking") |
|
31 |
+ flags.StringVar(&conf.ExecRoot, "exec-root", defaultExecRoot, "Root directory for execution state files") |
|
32 |
+ flags.StringVar(&conf.BridgeConfig.FixedCIDRv6, "fixed-cidr-v6", "", "IPv6 subnet for fixed IPs") |
|
33 |
+ flags.BoolVar(&conf.BridgeConfig.EnableUserlandProxy, "userland-proxy", true, "Use userland proxy for loopback traffic") |
|
34 |
+ flags.StringVar(&conf.BridgeConfig.UserlandProxyPath, "userland-proxy-path", "", "Path to the userland proxy binary") |
|
35 |
+ flags.BoolVar(&conf.EnableCors, "api-enable-cors", false, "Enable CORS headers in the Engine API, this is deprecated by --api-cors-header") |
|
36 |
+ flags.MarkDeprecated("api-enable-cors", "Please use --api-cors-header") |
|
37 |
+ flags.StringVar(&conf.CgroupParent, "cgroup-parent", "", "Set parent cgroup for all containers") |
|
38 |
+ flags.StringVar(&conf.RemappedRoot, "userns-remap", "", "User/Group setting for user namespaces") |
|
39 |
+ flags.StringVar(&conf.ContainerdAddr, "containerd", "", "Path to containerd socket") |
|
40 |
+ flags.BoolVar(&conf.LiveRestoreEnabled, "live-restore", false, "Enable live restore of docker when containers are still running") |
|
41 |
+ flags.IntVar(&conf.OOMScoreAdjust, "oom-score-adjust", -500, "Set the oom_score_adj for the daemon") |
|
42 |
+ flags.BoolVar(&conf.Init, "init", false, "Run an init in the container to forward signals and reap processes") |
|
43 |
+ flags.StringVar(&conf.InitPath, "init-path", "", "Path to the docker-init binary") |
|
44 |
+ flags.Int64Var(&conf.CPURealtimePeriod, "cpu-rt-period", 0, "Limit the CPU real-time period in microseconds") |
|
45 |
+ flags.Int64Var(&conf.CPURealtimeRuntime, "cpu-rt-runtime", 0, "Limit the CPU real-time runtime in microseconds") |
|
46 |
+ flags.StringVar(&conf.SeccompProfile, "seccomp-profile", "", "Path to seccomp profile") |
|
47 |
+ flags.Var(&conf.ShmSize, "default-shm-size", "Default shm size for containers") |
|
48 |
+ |
|
49 |
+ attachExperimentalFlags(conf, flags) |
|
50 |
+} |
0 | 51 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,32 @@ |
0 |
+// +build linux,!solaris freebsd,!solaris |
|
1 |
+ |
|
2 |
+package main |
|
3 |
+ |
|
4 |
+import ( |
|
5 |
+ "runtime" |
|
6 |
+ "testing" |
|
7 |
+ |
|
8 |
+ "github.com/docker/docker/daemon/config" |
|
9 |
+ "github.com/docker/docker/pkg/testutil/assert" |
|
10 |
+ "github.com/spf13/pflag" |
|
11 |
+) |
|
12 |
+ |
|
13 |
+func TestDaemonParseShmSize(t *testing.T) { |
|
14 |
+ if runtime.GOOS == "solaris" { |
|
15 |
+ t.Skip("ShmSize not supported on Solaris\n") |
|
16 |
+ } |
|
17 |
+ flags := pflag.NewFlagSet("test", pflag.ContinueOnError) |
|
18 |
+ |
|
19 |
+ conf := &config.Config{} |
|
20 |
+ installConfigFlags(conf, flags) |
|
21 |
+ // By default `--default-shm-size=64M` |
|
22 |
+ expectedValue := 64 * 1024 * 1024 |
|
23 |
+ if conf.ShmSize.Value() != int64(expectedValue) { |
|
24 |
+ t.Fatalf("expected default shm size %d, got %d", expectedValue, conf.ShmSize.Value()) |
|
25 |
+ } |
|
26 |
+ assert.NilError(t, flags.Set("default-shm-size", "128M")) |
|
27 |
+ expectedValue = 128 * 1024 * 1024 |
|
28 |
+ if conf.ShmSize.Value() != int64(expectedValue) { |
|
29 |
+ t.Fatalf("expected default shm size %d, got %d", expectedValue, conf.ShmSize.Value()) |
|
30 |
+ } |
|
31 |
+} |
0 | 32 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,25 @@ |
0 |
+package main |
|
1 |
+ |
|
2 |
+import ( |
|
3 |
+ "os" |
|
4 |
+ "path/filepath" |
|
5 |
+ |
|
6 |
+ "github.com/docker/docker/daemon/config" |
|
7 |
+ "github.com/spf13/pflag" |
|
8 |
+) |
|
9 |
+ |
|
10 |
+var ( |
|
11 |
+ defaultPidFile string |
|
12 |
+ defaultGraph = filepath.Join(os.Getenv("programdata"), "docker") |
|
13 |
+) |
|
14 |
+ |
|
15 |
+// installConfigFlags adds flags to the pflag.FlagSet to configure the daemon |
|
16 |
+func installConfigFlags(conf *config.Config, flags *pflag.FlagSet) { |
|
17 |
+ // First handle install flags which are consistent cross-platform |
|
18 |
+ installCommonConfigFlags(conf, flags) |
|
19 |
+ |
|
20 |
+ // Then platform-specific install flags. |
|
21 |
+ flags.StringVar(&conf.BridgeConfig.FixedCIDR, "fixed-cidr", "", "IPv4 subnet for fixed IPs") |
|
22 |
+ flags.StringVarP(&conf.BridgeConfig.Iface, "bridge", "b", "", "Attach containers to a virtual switch") |
|
23 |
+ flags.StringVarP(&conf.SocketGroup, "group", "G", "", "Users or groups that can access the named pipe") |
|
24 |
+} |
... | ... |
@@ -31,6 +31,7 @@ import ( |
31 | 31 |
cliflags "github.com/docker/docker/cli/flags" |
32 | 32 |
"github.com/docker/docker/daemon" |
33 | 33 |
"github.com/docker/docker/daemon/cluster" |
34 |
+ "github.com/docker/docker/daemon/config" |
|
34 | 35 |
"github.com/docker/docker/daemon/logger" |
35 | 36 |
"github.com/docker/docker/dockerversion" |
36 | 37 |
"github.com/docker/docker/libcontainerd" |
... | ... |
@@ -54,7 +55,7 @@ const ( |
54 | 54 |
|
55 | 55 |
// DaemonCli represents the daemon CLI. |
56 | 56 |
type DaemonCli struct { |
57 |
- *daemon.Config |
|
57 |
+ *config.Config |
|
58 | 58 |
configFile *string |
59 | 59 |
flags *pflag.FlagSet |
60 | 60 |
|
... | ... |
@@ -68,7 +69,7 @@ func NewDaemonCli() *DaemonCli { |
68 | 68 |
return &DaemonCli{} |
69 | 69 |
} |
70 | 70 |
|
71 |
-func migrateKey(config *daemon.Config) (err error) { |
|
71 |
+func migrateKey(config *config.Config) (err error) { |
|
72 | 72 |
// No migration necessary on Windows |
73 | 73 |
if runtime.GOOS == "windows" { |
74 | 74 |
return nil |
... | ... |
@@ -335,7 +336,7 @@ func (cli *DaemonCli) start(opts daemonOptions) (err error) { |
335 | 335 |
} |
336 | 336 |
|
337 | 337 |
func (cli *DaemonCli) reloadConfig() { |
338 |
- reload := func(config *daemon.Config) { |
|
338 |
+ reload := func(config *config.Config) { |
|
339 | 339 |
|
340 | 340 |
// Revalidate and reload the authorization plugins |
341 | 341 |
if err := validateAuthzPlugins(config.AuthorizationPlugins, cli.d.PluginStore); err != nil { |
... | ... |
@@ -363,7 +364,7 @@ func (cli *DaemonCli) reloadConfig() { |
363 | 363 |
} |
364 | 364 |
} |
365 | 365 |
|
366 |
- if err := daemon.ReloadConfiguration(*cli.configFile, cli.flags, reload); err != nil { |
|
366 |
+ if err := config.Reload(*cli.configFile, cli.flags, reload); err != nil { |
|
367 | 367 |
logrus.Error(err) |
368 | 368 |
} |
369 | 369 |
} |
... | ... |
@@ -395,24 +396,24 @@ func shutdownDaemon(d *daemon.Daemon) { |
395 | 395 |
} |
396 | 396 |
} |
397 | 397 |
|
398 |
-func loadDaemonCliConfig(opts daemonOptions) (*daemon.Config, error) { |
|
399 |
- config := opts.daemonConfig |
|
398 |
+func loadDaemonCliConfig(opts daemonOptions) (*config.Config, error) { |
|
399 |
+ conf := opts.daemonConfig |
|
400 | 400 |
flags := opts.flags |
401 |
- config.Debug = opts.common.Debug |
|
402 |
- config.Hosts = opts.common.Hosts |
|
403 |
- config.LogLevel = opts.common.LogLevel |
|
404 |
- config.TLS = opts.common.TLS |
|
405 |
- config.TLSVerify = opts.common.TLSVerify |
|
406 |
- config.CommonTLSOptions = daemon.CommonTLSOptions{} |
|
401 |
+ conf.Debug = opts.common.Debug |
|
402 |
+ conf.Hosts = opts.common.Hosts |
|
403 |
+ conf.LogLevel = opts.common.LogLevel |
|
404 |
+ conf.TLS = opts.common.TLS |
|
405 |
+ conf.TLSVerify = opts.common.TLSVerify |
|
406 |
+ conf.CommonTLSOptions = config.CommonTLSOptions{} |
|
407 | 407 |
|
408 | 408 |
if opts.common.TLSOptions != nil { |
409 |
- config.CommonTLSOptions.CAFile = opts.common.TLSOptions.CAFile |
|
410 |
- config.CommonTLSOptions.CertFile = opts.common.TLSOptions.CertFile |
|
411 |
- config.CommonTLSOptions.KeyFile = opts.common.TLSOptions.KeyFile |
|
409 |
+ conf.CommonTLSOptions.CAFile = opts.common.TLSOptions.CAFile |
|
410 |
+ conf.CommonTLSOptions.CertFile = opts.common.TLSOptions.CertFile |
|
411 |
+ conf.CommonTLSOptions.KeyFile = opts.common.TLSOptions.KeyFile |
|
412 | 412 |
} |
413 | 413 |
|
414 | 414 |
if opts.configFile != "" { |
415 |
- c, err := daemon.MergeDaemonConfigurations(config, flags, opts.configFile) |
|
415 |
+ c, err := config.MergeDaemonConfigurations(conf, flags, opts.configFile) |
|
416 | 416 |
if err != nil { |
417 | 417 |
if flags.Changed(flagDaemonConfigFile) || !os.IsNotExist(err) { |
418 | 418 |
return nil, fmt.Errorf("unable to configure the Docker daemon with file %s: %v\n", opts.configFile, err) |
... | ... |
@@ -421,11 +422,11 @@ func loadDaemonCliConfig(opts daemonOptions) (*daemon.Config, error) { |
421 | 421 |
// the merged configuration can be nil if the config file didn't exist. |
422 | 422 |
// leave the current configuration as it is if when that happens. |
423 | 423 |
if c != nil { |
424 |
- config = c |
|
424 |
+ conf = c |
|
425 | 425 |
} |
426 | 426 |
} |
427 | 427 |
|
428 |
- if err := daemon.ValidateConfiguration(config); err != nil { |
|
428 |
+ if err := config.Validate(conf); err != nil { |
|
429 | 429 |
return nil, err |
430 | 430 |
} |
431 | 431 |
|
... | ... |
@@ -442,20 +443,20 @@ func loadDaemonCliConfig(opts daemonOptions) (*daemon.Config, error) { |
442 | 442 |
// } |
443 | 443 |
// config.Labels = newLabels |
444 | 444 |
// |
445 |
- if _, err := daemon.GetConflictFreeLabels(config.Labels); err != nil { |
|
445 |
+ if _, err := config.GetConflictFreeLabels(conf.Labels); err != nil { |
|
446 | 446 |
logrus.Warnf("Engine labels with duplicate keys and conflicting values have been deprecated: %s", err) |
447 | 447 |
} |
448 | 448 |
|
449 | 449 |
// Regardless of whether the user sets it to true or false, if they |
450 | 450 |
// specify TLSVerify at all then we need to turn on TLS |
451 |
- if config.IsValueSet(cliflags.FlagTLSVerify) { |
|
452 |
- config.TLS = true |
|
451 |
+ if conf.IsValueSet(cliflags.FlagTLSVerify) { |
|
452 |
+ conf.TLS = true |
|
453 | 453 |
} |
454 | 454 |
|
455 | 455 |
// ensure that the log level is the one set after merging configurations |
456 |
- cliflags.SetLogLevel(config.LogLevel) |
|
456 |
+ cliflags.SetLogLevel(conf.LogLevel) |
|
457 | 457 |
|
458 |
- return config, nil |
|
458 |
+ return conf, nil |
|
459 | 459 |
} |
460 | 460 |
|
461 | 461 |
func initRouter(s *apiserver.Server, d *daemon.Daemon, c *cluster.Cluster) { |
... | ... |
@@ -5,7 +5,7 @@ import ( |
5 | 5 |
|
6 | 6 |
"github.com/Sirupsen/logrus" |
7 | 7 |
cliflags "github.com/docker/docker/cli/flags" |
8 |
- "github.com/docker/docker/daemon" |
|
8 |
+ "github.com/docker/docker/daemon/config" |
|
9 | 9 |
"github.com/docker/docker/pkg/testutil/assert" |
10 | 10 |
"github.com/docker/docker/pkg/testutil/tempfile" |
11 | 11 |
"github.com/spf13/pflag" |
... | ... |
@@ -13,12 +13,12 @@ import ( |
13 | 13 |
|
14 | 14 |
func defaultOptions(configFile string) daemonOptions { |
15 | 15 |
opts := daemonOptions{ |
16 |
- daemonConfig: &daemon.Config{}, |
|
16 |
+ daemonConfig: &config.Config{}, |
|
17 | 17 |
flags: &pflag.FlagSet{}, |
18 | 18 |
common: cliflags.NewCommonOptions(), |
19 | 19 |
} |
20 | 20 |
opts.common.InstallFlags(opts.flags) |
21 |
- opts.daemonConfig.InstallFlags(opts.flags) |
|
21 |
+ installConfigFlags(opts.daemonConfig, opts.flags) |
|
22 | 22 |
opts.flags.StringVar(&opts.configFile, flagDaemonConfigFile, defaultDaemonConfigFile, "") |
23 | 23 |
opts.configFile = configFile |
24 | 24 |
return opts |
... | ... |
@@ -6,10 +6,11 @@ |
6 | 6 |
package main |
7 | 7 |
|
8 | 8 |
import ( |
9 |
- "github.com/docker/docker/daemon" |
|
9 |
+ "testing" |
|
10 |
+ |
|
11 |
+ "github.com/docker/docker/daemon/config" |
|
10 | 12 |
"github.com/docker/docker/pkg/testutil/assert" |
11 | 13 |
"github.com/docker/docker/pkg/testutil/tempfile" |
12 |
- "testing" |
|
13 | 14 |
) |
14 | 15 |
|
15 | 16 |
func TestLoadDaemonCliConfigWithDaemonFlags(t *testing.T) { |
... | ... |
@@ -82,10 +83,10 @@ func TestLoadDaemonConfigWithTrueDefaultValues(t *testing.T) { |
82 | 82 |
|
83 | 83 |
// make sure reloading doesn't generate configuration |
84 | 84 |
// conflicts after normalizing boolean values. |
85 |
- reload := func(reloadedConfig *daemon.Config) { |
|
85 |
+ reload := func(reloadedConfig *config.Config) { |
|
86 | 86 |
assert.Equal(t, reloadedConfig.EnableUserlandProxy, false) |
87 | 87 |
} |
88 |
- assert.NilError(t, daemon.ReloadConfiguration(opts.configFile, opts.flags, reload)) |
|
88 |
+ assert.NilError(t, config.Reload(opts.configFile, opts.flags, reload)) |
|
89 | 89 |
} |
90 | 90 |
|
91 | 91 |
func TestLoadDaemonConfigWithTrueDefaultValuesLeaveDefaults(t *testing.T) { |
... | ... |
@@ -9,7 +9,7 @@ import ( |
9 | 9 |
"github.com/Sirupsen/logrus" |
10 | 10 |
"github.com/docker/docker/cli" |
11 | 11 |
cliflags "github.com/docker/docker/cli/flags" |
12 |
- "github.com/docker/docker/daemon" |
|
12 |
+ "github.com/docker/docker/daemon/config" |
|
13 | 13 |
"github.com/docker/docker/dockerversion" |
14 | 14 |
"github.com/docker/docker/pkg/reexec" |
15 | 15 |
"github.com/docker/docker/pkg/term" |
... | ... |
@@ -20,14 +20,14 @@ import ( |
20 | 20 |
type daemonOptions struct { |
21 | 21 |
version bool |
22 | 22 |
configFile string |
23 |
- daemonConfig *daemon.Config |
|
23 |
+ daemonConfig *config.Config |
|
24 | 24 |
common *cliflags.CommonOptions |
25 | 25 |
flags *pflag.FlagSet |
26 | 26 |
} |
27 | 27 |
|
28 | 28 |
func newDaemonCommand() *cobra.Command { |
29 | 29 |
opts := daemonOptions{ |
30 |
- daemonConfig: daemon.NewConfig(), |
|
30 |
+ daemonConfig: config.New(), |
|
31 | 31 |
common: cliflags.NewCommonOptions(), |
32 | 32 |
} |
33 | 33 |
|
... | ... |
@@ -48,7 +48,7 @@ func newDaemonCommand() *cobra.Command { |
48 | 48 |
flags.BoolVarP(&opts.version, "version", "v", false, "Print version information and quit") |
49 | 49 |
flags.StringVar(&opts.configFile, flagDaemonConfigFile, defaultDaemonConfigFile, "Daemon configuration file") |
50 | 50 |
opts.common.InstallFlags(flags) |
51 |
- opts.daemonConfig.InstallFlags(flags) |
|
51 |
+ installConfigFlags(opts.daemonConfig, flags) |
|
52 | 52 |
installServiceFlags(flags) |
53 | 53 |
|
54 | 54 |
return cmd |
55 | 55 |
deleted file mode 100644 |
... | ... |
@@ -1,539 +0,0 @@ |
1 |
-package daemon |
|
2 |
- |
|
3 |
-import ( |
|
4 |
- "bytes" |
|
5 |
- "encoding/json" |
|
6 |
- "errors" |
|
7 |
- "fmt" |
|
8 |
- "io" |
|
9 |
- "io/ioutil" |
|
10 |
- "runtime" |
|
11 |
- "sort" |
|
12 |
- "strings" |
|
13 |
- "sync" |
|
14 |
- |
|
15 |
- "github.com/Sirupsen/logrus" |
|
16 |
- "github.com/docker/docker/opts" |
|
17 |
- "github.com/docker/docker/pkg/discovery" |
|
18 |
- "github.com/docker/docker/registry" |
|
19 |
- "github.com/imdario/mergo" |
|
20 |
- "github.com/spf13/pflag" |
|
21 |
-) |
|
22 |
- |
|
23 |
-const ( |
|
24 |
- // defaultMaxConcurrentDownloads is the default value for |
|
25 |
- // maximum number of downloads that |
|
26 |
- // may take place at a time for each pull. |
|
27 |
- defaultMaxConcurrentDownloads = 3 |
|
28 |
- // defaultMaxConcurrentUploads is the default value for |
|
29 |
- // maximum number of uploads that |
|
30 |
- // may take place at a time for each push. |
|
31 |
- defaultMaxConcurrentUploads = 5 |
|
32 |
- // stockRuntimeName is the reserved name/alias used to represent the |
|
33 |
- // OCI runtime being shipped with the docker daemon package. |
|
34 |
- stockRuntimeName = "runc" |
|
35 |
-) |
|
36 |
- |
|
37 |
-const ( |
|
38 |
- defaultNetworkMtu = 1500 |
|
39 |
- disableNetworkBridge = "none" |
|
40 |
-) |
|
41 |
- |
|
42 |
-const ( |
|
43 |
- defaultShutdownTimeout = 15 |
|
44 |
-) |
|
45 |
- |
|
46 |
-// flatOptions contains configuration keys |
|
47 |
-// that MUST NOT be parsed as deep structures. |
|
48 |
-// Use this to differentiate these options |
|
49 |
-// with others like the ones in CommonTLSOptions. |
|
50 |
-var flatOptions = map[string]bool{ |
|
51 |
- "cluster-store-opts": true, |
|
52 |
- "log-opts": true, |
|
53 |
- "runtimes": true, |
|
54 |
- "default-ulimits": true, |
|
55 |
-} |
|
56 |
- |
|
57 |
-// LogConfig represents the default log configuration. |
|
58 |
-// It includes json tags to deserialize configuration from a file |
|
59 |
-// using the same names that the flags in the command line use. |
|
60 |
-type LogConfig struct { |
|
61 |
- Type string `json:"log-driver,omitempty"` |
|
62 |
- Config map[string]string `json:"log-opts,omitempty"` |
|
63 |
-} |
|
64 |
- |
|
65 |
-// commonBridgeConfig stores all the platform-common bridge driver specific |
|
66 |
-// configuration. |
|
67 |
-type commonBridgeConfig struct { |
|
68 |
- Iface string `json:"bridge,omitempty"` |
|
69 |
- FixedCIDR string `json:"fixed-cidr,omitempty"` |
|
70 |
-} |
|
71 |
- |
|
72 |
-// CommonTLSOptions defines TLS configuration for the daemon server. |
|
73 |
-// It includes json tags to deserialize configuration from a file |
|
74 |
-// using the same names that the flags in the command line use. |
|
75 |
-type CommonTLSOptions struct { |
|
76 |
- CAFile string `json:"tlscacert,omitempty"` |
|
77 |
- CertFile string `json:"tlscert,omitempty"` |
|
78 |
- KeyFile string `json:"tlskey,omitempty"` |
|
79 |
-} |
|
80 |
- |
|
81 |
-// CommonConfig defines the configuration of a docker daemon which is |
|
82 |
-// common across platforms. |
|
83 |
-// It includes json tags to deserialize configuration from a file |
|
84 |
-// using the same names that the flags in the command line use. |
|
85 |
-type CommonConfig struct { |
|
86 |
- AuthorizationPlugins []string `json:"authorization-plugins,omitempty"` // AuthorizationPlugins holds list of authorization plugins |
|
87 |
- AutoRestart bool `json:"-"` |
|
88 |
- Context map[string][]string `json:"-"` |
|
89 |
- DisableBridge bool `json:"-"` |
|
90 |
- DNS []string `json:"dns,omitempty"` |
|
91 |
- DNSOptions []string `json:"dns-opts,omitempty"` |
|
92 |
- DNSSearch []string `json:"dns-search,omitempty"` |
|
93 |
- ExecOptions []string `json:"exec-opts,omitempty"` |
|
94 |
- GraphDriver string `json:"storage-driver,omitempty"` |
|
95 |
- GraphOptions []string `json:"storage-opts,omitempty"` |
|
96 |
- Labels []string `json:"labels,omitempty"` |
|
97 |
- Mtu int `json:"mtu,omitempty"` |
|
98 |
- Pidfile string `json:"pidfile,omitempty"` |
|
99 |
- RawLogs bool `json:"raw-logs,omitempty"` |
|
100 |
- Root string `json:"graph,omitempty"` |
|
101 |
- SocketGroup string `json:"group,omitempty"` |
|
102 |
- TrustKeyPath string `json:"-"` |
|
103 |
- CorsHeaders string `json:"api-cors-header,omitempty"` |
|
104 |
- EnableCors bool `json:"api-enable-cors,omitempty"` |
|
105 |
- |
|
106 |
- // LiveRestoreEnabled determines whether we should keep containers |
|
107 |
- // alive upon daemon shutdown/start |
|
108 |
- LiveRestoreEnabled bool `json:"live-restore,omitempty"` |
|
109 |
- |
|
110 |
- // ClusterStore is the storage backend used for the cluster information. It is used by both |
|
111 |
- // multihost networking (to store networks and endpoints information) and by the node discovery |
|
112 |
- // mechanism. |
|
113 |
- ClusterStore string `json:"cluster-store,omitempty"` |
|
114 |
- |
|
115 |
- // ClusterOpts is used to pass options to the discovery package for tuning libkv settings, such |
|
116 |
- // as TLS configuration settings. |
|
117 |
- ClusterOpts map[string]string `json:"cluster-store-opts,omitempty"` |
|
118 |
- |
|
119 |
- // ClusterAdvertise is the network endpoint that the Engine advertises for the purpose of node |
|
120 |
- // discovery. This should be a 'host:port' combination on which that daemon instance is |
|
121 |
- // reachable by other hosts. |
|
122 |
- ClusterAdvertise string `json:"cluster-advertise,omitempty"` |
|
123 |
- |
|
124 |
- // MaxConcurrentDownloads is the maximum number of downloads that |
|
125 |
- // may take place at a time for each pull. |
|
126 |
- MaxConcurrentDownloads *int `json:"max-concurrent-downloads,omitempty"` |
|
127 |
- |
|
128 |
- // MaxConcurrentUploads is the maximum number of uploads that |
|
129 |
- // may take place at a time for each push. |
|
130 |
- MaxConcurrentUploads *int `json:"max-concurrent-uploads,omitempty"` |
|
131 |
- |
|
132 |
- // ShutdownTimeout is the timeout value (in seconds) the daemon will wait for the container |
|
133 |
- // to stop when daemon is being shutdown |
|
134 |
- ShutdownTimeout int `json:"shutdown-timeout,omitempty"` |
|
135 |
- |
|
136 |
- Debug bool `json:"debug,omitempty"` |
|
137 |
- Hosts []string `json:"hosts,omitempty"` |
|
138 |
- LogLevel string `json:"log-level,omitempty"` |
|
139 |
- TLS bool `json:"tls,omitempty"` |
|
140 |
- TLSVerify bool `json:"tlsverify,omitempty"` |
|
141 |
- |
|
142 |
- // Embedded structs that allow config |
|
143 |
- // deserialization without the full struct. |
|
144 |
- CommonTLSOptions |
|
145 |
- |
|
146 |
- // SwarmDefaultAdvertiseAddr is the default host/IP or network interface |
|
147 |
- // to use if a wildcard address is specified in the ListenAddr value |
|
148 |
- // given to the /swarm/init endpoint and no advertise address is |
|
149 |
- // specified. |
|
150 |
- SwarmDefaultAdvertiseAddr string `json:"swarm-default-advertise-addr"` |
|
151 |
- MetricsAddress string `json:"metrics-addr"` |
|
152 |
- |
|
153 |
- LogConfig |
|
154 |
- bridgeConfig // bridgeConfig holds bridge network specific configuration. |
|
155 |
- registry.ServiceOptions |
|
156 |
- |
|
157 |
- reloadLock sync.Mutex |
|
158 |
- valuesSet map[string]interface{} |
|
159 |
- |
|
160 |
- Experimental bool `json:"experimental"` // Experimental indicates whether experimental features should be exposed or not |
|
161 |
-} |
|
162 |
- |
|
163 |
-// InstallCommonFlags adds flags to the pflag.FlagSet to configure the daemon |
|
164 |
-func (config *Config) InstallCommonFlags(flags *pflag.FlagSet) { |
|
165 |
- var maxConcurrentDownloads, maxConcurrentUploads int |
|
166 |
- |
|
167 |
- config.ServiceOptions.InstallCliFlags(flags) |
|
168 |
- |
|
169 |
- flags.Var(opts.NewNamedListOptsRef("storage-opts", &config.GraphOptions, nil), "storage-opt", "Storage driver options") |
|
170 |
- flags.Var(opts.NewNamedListOptsRef("authorization-plugins", &config.AuthorizationPlugins, nil), "authorization-plugin", "Authorization plugins to load") |
|
171 |
- flags.Var(opts.NewNamedListOptsRef("exec-opts", &config.ExecOptions, nil), "exec-opt", "Runtime execution options") |
|
172 |
- flags.StringVarP(&config.Pidfile, "pidfile", "p", defaultPidFile, "Path to use for daemon PID file") |
|
173 |
- flags.StringVarP(&config.Root, "graph", "g", defaultGraph, "Root of the Docker runtime") |
|
174 |
- flags.BoolVarP(&config.AutoRestart, "restart", "r", true, "--restart on the daemon has been deprecated in favor of --restart policies on docker run") |
|
175 |
- flags.MarkDeprecated("restart", "Please use a restart policy on docker run") |
|
176 |
- flags.StringVarP(&config.GraphDriver, "storage-driver", "s", "", "Storage driver to use") |
|
177 |
- flags.IntVar(&config.Mtu, "mtu", 0, "Set the containers network MTU") |
|
178 |
- flags.BoolVar(&config.RawLogs, "raw-logs", false, "Full timestamps without ANSI coloring") |
|
179 |
- // FIXME: why the inconsistency between "hosts" and "sockets"? |
|
180 |
- flags.Var(opts.NewListOptsRef(&config.DNS, opts.ValidateIPAddress), "dns", "DNS server to use") |
|
181 |
- flags.Var(opts.NewNamedListOptsRef("dns-opts", &config.DNSOptions, nil), "dns-opt", "DNS options to use") |
|
182 |
- flags.Var(opts.NewListOptsRef(&config.DNSSearch, opts.ValidateDNSSearch), "dns-search", "DNS search domains to use") |
|
183 |
- flags.Var(opts.NewNamedListOptsRef("labels", &config.Labels, opts.ValidateLabel), "label", "Set key=value labels to the daemon") |
|
184 |
- flags.StringVar(&config.LogConfig.Type, "log-driver", "json-file", "Default driver for container logs") |
|
185 |
- flags.Var(opts.NewNamedMapOpts("log-opts", config.LogConfig.Config, nil), "log-opt", "Default log driver options for containers") |
|
186 |
- flags.StringVar(&config.ClusterAdvertise, "cluster-advertise", "", "Address or interface name to advertise") |
|
187 |
- flags.StringVar(&config.ClusterStore, "cluster-store", "", "URL of the distributed storage backend") |
|
188 |
- flags.Var(opts.NewNamedMapOpts("cluster-store-opts", config.ClusterOpts, nil), "cluster-store-opt", "Set cluster store options") |
|
189 |
- flags.StringVar(&config.CorsHeaders, "api-cors-header", "", "Set CORS headers in the Engine API") |
|
190 |
- flags.IntVar(&maxConcurrentDownloads, "max-concurrent-downloads", defaultMaxConcurrentDownloads, "Set the max concurrent downloads for each pull") |
|
191 |
- flags.IntVar(&maxConcurrentUploads, "max-concurrent-uploads", defaultMaxConcurrentUploads, "Set the max concurrent uploads for each push") |
|
192 |
- flags.IntVar(&config.ShutdownTimeout, "shutdown-timeout", defaultShutdownTimeout, "Set the default shutdown timeout") |
|
193 |
- |
|
194 |
- flags.StringVar(&config.SwarmDefaultAdvertiseAddr, "swarm-default-advertise-addr", "", "Set default address or interface for swarm advertised address") |
|
195 |
- flags.BoolVar(&config.Experimental, "experimental", false, "Enable experimental features") |
|
196 |
- |
|
197 |
- flags.StringVar(&config.MetricsAddress, "metrics-addr", "", "Set default address and port to serve the metrics api on") |
|
198 |
- |
|
199 |
- config.MaxConcurrentDownloads = &maxConcurrentDownloads |
|
200 |
- config.MaxConcurrentUploads = &maxConcurrentUploads |
|
201 |
-} |
|
202 |
- |
|
203 |
-// IsValueSet returns true if a configuration value |
|
204 |
-// was explicitly set in the configuration file. |
|
205 |
-func (config *Config) IsValueSet(name string) bool { |
|
206 |
- if config.valuesSet == nil { |
|
207 |
- return false |
|
208 |
- } |
|
209 |
- _, ok := config.valuesSet[name] |
|
210 |
- return ok |
|
211 |
-} |
|
212 |
- |
|
213 |
-// NewConfig returns a new fully initialized Config struct |
|
214 |
-func NewConfig() *Config { |
|
215 |
- config := Config{} |
|
216 |
- config.LogConfig.Config = make(map[string]string) |
|
217 |
- config.ClusterOpts = make(map[string]string) |
|
218 |
- |
|
219 |
- if runtime.GOOS != "linux" { |
|
220 |
- config.V2Only = true |
|
221 |
- } |
|
222 |
- return &config |
|
223 |
-} |
|
224 |
- |
|
225 |
-func parseClusterAdvertiseSettings(clusterStore, clusterAdvertise string) (string, error) { |
|
226 |
- if runtime.GOOS == "solaris" && (clusterAdvertise != "" || clusterStore != "") { |
|
227 |
- return "", errors.New("Cluster Advertise Settings not supported on Solaris") |
|
228 |
- } |
|
229 |
- if clusterAdvertise == "" { |
|
230 |
- return "", errDiscoveryDisabled |
|
231 |
- } |
|
232 |
- if clusterStore == "" { |
|
233 |
- return "", errors.New("invalid cluster configuration. --cluster-advertise must be accompanied by --cluster-store configuration") |
|
234 |
- } |
|
235 |
- |
|
236 |
- advertise, err := discovery.ParseAdvertise(clusterAdvertise) |
|
237 |
- if err != nil { |
|
238 |
- return "", fmt.Errorf("discovery advertise parsing failed (%v)", err) |
|
239 |
- } |
|
240 |
- return advertise, nil |
|
241 |
-} |
|
242 |
- |
|
243 |
-// GetConflictFreeLabels validates Labels for conflict |
|
244 |
-// In swarm the duplicates for labels are removed |
|
245 |
-// so we only take same values here, no conflict values |
|
246 |
-// If the key-value is the same we will only take the last label |
|
247 |
-func GetConflictFreeLabels(labels []string) ([]string, error) { |
|
248 |
- labelMap := map[string]string{} |
|
249 |
- for _, label := range labels { |
|
250 |
- stringSlice := strings.SplitN(label, "=", 2) |
|
251 |
- if len(stringSlice) > 1 { |
|
252 |
- // If there is a conflict we will return an error |
|
253 |
- if v, ok := labelMap[stringSlice[0]]; ok && v != stringSlice[1] { |
|
254 |
- return nil, fmt.Errorf("conflict labels for %s=%s and %s=%s", stringSlice[0], stringSlice[1], stringSlice[0], v) |
|
255 |
- } |
|
256 |
- labelMap[stringSlice[0]] = stringSlice[1] |
|
257 |
- } |
|
258 |
- } |
|
259 |
- |
|
260 |
- newLabels := []string{} |
|
261 |
- for k, v := range labelMap { |
|
262 |
- newLabels = append(newLabels, fmt.Sprintf("%s=%s", k, v)) |
|
263 |
- } |
|
264 |
- return newLabels, nil |
|
265 |
-} |
|
266 |
- |
|
267 |
-// ReloadConfiguration reads the configuration in the host and reloads the daemon and server. |
|
268 |
-func ReloadConfiguration(configFile string, flags *pflag.FlagSet, reload func(*Config)) error { |
|
269 |
- logrus.Infof("Got signal to reload configuration, reloading from: %s", configFile) |
|
270 |
- newConfig, err := getConflictFreeConfiguration(configFile, flags) |
|
271 |
- if err != nil { |
|
272 |
- return err |
|
273 |
- } |
|
274 |
- |
|
275 |
- if err := ValidateConfiguration(newConfig); err != nil { |
|
276 |
- return fmt.Errorf("file configuration validation failed (%v)", err) |
|
277 |
- } |
|
278 |
- |
|
279 |
- // Labels of the docker engine used to allow multiple values associated with the same key. |
|
280 |
- // This is deprecated in 1.13, and, be removed after 3 release cycles. |
|
281 |
- // The following will check the conflict of labels, and report a warning for deprecation. |
|
282 |
- // |
|
283 |
- // TODO: After 3 release cycles (1.16) an error will be returned, and labels will be |
|
284 |
- // sanitized to consolidate duplicate key-value pairs (config.Labels = newLabels): |
|
285 |
- // |
|
286 |
- // newLabels, err := GetConflictFreeLabels(newConfig.Labels) |
|
287 |
- // if err != nil { |
|
288 |
- // return err |
|
289 |
- // } |
|
290 |
- // newConfig.Labels = newLabels |
|
291 |
- // |
|
292 |
- if _, err := GetConflictFreeLabels(newConfig.Labels); err != nil { |
|
293 |
- logrus.Warnf("Engine labels with duplicate keys and conflicting values have been deprecated: %s", err) |
|
294 |
- } |
|
295 |
- |
|
296 |
- reload(newConfig) |
|
297 |
- return nil |
|
298 |
-} |
|
299 |
- |
|
300 |
-// boolValue is an interface that boolean value flags implement |
|
301 |
-// to tell the command line how to make -name equivalent to -name=true. |
|
302 |
-type boolValue interface { |
|
303 |
- IsBoolFlag() bool |
|
304 |
-} |
|
305 |
- |
|
306 |
-// MergeDaemonConfigurations reads a configuration file, |
|
307 |
-// loads the file configuration in an isolated structure, |
|
308 |
-// and merges the configuration provided from flags on top |
|
309 |
-// if there are no conflicts. |
|
310 |
-func MergeDaemonConfigurations(flagsConfig *Config, flags *pflag.FlagSet, configFile string) (*Config, error) { |
|
311 |
- fileConfig, err := getConflictFreeConfiguration(configFile, flags) |
|
312 |
- if err != nil { |
|
313 |
- return nil, err |
|
314 |
- } |
|
315 |
- |
|
316 |
- if err := ValidateConfiguration(fileConfig); err != nil { |
|
317 |
- return nil, fmt.Errorf("file configuration validation failed (%v)", err) |
|
318 |
- } |
|
319 |
- |
|
320 |
- // merge flags configuration on top of the file configuration |
|
321 |
- if err := mergo.Merge(fileConfig, flagsConfig); err != nil { |
|
322 |
- return nil, err |
|
323 |
- } |
|
324 |
- |
|
325 |
- // We need to validate again once both fileConfig and flagsConfig |
|
326 |
- // have been merged |
|
327 |
- if err := ValidateConfiguration(fileConfig); err != nil { |
|
328 |
- return nil, fmt.Errorf("file configuration validation failed (%v)", err) |
|
329 |
- } |
|
330 |
- |
|
331 |
- return fileConfig, nil |
|
332 |
-} |
|
333 |
- |
|
334 |
-// getConflictFreeConfiguration loads the configuration from a JSON file. |
|
335 |
-// It compares that configuration with the one provided by the flags, |
|
336 |
-// and returns an error if there are conflicts. |
|
337 |
-func getConflictFreeConfiguration(configFile string, flags *pflag.FlagSet) (*Config, error) { |
|
338 |
- b, err := ioutil.ReadFile(configFile) |
|
339 |
- if err != nil { |
|
340 |
- return nil, err |
|
341 |
- } |
|
342 |
- |
|
343 |
- var config Config |
|
344 |
- var reader io.Reader |
|
345 |
- if flags != nil { |
|
346 |
- var jsonConfig map[string]interface{} |
|
347 |
- reader = bytes.NewReader(b) |
|
348 |
- if err := json.NewDecoder(reader).Decode(&jsonConfig); err != nil { |
|
349 |
- return nil, err |
|
350 |
- } |
|
351 |
- |
|
352 |
- configSet := configValuesSet(jsonConfig) |
|
353 |
- |
|
354 |
- if err := findConfigurationConflicts(configSet, flags); err != nil { |
|
355 |
- return nil, err |
|
356 |
- } |
|
357 |
- |
|
358 |
- // Override flag values to make sure the values set in the config file with nullable values, like `false`, |
|
359 |
- // are not overridden by default truthy values from the flags that were not explicitly set. |
|
360 |
- // See https://github.com/docker/docker/issues/20289 for an example. |
|
361 |
- // |
|
362 |
- // TODO: Rewrite configuration logic to avoid same issue with other nullable values, like numbers. |
|
363 |
- namedOptions := make(map[string]interface{}) |
|
364 |
- for key, value := range configSet { |
|
365 |
- f := flags.Lookup(key) |
|
366 |
- if f == nil { // ignore named flags that don't match |
|
367 |
- namedOptions[key] = value |
|
368 |
- continue |
|
369 |
- } |
|
370 |
- |
|
371 |
- if _, ok := f.Value.(boolValue); ok { |
|
372 |
- f.Value.Set(fmt.Sprintf("%v", value)) |
|
373 |
- } |
|
374 |
- } |
|
375 |
- if len(namedOptions) > 0 { |
|
376 |
- // set also default for mergeVal flags that are boolValue at the same time. |
|
377 |
- flags.VisitAll(func(f *pflag.Flag) { |
|
378 |
- if opt, named := f.Value.(opts.NamedOption); named { |
|
379 |
- v, set := namedOptions[opt.Name()] |
|
380 |
- _, boolean := f.Value.(boolValue) |
|
381 |
- if set && boolean { |
|
382 |
- f.Value.Set(fmt.Sprintf("%v", v)) |
|
383 |
- } |
|
384 |
- } |
|
385 |
- }) |
|
386 |
- } |
|
387 |
- |
|
388 |
- config.valuesSet = configSet |
|
389 |
- } |
|
390 |
- |
|
391 |
- reader = bytes.NewReader(b) |
|
392 |
- err = json.NewDecoder(reader).Decode(&config) |
|
393 |
- return &config, err |
|
394 |
-} |
|
395 |
- |
|
396 |
-// configValuesSet returns the configuration values explicitly set in the file. |
|
397 |
-func configValuesSet(config map[string]interface{}) map[string]interface{} { |
|
398 |
- flatten := make(map[string]interface{}) |
|
399 |
- for k, v := range config { |
|
400 |
- if m, isMap := v.(map[string]interface{}); isMap && !flatOptions[k] { |
|
401 |
- for km, vm := range m { |
|
402 |
- flatten[km] = vm |
|
403 |
- } |
|
404 |
- continue |
|
405 |
- } |
|
406 |
- |
|
407 |
- flatten[k] = v |
|
408 |
- } |
|
409 |
- return flatten |
|
410 |
-} |
|
411 |
- |
|
412 |
-// findConfigurationConflicts iterates over the provided flags searching for |
|
413 |
-// duplicated configurations and unknown keys. It returns an error with all the conflicts if |
|
414 |
-// it finds any. |
|
415 |
-func findConfigurationConflicts(config map[string]interface{}, flags *pflag.FlagSet) error { |
|
416 |
- // 1. Search keys from the file that we don't recognize as flags. |
|
417 |
- unknownKeys := make(map[string]interface{}) |
|
418 |
- for key, value := range config { |
|
419 |
- if flag := flags.Lookup(key); flag == nil { |
|
420 |
- unknownKeys[key] = value |
|
421 |
- } |
|
422 |
- } |
|
423 |
- |
|
424 |
- // 2. Discard values that implement NamedOption. |
|
425 |
- // Their configuration name differs from their flag name, like `labels` and `label`. |
|
426 |
- if len(unknownKeys) > 0 { |
|
427 |
- unknownNamedConflicts := func(f *pflag.Flag) { |
|
428 |
- if namedOption, ok := f.Value.(opts.NamedOption); ok { |
|
429 |
- if _, valid := unknownKeys[namedOption.Name()]; valid { |
|
430 |
- delete(unknownKeys, namedOption.Name()) |
|
431 |
- } |
|
432 |
- } |
|
433 |
- } |
|
434 |
- flags.VisitAll(unknownNamedConflicts) |
|
435 |
- } |
|
436 |
- |
|
437 |
- if len(unknownKeys) > 0 { |
|
438 |
- var unknown []string |
|
439 |
- for key := range unknownKeys { |
|
440 |
- unknown = append(unknown, key) |
|
441 |
- } |
|
442 |
- return fmt.Errorf("the following directives don't match any configuration option: %s", strings.Join(unknown, ", ")) |
|
443 |
- } |
|
444 |
- |
|
445 |
- var conflicts []string |
|
446 |
- printConflict := func(name string, flagValue, fileValue interface{}) string { |
|
447 |
- return fmt.Sprintf("%s: (from flag: %v, from file: %v)", name, flagValue, fileValue) |
|
448 |
- } |
|
449 |
- |
|
450 |
- // 3. Search keys that are present as a flag and as a file option. |
|
451 |
- duplicatedConflicts := func(f *pflag.Flag) { |
|
452 |
- // search option name in the json configuration payload if the value is a named option |
|
453 |
- if namedOption, ok := f.Value.(opts.NamedOption); ok { |
|
454 |
- if optsValue, ok := config[namedOption.Name()]; ok { |
|
455 |
- conflicts = append(conflicts, printConflict(namedOption.Name(), f.Value.String(), optsValue)) |
|
456 |
- } |
|
457 |
- } else { |
|
458 |
- // search flag name in the json configuration payload |
|
459 |
- for _, name := range []string{f.Name, f.Shorthand} { |
|
460 |
- if value, ok := config[name]; ok { |
|
461 |
- conflicts = append(conflicts, printConflict(name, f.Value.String(), value)) |
|
462 |
- break |
|
463 |
- } |
|
464 |
- } |
|
465 |
- } |
|
466 |
- } |
|
467 |
- |
|
468 |
- flags.Visit(duplicatedConflicts) |
|
469 |
- |
|
470 |
- if len(conflicts) > 0 { |
|
471 |
- return fmt.Errorf("the following directives are specified both as a flag and in the configuration file: %s", strings.Join(conflicts, ", ")) |
|
472 |
- } |
|
473 |
- return nil |
|
474 |
-} |
|
475 |
- |
|
476 |
-// ValidateConfiguration validates some specific configs. |
|
477 |
-// such as config.DNS, config.Labels, config.DNSSearch, |
|
478 |
-// as well as config.MaxConcurrentDownloads, config.MaxConcurrentUploads. |
|
479 |
-func ValidateConfiguration(config *Config) error { |
|
480 |
- // validate DNS |
|
481 |
- for _, dns := range config.DNS { |
|
482 |
- if _, err := opts.ValidateIPAddress(dns); err != nil { |
|
483 |
- return err |
|
484 |
- } |
|
485 |
- } |
|
486 |
- |
|
487 |
- // validate DNSSearch |
|
488 |
- for _, dnsSearch := range config.DNSSearch { |
|
489 |
- if _, err := opts.ValidateDNSSearch(dnsSearch); err != nil { |
|
490 |
- return err |
|
491 |
- } |
|
492 |
- } |
|
493 |
- |
|
494 |
- // validate Labels |
|
495 |
- for _, label := range config.Labels { |
|
496 |
- if _, err := opts.ValidateLabel(label); err != nil { |
|
497 |
- return err |
|
498 |
- } |
|
499 |
- } |
|
500 |
- |
|
501 |
- // validate MaxConcurrentDownloads |
|
502 |
- if config.IsValueSet("max-concurrent-downloads") && config.MaxConcurrentDownloads != nil && *config.MaxConcurrentDownloads < 0 { |
|
503 |
- return fmt.Errorf("invalid max concurrent downloads: %d", *config.MaxConcurrentDownloads) |
|
504 |
- } |
|
505 |
- |
|
506 |
- // validate MaxConcurrentUploads |
|
507 |
- if config.IsValueSet("max-concurrent-uploads") && config.MaxConcurrentUploads != nil && *config.MaxConcurrentUploads < 0 { |
|
508 |
- return fmt.Errorf("invalid max concurrent uploads: %d", *config.MaxConcurrentUploads) |
|
509 |
- } |
|
510 |
- |
|
511 |
- // validate that "default" runtime is not reset |
|
512 |
- if runtimes := config.GetAllRuntimes(); len(runtimes) > 0 { |
|
513 |
- if _, ok := runtimes[stockRuntimeName]; ok { |
|
514 |
- return fmt.Errorf("runtime name '%s' is reserved", stockRuntimeName) |
|
515 |
- } |
|
516 |
- } |
|
517 |
- |
|
518 |
- if defaultRuntime := config.GetDefaultRuntimeName(); defaultRuntime != "" && defaultRuntime != stockRuntimeName { |
|
519 |
- runtimes := config.GetAllRuntimes() |
|
520 |
- if _, ok := runtimes[defaultRuntime]; !ok { |
|
521 |
- return fmt.Errorf("specified default runtime '%s' does not exist", defaultRuntime) |
|
522 |
- } |
|
523 |
- } |
|
524 |
- |
|
525 |
- return nil |
|
526 |
-} |
|
527 |
- |
|
528 |
-// GetAuthorizationPlugins returns daemon's sorted authorization plugins |
|
529 |
-func (config *Config) GetAuthorizationPlugins() []string { |
|
530 |
- config.reloadLock.Lock() |
|
531 |
- defer config.reloadLock.Unlock() |
|
532 |
- |
|
533 |
- authPlugins := make([]string, 0, len(config.AuthorizationPlugins)) |
|
534 |
- for _, p := range config.AuthorizationPlugins { |
|
535 |
- authPlugins = append(authPlugins, p) |
|
536 |
- } |
|
537 |
- sort.Strings(authPlugins) |
|
538 |
- return authPlugins |
|
539 |
-} |
540 | 1 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,516 @@ |
0 |
+package config |
|
1 |
+ |
|
2 |
+import ( |
|
3 |
+ "bytes" |
|
4 |
+ "encoding/json" |
|
5 |
+ "errors" |
|
6 |
+ "fmt" |
|
7 |
+ "io" |
|
8 |
+ "io/ioutil" |
|
9 |
+ "reflect" |
|
10 |
+ "runtime" |
|
11 |
+ "sort" |
|
12 |
+ "strings" |
|
13 |
+ "sync" |
|
14 |
+ |
|
15 |
+ "github.com/Sirupsen/logrus" |
|
16 |
+ daemondiscovery "github.com/docker/docker/daemon/discovery" |
|
17 |
+ "github.com/docker/docker/opts" |
|
18 |
+ "github.com/docker/docker/pkg/discovery" |
|
19 |
+ "github.com/docker/docker/registry" |
|
20 |
+ "github.com/imdario/mergo" |
|
21 |
+ "github.com/spf13/pflag" |
|
22 |
+) |
|
23 |
+ |
|
24 |
+const ( |
|
25 |
+ // DefaultMaxConcurrentDownloads is the default value for |
|
26 |
+ // maximum number of downloads that |
|
27 |
+ // may take place at a time for each pull. |
|
28 |
+ DefaultMaxConcurrentDownloads = 3 |
|
29 |
+ // DefaultMaxConcurrentUploads is the default value for |
|
30 |
+ // maximum number of uploads that |
|
31 |
+ // may take place at a time for each push. |
|
32 |
+ DefaultMaxConcurrentUploads = 5 |
|
33 |
+ // StockRuntimeName is the reserved name/alias used to represent the |
|
34 |
+ // OCI runtime being shipped with the docker daemon package. |
|
35 |
+ StockRuntimeName = "runc" |
|
36 |
+ // DefaultShmSize is the default value for container's shm size |
|
37 |
+ DefaultShmSize = int64(67108864) |
|
38 |
+ // DefaultNetworkMtu is the default value for network MTU |
|
39 |
+ DefaultNetworkMtu = 1500 |
|
40 |
+ // DisableNetworkBridge is the default value of the option to disable network bridge |
|
41 |
+ DisableNetworkBridge = "none" |
|
42 |
+) |
|
43 |
+ |
|
44 |
+// flatOptions contains configuration keys |
|
45 |
+// that MUST NOT be parsed as deep structures. |
|
46 |
+// Use this to differentiate these options |
|
47 |
+// with others like the ones in CommonTLSOptions. |
|
48 |
+var flatOptions = map[string]bool{ |
|
49 |
+ "cluster-store-opts": true, |
|
50 |
+ "log-opts": true, |
|
51 |
+ "runtimes": true, |
|
52 |
+ "default-ulimits": true, |
|
53 |
+} |
|
54 |
+ |
|
55 |
+// LogConfig represents the default log configuration. |
|
56 |
+// It includes json tags to deserialize configuration from a file |
|
57 |
+// using the same names that the flags in the command line use. |
|
58 |
+type LogConfig struct { |
|
59 |
+ Type string `json:"log-driver,omitempty"` |
|
60 |
+ Config map[string]string `json:"log-opts,omitempty"` |
|
61 |
+} |
|
62 |
+ |
|
63 |
+// commonBridgeConfig stores all the platform-common bridge driver specific |
|
64 |
+// configuration. |
|
65 |
+type commonBridgeConfig struct { |
|
66 |
+ Iface string `json:"bridge,omitempty"` |
|
67 |
+ FixedCIDR string `json:"fixed-cidr,omitempty"` |
|
68 |
+} |
|
69 |
+ |
|
70 |
+// CommonTLSOptions defines TLS configuration for the daemon server. |
|
71 |
+// It includes json tags to deserialize configuration from a file |
|
72 |
+// using the same names that the flags in the command line use. |
|
73 |
+type CommonTLSOptions struct { |
|
74 |
+ CAFile string `json:"tlscacert,omitempty"` |
|
75 |
+ CertFile string `json:"tlscert,omitempty"` |
|
76 |
+ KeyFile string `json:"tlskey,omitempty"` |
|
77 |
+} |
|
78 |
+ |
|
79 |
+// CommonConfig defines the configuration of a docker daemon which is |
|
80 |
+// common across platforms. |
|
81 |
+// It includes json tags to deserialize configuration from a file |
|
82 |
+// using the same names that the flags in the command line use. |
|
83 |
+type CommonConfig struct { |
|
84 |
+ AuthorizationPlugins []string `json:"authorization-plugins,omitempty"` // AuthorizationPlugins holds list of authorization plugins |
|
85 |
+ AutoRestart bool `json:"-"` |
|
86 |
+ Context map[string][]string `json:"-"` |
|
87 |
+ DisableBridge bool `json:"-"` |
|
88 |
+ DNS []string `json:"dns,omitempty"` |
|
89 |
+ DNSOptions []string `json:"dns-opts,omitempty"` |
|
90 |
+ DNSSearch []string `json:"dns-search,omitempty"` |
|
91 |
+ ExecOptions []string `json:"exec-opts,omitempty"` |
|
92 |
+ GraphDriver string `json:"storage-driver,omitempty"` |
|
93 |
+ GraphOptions []string `json:"storage-opts,omitempty"` |
|
94 |
+ Labels []string `json:"labels,omitempty"` |
|
95 |
+ Mtu int `json:"mtu,omitempty"` |
|
96 |
+ Pidfile string `json:"pidfile,omitempty"` |
|
97 |
+ RawLogs bool `json:"raw-logs,omitempty"` |
|
98 |
+ Root string `json:"graph,omitempty"` |
|
99 |
+ SocketGroup string `json:"group,omitempty"` |
|
100 |
+ TrustKeyPath string `json:"-"` |
|
101 |
+ CorsHeaders string `json:"api-cors-header,omitempty"` |
|
102 |
+ EnableCors bool `json:"api-enable-cors,omitempty"` |
|
103 |
+ |
|
104 |
+ // LiveRestoreEnabled determines whether we should keep containers |
|
105 |
+ // alive upon daemon shutdown/start |
|
106 |
+ LiveRestoreEnabled bool `json:"live-restore,omitempty"` |
|
107 |
+ |
|
108 |
+ // ClusterStore is the storage backend used for the cluster information. It is used by both |
|
109 |
+ // multihost networking (to store networks and endpoints information) and by the node discovery |
|
110 |
+ // mechanism. |
|
111 |
+ ClusterStore string `json:"cluster-store,omitempty"` |
|
112 |
+ |
|
113 |
+ // ClusterOpts is used to pass options to the discovery package for tuning libkv settings, such |
|
114 |
+ // as TLS configuration settings. |
|
115 |
+ ClusterOpts map[string]string `json:"cluster-store-opts,omitempty"` |
|
116 |
+ |
|
117 |
+ // ClusterAdvertise is the network endpoint that the Engine advertises for the purpose of node |
|
118 |
+ // discovery. This should be a 'host:port' combination on which that daemon instance is |
|
119 |
+ // reachable by other hosts. |
|
120 |
+ ClusterAdvertise string `json:"cluster-advertise,omitempty"` |
|
121 |
+ |
|
122 |
+ // MaxConcurrentDownloads is the maximum number of downloads that |
|
123 |
+ // may take place at a time for each pull. |
|
124 |
+ MaxConcurrentDownloads *int `json:"max-concurrent-downloads,omitempty"` |
|
125 |
+ |
|
126 |
+ // MaxConcurrentUploads is the maximum number of uploads that |
|
127 |
+ // may take place at a time for each push. |
|
128 |
+ MaxConcurrentUploads *int `json:"max-concurrent-uploads,omitempty"` |
|
129 |
+ |
|
130 |
+ // ShutdownTimeout is the timeout value (in seconds) the daemon will wait for the container |
|
131 |
+ // to stop when daemon is being shutdown |
|
132 |
+ ShutdownTimeout int `json:"shutdown-timeout,omitempty"` |
|
133 |
+ |
|
134 |
+ Debug bool `json:"debug,omitempty"` |
|
135 |
+ Hosts []string `json:"hosts,omitempty"` |
|
136 |
+ LogLevel string `json:"log-level,omitempty"` |
|
137 |
+ TLS bool `json:"tls,omitempty"` |
|
138 |
+ TLSVerify bool `json:"tlsverify,omitempty"` |
|
139 |
+ |
|
140 |
+ // Embedded structs that allow config |
|
141 |
+ // deserialization without the full struct. |
|
142 |
+ CommonTLSOptions |
|
143 |
+ |
|
144 |
+ // SwarmDefaultAdvertiseAddr is the default host/IP or network interface |
|
145 |
+ // to use if a wildcard address is specified in the ListenAddr value |
|
146 |
+ // given to the /swarm/init endpoint and no advertise address is |
|
147 |
+ // specified. |
|
148 |
+ SwarmDefaultAdvertiseAddr string `json:"swarm-default-advertise-addr"` |
|
149 |
+ MetricsAddress string `json:"metrics-addr"` |
|
150 |
+ |
|
151 |
+ LogConfig |
|
152 |
+ BridgeConfig // bridgeConfig holds bridge network specific configuration. |
|
153 |
+ registry.ServiceOptions |
|
154 |
+ |
|
155 |
+ sync.Mutex |
|
156 |
+ // FIXME(vdemeester) This part is not that clear and is mainly dependent on cli flags |
|
157 |
+ // It should probably be handled outside this package. |
|
158 |
+ ValuesSet map[string]interface{} |
|
159 |
+ |
|
160 |
+ Experimental bool `json:"experimental"` // Experimental indicates whether experimental features should be exposed or not |
|
161 |
+} |
|
162 |
+ |
|
163 |
+// IsValueSet returns true if a configuration value |
|
164 |
+// was explicitly set in the configuration file. |
|
165 |
+func (conf *Config) IsValueSet(name string) bool { |
|
166 |
+ if conf.ValuesSet == nil { |
|
167 |
+ return false |
|
168 |
+ } |
|
169 |
+ _, ok := conf.ValuesSet[name] |
|
170 |
+ return ok |
|
171 |
+} |
|
172 |
+ |
|
173 |
+// New returns a new fully initialized Config struct |
|
174 |
+func New() *Config { |
|
175 |
+ config := Config{} |
|
176 |
+ config.LogConfig.Config = make(map[string]string) |
|
177 |
+ config.ClusterOpts = make(map[string]string) |
|
178 |
+ |
|
179 |
+ if runtime.GOOS != "linux" { |
|
180 |
+ config.V2Only = true |
|
181 |
+ } |
|
182 |
+ return &config |
|
183 |
+} |
|
184 |
+ |
|
185 |
+// ParseClusterAdvertiseSettings parses the specified advertise settings |
|
186 |
+func ParseClusterAdvertiseSettings(clusterStore, clusterAdvertise string) (string, error) { |
|
187 |
+ if runtime.GOOS == "solaris" && (clusterAdvertise != "" || clusterStore != "") { |
|
188 |
+ return "", errors.New("Cluster Advertise Settings not supported on Solaris") |
|
189 |
+ } |
|
190 |
+ if clusterAdvertise == "" { |
|
191 |
+ return "", daemondiscovery.ErrDiscoveryDisabled |
|
192 |
+ } |
|
193 |
+ if clusterStore == "" { |
|
194 |
+ return "", errors.New("invalid cluster configuration. --cluster-advertise must be accompanied by --cluster-store configuration") |
|
195 |
+ } |
|
196 |
+ |
|
197 |
+ advertise, err := discovery.ParseAdvertise(clusterAdvertise) |
|
198 |
+ if err != nil { |
|
199 |
+ return "", fmt.Errorf("discovery advertise parsing failed (%v)", err) |
|
200 |
+ } |
|
201 |
+ return advertise, nil |
|
202 |
+} |
|
203 |
+ |
|
204 |
+// GetConflictFreeLabels validates Labels for conflict |
|
205 |
+// In swarm the duplicates for labels are removed |
|
206 |
+// so we only take same values here, no conflict values |
|
207 |
+// If the key-value is the same we will only take the last label |
|
208 |
+func GetConflictFreeLabels(labels []string) ([]string, error) { |
|
209 |
+ labelMap := map[string]string{} |
|
210 |
+ for _, label := range labels { |
|
211 |
+ stringSlice := strings.SplitN(label, "=", 2) |
|
212 |
+ if len(stringSlice) > 1 { |
|
213 |
+ // If there is a conflict we will return an error |
|
214 |
+ if v, ok := labelMap[stringSlice[0]]; ok && v != stringSlice[1] { |
|
215 |
+ return nil, fmt.Errorf("conflict labels for %s=%s and %s=%s", stringSlice[0], stringSlice[1], stringSlice[0], v) |
|
216 |
+ } |
|
217 |
+ labelMap[stringSlice[0]] = stringSlice[1] |
|
218 |
+ } |
|
219 |
+ } |
|
220 |
+ |
|
221 |
+ newLabels := []string{} |
|
222 |
+ for k, v := range labelMap { |
|
223 |
+ newLabels = append(newLabels, fmt.Sprintf("%s=%s", k, v)) |
|
224 |
+ } |
|
225 |
+ return newLabels, nil |
|
226 |
+} |
|
227 |
+ |
|
228 |
+// Reload reads the configuration in the host and reloads the daemon and server. |
|
229 |
+func Reload(configFile string, flags *pflag.FlagSet, reload func(*Config)) error { |
|
230 |
+ logrus.Infof("Got signal to reload configuration, reloading from: %s", configFile) |
|
231 |
+ newConfig, err := getConflictFreeConfiguration(configFile, flags) |
|
232 |
+ if err != nil { |
|
233 |
+ return err |
|
234 |
+ } |
|
235 |
+ |
|
236 |
+ if err := Validate(newConfig); err != nil { |
|
237 |
+ return fmt.Errorf("file configuration validation failed (%v)", err) |
|
238 |
+ } |
|
239 |
+ |
|
240 |
+ // Labels of the docker engine used to allow multiple values associated with the same key. |
|
241 |
+ // This is deprecated in 1.13, and, be removed after 3 release cycles. |
|
242 |
+ // The following will check the conflict of labels, and report a warning for deprecation. |
|
243 |
+ // |
|
244 |
+ // TODO: After 3 release cycles (1.16) an error will be returned, and labels will be |
|
245 |
+ // sanitized to consolidate duplicate key-value pairs (config.Labels = newLabels): |
|
246 |
+ // |
|
247 |
+ // newLabels, err := GetConflictFreeLabels(newConfig.Labels) |
|
248 |
+ // if err != nil { |
|
249 |
+ // return err |
|
250 |
+ // } |
|
251 |
+ // newConfig.Labels = newLabels |
|
252 |
+ // |
|
253 |
+ if _, err := GetConflictFreeLabels(newConfig.Labels); err != nil { |
|
254 |
+ logrus.Warnf("Engine labels with duplicate keys and conflicting values have been deprecated: %s", err) |
|
255 |
+ } |
|
256 |
+ |
|
257 |
+ reload(newConfig) |
|
258 |
+ return nil |
|
259 |
+} |
|
260 |
+ |
|
261 |
+// boolValue is an interface that boolean value flags implement |
|
262 |
+// to tell the command line how to make -name equivalent to -name=true. |
|
263 |
+type boolValue interface { |
|
264 |
+ IsBoolFlag() bool |
|
265 |
+} |
|
266 |
+ |
|
267 |
+// MergeDaemonConfigurations reads a configuration file, |
|
268 |
+// loads the file configuration in an isolated structure, |
|
269 |
+// and merges the configuration provided from flags on top |
|
270 |
+// if there are no conflicts. |
|
271 |
+func MergeDaemonConfigurations(flagsConfig *Config, flags *pflag.FlagSet, configFile string) (*Config, error) { |
|
272 |
+ fileConfig, err := getConflictFreeConfiguration(configFile, flags) |
|
273 |
+ if err != nil { |
|
274 |
+ return nil, err |
|
275 |
+ } |
|
276 |
+ |
|
277 |
+ if err := Validate(fileConfig); err != nil { |
|
278 |
+ return nil, fmt.Errorf("file configuration validation failed (%v)", err) |
|
279 |
+ } |
|
280 |
+ |
|
281 |
+ // merge flags configuration on top of the file configuration |
|
282 |
+ if err := mergo.Merge(fileConfig, flagsConfig); err != nil { |
|
283 |
+ return nil, err |
|
284 |
+ } |
|
285 |
+ |
|
286 |
+ // We need to validate again once both fileConfig and flagsConfig |
|
287 |
+ // have been merged |
|
288 |
+ if err := Validate(fileConfig); err != nil { |
|
289 |
+ return nil, fmt.Errorf("file configuration validation failed (%v)", err) |
|
290 |
+ } |
|
291 |
+ |
|
292 |
+ return fileConfig, nil |
|
293 |
+} |
|
294 |
+ |
|
295 |
+// getConflictFreeConfiguration loads the configuration from a JSON file. |
|
296 |
+// It compares that configuration with the one provided by the flags, |
|
297 |
+// and returns an error if there are conflicts. |
|
298 |
+func getConflictFreeConfiguration(configFile string, flags *pflag.FlagSet) (*Config, error) { |
|
299 |
+ b, err := ioutil.ReadFile(configFile) |
|
300 |
+ if err != nil { |
|
301 |
+ return nil, err |
|
302 |
+ } |
|
303 |
+ |
|
304 |
+ var config Config |
|
305 |
+ var reader io.Reader |
|
306 |
+ if flags != nil { |
|
307 |
+ var jsonConfig map[string]interface{} |
|
308 |
+ reader = bytes.NewReader(b) |
|
309 |
+ if err := json.NewDecoder(reader).Decode(&jsonConfig); err != nil { |
|
310 |
+ return nil, err |
|
311 |
+ } |
|
312 |
+ |
|
313 |
+ configSet := configValuesSet(jsonConfig) |
|
314 |
+ |
|
315 |
+ if err := findConfigurationConflicts(configSet, flags); err != nil { |
|
316 |
+ return nil, err |
|
317 |
+ } |
|
318 |
+ |
|
319 |
+ // Override flag values to make sure the values set in the config file with nullable values, like `false`, |
|
320 |
+ // are not overridden by default truthy values from the flags that were not explicitly set. |
|
321 |
+ // See https://github.com/docker/docker/issues/20289 for an example. |
|
322 |
+ // |
|
323 |
+ // TODO: Rewrite configuration logic to avoid same issue with other nullable values, like numbers. |
|
324 |
+ namedOptions := make(map[string]interface{}) |
|
325 |
+ for key, value := range configSet { |
|
326 |
+ f := flags.Lookup(key) |
|
327 |
+ if f == nil { // ignore named flags that don't match |
|
328 |
+ namedOptions[key] = value |
|
329 |
+ continue |
|
330 |
+ } |
|
331 |
+ |
|
332 |
+ if _, ok := f.Value.(boolValue); ok { |
|
333 |
+ f.Value.Set(fmt.Sprintf("%v", value)) |
|
334 |
+ } |
|
335 |
+ } |
|
336 |
+ if len(namedOptions) > 0 { |
|
337 |
+ // set also default for mergeVal flags that are boolValue at the same time. |
|
338 |
+ flags.VisitAll(func(f *pflag.Flag) { |
|
339 |
+ if opt, named := f.Value.(opts.NamedOption); named { |
|
340 |
+ v, set := namedOptions[opt.Name()] |
|
341 |
+ _, boolean := f.Value.(boolValue) |
|
342 |
+ if set && boolean { |
|
343 |
+ f.Value.Set(fmt.Sprintf("%v", v)) |
|
344 |
+ } |
|
345 |
+ } |
|
346 |
+ }) |
|
347 |
+ } |
|
348 |
+ |
|
349 |
+ config.ValuesSet = configSet |
|
350 |
+ } |
|
351 |
+ |
|
352 |
+ reader = bytes.NewReader(b) |
|
353 |
+ err = json.NewDecoder(reader).Decode(&config) |
|
354 |
+ return &config, err |
|
355 |
+} |
|
356 |
+ |
|
357 |
+// configValuesSet returns the configuration values explicitly set in the file. |
|
358 |
+func configValuesSet(config map[string]interface{}) map[string]interface{} { |
|
359 |
+ flatten := make(map[string]interface{}) |
|
360 |
+ for k, v := range config { |
|
361 |
+ if m, isMap := v.(map[string]interface{}); isMap && !flatOptions[k] { |
|
362 |
+ for km, vm := range m { |
|
363 |
+ flatten[km] = vm |
|
364 |
+ } |
|
365 |
+ continue |
|
366 |
+ } |
|
367 |
+ |
|
368 |
+ flatten[k] = v |
|
369 |
+ } |
|
370 |
+ return flatten |
|
371 |
+} |
|
372 |
+ |
|
373 |
+// findConfigurationConflicts iterates over the provided flags searching for |
|
374 |
+// duplicated configurations and unknown keys. It returns an error with all the conflicts if |
|
375 |
+// it finds any. |
|
376 |
+func findConfigurationConflicts(config map[string]interface{}, flags *pflag.FlagSet) error { |
|
377 |
+ // 1. Search keys from the file that we don't recognize as flags. |
|
378 |
+ unknownKeys := make(map[string]interface{}) |
|
379 |
+ for key, value := range config { |
|
380 |
+ if flag := flags.Lookup(key); flag == nil { |
|
381 |
+ unknownKeys[key] = value |
|
382 |
+ } |
|
383 |
+ } |
|
384 |
+ |
|
385 |
+ // 2. Discard values that implement NamedOption. |
|
386 |
+ // Their configuration name differs from their flag name, like `labels` and `label`. |
|
387 |
+ if len(unknownKeys) > 0 { |
|
388 |
+ unknownNamedConflicts := func(f *pflag.Flag) { |
|
389 |
+ if namedOption, ok := f.Value.(opts.NamedOption); ok { |
|
390 |
+ if _, valid := unknownKeys[namedOption.Name()]; valid { |
|
391 |
+ delete(unknownKeys, namedOption.Name()) |
|
392 |
+ } |
|
393 |
+ } |
|
394 |
+ } |
|
395 |
+ flags.VisitAll(unknownNamedConflicts) |
|
396 |
+ } |
|
397 |
+ |
|
398 |
+ if len(unknownKeys) > 0 { |
|
399 |
+ var unknown []string |
|
400 |
+ for key := range unknownKeys { |
|
401 |
+ unknown = append(unknown, key) |
|
402 |
+ } |
|
403 |
+ return fmt.Errorf("the following directives don't match any configuration option: %s", strings.Join(unknown, ", ")) |
|
404 |
+ } |
|
405 |
+ |
|
406 |
+ var conflicts []string |
|
407 |
+ printConflict := func(name string, flagValue, fileValue interface{}) string { |
|
408 |
+ return fmt.Sprintf("%s: (from flag: %v, from file: %v)", name, flagValue, fileValue) |
|
409 |
+ } |
|
410 |
+ |
|
411 |
+ // 3. Search keys that are present as a flag and as a file option. |
|
412 |
+ duplicatedConflicts := func(f *pflag.Flag) { |
|
413 |
+ // search option name in the json configuration payload if the value is a named option |
|
414 |
+ if namedOption, ok := f.Value.(opts.NamedOption); ok { |
|
415 |
+ if optsValue, ok := config[namedOption.Name()]; ok { |
|
416 |
+ conflicts = append(conflicts, printConflict(namedOption.Name(), f.Value.String(), optsValue)) |
|
417 |
+ } |
|
418 |
+ } else { |
|
419 |
+ // search flag name in the json configuration payload |
|
420 |
+ for _, name := range []string{f.Name, f.Shorthand} { |
|
421 |
+ if value, ok := config[name]; ok { |
|
422 |
+ conflicts = append(conflicts, printConflict(name, f.Value.String(), value)) |
|
423 |
+ break |
|
424 |
+ } |
|
425 |
+ } |
|
426 |
+ } |
|
427 |
+ } |
|
428 |
+ |
|
429 |
+ flags.Visit(duplicatedConflicts) |
|
430 |
+ |
|
431 |
+ if len(conflicts) > 0 { |
|
432 |
+ return fmt.Errorf("the following directives are specified both as a flag and in the configuration file: %s", strings.Join(conflicts, ", ")) |
|
433 |
+ } |
|
434 |
+ return nil |
|
435 |
+} |
|
436 |
+ |
|
437 |
+// Validate validates some specific configs. |
|
438 |
+// such as config.DNS, config.Labels, config.DNSSearch, |
|
439 |
+// as well as config.MaxConcurrentDownloads, config.MaxConcurrentUploads. |
|
440 |
+func Validate(config *Config) error { |
|
441 |
+ // validate DNS |
|
442 |
+ for _, dns := range config.DNS { |
|
443 |
+ if _, err := opts.ValidateIPAddress(dns); err != nil { |
|
444 |
+ return err |
|
445 |
+ } |
|
446 |
+ } |
|
447 |
+ |
|
448 |
+ // validate DNSSearch |
|
449 |
+ for _, dnsSearch := range config.DNSSearch { |
|
450 |
+ if _, err := opts.ValidateDNSSearch(dnsSearch); err != nil { |
|
451 |
+ return err |
|
452 |
+ } |
|
453 |
+ } |
|
454 |
+ |
|
455 |
+ // validate Labels |
|
456 |
+ for _, label := range config.Labels { |
|
457 |
+ if _, err := opts.ValidateLabel(label); err != nil { |
|
458 |
+ return err |
|
459 |
+ } |
|
460 |
+ } |
|
461 |
+ |
|
462 |
+ // validate MaxConcurrentDownloads |
|
463 |
+ if config.IsValueSet("max-concurrent-downloads") && config.MaxConcurrentDownloads != nil && *config.MaxConcurrentDownloads < 0 { |
|
464 |
+ return fmt.Errorf("invalid max concurrent downloads: %d", *config.MaxConcurrentDownloads) |
|
465 |
+ } |
|
466 |
+ |
|
467 |
+ // validate MaxConcurrentUploads |
|
468 |
+ if config.IsValueSet("max-concurrent-uploads") && config.MaxConcurrentUploads != nil && *config.MaxConcurrentUploads < 0 { |
|
469 |
+ return fmt.Errorf("invalid max concurrent uploads: %d", *config.MaxConcurrentUploads) |
|
470 |
+ } |
|
471 |
+ |
|
472 |
+ // validate that "default" runtime is not reset |
|
473 |
+ if runtimes := config.GetAllRuntimes(); len(runtimes) > 0 { |
|
474 |
+ if _, ok := runtimes[StockRuntimeName]; ok { |
|
475 |
+ return fmt.Errorf("runtime name '%s' is reserved", StockRuntimeName) |
|
476 |
+ } |
|
477 |
+ } |
|
478 |
+ |
|
479 |
+ if defaultRuntime := config.GetDefaultRuntimeName(); defaultRuntime != "" && defaultRuntime != StockRuntimeName { |
|
480 |
+ runtimes := config.GetAllRuntimes() |
|
481 |
+ if _, ok := runtimes[defaultRuntime]; !ok { |
|
482 |
+ return fmt.Errorf("specified default runtime '%s' does not exist", defaultRuntime) |
|
483 |
+ } |
|
484 |
+ } |
|
485 |
+ |
|
486 |
+ return nil |
|
487 |
+} |
|
488 |
+ |
|
489 |
+// GetAuthorizationPlugins returns daemon's sorted authorization plugins |
|
490 |
+func (conf *Config) GetAuthorizationPlugins() []string { |
|
491 |
+ conf.Lock() |
|
492 |
+ defer conf.Unlock() |
|
493 |
+ |
|
494 |
+ authPlugins := make([]string, 0, len(conf.AuthorizationPlugins)) |
|
495 |
+ for _, p := range conf.AuthorizationPlugins { |
|
496 |
+ authPlugins = append(authPlugins, p) |
|
497 |
+ } |
|
498 |
+ sort.Strings(authPlugins) |
|
499 |
+ return authPlugins |
|
500 |
+} |
|
501 |
+ |
|
502 |
+// ModifiedDiscoverySettings returns whether the discovery configuration has been modified or not. |
|
503 |
+func ModifiedDiscoverySettings(config *Config, backendType, advertise string, clusterOpts map[string]string) bool { |
|
504 |
+ if config.ClusterStore != backendType || config.ClusterAdvertise != advertise { |
|
505 |
+ return true |
|
506 |
+ } |
|
507 |
+ |
|
508 |
+ if (config.ClusterOpts == nil && clusterOpts == nil) || |
|
509 |
+ (config.ClusterOpts == nil && len(clusterOpts) == 0) || |
|
510 |
+ (len(config.ClusterOpts) == 0 && clusterOpts == nil) { |
|
511 |
+ return false |
|
512 |
+ } |
|
513 |
+ |
|
514 |
+ return !reflect.DeepEqual(config.ClusterOpts, clusterOpts) |
|
515 |
+} |
0 | 516 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,70 @@ |
0 |
+// +build solaris linux freebsd |
|
1 |
+ |
|
2 |
+package config |
|
3 |
+ |
|
4 |
+import ( |
|
5 |
+ "net" |
|
6 |
+ |
|
7 |
+ "github.com/docker/docker/api/types" |
|
8 |
+) |
|
9 |
+ |
|
10 |
+// CommonUnixConfig defines configuration of a docker daemon that is |
|
11 |
+// common across Unix platforms. |
|
12 |
+type CommonUnixConfig struct { |
|
13 |
+ ExecRoot string `json:"exec-root,omitempty"` |
|
14 |
+ ContainerdAddr string `json:"containerd,omitempty"` |
|
15 |
+ Runtimes map[string]types.Runtime `json:"runtimes,omitempty"` |
|
16 |
+ DefaultRuntime string `json:"default-runtime,omitempty"` |
|
17 |
+ DefaultInitBinary string `json:"default-init,omitempty"` |
|
18 |
+} |
|
19 |
+ |
|
20 |
+type commonUnixBridgeConfig struct { |
|
21 |
+ DefaultIP net.IP `json:"ip,omitempty"` |
|
22 |
+ IP string `json:"bip,omitempty"` |
|
23 |
+ DefaultGatewayIPv4 net.IP `json:"default-gateway,omitempty"` |
|
24 |
+ DefaultGatewayIPv6 net.IP `json:"default-gateway-v6,omitempty"` |
|
25 |
+ InterContainerCommunication bool `json:"icc,omitempty"` |
|
26 |
+} |
|
27 |
+ |
|
28 |
+// GetRuntime returns the runtime path and arguments for a given |
|
29 |
+// runtime name |
|
30 |
+func (conf *Config) GetRuntime(name string) *types.Runtime { |
|
31 |
+ conf.Lock() |
|
32 |
+ defer conf.Unlock() |
|
33 |
+ if rt, ok := conf.Runtimes[name]; ok { |
|
34 |
+ return &rt |
|
35 |
+ } |
|
36 |
+ return nil |
|
37 |
+} |
|
38 |
+ |
|
39 |
+// GetDefaultRuntimeName returns the current default runtime |
|
40 |
+func (conf *Config) GetDefaultRuntimeName() string { |
|
41 |
+ conf.Lock() |
|
42 |
+ rt := conf.DefaultRuntime |
|
43 |
+ conf.Unlock() |
|
44 |
+ |
|
45 |
+ return rt |
|
46 |
+} |
|
47 |
+ |
|
48 |
+// GetAllRuntimes returns a copy of the runtimes map |
|
49 |
+func (conf *Config) GetAllRuntimes() map[string]types.Runtime { |
|
50 |
+ conf.Lock() |
|
51 |
+ rts := conf.Runtimes |
|
52 |
+ conf.Unlock() |
|
53 |
+ return rts |
|
54 |
+} |
|
55 |
+ |
|
56 |
+// GetExecRoot returns the user configured Exec-root |
|
57 |
+func (conf *Config) GetExecRoot() string { |
|
58 |
+ return conf.ExecRoot |
|
59 |
+} |
|
60 |
+ |
|
61 |
+// GetInitPath returns the configure docker-init path |
|
62 |
+func (conf *Config) GetInitPath() string { |
|
63 |
+ conf.Lock() |
|
64 |
+ defer conf.Unlock() |
|
65 |
+ if conf.InitPath != "" { |
|
66 |
+ return conf.InitPath |
|
67 |
+ } |
|
68 |
+ return conf.DefaultInitBinary |
|
69 |
+} |
0 | 70 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,43 @@ |
0 |
+// +build !windows |
|
1 |
+ |
|
2 |
+package config |
|
3 |
+ |
|
4 |
+import ( |
|
5 |
+ "testing" |
|
6 |
+ |
|
7 |
+ "github.com/docker/docker/api/types" |
|
8 |
+) |
|
9 |
+ |
|
10 |
+func TestCommonUnixValidateConfigurationErrors(t *testing.T) { |
|
11 |
+ testCases := []struct { |
|
12 |
+ config *Config |
|
13 |
+ }{ |
|
14 |
+ // Can't override the stock runtime |
|
15 |
+ { |
|
16 |
+ config: &Config{ |
|
17 |
+ CommonUnixConfig: CommonUnixConfig{ |
|
18 |
+ Runtimes: map[string]types.Runtime{ |
|
19 |
+ StockRuntimeName: {}, |
|
20 |
+ }, |
|
21 |
+ }, |
|
22 |
+ }, |
|
23 |
+ }, |
|
24 |
+ // Default runtime should be present in runtimes |
|
25 |
+ { |
|
26 |
+ config: &Config{ |
|
27 |
+ CommonUnixConfig: CommonUnixConfig{ |
|
28 |
+ Runtimes: map[string]types.Runtime{ |
|
29 |
+ "foo": {}, |
|
30 |
+ }, |
|
31 |
+ DefaultRuntime: "bar", |
|
32 |
+ }, |
|
33 |
+ }, |
|
34 |
+ }, |
|
35 |
+ } |
|
36 |
+ for _, tc := range testCases { |
|
37 |
+ err := Validate(tc.config) |
|
38 |
+ if err == nil { |
|
39 |
+ t.Fatalf("expected error, got nil for config %v", tc.config) |
|
40 |
+ } |
|
41 |
+ } |
|
42 |
+} |
0 | 43 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,35 @@ |
0 |
+package config |
|
1 |
+ |
|
2 |
+import ( |
|
3 |
+ "github.com/spf13/pflag" |
|
4 |
+) |
|
5 |
+ |
|
6 |
+var ( |
|
7 |
+ defaultPidFile = "/system/volatile/docker/docker.pid" |
|
8 |
+ defaultGraph = "/var/lib/docker" |
|
9 |
+ defaultExec = "zones" |
|
10 |
+) |
|
11 |
+ |
|
12 |
+// Config defines the configuration of a docker daemon. |
|
13 |
+// These are the configuration settings that you pass |
|
14 |
+// to the docker daemon when you launch it with say: `docker -d -e lxc` |
|
15 |
+type Config struct { |
|
16 |
+ CommonConfig |
|
17 |
+ |
|
18 |
+ // These fields are common to all unix platforms. |
|
19 |
+ CommonUnixConfig |
|
20 |
+} |
|
21 |
+ |
|
22 |
+// BridgeConfig stores all the bridge driver specific |
|
23 |
+// configuration. |
|
24 |
+type BridgeConfig struct { |
|
25 |
+ commonBridgeConfig |
|
26 |
+ |
|
27 |
+ // Fields below here are platform specific. |
|
28 |
+ commonUnixBridgeConfig |
|
29 |
+} |
|
30 |
+ |
|
31 |
+// IsSwarmCompatible defines if swarm mode can be enabled in this config |
|
32 |
+func (conf *Config) IsSwarmCompatible() error { |
|
33 |
+ return nil |
|
34 |
+} |
0 | 35 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,335 @@ |
0 |
+package config |
|
1 |
+ |
|
2 |
+import ( |
|
3 |
+ "io/ioutil" |
|
4 |
+ "os" |
|
5 |
+ "runtime" |
|
6 |
+ "strings" |
|
7 |
+ "testing" |
|
8 |
+ |
|
9 |
+ "github.com/docker/docker/daemon/discovery" |
|
10 |
+ "github.com/docker/docker/opts" |
|
11 |
+ "github.com/docker/docker/pkg/testutil/assert" |
|
12 |
+ "github.com/spf13/pflag" |
|
13 |
+) |
|
14 |
+ |
|
15 |
+func TestDaemonConfigurationNotFound(t *testing.T) { |
|
16 |
+ _, err := MergeDaemonConfigurations(&Config{}, nil, "/tmp/foo-bar-baz-docker") |
|
17 |
+ if err == nil || !os.IsNotExist(err) { |
|
18 |
+ t.Fatalf("expected does not exist error, got %v", err) |
|
19 |
+ } |
|
20 |
+} |
|
21 |
+ |
|
22 |
+func TestDaemonBrokenConfiguration(t *testing.T) { |
|
23 |
+ f, err := ioutil.TempFile("", "docker-config-") |
|
24 |
+ if err != nil { |
|
25 |
+ t.Fatal(err) |
|
26 |
+ } |
|
27 |
+ |
|
28 |
+ configFile := f.Name() |
|
29 |
+ f.Write([]byte(`{"Debug": tru`)) |
|
30 |
+ f.Close() |
|
31 |
+ |
|
32 |
+ _, err = MergeDaemonConfigurations(&Config{}, nil, configFile) |
|
33 |
+ if err == nil { |
|
34 |
+ t.Fatalf("expected error, got %v", err) |
|
35 |
+ } |
|
36 |
+} |
|
37 |
+ |
|
38 |
+func TestParseClusterAdvertiseSettings(t *testing.T) { |
|
39 |
+ if runtime.GOOS == "solaris" { |
|
40 |
+ t.Skip("ClusterSettings not supported on Solaris\n") |
|
41 |
+ } |
|
42 |
+ _, err := ParseClusterAdvertiseSettings("something", "") |
|
43 |
+ if err != discovery.ErrDiscoveryDisabled { |
|
44 |
+ t.Fatalf("expected discovery disabled error, got %v\n", err) |
|
45 |
+ } |
|
46 |
+ |
|
47 |
+ _, err = ParseClusterAdvertiseSettings("", "something") |
|
48 |
+ if err == nil { |
|
49 |
+ t.Fatalf("expected discovery store error, got %v\n", err) |
|
50 |
+ } |
|
51 |
+ |
|
52 |
+ _, err = ParseClusterAdvertiseSettings("etcd", "127.0.0.1:8080") |
|
53 |
+ if err != nil { |
|
54 |
+ t.Fatal(err) |
|
55 |
+ } |
|
56 |
+} |
|
57 |
+ |
|
58 |
+func TestFindConfigurationConflicts(t *testing.T) { |
|
59 |
+ config := map[string]interface{}{"authorization-plugins": "foobar"} |
|
60 |
+ flags := pflag.NewFlagSet("test", pflag.ContinueOnError) |
|
61 |
+ |
|
62 |
+ flags.String("authorization-plugins", "", "") |
|
63 |
+ assert.NilError(t, flags.Set("authorization-plugins", "asdf")) |
|
64 |
+ |
|
65 |
+ assert.Error(t, |
|
66 |
+ findConfigurationConflicts(config, flags), |
|
67 |
+ "authorization-plugins: (from flag: asdf, from file: foobar)") |
|
68 |
+} |
|
69 |
+ |
|
70 |
+func TestFindConfigurationConflictsWithNamedOptions(t *testing.T) { |
|
71 |
+ config := map[string]interface{}{"hosts": []string{"qwer"}} |
|
72 |
+ flags := pflag.NewFlagSet("test", pflag.ContinueOnError) |
|
73 |
+ |
|
74 |
+ var hosts []string |
|
75 |
+ flags.VarP(opts.NewNamedListOptsRef("hosts", &hosts, opts.ValidateHost), "host", "H", "Daemon socket(s) to connect to") |
|
76 |
+ assert.NilError(t, flags.Set("host", "tcp://127.0.0.1:4444")) |
|
77 |
+ assert.NilError(t, flags.Set("host", "unix:///var/run/docker.sock")) |
|
78 |
+ |
|
79 |
+ assert.Error(t, findConfigurationConflicts(config, flags), "hosts") |
|
80 |
+} |
|
81 |
+ |
|
82 |
+func TestDaemonConfigurationMergeConflicts(t *testing.T) { |
|
83 |
+ f, err := ioutil.TempFile("", "docker-config-") |
|
84 |
+ if err != nil { |
|
85 |
+ t.Fatal(err) |
|
86 |
+ } |
|
87 |
+ |
|
88 |
+ configFile := f.Name() |
|
89 |
+ f.Write([]byte(`{"debug": true}`)) |
|
90 |
+ f.Close() |
|
91 |
+ |
|
92 |
+ flags := pflag.NewFlagSet("test", pflag.ContinueOnError) |
|
93 |
+ flags.Bool("debug", false, "") |
|
94 |
+ flags.Set("debug", "false") |
|
95 |
+ |
|
96 |
+ _, err = MergeDaemonConfigurations(&Config{}, flags, configFile) |
|
97 |
+ if err == nil { |
|
98 |
+ t.Fatal("expected error, got nil") |
|
99 |
+ } |
|
100 |
+ if !strings.Contains(err.Error(), "debug") { |
|
101 |
+ t.Fatalf("expected debug conflict, got %v", err) |
|
102 |
+ } |
|
103 |
+} |
|
104 |
+ |
|
105 |
+func TestDaemonConfigurationMergeConflictsWithInnerStructs(t *testing.T) { |
|
106 |
+ f, err := ioutil.TempFile("", "docker-config-") |
|
107 |
+ if err != nil { |
|
108 |
+ t.Fatal(err) |
|
109 |
+ } |
|
110 |
+ |
|
111 |
+ configFile := f.Name() |
|
112 |
+ f.Write([]byte(`{"tlscacert": "/etc/certificates/ca.pem"}`)) |
|
113 |
+ f.Close() |
|
114 |
+ |
|
115 |
+ flags := pflag.NewFlagSet("test", pflag.ContinueOnError) |
|
116 |
+ flags.String("tlscacert", "", "") |
|
117 |
+ flags.Set("tlscacert", "~/.docker/ca.pem") |
|
118 |
+ |
|
119 |
+ _, err = MergeDaemonConfigurations(&Config{}, flags, configFile) |
|
120 |
+ if err == nil { |
|
121 |
+ t.Fatal("expected error, got nil") |
|
122 |
+ } |
|
123 |
+ if !strings.Contains(err.Error(), "tlscacert") { |
|
124 |
+ t.Fatalf("expected tlscacert conflict, got %v", err) |
|
125 |
+ } |
|
126 |
+} |
|
127 |
+ |
|
128 |
+func TestFindConfigurationConflictsWithUnknownKeys(t *testing.T) { |
|
129 |
+ config := map[string]interface{}{"tls-verify": "true"} |
|
130 |
+ flags := pflag.NewFlagSet("test", pflag.ContinueOnError) |
|
131 |
+ |
|
132 |
+ flags.Bool("tlsverify", false, "") |
|
133 |
+ err := findConfigurationConflicts(config, flags) |
|
134 |
+ if err == nil { |
|
135 |
+ t.Fatal("expected error, got nil") |
|
136 |
+ } |
|
137 |
+ if !strings.Contains(err.Error(), "the following directives don't match any configuration option: tls-verify") { |
|
138 |
+ t.Fatalf("expected tls-verify conflict, got %v", err) |
|
139 |
+ } |
|
140 |
+} |
|
141 |
+ |
|
142 |
+func TestFindConfigurationConflictsWithMergedValues(t *testing.T) { |
|
143 |
+ var hosts []string |
|
144 |
+ config := map[string]interface{}{"hosts": "tcp://127.0.0.1:2345"} |
|
145 |
+ flags := pflag.NewFlagSet("base", pflag.ContinueOnError) |
|
146 |
+ flags.VarP(opts.NewNamedListOptsRef("hosts", &hosts, nil), "host", "H", "") |
|
147 |
+ |
|
148 |
+ err := findConfigurationConflicts(config, flags) |
|
149 |
+ if err != nil { |
|
150 |
+ t.Fatal(err) |
|
151 |
+ } |
|
152 |
+ |
|
153 |
+ flags.Set("host", "unix:///var/run/docker.sock") |
|
154 |
+ err = findConfigurationConflicts(config, flags) |
|
155 |
+ if err == nil { |
|
156 |
+ t.Fatal("expected error, got nil") |
|
157 |
+ } |
|
158 |
+ if !strings.Contains(err.Error(), "hosts: (from flag: [unix:///var/run/docker.sock], from file: tcp://127.0.0.1:2345)") { |
|
159 |
+ t.Fatalf("expected hosts conflict, got %v", err) |
|
160 |
+ } |
|
161 |
+} |
|
162 |
+ |
|
163 |
+func TestValidateConfigurationErrors(t *testing.T) { |
|
164 |
+ minusNumber := -10 |
|
165 |
+ testCases := []struct { |
|
166 |
+ config *Config |
|
167 |
+ }{ |
|
168 |
+ { |
|
169 |
+ config: &Config{ |
|
170 |
+ CommonConfig: CommonConfig{ |
|
171 |
+ Labels: []string{"one"}, |
|
172 |
+ }, |
|
173 |
+ }, |
|
174 |
+ }, |
|
175 |
+ { |
|
176 |
+ config: &Config{ |
|
177 |
+ CommonConfig: CommonConfig{ |
|
178 |
+ Labels: []string{"foo=bar", "one"}, |
|
179 |
+ }, |
|
180 |
+ }, |
|
181 |
+ }, |
|
182 |
+ { |
|
183 |
+ config: &Config{ |
|
184 |
+ CommonConfig: CommonConfig{ |
|
185 |
+ DNS: []string{"1.1.1.1o"}, |
|
186 |
+ }, |
|
187 |
+ }, |
|
188 |
+ }, |
|
189 |
+ { |
|
190 |
+ config: &Config{ |
|
191 |
+ CommonConfig: CommonConfig{ |
|
192 |
+ DNS: []string{"2.2.2.2", "1.1.1.1o"}, |
|
193 |
+ }, |
|
194 |
+ }, |
|
195 |
+ }, |
|
196 |
+ { |
|
197 |
+ config: &Config{ |
|
198 |
+ CommonConfig: CommonConfig{ |
|
199 |
+ DNSSearch: []string{"123456"}, |
|
200 |
+ }, |
|
201 |
+ }, |
|
202 |
+ }, |
|
203 |
+ { |
|
204 |
+ config: &Config{ |
|
205 |
+ CommonConfig: CommonConfig{ |
|
206 |
+ DNSSearch: []string{"a.b.c", "123456"}, |
|
207 |
+ }, |
|
208 |
+ }, |
|
209 |
+ }, |
|
210 |
+ { |
|
211 |
+ config: &Config{ |
|
212 |
+ CommonConfig: CommonConfig{ |
|
213 |
+ MaxConcurrentDownloads: &minusNumber, |
|
214 |
+ // This is weird... |
|
215 |
+ ValuesSet: map[string]interface{}{ |
|
216 |
+ "max-concurrent-downloads": -1, |
|
217 |
+ }, |
|
218 |
+ }, |
|
219 |
+ }, |
|
220 |
+ }, |
|
221 |
+ { |
|
222 |
+ config: &Config{ |
|
223 |
+ CommonConfig: CommonConfig{ |
|
224 |
+ MaxConcurrentUploads: &minusNumber, |
|
225 |
+ // This is weird... |
|
226 |
+ ValuesSet: map[string]interface{}{ |
|
227 |
+ "max-concurrent-uploads": -1, |
|
228 |
+ }, |
|
229 |
+ }, |
|
230 |
+ }, |
|
231 |
+ }, |
|
232 |
+ } |
|
233 |
+ for _, tc := range testCases { |
|
234 |
+ err := Validate(tc.config) |
|
235 |
+ if err == nil { |
|
236 |
+ t.Fatalf("expected error, got nil for config %v", tc.config) |
|
237 |
+ } |
|
238 |
+ } |
|
239 |
+} |
|
240 |
+ |
|
241 |
+func TestValidateConfiguration(t *testing.T) { |
|
242 |
+ testCases := []struct { |
|
243 |
+ config *Config |
|
244 |
+ }{ |
|
245 |
+ { |
|
246 |
+ config: &Config{ |
|
247 |
+ CommonConfig: CommonConfig{ |
|
248 |
+ Labels: []string{"one=two"}, |
|
249 |
+ }, |
|
250 |
+ }, |
|
251 |
+ }, |
|
252 |
+ { |
|
253 |
+ config: &Config{ |
|
254 |
+ CommonConfig: CommonConfig{ |
|
255 |
+ DNS: []string{"1.1.1.1"}, |
|
256 |
+ }, |
|
257 |
+ }, |
|
258 |
+ }, |
|
259 |
+ { |
|
260 |
+ config: &Config{ |
|
261 |
+ CommonConfig: CommonConfig{ |
|
262 |
+ DNSSearch: []string{"a.b.c"}, |
|
263 |
+ }, |
|
264 |
+ }, |
|
265 |
+ }, |
|
266 |
+ } |
|
267 |
+ for _, tc := range testCases { |
|
268 |
+ err := Validate(tc.config) |
|
269 |
+ if err != nil { |
|
270 |
+ t.Fatalf("expected no error, got error %v", err) |
|
271 |
+ } |
|
272 |
+ } |
|
273 |
+} |
|
274 |
+ |
|
275 |
+func TestModifiedDiscoverySettings(t *testing.T) { |
|
276 |
+ cases := []struct { |
|
277 |
+ current *Config |
|
278 |
+ modified *Config |
|
279 |
+ expected bool |
|
280 |
+ }{ |
|
281 |
+ { |
|
282 |
+ current: discoveryConfig("foo", "bar", map[string]string{}), |
|
283 |
+ modified: discoveryConfig("foo", "bar", map[string]string{}), |
|
284 |
+ expected: false, |
|
285 |
+ }, |
|
286 |
+ { |
|
287 |
+ current: discoveryConfig("foo", "bar", map[string]string{"foo": "bar"}), |
|
288 |
+ modified: discoveryConfig("foo", "bar", map[string]string{"foo": "bar"}), |
|
289 |
+ expected: false, |
|
290 |
+ }, |
|
291 |
+ { |
|
292 |
+ current: discoveryConfig("foo", "bar", map[string]string{}), |
|
293 |
+ modified: discoveryConfig("foo", "bar", nil), |
|
294 |
+ expected: false, |
|
295 |
+ }, |
|
296 |
+ { |
|
297 |
+ current: discoveryConfig("foo", "bar", nil), |
|
298 |
+ modified: discoveryConfig("foo", "bar", map[string]string{}), |
|
299 |
+ expected: false, |
|
300 |
+ }, |
|
301 |
+ { |
|
302 |
+ current: discoveryConfig("foo", "bar", nil), |
|
303 |
+ modified: discoveryConfig("baz", "bar", nil), |
|
304 |
+ expected: true, |
|
305 |
+ }, |
|
306 |
+ { |
|
307 |
+ current: discoveryConfig("foo", "bar", nil), |
|
308 |
+ modified: discoveryConfig("foo", "baz", nil), |
|
309 |
+ expected: true, |
|
310 |
+ }, |
|
311 |
+ { |
|
312 |
+ current: discoveryConfig("foo", "bar", nil), |
|
313 |
+ modified: discoveryConfig("foo", "bar", map[string]string{"foo": "bar"}), |
|
314 |
+ expected: true, |
|
315 |
+ }, |
|
316 |
+ } |
|
317 |
+ |
|
318 |
+ for _, c := range cases { |
|
319 |
+ got := ModifiedDiscoverySettings(c.current, c.modified.ClusterStore, c.modified.ClusterAdvertise, c.modified.ClusterOpts) |
|
320 |
+ if c.expected != got { |
|
321 |
+ t.Fatalf("expected %v, got %v: current config %v, new config %v", c.expected, got, c.current, c.modified) |
|
322 |
+ } |
|
323 |
+ } |
|
324 |
+} |
|
325 |
+ |
|
326 |
+func discoveryConfig(backendAddr, advertiseAddr string, opts map[string]string) *Config { |
|
327 |
+ return &Config{ |
|
328 |
+ CommonConfig: CommonConfig{ |
|
329 |
+ ClusterStore: backendAddr, |
|
330 |
+ ClusterAdvertise: advertiseAddr, |
|
331 |
+ ClusterOpts: opts, |
|
332 |
+ }, |
|
333 |
+ } |
|
334 |
+} |
0 | 335 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,62 @@ |
0 |
+// +build linux freebsd |
|
1 |
+ |
|
2 |
+package config |
|
3 |
+ |
|
4 |
+import ( |
|
5 |
+ "fmt" |
|
6 |
+ |
|
7 |
+ "github.com/docker/docker/opts" |
|
8 |
+ units "github.com/docker/go-units" |
|
9 |
+) |
|
10 |
+ |
|
11 |
+// Config defines the configuration of a docker daemon. |
|
12 |
+// It includes json tags to deserialize configuration from a file |
|
13 |
+// using the same names that the flags in the command line uses. |
|
14 |
+type Config struct { |
|
15 |
+ CommonConfig |
|
16 |
+ |
|
17 |
+ // These fields are common to all unix platforms. |
|
18 |
+ CommonUnixConfig |
|
19 |
+ |
|
20 |
+ // Fields below here are platform specific. |
|
21 |
+ CgroupParent string `json:"cgroup-parent,omitempty"` |
|
22 |
+ EnableSelinuxSupport bool `json:"selinux-enabled,omitempty"` |
|
23 |
+ RemappedRoot string `json:"userns-remap,omitempty"` |
|
24 |
+ Ulimits map[string]*units.Ulimit `json:"default-ulimits,omitempty"` |
|
25 |
+ CPURealtimePeriod int64 `json:"cpu-rt-period,omitempty"` |
|
26 |
+ CPURealtimeRuntime int64 `json:"cpu-rt-runtime,omitempty"` |
|
27 |
+ OOMScoreAdjust int `json:"oom-score-adjust,omitempty"` |
|
28 |
+ Init bool `json:"init,omitempty"` |
|
29 |
+ InitPath string `json:"init-path,omitempty"` |
|
30 |
+ SeccompProfile string `json:"seccomp-profile,omitempty"` |
|
31 |
+ ShmSize opts.MemBytes `json:"default-shm-size,omitempty"` |
|
32 |
+} |
|
33 |
+ |
|
34 |
+// BridgeConfig stores all the bridge driver specific |
|
35 |
+// configuration. |
|
36 |
+type BridgeConfig struct { |
|
37 |
+ commonBridgeConfig |
|
38 |
+ |
|
39 |
+ // These fields are common to all unix platforms. |
|
40 |
+ commonUnixBridgeConfig |
|
41 |
+ |
|
42 |
+ // Fields below here are platform specific. |
|
43 |
+ EnableIPv6 bool `json:"ipv6,omitempty"` |
|
44 |
+ EnableIPTables bool `json:"iptables,omitempty"` |
|
45 |
+ EnableIPForward bool `json:"ip-forward,omitempty"` |
|
46 |
+ EnableIPMasq bool `json:"ip-masq,omitempty"` |
|
47 |
+ EnableUserlandProxy bool `json:"userland-proxy,omitempty"` |
|
48 |
+ UserlandProxyPath string `json:"userland-proxy-path,omitempty"` |
|
49 |
+ FixedCIDRv6 string `json:"fixed-cidr-v6,omitempty"` |
|
50 |
+} |
|
51 |
+ |
|
52 |
+// IsSwarmCompatible defines if swarm mode can be enabled in this config |
|
53 |
+func (conf *Config) IsSwarmCompatible() error { |
|
54 |
+ if conf.ClusterStore != "" || conf.ClusterAdvertise != "" { |
|
55 |
+ return fmt.Errorf("--cluster-store and --cluster-advertise daemon configurations are incompatible with swarm mode") |
|
56 |
+ } |
|
57 |
+ if conf.LiveRestoreEnabled { |
|
58 |
+ return fmt.Errorf("--live-restore daemon configuration is incompatible with swarm mode") |
|
59 |
+ } |
|
60 |
+ return nil |
|
61 |
+} |
0 | 62 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,111 @@ |
0 |
+// +build !windows |
|
1 |
+ |
|
2 |
+package config |
|
3 |
+ |
|
4 |
+import ( |
|
5 |
+ "io/ioutil" |
|
6 |
+ "runtime" |
|
7 |
+ |
|
8 |
+ "testing" |
|
9 |
+) |
|
10 |
+ |
|
11 |
+func TestDaemonConfigurationMerge(t *testing.T) { |
|
12 |
+ f, err := ioutil.TempFile("", "docker-config-") |
|
13 |
+ if err != nil { |
|
14 |
+ t.Fatal(err) |
|
15 |
+ } |
|
16 |
+ |
|
17 |
+ configFile := f.Name() |
|
18 |
+ |
|
19 |
+ f.Write([]byte(` |
|
20 |
+ { |
|
21 |
+ "debug": true, |
|
22 |
+ "default-ulimits": { |
|
23 |
+ "nofile": { |
|
24 |
+ "Name": "nofile", |
|
25 |
+ "Hard": 2048, |
|
26 |
+ "Soft": 1024 |
|
27 |
+ } |
|
28 |
+ }, |
|
29 |
+ "log-opts": { |
|
30 |
+ "tag": "test_tag" |
|
31 |
+ } |
|
32 |
+ }`)) |
|
33 |
+ |
|
34 |
+ f.Close() |
|
35 |
+ |
|
36 |
+ c := &Config{ |
|
37 |
+ CommonConfig: CommonConfig{ |
|
38 |
+ AutoRestart: true, |
|
39 |
+ LogConfig: LogConfig{ |
|
40 |
+ Type: "syslog", |
|
41 |
+ Config: map[string]string{"tag": "test"}, |
|
42 |
+ }, |
|
43 |
+ }, |
|
44 |
+ } |
|
45 |
+ |
|
46 |
+ cc, err := MergeDaemonConfigurations(c, nil, configFile) |
|
47 |
+ if err != nil { |
|
48 |
+ t.Fatal(err) |
|
49 |
+ } |
|
50 |
+ if !cc.Debug { |
|
51 |
+ t.Fatalf("expected %v, got %v\n", true, cc.Debug) |
|
52 |
+ } |
|
53 |
+ if !cc.AutoRestart { |
|
54 |
+ t.Fatalf("expected %v, got %v\n", true, cc.AutoRestart) |
|
55 |
+ } |
|
56 |
+ if cc.LogConfig.Type != "syslog" { |
|
57 |
+ t.Fatalf("expected syslog config, got %q\n", cc.LogConfig) |
|
58 |
+ } |
|
59 |
+ |
|
60 |
+ if configValue, OK := cc.LogConfig.Config["tag"]; !OK { |
|
61 |
+ t.Fatal("expected syslog config attributes, got nil\n") |
|
62 |
+ } else { |
|
63 |
+ if configValue != "test_tag" { |
|
64 |
+ t.Fatalf("expected syslog config attributes 'tag=test_tag', got 'tag=%s'\n", configValue) |
|
65 |
+ } |
|
66 |
+ } |
|
67 |
+ |
|
68 |
+ if cc.Ulimits == nil { |
|
69 |
+ t.Fatal("expected default ulimit config, got nil\n") |
|
70 |
+ } else { |
|
71 |
+ if _, OK := cc.Ulimits["nofile"]; OK { |
|
72 |
+ if cc.Ulimits["nofile"].Name != "nofile" || |
|
73 |
+ cc.Ulimits["nofile"].Hard != 2048 || |
|
74 |
+ cc.Ulimits["nofile"].Soft != 1024 { |
|
75 |
+ t.Fatalf("expected default ulimit name, hard and soft are nofile, 2048, 1024, got %s, %d, %d\n", cc.Ulimits["nofile"].Name, cc.Ulimits["nofile"].Hard, cc.Ulimits["nofile"].Soft) |
|
76 |
+ } |
|
77 |
+ } else { |
|
78 |
+ t.Fatal("expected default ulimit name nofile, got nil\n") |
|
79 |
+ } |
|
80 |
+ } |
|
81 |
+} |
|
82 |
+ |
|
83 |
+func TestDaemonConfigurationMergeShmSize(t *testing.T) { |
|
84 |
+ if runtime.GOOS == "solaris" { |
|
85 |
+ t.Skip("ShmSize not supported on Solaris\n") |
|
86 |
+ } |
|
87 |
+ f, err := ioutil.TempFile("", "docker-config-") |
|
88 |
+ if err != nil { |
|
89 |
+ t.Fatal(err) |
|
90 |
+ } |
|
91 |
+ |
|
92 |
+ configFile := f.Name() |
|
93 |
+ |
|
94 |
+ f.Write([]byte(` |
|
95 |
+ { |
|
96 |
+ "default-shm-size": "1g" |
|
97 |
+ }`)) |
|
98 |
+ |
|
99 |
+ f.Close() |
|
100 |
+ |
|
101 |
+ c := &Config{} |
|
102 |
+ cc, err := MergeDaemonConfigurations(c, nil, configFile) |
|
103 |
+ if err != nil { |
|
104 |
+ t.Fatal(err) |
|
105 |
+ } |
|
106 |
+ expectedValue := 1 * 1024 * 1024 * 1024 |
|
107 |
+ if cc.ShmSize.Value() != int64(expectedValue) { |
|
108 |
+ t.Fatalf("expected default shm size %d, got %d", expectedValue, cc.ShmSize.Value()) |
|
109 |
+ } |
|
110 |
+} |
0 | 111 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,52 @@ |
0 |
+package config |
|
1 |
+ |
|
2 |
+import ( |
|
3 |
+ "github.com/docker/docker/api/types" |
|
4 |
+) |
|
5 |
+ |
|
6 |
+// BridgeConfig stores all the bridge driver specific |
|
7 |
+// configuration. |
|
8 |
+type BridgeConfig struct { |
|
9 |
+ commonBridgeConfig |
|
10 |
+} |
|
11 |
+ |
|
12 |
+// Config defines the configuration of a docker daemon. |
|
13 |
+// These are the configuration settings that you pass |
|
14 |
+// to the docker daemon when you launch it with say: `dockerd -e windows` |
|
15 |
+type Config struct { |
|
16 |
+ CommonConfig |
|
17 |
+ |
|
18 |
+ // Fields below here are platform specific. (There are none presently |
|
19 |
+ // for the Windows daemon.) |
|
20 |
+} |
|
21 |
+ |
|
22 |
+// GetRuntime returns the runtime path and arguments for a given |
|
23 |
+// runtime name |
|
24 |
+func (conf *Config) GetRuntime(name string) *types.Runtime { |
|
25 |
+ return nil |
|
26 |
+} |
|
27 |
+ |
|
28 |
+// GetInitPath returns the configure docker-init path |
|
29 |
+func (conf *Config) GetInitPath() string { |
|
30 |
+ return "" |
|
31 |
+} |
|
32 |
+ |
|
33 |
+// GetDefaultRuntimeName returns the current default runtime |
|
34 |
+func (conf *Config) GetDefaultRuntimeName() string { |
|
35 |
+ return StockRuntimeName |
|
36 |
+} |
|
37 |
+ |
|
38 |
+// GetAllRuntimes returns a copy of the runtimes map |
|
39 |
+func (conf *Config) GetAllRuntimes() map[string]types.Runtime { |
|
40 |
+ return map[string]types.Runtime{} |
|
41 |
+} |
|
42 |
+ |
|
43 |
+// GetExecRoot returns the user configured Exec-root |
|
44 |
+func (conf *Config) GetExecRoot() string { |
|
45 |
+ return "" |
|
46 |
+} |
|
47 |
+ |
|
48 |
+// IsSwarmCompatible defines if swarm mode can be enabled in this config |
|
49 |
+func (conf *Config) IsSwarmCompatible() error { |
|
50 |
+ return nil |
|
51 |
+} |
0 | 52 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,59 @@ |
0 |
+// +build windows |
|
1 |
+ |
|
2 |
+package config |
|
3 |
+ |
|
4 |
+import ( |
|
5 |
+ "io/ioutil" |
|
6 |
+ "testing" |
|
7 |
+) |
|
8 |
+ |
|
9 |
+func TestDaemonConfigurationMerge(t *testing.T) { |
|
10 |
+ f, err := ioutil.TempFile("", "docker-config-") |
|
11 |
+ if err != nil { |
|
12 |
+ t.Fatal(err) |
|
13 |
+ } |
|
14 |
+ |
|
15 |
+ configFile := f.Name() |
|
16 |
+ |
|
17 |
+ f.Write([]byte(` |
|
18 |
+ { |
|
19 |
+ "debug": true, |
|
20 |
+ "log-opts": { |
|
21 |
+ "tag": "test_tag" |
|
22 |
+ } |
|
23 |
+ }`)) |
|
24 |
+ |
|
25 |
+ f.Close() |
|
26 |
+ |
|
27 |
+ c := &Config{ |
|
28 |
+ CommonConfig: CommonConfig{ |
|
29 |
+ AutoRestart: true, |
|
30 |
+ LogConfig: LogConfig{ |
|
31 |
+ Type: "syslog", |
|
32 |
+ Config: map[string]string{"tag": "test"}, |
|
33 |
+ }, |
|
34 |
+ }, |
|
35 |
+ } |
|
36 |
+ |
|
37 |
+ cc, err := MergeDaemonConfigurations(c, nil, configFile) |
|
38 |
+ if err != nil { |
|
39 |
+ t.Fatal(err) |
|
40 |
+ } |
|
41 |
+ if !cc.Debug { |
|
42 |
+ t.Fatalf("expected %v, got %v\n", true, cc.Debug) |
|
43 |
+ } |
|
44 |
+ if !cc.AutoRestart { |
|
45 |
+ t.Fatalf("expected %v, got %v\n", true, cc.AutoRestart) |
|
46 |
+ } |
|
47 |
+ if cc.LogConfig.Type != "syslog" { |
|
48 |
+ t.Fatalf("expected syslog config, got %q\n", cc.LogConfig) |
|
49 |
+ } |
|
50 |
+ |
|
51 |
+ if configValue, OK := cc.LogConfig.Config["tag"]; !OK { |
|
52 |
+ t.Fatal("expected syslog config attributes, got nil\n") |
|
53 |
+ } else { |
|
54 |
+ if configValue != "test_tag" { |
|
55 |
+ t.Fatalf("expected syslog config attributes 'tag=test_tag', got 'tag=%s'\n", configValue) |
|
56 |
+ } |
|
57 |
+ } |
|
58 |
+} |
0 | 59 |
deleted file mode 100644 |
... | ... |
@@ -1,89 +0,0 @@ |
1 |
-// +build solaris linux freebsd |
|
2 |
- |
|
3 |
-package daemon |
|
4 |
- |
|
5 |
-import ( |
|
6 |
- "net" |
|
7 |
- |
|
8 |
- "github.com/docker/docker/api/types" |
|
9 |
- "github.com/docker/docker/opts" |
|
10 |
- "github.com/spf13/pflag" |
|
11 |
-) |
|
12 |
- |
|
13 |
-// CommonUnixConfig defines configuration of a docker daemon that is |
|
14 |
-// common across Unix platforms. |
|
15 |
-type CommonUnixConfig struct { |
|
16 |
- ExecRoot string `json:"exec-root,omitempty"` |
|
17 |
- ContainerdAddr string `json:"containerd,omitempty"` |
|
18 |
- Runtimes map[string]types.Runtime `json:"runtimes,omitempty"` |
|
19 |
- DefaultRuntime string `json:"default-runtime,omitempty"` |
|
20 |
-} |
|
21 |
- |
|
22 |
-type commonUnixBridgeConfig struct { |
|
23 |
- DefaultIP net.IP `json:"ip,omitempty"` |
|
24 |
- IP string `json:"bip,omitempty"` |
|
25 |
- DefaultGatewayIPv4 net.IP `json:"default-gateway,omitempty"` |
|
26 |
- DefaultGatewayIPv6 net.IP `json:"default-gateway-v6,omitempty"` |
|
27 |
- InterContainerCommunication bool `json:"icc,omitempty"` |
|
28 |
-} |
|
29 |
- |
|
30 |
-// InstallCommonUnixFlags adds command-line options to the top-level flag parser for |
|
31 |
-// the current process that are common across Unix platforms. |
|
32 |
-func (config *Config) InstallCommonUnixFlags(flags *pflag.FlagSet) { |
|
33 |
- config.Runtimes = make(map[string]types.Runtime) |
|
34 |
- |
|
35 |
- flags.StringVarP(&config.SocketGroup, "group", "G", "docker", "Group for the unix socket") |
|
36 |
- flags.StringVar(&config.bridgeConfig.IP, "bip", "", "Specify network bridge IP") |
|
37 |
- flags.StringVarP(&config.bridgeConfig.Iface, "bridge", "b", "", "Attach containers to a network bridge") |
|
38 |
- flags.StringVar(&config.bridgeConfig.FixedCIDR, "fixed-cidr", "", "IPv4 subnet for fixed IPs") |
|
39 |
- flags.Var(opts.NewIPOpt(&config.bridgeConfig.DefaultGatewayIPv4, ""), "default-gateway", "Container default gateway IPv4 address") |
|
40 |
- flags.Var(opts.NewIPOpt(&config.bridgeConfig.DefaultGatewayIPv6, ""), "default-gateway-v6", "Container default gateway IPv6 address") |
|
41 |
- flags.BoolVar(&config.bridgeConfig.InterContainerCommunication, "icc", true, "Enable inter-container communication") |
|
42 |
- flags.Var(opts.NewIPOpt(&config.bridgeConfig.DefaultIP, "0.0.0.0"), "ip", "Default IP when binding container ports") |
|
43 |
- flags.Var(opts.NewNamedRuntimeOpt("runtimes", &config.Runtimes, stockRuntimeName), "add-runtime", "Register an additional OCI compatible runtime") |
|
44 |
- flags.StringVar(&config.DefaultRuntime, "default-runtime", stockRuntimeName, "Default OCI runtime for containers") |
|
45 |
- |
|
46 |
-} |
|
47 |
- |
|
48 |
-// GetRuntime returns the runtime path and arguments for a given |
|
49 |
-// runtime name |
|
50 |
-func (config *Config) GetRuntime(name string) *types.Runtime { |
|
51 |
- config.reloadLock.Lock() |
|
52 |
- defer config.reloadLock.Unlock() |
|
53 |
- if rt, ok := config.Runtimes[name]; ok { |
|
54 |
- return &rt |
|
55 |
- } |
|
56 |
- return nil |
|
57 |
-} |
|
58 |
- |
|
59 |
-// GetDefaultRuntimeName returns the current default runtime |
|
60 |
-func (config *Config) GetDefaultRuntimeName() string { |
|
61 |
- config.reloadLock.Lock() |
|
62 |
- rt := config.DefaultRuntime |
|
63 |
- config.reloadLock.Unlock() |
|
64 |
- |
|
65 |
- return rt |
|
66 |
-} |
|
67 |
- |
|
68 |
-// GetAllRuntimes returns a copy of the runtimes map |
|
69 |
-func (config *Config) GetAllRuntimes() map[string]types.Runtime { |
|
70 |
- config.reloadLock.Lock() |
|
71 |
- rts := config.Runtimes |
|
72 |
- config.reloadLock.Unlock() |
|
73 |
- return rts |
|
74 |
-} |
|
75 |
- |
|
76 |
-// GetExecRoot returns the user configured Exec-root |
|
77 |
-func (config *Config) GetExecRoot() string { |
|
78 |
- return config.ExecRoot |
|
79 |
-} |
|
80 |
- |
|
81 |
-// GetInitPath returns the configure docker-init path |
|
82 |
-func (config *Config) GetInitPath() string { |
|
83 |
- config.reloadLock.Lock() |
|
84 |
- defer config.reloadLock.Unlock() |
|
85 |
- if config.InitPath != "" { |
|
86 |
- return config.InitPath |
|
87 |
- } |
|
88 |
- return DefaultInitBinary |
|
89 |
-} |
9 | 1 |
deleted file mode 100644 |
... | ... |
@@ -1,47 +0,0 @@ |
1 |
-package daemon |
|
2 |
- |
|
3 |
-import ( |
|
4 |
- "github.com/spf13/pflag" |
|
5 |
-) |
|
6 |
- |
|
7 |
-var ( |
|
8 |
- defaultPidFile = "/system/volatile/docker/docker.pid" |
|
9 |
- defaultGraph = "/var/lib/docker" |
|
10 |
- defaultExec = "zones" |
|
11 |
-) |
|
12 |
- |
|
13 |
-// Config defines the configuration of a docker daemon. |
|
14 |
-// These are the configuration settings that you pass |
|
15 |
-// to the docker daemon when you launch it with say: `docker -d -e lxc` |
|
16 |
-type Config struct { |
|
17 |
- CommonConfig |
|
18 |
- |
|
19 |
- // These fields are common to all unix platforms. |
|
20 |
- CommonUnixConfig |
|
21 |
-} |
|
22 |
- |
|
23 |
-// bridgeConfig stores all the bridge driver specific |
|
24 |
-// configuration. |
|
25 |
-type bridgeConfig struct { |
|
26 |
- commonBridgeConfig |
|
27 |
- |
|
28 |
- // Fields below here are platform specific. |
|
29 |
- commonUnixBridgeConfig |
|
30 |
-} |
|
31 |
- |
|
32 |
-// InstallFlags adds command-line options to the top-level flag parser for |
|
33 |
-// the current process. |
|
34 |
-func (config *Config) InstallFlags(flags *pflag.FlagSet) { |
|
35 |
- // First handle install flags which are consistent cross-platform |
|
36 |
- config.InstallCommonFlags(flags) |
|
37 |
- |
|
38 |
- // Then install flags common to unix platforms |
|
39 |
- config.InstallCommonUnixFlags(flags) |
|
40 |
- |
|
41 |
- // Then platform-specific install flags |
|
42 |
- config.attachExperimentalFlags(flags) |
|
43 |
-} |
|
44 |
- |
|
45 |
-func (config *Config) isSwarmCompatible() error { |
|
46 |
- return nil |
|
47 |
-} |
48 | 1 |
deleted file mode 100644 |
... | ... |
@@ -1,229 +0,0 @@ |
1 |
-package daemon |
|
2 |
- |
|
3 |
-import ( |
|
4 |
- "io/ioutil" |
|
5 |
- "os" |
|
6 |
- "runtime" |
|
7 |
- "strings" |
|
8 |
- "testing" |
|
9 |
- |
|
10 |
- "github.com/docker/docker/opts" |
|
11 |
- "github.com/docker/docker/pkg/testutil/assert" |
|
12 |
- "github.com/spf13/pflag" |
|
13 |
-) |
|
14 |
- |
|
15 |
-func TestDaemonConfigurationNotFound(t *testing.T) { |
|
16 |
- _, err := MergeDaemonConfigurations(&Config{}, nil, "/tmp/foo-bar-baz-docker") |
|
17 |
- if err == nil || !os.IsNotExist(err) { |
|
18 |
- t.Fatalf("expected does not exist error, got %v", err) |
|
19 |
- } |
|
20 |
-} |
|
21 |
- |
|
22 |
-func TestDaemonBrokenConfiguration(t *testing.T) { |
|
23 |
- f, err := ioutil.TempFile("", "docker-config-") |
|
24 |
- if err != nil { |
|
25 |
- t.Fatal(err) |
|
26 |
- } |
|
27 |
- |
|
28 |
- configFile := f.Name() |
|
29 |
- f.Write([]byte(`{"Debug": tru`)) |
|
30 |
- f.Close() |
|
31 |
- |
|
32 |
- _, err = MergeDaemonConfigurations(&Config{}, nil, configFile) |
|
33 |
- if err == nil { |
|
34 |
- t.Fatalf("expected error, got %v", err) |
|
35 |
- } |
|
36 |
-} |
|
37 |
- |
|
38 |
-func TestParseClusterAdvertiseSettings(t *testing.T) { |
|
39 |
- if runtime.GOOS == "solaris" { |
|
40 |
- t.Skip("ClusterSettings not supported on Solaris\n") |
|
41 |
- } |
|
42 |
- _, err := parseClusterAdvertiseSettings("something", "") |
|
43 |
- if err != errDiscoveryDisabled { |
|
44 |
- t.Fatalf("expected discovery disabled error, got %v\n", err) |
|
45 |
- } |
|
46 |
- |
|
47 |
- _, err = parseClusterAdvertiseSettings("", "something") |
|
48 |
- if err == nil { |
|
49 |
- t.Fatalf("expected discovery store error, got %v\n", err) |
|
50 |
- } |
|
51 |
- |
|
52 |
- _, err = parseClusterAdvertiseSettings("etcd", "127.0.0.1:8080") |
|
53 |
- if err != nil { |
|
54 |
- t.Fatal(err) |
|
55 |
- } |
|
56 |
-} |
|
57 |
- |
|
58 |
-func TestFindConfigurationConflicts(t *testing.T) { |
|
59 |
- config := map[string]interface{}{"authorization-plugins": "foobar"} |
|
60 |
- flags := pflag.NewFlagSet("test", pflag.ContinueOnError) |
|
61 |
- |
|
62 |
- flags.String("authorization-plugins", "", "") |
|
63 |
- assert.NilError(t, flags.Set("authorization-plugins", "asdf")) |
|
64 |
- |
|
65 |
- assert.Error(t, |
|
66 |
- findConfigurationConflicts(config, flags), |
|
67 |
- "authorization-plugins: (from flag: asdf, from file: foobar)") |
|
68 |
-} |
|
69 |
- |
|
70 |
-func TestFindConfigurationConflictsWithNamedOptions(t *testing.T) { |
|
71 |
- config := map[string]interface{}{"hosts": []string{"qwer"}} |
|
72 |
- flags := pflag.NewFlagSet("test", pflag.ContinueOnError) |
|
73 |
- |
|
74 |
- var hosts []string |
|
75 |
- flags.VarP(opts.NewNamedListOptsRef("hosts", &hosts, opts.ValidateHost), "host", "H", "Daemon socket(s) to connect to") |
|
76 |
- assert.NilError(t, flags.Set("host", "tcp://127.0.0.1:4444")) |
|
77 |
- assert.NilError(t, flags.Set("host", "unix:///var/run/docker.sock")) |
|
78 |
- |
|
79 |
- assert.Error(t, findConfigurationConflicts(config, flags), "hosts") |
|
80 |
-} |
|
81 |
- |
|
82 |
-func TestDaemonConfigurationMergeConflicts(t *testing.T) { |
|
83 |
- f, err := ioutil.TempFile("", "docker-config-") |
|
84 |
- if err != nil { |
|
85 |
- t.Fatal(err) |
|
86 |
- } |
|
87 |
- |
|
88 |
- configFile := f.Name() |
|
89 |
- f.Write([]byte(`{"debug": true}`)) |
|
90 |
- f.Close() |
|
91 |
- |
|
92 |
- flags := pflag.NewFlagSet("test", pflag.ContinueOnError) |
|
93 |
- flags.Bool("debug", false, "") |
|
94 |
- flags.Set("debug", "false") |
|
95 |
- |
|
96 |
- _, err = MergeDaemonConfigurations(&Config{}, flags, configFile) |
|
97 |
- if err == nil { |
|
98 |
- t.Fatal("expected error, got nil") |
|
99 |
- } |
|
100 |
- if !strings.Contains(err.Error(), "debug") { |
|
101 |
- t.Fatalf("expected debug conflict, got %v", err) |
|
102 |
- } |
|
103 |
-} |
|
104 |
- |
|
105 |
-func TestDaemonConfigurationMergeConflictsWithInnerStructs(t *testing.T) { |
|
106 |
- f, err := ioutil.TempFile("", "docker-config-") |
|
107 |
- if err != nil { |
|
108 |
- t.Fatal(err) |
|
109 |
- } |
|
110 |
- |
|
111 |
- configFile := f.Name() |
|
112 |
- f.Write([]byte(`{"tlscacert": "/etc/certificates/ca.pem"}`)) |
|
113 |
- f.Close() |
|
114 |
- |
|
115 |
- flags := pflag.NewFlagSet("test", pflag.ContinueOnError) |
|
116 |
- flags.String("tlscacert", "", "") |
|
117 |
- flags.Set("tlscacert", "~/.docker/ca.pem") |
|
118 |
- |
|
119 |
- _, err = MergeDaemonConfigurations(&Config{}, flags, configFile) |
|
120 |
- if err == nil { |
|
121 |
- t.Fatal("expected error, got nil") |
|
122 |
- } |
|
123 |
- if !strings.Contains(err.Error(), "tlscacert") { |
|
124 |
- t.Fatalf("expected tlscacert conflict, got %v", err) |
|
125 |
- } |
|
126 |
-} |
|
127 |
- |
|
128 |
-func TestFindConfigurationConflictsWithUnknownKeys(t *testing.T) { |
|
129 |
- config := map[string]interface{}{"tls-verify": "true"} |
|
130 |
- flags := pflag.NewFlagSet("test", pflag.ContinueOnError) |
|
131 |
- |
|
132 |
- flags.Bool("tlsverify", false, "") |
|
133 |
- err := findConfigurationConflicts(config, flags) |
|
134 |
- if err == nil { |
|
135 |
- t.Fatal("expected error, got nil") |
|
136 |
- } |
|
137 |
- if !strings.Contains(err.Error(), "the following directives don't match any configuration option: tls-verify") { |
|
138 |
- t.Fatalf("expected tls-verify conflict, got %v", err) |
|
139 |
- } |
|
140 |
-} |
|
141 |
- |
|
142 |
-func TestFindConfigurationConflictsWithMergedValues(t *testing.T) { |
|
143 |
- var hosts []string |
|
144 |
- config := map[string]interface{}{"hosts": "tcp://127.0.0.1:2345"} |
|
145 |
- flags := pflag.NewFlagSet("base", pflag.ContinueOnError) |
|
146 |
- flags.VarP(opts.NewNamedListOptsRef("hosts", &hosts, nil), "host", "H", "") |
|
147 |
- |
|
148 |
- err := findConfigurationConflicts(config, flags) |
|
149 |
- if err != nil { |
|
150 |
- t.Fatal(err) |
|
151 |
- } |
|
152 |
- |
|
153 |
- flags.Set("host", "unix:///var/run/docker.sock") |
|
154 |
- err = findConfigurationConflicts(config, flags) |
|
155 |
- if err == nil { |
|
156 |
- t.Fatal("expected error, got nil") |
|
157 |
- } |
|
158 |
- if !strings.Contains(err.Error(), "hosts: (from flag: [unix:///var/run/docker.sock], from file: tcp://127.0.0.1:2345)") { |
|
159 |
- t.Fatalf("expected hosts conflict, got %v", err) |
|
160 |
- } |
|
161 |
-} |
|
162 |
- |
|
163 |
-func TestValidateConfiguration(t *testing.T) { |
|
164 |
- c1 := &Config{ |
|
165 |
- CommonConfig: CommonConfig{ |
|
166 |
- Labels: []string{"one"}, |
|
167 |
- }, |
|
168 |
- } |
|
169 |
- |
|
170 |
- err := ValidateConfiguration(c1) |
|
171 |
- if err == nil { |
|
172 |
- t.Fatal("expected error, got nil") |
|
173 |
- } |
|
174 |
- |
|
175 |
- c2 := &Config{ |
|
176 |
- CommonConfig: CommonConfig{ |
|
177 |
- Labels: []string{"one=two"}, |
|
178 |
- }, |
|
179 |
- } |
|
180 |
- |
|
181 |
- err = ValidateConfiguration(c2) |
|
182 |
- if err != nil { |
|
183 |
- t.Fatalf("expected no error, got error %v", err) |
|
184 |
- } |
|
185 |
- |
|
186 |
- c3 := &Config{ |
|
187 |
- CommonConfig: CommonConfig{ |
|
188 |
- DNS: []string{"1.1.1.1"}, |
|
189 |
- }, |
|
190 |
- } |
|
191 |
- |
|
192 |
- err = ValidateConfiguration(c3) |
|
193 |
- if err != nil { |
|
194 |
- t.Fatalf("expected no error, got error %v", err) |
|
195 |
- } |
|
196 |
- |
|
197 |
- c4 := &Config{ |
|
198 |
- CommonConfig: CommonConfig{ |
|
199 |
- DNS: []string{"1.1.1.1o"}, |
|
200 |
- }, |
|
201 |
- } |
|
202 |
- |
|
203 |
- err = ValidateConfiguration(c4) |
|
204 |
- if err == nil { |
|
205 |
- t.Fatal("expected error, got nil") |
|
206 |
- } |
|
207 |
- |
|
208 |
- c5 := &Config{ |
|
209 |
- CommonConfig: CommonConfig{ |
|
210 |
- DNSSearch: []string{"a.b.c"}, |
|
211 |
- }, |
|
212 |
- } |
|
213 |
- |
|
214 |
- err = ValidateConfiguration(c5) |
|
215 |
- if err != nil { |
|
216 |
- t.Fatalf("expected no error, got error %v", err) |
|
217 |
- } |
|
218 |
- |
|
219 |
- c6 := &Config{ |
|
220 |
- CommonConfig: CommonConfig{ |
|
221 |
- DNSSearch: []string{"123456"}, |
|
222 |
- }, |
|
223 |
- } |
|
224 |
- |
|
225 |
- err = ValidateConfiguration(c6) |
|
226 |
- if err == nil { |
|
227 |
- t.Fatal("expected error, got nil") |
|
228 |
- } |
|
229 |
-} |
230 | 1 |
deleted file mode 100644 |
... | ... |
@@ -1,110 +0,0 @@ |
1 |
-// +build linux freebsd |
|
2 |
- |
|
3 |
-package daemon |
|
4 |
- |
|
5 |
-import ( |
|
6 |
- "fmt" |
|
7 |
- |
|
8 |
- "github.com/docker/docker/opts" |
|
9 |
- units "github.com/docker/go-units" |
|
10 |
- "github.com/spf13/pflag" |
|
11 |
-) |
|
12 |
- |
|
13 |
-var ( |
|
14 |
- defaultPidFile = "/var/run/docker.pid" |
|
15 |
- defaultGraph = "/var/lib/docker" |
|
16 |
- defaultExecRoot = "/var/run/docker" |
|
17 |
- defaultShmSize = int64(67108864) |
|
18 |
-) |
|
19 |
- |
|
20 |
-// Config defines the configuration of a docker daemon. |
|
21 |
-// It includes json tags to deserialize configuration from a file |
|
22 |
-// using the same names that the flags in the command line uses. |
|
23 |
-type Config struct { |
|
24 |
- CommonConfig |
|
25 |
- |
|
26 |
- // These fields are common to all unix platforms. |
|
27 |
- CommonUnixConfig |
|
28 |
- |
|
29 |
- // Fields below here are platform specific. |
|
30 |
- CgroupParent string `json:"cgroup-parent,omitempty"` |
|
31 |
- EnableSelinuxSupport bool `json:"selinux-enabled,omitempty"` |
|
32 |
- RemappedRoot string `json:"userns-remap,omitempty"` |
|
33 |
- Ulimits map[string]*units.Ulimit `json:"default-ulimits,omitempty"` |
|
34 |
- CPURealtimePeriod int64 `json:"cpu-rt-period,omitempty"` |
|
35 |
- CPURealtimeRuntime int64 `json:"cpu-rt-runtime,omitempty"` |
|
36 |
- OOMScoreAdjust int `json:"oom-score-adjust,omitempty"` |
|
37 |
- Init bool `json:"init,omitempty"` |
|
38 |
- InitPath string `json:"init-path,omitempty"` |
|
39 |
- SeccompProfile string `json:"seccomp-profile,omitempty"` |
|
40 |
- ShmSize opts.MemBytes `json:"default-shm-size,omitempty"` |
|
41 |
-} |
|
42 |
- |
|
43 |
-// bridgeConfig stores all the bridge driver specific |
|
44 |
-// configuration. |
|
45 |
-type bridgeConfig struct { |
|
46 |
- commonBridgeConfig |
|
47 |
- |
|
48 |
- // These fields are common to all unix platforms. |
|
49 |
- commonUnixBridgeConfig |
|
50 |
- |
|
51 |
- // Fields below here are platform specific. |
|
52 |
- EnableIPv6 bool `json:"ipv6,omitempty"` |
|
53 |
- EnableIPTables bool `json:"iptables,omitempty"` |
|
54 |
- EnableIPForward bool `json:"ip-forward,omitempty"` |
|
55 |
- EnableIPMasq bool `json:"ip-masq,omitempty"` |
|
56 |
- EnableUserlandProxy bool `json:"userland-proxy,omitempty"` |
|
57 |
- UserlandProxyPath string `json:"userland-proxy-path,omitempty"` |
|
58 |
- FixedCIDRv6 string `json:"fixed-cidr-v6,omitempty"` |
|
59 |
-} |
|
60 |
- |
|
61 |
-// InstallFlags adds flags to the pflag.FlagSet to configure the daemon |
|
62 |
-func (config *Config) InstallFlags(flags *pflag.FlagSet) { |
|
63 |
- // First handle install flags which are consistent cross-platform |
|
64 |
- config.InstallCommonFlags(flags) |
|
65 |
- |
|
66 |
- // Then install flags common to unix platforms |
|
67 |
- config.InstallCommonUnixFlags(flags) |
|
68 |
- |
|
69 |
- config.Ulimits = make(map[string]*units.Ulimit) |
|
70 |
- |
|
71 |
- // Set default value for `--default-shm-size` |
|
72 |
- config.ShmSize = opts.MemBytes(defaultShmSize) |
|
73 |
- |
|
74 |
- // Then platform-specific install flags |
|
75 |
- flags.BoolVar(&config.EnableSelinuxSupport, "selinux-enabled", false, "Enable selinux support") |
|
76 |
- flags.Var(opts.NewUlimitOpt(&config.Ulimits), "default-ulimit", "Default ulimits for containers") |
|
77 |
- flags.BoolVar(&config.bridgeConfig.EnableIPTables, "iptables", true, "Enable addition of iptables rules") |
|
78 |
- flags.BoolVar(&config.bridgeConfig.EnableIPForward, "ip-forward", true, "Enable net.ipv4.ip_forward") |
|
79 |
- flags.BoolVar(&config.bridgeConfig.EnableIPMasq, "ip-masq", true, "Enable IP masquerading") |
|
80 |
- flags.BoolVar(&config.bridgeConfig.EnableIPv6, "ipv6", false, "Enable IPv6 networking") |
|
81 |
- flags.StringVar(&config.ExecRoot, "exec-root", defaultExecRoot, "Root directory for execution state files") |
|
82 |
- flags.StringVar(&config.bridgeConfig.FixedCIDRv6, "fixed-cidr-v6", "", "IPv6 subnet for fixed IPs") |
|
83 |
- flags.BoolVar(&config.bridgeConfig.EnableUserlandProxy, "userland-proxy", true, "Use userland proxy for loopback traffic") |
|
84 |
- flags.StringVar(&config.bridgeConfig.UserlandProxyPath, "userland-proxy-path", "", "Path to the userland proxy binary") |
|
85 |
- flags.BoolVar(&config.EnableCors, "api-enable-cors", false, "Enable CORS headers in the Engine API, this is deprecated by --api-cors-header") |
|
86 |
- flags.MarkDeprecated("api-enable-cors", "Please use --api-cors-header") |
|
87 |
- flags.StringVar(&config.CgroupParent, "cgroup-parent", "", "Set parent cgroup for all containers") |
|
88 |
- flags.StringVar(&config.RemappedRoot, "userns-remap", "", "User/Group setting for user namespaces") |
|
89 |
- flags.StringVar(&config.ContainerdAddr, "containerd", "", "Path to containerd socket") |
|
90 |
- flags.BoolVar(&config.LiveRestoreEnabled, "live-restore", false, "Enable live restore of docker when containers are still running") |
|
91 |
- flags.IntVar(&config.OOMScoreAdjust, "oom-score-adjust", -500, "Set the oom_score_adj for the daemon") |
|
92 |
- flags.BoolVar(&config.Init, "init", false, "Run an init in the container to forward signals and reap processes") |
|
93 |
- flags.StringVar(&config.InitPath, "init-path", "", "Path to the docker-init binary") |
|
94 |
- flags.Int64Var(&config.CPURealtimePeriod, "cpu-rt-period", 0, "Limit the CPU real-time period in microseconds") |
|
95 |
- flags.Int64Var(&config.CPURealtimeRuntime, "cpu-rt-runtime", 0, "Limit the CPU real-time runtime in microseconds") |
|
96 |
- flags.StringVar(&config.SeccompProfile, "seccomp-profile", "", "Path to seccomp profile") |
|
97 |
- flags.Var(&config.ShmSize, "default-shm-size", "Default shm size for containers") |
|
98 |
- |
|
99 |
- config.attachExperimentalFlags(flags) |
|
100 |
-} |
|
101 |
- |
|
102 |
-func (config *Config) isSwarmCompatible() error { |
|
103 |
- if config.ClusterStore != "" || config.ClusterAdvertise != "" { |
|
104 |
- return fmt.Errorf("--cluster-store and --cluster-advertise daemon configurations are incompatible with swarm mode") |
|
105 |
- } |
|
106 |
- if config.LiveRestoreEnabled { |
|
107 |
- return fmt.Errorf("--live-restore daemon configuration is incompatible with swarm mode") |
|
108 |
- } |
|
109 |
- return nil |
|
110 |
-} |
111 | 1 |
deleted file mode 100644 |
... | ... |
@@ -1,134 +0,0 @@ |
1 |
-// +build !windows |
|
2 |
- |
|
3 |
-package daemon |
|
4 |
- |
|
5 |
-import ( |
|
6 |
- "io/ioutil" |
|
7 |
- "runtime" |
|
8 |
- |
|
9 |
- "testing" |
|
10 |
- |
|
11 |
- "github.com/docker/docker/pkg/testutil/assert" |
|
12 |
- "github.com/spf13/pflag" |
|
13 |
-) |
|
14 |
- |
|
15 |
-func TestDaemonConfigurationMerge(t *testing.T) { |
|
16 |
- f, err := ioutil.TempFile("", "docker-config-") |
|
17 |
- if err != nil { |
|
18 |
- t.Fatal(err) |
|
19 |
- } |
|
20 |
- |
|
21 |
- configFile := f.Name() |
|
22 |
- |
|
23 |
- f.Write([]byte(` |
|
24 |
- { |
|
25 |
- "debug": true, |
|
26 |
- "default-ulimits": { |
|
27 |
- "nofile": { |
|
28 |
- "Name": "nofile", |
|
29 |
- "Hard": 2048, |
|
30 |
- "Soft": 1024 |
|
31 |
- } |
|
32 |
- }, |
|
33 |
- "log-opts": { |
|
34 |
- "tag": "test_tag" |
|
35 |
- } |
|
36 |
- }`)) |
|
37 |
- |
|
38 |
- f.Close() |
|
39 |
- |
|
40 |
- c := &Config{ |
|
41 |
- CommonConfig: CommonConfig{ |
|
42 |
- AutoRestart: true, |
|
43 |
- LogConfig: LogConfig{ |
|
44 |
- Type: "syslog", |
|
45 |
- Config: map[string]string{"tag": "test"}, |
|
46 |
- }, |
|
47 |
- }, |
|
48 |
- } |
|
49 |
- |
|
50 |
- cc, err := MergeDaemonConfigurations(c, nil, configFile) |
|
51 |
- if err != nil { |
|
52 |
- t.Fatal(err) |
|
53 |
- } |
|
54 |
- if !cc.Debug { |
|
55 |
- t.Fatalf("expected %v, got %v\n", true, cc.Debug) |
|
56 |
- } |
|
57 |
- if !cc.AutoRestart { |
|
58 |
- t.Fatalf("expected %v, got %v\n", true, cc.AutoRestart) |
|
59 |
- } |
|
60 |
- if cc.LogConfig.Type != "syslog" { |
|
61 |
- t.Fatalf("expected syslog config, got %q\n", cc.LogConfig) |
|
62 |
- } |
|
63 |
- |
|
64 |
- if configValue, OK := cc.LogConfig.Config["tag"]; !OK { |
|
65 |
- t.Fatal("expected syslog config attributes, got nil\n") |
|
66 |
- } else { |
|
67 |
- if configValue != "test_tag" { |
|
68 |
- t.Fatalf("expected syslog config attributes 'tag=test_tag', got 'tag=%s'\n", configValue) |
|
69 |
- } |
|
70 |
- } |
|
71 |
- |
|
72 |
- if cc.Ulimits == nil { |
|
73 |
- t.Fatal("expected default ulimit config, got nil\n") |
|
74 |
- } else { |
|
75 |
- if _, OK := cc.Ulimits["nofile"]; OK { |
|
76 |
- if cc.Ulimits["nofile"].Name != "nofile" || |
|
77 |
- cc.Ulimits["nofile"].Hard != 2048 || |
|
78 |
- cc.Ulimits["nofile"].Soft != 1024 { |
|
79 |
- t.Fatalf("expected default ulimit name, hard and soft are nofile, 2048, 1024, got %s, %d, %d\n", cc.Ulimits["nofile"].Name, cc.Ulimits["nofile"].Hard, cc.Ulimits["nofile"].Soft) |
|
80 |
- } |
|
81 |
- } else { |
|
82 |
- t.Fatal("expected default ulimit name nofile, got nil\n") |
|
83 |
- } |
|
84 |
- } |
|
85 |
-} |
|
86 |
- |
|
87 |
-func TestDaemonParseShmSize(t *testing.T) { |
|
88 |
- if runtime.GOOS == "solaris" { |
|
89 |
- t.Skip("ShmSize not supported on Solaris\n") |
|
90 |
- } |
|
91 |
- flags := pflag.NewFlagSet("test", pflag.ContinueOnError) |
|
92 |
- |
|
93 |
- config := &Config{} |
|
94 |
- config.InstallFlags(flags) |
|
95 |
- // By default `--default-shm-size=64M` |
|
96 |
- expectedValue := 64 * 1024 * 1024 |
|
97 |
- if config.ShmSize.Value() != int64(expectedValue) { |
|
98 |
- t.Fatalf("expected default shm size %d, got %d", expectedValue, config.ShmSize.Value()) |
|
99 |
- } |
|
100 |
- assert.NilError(t, flags.Set("default-shm-size", "128M")) |
|
101 |
- expectedValue = 128 * 1024 * 1024 |
|
102 |
- if config.ShmSize.Value() != int64(expectedValue) { |
|
103 |
- t.Fatalf("expected default shm size %d, got %d", expectedValue, config.ShmSize.Value()) |
|
104 |
- } |
|
105 |
-} |
|
106 |
- |
|
107 |
-func TestDaemonConfigurationMergeShmSize(t *testing.T) { |
|
108 |
- if runtime.GOOS == "solaris" { |
|
109 |
- t.Skip("ShmSize not supported on Solaris\n") |
|
110 |
- } |
|
111 |
- f, err := ioutil.TempFile("", "docker-config-") |
|
112 |
- if err != nil { |
|
113 |
- t.Fatal(err) |
|
114 |
- } |
|
115 |
- |
|
116 |
- configFile := f.Name() |
|
117 |
- |
|
118 |
- f.Write([]byte(` |
|
119 |
- { |
|
120 |
- "default-shm-size": "1g" |
|
121 |
- }`)) |
|
122 |
- |
|
123 |
- f.Close() |
|
124 |
- |
|
125 |
- c := &Config{} |
|
126 |
- cc, err := MergeDaemonConfigurations(c, nil, configFile) |
|
127 |
- if err != nil { |
|
128 |
- t.Fatal(err) |
|
129 |
- } |
|
130 |
- expectedValue := 1 * 1024 * 1024 * 1024 |
|
131 |
- if cc.ShmSize.Value() != int64(expectedValue) { |
|
132 |
- t.Fatalf("expected default shm size %d, got %d", expectedValue, cc.ShmSize.Value()) |
|
133 |
- } |
|
134 |
-} |
135 | 1 |
deleted file mode 100644 |
... | ... |
@@ -1,71 +0,0 @@ |
1 |
-package daemon |
|
2 |
- |
|
3 |
-import ( |
|
4 |
- "os" |
|
5 |
- "path/filepath" |
|
6 |
- |
|
7 |
- "github.com/docker/docker/api/types" |
|
8 |
- "github.com/spf13/pflag" |
|
9 |
-) |
|
10 |
- |
|
11 |
-var ( |
|
12 |
- defaultPidFile string |
|
13 |
- defaultGraph = filepath.Join(os.Getenv("programdata"), "docker") |
|
14 |
-) |
|
15 |
- |
|
16 |
-// bridgeConfig stores all the bridge driver specific |
|
17 |
-// configuration. |
|
18 |
-type bridgeConfig struct { |
|
19 |
- commonBridgeConfig |
|
20 |
-} |
|
21 |
- |
|
22 |
-// Config defines the configuration of a docker daemon. |
|
23 |
-// These are the configuration settings that you pass |
|
24 |
-// to the docker daemon when you launch it with say: `dockerd -e windows` |
|
25 |
-type Config struct { |
|
26 |
- CommonConfig |
|
27 |
- |
|
28 |
- // Fields below here are platform specific. (There are none presently |
|
29 |
- // for the Windows daemon.) |
|
30 |
-} |
|
31 |
- |
|
32 |
-// InstallFlags adds flags to the pflag.FlagSet to configure the daemon |
|
33 |
-func (config *Config) InstallFlags(flags *pflag.FlagSet) { |
|
34 |
- // First handle install flags which are consistent cross-platform |
|
35 |
- config.InstallCommonFlags(flags) |
|
36 |
- |
|
37 |
- // Then platform-specific install flags. |
|
38 |
- flags.StringVar(&config.bridgeConfig.FixedCIDR, "fixed-cidr", "", "IPv4 subnet for fixed IPs") |
|
39 |
- flags.StringVarP(&config.bridgeConfig.Iface, "bridge", "b", "", "Attach containers to a virtual switch") |
|
40 |
- flags.StringVarP(&config.SocketGroup, "group", "G", "", "Users or groups that can access the named pipe") |
|
41 |
-} |
|
42 |
- |
|
43 |
-// GetRuntime returns the runtime path and arguments for a given |
|
44 |
-// runtime name |
|
45 |
-func (config *Config) GetRuntime(name string) *types.Runtime { |
|
46 |
- return nil |
|
47 |
-} |
|
48 |
- |
|
49 |
-// GetInitPath returns the configure docker-init path |
|
50 |
-func (config *Config) GetInitPath() string { |
|
51 |
- return "" |
|
52 |
-} |
|
53 |
- |
|
54 |
-// GetDefaultRuntimeName returns the current default runtime |
|
55 |
-func (config *Config) GetDefaultRuntimeName() string { |
|
56 |
- return stockRuntimeName |
|
57 |
-} |
|
58 |
- |
|
59 |
-// GetAllRuntimes returns a copy of the runtimes map |
|
60 |
-func (config *Config) GetAllRuntimes() map[string]types.Runtime { |
|
61 |
- return map[string]types.Runtime{} |
|
62 |
-} |
|
63 |
- |
|
64 |
-// GetExecRoot returns the user configured Exec-root |
|
65 |
-func (config *Config) GetExecRoot() string { |
|
66 |
- return "" |
|
67 |
-} |
|
68 |
- |
|
69 |
-func (config *Config) isSwarmCompatible() error { |
|
70 |
- return nil |
|
71 |
-} |
72 | 1 |
deleted file mode 100644 |
... | ... |
@@ -1,59 +0,0 @@ |
1 |
-// +build windows |
|
2 |
- |
|
3 |
-package daemon |
|
4 |
- |
|
5 |
-import ( |
|
6 |
- "io/ioutil" |
|
7 |
- "testing" |
|
8 |
-) |
|
9 |
- |
|
10 |
-func TestDaemonConfigurationMerge(t *testing.T) { |
|
11 |
- f, err := ioutil.TempFile("", "docker-config-") |
|
12 |
- if err != nil { |
|
13 |
- t.Fatal(err) |
|
14 |
- } |
|
15 |
- |
|
16 |
- configFile := f.Name() |
|
17 |
- |
|
18 |
- f.Write([]byte(` |
|
19 |
- { |
|
20 |
- "debug": true, |
|
21 |
- "log-opts": { |
|
22 |
- "tag": "test_tag" |
|
23 |
- } |
|
24 |
- }`)) |
|
25 |
- |
|
26 |
- f.Close() |
|
27 |
- |
|
28 |
- c := &Config{ |
|
29 |
- CommonConfig: CommonConfig{ |
|
30 |
- AutoRestart: true, |
|
31 |
- LogConfig: LogConfig{ |
|
32 |
- Type: "syslog", |
|
33 |
- Config: map[string]string{"tag": "test"}, |
|
34 |
- }, |
|
35 |
- }, |
|
36 |
- } |
|
37 |
- |
|
38 |
- cc, err := MergeDaemonConfigurations(c, nil, configFile) |
|
39 |
- if err != nil { |
|
40 |
- t.Fatal(err) |
|
41 |
- } |
|
42 |
- if !cc.Debug { |
|
43 |
- t.Fatalf("expected %v, got %v\n", true, cc.Debug) |
|
44 |
- } |
|
45 |
- if !cc.AutoRestart { |
|
46 |
- t.Fatalf("expected %v, got %v\n", true, cc.AutoRestart) |
|
47 |
- } |
|
48 |
- if cc.LogConfig.Type != "syslog" { |
|
49 |
- t.Fatalf("expected syslog config, got %q\n", cc.LogConfig) |
|
50 |
- } |
|
51 |
- |
|
52 |
- if configValue, OK := cc.LogConfig.Config["tag"]; !OK { |
|
53 |
- t.Fatal("expected syslog config attributes, got nil\n") |
|
54 |
- } else { |
|
55 |
- if configValue != "test_tag" { |
|
56 |
- t.Fatalf("expected syslog config attributes 'tag=test_tag', got 'tag=%s'\n", configValue) |
|
57 |
- } |
|
58 |
- } |
|
59 |
-} |
... | ... |
@@ -282,7 +282,7 @@ func (daemon *Daemon) updateEndpointNetworkSettings(container *container.Contain |
282 | 282 |
} |
283 | 283 |
|
284 | 284 |
if container.HostConfig.NetworkMode == runconfig.DefaultDaemonNetworkMode() { |
285 |
- container.NetworkSettings.Bridge = daemon.configStore.bridgeConfig.Iface |
|
285 |
+ container.NetworkSettings.Bridge = daemon.configStore.BridgeConfig.Iface |
|
286 | 286 |
} |
287 | 287 |
|
288 | 288 |
return nil |
... | ... |
@@ -24,6 +24,8 @@ import ( |
24 | 24 |
"github.com/docker/docker/api/types" |
25 | 25 |
containertypes "github.com/docker/docker/api/types/container" |
26 | 26 |
"github.com/docker/docker/container" |
27 |
+ "github.com/docker/docker/daemon/config" |
|
28 |
+ "github.com/docker/docker/daemon/discovery" |
|
27 | 29 |
"github.com/docker/docker/daemon/events" |
28 | 30 |
"github.com/docker/docker/daemon/exec" |
29 | 31 |
// register graph drivers |
... | ... |
@@ -82,14 +84,14 @@ type Daemon struct { |
82 | 82 |
distributionMetadataStore dmetadata.Store |
83 | 83 |
trustKey libtrust.PrivateKey |
84 | 84 |
idIndex *truncindex.TruncIndex |
85 |
- configStore *Config |
|
85 |
+ configStore *config.Config |
|
86 | 86 |
statsCollector *stats.Collector |
87 | 87 |
defaultLogConfig containertypes.LogConfig |
88 | 88 |
RegistryService registry.Service |
89 | 89 |
EventsService *events.Events |
90 | 90 |
netController libnetwork.NetworkController |
91 | 91 |
volumes *store.VolumeStore |
92 |
- discoveryWatcher discoveryReloader |
|
92 |
+ discoveryWatcher discovery.Reloader |
|
93 | 93 |
root string |
94 | 94 |
seccompEnabled bool |
95 | 95 |
apparmorEnabled bool |
... | ... |
@@ -459,12 +461,12 @@ func (daemon *Daemon) IsSwarmCompatible() error { |
459 | 459 |
if daemon.configStore == nil { |
460 | 460 |
return nil |
461 | 461 |
} |
462 |
- return daemon.configStore.isSwarmCompatible() |
|
462 |
+ return daemon.configStore.IsSwarmCompatible() |
|
463 | 463 |
} |
464 | 464 |
|
465 | 465 |
// NewDaemon sets up everything for the daemon to be able to service |
466 | 466 |
// requests from the webserver. |
467 |
-func NewDaemon(config *Config, registryService registry.Service, containerdRemote libcontainerd.Remote) (daemon *Daemon, err error) { |
|
467 |
+func NewDaemon(config *config.Config, registryService registry.Service, containerdRemote libcontainerd.Remote) (daemon *Daemon, err error) { |
|
468 | 468 |
setDefaultMtu(config) |
469 | 469 |
|
470 | 470 |
// Ensure that we have a correct root key limit for launching containers. |
... | ... |
@@ -947,12 +949,12 @@ func (daemon *Daemon) setupInitLayer(initPath string) error { |
947 | 947 |
return initlayer.Setup(initPath, rootUID, rootGID) |
948 | 948 |
} |
949 | 949 |
|
950 |
-func setDefaultMtu(config *Config) { |
|
950 |
+func setDefaultMtu(conf *config.Config) { |
|
951 | 951 |
// do nothing if the config does not have the default 0 value. |
952 |
- if config.Mtu != 0 { |
|
952 |
+ if conf.Mtu != 0 { |
|
953 | 953 |
return |
954 | 954 |
} |
955 |
- config.Mtu = defaultNetworkMtu |
|
955 |
+ conf.Mtu = config.DefaultNetworkMtu |
|
956 | 956 |
} |
957 | 957 |
|
958 | 958 |
func (daemon *Daemon) configureVolumes(rootUID, rootGID int) (*store.VolumeStore, error) { |
... | ... |
@@ -975,17 +977,17 @@ func (daemon *Daemon) IsShuttingDown() bool { |
975 | 975 |
} |
976 | 976 |
|
977 | 977 |
// initDiscovery initializes the discovery watcher for this daemon. |
978 |
-func (daemon *Daemon) initDiscovery(config *Config) error { |
|
979 |
- advertise, err := parseClusterAdvertiseSettings(config.ClusterStore, config.ClusterAdvertise) |
|
978 |
+func (daemon *Daemon) initDiscovery(conf *config.Config) error { |
|
979 |
+ advertise, err := config.ParseClusterAdvertiseSettings(conf.ClusterStore, conf.ClusterAdvertise) |
|
980 | 980 |
if err != nil { |
981 |
- if err == errDiscoveryDisabled { |
|
981 |
+ if err == discovery.ErrDiscoveryDisabled { |
|
982 | 982 |
return nil |
983 | 983 |
} |
984 | 984 |
return err |
985 | 985 |
} |
986 | 986 |
|
987 |
- config.ClusterAdvertise = advertise |
|
988 |
- discoveryWatcher, err := initDiscovery(config.ClusterStore, config.ClusterAdvertise, config.ClusterOpts) |
|
987 |
+ conf.ClusterAdvertise = advertise |
|
988 |
+ discoveryWatcher, err := discovery.Init(conf.ClusterStore, conf.ClusterAdvertise, conf.ClusterOpts) |
|
989 | 989 |
if err != nil { |
990 | 990 |
return fmt.Errorf("discovery initialization failed (%v)", err) |
991 | 991 |
} |
... | ... |
@@ -1005,60 +1007,60 @@ func (daemon *Daemon) initDiscovery(config *Config) error { |
1005 | 1005 |
// - Daemon max concurrent uploads |
1006 | 1006 |
// - Cluster discovery (reconfigure and restart) |
1007 | 1007 |
// - Daemon live restore |
1008 |
-// - Daemon shutdown timeout (in seconds) |
|
1009 |
-func (daemon *Daemon) Reload(config *Config) (err error) { |
|
1008 |
+// - Daemon shutdown timeout (in seconds). |
|
1009 |
+func (daemon *Daemon) Reload(conf *config.Config) (err error) { |
|
1010 | 1010 |
|
1011 |
- daemon.configStore.reloadLock.Lock() |
|
1011 |
+ daemon.configStore.Lock() |
|
1012 | 1012 |
|
1013 |
- attributes := daemon.platformReload(config) |
|
1013 |
+ attributes := daemon.platformReload(conf) |
|
1014 | 1014 |
|
1015 | 1015 |
defer func() { |
1016 | 1016 |
// we're unlocking here, because |
1017 | 1017 |
// LogDaemonEventWithAttributes() -> SystemInfo() -> GetAllRuntimes() |
1018 | 1018 |
// holds that lock too. |
1019 |
- daemon.configStore.reloadLock.Unlock() |
|
1019 |
+ daemon.configStore.Unlock() |
|
1020 | 1020 |
if err == nil { |
1021 | 1021 |
daemon.LogDaemonEventWithAttributes("reload", attributes) |
1022 | 1022 |
} |
1023 | 1023 |
}() |
1024 | 1024 |
|
1025 |
- if err := daemon.reloadClusterDiscovery(config); err != nil { |
|
1025 |
+ if err := daemon.reloadClusterDiscovery(conf); err != nil { |
|
1026 | 1026 |
return err |
1027 | 1027 |
} |
1028 | 1028 |
|
1029 |
- if config.IsValueSet("labels") { |
|
1030 |
- daemon.configStore.Labels = config.Labels |
|
1029 |
+ if conf.IsValueSet("labels") { |
|
1030 |
+ daemon.configStore.Labels = conf.Labels |
|
1031 | 1031 |
} |
1032 |
- if config.IsValueSet("debug") { |
|
1033 |
- daemon.configStore.Debug = config.Debug |
|
1032 |
+ if conf.IsValueSet("debug") { |
|
1033 |
+ daemon.configStore.Debug = conf.Debug |
|
1034 | 1034 |
} |
1035 |
- if config.IsValueSet("insecure-registries") { |
|
1036 |
- daemon.configStore.InsecureRegistries = config.InsecureRegistries |
|
1037 |
- if err := daemon.RegistryService.LoadInsecureRegistries(config.InsecureRegistries); err != nil { |
|
1035 |
+ if conf.IsValueSet("insecure-registries") { |
|
1036 |
+ daemon.configStore.InsecureRegistries = conf.InsecureRegistries |
|
1037 |
+ if err := daemon.RegistryService.LoadInsecureRegistries(conf.InsecureRegistries); err != nil { |
|
1038 | 1038 |
return err |
1039 | 1039 |
} |
1040 | 1040 |
} |
1041 | 1041 |
|
1042 |
- if config.IsValueSet("registry-mirrors") { |
|
1043 |
- daemon.configStore.Mirrors = config.Mirrors |
|
1044 |
- if err := daemon.RegistryService.LoadMirrors(config.Mirrors); err != nil { |
|
1042 |
+ if conf.IsValueSet("registry-mirrors") { |
|
1043 |
+ daemon.configStore.Mirrors = conf.Mirrors |
|
1044 |
+ if err := daemon.RegistryService.LoadMirrors(conf.Mirrors); err != nil { |
|
1045 | 1045 |
return err |
1046 | 1046 |
} |
1047 | 1047 |
} |
1048 | 1048 |
|
1049 |
- if config.IsValueSet("live-restore") { |
|
1050 |
- daemon.configStore.LiveRestoreEnabled = config.LiveRestoreEnabled |
|
1051 |
- if err := daemon.containerdRemote.UpdateOptions(libcontainerd.WithLiveRestore(config.LiveRestoreEnabled)); err != nil { |
|
1049 |
+ if conf.IsValueSet("live-restore") { |
|
1050 |
+ daemon.configStore.LiveRestoreEnabled = conf.LiveRestoreEnabled |
|
1051 |
+ if err := daemon.containerdRemote.UpdateOptions(libcontainerd.WithLiveRestore(conf.LiveRestoreEnabled)); err != nil { |
|
1052 | 1052 |
return err |
1053 | 1053 |
} |
1054 | 1054 |
} |
1055 | 1055 |
|
1056 | 1056 |
// If no value is set for max-concurrent-downloads we assume it is the default value |
1057 | 1057 |
// We always "reset" as the cost is lightweight and easy to maintain. |
1058 |
- if config.IsValueSet("max-concurrent-downloads") && config.MaxConcurrentDownloads != nil { |
|
1059 |
- *daemon.configStore.MaxConcurrentDownloads = *config.MaxConcurrentDownloads |
|
1058 |
+ if conf.IsValueSet("max-concurrent-downloads") && conf.MaxConcurrentDownloads != nil { |
|
1059 |
+ *daemon.configStore.MaxConcurrentDownloads = *conf.MaxConcurrentDownloads |
|
1060 | 1060 |
} else { |
1061 |
- maxConcurrentDownloads := defaultMaxConcurrentDownloads |
|
1061 |
+ maxConcurrentDownloads := config.DefaultMaxConcurrentDownloads |
|
1062 | 1062 |
daemon.configStore.MaxConcurrentDownloads = &maxConcurrentDownloads |
1063 | 1063 |
} |
1064 | 1064 |
logrus.Debugf("Reset Max Concurrent Downloads: %d", *daemon.configStore.MaxConcurrentDownloads) |
... | ... |
@@ -1068,10 +1070,10 @@ func (daemon *Daemon) Reload(config *Config) (err error) { |
1068 | 1068 |
|
1069 | 1069 |
// If no value is set for max-concurrent-upload we assume it is the default value |
1070 | 1070 |
// We always "reset" as the cost is lightweight and easy to maintain. |
1071 |
- if config.IsValueSet("max-concurrent-uploads") && config.MaxConcurrentUploads != nil { |
|
1072 |
- *daemon.configStore.MaxConcurrentUploads = *config.MaxConcurrentUploads |
|
1071 |
+ if conf.IsValueSet("max-concurrent-uploads") && conf.MaxConcurrentUploads != nil { |
|
1072 |
+ *daemon.configStore.MaxConcurrentUploads = *conf.MaxConcurrentUploads |
|
1073 | 1073 |
} else { |
1074 |
- maxConcurrentUploads := defaultMaxConcurrentUploads |
|
1074 |
+ maxConcurrentUploads := config.DefaultMaxConcurrentUploads |
|
1075 | 1075 |
daemon.configStore.MaxConcurrentUploads = &maxConcurrentUploads |
1076 | 1076 |
} |
1077 | 1077 |
logrus.Debugf("Reset Max Concurrent Uploads: %d", *daemon.configStore.MaxConcurrentUploads) |
... | ... |
@@ -1079,8 +1081,8 @@ func (daemon *Daemon) Reload(config *Config) (err error) { |
1079 | 1079 |
daemon.uploadManager.SetConcurrency(*daemon.configStore.MaxConcurrentUploads) |
1080 | 1080 |
} |
1081 | 1081 |
|
1082 |
- if config.IsValueSet("shutdown-timeout") { |
|
1083 |
- daemon.configStore.ShutdownTimeout = config.ShutdownTimeout |
|
1082 |
+ if conf.IsValueSet("shutdown-timeout") { |
|
1083 |
+ daemon.configStore.ShutdownTimeout = conf.ShutdownTimeout |
|
1084 | 1084 |
logrus.Debugf("Reset Shutdown Timeout: %d", daemon.configStore.ShutdownTimeout) |
1085 | 1085 |
} |
1086 | 1086 |
|
... | ... |
@@ -1137,52 +1139,52 @@ func (daemon *Daemon) Reload(config *Config) (err error) { |
1137 | 1137 |
return nil |
1138 | 1138 |
} |
1139 | 1139 |
|
1140 |
-func (daemon *Daemon) reloadClusterDiscovery(config *Config) error { |
|
1140 |
+func (daemon *Daemon) reloadClusterDiscovery(conf *config.Config) error { |
|
1141 | 1141 |
var err error |
1142 | 1142 |
newAdvertise := daemon.configStore.ClusterAdvertise |
1143 | 1143 |
newClusterStore := daemon.configStore.ClusterStore |
1144 |
- if config.IsValueSet("cluster-advertise") { |
|
1145 |
- if config.IsValueSet("cluster-store") { |
|
1146 |
- newClusterStore = config.ClusterStore |
|
1144 |
+ if conf.IsValueSet("cluster-advertise") { |
|
1145 |
+ if conf.IsValueSet("cluster-store") { |
|
1146 |
+ newClusterStore = conf.ClusterStore |
|
1147 | 1147 |
} |
1148 |
- newAdvertise, err = parseClusterAdvertiseSettings(newClusterStore, config.ClusterAdvertise) |
|
1149 |
- if err != nil && err != errDiscoveryDisabled { |
|
1148 |
+ newAdvertise, err = config.ParseClusterAdvertiseSettings(newClusterStore, conf.ClusterAdvertise) |
|
1149 |
+ if err != nil && err != discovery.ErrDiscoveryDisabled { |
|
1150 | 1150 |
return err |
1151 | 1151 |
} |
1152 | 1152 |
} |
1153 | 1153 |
|
1154 | 1154 |
if daemon.clusterProvider != nil { |
1155 |
- if err := config.isSwarmCompatible(); err != nil { |
|
1155 |
+ if err := conf.IsSwarmCompatible(); err != nil { |
|
1156 | 1156 |
return err |
1157 | 1157 |
} |
1158 | 1158 |
} |
1159 | 1159 |
|
1160 | 1160 |
// check discovery modifications |
1161 |
- if !modifiedDiscoverySettings(daemon.configStore, newAdvertise, newClusterStore, config.ClusterOpts) { |
|
1161 |
+ if !config.ModifiedDiscoverySettings(daemon.configStore, newAdvertise, newClusterStore, conf.ClusterOpts) { |
|
1162 | 1162 |
return nil |
1163 | 1163 |
} |
1164 | 1164 |
|
1165 | 1165 |
// enable discovery for the first time if it was not previously enabled |
1166 | 1166 |
if daemon.discoveryWatcher == nil { |
1167 |
- discoveryWatcher, err := initDiscovery(newClusterStore, newAdvertise, config.ClusterOpts) |
|
1167 |
+ discoveryWatcher, err := discovery.Init(newClusterStore, newAdvertise, conf.ClusterOpts) |
|
1168 | 1168 |
if err != nil { |
1169 | 1169 |
return fmt.Errorf("discovery initialization failed (%v)", err) |
1170 | 1170 |
} |
1171 | 1171 |
daemon.discoveryWatcher = discoveryWatcher |
1172 | 1172 |
} else { |
1173 |
- if err == errDiscoveryDisabled { |
|
1173 |
+ if err == discovery.ErrDiscoveryDisabled { |
|
1174 | 1174 |
// disable discovery if it was previously enabled and it's disabled now |
1175 | 1175 |
daemon.discoveryWatcher.Stop() |
1176 | 1176 |
} else { |
1177 | 1177 |
// reload discovery |
1178 |
- if err = daemon.discoveryWatcher.Reload(config.ClusterStore, newAdvertise, config.ClusterOpts); err != nil { |
|
1178 |
+ if err = daemon.discoveryWatcher.Reload(conf.ClusterStore, newAdvertise, conf.ClusterOpts); err != nil { |
|
1179 | 1179 |
return err |
1180 | 1180 |
} |
1181 | 1181 |
} |
1182 | 1182 |
} |
1183 | 1183 |
|
1184 | 1184 |
daemon.configStore.ClusterStore = newClusterStore |
1185 |
- daemon.configStore.ClusterOpts = config.ClusterOpts |
|
1185 |
+ daemon.configStore.ClusterOpts = conf.ClusterOpts |
|
1186 | 1186 |
daemon.configStore.ClusterAdvertise = newAdvertise |
1187 | 1187 |
|
1188 | 1188 |
if daemon.netController == nil { |
... | ... |
@@ -1201,11 +1203,11 @@ func (daemon *Daemon) reloadClusterDiscovery(config *Config) error { |
1201 | 1201 |
return nil |
1202 | 1202 |
} |
1203 | 1203 |
|
1204 |
-func isBridgeNetworkDisabled(config *Config) bool { |
|
1205 |
- return config.bridgeConfig.Iface == disableNetworkBridge |
|
1204 |
+func isBridgeNetworkDisabled(conf *config.Config) bool { |
|
1205 |
+ return conf.BridgeConfig.Iface == config.DisableNetworkBridge |
|
1206 | 1206 |
} |
1207 | 1207 |
|
1208 |
-func (daemon *Daemon) networkOptions(dconfig *Config, pg plugingetter.PluginGetter, activeSandboxes map[string]interface{}) ([]nwconfig.Option, error) { |
|
1208 |
+func (daemon *Daemon) networkOptions(dconfig *config.Config, pg plugingetter.PluginGetter, activeSandboxes map[string]interface{}) ([]nwconfig.Option, error) { |
|
1209 | 1209 |
options := []nwconfig.Option{} |
1210 | 1210 |
if dconfig == nil { |
1211 | 1211 |
return options, nil |
... | ... |
@@ -1297,7 +1299,7 @@ func (daemon *Daemon) PluginGetter() *plugin.Store { |
1297 | 1297 |
} |
1298 | 1298 |
|
1299 | 1299 |
// CreateDaemonRoot creates the root for the daemon |
1300 |
-func CreateDaemonRoot(config *Config) error { |
|
1300 |
+func CreateDaemonRoot(config *config.Config) error { |
|
1301 | 1301 |
// get the canonical path to the Docker root directory |
1302 | 1302 |
var realRoot string |
1303 | 1303 |
if _, err := os.Stat(config.Root); err != nil && os.IsNotExist(err) { |
... | ... |
@@ -12,6 +12,7 @@ import ( |
12 | 12 |
|
13 | 13 |
containertypes "github.com/docker/docker/api/types/container" |
14 | 14 |
"github.com/docker/docker/container" |
15 |
+ "github.com/docker/docker/daemon/config" |
|
15 | 16 |
"github.com/docker/docker/pkg/discovery" |
16 | 17 |
_ "github.com/docker/docker/pkg/discovery/memory" |
17 | 18 |
"github.com/docker/docker/pkg/registrar" |
... | ... |
@@ -316,18 +317,18 @@ func TestMerge(t *testing.T) { |
316 | 316 |
|
317 | 317 |
func TestDaemonReloadLabels(t *testing.T) { |
318 | 318 |
daemon := &Daemon{} |
319 |
- daemon.configStore = &Config{ |
|
320 |
- CommonConfig: CommonConfig{ |
|
319 |
+ daemon.configStore = &config.Config{ |
|
320 |
+ CommonConfig: config.CommonConfig{ |
|
321 | 321 |
Labels: []string{"foo:bar"}, |
322 | 322 |
}, |
323 | 323 |
} |
324 | 324 |
|
325 | 325 |
valuesSets := make(map[string]interface{}) |
326 | 326 |
valuesSets["labels"] = "foo:baz" |
327 |
- newConfig := &Config{ |
|
328 |
- CommonConfig: CommonConfig{ |
|
327 |
+ newConfig := &config.Config{ |
|
328 |
+ CommonConfig: config.CommonConfig{ |
|
329 | 329 |
Labels: []string{"foo:baz"}, |
330 |
- valuesSet: valuesSets, |
|
330 |
+ ValuesSet: valuesSets, |
|
331 | 331 |
}, |
332 | 332 |
} |
333 | 333 |
|
... | ... |
@@ -353,7 +354,7 @@ func TestDaemonReloadMirrors(t *testing.T) { |
353 | 353 |
}, |
354 | 354 |
}) |
355 | 355 |
|
356 |
- daemon.configStore = &Config{} |
|
356 |
+ daemon.configStore = &config.Config{} |
|
357 | 357 |
|
358 | 358 |
type pair struct { |
359 | 359 |
valid bool |
... | ... |
@@ -388,12 +389,12 @@ func TestDaemonReloadMirrors(t *testing.T) { |
388 | 388 |
valuesSets := make(map[string]interface{}) |
389 | 389 |
valuesSets["registry-mirrors"] = value.mirrors |
390 | 390 |
|
391 |
- newConfig := &Config{ |
|
392 |
- CommonConfig: CommonConfig{ |
|
391 |
+ newConfig := &config.Config{ |
|
392 |
+ CommonConfig: config.CommonConfig{ |
|
393 | 393 |
ServiceOptions: registry.ServiceOptions{ |
394 | 394 |
Mirrors: value.mirrors, |
395 | 395 |
}, |
396 |
- valuesSet: valuesSets, |
|
396 |
+ ValuesSet: valuesSets, |
|
397 | 397 |
}, |
398 | 398 |
} |
399 | 399 |
|
... | ... |
@@ -448,7 +449,7 @@ func TestDaemonReloadInsecureRegistries(t *testing.T) { |
448 | 448 |
}, |
449 | 449 |
}) |
450 | 450 |
|
451 |
- daemon.configStore = &Config{} |
|
451 |
+ daemon.configStore = &config.Config{} |
|
452 | 452 |
|
453 | 453 |
insecureRegistries := []string{ |
454 | 454 |
"127.0.0.0/8", // this will be kept |
... | ... |
@@ -461,12 +462,12 @@ func TestDaemonReloadInsecureRegistries(t *testing.T) { |
461 | 461 |
valuesSets := make(map[string]interface{}) |
462 | 462 |
valuesSets["insecure-registries"] = insecureRegistries |
463 | 463 |
|
464 |
- newConfig := &Config{ |
|
465 |
- CommonConfig: CommonConfig{ |
|
464 |
+ newConfig := &config.Config{ |
|
465 |
+ CommonConfig: config.CommonConfig{ |
|
466 | 466 |
ServiceOptions: registry.ServiceOptions{ |
467 | 467 |
InsecureRegistries: insecureRegistries, |
468 | 468 |
}, |
469 |
- valuesSet: valuesSets, |
|
469 |
+ ValuesSet: valuesSets, |
|
470 | 470 |
}, |
471 | 471 |
} |
472 | 472 |
|
... | ... |
@@ -523,8 +524,8 @@ func TestDaemonReloadInsecureRegistries(t *testing.T) { |
523 | 523 |
|
524 | 524 |
func TestDaemonReloadNotAffectOthers(t *testing.T) { |
525 | 525 |
daemon := &Daemon{} |
526 |
- daemon.configStore = &Config{ |
|
527 |
- CommonConfig: CommonConfig{ |
|
526 |
+ daemon.configStore = &config.Config{ |
|
527 |
+ CommonConfig: config.CommonConfig{ |
|
528 | 528 |
Labels: []string{"foo:bar"}, |
529 | 529 |
Debug: true, |
530 | 530 |
}, |
... | ... |
@@ -532,10 +533,10 @@ func TestDaemonReloadNotAffectOthers(t *testing.T) { |
532 | 532 |
|
533 | 533 |
valuesSets := make(map[string]interface{}) |
534 | 534 |
valuesSets["labels"] = "foo:baz" |
535 |
- newConfig := &Config{ |
|
536 |
- CommonConfig: CommonConfig{ |
|
535 |
+ newConfig := &config.Config{ |
|
536 |
+ CommonConfig: config.CommonConfig{ |
|
537 | 537 |
Labels: []string{"foo:baz"}, |
538 |
- valuesSet: valuesSets, |
|
538 |
+ ValuesSet: valuesSets, |
|
539 | 539 |
}, |
540 | 540 |
} |
541 | 541 |
|
... | ... |
@@ -555,8 +556,8 @@ func TestDaemonReloadNotAffectOthers(t *testing.T) { |
555 | 555 |
|
556 | 556 |
func TestDaemonDiscoveryReload(t *testing.T) { |
557 | 557 |
daemon := &Daemon{} |
558 |
- daemon.configStore = &Config{ |
|
559 |
- CommonConfig: CommonConfig{ |
|
558 |
+ daemon.configStore = &config.Config{ |
|
559 |
+ CommonConfig: config.CommonConfig{ |
|
560 | 560 |
ClusterStore: "memory://127.0.0.1", |
561 | 561 |
ClusterAdvertise: "127.0.0.1:3333", |
562 | 562 |
}, |
... | ... |
@@ -594,11 +595,11 @@ func TestDaemonDiscoveryReload(t *testing.T) { |
594 | 594 |
valuesSets := make(map[string]interface{}) |
595 | 595 |
valuesSets["cluster-store"] = "memory://127.0.0.1:2222" |
596 | 596 |
valuesSets["cluster-advertise"] = "127.0.0.1:5555" |
597 |
- newConfig := &Config{ |
|
598 |
- CommonConfig: CommonConfig{ |
|
597 |
+ newConfig := &config.Config{ |
|
598 |
+ CommonConfig: config.CommonConfig{ |
|
599 | 599 |
ClusterStore: "memory://127.0.0.1:2222", |
600 | 600 |
ClusterAdvertise: "127.0.0.1:5555", |
601 |
- valuesSet: valuesSets, |
|
601 |
+ ValuesSet: valuesSets, |
|
602 | 602 |
}, |
603 | 603 |
} |
604 | 604 |
|
... | ... |
@@ -632,16 +633,16 @@ func TestDaemonDiscoveryReload(t *testing.T) { |
632 | 632 |
|
633 | 633 |
func TestDaemonDiscoveryReloadFromEmptyDiscovery(t *testing.T) { |
634 | 634 |
daemon := &Daemon{} |
635 |
- daemon.configStore = &Config{} |
|
635 |
+ daemon.configStore = &config.Config{} |
|
636 | 636 |
|
637 | 637 |
valuesSet := make(map[string]interface{}) |
638 | 638 |
valuesSet["cluster-store"] = "memory://127.0.0.1:2222" |
639 | 639 |
valuesSet["cluster-advertise"] = "127.0.0.1:5555" |
640 |
- newConfig := &Config{ |
|
641 |
- CommonConfig: CommonConfig{ |
|
640 |
+ newConfig := &config.Config{ |
|
641 |
+ CommonConfig: config.CommonConfig{ |
|
642 | 642 |
ClusterStore: "memory://127.0.0.1:2222", |
643 | 643 |
ClusterAdvertise: "127.0.0.1:5555", |
644 |
- valuesSet: valuesSet, |
|
644 |
+ ValuesSet: valuesSet, |
|
645 | 645 |
}, |
646 | 646 |
} |
647 | 647 |
|
... | ... |
@@ -677,17 +678,17 @@ func TestDaemonDiscoveryReloadFromEmptyDiscovery(t *testing.T) { |
677 | 677 |
|
678 | 678 |
func TestDaemonDiscoveryReloadOnlyClusterAdvertise(t *testing.T) { |
679 | 679 |
daemon := &Daemon{} |
680 |
- daemon.configStore = &Config{ |
|
681 |
- CommonConfig: CommonConfig{ |
|
680 |
+ daemon.configStore = &config.Config{ |
|
681 |
+ CommonConfig: config.CommonConfig{ |
|
682 | 682 |
ClusterStore: "memory://127.0.0.1", |
683 | 683 |
}, |
684 | 684 |
} |
685 | 685 |
valuesSets := make(map[string]interface{}) |
686 | 686 |
valuesSets["cluster-advertise"] = "127.0.0.1:5555" |
687 |
- newConfig := &Config{ |
|
688 |
- CommonConfig: CommonConfig{ |
|
687 |
+ newConfig := &config.Config{ |
|
688 |
+ CommonConfig: config.CommonConfig{ |
|
689 | 689 |
ClusterAdvertise: "127.0.0.1:5555", |
690 |
- valuesSet: valuesSets, |
|
690 |
+ ValuesSet: valuesSets, |
|
691 | 691 |
}, |
692 | 692 |
} |
693 | 693 |
expected := discovery.Entries{ |
... | ... |
@@ -23,6 +23,7 @@ import ( |
23 | 23 |
pblkiodev "github.com/docker/docker/api/types/blkiodev" |
24 | 24 |
containertypes "github.com/docker/docker/api/types/container" |
25 | 25 |
"github.com/docker/docker/container" |
26 |
+ "github.com/docker/docker/daemon/config" |
|
26 | 27 |
"github.com/docker/docker/image" |
27 | 28 |
"github.com/docker/docker/opts" |
28 | 29 |
"github.com/docker/docker/pkg/idtools" |
... | ... |
@@ -256,7 +257,7 @@ func (daemon *Daemon) adaptContainerSettings(hostConfig *containertypes.HostConf |
256 | 256 |
hostConfig.MemorySwap = hostConfig.Memory * 2 |
257 | 257 |
} |
258 | 258 |
if hostConfig.ShmSize == 0 { |
259 |
- hostConfig.ShmSize = defaultShmSize |
|
259 |
+ hostConfig.ShmSize = config.DefaultShmSize |
|
260 | 260 |
if daemon.configStore != nil { |
261 | 261 |
hostConfig.ShmSize = int64(daemon.configStore.ShmSize) |
262 | 262 |
} |
... | ... |
@@ -474,7 +475,7 @@ func (daemon *Daemon) getCgroupDriver() string { |
474 | 474 |
} |
475 | 475 |
|
476 | 476 |
// getCD gets the raw value of the native.cgroupdriver option, if set. |
477 |
-func getCD(config *Config) string { |
|
477 |
+func getCD(config *config.Config) string { |
|
478 | 478 |
for _, option := range config.ExecOptions { |
479 | 479 |
key, val, err := parsers.ParseKeyValueOpt(option) |
480 | 480 |
if err != nil || !strings.EqualFold(key, "native.cgroupdriver") { |
... | ... |
@@ -486,7 +487,7 @@ func getCD(config *Config) string { |
486 | 486 |
} |
487 | 487 |
|
488 | 488 |
// VerifyCgroupDriver validates native.cgroupdriver |
489 |
-func VerifyCgroupDriver(config *Config) error { |
|
489 |
+func VerifyCgroupDriver(config *config.Config) error { |
|
490 | 490 |
cd := getCD(config) |
491 | 491 |
if cd == "" || cd == cgroupFsDriver || cd == cgroupSystemdDriver { |
492 | 492 |
return nil |
... | ... |
@@ -495,7 +496,7 @@ func VerifyCgroupDriver(config *Config) error { |
495 | 495 |
} |
496 | 496 |
|
497 | 497 |
// UsingSystemd returns true if cli option includes native.cgroupdriver=systemd |
498 |
-func UsingSystemd(config *Config) bool { |
|
498 |
+func UsingSystemd(config *config.Config) bool { |
|
499 | 499 |
return getCD(config) == cgroupSystemdDriver |
500 | 500 |
} |
501 | 501 |
|
... | ... |
@@ -568,19 +569,19 @@ func verifyPlatformContainerSettings(daemon *Daemon, hostConfig *containertypes. |
568 | 568 |
} |
569 | 569 |
|
570 | 570 |
// platformReload updates configuration with platform specific options |
571 |
-func (daemon *Daemon) platformReload(config *Config) map[string]string { |
|
572 |
- if config.IsValueSet("runtimes") { |
|
573 |
- daemon.configStore.Runtimes = config.Runtimes |
|
571 |
+func (daemon *Daemon) platformReload(conf *config.Config) map[string]string { |
|
572 |
+ if conf.IsValueSet("runtimes") { |
|
573 |
+ daemon.configStore.Runtimes = conf.Runtimes |
|
574 | 574 |
// Always set the default one |
575 |
- daemon.configStore.Runtimes[stockRuntimeName] = types.Runtime{Path: DefaultRuntimeBinary} |
|
575 |
+ daemon.configStore.Runtimes[config.StockRuntimeName] = types.Runtime{Path: DefaultRuntimeBinary} |
|
576 | 576 |
} |
577 | 577 |
|
578 |
- if config.DefaultRuntime != "" { |
|
579 |
- daemon.configStore.DefaultRuntime = config.DefaultRuntime |
|
578 |
+ if conf.DefaultRuntime != "" { |
|
579 |
+ daemon.configStore.DefaultRuntime = conf.DefaultRuntime |
|
580 | 580 |
} |
581 | 581 |
|
582 |
- if config.IsValueSet("default-shm-size") { |
|
583 |
- daemon.configStore.ShmSize = config.ShmSize |
|
582 |
+ if conf.IsValueSet("default-shm-size") { |
|
583 |
+ daemon.configStore.ShmSize = conf.ShmSize |
|
584 | 584 |
} |
585 | 585 |
|
586 | 586 |
// Update attributes |
... | ... |
@@ -600,33 +601,33 @@ func (daemon *Daemon) platformReload(config *Config) map[string]string { |
600 | 600 |
} |
601 | 601 |
|
602 | 602 |
// verifyDaemonSettings performs validation of daemon config struct |
603 |
-func verifyDaemonSettings(config *Config) error { |
|
603 |
+func verifyDaemonSettings(conf *config.Config) error { |
|
604 | 604 |
// Check for mutually incompatible config options |
605 |
- if config.bridgeConfig.Iface != "" && config.bridgeConfig.IP != "" { |
|
605 |
+ if conf.BridgeConfig.Iface != "" && conf.BridgeConfig.IP != "" { |
|
606 | 606 |
return fmt.Errorf("You specified -b & --bip, mutually exclusive options. Please specify only one") |
607 | 607 |
} |
608 |
- if !config.bridgeConfig.EnableIPTables && !config.bridgeConfig.InterContainerCommunication { |
|
608 |
+ if !conf.BridgeConfig.EnableIPTables && !conf.BridgeConfig.InterContainerCommunication { |
|
609 | 609 |
return fmt.Errorf("You specified --iptables=false with --icc=false. ICC=false uses iptables to function. Please set --icc or --iptables to true") |
610 | 610 |
} |
611 |
- if !config.bridgeConfig.EnableIPTables && config.bridgeConfig.EnableIPMasq { |
|
612 |
- config.bridgeConfig.EnableIPMasq = false |
|
611 |
+ if !conf.BridgeConfig.EnableIPTables && conf.BridgeConfig.EnableIPMasq { |
|
612 |
+ conf.BridgeConfig.EnableIPMasq = false |
|
613 | 613 |
} |
614 |
- if err := VerifyCgroupDriver(config); err != nil { |
|
614 |
+ if err := VerifyCgroupDriver(conf); err != nil { |
|
615 | 615 |
return err |
616 | 616 |
} |
617 |
- if config.CgroupParent != "" && UsingSystemd(config) { |
|
618 |
- if len(config.CgroupParent) <= 6 || !strings.HasSuffix(config.CgroupParent, ".slice") { |
|
617 |
+ if conf.CgroupParent != "" && UsingSystemd(conf) { |
|
618 |
+ if len(conf.CgroupParent) <= 6 || !strings.HasSuffix(conf.CgroupParent, ".slice") { |
|
619 | 619 |
return fmt.Errorf("cgroup-parent for systemd cgroup should be a valid slice named as \"xxx.slice\"") |
620 | 620 |
} |
621 | 621 |
} |
622 | 622 |
|
623 |
- if config.DefaultRuntime == "" { |
|
624 |
- config.DefaultRuntime = stockRuntimeName |
|
623 |
+ if conf.DefaultRuntime == "" { |
|
624 |
+ conf.DefaultRuntime = config.StockRuntimeName |
|
625 | 625 |
} |
626 |
- if config.Runtimes == nil { |
|
627 |
- config.Runtimes = make(map[string]types.Runtime) |
|
626 |
+ if conf.Runtimes == nil { |
|
627 |
+ conf.Runtimes = make(map[string]types.Runtime) |
|
628 | 628 |
} |
629 |
- config.Runtimes[stockRuntimeName] = types.Runtime{Path: DefaultRuntimeBinary} |
|
629 |
+ conf.Runtimes[config.StockRuntimeName] = types.Runtime{Path: DefaultRuntimeBinary} |
|
630 | 630 |
|
631 | 631 |
return nil |
632 | 632 |
} |
... | ... |
@@ -641,7 +642,7 @@ func checkSystem() error { |
641 | 641 |
|
642 | 642 |
// configureMaxThreads sets the Go runtime max threads threshold |
643 | 643 |
// which is 90% of the kernel setting from /proc/sys/kernel/threads-max |
644 |
-func configureMaxThreads(config *Config) error { |
|
644 |
+func configureMaxThreads(config *config.Config) error { |
|
645 | 645 |
mt, err := ioutil.ReadFile("/proc/sys/kernel/threads-max") |
646 | 646 |
if err != nil { |
647 | 647 |
return err |
... | ... |
@@ -688,7 +689,7 @@ func overlaySupportsSelinux() (bool, error) { |
688 | 688 |
} |
689 | 689 |
|
690 | 690 |
// configureKernelSecuritySupport configures and validates security support for the kernel |
691 |
-func configureKernelSecuritySupport(config *Config, driverName string) error { |
|
691 |
+func configureKernelSecuritySupport(config *config.Config, driverName string) error { |
|
692 | 692 |
if config.EnableSelinuxSupport { |
693 | 693 |
if !selinuxEnabled() { |
694 | 694 |
logrus.Warn("Docker could not enable SELinux on the host system") |
... | ... |
@@ -713,7 +714,7 @@ func configureKernelSecuritySupport(config *Config, driverName string) error { |
713 | 713 |
return nil |
714 | 714 |
} |
715 | 715 |
|
716 |
-func (daemon *Daemon) initNetworkController(config *Config, activeSandboxes map[string]interface{}) (libnetwork.NetworkController, error) { |
|
716 |
+func (daemon *Daemon) initNetworkController(config *config.Config, activeSandboxes map[string]interface{}) (libnetwork.NetworkController, error) { |
|
717 | 717 |
netOptions, err := daemon.networkOptions(config, daemon.PluginStore, activeSandboxes) |
718 | 718 |
if err != nil { |
719 | 719 |
return nil, err |
... | ... |
@@ -762,12 +763,12 @@ func (daemon *Daemon) initNetworkController(config *Config, activeSandboxes map[ |
762 | 762 |
return controller, nil |
763 | 763 |
} |
764 | 764 |
|
765 |
-func driverOptions(config *Config) []nwconfig.Option { |
|
765 |
+func driverOptions(config *config.Config) []nwconfig.Option { |
|
766 | 766 |
bridgeConfig := options.Generic{ |
767 |
- "EnableIPForwarding": config.bridgeConfig.EnableIPForward, |
|
768 |
- "EnableIPTables": config.bridgeConfig.EnableIPTables, |
|
769 |
- "EnableUserlandProxy": config.bridgeConfig.EnableUserlandProxy, |
|
770 |
- "UserlandProxyPath": config.bridgeConfig.UserlandProxyPath} |
|
767 |
+ "EnableIPForwarding": config.BridgeConfig.EnableIPForward, |
|
768 |
+ "EnableIPTables": config.BridgeConfig.EnableIPTables, |
|
769 |
+ "EnableUserlandProxy": config.BridgeConfig.EnableUserlandProxy, |
|
770 |
+ "UserlandProxyPath": config.BridgeConfig.UserlandProxyPath} |
|
771 | 771 |
bridgeOption := options.Generic{netlabel.GenericData: bridgeConfig} |
772 | 772 |
|
773 | 773 |
dOptions := []nwconfig.Option{} |
... | ... |
@@ -775,22 +776,22 @@ func driverOptions(config *Config) []nwconfig.Option { |
775 | 775 |
return dOptions |
776 | 776 |
} |
777 | 777 |
|
778 |
-func initBridgeDriver(controller libnetwork.NetworkController, config *Config) error { |
|
778 |
+func initBridgeDriver(controller libnetwork.NetworkController, config *config.Config) error { |
|
779 | 779 |
bridgeName := bridge.DefaultBridgeName |
780 |
- if config.bridgeConfig.Iface != "" { |
|
781 |
- bridgeName = config.bridgeConfig.Iface |
|
780 |
+ if config.BridgeConfig.Iface != "" { |
|
781 |
+ bridgeName = config.BridgeConfig.Iface |
|
782 | 782 |
} |
783 | 783 |
netOption := map[string]string{ |
784 | 784 |
bridge.BridgeName: bridgeName, |
785 | 785 |
bridge.DefaultBridge: strconv.FormatBool(true), |
786 | 786 |
netlabel.DriverMTU: strconv.Itoa(config.Mtu), |
787 |
- bridge.EnableIPMasquerade: strconv.FormatBool(config.bridgeConfig.EnableIPMasq), |
|
788 |
- bridge.EnableICC: strconv.FormatBool(config.bridgeConfig.InterContainerCommunication), |
|
787 |
+ bridge.EnableIPMasquerade: strconv.FormatBool(config.BridgeConfig.EnableIPMasq), |
|
788 |
+ bridge.EnableICC: strconv.FormatBool(config.BridgeConfig.InterContainerCommunication), |
|
789 | 789 |
} |
790 | 790 |
|
791 | 791 |
// --ip processing |
792 |
- if config.bridgeConfig.DefaultIP != nil { |
|
793 |
- netOption[bridge.DefaultBindingIP] = config.bridgeConfig.DefaultIP.String() |
|
792 |
+ if config.BridgeConfig.DefaultIP != nil { |
|
793 |
+ netOption[bridge.DefaultBindingIP] = config.BridgeConfig.DefaultIP.String() |
|
794 | 794 |
} |
795 | 795 |
|
796 | 796 |
var ( |
... | ... |
@@ -806,8 +807,8 @@ func initBridgeDriver(controller libnetwork.NetworkController, config *Config) e |
806 | 806 |
} |
807 | 807 |
|
808 | 808 |
nw := nwList[0] |
809 |
- if len(nwList) > 1 && config.bridgeConfig.FixedCIDR != "" { |
|
810 |
- _, fCIDR, err := net.ParseCIDR(config.bridgeConfig.FixedCIDR) |
|
809 |
+ if len(nwList) > 1 && config.BridgeConfig.FixedCIDR != "" { |
|
810 |
+ _, fCIDR, err := net.ParseCIDR(config.BridgeConfig.FixedCIDR) |
|
811 | 811 |
if err != nil { |
812 | 812 |
return errors.Wrap(err, "parse CIDR failed") |
813 | 813 |
} |
... | ... |
@@ -826,9 +827,9 @@ func initBridgeDriver(controller libnetwork.NetworkController, config *Config) e |
826 | 826 |
ipamV4Conf.Gateway = nw.IP.String() |
827 | 827 |
} |
828 | 828 |
|
829 |
- if config.bridgeConfig.IP != "" { |
|
830 |
- ipamV4Conf.PreferredPool = config.bridgeConfig.IP |
|
831 |
- ip, _, err := net.ParseCIDR(config.bridgeConfig.IP) |
|
829 |
+ if config.BridgeConfig.IP != "" { |
|
830 |
+ ipamV4Conf.PreferredPool = config.BridgeConfig.IP |
|
831 |
+ ip, _, err := net.ParseCIDR(config.BridgeConfig.IP) |
|
832 | 832 |
if err != nil { |
833 | 833 |
return err |
834 | 834 |
} |
... | ... |
@@ -837,8 +838,8 @@ func initBridgeDriver(controller libnetwork.NetworkController, config *Config) e |
837 | 837 |
logrus.Infof("Default bridge (%s) is assigned with an IP address %s. Daemon option --bip can be used to set a preferred IP address", bridgeName, ipamV4Conf.PreferredPool) |
838 | 838 |
} |
839 | 839 |
|
840 |
- if config.bridgeConfig.FixedCIDR != "" { |
|
841 |
- _, fCIDR, err := net.ParseCIDR(config.bridgeConfig.FixedCIDR) |
|
840 |
+ if config.BridgeConfig.FixedCIDR != "" { |
|
841 |
+ _, fCIDR, err := net.ParseCIDR(config.BridgeConfig.FixedCIDR) |
|
842 | 842 |
if err != nil { |
843 | 843 |
return err |
844 | 844 |
} |
... | ... |
@@ -846,13 +847,13 @@ func initBridgeDriver(controller libnetwork.NetworkController, config *Config) e |
846 | 846 |
ipamV4Conf.SubPool = fCIDR.String() |
847 | 847 |
} |
848 | 848 |
|
849 |
- if config.bridgeConfig.DefaultGatewayIPv4 != nil { |
|
850 |
- ipamV4Conf.AuxAddresses["DefaultGatewayIPv4"] = config.bridgeConfig.DefaultGatewayIPv4.String() |
|
849 |
+ if config.BridgeConfig.DefaultGatewayIPv4 != nil { |
|
850 |
+ ipamV4Conf.AuxAddresses["DefaultGatewayIPv4"] = config.BridgeConfig.DefaultGatewayIPv4.String() |
|
851 | 851 |
} |
852 | 852 |
|
853 | 853 |
var deferIPv6Alloc bool |
854 |
- if config.bridgeConfig.FixedCIDRv6 != "" { |
|
855 |
- _, fCIDRv6, err := net.ParseCIDR(config.bridgeConfig.FixedCIDRv6) |
|
854 |
+ if config.BridgeConfig.FixedCIDRv6 != "" { |
|
855 |
+ _, fCIDRv6, err := net.ParseCIDR(config.BridgeConfig.FixedCIDRv6) |
|
856 | 856 |
if err != nil { |
857 | 857 |
return err |
858 | 858 |
} |
... | ... |
@@ -882,11 +883,11 @@ func initBridgeDriver(controller libnetwork.NetworkController, config *Config) e |
882 | 882 |
} |
883 | 883 |
} |
884 | 884 |
|
885 |
- if config.bridgeConfig.DefaultGatewayIPv6 != nil { |
|
885 |
+ if config.BridgeConfig.DefaultGatewayIPv6 != nil { |
|
886 | 886 |
if ipamV6Conf == nil { |
887 | 887 |
ipamV6Conf = &libnetwork.IpamConf{AuxAddresses: make(map[string]string)} |
888 | 888 |
} |
889 |
- ipamV6Conf.AuxAddresses["DefaultGatewayIPv6"] = config.bridgeConfig.DefaultGatewayIPv6.String() |
|
889 |
+ ipamV6Conf.AuxAddresses["DefaultGatewayIPv6"] = config.BridgeConfig.DefaultGatewayIPv6.String() |
|
890 | 890 |
} |
891 | 891 |
|
892 | 892 |
v4Conf := []*libnetwork.IpamConf{ipamV4Conf} |
... | ... |
@@ -896,7 +897,7 @@ func initBridgeDriver(controller libnetwork.NetworkController, config *Config) e |
896 | 896 |
} |
897 | 897 |
// Initialize default network on "bridge" with the same name |
898 | 898 |
_, err = controller.NewNetwork("bridge", "bridge", "", |
899 |
- libnetwork.NetworkOptionEnableIPv6(config.bridgeConfig.EnableIPv6), |
|
899 |
+ libnetwork.NetworkOptionEnableIPv6(config.BridgeConfig.EnableIPv6), |
|
900 | 900 |
libnetwork.NetworkOptionDriverOpts(netOption), |
901 | 901 |
libnetwork.NetworkOptionIpam("default", "", v4Conf, v6Conf, nil), |
902 | 902 |
libnetwork.NetworkOptionDeferIPv6Alloc(deferIPv6Alloc)) |
... | ... |
@@ -1012,7 +1013,7 @@ func parseRemappedRoot(usergrp string) (string, string, error) { |
1012 | 1012 |
return username, groupname, nil |
1013 | 1013 |
} |
1014 | 1014 |
|
1015 |
-func setupRemappedRoot(config *Config) ([]idtools.IDMap, []idtools.IDMap, error) { |
|
1015 |
+func setupRemappedRoot(config *config.Config) ([]idtools.IDMap, []idtools.IDMap, error) { |
|
1016 | 1016 |
if runtime.GOOS != "linux" && config.RemappedRoot != "" { |
1017 | 1017 |
return nil, nil, fmt.Errorf("User namespaces are only supported on Linux") |
1018 | 1018 |
} |
... | ... |
@@ -1045,7 +1046,7 @@ func setupRemappedRoot(config *Config) ([]idtools.IDMap, []idtools.IDMap, error) |
1045 | 1045 |
return uidMaps, gidMaps, nil |
1046 | 1046 |
} |
1047 | 1047 |
|
1048 |
-func setupDaemonRoot(config *Config, rootDir string, rootUID, rootGID int) error { |
|
1048 |
+func setupDaemonRoot(config *config.Config, rootDir string, rootUID, rootGID int) error { |
|
1049 | 1049 |
config.Root = rootDir |
1050 | 1050 |
// the docker root metadata directory needs to have execute permissions for all users (g+x,o+x) |
1051 | 1051 |
// so that syscalls executing as non-root, operating on subdirectories of the graph root |
... | ... |
@@ -1219,7 +1220,7 @@ func rootFSToAPIType(rootfs *image.RootFS) types.RootFS { |
1219 | 1219 |
} |
1220 | 1220 |
|
1221 | 1221 |
// setupDaemonProcess sets various settings for the daemon's process |
1222 |
-func setupDaemonProcess(config *Config) error { |
|
1222 |
+func setupDaemonProcess(config *config.Config) error { |
|
1223 | 1223 |
// setup the daemons oom_score_adj |
1224 | 1224 |
return setupOOMScoreAdj(config.OOMScoreAdjust) |
1225 | 1225 |
} |
... | ... |
@@ -10,6 +10,7 @@ import ( |
10 | 10 |
|
11 | 11 |
containertypes "github.com/docker/docker/api/types/container" |
12 | 12 |
"github.com/docker/docker/container" |
13 |
+ "github.com/docker/docker/daemon/config" |
|
13 | 14 |
"github.com/docker/docker/volume" |
14 | 15 |
"github.com/docker/docker/volume/drivers" |
15 | 16 |
"github.com/docker/docker/volume/local" |
... | ... |
@@ -181,8 +182,8 @@ func TestParseSecurityOpt(t *testing.T) { |
181 | 181 |
|
182 | 182 |
func TestNetworkOptions(t *testing.T) { |
183 | 183 |
daemon := &Daemon{} |
184 |
- dconfigCorrect := &Config{ |
|
185 |
- CommonConfig: CommonConfig{ |
|
184 |
+ dconfigCorrect := &config.Config{ |
|
185 |
+ CommonConfig: config.CommonConfig{ |
|
186 | 186 |
ClusterStore: "consul://localhost:8500", |
187 | 187 |
ClusterAdvertise: "192.168.0.1:8000", |
188 | 188 |
}, |
... | ... |
@@ -192,8 +193,8 @@ func TestNetworkOptions(t *testing.T) { |
192 | 192 |
t.Fatalf("Expect networkOptions success, got error: %v", err) |
193 | 193 |
} |
194 | 194 |
|
195 |
- dconfigWrong := &Config{ |
|
196 |
- CommonConfig: CommonConfig{ |
|
195 |
+ dconfigWrong := &config.Config{ |
|
196 |
+ CommonConfig: config.CommonConfig{ |
|
197 | 197 |
ClusterStore: "consul://localhost:8500://test://bbb", |
198 | 198 |
}, |
199 | 199 |
} |
... | ... |
@@ -11,6 +11,7 @@ import ( |
11 | 11 |
"github.com/docker/docker/api/types" |
12 | 12 |
containertypes "github.com/docker/docker/api/types/container" |
13 | 13 |
"github.com/docker/docker/container" |
14 |
+ "github.com/docker/docker/daemon/config" |
|
14 | 15 |
"github.com/docker/docker/image" |
15 | 16 |
"github.com/docker/docker/pkg/idtools" |
16 | 17 |
"github.com/docker/docker/pkg/parsers" |
... | ... |
@@ -210,12 +211,12 @@ func verifyPlatformContainerSettings(daemon *Daemon, hostConfig *containertypes. |
210 | 210 |
} |
211 | 211 |
|
212 | 212 |
// platformReload updates configuration with platform specific options |
213 |
-func (daemon *Daemon) platformReload(config *Config) map[string]string { |
|
213 |
+func (daemon *Daemon) platformReload(config *config.Config) map[string]string { |
|
214 | 214 |
return map[string]string{} |
215 | 215 |
} |
216 | 216 |
|
217 | 217 |
// verifyDaemonSettings performs validation of daemon config struct |
218 |
-func verifyDaemonSettings(config *Config) error { |
|
218 |
+func verifyDaemonSettings(config *config.Config) error { |
|
219 | 219 |
return nil |
220 | 220 |
} |
221 | 221 |
|
... | ... |
@@ -239,16 +240,16 @@ func checkSystem() error { |
239 | 239 |
} |
240 | 240 |
|
241 | 241 |
// configureKernelSecuritySupport configures and validate security support for the kernel |
242 |
-func configureKernelSecuritySupport(config *Config, driverName string) error { |
|
242 |
+func configureKernelSecuritySupport(config *config.Config, driverName string) error { |
|
243 | 243 |
return nil |
244 | 244 |
} |
245 | 245 |
|
246 | 246 |
// configureMaxThreads sets the Go runtime max threads threshold |
247 |
-func configureMaxThreads(config *Config) error { |
|
247 |
+func configureMaxThreads(config *config.Config) error { |
|
248 | 248 |
return nil |
249 | 249 |
} |
250 | 250 |
|
251 |
-func (daemon *Daemon) initNetworkController(config *Config, activeSandboxes map[string]interface{}) (libnetwork.NetworkController, error) { |
|
251 |
+func (daemon *Daemon) initNetworkController(config *config.Config, activeSandboxes map[string]interface{}) (libnetwork.NetworkController, error) { |
|
252 | 252 |
netOptions, err := daemon.networkOptions(config, nil, nil) |
253 | 253 |
if err != nil { |
254 | 254 |
return nil, err |
... | ... |
@@ -376,7 +377,7 @@ func (daemon *Daemon) initNetworkController(config *Config, activeSandboxes map[ |
376 | 376 |
return controller, nil |
377 | 377 |
} |
378 | 378 |
|
379 |
-func initBridgeDriver(controller libnetwork.NetworkController, config *Config) error { |
|
379 |
+func initBridgeDriver(controller libnetwork.NetworkController, config *config.Config) error { |
|
380 | 380 |
if _, err := controller.NetworkByName(runconfig.DefaultDaemonNetworkMode().NetworkName()); err == nil { |
381 | 381 |
return nil |
382 | 382 |
} |
... | ... |
@@ -388,8 +389,8 @@ func initBridgeDriver(controller libnetwork.NetworkController, config *Config) e |
388 | 388 |
var ipamOption libnetwork.NetworkOption |
389 | 389 |
var subnetPrefix string |
390 | 390 |
|
391 |
- if config.bridgeConfig.FixedCIDR != "" { |
|
392 |
- subnetPrefix = config.bridgeConfig.FixedCIDR |
|
391 |
+ if config.BridgeConfig.FixedCIDR != "" { |
|
392 |
+ subnetPrefix = config.BridgeConfig.FixedCIDR |
|
393 | 393 |
} else { |
394 | 394 |
// TP5 doesn't support properly detecting subnet |
395 | 395 |
osv := system.GetOSVersion() |
... | ... |
@@ -434,11 +435,11 @@ func (daemon *Daemon) cleanupMounts() error { |
434 | 434 |
return nil |
435 | 435 |
} |
436 | 436 |
|
437 |
-func setupRemappedRoot(config *Config) ([]idtools.IDMap, []idtools.IDMap, error) { |
|
437 |
+func setupRemappedRoot(config *config.Config) ([]idtools.IDMap, []idtools.IDMap, error) { |
|
438 | 438 |
return nil, nil, nil |
439 | 439 |
} |
440 | 440 |
|
441 |
-func setupDaemonRoot(config *Config, rootDir string, rootUID, rootGID int) error { |
|
441 |
+func setupDaemonRoot(config *config.Config, rootDir string, rootUID, rootGID int) error { |
|
442 | 442 |
config.Root = rootDir |
443 | 443 |
// Create the root directory if it doesn't exists |
444 | 444 |
if err := system.MkdirAllWithACL(config.Root, 0); err != nil && !os.IsExist(err) { |
... | ... |
@@ -479,7 +480,7 @@ func (daemon *Daemon) conditionalUnmountOnCleanup(container *container.Container |
479 | 479 |
return nil |
480 | 480 |
} |
481 | 481 |
|
482 |
-func driverOptions(config *Config) []nwconfig.Option { |
|
482 |
+func driverOptions(config *config.Config) []nwconfig.Option { |
|
483 | 483 |
return []nwconfig.Option{} |
484 | 484 |
} |
485 | 485 |
|
... | ... |
@@ -593,7 +594,7 @@ func rootFSToAPIType(rootfs *image.RootFS) types.RootFS { |
593 | 593 |
} |
594 | 594 |
} |
595 | 595 |
|
596 |
-func setupDaemonProcess(config *Config) error { |
|
596 |
+func setupDaemonProcess(config *config.Config) error { |
|
597 | 597 |
return nil |
598 | 598 |
} |
599 | 599 |
|
600 | 600 |
deleted file mode 100644 |
... | ... |
@@ -1,215 +0,0 @@ |
1 |
-package daemon |
|
2 |
- |
|
3 |
-import ( |
|
4 |
- "errors" |
|
5 |
- "fmt" |
|
6 |
- "reflect" |
|
7 |
- "strconv" |
|
8 |
- "time" |
|
9 |
- |
|
10 |
- "github.com/Sirupsen/logrus" |
|
11 |
- "github.com/docker/docker/pkg/discovery" |
|
12 |
- |
|
13 |
- // Register the libkv backends for discovery. |
|
14 |
- _ "github.com/docker/docker/pkg/discovery/kv" |
|
15 |
-) |
|
16 |
- |
|
17 |
-const ( |
|
18 |
- // defaultDiscoveryHeartbeat is the default value for discovery heartbeat interval. |
|
19 |
- defaultDiscoveryHeartbeat = 20 * time.Second |
|
20 |
- // defaultDiscoveryTTLFactor is the default TTL factor for discovery |
|
21 |
- defaultDiscoveryTTLFactor = 3 |
|
22 |
-) |
|
23 |
- |
|
24 |
-var errDiscoveryDisabled = errors.New("discovery is disabled") |
|
25 |
- |
|
26 |
-type discoveryReloader interface { |
|
27 |
- discovery.Watcher |
|
28 |
- Stop() |
|
29 |
- Reload(backend, address string, clusterOpts map[string]string) error |
|
30 |
- ReadyCh() <-chan struct{} |
|
31 |
-} |
|
32 |
- |
|
33 |
-type daemonDiscoveryReloader struct { |
|
34 |
- backend discovery.Backend |
|
35 |
- ticker *time.Ticker |
|
36 |
- term chan bool |
|
37 |
- readyCh chan struct{} |
|
38 |
-} |
|
39 |
- |
|
40 |
-func (d *daemonDiscoveryReloader) Watch(stopCh <-chan struct{}) (<-chan discovery.Entries, <-chan error) { |
|
41 |
- return d.backend.Watch(stopCh) |
|
42 |
-} |
|
43 |
- |
|
44 |
-func (d *daemonDiscoveryReloader) ReadyCh() <-chan struct{} { |
|
45 |
- return d.readyCh |
|
46 |
-} |
|
47 |
- |
|
48 |
-func discoveryOpts(clusterOpts map[string]string) (time.Duration, time.Duration, error) { |
|
49 |
- var ( |
|
50 |
- heartbeat = defaultDiscoveryHeartbeat |
|
51 |
- ttl = defaultDiscoveryTTLFactor * defaultDiscoveryHeartbeat |
|
52 |
- ) |
|
53 |
- |
|
54 |
- if hb, ok := clusterOpts["discovery.heartbeat"]; ok { |
|
55 |
- h, err := strconv.Atoi(hb) |
|
56 |
- if err != nil { |
|
57 |
- return time.Duration(0), time.Duration(0), err |
|
58 |
- } |
|
59 |
- |
|
60 |
- if h <= 0 { |
|
61 |
- return time.Duration(0), time.Duration(0), |
|
62 |
- fmt.Errorf("discovery.heartbeat must be positive") |
|
63 |
- } |
|
64 |
- |
|
65 |
- heartbeat = time.Duration(h) * time.Second |
|
66 |
- ttl = defaultDiscoveryTTLFactor * heartbeat |
|
67 |
- } |
|
68 |
- |
|
69 |
- if tstr, ok := clusterOpts["discovery.ttl"]; ok { |
|
70 |
- t, err := strconv.Atoi(tstr) |
|
71 |
- if err != nil { |
|
72 |
- return time.Duration(0), time.Duration(0), err |
|
73 |
- } |
|
74 |
- |
|
75 |
- if t <= 0 { |
|
76 |
- return time.Duration(0), time.Duration(0), |
|
77 |
- fmt.Errorf("discovery.ttl must be positive") |
|
78 |
- } |
|
79 |
- |
|
80 |
- ttl = time.Duration(t) * time.Second |
|
81 |
- |
|
82 |
- if _, ok := clusterOpts["discovery.heartbeat"]; !ok { |
|
83 |
- h := int(t / defaultDiscoveryTTLFactor) |
|
84 |
- heartbeat = time.Duration(h) * time.Second |
|
85 |
- } |
|
86 |
- |
|
87 |
- if ttl <= heartbeat { |
|
88 |
- return time.Duration(0), time.Duration(0), |
|
89 |
- fmt.Errorf("discovery.ttl timer must be greater than discovery.heartbeat") |
|
90 |
- } |
|
91 |
- } |
|
92 |
- |
|
93 |
- return heartbeat, ttl, nil |
|
94 |
-} |
|
95 |
- |
|
96 |
-// initDiscovery initializes the nodes discovery subsystem by connecting to the specified backend |
|
97 |
-// and starts a registration loop to advertise the current node under the specified address. |
|
98 |
-func initDiscovery(backendAddress, advertiseAddress string, clusterOpts map[string]string) (discoveryReloader, error) { |
|
99 |
- heartbeat, backend, err := parseDiscoveryOptions(backendAddress, clusterOpts) |
|
100 |
- if err != nil { |
|
101 |
- return nil, err |
|
102 |
- } |
|
103 |
- |
|
104 |
- reloader := &daemonDiscoveryReloader{ |
|
105 |
- backend: backend, |
|
106 |
- ticker: time.NewTicker(heartbeat), |
|
107 |
- term: make(chan bool), |
|
108 |
- readyCh: make(chan struct{}), |
|
109 |
- } |
|
110 |
- // We call Register() on the discovery backend in a loop for the whole lifetime of the daemon, |
|
111 |
- // but we never actually Watch() for nodes appearing and disappearing for the moment. |
|
112 |
- go reloader.advertiseHeartbeat(advertiseAddress) |
|
113 |
- return reloader, nil |
|
114 |
-} |
|
115 |
- |
|
116 |
-// advertiseHeartbeat registers the current node against the discovery backend using the specified |
|
117 |
-// address. The function never returns, as registration against the backend comes with a TTL and |
|
118 |
-// requires regular heartbeats. |
|
119 |
-func (d *daemonDiscoveryReloader) advertiseHeartbeat(address string) { |
|
120 |
- var ready bool |
|
121 |
- if err := d.initHeartbeat(address); err == nil { |
|
122 |
- ready = true |
|
123 |
- close(d.readyCh) |
|
124 |
- } |
|
125 |
- |
|
126 |
- for { |
|
127 |
- select { |
|
128 |
- case <-d.ticker.C: |
|
129 |
- if err := d.backend.Register(address); err != nil { |
|
130 |
- logrus.Warnf("Registering as %q in discovery failed: %v", address, err) |
|
131 |
- } else { |
|
132 |
- if !ready { |
|
133 |
- close(d.readyCh) |
|
134 |
- ready = true |
|
135 |
- } |
|
136 |
- } |
|
137 |
- case <-d.term: |
|
138 |
- return |
|
139 |
- } |
|
140 |
- } |
|
141 |
-} |
|
142 |
- |
|
143 |
-// initHeartbeat is used to do the first heartbeat. It uses a tight loop until |
|
144 |
-// either the timeout period is reached or the heartbeat is successful and returns. |
|
145 |
-func (d *daemonDiscoveryReloader) initHeartbeat(address string) error { |
|
146 |
- // Setup a short ticker until the first heartbeat has succeeded |
|
147 |
- t := time.NewTicker(500 * time.Millisecond) |
|
148 |
- defer t.Stop() |
|
149 |
- // timeout makes sure that after a period of time we stop being so aggressive trying to reach the discovery service |
|
150 |
- timeout := time.After(60 * time.Second) |
|
151 |
- |
|
152 |
- for { |
|
153 |
- select { |
|
154 |
- case <-timeout: |
|
155 |
- return errors.New("timeout waiting for initial discovery") |
|
156 |
- case <-d.term: |
|
157 |
- return errors.New("terminated") |
|
158 |
- case <-t.C: |
|
159 |
- if err := d.backend.Register(address); err == nil { |
|
160 |
- return nil |
|
161 |
- } |
|
162 |
- } |
|
163 |
- } |
|
164 |
-} |
|
165 |
- |
|
166 |
-// Reload makes the watcher to stop advertising and reconfigures it to advertise in a new address. |
|
167 |
-func (d *daemonDiscoveryReloader) Reload(backendAddress, advertiseAddress string, clusterOpts map[string]string) error { |
|
168 |
- d.Stop() |
|
169 |
- |
|
170 |
- heartbeat, backend, err := parseDiscoveryOptions(backendAddress, clusterOpts) |
|
171 |
- if err != nil { |
|
172 |
- return err |
|
173 |
- } |
|
174 |
- |
|
175 |
- d.backend = backend |
|
176 |
- d.ticker = time.NewTicker(heartbeat) |
|
177 |
- d.readyCh = make(chan struct{}) |
|
178 |
- |
|
179 |
- go d.advertiseHeartbeat(advertiseAddress) |
|
180 |
- return nil |
|
181 |
-} |
|
182 |
- |
|
183 |
-// Stop terminates the discovery advertising. |
|
184 |
-func (d *daemonDiscoveryReloader) Stop() { |
|
185 |
- d.ticker.Stop() |
|
186 |
- d.term <- true |
|
187 |
-} |
|
188 |
- |
|
189 |
-func parseDiscoveryOptions(backendAddress string, clusterOpts map[string]string) (time.Duration, discovery.Backend, error) { |
|
190 |
- heartbeat, ttl, err := discoveryOpts(clusterOpts) |
|
191 |
- if err != nil { |
|
192 |
- return 0, nil, err |
|
193 |
- } |
|
194 |
- |
|
195 |
- backend, err := discovery.New(backendAddress, heartbeat, ttl, clusterOpts) |
|
196 |
- if err != nil { |
|
197 |
- return 0, nil, err |
|
198 |
- } |
|
199 |
- return heartbeat, backend, nil |
|
200 |
-} |
|
201 |
- |
|
202 |
-// modifiedDiscoverySettings returns whether the discovery configuration has been modified or not. |
|
203 |
-func modifiedDiscoverySettings(config *Config, backendType, advertise string, clusterOpts map[string]string) bool { |
|
204 |
- if config.ClusterStore != backendType || config.ClusterAdvertise != advertise { |
|
205 |
- return true |
|
206 |
- } |
|
207 |
- |
|
208 |
- if (config.ClusterOpts == nil && clusterOpts == nil) || |
|
209 |
- (config.ClusterOpts == nil && len(clusterOpts) == 0) || |
|
210 |
- (len(config.ClusterOpts) == 0 && clusterOpts == nil) { |
|
211 |
- return false |
|
212 |
- } |
|
213 |
- |
|
214 |
- return !reflect.DeepEqual(config.ClusterOpts, clusterOpts) |
|
215 |
-} |
216 | 1 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,201 @@ |
0 |
+package discovery |
|
1 |
+ |
|
2 |
+import ( |
|
3 |
+ "errors" |
|
4 |
+ "fmt" |
|
5 |
+ "strconv" |
|
6 |
+ "time" |
|
7 |
+ |
|
8 |
+ "github.com/Sirupsen/logrus" |
|
9 |
+ "github.com/docker/docker/pkg/discovery" |
|
10 |
+ |
|
11 |
+ // Register the libkv backends for discovery. |
|
12 |
+ _ "github.com/docker/docker/pkg/discovery/kv" |
|
13 |
+) |
|
14 |
+ |
|
15 |
+const ( |
|
16 |
+ // defaultDiscoveryHeartbeat is the default value for discovery heartbeat interval. |
|
17 |
+ defaultDiscoveryHeartbeat = 20 * time.Second |
|
18 |
+ // defaultDiscoveryTTLFactor is the default TTL factor for discovery |
|
19 |
+ defaultDiscoveryTTLFactor = 3 |
|
20 |
+) |
|
21 |
+ |
|
22 |
+// ErrDiscoveryDisabled is an error returned if the discovery is disabled |
|
23 |
+var ErrDiscoveryDisabled = errors.New("discovery is disabled") |
|
24 |
+ |
|
25 |
+// Reloader is the discovery reloader of the daemon |
|
26 |
+type Reloader interface { |
|
27 |
+ discovery.Watcher |
|
28 |
+ Stop() |
|
29 |
+ Reload(backend, address string, clusterOpts map[string]string) error |
|
30 |
+ ReadyCh() <-chan struct{} |
|
31 |
+} |
|
32 |
+ |
|
33 |
+type daemonDiscoveryReloader struct { |
|
34 |
+ backend discovery.Backend |
|
35 |
+ ticker *time.Ticker |
|
36 |
+ term chan bool |
|
37 |
+ readyCh chan struct{} |
|
38 |
+} |
|
39 |
+ |
|
40 |
+func (d *daemonDiscoveryReloader) Watch(stopCh <-chan struct{}) (<-chan discovery.Entries, <-chan error) { |
|
41 |
+ return d.backend.Watch(stopCh) |
|
42 |
+} |
|
43 |
+ |
|
44 |
+func (d *daemonDiscoveryReloader) ReadyCh() <-chan struct{} { |
|
45 |
+ return d.readyCh |
|
46 |
+} |
|
47 |
+ |
|
48 |
+func discoveryOpts(clusterOpts map[string]string) (time.Duration, time.Duration, error) { |
|
49 |
+ var ( |
|
50 |
+ heartbeat = defaultDiscoveryHeartbeat |
|
51 |
+ ttl = defaultDiscoveryTTLFactor * defaultDiscoveryHeartbeat |
|
52 |
+ ) |
|
53 |
+ |
|
54 |
+ if hb, ok := clusterOpts["discovery.heartbeat"]; ok { |
|
55 |
+ h, err := strconv.Atoi(hb) |
|
56 |
+ if err != nil { |
|
57 |
+ return time.Duration(0), time.Duration(0), err |
|
58 |
+ } |
|
59 |
+ |
|
60 |
+ if h <= 0 { |
|
61 |
+ return time.Duration(0), time.Duration(0), |
|
62 |
+ fmt.Errorf("discovery.heartbeat must be positive") |
|
63 |
+ } |
|
64 |
+ |
|
65 |
+ heartbeat = time.Duration(h) * time.Second |
|
66 |
+ ttl = defaultDiscoveryTTLFactor * heartbeat |
|
67 |
+ } |
|
68 |
+ |
|
69 |
+ if tstr, ok := clusterOpts["discovery.ttl"]; ok { |
|
70 |
+ t, err := strconv.Atoi(tstr) |
|
71 |
+ if err != nil { |
|
72 |
+ return time.Duration(0), time.Duration(0), err |
|
73 |
+ } |
|
74 |
+ |
|
75 |
+ if t <= 0 { |
|
76 |
+ return time.Duration(0), time.Duration(0), |
|
77 |
+ fmt.Errorf("discovery.ttl must be positive") |
|
78 |
+ } |
|
79 |
+ |
|
80 |
+ ttl = time.Duration(t) * time.Second |
|
81 |
+ |
|
82 |
+ if _, ok := clusterOpts["discovery.heartbeat"]; !ok { |
|
83 |
+ h := int(t / defaultDiscoveryTTLFactor) |
|
84 |
+ heartbeat = time.Duration(h) * time.Second |
|
85 |
+ } |
|
86 |
+ |
|
87 |
+ if ttl <= heartbeat { |
|
88 |
+ return time.Duration(0), time.Duration(0), |
|
89 |
+ fmt.Errorf("discovery.ttl timer must be greater than discovery.heartbeat") |
|
90 |
+ } |
|
91 |
+ } |
|
92 |
+ |
|
93 |
+ return heartbeat, ttl, nil |
|
94 |
+} |
|
95 |
+ |
|
96 |
+// Init initializes the nodes discovery subsystem by connecting to the specified backend |
|
97 |
+// and starts a registration loop to advertise the current node under the specified address. |
|
98 |
+func Init(backendAddress, advertiseAddress string, clusterOpts map[string]string) (Reloader, error) { |
|
99 |
+ heartbeat, backend, err := parseDiscoveryOptions(backendAddress, clusterOpts) |
|
100 |
+ if err != nil { |
|
101 |
+ return nil, err |
|
102 |
+ } |
|
103 |
+ |
|
104 |
+ reloader := &daemonDiscoveryReloader{ |
|
105 |
+ backend: backend, |
|
106 |
+ ticker: time.NewTicker(heartbeat), |
|
107 |
+ term: make(chan bool), |
|
108 |
+ readyCh: make(chan struct{}), |
|
109 |
+ } |
|
110 |
+ // We call Register() on the discovery backend in a loop for the whole lifetime of the daemon, |
|
111 |
+ // but we never actually Watch() for nodes appearing and disappearing for the moment. |
|
112 |
+ go reloader.advertiseHeartbeat(advertiseAddress) |
|
113 |
+ return reloader, nil |
|
114 |
+} |
|
115 |
+ |
|
116 |
+// advertiseHeartbeat registers the current node against the discovery backend using the specified |
|
117 |
+// address. The function never returns, as registration against the backend comes with a TTL and |
|
118 |
+// requires regular heartbeats. |
|
119 |
+func (d *daemonDiscoveryReloader) advertiseHeartbeat(address string) { |
|
120 |
+ var ready bool |
|
121 |
+ if err := d.initHeartbeat(address); err == nil { |
|
122 |
+ ready = true |
|
123 |
+ close(d.readyCh) |
|
124 |
+ } |
|
125 |
+ |
|
126 |
+ for { |
|
127 |
+ select { |
|
128 |
+ case <-d.ticker.C: |
|
129 |
+ if err := d.backend.Register(address); err != nil { |
|
130 |
+ logrus.Warnf("Registering as %q in discovery failed: %v", address, err) |
|
131 |
+ } else { |
|
132 |
+ if !ready { |
|
133 |
+ close(d.readyCh) |
|
134 |
+ ready = true |
|
135 |
+ } |
|
136 |
+ } |
|
137 |
+ case <-d.term: |
|
138 |
+ return |
|
139 |
+ } |
|
140 |
+ } |
|
141 |
+} |
|
142 |
+ |
|
143 |
+// initHeartbeat is used to do the first heartbeat. It uses a tight loop until |
|
144 |
+// either the timeout period is reached or the heartbeat is successful and returns. |
|
145 |
+func (d *daemonDiscoveryReloader) initHeartbeat(address string) error { |
|
146 |
+ // Setup a short ticker until the first heartbeat has succeeded |
|
147 |
+ t := time.NewTicker(500 * time.Millisecond) |
|
148 |
+ defer t.Stop() |
|
149 |
+ // timeout makes sure that after a period of time we stop being so aggressive trying to reach the discovery service |
|
150 |
+ timeout := time.After(60 * time.Second) |
|
151 |
+ |
|
152 |
+ for { |
|
153 |
+ select { |
|
154 |
+ case <-timeout: |
|
155 |
+ return errors.New("timeout waiting for initial discovery") |
|
156 |
+ case <-d.term: |
|
157 |
+ return errors.New("terminated") |
|
158 |
+ case <-t.C: |
|
159 |
+ if err := d.backend.Register(address); err == nil { |
|
160 |
+ return nil |
|
161 |
+ } |
|
162 |
+ } |
|
163 |
+ } |
|
164 |
+} |
|
165 |
+ |
|
166 |
+// Reload makes the watcher to stop advertising and reconfigures it to advertise in a new address. |
|
167 |
+func (d *daemonDiscoveryReloader) Reload(backendAddress, advertiseAddress string, clusterOpts map[string]string) error { |
|
168 |
+ d.Stop() |
|
169 |
+ |
|
170 |
+ heartbeat, backend, err := parseDiscoveryOptions(backendAddress, clusterOpts) |
|
171 |
+ if err != nil { |
|
172 |
+ return err |
|
173 |
+ } |
|
174 |
+ |
|
175 |
+ d.backend = backend |
|
176 |
+ d.ticker = time.NewTicker(heartbeat) |
|
177 |
+ d.readyCh = make(chan struct{}) |
|
178 |
+ |
|
179 |
+ go d.advertiseHeartbeat(advertiseAddress) |
|
180 |
+ return nil |
|
181 |
+} |
|
182 |
+ |
|
183 |
+// Stop terminates the discovery advertising. |
|
184 |
+func (d *daemonDiscoveryReloader) Stop() { |
|
185 |
+ d.ticker.Stop() |
|
186 |
+ d.term <- true |
|
187 |
+} |
|
188 |
+ |
|
189 |
+func parseDiscoveryOptions(backendAddress string, clusterOpts map[string]string) (time.Duration, discovery.Backend, error) { |
|
190 |
+ heartbeat, ttl, err := discoveryOpts(clusterOpts) |
|
191 |
+ if err != nil { |
|
192 |
+ return 0, nil, err |
|
193 |
+ } |
|
194 |
+ |
|
195 |
+ backend, err := discovery.New(backendAddress, heartbeat, ttl, clusterOpts) |
|
196 |
+ if err != nil { |
|
197 |
+ return 0, nil, err |
|
198 |
+ } |
|
199 |
+ return heartbeat, backend, nil |
|
200 |
+} |
0 | 201 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,103 @@ |
0 |
+package discovery |
|
1 |
+ |
|
2 |
+import ( |
|
3 |
+ "testing" |
|
4 |
+ "time" |
|
5 |
+) |
|
6 |
+ |
|
7 |
+func TestDiscoveryOpts(t *testing.T) { |
|
8 |
+ clusterOpts := map[string]string{"discovery.heartbeat": "10", "discovery.ttl": "5"} |
|
9 |
+ heartbeat, ttl, err := discoveryOpts(clusterOpts) |
|
10 |
+ if err == nil { |
|
11 |
+ t.Fatalf("discovery.ttl < discovery.heartbeat must fail") |
|
12 |
+ } |
|
13 |
+ |
|
14 |
+ clusterOpts = map[string]string{"discovery.heartbeat": "10", "discovery.ttl": "10"} |
|
15 |
+ heartbeat, ttl, err = discoveryOpts(clusterOpts) |
|
16 |
+ if err == nil { |
|
17 |
+ t.Fatalf("discovery.ttl == discovery.heartbeat must fail") |
|
18 |
+ } |
|
19 |
+ |
|
20 |
+ clusterOpts = map[string]string{"discovery.heartbeat": "-10", "discovery.ttl": "10"} |
|
21 |
+ heartbeat, ttl, err = discoveryOpts(clusterOpts) |
|
22 |
+ if err == nil { |
|
23 |
+ t.Fatalf("negative discovery.heartbeat must fail") |
|
24 |
+ } |
|
25 |
+ |
|
26 |
+ clusterOpts = map[string]string{"discovery.heartbeat": "10", "discovery.ttl": "-10"} |
|
27 |
+ heartbeat, ttl, err = discoveryOpts(clusterOpts) |
|
28 |
+ if err == nil { |
|
29 |
+ t.Fatalf("negative discovery.ttl must fail") |
|
30 |
+ } |
|
31 |
+ |
|
32 |
+ clusterOpts = map[string]string{"discovery.heartbeat": "invalid"} |
|
33 |
+ heartbeat, ttl, err = discoveryOpts(clusterOpts) |
|
34 |
+ if err == nil { |
|
35 |
+ t.Fatalf("invalid discovery.heartbeat must fail") |
|
36 |
+ } |
|
37 |
+ |
|
38 |
+ clusterOpts = map[string]string{"discovery.ttl": "invalid"} |
|
39 |
+ heartbeat, ttl, err = discoveryOpts(clusterOpts) |
|
40 |
+ if err == nil { |
|
41 |
+ t.Fatalf("invalid discovery.ttl must fail") |
|
42 |
+ } |
|
43 |
+ |
|
44 |
+ clusterOpts = map[string]string{"discovery.heartbeat": "10", "discovery.ttl": "20"} |
|
45 |
+ heartbeat, ttl, err = discoveryOpts(clusterOpts) |
|
46 |
+ if err != nil { |
|
47 |
+ t.Fatal(err) |
|
48 |
+ } |
|
49 |
+ |
|
50 |
+ if heartbeat != 10*time.Second { |
|
51 |
+ t.Fatalf("Heartbeat - Expected : %v, Actual : %v", 10*time.Second, heartbeat) |
|
52 |
+ } |
|
53 |
+ |
|
54 |
+ if ttl != 20*time.Second { |
|
55 |
+ t.Fatalf("TTL - Expected : %v, Actual : %v", 20*time.Second, ttl) |
|
56 |
+ } |
|
57 |
+ |
|
58 |
+ clusterOpts = map[string]string{"discovery.heartbeat": "10"} |
|
59 |
+ heartbeat, ttl, err = discoveryOpts(clusterOpts) |
|
60 |
+ if err != nil { |
|
61 |
+ t.Fatal(err) |
|
62 |
+ } |
|
63 |
+ |
|
64 |
+ if heartbeat != 10*time.Second { |
|
65 |
+ t.Fatalf("Heartbeat - Expected : %v, Actual : %v", 10*time.Second, heartbeat) |
|
66 |
+ } |
|
67 |
+ |
|
68 |
+ expected := 10 * defaultDiscoveryTTLFactor * time.Second |
|
69 |
+ if ttl != expected { |
|
70 |
+ t.Fatalf("TTL - Expected : %v, Actual : %v", expected, ttl) |
|
71 |
+ } |
|
72 |
+ |
|
73 |
+ clusterOpts = map[string]string{"discovery.ttl": "30"} |
|
74 |
+ heartbeat, ttl, err = discoveryOpts(clusterOpts) |
|
75 |
+ if err != nil { |
|
76 |
+ t.Fatal(err) |
|
77 |
+ } |
|
78 |
+ |
|
79 |
+ if ttl != 30*time.Second { |
|
80 |
+ t.Fatalf("TTL - Expected : %v, Actual : %v", 30*time.Second, ttl) |
|
81 |
+ } |
|
82 |
+ |
|
83 |
+ expected = 30 * time.Second / defaultDiscoveryTTLFactor |
|
84 |
+ if heartbeat != expected { |
|
85 |
+ t.Fatalf("Heartbeat - Expected : %v, Actual : %v", expected, heartbeat) |
|
86 |
+ } |
|
87 |
+ |
|
88 |
+ clusterOpts = map[string]string{} |
|
89 |
+ heartbeat, ttl, err = discoveryOpts(clusterOpts) |
|
90 |
+ if err != nil { |
|
91 |
+ t.Fatal(err) |
|
92 |
+ } |
|
93 |
+ |
|
94 |
+ if heartbeat != defaultDiscoveryHeartbeat { |
|
95 |
+ t.Fatalf("Heartbeat - Expected : %v, Actual : %v", defaultDiscoveryHeartbeat, heartbeat) |
|
96 |
+ } |
|
97 |
+ |
|
98 |
+ expected = defaultDiscoveryHeartbeat * defaultDiscoveryTTLFactor |
|
99 |
+ if ttl != expected { |
|
100 |
+ t.Fatalf("TTL - Expected : %v, Actual : %v", expected, ttl) |
|
101 |
+ } |
|
102 |
+} |
0 | 103 |
deleted file mode 100644 |
... | ... |
@@ -1,164 +0,0 @@ |
1 |
-package daemon |
|
2 |
- |
|
3 |
-import ( |
|
4 |
- "testing" |
|
5 |
- "time" |
|
6 |
-) |
|
7 |
- |
|
8 |
-func TestDiscoveryOpts(t *testing.T) { |
|
9 |
- clusterOpts := map[string]string{"discovery.heartbeat": "10", "discovery.ttl": "5"} |
|
10 |
- heartbeat, ttl, err := discoveryOpts(clusterOpts) |
|
11 |
- if err == nil { |
|
12 |
- t.Fatalf("discovery.ttl < discovery.heartbeat must fail") |
|
13 |
- } |
|
14 |
- |
|
15 |
- clusterOpts = map[string]string{"discovery.heartbeat": "10", "discovery.ttl": "10"} |
|
16 |
- heartbeat, ttl, err = discoveryOpts(clusterOpts) |
|
17 |
- if err == nil { |
|
18 |
- t.Fatalf("discovery.ttl == discovery.heartbeat must fail") |
|
19 |
- } |
|
20 |
- |
|
21 |
- clusterOpts = map[string]string{"discovery.heartbeat": "-10", "discovery.ttl": "10"} |
|
22 |
- heartbeat, ttl, err = discoveryOpts(clusterOpts) |
|
23 |
- if err == nil { |
|
24 |
- t.Fatalf("negative discovery.heartbeat must fail") |
|
25 |
- } |
|
26 |
- |
|
27 |
- clusterOpts = map[string]string{"discovery.heartbeat": "10", "discovery.ttl": "-10"} |
|
28 |
- heartbeat, ttl, err = discoveryOpts(clusterOpts) |
|
29 |
- if err == nil { |
|
30 |
- t.Fatalf("negative discovery.ttl must fail") |
|
31 |
- } |
|
32 |
- |
|
33 |
- clusterOpts = map[string]string{"discovery.heartbeat": "invalid"} |
|
34 |
- heartbeat, ttl, err = discoveryOpts(clusterOpts) |
|
35 |
- if err == nil { |
|
36 |
- t.Fatalf("invalid discovery.heartbeat must fail") |
|
37 |
- } |
|
38 |
- |
|
39 |
- clusterOpts = map[string]string{"discovery.ttl": "invalid"} |
|
40 |
- heartbeat, ttl, err = discoveryOpts(clusterOpts) |
|
41 |
- if err == nil { |
|
42 |
- t.Fatalf("invalid discovery.ttl must fail") |
|
43 |
- } |
|
44 |
- |
|
45 |
- clusterOpts = map[string]string{"discovery.heartbeat": "10", "discovery.ttl": "20"} |
|
46 |
- heartbeat, ttl, err = discoveryOpts(clusterOpts) |
|
47 |
- if err != nil { |
|
48 |
- t.Fatal(err) |
|
49 |
- } |
|
50 |
- |
|
51 |
- if heartbeat != 10*time.Second { |
|
52 |
- t.Fatalf("Heartbeat - Expected : %v, Actual : %v", 10*time.Second, heartbeat) |
|
53 |
- } |
|
54 |
- |
|
55 |
- if ttl != 20*time.Second { |
|
56 |
- t.Fatalf("TTL - Expected : %v, Actual : %v", 20*time.Second, ttl) |
|
57 |
- } |
|
58 |
- |
|
59 |
- clusterOpts = map[string]string{"discovery.heartbeat": "10"} |
|
60 |
- heartbeat, ttl, err = discoveryOpts(clusterOpts) |
|
61 |
- if err != nil { |
|
62 |
- t.Fatal(err) |
|
63 |
- } |
|
64 |
- |
|
65 |
- if heartbeat != 10*time.Second { |
|
66 |
- t.Fatalf("Heartbeat - Expected : %v, Actual : %v", 10*time.Second, heartbeat) |
|
67 |
- } |
|
68 |
- |
|
69 |
- expected := 10 * defaultDiscoveryTTLFactor * time.Second |
|
70 |
- if ttl != expected { |
|
71 |
- t.Fatalf("TTL - Expected : %v, Actual : %v", expected, ttl) |
|
72 |
- } |
|
73 |
- |
|
74 |
- clusterOpts = map[string]string{"discovery.ttl": "30"} |
|
75 |
- heartbeat, ttl, err = discoveryOpts(clusterOpts) |
|
76 |
- if err != nil { |
|
77 |
- t.Fatal(err) |
|
78 |
- } |
|
79 |
- |
|
80 |
- if ttl != 30*time.Second { |
|
81 |
- t.Fatalf("TTL - Expected : %v, Actual : %v", 30*time.Second, ttl) |
|
82 |
- } |
|
83 |
- |
|
84 |
- expected = 30 * time.Second / defaultDiscoveryTTLFactor |
|
85 |
- if heartbeat != expected { |
|
86 |
- t.Fatalf("Heartbeat - Expected : %v, Actual : %v", expected, heartbeat) |
|
87 |
- } |
|
88 |
- |
|
89 |
- clusterOpts = map[string]string{} |
|
90 |
- heartbeat, ttl, err = discoveryOpts(clusterOpts) |
|
91 |
- if err != nil { |
|
92 |
- t.Fatal(err) |
|
93 |
- } |
|
94 |
- |
|
95 |
- if heartbeat != defaultDiscoveryHeartbeat { |
|
96 |
- t.Fatalf("Heartbeat - Expected : %v, Actual : %v", defaultDiscoveryHeartbeat, heartbeat) |
|
97 |
- } |
|
98 |
- |
|
99 |
- expected = defaultDiscoveryHeartbeat * defaultDiscoveryTTLFactor |
|
100 |
- if ttl != expected { |
|
101 |
- t.Fatalf("TTL - Expected : %v, Actual : %v", expected, ttl) |
|
102 |
- } |
|
103 |
-} |
|
104 |
- |
|
105 |
-func TestModifiedDiscoverySettings(t *testing.T) { |
|
106 |
- cases := []struct { |
|
107 |
- current *Config |
|
108 |
- modified *Config |
|
109 |
- expected bool |
|
110 |
- }{ |
|
111 |
- { |
|
112 |
- current: discoveryConfig("foo", "bar", map[string]string{}), |
|
113 |
- modified: discoveryConfig("foo", "bar", map[string]string{}), |
|
114 |
- expected: false, |
|
115 |
- }, |
|
116 |
- { |
|
117 |
- current: discoveryConfig("foo", "bar", map[string]string{"foo": "bar"}), |
|
118 |
- modified: discoveryConfig("foo", "bar", map[string]string{"foo": "bar"}), |
|
119 |
- expected: false, |
|
120 |
- }, |
|
121 |
- { |
|
122 |
- current: discoveryConfig("foo", "bar", map[string]string{}), |
|
123 |
- modified: discoveryConfig("foo", "bar", nil), |
|
124 |
- expected: false, |
|
125 |
- }, |
|
126 |
- { |
|
127 |
- current: discoveryConfig("foo", "bar", nil), |
|
128 |
- modified: discoveryConfig("foo", "bar", map[string]string{}), |
|
129 |
- expected: false, |
|
130 |
- }, |
|
131 |
- { |
|
132 |
- current: discoveryConfig("foo", "bar", nil), |
|
133 |
- modified: discoveryConfig("baz", "bar", nil), |
|
134 |
- expected: true, |
|
135 |
- }, |
|
136 |
- { |
|
137 |
- current: discoveryConfig("foo", "bar", nil), |
|
138 |
- modified: discoveryConfig("foo", "baz", nil), |
|
139 |
- expected: true, |
|
140 |
- }, |
|
141 |
- { |
|
142 |
- current: discoveryConfig("foo", "bar", nil), |
|
143 |
- modified: discoveryConfig("foo", "bar", map[string]string{"foo": "bar"}), |
|
144 |
- expected: true, |
|
145 |
- }, |
|
146 |
- } |
|
147 |
- |
|
148 |
- for _, c := range cases { |
|
149 |
- got := modifiedDiscoverySettings(c.current, c.modified.ClusterStore, c.modified.ClusterAdvertise, c.modified.ClusterOpts) |
|
150 |
- if c.expected != got { |
|
151 |
- t.Fatalf("expected %v, got %v: current config %v, new config %v", c.expected, got, c.current, c.modified) |
|
152 |
- } |
|
153 |
- } |
|
154 |
-} |
|
155 |
- |
|
156 |
-func discoveryConfig(backendAddr, advertiseAddr string, opts map[string]string) *Config { |
|
157 |
- return &Config{ |
|
158 |
- CommonConfig: CommonConfig{ |
|
159 |
- ClusterStore: backendAddr, |
|
160 |
- ClusterAdvertise: advertiseAddr, |
|
161 |
- ClusterOpts: opts, |
|
162 |
- }, |
|
163 |
- } |
|
164 |
-} |