diff --git a/cmd/dockerd/config_unix.go b/cmd/dockerd/config_unix.go index 8e741aa904..ba37121e96 100644 --- a/cmd/dockerd/config_unix.go +++ b/cmd/dockerd/config_unix.go @@ -24,7 +24,7 @@ func installConfigFlags(conf *config.Config, flags *pflag.FlagSet) { // Then platform-specific install flags flags.BoolVar(&conf.EnableSelinuxSupport, "selinux-enabled", false, "Enable selinux support") - flags.Var(opts.NewUlimitOpt(&conf.Ulimits), "default-ulimit", "Default ulimits for containers") + flags.Var(opts.NewNamedUlimitOpt("default-ulimits", &conf.Ulimits), "default-ulimit", "Default ulimits for containers") flags.BoolVar(&conf.BridgeConfig.EnableIPTables, "iptables", true, "Enable addition of iptables rules") flags.BoolVar(&conf.BridgeConfig.EnableIPForward, "ip-forward", true, "Enable net.ipv4.ip_forward") flags.BoolVar(&conf.BridgeConfig.EnableIPMasq, "ip-masq", true, "Enable IP masquerading") diff --git a/daemon/config/config_unix_test.go b/daemon/config/config_unix_test.go index 3e7d1be94a..9e52cb70fe 100644 --- a/daemon/config/config_unix_test.go +++ b/daemon/config/config_unix_test.go @@ -3,21 +3,18 @@ package config import ( - "io/ioutil" - "runtime" - "testing" + + "github.com/docker/docker/opts" + "github.com/docker/docker/pkg/testutil/tempfile" + "github.com/docker/go-units" + "github.com/spf13/pflag" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) -func TestDaemonConfigurationMerge(t *testing.T) { - f, err := ioutil.TempFile("", "docker-config-") - if err != nil { - t.Fatal(err) - } - - configFile := f.Name() - - f.Write([]byte(` +func TestGetConflictFreeConfiguration(t *testing.T) { + configFileData := string([]byte(` { "debug": true, "default-ulimits": { @@ -32,7 +29,49 @@ func TestDaemonConfigurationMerge(t *testing.T) { } }`)) - f.Close() + file := tempfile.NewTempFile(t, "docker-config", configFileData) + defer file.Remove() + + flags := pflag.NewFlagSet("test", pflag.ContinueOnError) + var debug bool + flags.BoolVarP(&debug, "debug", "D", false, "") + flags.Var(opts.NewNamedUlimitOpt("default-ulimits", nil), "default-ulimit", "") + flags.Var(opts.NewNamedMapOpts("log-opts", nil, nil), "log-opt", "") + + cc, err := getConflictFreeConfiguration(file.Name(), flags) + require.NoError(t, err) + + assert.True(t, cc.Debug) + + expectedUlimits := map[string]*units.Ulimit{ + "nofile": { + Name: "nofile", + Hard: 2048, + Soft: 1024, + }, + } + + assert.Equal(t, expectedUlimits, cc.Ulimits) +} + +func TestDaemonConfigurationMerge(t *testing.T) { + configFileData := string([]byte(` + { + "debug": true, + "default-ulimits": { + "nofile": { + "Name": "nofile", + "Hard": 2048, + "Soft": 1024 + } + }, + "log-opts": { + "tag": "test_tag" + } + }`)) + + file := tempfile.NewTempFile(t, "docker-config", configFileData) + defer file.Remove() c := &Config{ CommonConfig: CommonConfig{ @@ -44,66 +83,55 @@ func TestDaemonConfigurationMerge(t *testing.T) { }, } - cc, err := MergeDaemonConfigurations(c, nil, configFile) - if err != nil { - t.Fatal(err) - } - if !cc.Debug { - t.Fatalf("expected %v, got %v\n", true, cc.Debug) - } - if !cc.AutoRestart { - t.Fatalf("expected %v, got %v\n", true, cc.AutoRestart) - } - if cc.LogConfig.Type != "syslog" { - t.Fatalf("expected syslog config, got %q\n", cc.LogConfig) + flags := pflag.NewFlagSet("test", pflag.ContinueOnError) + + var debug bool + flags.BoolVarP(&debug, "debug", "D", false, "") + flags.Var(opts.NewNamedUlimitOpt("default-ulimits", nil), "default-ulimit", "") + flags.Var(opts.NewNamedMapOpts("log-opts", nil, nil), "log-opt", "") + + cc, err := MergeDaemonConfigurations(c, flags, file.Name()) + require.NoError(t, err) + + assert.True(t, cc.Debug) + assert.True(t, cc.AutoRestart) + + expectedLogConfig := LogConfig{ + Type: "syslog", + Config: map[string]string{"tag": "test_tag"}, } - if configValue, OK := cc.LogConfig.Config["tag"]; !OK { - t.Fatal("expected syslog config attributes, got nil\n") - } else { - if configValue != "test_tag" { - t.Fatalf("expected syslog config attributes 'tag=test_tag', got 'tag=%s'\n", configValue) - } + assert.Equal(t, expectedLogConfig, cc.LogConfig) + + expectedUlimits := map[string]*units.Ulimit{ + "nofile": { + Name: "nofile", + Hard: 2048, + Soft: 1024, + }, } - if cc.Ulimits == nil { - t.Fatal("expected default ulimit config, got nil\n") - } else { - if _, OK := cc.Ulimits["nofile"]; OK { - if cc.Ulimits["nofile"].Name != "nofile" || - cc.Ulimits["nofile"].Hard != 2048 || - cc.Ulimits["nofile"].Soft != 1024 { - 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) - } - } else { - t.Fatal("expected default ulimit name nofile, got nil\n") - } - } + assert.Equal(t, expectedUlimits, cc.Ulimits) } func TestDaemonConfigurationMergeShmSize(t *testing.T) { - if runtime.GOOS == "solaris" { - t.Skip("ShmSize not supported on Solaris\n") - } - f, err := ioutil.TempFile("", "docker-config-") - if err != nil { - t.Fatal(err) - } - - configFile := f.Name() - - f.Write([]byte(` + data := string([]byte(` { "default-shm-size": "1g" }`)) - f.Close() + file := tempfile.NewTempFile(t, "docker-config", data) + defer file.Remove() c := &Config{} - cc, err := MergeDaemonConfigurations(c, nil, configFile) - if err != nil { - t.Fatal(err) - } + + flags := pflag.NewFlagSet("test", pflag.ContinueOnError) + shmSize := opts.MemBytes(DefaultShmSize) + flags.Var(&shmSize, "default-shm-size", "") + + cc, err := MergeDaemonConfigurations(c, flags, file.Name()) + require.NoError(t, err) + expectedValue := 1 * 1024 * 1024 * 1024 if cc.ShmSize.Value() != int64(expectedValue) { t.Fatalf("expected default shm size %d, got %d", expectedValue, cc.ShmSize.Value()) diff --git a/daemon/config/config_windows_test.go b/daemon/config/config_windows_test.go index 1c435c630a..92ee8e4acd 100644 --- a/daemon/config/config_windows_test.go +++ b/daemon/config/config_windows_test.go @@ -5,6 +5,11 @@ package config import ( "io/ioutil" "testing" + + "github.com/docker/docker/opts" + "github.com/spf13/pflag" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestDaemonConfigurationMerge(t *testing.T) { @@ -35,25 +40,21 @@ func TestDaemonConfigurationMerge(t *testing.T) { }, } - cc, err := MergeDaemonConfigurations(c, nil, configFile) - if err != nil { - t.Fatal(err) - } - if !cc.Debug { - t.Fatalf("expected %v, got %v\n", true, cc.Debug) - } - if !cc.AutoRestart { - t.Fatalf("expected %v, got %v\n", true, cc.AutoRestart) - } - if cc.LogConfig.Type != "syslog" { - t.Fatalf("expected syslog config, got %q\n", cc.LogConfig) + flags := pflag.NewFlagSet("test", pflag.ContinueOnError) + var debug bool + flags.BoolVarP(&debug, "debug", "D", false, "") + flags.Var(opts.NewNamedMapOpts("log-opts", nil, nil), "log-opt", "") + + cc, err := MergeDaemonConfigurations(c, flags, configFile) + require.NoError(t, err) + + assert.True(t, cc.Debug) + assert.True(t, cc.AutoRestart) + + expectedLogConfig := LogConfig{ + Type: "syslog", + Config: map[string]string{"tag": "test_tag"}, } - if configValue, OK := cc.LogConfig.Config["tag"]; !OK { - t.Fatal("expected syslog config attributes, got nil\n") - } else { - if configValue != "test_tag" { - t.Fatalf("expected syslog config attributes 'tag=test_tag', got 'tag=%s'\n", configValue) - } - } + assert.Equal(t, expectedLogConfig, cc.LogConfig) } diff --git a/opts/ulimit.go b/opts/ulimit.go index 5adfe30851..a2a65fcd21 100644 --- a/opts/ulimit.go +++ b/opts/ulimit.go @@ -55,3 +55,27 @@ func (o *UlimitOpt) GetList() []*units.Ulimit { func (o *UlimitOpt) Type() string { return "ulimit" } + +// NamedUlimitOpt defines a named map of Ulimits +type NamedUlimitOpt struct { + name string + UlimitOpt +} + +var _ NamedOption = &NamedUlimitOpt{} + +// NewNamedUlimitOpt creates a new NamedUlimitOpt +func NewNamedUlimitOpt(name string, ref *map[string]*units.Ulimit) *NamedUlimitOpt { + if ref == nil { + ref = &map[string]*units.Ulimit{} + } + return &NamedUlimitOpt{ + name: name, + UlimitOpt: *NewUlimitOpt(ref), + } +} + +// Name returns the option name +func (o *NamedUlimitOpt) Name() string { + return o.name +}