github.com/docker/docker@v299999999.0.0-20200612211812-aaf470eca7b5+incompatible/daemon/reload_test.go (about)

     1  package daemon // import "github.com/docker/docker/daemon"
     2  
     3  import (
     4  	"os"
     5  	"reflect"
     6  	"sort"
     7  	"testing"
     8  	"time"
     9  
    10  	"github.com/docker/docker/daemon/config"
    11  	"github.com/docker/docker/daemon/images"
    12  	"github.com/docker/docker/pkg/discovery"
    13  	_ "github.com/docker/docker/pkg/discovery/memory"
    14  	"github.com/docker/docker/registry"
    15  	"github.com/docker/libnetwork"
    16  	"github.com/sirupsen/logrus"
    17  	"gotest.tools/v3/assert"
    18  	is "gotest.tools/v3/assert/cmp"
    19  )
    20  
    21  // muteLogs suppresses logs that are generated during the test
    22  func muteLogs() {
    23  	logrus.SetLevel(logrus.ErrorLevel)
    24  }
    25  
    26  func TestDaemonReloadLabels(t *testing.T) {
    27  	daemon := &Daemon{
    28  		configStore: &config.Config{
    29  			CommonConfig: config.CommonConfig{
    30  				Labels: []string{"foo:bar"},
    31  			},
    32  		},
    33  		imageService: images.NewImageService(images.ImageServiceConfig{}),
    34  	}
    35  	muteLogs()
    36  
    37  	valuesSets := make(map[string]interface{})
    38  	valuesSets["labels"] = "foo:baz"
    39  	newConfig := &config.Config{
    40  		CommonConfig: config.CommonConfig{
    41  			Labels:    []string{"foo:baz"},
    42  			ValuesSet: valuesSets,
    43  		},
    44  	}
    45  
    46  	if err := daemon.Reload(newConfig); err != nil {
    47  		t.Fatal(err)
    48  	}
    49  
    50  	label := daemon.configStore.Labels[0]
    51  	if label != "foo:baz" {
    52  		t.Fatalf("Expected daemon label `foo:baz`, got %s", label)
    53  	}
    54  }
    55  
    56  func TestDaemonReloadAllowNondistributableArtifacts(t *testing.T) {
    57  	daemon := &Daemon{
    58  		configStore:  &config.Config{},
    59  		imageService: images.NewImageService(images.ImageServiceConfig{}),
    60  	}
    61  	muteLogs()
    62  
    63  	var err error
    64  	// Initialize daemon with some registries.
    65  	daemon.RegistryService, err = registry.NewService(registry.ServiceOptions{
    66  		AllowNondistributableArtifacts: []string{
    67  			"127.0.0.0/8",
    68  			"10.10.1.11:5000",
    69  			"10.10.1.22:5000", // This will be removed during reload.
    70  			"docker1.com",
    71  			"docker2.com", // This will be removed during reload.
    72  		},
    73  	})
    74  	if err != nil {
    75  		t.Fatal(err)
    76  	}
    77  
    78  	registries := []string{
    79  		"127.0.0.0/8",
    80  		"10.10.1.11:5000",
    81  		"10.10.1.33:5000", // This will be added during reload.
    82  		"docker1.com",
    83  		"docker3.com", // This will be added during reload.
    84  	}
    85  
    86  	newConfig := &config.Config{
    87  		CommonConfig: config.CommonConfig{
    88  			ServiceOptions: registry.ServiceOptions{
    89  				AllowNondistributableArtifacts: registries,
    90  			},
    91  			ValuesSet: map[string]interface{}{
    92  				"allow-nondistributable-artifacts": registries,
    93  			},
    94  		},
    95  	}
    96  
    97  	if err := daemon.Reload(newConfig); err != nil {
    98  		t.Fatal(err)
    99  	}
   100  
   101  	var actual []string
   102  	serviceConfig := daemon.RegistryService.ServiceConfig()
   103  	for _, value := range serviceConfig.AllowNondistributableArtifactsCIDRs {
   104  		actual = append(actual, value.String())
   105  	}
   106  	actual = append(actual, serviceConfig.AllowNondistributableArtifactsHostnames...)
   107  
   108  	sort.Strings(registries)
   109  	sort.Strings(actual)
   110  	assert.Check(t, is.DeepEqual(registries, actual))
   111  }
   112  
   113  func TestDaemonReloadMirrors(t *testing.T) {
   114  	daemon := &Daemon{
   115  		imageService: images.NewImageService(images.ImageServiceConfig{}),
   116  	}
   117  	muteLogs()
   118  
   119  	var err error
   120  	daemon.RegistryService, err = registry.NewService(registry.ServiceOptions{
   121  		InsecureRegistries: []string{},
   122  		Mirrors: []string{
   123  			"https://mirror.test1.com",
   124  			"https://mirror.test2.com", // this will be removed when reloading
   125  			"https://mirror.test3.com", // this will be removed when reloading
   126  		},
   127  	})
   128  	if err != nil {
   129  		t.Fatal(err)
   130  	}
   131  
   132  	daemon.configStore = &config.Config{}
   133  
   134  	type pair struct {
   135  		valid   bool
   136  		mirrors []string
   137  		after   []string
   138  	}
   139  
   140  	loadMirrors := []pair{
   141  		{
   142  			valid:   false,
   143  			mirrors: []string{"10.10.1.11:5000"}, // this mirror is invalid
   144  			after:   []string{},
   145  		},
   146  		{
   147  			valid:   false,
   148  			mirrors: []string{"mirror.test1.com"}, // this mirror is invalid
   149  			after:   []string{},
   150  		},
   151  		{
   152  			valid:   false,
   153  			mirrors: []string{"10.10.1.11:5000", "mirror.test1.com"}, // mirrors are invalid
   154  			after:   []string{},
   155  		},
   156  		{
   157  			valid:   true,
   158  			mirrors: []string{"https://mirror.test1.com", "https://mirror.test4.com"},
   159  			after:   []string{"https://mirror.test1.com/", "https://mirror.test4.com/"},
   160  		},
   161  	}
   162  
   163  	for _, value := range loadMirrors {
   164  		valuesSets := make(map[string]interface{})
   165  		valuesSets["registry-mirrors"] = value.mirrors
   166  
   167  		newConfig := &config.Config{
   168  			CommonConfig: config.CommonConfig{
   169  				ServiceOptions: registry.ServiceOptions{
   170  					Mirrors: value.mirrors,
   171  				},
   172  				ValuesSet: valuesSets,
   173  			},
   174  		}
   175  
   176  		err := daemon.Reload(newConfig)
   177  		if !value.valid && err == nil {
   178  			// mirrors should be invalid, should be a non-nil error
   179  			t.Fatalf("Expected daemon reload error with invalid mirrors: %s, while get nil", value.mirrors)
   180  		}
   181  
   182  		if value.valid {
   183  			if err != nil {
   184  				// mirrors should be valid, should be no error
   185  				t.Fatal(err)
   186  			}
   187  			registryService := daemon.RegistryService.ServiceConfig()
   188  
   189  			if len(registryService.Mirrors) != len(value.after) {
   190  				t.Fatalf("Expected %d daemon mirrors %s while get %d with %s",
   191  					len(value.after),
   192  					value.after,
   193  					len(registryService.Mirrors),
   194  					registryService.Mirrors)
   195  			}
   196  
   197  			dataMap := map[string]struct{}{}
   198  
   199  			for _, mirror := range registryService.Mirrors {
   200  				if _, exist := dataMap[mirror]; !exist {
   201  					dataMap[mirror] = struct{}{}
   202  				}
   203  			}
   204  
   205  			for _, address := range value.after {
   206  				if _, exist := dataMap[address]; !exist {
   207  					t.Fatalf("Expected %s in daemon mirrors, while get none", address)
   208  				}
   209  			}
   210  		}
   211  	}
   212  }
   213  
   214  func TestDaemonReloadInsecureRegistries(t *testing.T) {
   215  	daemon := &Daemon{
   216  		imageService: images.NewImageService(images.ImageServiceConfig{}),
   217  	}
   218  	muteLogs()
   219  
   220  	var err error
   221  	// initialize daemon with existing insecure registries: "127.0.0.0/8", "10.10.1.11:5000", "10.10.1.22:5000"
   222  	daemon.RegistryService, err = registry.NewService(registry.ServiceOptions{
   223  		InsecureRegistries: []string{
   224  			"127.0.0.0/8",
   225  			"10.10.1.11:5000",
   226  			"10.10.1.22:5000", // this will be removed when reloading
   227  			"docker1.com",
   228  			"docker2.com", // this will be removed when reloading
   229  		},
   230  	})
   231  	if err != nil {
   232  		t.Fatal(err)
   233  	}
   234  
   235  	daemon.configStore = &config.Config{}
   236  
   237  	insecureRegistries := []string{
   238  		"127.0.0.0/8",     // this will be kept
   239  		"10.10.1.11:5000", // this will be kept
   240  		"10.10.1.33:5000", // this will be newly added
   241  		"docker1.com",     // this will be kept
   242  		"docker3.com",     // this will be newly added
   243  	}
   244  
   245  	valuesSets := make(map[string]interface{})
   246  	valuesSets["insecure-registries"] = insecureRegistries
   247  
   248  	newConfig := &config.Config{
   249  		CommonConfig: config.CommonConfig{
   250  			ServiceOptions: registry.ServiceOptions{
   251  				InsecureRegistries: insecureRegistries,
   252  			},
   253  			ValuesSet: valuesSets,
   254  		},
   255  	}
   256  
   257  	if err := daemon.Reload(newConfig); err != nil {
   258  		t.Fatal(err)
   259  	}
   260  
   261  	// After Reload, daemon.RegistryService will be changed which is useful
   262  	// for registry communication in daemon.
   263  	registries := daemon.RegistryService.ServiceConfig()
   264  
   265  	// After Reload(), newConfig has come to registries.InsecureRegistryCIDRs and registries.IndexConfigs in daemon.
   266  	// Then collect registries.InsecureRegistryCIDRs in dataMap.
   267  	// When collecting, we need to convert CIDRS into string as a key,
   268  	// while the times of key appears as value.
   269  	dataMap := map[string]int{}
   270  	for _, value := range registries.InsecureRegistryCIDRs {
   271  		if _, ok := dataMap[value.String()]; !ok {
   272  			dataMap[value.String()] = 1
   273  		} else {
   274  			dataMap[value.String()]++
   275  		}
   276  	}
   277  
   278  	for _, value := range registries.IndexConfigs {
   279  		if _, ok := dataMap[value.Name]; !ok {
   280  			dataMap[value.Name] = 1
   281  		} else {
   282  			dataMap[value.Name]++
   283  		}
   284  	}
   285  
   286  	// Finally compare dataMap with the original insecureRegistries.
   287  	// Each value in insecureRegistries should appear in daemon's insecure registries,
   288  	// and each can only appear exactly ONCE.
   289  	for _, r := range insecureRegistries {
   290  		if value, ok := dataMap[r]; !ok {
   291  			t.Fatalf("Expected daemon insecure registry %s, got none", r)
   292  		} else if value != 1 {
   293  			t.Fatalf("Expected only 1 daemon insecure registry %s, got %d", r, value)
   294  		}
   295  	}
   296  
   297  	// assert if "10.10.1.22:5000" is removed when reloading
   298  	if value, ok := dataMap["10.10.1.22:5000"]; ok {
   299  		t.Fatalf("Expected no insecure registry of 10.10.1.22:5000, got %d", value)
   300  	}
   301  
   302  	// assert if "docker2.com" is removed when reloading
   303  	if value, ok := dataMap["docker2.com"]; ok {
   304  		t.Fatalf("Expected no insecure registry of docker2.com, got %d", value)
   305  	}
   306  }
   307  
   308  func TestDaemonReloadNotAffectOthers(t *testing.T) {
   309  	daemon := &Daemon{
   310  		imageService: images.NewImageService(images.ImageServiceConfig{}),
   311  	}
   312  	muteLogs()
   313  
   314  	daemon.configStore = &config.Config{
   315  		CommonConfig: config.CommonConfig{
   316  			Labels: []string{"foo:bar"},
   317  			Debug:  true,
   318  		},
   319  	}
   320  
   321  	valuesSets := make(map[string]interface{})
   322  	valuesSets["labels"] = "foo:baz"
   323  	newConfig := &config.Config{
   324  		CommonConfig: config.CommonConfig{
   325  			Labels:    []string{"foo:baz"},
   326  			ValuesSet: valuesSets,
   327  		},
   328  	}
   329  
   330  	if err := daemon.Reload(newConfig); err != nil {
   331  		t.Fatal(err)
   332  	}
   333  
   334  	label := daemon.configStore.Labels[0]
   335  	if label != "foo:baz" {
   336  		t.Fatalf("Expected daemon label `foo:baz`, got %s", label)
   337  	}
   338  	debug := daemon.configStore.Debug
   339  	if !debug {
   340  		t.Fatal("Expected debug 'enabled', got 'disabled'")
   341  	}
   342  }
   343  
   344  func TestDaemonDiscoveryReload(t *testing.T) {
   345  	daemon := &Daemon{
   346  		imageService: images.NewImageService(images.ImageServiceConfig{}),
   347  	}
   348  	muteLogs()
   349  	daemon.configStore = &config.Config{
   350  		CommonConfig: config.CommonConfig{
   351  			ClusterStore:     "memory://127.0.0.1",
   352  			ClusterAdvertise: "127.0.0.1:3333",
   353  		},
   354  	}
   355  
   356  	if err := daemon.initDiscovery(daemon.configStore); err != nil {
   357  		t.Fatal(err)
   358  	}
   359  
   360  	expected := discovery.Entries{
   361  		&discovery.Entry{Host: "127.0.0.1", Port: "3333"},
   362  	}
   363  
   364  	select {
   365  	case <-time.After(10 * time.Second):
   366  		t.Fatal("timeout waiting for discovery")
   367  	case <-daemon.discoveryWatcher.ReadyCh():
   368  	}
   369  
   370  	stopCh := make(chan struct{})
   371  	defer close(stopCh)
   372  	ch, errCh := daemon.discoveryWatcher.Watch(stopCh)
   373  
   374  	select {
   375  	case <-time.After(1 * time.Second):
   376  		t.Fatal("failed to get discovery advertisements in time")
   377  	case e := <-ch:
   378  		if !reflect.DeepEqual(e, expected) {
   379  			t.Fatalf("expected %v, got %v\n", expected, e)
   380  		}
   381  	case e := <-errCh:
   382  		t.Fatal(e)
   383  	}
   384  
   385  	valuesSets := make(map[string]interface{})
   386  	valuesSets["cluster-store"] = "memory://127.0.0.1:2222"
   387  	valuesSets["cluster-advertise"] = "127.0.0.1:5555"
   388  	newConfig := &config.Config{
   389  		CommonConfig: config.CommonConfig{
   390  			ClusterStore:     "memory://127.0.0.1:2222",
   391  			ClusterAdvertise: "127.0.0.1:5555",
   392  			ValuesSet:        valuesSets,
   393  		},
   394  	}
   395  
   396  	expected = discovery.Entries{
   397  		&discovery.Entry{Host: "127.0.0.1", Port: "5555"},
   398  	}
   399  
   400  	if err := daemon.Reload(newConfig); err != nil {
   401  		t.Fatal(err)
   402  	}
   403  
   404  	select {
   405  	case <-time.After(10 * time.Second):
   406  		t.Fatal("timeout waiting for discovery")
   407  	case <-daemon.discoveryWatcher.ReadyCh():
   408  	}
   409  
   410  	ch, errCh = daemon.discoveryWatcher.Watch(stopCh)
   411  
   412  	select {
   413  	case <-time.After(1 * time.Second):
   414  		t.Fatal("failed to get discovery advertisements in time")
   415  	case e := <-ch:
   416  		if !reflect.DeepEqual(e, expected) {
   417  			t.Fatalf("expected %v, got %v\n", expected, e)
   418  		}
   419  	case e := <-errCh:
   420  		t.Fatal(e)
   421  	}
   422  }
   423  
   424  func TestDaemonDiscoveryReloadFromEmptyDiscovery(t *testing.T) {
   425  	daemon := &Daemon{
   426  		imageService: images.NewImageService(images.ImageServiceConfig{}),
   427  	}
   428  	daemon.configStore = &config.Config{}
   429  	muteLogs()
   430  
   431  	valuesSet := make(map[string]interface{})
   432  	valuesSet["cluster-store"] = "memory://127.0.0.1:2222"
   433  	valuesSet["cluster-advertise"] = "127.0.0.1:5555"
   434  	newConfig := &config.Config{
   435  		CommonConfig: config.CommonConfig{
   436  			ClusterStore:     "memory://127.0.0.1:2222",
   437  			ClusterAdvertise: "127.0.0.1:5555",
   438  			ValuesSet:        valuesSet,
   439  		},
   440  	}
   441  
   442  	expected := discovery.Entries{
   443  		&discovery.Entry{Host: "127.0.0.1", Port: "5555"},
   444  	}
   445  
   446  	if err := daemon.Reload(newConfig); err != nil {
   447  		t.Fatal(err)
   448  	}
   449  
   450  	select {
   451  	case <-time.After(10 * time.Second):
   452  		t.Fatal("timeout waiting for discovery")
   453  	case <-daemon.discoveryWatcher.ReadyCh():
   454  	}
   455  
   456  	stopCh := make(chan struct{})
   457  	defer close(stopCh)
   458  	ch, errCh := daemon.discoveryWatcher.Watch(stopCh)
   459  
   460  	select {
   461  	case <-time.After(1 * time.Second):
   462  		t.Fatal("failed to get discovery advertisements in time")
   463  	case e := <-ch:
   464  		if !reflect.DeepEqual(e, expected) {
   465  			t.Fatalf("expected %v, got %v\n", expected, e)
   466  		}
   467  	case e := <-errCh:
   468  		t.Fatal(e)
   469  	}
   470  }
   471  
   472  func TestDaemonDiscoveryReloadOnlyClusterAdvertise(t *testing.T) {
   473  	daemon := &Daemon{
   474  		imageService: images.NewImageService(images.ImageServiceConfig{}),
   475  	}
   476  	daemon.configStore = &config.Config{
   477  		CommonConfig: config.CommonConfig{
   478  			ClusterStore: "memory://127.0.0.1",
   479  		},
   480  	}
   481  	valuesSets := make(map[string]interface{})
   482  	valuesSets["cluster-advertise"] = "127.0.0.1:5555"
   483  	newConfig := &config.Config{
   484  		CommonConfig: config.CommonConfig{
   485  			ClusterAdvertise: "127.0.0.1:5555",
   486  			ValuesSet:        valuesSets,
   487  		},
   488  	}
   489  	expected := discovery.Entries{
   490  		&discovery.Entry{Host: "127.0.0.1", Port: "5555"},
   491  	}
   492  
   493  	if err := daemon.Reload(newConfig); err != nil {
   494  		t.Fatal(err)
   495  	}
   496  
   497  	select {
   498  	case <-daemon.discoveryWatcher.ReadyCh():
   499  	case <-time.After(10 * time.Second):
   500  		t.Fatal("Timeout waiting for discovery")
   501  	}
   502  	stopCh := make(chan struct{})
   503  	defer close(stopCh)
   504  	ch, errCh := daemon.discoveryWatcher.Watch(stopCh)
   505  
   506  	select {
   507  	case <-time.After(1 * time.Second):
   508  		t.Fatal("failed to get discovery advertisements in time")
   509  	case e := <-ch:
   510  		if !reflect.DeepEqual(e, expected) {
   511  			t.Fatalf("expected %v, got %v\n", expected, e)
   512  		}
   513  	case e := <-errCh:
   514  		t.Fatal(e)
   515  	}
   516  }
   517  
   518  func TestDaemonReloadNetworkDiagnosticPort(t *testing.T) {
   519  	if os.Getuid() != 0 {
   520  		t.Skip("root required")
   521  	}
   522  	daemon := &Daemon{
   523  		imageService: images.NewImageService(images.ImageServiceConfig{}),
   524  	}
   525  	daemon.configStore = &config.Config{}
   526  
   527  	valuesSet := make(map[string]interface{})
   528  	valuesSet["network-diagnostic-port"] = 2000
   529  	enableConfig := &config.Config{
   530  		CommonConfig: config.CommonConfig{
   531  			NetworkDiagnosticPort: 2000,
   532  			ValuesSet:             valuesSet,
   533  		},
   534  	}
   535  	disableConfig := &config.Config{
   536  		CommonConfig: config.CommonConfig{},
   537  	}
   538  
   539  	netOptions, err := daemon.networkOptions(enableConfig, nil, nil)
   540  	if err != nil {
   541  		t.Fatal(err)
   542  	}
   543  	controller, err := libnetwork.New(netOptions...)
   544  	if err != nil {
   545  		t.Fatal(err)
   546  	}
   547  	daemon.netController = controller
   548  
   549  	// Enable/Disable the server for some iterations
   550  	for i := 0; i < 10; i++ {
   551  		enableConfig.CommonConfig.NetworkDiagnosticPort++
   552  		if err := daemon.Reload(enableConfig); err != nil {
   553  			t.Fatal(err)
   554  		}
   555  		// Check that the diagnostic is enabled
   556  		if !daemon.netController.IsDiagnosticEnabled() {
   557  			t.Fatalf("diagnostic should be enable")
   558  		}
   559  
   560  		// Reload
   561  		if err := daemon.Reload(disableConfig); err != nil {
   562  			t.Fatal(err)
   563  		}
   564  		// Check that the diagnostic is disabled
   565  		if daemon.netController.IsDiagnosticEnabled() {
   566  			t.Fatalf("diagnostic should be disable")
   567  		}
   568  	}
   569  
   570  	enableConfig.CommonConfig.NetworkDiagnosticPort++
   571  	// 2 times the enable should not create problems
   572  	if err := daemon.Reload(enableConfig); err != nil {
   573  		t.Fatal(err)
   574  	}
   575  	// Check that the diagnostic is enabled
   576  	if !daemon.netController.IsDiagnosticEnabled() {
   577  		t.Fatalf("diagnostic should be enable")
   578  	}
   579  
   580  	// Check that another reload does not cause issues
   581  	if err := daemon.Reload(enableConfig); err != nil {
   582  		t.Fatal(err)
   583  	}
   584  	// Check that the diagnostic is enable
   585  	if !daemon.netController.IsDiagnosticEnabled() {
   586  		t.Fatalf("diagnostic should be enable")
   587  	}
   588  
   589  }