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