github.com/skanehira/moby@v17.12.1-ce-rc2+incompatible/daemon/config/config_test.go (about) 1 package config 2 3 import ( 4 "io/ioutil" 5 "os" 6 "strings" 7 "testing" 8 9 "github.com/docker/docker/daemon/discovery" 10 "github.com/docker/docker/internal/testutil" 11 "github.com/docker/docker/opts" 12 "github.com/gotestyourself/gotestyourself/fs" 13 "github.com/spf13/pflag" 14 "github.com/stretchr/testify/assert" 15 ) 16 17 func TestDaemonConfigurationNotFound(t *testing.T) { 18 _, err := MergeDaemonConfigurations(&Config{}, nil, "/tmp/foo-bar-baz-docker") 19 if err == nil || !os.IsNotExist(err) { 20 t.Fatalf("expected does not exist error, got %v", err) 21 } 22 } 23 24 func TestDaemonBrokenConfiguration(t *testing.T) { 25 f, err := ioutil.TempFile("", "docker-config-") 26 if err != nil { 27 t.Fatal(err) 28 } 29 30 configFile := f.Name() 31 f.Write([]byte(`{"Debug": tru`)) 32 f.Close() 33 34 _, err = MergeDaemonConfigurations(&Config{}, nil, configFile) 35 if err == nil { 36 t.Fatalf("expected error, got %v", err) 37 } 38 } 39 40 func TestParseClusterAdvertiseSettings(t *testing.T) { 41 _, err := ParseClusterAdvertiseSettings("something", "") 42 if err != discovery.ErrDiscoveryDisabled { 43 t.Fatalf("expected discovery disabled error, got %v\n", err) 44 } 45 46 _, err = ParseClusterAdvertiseSettings("", "something") 47 if err == nil { 48 t.Fatalf("expected discovery store error, got %v\n", err) 49 } 50 51 _, err = ParseClusterAdvertiseSettings("etcd", "127.0.0.1:8080") 52 if err != nil { 53 t.Fatal(err) 54 } 55 } 56 57 func TestFindConfigurationConflicts(t *testing.T) { 58 config := map[string]interface{}{"authorization-plugins": "foobar"} 59 flags := pflag.NewFlagSet("test", pflag.ContinueOnError) 60 61 flags.String("authorization-plugins", "", "") 62 assert.NoError(t, flags.Set("authorization-plugins", "asdf")) 63 64 testutil.ErrorContains(t, 65 findConfigurationConflicts(config, flags), 66 "authorization-plugins: (from flag: asdf, from file: foobar)") 67 } 68 69 func TestFindConfigurationConflictsWithNamedOptions(t *testing.T) { 70 config := map[string]interface{}{"hosts": []string{"qwer"}} 71 flags := pflag.NewFlagSet("test", pflag.ContinueOnError) 72 73 var hosts []string 74 flags.VarP(opts.NewNamedListOptsRef("hosts", &hosts, opts.ValidateHost), "host", "H", "Daemon socket(s) to connect to") 75 assert.NoError(t, flags.Set("host", "tcp://127.0.0.1:4444")) 76 assert.NoError(t, flags.Set("host", "unix:///var/run/docker.sock")) 77 78 testutil.ErrorContains(t, findConfigurationConflicts(config, flags), "hosts") 79 } 80 81 func TestDaemonConfigurationMergeConflicts(t *testing.T) { 82 f, err := ioutil.TempFile("", "docker-config-") 83 if err != nil { 84 t.Fatal(err) 85 } 86 87 configFile := f.Name() 88 f.Write([]byte(`{"debug": true}`)) 89 f.Close() 90 91 flags := pflag.NewFlagSet("test", pflag.ContinueOnError) 92 flags.Bool("debug", false, "") 93 flags.Set("debug", "false") 94 95 _, err = MergeDaemonConfigurations(&Config{}, flags, configFile) 96 if err == nil { 97 t.Fatal("expected error, got nil") 98 } 99 if !strings.Contains(err.Error(), "debug") { 100 t.Fatalf("expected debug conflict, got %v", err) 101 } 102 } 103 104 func TestDaemonConfigurationMergeConcurrent(t *testing.T) { 105 f, err := ioutil.TempFile("", "docker-config-") 106 if err != nil { 107 t.Fatal(err) 108 } 109 110 configFile := f.Name() 111 f.Write([]byte(`{"max-concurrent-downloads": 1}`)) 112 f.Close() 113 114 _, err = MergeDaemonConfigurations(&Config{}, nil, configFile) 115 if err != nil { 116 t.Fatal("expected error, got nil") 117 } 118 } 119 120 func TestDaemonConfigurationMergeConcurrentError(t *testing.T) { 121 f, err := ioutil.TempFile("", "docker-config-") 122 if err != nil { 123 t.Fatal(err) 124 } 125 126 configFile := f.Name() 127 f.Write([]byte(`{"max-concurrent-downloads": -1}`)) 128 f.Close() 129 130 _, err = MergeDaemonConfigurations(&Config{}, nil, configFile) 131 if err == nil { 132 t.Fatalf("expected no error, got error %v", err) 133 } 134 } 135 136 func TestDaemonConfigurationMergeConflictsWithInnerStructs(t *testing.T) { 137 f, err := ioutil.TempFile("", "docker-config-") 138 if err != nil { 139 t.Fatal(err) 140 } 141 142 configFile := f.Name() 143 f.Write([]byte(`{"tlscacert": "/etc/certificates/ca.pem"}`)) 144 f.Close() 145 146 flags := pflag.NewFlagSet("test", pflag.ContinueOnError) 147 flags.String("tlscacert", "", "") 148 flags.Set("tlscacert", "~/.docker/ca.pem") 149 150 _, err = MergeDaemonConfigurations(&Config{}, flags, configFile) 151 if err == nil { 152 t.Fatal("expected error, got nil") 153 } 154 if !strings.Contains(err.Error(), "tlscacert") { 155 t.Fatalf("expected tlscacert conflict, got %v", err) 156 } 157 } 158 159 func TestFindConfigurationConflictsWithUnknownKeys(t *testing.T) { 160 config := map[string]interface{}{"tls-verify": "true"} 161 flags := pflag.NewFlagSet("test", pflag.ContinueOnError) 162 163 flags.Bool("tlsverify", false, "") 164 err := findConfigurationConflicts(config, flags) 165 if err == nil { 166 t.Fatal("expected error, got nil") 167 } 168 if !strings.Contains(err.Error(), "the following directives don't match any configuration option: tls-verify") { 169 t.Fatalf("expected tls-verify conflict, got %v", err) 170 } 171 } 172 173 func TestFindConfigurationConflictsWithMergedValues(t *testing.T) { 174 var hosts []string 175 config := map[string]interface{}{"hosts": "tcp://127.0.0.1:2345"} 176 flags := pflag.NewFlagSet("base", pflag.ContinueOnError) 177 flags.VarP(opts.NewNamedListOptsRef("hosts", &hosts, nil), "host", "H", "") 178 179 err := findConfigurationConflicts(config, flags) 180 if err != nil { 181 t.Fatal(err) 182 } 183 184 flags.Set("host", "unix:///var/run/docker.sock") 185 err = findConfigurationConflicts(config, flags) 186 if err == nil { 187 t.Fatal("expected error, got nil") 188 } 189 if !strings.Contains(err.Error(), "hosts: (from flag: [unix:///var/run/docker.sock], from file: tcp://127.0.0.1:2345)") { 190 t.Fatalf("expected hosts conflict, got %v", err) 191 } 192 } 193 194 func TestValidateConfigurationErrors(t *testing.T) { 195 minusNumber := -10 196 testCases := []struct { 197 config *Config 198 }{ 199 { 200 config: &Config{ 201 CommonConfig: CommonConfig{ 202 Labels: []string{"one"}, 203 }, 204 }, 205 }, 206 { 207 config: &Config{ 208 CommonConfig: CommonConfig{ 209 Labels: []string{"foo=bar", "one"}, 210 }, 211 }, 212 }, 213 { 214 config: &Config{ 215 CommonConfig: CommonConfig{ 216 DNS: []string{"1.1.1.1o"}, 217 }, 218 }, 219 }, 220 { 221 config: &Config{ 222 CommonConfig: CommonConfig{ 223 DNS: []string{"2.2.2.2", "1.1.1.1o"}, 224 }, 225 }, 226 }, 227 { 228 config: &Config{ 229 CommonConfig: CommonConfig{ 230 DNSSearch: []string{"123456"}, 231 }, 232 }, 233 }, 234 { 235 config: &Config{ 236 CommonConfig: CommonConfig{ 237 DNSSearch: []string{"a.b.c", "123456"}, 238 }, 239 }, 240 }, 241 { 242 config: &Config{ 243 CommonConfig: CommonConfig{ 244 MaxConcurrentDownloads: &minusNumber, 245 // This is weird... 246 ValuesSet: map[string]interface{}{ 247 "max-concurrent-downloads": -1, 248 }, 249 }, 250 }, 251 }, 252 { 253 config: &Config{ 254 CommonConfig: CommonConfig{ 255 MaxConcurrentUploads: &minusNumber, 256 // This is weird... 257 ValuesSet: map[string]interface{}{ 258 "max-concurrent-uploads": -1, 259 }, 260 }, 261 }, 262 }, 263 { 264 config: &Config{ 265 CommonConfig: CommonConfig{ 266 NodeGenericResources: []string{"foo"}, 267 }, 268 }, 269 }, 270 { 271 config: &Config{ 272 CommonConfig: CommonConfig{ 273 NodeGenericResources: []string{"foo=bar", "foo=1"}, 274 }, 275 }, 276 }, 277 } 278 for _, tc := range testCases { 279 err := Validate(tc.config) 280 if err == nil { 281 t.Fatalf("expected error, got nil for config %v", tc.config) 282 } 283 } 284 } 285 286 func TestValidateConfiguration(t *testing.T) { 287 minusNumber := 4 288 testCases := []struct { 289 config *Config 290 }{ 291 { 292 config: &Config{ 293 CommonConfig: CommonConfig{ 294 Labels: []string{"one=two"}, 295 }, 296 }, 297 }, 298 { 299 config: &Config{ 300 CommonConfig: CommonConfig{ 301 DNS: []string{"1.1.1.1"}, 302 }, 303 }, 304 }, 305 { 306 config: &Config{ 307 CommonConfig: CommonConfig{ 308 DNSSearch: []string{"a.b.c"}, 309 }, 310 }, 311 }, 312 { 313 config: &Config{ 314 CommonConfig: CommonConfig{ 315 MaxConcurrentDownloads: &minusNumber, 316 // This is weird... 317 ValuesSet: map[string]interface{}{ 318 "max-concurrent-downloads": -1, 319 }, 320 }, 321 }, 322 }, 323 { 324 config: &Config{ 325 CommonConfig: CommonConfig{ 326 MaxConcurrentUploads: &minusNumber, 327 // This is weird... 328 ValuesSet: map[string]interface{}{ 329 "max-concurrent-uploads": -1, 330 }, 331 }, 332 }, 333 }, 334 { 335 config: &Config{ 336 CommonConfig: CommonConfig{ 337 NodeGenericResources: []string{"foo=bar", "foo=baz"}, 338 }, 339 }, 340 }, 341 { 342 config: &Config{ 343 CommonConfig: CommonConfig{ 344 NodeGenericResources: []string{"foo=1"}, 345 }, 346 }, 347 }, 348 } 349 for _, tc := range testCases { 350 err := Validate(tc.config) 351 if err != nil { 352 t.Fatalf("expected no error, got error %v", err) 353 } 354 } 355 } 356 357 func TestModifiedDiscoverySettings(t *testing.T) { 358 cases := []struct { 359 current *Config 360 modified *Config 361 expected bool 362 }{ 363 { 364 current: discoveryConfig("foo", "bar", map[string]string{}), 365 modified: discoveryConfig("foo", "bar", map[string]string{}), 366 expected: false, 367 }, 368 { 369 current: discoveryConfig("foo", "bar", map[string]string{"foo": "bar"}), 370 modified: discoveryConfig("foo", "bar", map[string]string{"foo": "bar"}), 371 expected: false, 372 }, 373 { 374 current: discoveryConfig("foo", "bar", map[string]string{}), 375 modified: discoveryConfig("foo", "bar", nil), 376 expected: false, 377 }, 378 { 379 current: discoveryConfig("foo", "bar", nil), 380 modified: discoveryConfig("foo", "bar", map[string]string{}), 381 expected: false, 382 }, 383 { 384 current: discoveryConfig("foo", "bar", nil), 385 modified: discoveryConfig("baz", "bar", nil), 386 expected: true, 387 }, 388 { 389 current: discoveryConfig("foo", "bar", nil), 390 modified: discoveryConfig("foo", "baz", nil), 391 expected: true, 392 }, 393 { 394 current: discoveryConfig("foo", "bar", nil), 395 modified: discoveryConfig("foo", "bar", map[string]string{"foo": "bar"}), 396 expected: true, 397 }, 398 } 399 400 for _, c := range cases { 401 got := ModifiedDiscoverySettings(c.current, c.modified.ClusterStore, c.modified.ClusterAdvertise, c.modified.ClusterOpts) 402 if c.expected != got { 403 t.Fatalf("expected %v, got %v: current config %v, new config %v", c.expected, got, c.current, c.modified) 404 } 405 } 406 } 407 408 func discoveryConfig(backendAddr, advertiseAddr string, opts map[string]string) *Config { 409 return &Config{ 410 CommonConfig: CommonConfig{ 411 ClusterStore: backendAddr, 412 ClusterAdvertise: advertiseAddr, 413 ClusterOpts: opts, 414 }, 415 } 416 } 417 418 // TestReloadSetConfigFileNotExist tests that when `--config-file` is set 419 // and it doesn't exist the `Reload` function returns an error. 420 func TestReloadSetConfigFileNotExist(t *testing.T) { 421 configFile := "/tmp/blabla/not/exists/config.json" 422 flags := pflag.NewFlagSet("test", pflag.ContinueOnError) 423 flags.String("config-file", "", "") 424 flags.Set("config-file", configFile) 425 426 err := Reload(configFile, flags, func(c *Config) {}) 427 assert.Error(t, err) 428 testutil.ErrorContains(t, err, "unable to configure the Docker daemon with file") 429 } 430 431 // TestReloadDefaultConfigNotExist tests that if the default configuration file 432 // doesn't exist the daemon still will be reloaded. 433 func TestReloadDefaultConfigNotExist(t *testing.T) { 434 reloaded := false 435 configFile := "/etc/docker/daemon.json" 436 flags := pflag.NewFlagSet("test", pflag.ContinueOnError) 437 flags.String("config-file", configFile, "") 438 err := Reload(configFile, flags, func(c *Config) { 439 reloaded = true 440 }) 441 assert.Nil(t, err) 442 assert.True(t, reloaded) 443 } 444 445 // TestReloadBadDefaultConfig tests that when `--config-file` is not set 446 // and the default configuration file exists and is bad return an error 447 func TestReloadBadDefaultConfig(t *testing.T) { 448 f, err := ioutil.TempFile("", "docker-config-") 449 if err != nil { 450 t.Fatal(err) 451 } 452 453 configFile := f.Name() 454 f.Write([]byte(`{wrong: "configuration"}`)) 455 f.Close() 456 457 flags := pflag.NewFlagSet("test", pflag.ContinueOnError) 458 flags.String("config-file", configFile, "") 459 err = Reload(configFile, flags, func(c *Config) {}) 460 assert.Error(t, err) 461 testutil.ErrorContains(t, err, "unable to configure the Docker daemon with file") 462 } 463 464 func TestReloadWithConflictingLabels(t *testing.T) { 465 tempFile := fs.NewFile(t, "config", fs.WithContent(`{"labels":["foo=bar","foo=baz"]}`)) 466 defer tempFile.Remove() 467 configFile := tempFile.Path() 468 469 var lbls []string 470 flags := pflag.NewFlagSet("test", pflag.ContinueOnError) 471 flags.String("config-file", configFile, "") 472 flags.StringSlice("labels", lbls, "") 473 err := Reload(configFile, flags, func(c *Config) {}) 474 testutil.ErrorContains(t, err, "conflict labels for foo=baz and foo=bar") 475 } 476 477 func TestReloadWithDuplicateLabels(t *testing.T) { 478 tempFile := fs.NewFile(t, "config", fs.WithContent(`{"labels":["foo=the-same","foo=the-same"]}`)) 479 defer tempFile.Remove() 480 configFile := tempFile.Path() 481 482 var lbls []string 483 flags := pflag.NewFlagSet("test", pflag.ContinueOnError) 484 flags.String("config-file", configFile, "") 485 flags.StringSlice("labels", lbls, "") 486 err := Reload(configFile, flags, func(c *Config) {}) 487 assert.NoError(t, err) 488 }