github.com/Heebron/moby@v0.0.0-20221111184709-6eab4f55faf7/daemon/reload_test.go (about)

     1  package daemon // import "github.com/docker/docker/daemon"
     2  
     3  import (
     4  	"os"
     5  	"sort"
     6  	"testing"
     7  
     8  	"github.com/docker/docker/daemon/config"
     9  	"github.com/docker/docker/daemon/images"
    10  	"github.com/docker/docker/libnetwork"
    11  	"github.com/docker/docker/registry"
    12  	"github.com/sirupsen/logrus"
    13  	"gotest.tools/v3/assert"
    14  	is "gotest.tools/v3/assert/cmp"
    15  )
    16  
    17  // muteLogs suppresses logs that are generated during the test
    18  func muteLogs() {
    19  	logrus.SetLevel(logrus.ErrorLevel)
    20  }
    21  
    22  func TestDaemonReloadLabels(t *testing.T) {
    23  	daemon := &Daemon{
    24  		configStore: &config.Config{
    25  			CommonConfig: config.CommonConfig{
    26  				Labels: []string{"foo:bar"},
    27  			},
    28  		},
    29  		imageService: images.NewImageService(images.ImageServiceConfig{}),
    30  	}
    31  	muteLogs()
    32  
    33  	valuesSets := make(map[string]interface{})
    34  	valuesSets["labels"] = "foo:baz"
    35  	newConfig := &config.Config{
    36  		CommonConfig: config.CommonConfig{
    37  			Labels:    []string{"foo:baz"},
    38  			ValuesSet: valuesSets,
    39  		},
    40  	}
    41  
    42  	if err := daemon.Reload(newConfig); err != nil {
    43  		t.Fatal(err)
    44  	}
    45  
    46  	label := daemon.configStore.Labels[0]
    47  	if label != "foo:baz" {
    48  		t.Fatalf("Expected daemon label `foo:baz`, got %s", label)
    49  	}
    50  }
    51  
    52  func TestDaemonReloadAllowNondistributableArtifacts(t *testing.T) {
    53  	daemon := &Daemon{
    54  		configStore:  &config.Config{},
    55  		imageService: images.NewImageService(images.ImageServiceConfig{}),
    56  	}
    57  	muteLogs()
    58  
    59  	var err error
    60  	// Initialize daemon with some registries.
    61  	daemon.registryService, err = registry.NewService(registry.ServiceOptions{
    62  		AllowNondistributableArtifacts: []string{
    63  			"127.0.0.0/8",
    64  			"10.10.1.11:5000",
    65  			"10.10.1.22:5000", // This will be removed during reload.
    66  			"docker1.com",
    67  			"docker2.com", // This will be removed during reload.
    68  		},
    69  	})
    70  	if err != nil {
    71  		t.Fatal(err)
    72  	}
    73  
    74  	registries := []string{
    75  		"127.0.0.0/8",
    76  		"10.10.1.11:5000",
    77  		"10.10.1.33:5000", // This will be added during reload.
    78  		"docker1.com",
    79  		"docker3.com", // This will be added during reload.
    80  	}
    81  
    82  	newConfig := &config.Config{
    83  		CommonConfig: config.CommonConfig{
    84  			ServiceOptions: registry.ServiceOptions{
    85  				AllowNondistributableArtifacts: registries,
    86  			},
    87  			ValuesSet: map[string]interface{}{
    88  				"allow-nondistributable-artifacts": registries,
    89  			},
    90  		},
    91  	}
    92  
    93  	if err := daemon.Reload(newConfig); err != nil {
    94  		t.Fatal(err)
    95  	}
    96  
    97  	var actual []string
    98  	serviceConfig := daemon.registryService.ServiceConfig()
    99  	for _, value := range serviceConfig.AllowNondistributableArtifactsCIDRs {
   100  		actual = append(actual, value.String())
   101  	}
   102  	actual = append(actual, serviceConfig.AllowNondistributableArtifactsHostnames...)
   103  
   104  	sort.Strings(registries)
   105  	sort.Strings(actual)
   106  	assert.Check(t, is.DeepEqual(registries, actual))
   107  }
   108  
   109  func TestDaemonReloadMirrors(t *testing.T) {
   110  	daemon := &Daemon{
   111  		imageService: images.NewImageService(images.ImageServiceConfig{}),
   112  	}
   113  	muteLogs()
   114  
   115  	var err error
   116  	daemon.registryService, err = registry.NewService(registry.ServiceOptions{
   117  		InsecureRegistries: []string{},
   118  		Mirrors: []string{
   119  			"https://mirror.test1.example.com",
   120  			"https://mirror.test2.example.com", // this will be removed when reloading
   121  			"https://mirror.test3.example.com", // this will be removed when reloading
   122  		},
   123  	})
   124  	if err != nil {
   125  		t.Fatal(err)
   126  	}
   127  
   128  	daemon.configStore = &config.Config{}
   129  
   130  	type pair struct {
   131  		valid   bool
   132  		mirrors []string
   133  		after   []string
   134  	}
   135  
   136  	loadMirrors := []pair{
   137  		{
   138  			valid:   false,
   139  			mirrors: []string{"10.10.1.11:5000"}, // this mirror is invalid
   140  			after:   []string{},
   141  		},
   142  		{
   143  			valid:   false,
   144  			mirrors: []string{"mirror.test1.com"}, // this mirror is invalid
   145  			after:   []string{},
   146  		},
   147  		{
   148  			valid:   false,
   149  			mirrors: []string{"10.10.1.11:5000", "mirror.test1.example.com"}, // mirrors are invalid
   150  			after:   []string{},
   151  		},
   152  		{
   153  			valid:   true,
   154  			mirrors: []string{"https://mirror.test1.example.com", "https://mirror.test4.example.com"},
   155  			after:   []string{"https://mirror.test1.example.com/", "https://mirror.test4.example.com/"},
   156  		},
   157  	}
   158  
   159  	for _, value := range loadMirrors {
   160  		valuesSets := make(map[string]interface{})
   161  		valuesSets["registry-mirrors"] = value.mirrors
   162  
   163  		newConfig := &config.Config{
   164  			CommonConfig: config.CommonConfig{
   165  				ServiceOptions: registry.ServiceOptions{
   166  					Mirrors: value.mirrors,
   167  				},
   168  				ValuesSet: valuesSets,
   169  			},
   170  		}
   171  
   172  		err := daemon.Reload(newConfig)
   173  		if !value.valid && err == nil {
   174  			// mirrors should be invalid, should be a non-nil error
   175  			t.Fatalf("Expected daemon reload error with invalid mirrors: %s, while get nil", value.mirrors)
   176  		}
   177  
   178  		if value.valid {
   179  			if err != nil {
   180  				// mirrors should be valid, should be no error
   181  				t.Fatal(err)
   182  			}
   183  			registryService := daemon.registryService.ServiceConfig()
   184  
   185  			if len(registryService.Mirrors) != len(value.after) {
   186  				t.Fatalf("Expected %d daemon mirrors %s while get %d with %s",
   187  					len(value.after),
   188  					value.after,
   189  					len(registryService.Mirrors),
   190  					registryService.Mirrors)
   191  			}
   192  
   193  			dataMap := map[string]struct{}{}
   194  
   195  			for _, mirror := range registryService.Mirrors {
   196  				if _, exist := dataMap[mirror]; !exist {
   197  					dataMap[mirror] = struct{}{}
   198  				}
   199  			}
   200  
   201  			for _, address := range value.after {
   202  				if _, exist := dataMap[address]; !exist {
   203  					t.Fatalf("Expected %s in daemon mirrors, while get none", address)
   204  				}
   205  			}
   206  		}
   207  	}
   208  }
   209  
   210  func TestDaemonReloadInsecureRegistries(t *testing.T) {
   211  	daemon := &Daemon{
   212  		imageService: images.NewImageService(images.ImageServiceConfig{}),
   213  	}
   214  	muteLogs()
   215  
   216  	var err error
   217  	// initialize daemon with existing insecure registries: "127.0.0.0/8", "10.10.1.11:5000", "10.10.1.22:5000"
   218  	daemon.registryService, err = registry.NewService(registry.ServiceOptions{
   219  		InsecureRegistries: []string{
   220  			"127.0.0.0/8",
   221  			"10.10.1.11:5000",
   222  			"10.10.1.22:5000", // this will be removed when reloading
   223  			"docker1.example.com",
   224  			"docker2.example.com", // this will be removed when reloading
   225  		},
   226  	})
   227  	if err != nil {
   228  		t.Fatal(err)
   229  	}
   230  
   231  	daemon.configStore = &config.Config{}
   232  
   233  	insecureRegistries := []string{
   234  		"127.0.0.0/8",         // this will be kept
   235  		"10.10.1.11:5000",     // this will be kept
   236  		"10.10.1.33:5000",     // this will be newly added
   237  		"docker1.example.com", // this will be kept
   238  		"docker3.example.com", // this will be newly added
   239  	}
   240  
   241  	valuesSets := make(map[string]interface{})
   242  	valuesSets["insecure-registries"] = insecureRegistries
   243  
   244  	newConfig := &config.Config{
   245  		CommonConfig: config.CommonConfig{
   246  			ServiceOptions: registry.ServiceOptions{
   247  				InsecureRegistries: insecureRegistries,
   248  			},
   249  			ValuesSet: valuesSets,
   250  		},
   251  	}
   252  
   253  	if err := daemon.Reload(newConfig); err != nil {
   254  		t.Fatal(err)
   255  	}
   256  
   257  	// After Reload, daemon.RegistryService will be changed which is useful
   258  	// for registry communication in daemon.
   259  	registries := daemon.registryService.ServiceConfig()
   260  
   261  	// After Reload(), newConfig has come to registries.InsecureRegistryCIDRs and registries.IndexConfigs in daemon.
   262  	// Then collect registries.InsecureRegistryCIDRs in dataMap.
   263  	// When collecting, we need to convert CIDRS into string as a key,
   264  	// while the times of key appears as value.
   265  	dataMap := map[string]int{}
   266  	for _, value := range registries.InsecureRegistryCIDRs {
   267  		if _, ok := dataMap[value.String()]; !ok {
   268  			dataMap[value.String()] = 1
   269  		} else {
   270  			dataMap[value.String()]++
   271  		}
   272  	}
   273  
   274  	for _, value := range registries.IndexConfigs {
   275  		if _, ok := dataMap[value.Name]; !ok {
   276  			dataMap[value.Name] = 1
   277  		} else {
   278  			dataMap[value.Name]++
   279  		}
   280  	}
   281  
   282  	// Finally compare dataMap with the original insecureRegistries.
   283  	// Each value in insecureRegistries should appear in daemon's insecure registries,
   284  	// and each can only appear exactly ONCE.
   285  	for _, r := range insecureRegistries {
   286  		if value, ok := dataMap[r]; !ok {
   287  			t.Fatalf("Expected daemon insecure registry %s, got none", r)
   288  		} else if value != 1 {
   289  			t.Fatalf("Expected only 1 daemon insecure registry %s, got %d", r, value)
   290  		}
   291  	}
   292  
   293  	// assert if "10.10.1.22:5000" is removed when reloading
   294  	if value, ok := dataMap["10.10.1.22:5000"]; ok {
   295  		t.Fatalf("Expected no insecure registry of 10.10.1.22:5000, got %d", value)
   296  	}
   297  
   298  	// assert if "docker2.com" is removed when reloading
   299  	if value, ok := dataMap["docker2.example.com"]; ok {
   300  		t.Fatalf("Expected no insecure registry of docker2.com, got %d", value)
   301  	}
   302  }
   303  
   304  func TestDaemonReloadNotAffectOthers(t *testing.T) {
   305  	daemon := &Daemon{
   306  		imageService: images.NewImageService(images.ImageServiceConfig{}),
   307  	}
   308  	muteLogs()
   309  
   310  	daemon.configStore = &config.Config{
   311  		CommonConfig: config.CommonConfig{
   312  			Labels: []string{"foo:bar"},
   313  			Debug:  true,
   314  		},
   315  	}
   316  
   317  	valuesSets := make(map[string]interface{})
   318  	valuesSets["labels"] = "foo:baz"
   319  	newConfig := &config.Config{
   320  		CommonConfig: config.CommonConfig{
   321  			Labels:    []string{"foo:baz"},
   322  			ValuesSet: valuesSets,
   323  		},
   324  	}
   325  
   326  	if err := daemon.Reload(newConfig); err != nil {
   327  		t.Fatal(err)
   328  	}
   329  
   330  	label := daemon.configStore.Labels[0]
   331  	if label != "foo:baz" {
   332  		t.Fatalf("Expected daemon label `foo:baz`, got %s", label)
   333  	}
   334  	debug := daemon.configStore.Debug
   335  	if !debug {
   336  		t.Fatal("Expected debug 'enabled', got 'disabled'")
   337  	}
   338  }
   339  
   340  func TestDaemonReloadNetworkDiagnosticPort(t *testing.T) {
   341  	if os.Getuid() != 0 {
   342  		t.Skip("root required")
   343  	}
   344  	daemon := &Daemon{
   345  		imageService: images.NewImageService(images.ImageServiceConfig{}),
   346  		configStore:  &config.Config{},
   347  	}
   348  
   349  	enableConfig := &config.Config{
   350  		CommonConfig: config.CommonConfig{
   351  			NetworkDiagnosticPort: 2000,
   352  			ValuesSet: map[string]interface{}{
   353  				"network-diagnostic-port": 2000,
   354  			},
   355  		},
   356  	}
   357  
   358  	netOptions, err := daemon.networkOptions(nil, nil)
   359  	if err != nil {
   360  		t.Fatal(err)
   361  	}
   362  	controller, err := libnetwork.New(netOptions...)
   363  	if err != nil {
   364  		t.Fatal(err)
   365  	}
   366  	daemon.netController = controller
   367  
   368  	// Enable/Disable the server for some iterations
   369  	for i := 0; i < 10; i++ {
   370  		enableConfig.CommonConfig.NetworkDiagnosticPort++
   371  		if err := daemon.Reload(enableConfig); err != nil {
   372  			t.Fatal(err)
   373  		}
   374  		// Check that the diagnostic is enabled
   375  		if !daemon.netController.IsDiagnosticEnabled() {
   376  			t.Fatalf("diagnostic should be enabled")
   377  		}
   378  
   379  		// Reload
   380  		if err := daemon.Reload(&config.Config{}); err != nil {
   381  			t.Fatal(err)
   382  		}
   383  		// Check that the diagnostic is disabled
   384  		if daemon.netController.IsDiagnosticEnabled() {
   385  			t.Fatalf("diagnostic should be disabled")
   386  		}
   387  	}
   388  
   389  	enableConfig.CommonConfig.NetworkDiagnosticPort++
   390  	// 2 times the enable should not create problems
   391  	if err := daemon.Reload(enableConfig); err != nil {
   392  		t.Fatal(err)
   393  	}
   394  	// Check that the diagnostic is enabled
   395  	if !daemon.netController.IsDiagnosticEnabled() {
   396  		t.Fatalf("diagnostic should be enable")
   397  	}
   398  
   399  	// Check that another reload does not cause issues
   400  	if err := daemon.Reload(enableConfig); err != nil {
   401  		t.Fatal(err)
   402  	}
   403  	// Check that the diagnostic is enable
   404  	if !daemon.netController.IsDiagnosticEnabled() {
   405  		t.Fatalf("diagnostic should be enable")
   406  	}
   407  }