Browse code

Extract daemon configuration and discovery to their own package

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>

Vincent Demeester authored on 2017/01/23 20:23:07
Showing 39 changed files
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 34
new file mode 100644
... ...
@@ -0,0 +1,9 @@
0
+package main
1
+
2
+import (
3
+	"github.com/docker/docker/daemon/config"
4
+	"github.com/spf13/pflag"
5
+)
6
+
7
+func attachExperimentalFlags(conf *config.Config, cmd *pflag.FlagSet) {
8
+}
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
-}
90 1
deleted file mode 100644
... ...
@@ -1,8 +0,0 @@
1
-package daemon
2
-
3
-import (
4
-	"github.com/spf13/pflag"
5
-)
6
-
7
-func (config *Config) attachExperimentalFlags(cmd *pflag.FlagSet) {
8
-}
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
-}