123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412 |
- package daemon // import "github.com/docker/docker/daemon"
- import (
- "os"
- "sort"
- "testing"
- "github.com/containerd/log"
- "github.com/docker/docker/daemon/config"
- "github.com/docker/docker/daemon/images"
- "github.com/docker/docker/libnetwork"
- "github.com/docker/docker/registry"
- "gotest.tools/v3/assert"
- is "gotest.tools/v3/assert/cmp"
- )
- // muteLogs suppresses logs that are generated during the test
- func muteLogs(t *testing.T) {
- t.Helper()
- err := log.SetLevel("error")
- if err != nil {
- t.Error(err)
- }
- }
- func newDaemonForReloadT(t *testing.T, cfg *config.Config) *Daemon {
- t.Helper()
- daemon := &Daemon{
- imageService: images.NewImageService(images.ImageServiceConfig{}),
- }
- var err error
- daemon.registryService, err = registry.NewService(registry.ServiceOptions{})
- assert.Assert(t, err)
- daemon.configStore.Store(&configStore{Config: *cfg})
- return daemon
- }
- func TestDaemonReloadLabels(t *testing.T) {
- daemon := newDaemonForReloadT(t, &config.Config{
- CommonConfig: config.CommonConfig{
- Labels: []string{"foo:bar"},
- },
- })
- muteLogs(t)
- valuesSets := make(map[string]interface{})
- valuesSets["labels"] = "foo:baz"
- newConfig := &config.Config{
- CommonConfig: config.CommonConfig{
- Labels: []string{"foo:baz"},
- ValuesSet: valuesSets,
- },
- }
- if err := daemon.Reload(newConfig); err != nil {
- t.Fatal(err)
- }
- label := daemon.config().Labels[0]
- if label != "foo:baz" {
- t.Fatalf("Expected daemon label `foo:baz`, got %s", label)
- }
- }
- func TestDaemonReloadAllowNondistributableArtifacts(t *testing.T) {
- daemon := newDaemonForReloadT(t, &config.Config{})
- muteLogs(t)
- var err error
- // Initialize daemon with some registries.
- daemon.registryService, err = registry.NewService(registry.ServiceOptions{
- AllowNondistributableArtifacts: []string{
- "127.0.0.0/8",
- "10.10.1.11:5000",
- "10.10.1.22:5000", // This will be removed during reload.
- "docker1.com",
- "docker2.com", // This will be removed during reload.
- },
- })
- if err != nil {
- t.Fatal(err)
- }
- registries := []string{
- "127.0.0.0/8",
- "10.10.1.11:5000",
- "10.10.1.33:5000", // This will be added during reload.
- "docker1.com",
- "docker3.com", // This will be added during reload.
- }
- newConfig := &config.Config{
- CommonConfig: config.CommonConfig{
- ServiceOptions: registry.ServiceOptions{
- AllowNondistributableArtifacts: registries,
- },
- ValuesSet: map[string]interface{}{
- "allow-nondistributable-artifacts": registries,
- },
- },
- }
- if err := daemon.Reload(newConfig); err != nil {
- t.Fatal(err)
- }
- var actual []string
- serviceConfig := daemon.registryService.ServiceConfig()
- for _, value := range serviceConfig.AllowNondistributableArtifactsCIDRs {
- actual = append(actual, value.String())
- }
- actual = append(actual, serviceConfig.AllowNondistributableArtifactsHostnames...)
- sort.Strings(registries)
- sort.Strings(actual)
- assert.Check(t, is.DeepEqual(registries, actual))
- }
- func TestDaemonReloadMirrors(t *testing.T) {
- daemon := &Daemon{
- imageService: images.NewImageService(images.ImageServiceConfig{}),
- }
- muteLogs(t)
- var err error
- daemon.registryService, err = registry.NewService(registry.ServiceOptions{
- InsecureRegistries: []string{},
- Mirrors: []string{
- "https://mirror.test1.example.com",
- "https://mirror.test2.example.com", // this will be removed when reloading
- "https://mirror.test3.example.com", // this will be removed when reloading
- },
- })
- if err != nil {
- t.Fatal(err)
- }
- type pair struct {
- valid bool
- mirrors []string
- after []string
- }
- loadMirrors := []pair{
- {
- valid: false,
- mirrors: []string{"10.10.1.11:5000"}, // this mirror is invalid
- after: []string{},
- },
- {
- valid: false,
- mirrors: []string{"mirror.test1.com"}, // this mirror is invalid
- after: []string{},
- },
- {
- valid: false,
- mirrors: []string{"10.10.1.11:5000", "mirror.test1.example.com"}, // mirrors are invalid
- after: []string{},
- },
- {
- valid: true,
- mirrors: []string{"https://mirror.test1.example.com", "https://mirror.test4.example.com"},
- after: []string{"https://mirror.test1.example.com/", "https://mirror.test4.example.com/"},
- },
- }
- for _, value := range loadMirrors {
- valuesSets := make(map[string]interface{})
- valuesSets["registry-mirrors"] = value.mirrors
- newConfig := &config.Config{
- CommonConfig: config.CommonConfig{
- ServiceOptions: registry.ServiceOptions{
- Mirrors: value.mirrors,
- },
- ValuesSet: valuesSets,
- },
- }
- err := daemon.Reload(newConfig)
- if !value.valid && err == nil {
- // mirrors should be invalid, should be a non-nil error
- t.Fatalf("Expected daemon reload error with invalid mirrors: %s, while get nil", value.mirrors)
- }
- if value.valid {
- if err != nil {
- // mirrors should be valid, should be no error
- t.Fatal(err)
- }
- registryService := daemon.registryService.ServiceConfig()
- if len(registryService.Mirrors) != len(value.after) {
- t.Fatalf("Expected %d daemon mirrors %s while get %d with %s",
- len(value.after),
- value.after,
- len(registryService.Mirrors),
- registryService.Mirrors)
- }
- dataMap := map[string]struct{}{}
- for _, mirror := range registryService.Mirrors {
- if _, exist := dataMap[mirror]; !exist {
- dataMap[mirror] = struct{}{}
- }
- }
- for _, address := range value.after {
- if _, exist := dataMap[address]; !exist {
- t.Fatalf("Expected %s in daemon mirrors, while get none", address)
- }
- }
- }
- }
- }
- func TestDaemonReloadInsecureRegistries(t *testing.T) {
- daemon := &Daemon{
- imageService: images.NewImageService(images.ImageServiceConfig{}),
- }
- muteLogs(t)
- var err error
- // initialize daemon with existing insecure registries: "127.0.0.0/8", "10.10.1.11:5000", "10.10.1.22:5000"
- daemon.registryService, err = registry.NewService(registry.ServiceOptions{
- InsecureRegistries: []string{
- "127.0.0.0/8",
- "10.10.1.11:5000",
- "10.10.1.22:5000", // this will be removed when reloading
- "docker1.example.com",
- "docker2.example.com", // this will be removed when reloading
- },
- })
- if err != nil {
- t.Fatal(err)
- }
- insecureRegistries := []string{
- "127.0.0.0/8", // this will be kept
- "10.10.1.11:5000", // this will be kept
- "10.10.1.33:5000", // this will be newly added
- "docker1.example.com", // this will be kept
- "docker3.example.com", // this will be newly added
- }
- mirrors := []string{
- "https://mirror.test.example.com",
- }
- valuesSets := make(map[string]interface{})
- valuesSets["insecure-registries"] = insecureRegistries
- valuesSets["registry-mirrors"] = mirrors
- newConfig := &config.Config{
- CommonConfig: config.CommonConfig{
- ServiceOptions: registry.ServiceOptions{
- InsecureRegistries: insecureRegistries,
- Mirrors: mirrors,
- },
- ValuesSet: valuesSets,
- },
- }
- if err := daemon.Reload(newConfig); err != nil {
- t.Fatal(err)
- }
- // After Reload, daemon.RegistryService will be changed which is useful
- // for registry communication in daemon.
- registries := daemon.registryService.ServiceConfig()
- // After Reload(), newConfig has come to registries.InsecureRegistryCIDRs and registries.IndexConfigs in daemon.
- // Then collect registries.InsecureRegistryCIDRs in dataMap.
- // When collecting, we need to convert CIDRS into string as a key,
- // while the times of key appears as value.
- dataMap := map[string]int{}
- for _, value := range registries.InsecureRegistryCIDRs {
- if _, ok := dataMap[value.String()]; !ok {
- dataMap[value.String()] = 1
- } else {
- dataMap[value.String()]++
- }
- }
- for _, value := range registries.IndexConfigs {
- if _, ok := dataMap[value.Name]; !ok {
- dataMap[value.Name] = 1
- } else {
- dataMap[value.Name]++
- }
- }
- // Finally compare dataMap with the original insecureRegistries.
- // Each value in insecureRegistries should appear in daemon's insecure registries,
- // and each can only appear exactly ONCE.
- for _, r := range insecureRegistries {
- if value, ok := dataMap[r]; !ok {
- t.Fatalf("Expected daemon insecure registry %s, got none", r)
- } else if value != 1 {
- t.Fatalf("Expected only 1 daemon insecure registry %s, got %d", r, value)
- }
- }
- // assert if "10.10.1.22:5000" is removed when reloading
- if value, ok := dataMap["10.10.1.22:5000"]; ok {
- t.Fatalf("Expected no insecure registry of 10.10.1.22:5000, got %d", value)
- }
- // assert if "docker2.com" is removed when reloading
- if value, ok := dataMap["docker2.example.com"]; ok {
- t.Fatalf("Expected no insecure registry of docker2.com, got %d", value)
- }
- }
- func TestDaemonReloadNotAffectOthers(t *testing.T) {
- daemon := newDaemonForReloadT(t, &config.Config{
- CommonConfig: config.CommonConfig{
- Labels: []string{"foo:bar"},
- Debug: true,
- },
- })
- muteLogs(t)
- valuesSets := make(map[string]interface{})
- valuesSets["labels"] = "foo:baz"
- newConfig := &config.Config{
- CommonConfig: config.CommonConfig{
- Labels: []string{"foo:baz"},
- ValuesSet: valuesSets,
- },
- }
- if err := daemon.Reload(newConfig); err != nil {
- t.Fatal(err)
- }
- label := daemon.config().Labels[0]
- if label != "foo:baz" {
- t.Fatalf("Expected daemon label `foo:baz`, got %s", label)
- }
- debug := daemon.config().Debug
- if !debug {
- t.Fatal("Expected debug 'enabled', got 'disabled'")
- }
- }
- func TestDaemonReloadNetworkDiagnosticPort(t *testing.T) {
- if os.Getuid() != 0 {
- t.Skip("root required")
- }
- daemon := newDaemonForReloadT(t, &config.Config{})
- enableConfig := &config.Config{
- CommonConfig: config.CommonConfig{
- NetworkDiagnosticPort: 2000,
- ValuesSet: map[string]interface{}{
- "network-diagnostic-port": 2000,
- },
- },
- }
- netOptions, err := daemon.networkOptions(&config.Config{}, nil, nil)
- if err != nil {
- t.Fatal(err)
- }
- controller, err := libnetwork.New(netOptions...)
- if err != nil {
- t.Fatal(err)
- }
- daemon.netController = controller
- // Enable/Disable the server for some iterations
- for i := 0; i < 10; i++ {
- enableConfig.CommonConfig.NetworkDiagnosticPort++
- if err := daemon.Reload(enableConfig); err != nil {
- t.Fatal(err)
- }
- // Check that the diagnostic is enabled
- if !daemon.netController.IsDiagnosticEnabled() {
- t.Fatalf("diagnostic should be enabled")
- }
- // Reload
- if err := daemon.Reload(&config.Config{}); err != nil {
- t.Fatal(err)
- }
- // Check that the diagnostic is disabled
- if daemon.netController.IsDiagnosticEnabled() {
- t.Fatalf("diagnostic should be disabled")
- }
- }
- enableConfig.CommonConfig.NetworkDiagnosticPort++
- // 2 times the enable should not create problems
- if err := daemon.Reload(enableConfig); err != nil {
- t.Fatal(err)
- }
- // Check that the diagnostic is enabled
- if !daemon.netController.IsDiagnosticEnabled() {
- t.Fatalf("diagnostic should be enable")
- }
- // Check that another reload does not cause issues
- if err := daemon.Reload(enableConfig); err != nil {
- t.Fatal(err)
- }
- // Check that the diagnostic is enable
- if !daemon.netController.IsDiagnosticEnabled() {
- t.Fatalf("diagnostic should be enable")
- }
- }
|