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 }