github.com/kaisenlinux/docker.io@v0.0.0-20230510090727-ea55db55fac7/swarmkit/manager/allocator/allocator_test.go (about) 1 package allocator 2 3 import ( 4 "context" 5 "net" 6 "runtime/debug" 7 "strconv" 8 "testing" 9 "time" 10 11 "github.com/docker/go-events" 12 "github.com/docker/swarmkit/api" 13 "github.com/docker/swarmkit/manager/state" 14 "github.com/docker/swarmkit/manager/state/store" 15 "github.com/stretchr/testify/assert" 16 "github.com/stretchr/testify/require" 17 ) 18 19 func init() { 20 // set artificially low retry interval for testing 21 retryInterval = 5 * time.Millisecond 22 } 23 24 func TestAllocator(t *testing.T) { 25 s := store.NewMemoryStore(nil) 26 assert.NotNil(t, s) 27 defer s.Close() 28 29 a, err := New(s, nil, nil) 30 assert.NoError(t, err) 31 assert.NotNil(t, a) 32 33 // Predefined node-local networkTestNoDuplicateIPs 34 p := &api.Network{ 35 ID: "one_unIque_id", 36 Spec: api.NetworkSpec{ 37 Annotations: api.Annotations{ 38 Name: "pred_bridge_network", 39 Labels: map[string]string{ 40 "com.docker.swarm.predefined": "true", 41 }, 42 }, 43 DriverConfig: &api.Driver{Name: "bridge"}, 44 }, 45 } 46 47 // Node-local swarm scope network 48 nln := &api.Network{ 49 ID: "another_unIque_id", 50 Spec: api.NetworkSpec{ 51 Annotations: api.Annotations{ 52 Name: "swarm-macvlan", 53 }, 54 DriverConfig: &api.Driver{Name: "macvlan"}, 55 }, 56 } 57 58 // Try adding some objects to store before allocator is started 59 assert.NoError(t, s.Update(func(tx store.Tx) error { 60 // populate ingress network 61 in := &api.Network{ 62 ID: "ingress-nw-id", 63 Spec: api.NetworkSpec{ 64 Annotations: api.Annotations{ 65 Name: "default-ingress", 66 }, 67 Ingress: true, 68 }, 69 } 70 assert.NoError(t, store.CreateNetwork(tx, in)) 71 72 n1 := &api.Network{ 73 ID: "testID1", 74 Spec: api.NetworkSpec{ 75 Annotations: api.Annotations{ 76 Name: "test1", 77 }, 78 }, 79 } 80 assert.NoError(t, store.CreateNetwork(tx, n1)) 81 82 s1 := &api.Service{ 83 ID: "testServiceID1", 84 Spec: api.ServiceSpec{ 85 Annotations: api.Annotations{ 86 Name: "service1", 87 }, 88 Task: api.TaskSpec{ 89 Networks: []*api.NetworkAttachmentConfig{ 90 { 91 Target: "testID1", 92 }, 93 }, 94 }, 95 Endpoint: &api.EndpointSpec{ 96 Mode: api.ResolutionModeVirtualIP, 97 Ports: []*api.PortConfig{ 98 { 99 Name: "portName", 100 Protocol: api.ProtocolTCP, 101 TargetPort: 8000, 102 PublishedPort: 8001, 103 }, 104 }, 105 }, 106 }, 107 } 108 assert.NoError(t, store.CreateService(tx, s1)) 109 110 t1 := &api.Task{ 111 ID: "testTaskID1", 112 Status: api.TaskStatus{ 113 State: api.TaskStateNew, 114 }, 115 Networks: []*api.NetworkAttachment{ 116 { 117 Network: n1, 118 }, 119 }, 120 } 121 assert.NoError(t, store.CreateTask(tx, t1)) 122 123 t2 := &api.Task{ 124 ID: "testTaskIDPreInit", 125 Status: api.TaskStatus{ 126 State: api.TaskStateNew, 127 }, 128 ServiceID: "testServiceID1", 129 DesiredState: api.TaskStateRunning, 130 } 131 assert.NoError(t, store.CreateTask(tx, t2)) 132 133 // Create the predefined node-local network with one service 134 assert.NoError(t, store.CreateNetwork(tx, p)) 135 136 sp1 := &api.Service{ 137 ID: "predServiceID1", 138 Spec: api.ServiceSpec{ 139 Annotations: api.Annotations{ 140 Name: "predService1", 141 }, 142 Task: api.TaskSpec{ 143 Networks: []*api.NetworkAttachmentConfig{ 144 { 145 Target: p.ID, 146 }, 147 }, 148 }, 149 Endpoint: &api.EndpointSpec{Mode: api.ResolutionModeDNSRoundRobin}, 150 }, 151 } 152 assert.NoError(t, store.CreateService(tx, sp1)) 153 154 tp1 := &api.Task{ 155 ID: "predTaskID1", 156 Status: api.TaskStatus{ 157 State: api.TaskStateNew, 158 }, 159 Networks: []*api.NetworkAttachment{ 160 { 161 Network: p, 162 }, 163 }, 164 } 165 assert.NoError(t, store.CreateTask(tx, tp1)) 166 167 // Create the the swarm level node-local network with one service 168 assert.NoError(t, store.CreateNetwork(tx, nln)) 169 170 sp2 := &api.Service{ 171 ID: "predServiceID2", 172 Spec: api.ServiceSpec{ 173 Annotations: api.Annotations{ 174 Name: "predService2", 175 }, 176 Task: api.TaskSpec{ 177 Networks: []*api.NetworkAttachmentConfig{ 178 { 179 Target: nln.ID, 180 }, 181 }, 182 }, 183 Endpoint: &api.EndpointSpec{Mode: api.ResolutionModeDNSRoundRobin}, 184 }, 185 } 186 assert.NoError(t, store.CreateService(tx, sp2)) 187 188 tp2 := &api.Task{ 189 ID: "predTaskID2", 190 Status: api.TaskStatus{ 191 State: api.TaskStateNew, 192 }, 193 Networks: []*api.NetworkAttachment{ 194 { 195 Network: nln, 196 }, 197 }, 198 } 199 assert.NoError(t, store.CreateTask(tx, tp2)) 200 201 return nil 202 })) 203 204 netWatch, cancel := state.Watch(s.WatchQueue(), api.EventUpdateNetwork{}, api.EventDeleteNetwork{}) 205 defer cancel() 206 taskWatch, cancel := state.Watch(s.WatchQueue(), api.EventUpdateTask{}, api.EventDeleteTask{}) 207 defer cancel() 208 serviceWatch, cancel := state.Watch(s.WatchQueue(), api.EventUpdateService{}, api.EventDeleteService{}) 209 defer cancel() 210 211 // Start allocator 212 go func() { 213 assert.NoError(t, a.Run(context.Background())) 214 }() 215 defer a.Stop() 216 217 // Now verify if we get network and tasks updated properly 218 watchNetwork(t, netWatch, false, isValidNetwork) 219 watchTask(t, s, taskWatch, false, isValidTask) // t1 220 watchTask(t, s, taskWatch, false, isValidTask) // t2 221 watchService(t, serviceWatch, false, nil) 222 223 // Verify no allocation was done for the node-local networks 224 var ( 225 ps *api.Network 226 sn *api.Network 227 ) 228 s.View(func(tx store.ReadTx) { 229 ps = store.GetNetwork(tx, p.ID) 230 sn = store.GetNetwork(tx, nln.ID) 231 232 }) 233 assert.NotNil(t, ps) 234 assert.NotNil(t, sn) 235 // Verify no allocation was done for tasks on node-local networks 236 var ( 237 tp1 *api.Task 238 tp2 *api.Task 239 ) 240 s.View(func(tx store.ReadTx) { 241 tp1 = store.GetTask(tx, "predTaskID1") 242 tp2 = store.GetTask(tx, "predTaskID2") 243 }) 244 assert.NotNil(t, tp1) 245 assert.NotNil(t, tp2) 246 assert.Equal(t, tp1.Networks[0].Network.ID, p.ID) 247 assert.Equal(t, tp2.Networks[0].Network.ID, nln.ID) 248 assert.Nil(t, tp1.Networks[0].Addresses, "Non nil addresses for task on node-local network") 249 assert.Nil(t, tp2.Networks[0].Addresses, "Non nil addresses for task on node-local network") 250 251 // Add new networks/tasks/services after allocator is started. 252 assert.NoError(t, s.Update(func(tx store.Tx) error { 253 n2 := &api.Network{ 254 ID: "testID2", 255 Spec: api.NetworkSpec{ 256 Annotations: api.Annotations{ 257 Name: "test2", 258 }, 259 }, 260 } 261 assert.NoError(t, store.CreateNetwork(tx, n2)) 262 return nil 263 })) 264 265 watchNetwork(t, netWatch, false, isValidNetwork) 266 267 assert.NoError(t, s.Update(func(tx store.Tx) error { 268 s2 := &api.Service{ 269 ID: "testServiceID2", 270 Spec: api.ServiceSpec{ 271 Annotations: api.Annotations{ 272 Name: "service2", 273 }, 274 Networks: []*api.NetworkAttachmentConfig{ 275 { 276 Target: "testID2", 277 }, 278 }, 279 Endpoint: &api.EndpointSpec{}, 280 }, 281 } 282 assert.NoError(t, store.CreateService(tx, s2)) 283 return nil 284 })) 285 286 watchService(t, serviceWatch, false, nil) 287 288 assert.NoError(t, s.Update(func(tx store.Tx) error { 289 t2 := &api.Task{ 290 ID: "testTaskID2", 291 Status: api.TaskStatus{ 292 State: api.TaskStateNew, 293 }, 294 ServiceID: "testServiceID2", 295 DesiredState: api.TaskStateRunning, 296 } 297 assert.NoError(t, store.CreateTask(tx, t2)) 298 return nil 299 })) 300 301 watchTask(t, s, taskWatch, false, isValidTask) 302 303 // Now try adding a task which depends on a network before adding the network. 304 n3 := &api.Network{ 305 ID: "testID3", 306 Spec: api.NetworkSpec{ 307 Annotations: api.Annotations{ 308 Name: "test3", 309 }, 310 }, 311 } 312 313 assert.NoError(t, s.Update(func(tx store.Tx) error { 314 t3 := &api.Task{ 315 ID: "testTaskID3", 316 Status: api.TaskStatus{ 317 State: api.TaskStateNew, 318 }, 319 DesiredState: api.TaskStateRunning, 320 Networks: []*api.NetworkAttachment{ 321 { 322 Network: n3, 323 }, 324 }, 325 } 326 assert.NoError(t, store.CreateTask(tx, t3)) 327 return nil 328 })) 329 330 // Wait for a little bit of time before adding network just to 331 // test network is not available while task allocation is 332 // going through 333 time.Sleep(10 * time.Millisecond) 334 335 assert.NoError(t, s.Update(func(tx store.Tx) error { 336 assert.NoError(t, store.CreateNetwork(tx, n3)) 337 return nil 338 })) 339 340 watchNetwork(t, netWatch, false, isValidNetwork) 341 watchTask(t, s, taskWatch, false, isValidTask) 342 343 assert.NoError(t, s.Update(func(tx store.Tx) error { 344 assert.NoError(t, store.DeleteTask(tx, "testTaskID3")) 345 return nil 346 })) 347 watchTask(t, s, taskWatch, false, isValidTask) 348 349 assert.NoError(t, s.Update(func(tx store.Tx) error { 350 t5 := &api.Task{ 351 ID: "testTaskID5", 352 Spec: api.TaskSpec{ 353 Networks: []*api.NetworkAttachmentConfig{ 354 { 355 Target: "testID2", 356 }, 357 }, 358 }, 359 Status: api.TaskStatus{ 360 State: api.TaskStateNew, 361 }, 362 DesiredState: api.TaskStateRunning, 363 ServiceID: "testServiceID2", 364 } 365 assert.NoError(t, store.CreateTask(tx, t5)) 366 return nil 367 })) 368 watchTask(t, s, taskWatch, false, isValidTask) 369 370 assert.NoError(t, s.Update(func(tx store.Tx) error { 371 assert.NoError(t, store.DeleteNetwork(tx, "testID3")) 372 return nil 373 })) 374 watchNetwork(t, netWatch, false, isValidNetwork) 375 376 assert.NoError(t, s.Update(func(tx store.Tx) error { 377 assert.NoError(t, store.DeleteService(tx, "testServiceID2")) 378 return nil 379 })) 380 watchService(t, serviceWatch, false, nil) 381 382 // Try to create a task with no network attachments and test 383 // that it moves to ALLOCATED state. 384 assert.NoError(t, s.Update(func(tx store.Tx) error { 385 t4 := &api.Task{ 386 ID: "testTaskID4", 387 Status: api.TaskStatus{ 388 State: api.TaskStateNew, 389 }, 390 DesiredState: api.TaskStateRunning, 391 } 392 assert.NoError(t, store.CreateTask(tx, t4)) 393 return nil 394 })) 395 watchTask(t, s, taskWatch, false, isValidTask) 396 397 assert.NoError(t, s.Update(func(tx store.Tx) error { 398 n2 := store.GetNetwork(tx, "testID2") 399 require.NotEqual(t, nil, n2) 400 assert.NoError(t, store.UpdateNetwork(tx, n2)) 401 return nil 402 })) 403 watchNetwork(t, netWatch, false, isValidNetwork) 404 watchNetwork(t, netWatch, true, nil) 405 406 // Try updating service which is already allocated with no endpointSpec 407 assert.NoError(t, s.Update(func(tx store.Tx) error { 408 s := store.GetService(tx, "testServiceID1") 409 s.Spec.Endpoint = nil 410 411 assert.NoError(t, store.UpdateService(tx, s)) 412 return nil 413 })) 414 watchService(t, serviceWatch, false, nil) 415 416 // Try updating task which is already allocated 417 assert.NoError(t, s.Update(func(tx store.Tx) error { 418 t2 := store.GetTask(tx, "testTaskID2") 419 require.NotEqual(t, nil, t2) 420 assert.NoError(t, store.UpdateTask(tx, t2)) 421 return nil 422 })) 423 watchTask(t, s, taskWatch, false, isValidTask) 424 watchTask(t, s, taskWatch, true, nil) 425 426 // Try adding networks with conflicting network resources and 427 // add task which attaches to a network which gets allocated 428 // later and verify if task reconciles and moves to ALLOCATED. 429 n4 := &api.Network{ 430 ID: "testID4", 431 Spec: api.NetworkSpec{ 432 Annotations: api.Annotations{ 433 Name: "test4", 434 }, 435 DriverConfig: &api.Driver{ 436 Name: "overlay", 437 Options: map[string]string{ 438 "com.docker.network.driver.overlay.vxlanid_list": "328", 439 }, 440 }, 441 }, 442 } 443 444 n5 := n4.Copy() 445 n5.ID = "testID5" 446 n5.Spec.Annotations.Name = "test5" 447 assert.NoError(t, s.Update(func(tx store.Tx) error { 448 assert.NoError(t, store.CreateNetwork(tx, n4)) 449 return nil 450 })) 451 watchNetwork(t, netWatch, false, isValidNetwork) 452 453 assert.NoError(t, s.Update(func(tx store.Tx) error { 454 assert.NoError(t, store.CreateNetwork(tx, n5)) 455 return nil 456 })) 457 watchNetwork(t, netWatch, true, nil) 458 459 assert.NoError(t, s.Update(func(tx store.Tx) error { 460 t6 := &api.Task{ 461 ID: "testTaskID6", 462 Status: api.TaskStatus{ 463 State: api.TaskStateNew, 464 }, 465 DesiredState: api.TaskStateRunning, 466 Networks: []*api.NetworkAttachment{ 467 { 468 Network: n5, 469 }, 470 }, 471 } 472 assert.NoError(t, store.CreateTask(tx, t6)) 473 return nil 474 })) 475 watchTask(t, s, taskWatch, true, nil) 476 477 // Now remove the conflicting network. 478 assert.NoError(t, s.Update(func(tx store.Tx) error { 479 assert.NoError(t, store.DeleteNetwork(tx, n4.ID)) 480 return nil 481 })) 482 watchNetwork(t, netWatch, false, isValidNetwork) 483 watchTask(t, s, taskWatch, false, isValidTask) 484 485 // Try adding services with conflicting port configs and add 486 // task which is part of the service whose allocation hasn't 487 // happened and when that happens later and verify if task 488 // reconciles and moves to ALLOCATED. 489 s3 := &api.Service{ 490 ID: "testServiceID3", 491 Spec: api.ServiceSpec{ 492 Annotations: api.Annotations{ 493 Name: "service3", 494 }, 495 Endpoint: &api.EndpointSpec{ 496 Ports: []*api.PortConfig{ 497 { 498 Name: "http", 499 TargetPort: 80, 500 PublishedPort: 8080, 501 }, 502 { 503 PublishMode: api.PublishModeHost, 504 Name: "http", 505 TargetPort: 80, 506 }, 507 }, 508 }, 509 }, 510 } 511 512 s4 := s3.Copy() 513 s4.ID = "testServiceID4" 514 s4.Spec.Annotations.Name = "service4" 515 assert.NoError(t, s.Update(func(tx store.Tx) error { 516 assert.NoError(t, store.CreateService(tx, s3)) 517 return nil 518 })) 519 watchService(t, serviceWatch, false, nil) 520 assert.NoError(t, s.Update(func(tx store.Tx) error { 521 assert.NoError(t, store.CreateService(tx, s4)) 522 return nil 523 })) 524 watchService(t, serviceWatch, true, nil) 525 526 assert.NoError(t, s.Update(func(tx store.Tx) error { 527 t7 := &api.Task{ 528 ID: "testTaskID7", 529 Status: api.TaskStatus{ 530 State: api.TaskStateNew, 531 }, 532 ServiceID: "testServiceID4", 533 DesiredState: api.TaskStateRunning, 534 } 535 assert.NoError(t, store.CreateTask(tx, t7)) 536 return nil 537 })) 538 watchTask(t, s, taskWatch, true, nil) 539 540 // Now remove the conflicting service. 541 assert.NoError(t, s.Update(func(tx store.Tx) error { 542 assert.NoError(t, store.DeleteService(tx, s3.ID)) 543 return nil 544 })) 545 watchService(t, serviceWatch, false, nil) 546 watchTask(t, s, taskWatch, false, isValidTask) 547 } 548 549 func TestNoDuplicateIPs(t *testing.T) { 550 s := store.NewMemoryStore(nil) 551 assert.NotNil(t, s) 552 defer s.Close() 553 554 // Try adding some objects to store before allocator is started 555 assert.NoError(t, s.Update(func(tx store.Tx) error { 556 // populate ingress network 557 in := &api.Network{ 558 ID: "ingress-nw-id", 559 Spec: api.NetworkSpec{ 560 Annotations: api.Annotations{ 561 Name: "default-ingress", 562 }, 563 Ingress: true, 564 }, 565 IPAM: &api.IPAMOptions{ 566 Driver: &api.Driver{}, 567 Configs: []*api.IPAMConfig{ 568 { 569 Subnet: "10.0.0.0/24", 570 Gateway: "10.0.0.1", 571 }, 572 }, 573 }, 574 DriverState: &api.Driver{}, 575 } 576 assert.NoError(t, store.CreateNetwork(tx, in)) 577 n1 := &api.Network{ 578 ID: "testID1", 579 Spec: api.NetworkSpec{ 580 Annotations: api.Annotations{ 581 Name: "test1", 582 }, 583 }, 584 IPAM: &api.IPAMOptions{ 585 Driver: &api.Driver{}, 586 Configs: []*api.IPAMConfig{ 587 { 588 Subnet: "10.1.0.0/24", 589 Gateway: "10.1.0.1", 590 }, 591 }, 592 }, 593 DriverState: &api.Driver{}, 594 } 595 assert.NoError(t, store.CreateNetwork(tx, n1)) 596 597 s1 := &api.Service{ 598 ID: "testServiceID1", 599 Spec: api.ServiceSpec{ 600 Annotations: api.Annotations{ 601 Name: "service1", 602 }, 603 Task: api.TaskSpec{ 604 Networks: []*api.NetworkAttachmentConfig{ 605 { 606 Target: "testID1", 607 }, 608 }, 609 }, 610 Endpoint: &api.EndpointSpec{ 611 Mode: api.ResolutionModeVirtualIP, 612 Ports: []*api.PortConfig{ 613 { 614 Name: "portName", 615 Protocol: api.ProtocolTCP, 616 TargetPort: 8000, 617 PublishedPort: 8001, 618 }, 619 }, 620 }, 621 }, 622 } 623 assert.NoError(t, store.CreateService(tx, s1)) 624 625 return nil 626 })) 627 628 taskWatch, cancel := state.Watch(s.WatchQueue(), api.EventUpdateTask{}, api.EventDeleteTask{}) 629 defer cancel() 630 631 assignedIPs := make(map[string]string) 632 hasUniqueIP := func(fakeT assert.TestingT, s *store.MemoryStore, task *api.Task) bool { 633 if len(task.Networks) == 0 { 634 panic("missing networks") 635 } 636 if len(task.Networks[0].Addresses) == 0 { 637 panic("missing network address") 638 } 639 640 assignedIP := task.Networks[0].Addresses[0] 641 oldTaskID, present := assignedIPs[assignedIP] 642 if present && task.ID != oldTaskID { 643 t.Fatalf("task %s assigned duplicate IP %s, previously assigned to task %s", task.ID, assignedIP, oldTaskID) 644 } 645 assignedIPs[assignedIP] = task.ID 646 return true 647 } 648 649 reps := 100 650 for i := 0; i != reps; i++ { 651 assert.NoError(t, s.Update(func(tx store.Tx) error { 652 t2 := &api.Task{ 653 // The allocator iterates over the tasks in 654 // lexical order, so number tasks in descending 655 // order. Note that the problem this test was 656 // meant to trigger also showed up with tasks 657 // numbered in ascending order, but it took 658 // until the 52nd task. 659 ID: "testTaskID" + strconv.Itoa(reps-i), 660 Status: api.TaskStatus{ 661 State: api.TaskStateNew, 662 }, 663 ServiceID: "testServiceID1", 664 DesiredState: api.TaskStateRunning, 665 } 666 assert.NoError(t, store.CreateTask(tx, t2)) 667 668 return nil 669 })) 670 a, err := New(s, nil, nil) 671 assert.NoError(t, err) 672 assert.NotNil(t, a) 673 674 // Start allocator 675 go func() { 676 assert.NoError(t, a.Run(context.Background())) 677 }() 678 679 // Confirm task gets a unique IP 680 watchTask(t, s, taskWatch, false, hasUniqueIP) 681 a.Stop() 682 } 683 } 684 685 func TestAllocatorRestoreForDuplicateIPs(t *testing.T) { 686 s := store.NewMemoryStore(nil) 687 assert.NotNil(t, s) 688 defer s.Close() 689 // Create 3 services with 1 task each 690 numsvcstsks := 3 691 assert.NoError(t, s.Update(func(tx store.Tx) error { 692 // populate ingress network 693 in := &api.Network{ 694 ID: "ingress-nw-id", 695 Spec: api.NetworkSpec{ 696 Annotations: api.Annotations{ 697 Name: "default-ingress", 698 }, 699 Ingress: true, 700 }, 701 IPAM: &api.IPAMOptions{ 702 Driver: &api.Driver{}, 703 Configs: []*api.IPAMConfig{ 704 { 705 Subnet: "10.0.0.0/24", 706 Gateway: "10.0.0.1", 707 }, 708 }, 709 }, 710 } 711 assert.NoError(t, store.CreateNetwork(tx, in)) 712 713 for i := 0; i != numsvcstsks; i++ { 714 svc := &api.Service{ 715 ID: "testServiceID" + strconv.Itoa(i), 716 Spec: api.ServiceSpec{ 717 Annotations: api.Annotations{ 718 Name: "service" + strconv.Itoa(i), 719 }, 720 Endpoint: &api.EndpointSpec{ 721 Mode: api.ResolutionModeVirtualIP, 722 723 Ports: []*api.PortConfig{ 724 { 725 Name: "", 726 Protocol: api.ProtocolTCP, 727 TargetPort: 8000, 728 PublishedPort: uint32(8001 + i), 729 }, 730 }, 731 }, 732 }, 733 Endpoint: &api.Endpoint{ 734 Ports: []*api.PortConfig{ 735 { 736 Name: "", 737 Protocol: api.ProtocolTCP, 738 TargetPort: 8000, 739 PublishedPort: uint32(8001 + i), 740 }, 741 }, 742 VirtualIPs: []*api.Endpoint_VirtualIP{ 743 { 744 NetworkID: "ingress-nw-id", 745 Addr: "10.0.0." + strconv.Itoa(2+i) + "/24", 746 }, 747 }, 748 }, 749 } 750 assert.NoError(t, store.CreateService(tx, svc)) 751 } 752 return nil 753 })) 754 755 for i := 0; i != numsvcstsks; i++ { 756 assert.NoError(t, s.Update(func(tx store.Tx) error { 757 tsk := &api.Task{ 758 ID: "testTaskID" + strconv.Itoa(i), 759 Status: api.TaskStatus{ 760 State: api.TaskStateNew, 761 }, 762 ServiceID: "testServiceID" + strconv.Itoa(i), 763 DesiredState: api.TaskStateRunning, 764 } 765 assert.NoError(t, store.CreateTask(tx, tsk)) 766 return nil 767 })) 768 } 769 770 assignedVIPs := make(map[string]bool) 771 assignedIPs := make(map[string]bool) 772 hasNoIPOverlapServices := func(fakeT assert.TestingT, service *api.Service) bool { 773 assert.NotEqual(fakeT, len(service.Endpoint.VirtualIPs), 0) 774 assert.NotEqual(fakeT, len(service.Endpoint.VirtualIPs[0].Addr), 0) 775 776 assignedVIP := service.Endpoint.VirtualIPs[0].Addr 777 if assignedVIPs[assignedVIP] { 778 t.Fatalf("service %s assigned duplicate IP %s", service.ID, assignedVIP) 779 } 780 assignedVIPs[assignedVIP] = true 781 if assignedIPs[assignedVIP] { 782 t.Fatalf("a task and service %s have the same IP %s", service.ID, assignedVIP) 783 } 784 return true 785 } 786 787 hasNoIPOverlapTasks := func(fakeT assert.TestingT, s *store.MemoryStore, task *api.Task) bool { 788 assert.NotEqual(fakeT, len(task.Networks), 0) 789 assert.NotEqual(fakeT, len(task.Networks[0].Addresses), 0) 790 791 assignedIP := task.Networks[0].Addresses[0] 792 if assignedIPs[assignedIP] { 793 t.Fatalf("task %s assigned duplicate IP %s", task.ID, assignedIP) 794 } 795 assignedIPs[assignedIP] = true 796 if assignedVIPs[assignedIP] { 797 t.Fatalf("a service and task %s have the same IP %s", task.ID, assignedIP) 798 } 799 return true 800 } 801 802 a, err := New(s, nil, nil) 803 assert.NoError(t, err) 804 assert.NotNil(t, a) 805 // Start allocator 806 go func() { 807 assert.NoError(t, a.Run(context.Background())) 808 }() 809 defer a.Stop() 810 811 taskWatch, cancel := state.Watch(s.WatchQueue(), api.EventUpdateTask{}, api.EventDeleteTask{}) 812 defer cancel() 813 814 serviceWatch, cancel := state.Watch(s.WatchQueue(), api.EventUpdateService{}, api.EventDeleteService{}) 815 defer cancel() 816 817 // Confirm tasks have no IPs that overlap with the services VIPs on restart 818 for i := 0; i != numsvcstsks; i++ { 819 watchTask(t, s, taskWatch, false, hasNoIPOverlapTasks) 820 watchService(t, serviceWatch, false, hasNoIPOverlapServices) 821 } 822 } 823 824 // TestAllocatorRestartNoEndpointSpec covers the leader election case when the service Spec 825 // does not contain the EndpointSpec. 826 // The expected behavior is that the VIP(s) are still correctly populated inside 827 // the IPAM and that no configuration on the service is changed. 828 func TestAllocatorRestartNoEndpointSpec(t *testing.T) { 829 s := store.NewMemoryStore(nil) 830 assert.NotNil(t, s) 831 defer s.Close() 832 // Create 3 services with 1 task each 833 numsvcstsks := 3 834 assert.NoError(t, s.Update(func(tx store.Tx) error { 835 // populate ingress network 836 in := &api.Network{ 837 ID: "overlay1", 838 Spec: api.NetworkSpec{ 839 Annotations: api.Annotations{ 840 Name: "net1", 841 }, 842 }, 843 IPAM: &api.IPAMOptions{ 844 Driver: &api.Driver{}, 845 Configs: []*api.IPAMConfig{ 846 { 847 Subnet: "10.0.0.0/24", 848 Gateway: "10.0.0.1", 849 }, 850 }, 851 }, 852 DriverState: &api.Driver{}, 853 } 854 assert.NoError(t, store.CreateNetwork(tx, in)) 855 856 for i := 0; i != numsvcstsks; i++ { 857 svc := &api.Service{ 858 ID: "testServiceID" + strconv.Itoa(i), 859 Spec: api.ServiceSpec{ 860 Annotations: api.Annotations{ 861 Name: "service" + strconv.Itoa(i), 862 }, 863 // Endpoint: &api.EndpointSpec{ 864 // Mode: api.ResolutionModeVirtualIP, 865 // }, 866 Task: api.TaskSpec{ 867 Networks: []*api.NetworkAttachmentConfig{ 868 { 869 Target: "overlay1", 870 }, 871 }, 872 }, 873 }, 874 Endpoint: &api.Endpoint{ 875 Spec: &api.EndpointSpec{ 876 Mode: api.ResolutionModeVirtualIP, 877 }, 878 VirtualIPs: []*api.Endpoint_VirtualIP{ 879 { 880 NetworkID: "overlay1", 881 Addr: "10.0.0." + strconv.Itoa(2+2*i) + "/24", 882 }, 883 }, 884 }, 885 } 886 assert.NoError(t, store.CreateService(tx, svc)) 887 } 888 return nil 889 })) 890 891 for i := 0; i != numsvcstsks; i++ { 892 assert.NoError(t, s.Update(func(tx store.Tx) error { 893 tsk := &api.Task{ 894 ID: "testTaskID" + strconv.Itoa(i), 895 Status: api.TaskStatus{ 896 State: api.TaskStateNew, 897 }, 898 ServiceID: "testServiceID" + strconv.Itoa(i), 899 DesiredState: api.TaskStateRunning, 900 Networks: []*api.NetworkAttachment{ 901 { 902 Network: &api.Network{ 903 ID: "overlay1", 904 }, 905 }, 906 }, 907 } 908 assert.NoError(t, store.CreateTask(tx, tsk)) 909 return nil 910 })) 911 } 912 913 expectedIPs := map[string]string{ 914 "testServiceID0": "10.0.0.2/24", 915 "testServiceID1": "10.0.0.4/24", 916 "testServiceID2": "10.0.0.6/24", 917 "testTaskID0": "10.0.0.3/24", 918 "testTaskID1": "10.0.0.5/24", 919 "testTaskID2": "10.0.0.7/24", 920 } 921 assignedIPs := make(map[string]bool) 922 hasNoIPOverlapServices := func(fakeT assert.TestingT, service *api.Service) bool { 923 assert.NotEqual(fakeT, len(service.Endpoint.VirtualIPs), 0) 924 assert.NotEqual(fakeT, len(service.Endpoint.VirtualIPs[0].Addr), 0) 925 assignedVIP := service.Endpoint.VirtualIPs[0].Addr 926 if assignedIPs[assignedVIP] { 927 t.Fatalf("service %s assigned duplicate IP %s", service.ID, assignedVIP) 928 } 929 assignedIPs[assignedVIP] = true 930 ip, ok := expectedIPs[service.ID] 931 assert.True(t, ok) 932 assert.Equal(t, ip, assignedVIP) 933 delete(expectedIPs, service.ID) 934 return true 935 } 936 937 hasNoIPOverlapTasks := func(fakeT assert.TestingT, s *store.MemoryStore, task *api.Task) bool { 938 assert.NotEqual(fakeT, len(task.Networks), 0) 939 assert.NotEqual(fakeT, len(task.Networks[0].Addresses), 0) 940 assignedIP := task.Networks[0].Addresses[0] 941 if assignedIPs[assignedIP] { 942 t.Fatalf("task %s assigned duplicate IP %s", task.ID, assignedIP) 943 } 944 assignedIPs[assignedIP] = true 945 ip, ok := expectedIPs[task.ID] 946 assert.True(t, ok) 947 assert.Equal(t, ip, assignedIP) 948 delete(expectedIPs, task.ID) 949 return true 950 } 951 952 a, err := New(s, nil, nil) 953 assert.NoError(t, err) 954 assert.NotNil(t, a) 955 // Start allocator 956 go func() { 957 assert.NoError(t, a.Run(context.Background())) 958 }() 959 defer a.Stop() 960 961 taskWatch, cancel := state.Watch(s.WatchQueue(), api.EventUpdateTask{}, api.EventDeleteTask{}) 962 defer cancel() 963 964 serviceWatch, cancel := state.Watch(s.WatchQueue(), api.EventUpdateService{}, api.EventDeleteService{}) 965 defer cancel() 966 967 // Confirm tasks have no IPs that overlap with the services VIPs on restart 968 for i := 0; i != numsvcstsks; i++ { 969 watchTask(t, s, taskWatch, false, hasNoIPOverlapTasks) 970 watchService(t, serviceWatch, false, hasNoIPOverlapServices) 971 } 972 assert.Len(t, expectedIPs, 0) 973 } 974 975 // TestAllocatorRestoreForUnallocatedNetwork tests allocator restart 976 // scenarios where there is a combination of allocated and unallocated 977 // networks and tests whether the restore logic ensures the networks 978 // services and tasks that were preallocated are allocated correctly 979 // followed by the allocation of unallocated networks prior to the 980 // restart. 981 func TestAllocatorRestoreForUnallocatedNetwork(t *testing.T) { 982 s := store.NewMemoryStore(nil) 983 assert.NotNil(t, s) 984 defer s.Close() 985 // Create 3 services with 1 task each 986 numsvcstsks := 3 987 var n1 *api.Network 988 var n2 *api.Network 989 assert.NoError(t, s.Update(func(tx store.Tx) error { 990 // populate ingress network 991 in := &api.Network{ 992 ID: "ingress-nw-id", 993 Spec: api.NetworkSpec{ 994 Annotations: api.Annotations{ 995 Name: "default-ingress", 996 }, 997 Ingress: true, 998 }, 999 IPAM: &api.IPAMOptions{ 1000 Driver: &api.Driver{}, 1001 Configs: []*api.IPAMConfig{ 1002 { 1003 Subnet: "10.0.0.0/24", 1004 Gateway: "10.0.0.1", 1005 }, 1006 }, 1007 }, 1008 } 1009 assert.NoError(t, store.CreateNetwork(tx, in)) 1010 1011 n1 = &api.Network{ 1012 ID: "testID1", 1013 Spec: api.NetworkSpec{ 1014 Annotations: api.Annotations{ 1015 Name: "test1", 1016 }, 1017 }, 1018 IPAM: &api.IPAMOptions{ 1019 Driver: &api.Driver{}, 1020 Configs: []*api.IPAMConfig{ 1021 { 1022 Subnet: "10.1.0.0/24", 1023 Gateway: "10.1.0.1", 1024 }, 1025 }, 1026 }, 1027 DriverState: &api.Driver{}, 1028 } 1029 assert.NoError(t, store.CreateNetwork(tx, n1)) 1030 1031 n2 = &api.Network{ 1032 // Intentionally named testID0 so that in restore this network 1033 // is looked into first 1034 ID: "testID0", 1035 Spec: api.NetworkSpec{ 1036 Annotations: api.Annotations{ 1037 Name: "test2", 1038 }, 1039 }, 1040 } 1041 assert.NoError(t, store.CreateNetwork(tx, n2)) 1042 1043 for i := 0; i != numsvcstsks; i++ { 1044 svc := &api.Service{ 1045 ID: "testServiceID" + strconv.Itoa(i), 1046 Spec: api.ServiceSpec{ 1047 Annotations: api.Annotations{ 1048 Name: "service" + strconv.Itoa(i), 1049 }, 1050 Task: api.TaskSpec{ 1051 Networks: []*api.NetworkAttachmentConfig{ 1052 { 1053 Target: "testID1", 1054 }, 1055 }, 1056 }, 1057 Endpoint: &api.EndpointSpec{ 1058 Mode: api.ResolutionModeVirtualIP, 1059 Ports: []*api.PortConfig{ 1060 { 1061 Name: "", 1062 Protocol: api.ProtocolTCP, 1063 TargetPort: 8000, 1064 PublishedPort: uint32(8001 + i), 1065 }, 1066 }, 1067 }, 1068 }, 1069 Endpoint: &api.Endpoint{ 1070 Ports: []*api.PortConfig{ 1071 { 1072 Name: "", 1073 Protocol: api.ProtocolTCP, 1074 TargetPort: 8000, 1075 PublishedPort: uint32(8001 + i), 1076 }, 1077 }, 1078 VirtualIPs: []*api.Endpoint_VirtualIP{ 1079 { 1080 NetworkID: "ingress-nw-id", 1081 Addr: "10.0.0." + strconv.Itoa(2+i) + "/24", 1082 }, 1083 { 1084 NetworkID: "testID1", 1085 Addr: "10.1.0." + strconv.Itoa(2+i) + "/24", 1086 }, 1087 }, 1088 }, 1089 } 1090 assert.NoError(t, store.CreateService(tx, svc)) 1091 } 1092 return nil 1093 })) 1094 1095 for i := 0; i != numsvcstsks; i++ { 1096 assert.NoError(t, s.Update(func(tx store.Tx) error { 1097 tsk := &api.Task{ 1098 ID: "testTaskID" + strconv.Itoa(i), 1099 Status: api.TaskStatus{ 1100 State: api.TaskStateNew, 1101 }, 1102 Spec: api.TaskSpec{ 1103 Networks: []*api.NetworkAttachmentConfig{ 1104 { 1105 Target: "testID1", 1106 }, 1107 }, 1108 }, 1109 ServiceID: "testServiceID" + strconv.Itoa(i), 1110 DesiredState: api.TaskStateRunning, 1111 } 1112 assert.NoError(t, store.CreateTask(tx, tsk)) 1113 return nil 1114 })) 1115 } 1116 1117 assignedIPs := make(map[string]bool) 1118 expectedIPs := map[string]string{ 1119 "testServiceID0": "10.1.0.2/24", 1120 "testServiceID1": "10.1.0.3/24", 1121 "testServiceID2": "10.1.0.4/24", 1122 "testTaskID0": "10.1.0.5/24", 1123 "testTaskID1": "10.1.0.6/24", 1124 "testTaskID2": "10.1.0.7/24", 1125 } 1126 hasNoIPOverlapServices := func(fakeT assert.TestingT, service *api.Service) bool { 1127 assert.NotEqual(fakeT, len(service.Endpoint.VirtualIPs), 0) 1128 assert.NotEqual(fakeT, len(service.Endpoint.VirtualIPs[0].Addr), 0) 1129 assignedVIP := service.Endpoint.VirtualIPs[1].Addr 1130 if assignedIPs[assignedVIP] { 1131 t.Fatalf("service %s assigned duplicate IP %s", service.ID, assignedVIP) 1132 } 1133 assignedIPs[assignedVIP] = true 1134 ip, ok := expectedIPs[service.ID] 1135 assert.True(t, ok) 1136 assert.Equal(t, ip, assignedVIP) 1137 delete(expectedIPs, service.ID) 1138 return true 1139 } 1140 1141 hasNoIPOverlapTasks := func(fakeT assert.TestingT, s *store.MemoryStore, task *api.Task) bool { 1142 assert.NotEqual(fakeT, len(task.Networks), 0) 1143 assert.NotEqual(fakeT, len(task.Networks[0].Addresses), 0) 1144 assignedIP := task.Networks[1].Addresses[0] 1145 if assignedIPs[assignedIP] { 1146 t.Fatalf("task %s assigned duplicate IP %s", task.ID, assignedIP) 1147 } 1148 assignedIPs[assignedIP] = true 1149 ip, ok := expectedIPs[task.ID] 1150 assert.True(t, ok) 1151 assert.Equal(t, ip, assignedIP) 1152 delete(expectedIPs, task.ID) 1153 return true 1154 } 1155 1156 a, err := New(s, nil, nil) 1157 assert.NoError(t, err) 1158 assert.NotNil(t, a) 1159 // Start allocator 1160 go func() { 1161 assert.NoError(t, a.Run(context.Background())) 1162 }() 1163 defer a.Stop() 1164 1165 taskWatch, cancel := state.Watch(s.WatchQueue(), api.EventUpdateTask{}, api.EventDeleteTask{}) 1166 defer cancel() 1167 1168 serviceWatch, cancel := state.Watch(s.WatchQueue(), api.EventUpdateService{}, api.EventDeleteService{}) 1169 defer cancel() 1170 1171 // Confirm tasks have no IPs that overlap with the services VIPs on restart 1172 for i := 0; i != numsvcstsks; i++ { 1173 watchTask(t, s, taskWatch, false, hasNoIPOverlapTasks) 1174 watchService(t, serviceWatch, false, hasNoIPOverlapServices) 1175 } 1176 } 1177 1178 func TestNodeAllocator(t *testing.T) { 1179 s := store.NewMemoryStore(nil) 1180 assert.NotNil(t, s) 1181 defer s.Close() 1182 1183 a, err := New(s, nil, nil) 1184 assert.NoError(t, err) 1185 assert.NotNil(t, a) 1186 1187 var node1FromStore *api.Node 1188 node1 := &api.Node{ 1189 ID: "nodeID1", 1190 } 1191 1192 // Try adding some objects to store before allocator is started 1193 assert.NoError(t, s.Update(func(tx store.Tx) error { 1194 // populate ingress network 1195 in := &api.Network{ 1196 ID: "ingress", 1197 Spec: api.NetworkSpec{ 1198 Annotations: api.Annotations{ 1199 Name: "ingress", 1200 }, 1201 Ingress: true, 1202 }, 1203 } 1204 assert.NoError(t, store.CreateNetwork(tx, in)) 1205 1206 n1 := &api.Network{ 1207 ID: "overlayID1", 1208 Spec: api.NetworkSpec{ 1209 Annotations: api.Annotations{ 1210 Name: "overlayID1", 1211 }, 1212 }, 1213 } 1214 assert.NoError(t, store.CreateNetwork(tx, n1)) 1215 1216 // this network will never be used for any task 1217 nUnused := &api.Network{ 1218 ID: "overlayIDUnused", 1219 Spec: api.NetworkSpec{ 1220 Annotations: api.Annotations{ 1221 Name: "overlayIDUnused", 1222 }, 1223 }, 1224 } 1225 assert.NoError(t, store.CreateNetwork(tx, nUnused)) 1226 1227 assert.NoError(t, store.CreateNode(tx, node1)) 1228 1229 return nil 1230 })) 1231 1232 nodeWatch, cancel := state.Watch(s.WatchQueue(), api.EventUpdateNode{}, api.EventDeleteNode{}) 1233 defer cancel() 1234 netWatch, cancel := state.Watch(s.WatchQueue(), api.EventUpdateNetwork{}, api.EventDeleteNetwork{}) 1235 defer cancel() 1236 taskWatch, cancel := state.Watch(s.WatchQueue(), api.EventUpdateTask{}) 1237 defer cancel() 1238 1239 // Start allocator 1240 go func() { 1241 assert.NoError(t, a.Run(context.Background())) 1242 }() 1243 defer a.Stop() 1244 1245 assert.NoError(t, s.Update(func(tx store.Tx) error { 1246 // create a task assigned to this node that has a network attachment on 1247 // n1 1248 t1 := &api.Task{ 1249 ID: "task1", 1250 NodeID: node1.ID, 1251 DesiredState: api.TaskStateRunning, 1252 Spec: api.TaskSpec{ 1253 Networks: []*api.NetworkAttachmentConfig{ 1254 { 1255 Target: "overlayID1", 1256 }, 1257 }, 1258 }, 1259 } 1260 1261 return store.CreateTask(tx, t1) 1262 })) 1263 1264 // validate that the task is created 1265 watchTask(t, s, taskWatch, false, isValidTask) 1266 1267 // Validate node has 2 LB IP address (1 for each network). 1268 watchNetwork(t, netWatch, false, isValidNetwork) // ingress 1269 watchNetwork(t, netWatch, false, isValidNetwork) // overlayID1 1270 watchNetwork(t, netWatch, false, isValidNetwork) // overlayIDUnused 1271 watchNode(t, nodeWatch, false, isValidNode, node1, []string{"ingress", "overlayID1"}) // node1 1272 1273 // Add a node and validate it gets a LB ip only on ingress, as it has no 1274 // tasks assigned. 1275 node2 := &api.Node{ 1276 ID: "nodeID2", 1277 } 1278 assert.NoError(t, s.Update(func(tx store.Tx) error { 1279 assert.NoError(t, store.CreateNode(tx, node2)) 1280 return nil 1281 })) 1282 watchNode(t, nodeWatch, false, isValidNode, node2, []string{"ingress"}) // node2 1283 1284 // Add a network and validate that nothing has changed in the nodes 1285 n2 := &api.Network{ 1286 ID: "overlayID2", 1287 Spec: api.NetworkSpec{ 1288 Annotations: api.Annotations{ 1289 Name: "overlayID2", 1290 }, 1291 }, 1292 } 1293 assert.NoError(t, s.Update(func(tx store.Tx) error { 1294 assert.NoError(t, store.CreateNetwork(tx, n2)) 1295 return nil 1296 })) 1297 watchNetwork(t, netWatch, false, isValidNetwork) // overlayID2 1298 // nothing should change, no updates 1299 watchNode(t, nodeWatch, true, isValidNode, node1, []string{"ingress", "overlayID1"}) // node1 1300 watchNode(t, nodeWatch, true, isValidNode, node2, []string{"ingress"}) // node2 1301 1302 // add a task and validate that the node gets the network for the task 1303 assert.NoError(t, s.Update(func(tx store.Tx) error { 1304 // create a task assigned to this node that has a network attachment on 1305 // n1 1306 t2 := &api.Task{ 1307 ID: "task2", 1308 NodeID: node2.ID, 1309 DesiredState: api.TaskStateRunning, 1310 Spec: api.TaskSpec{ 1311 Networks: []*api.NetworkAttachmentConfig{ 1312 { 1313 Target: "overlayID2", 1314 }, 1315 }, 1316 }, 1317 } 1318 1319 return store.CreateTask(tx, t2) 1320 })) 1321 // validate that the task is created 1322 watchTask(t, s, taskWatch, false, isValidTask) 1323 1324 // validate that node2 gets a new attachment and node1 stays the same 1325 watchNode(t, nodeWatch, false, isValidNode, node2, []string{"ingress", "overlayID2"}) // node2 1326 watchNode(t, nodeWatch, true, isValidNode, node1, []string{"ingress", "overlayID1"}) // node1 1327 1328 // add another task with the same network to a node and validate that it 1329 // still only has 1 attachment for that network 1330 assert.NoError(t, s.Update(func(tx store.Tx) error { 1331 // create a task assigned to this node that has a network attachment on 1332 // n1 1333 t3 := &api.Task{ 1334 ID: "task3", 1335 NodeID: node1.ID, 1336 DesiredState: api.TaskStateRunning, 1337 Spec: api.TaskSpec{ 1338 Networks: []*api.NetworkAttachmentConfig{ 1339 { 1340 Target: "overlayID1", 1341 }, 1342 }, 1343 }, 1344 } 1345 1346 return store.CreateTask(tx, t3) 1347 })) 1348 1349 // validate that the task is created 1350 watchTask(t, s, taskWatch, false, isValidTask) 1351 1352 // validate that nothing changes 1353 watchNode(t, nodeWatch, true, isValidNode, node1, []string{"ingress", "overlayID1"}) // node1 1354 watchNode(t, nodeWatch, true, isValidNode, node2, []string{"ingress", "overlayID2"}) // node2 1355 1356 // now remove that task we just created, and validate that the node still 1357 // has an attachment for the other task 1358 // Remove a node and validate remaining node has 2 LB IP addresses 1359 assert.NoError(t, s.Update(func(tx store.Tx) error { 1360 assert.NoError(t, store.DeleteTask(tx, "task1")) 1361 return nil 1362 })) 1363 1364 // validate that nothing changes 1365 watchNode(t, nodeWatch, true, isValidNode, node1, []string{"ingress", "overlayID1"}) // node1 1366 watchNode(t, nodeWatch, true, isValidNode, node2, []string{"ingress", "overlayID2"}) // node2 1367 1368 // now remove another task. this time the attachment on the node should be 1369 // removed as well 1370 assert.NoError(t, s.Update(func(tx store.Tx) error { 1371 assert.NoError(t, store.DeleteTask(tx, "task2")) 1372 return nil 1373 })) 1374 1375 watchNode(t, nodeWatch, false, isValidNode, node2, []string{"ingress"}) // node2 1376 watchNode(t, nodeWatch, true, isValidNode, node1, []string{"ingress", "overlayID1"}) // node1 1377 1378 // Remove a node and validate remaining node has 2 LB IP addresses 1379 assert.NoError(t, s.Update(func(tx store.Tx) error { 1380 assert.NoError(t, store.DeleteNode(tx, node2.ID)) 1381 return nil 1382 })) 1383 watchNode(t, nodeWatch, false, nil, nil, nil) // node2 1384 s.View(func(tx store.ReadTx) { 1385 node1FromStore = store.GetNode(tx, node1.ID) 1386 }) 1387 1388 isValidNode(t, node1, node1FromStore, []string{"ingress", "overlayID1"}) 1389 1390 // Validate that a LB IP address is not allocated for node-local networks 1391 p := &api.Network{ 1392 ID: "bridge", 1393 Spec: api.NetworkSpec{ 1394 Annotations: api.Annotations{ 1395 Name: "pred_bridge_network", 1396 Labels: map[string]string{ 1397 "com.docker.swarm.predefined": "true", 1398 }, 1399 }, 1400 DriverConfig: &api.Driver{Name: "bridge"}, 1401 }, 1402 } 1403 assert.NoError(t, s.Update(func(tx store.Tx) error { 1404 assert.NoError(t, store.CreateNetwork(tx, p)) 1405 return nil 1406 })) 1407 watchNetwork(t, netWatch, false, isValidNetwork) // bridge 1408 1409 s.View(func(tx store.ReadTx) { 1410 node1FromStore = store.GetNode(tx, node1.ID) 1411 }) 1412 1413 isValidNode(t, node1, node1FromStore, []string{"ingress", "overlayID1"}) 1414 } 1415 1416 // TestNodeAttachmentOnLeadershipChange tests that a Node which is only partly 1417 // allocated during a leadership change is correctly allocated afterward 1418 func TestNodeAttachmentOnLeadershipChange(t *testing.T) { 1419 s := store.NewMemoryStore(nil) 1420 assert.NotNil(t, s) 1421 defer s.Close() 1422 1423 a, err := New(s, nil, nil) 1424 assert.NoError(t, err) 1425 assert.NotNil(t, a) 1426 1427 net1 := &api.Network{ 1428 ID: "ingress", 1429 Spec: api.NetworkSpec{ 1430 Annotations: api.Annotations{ 1431 Name: "ingress", 1432 }, 1433 Ingress: true, 1434 }, 1435 } 1436 1437 net2 := &api.Network{ 1438 ID: "net2", 1439 Spec: api.NetworkSpec{ 1440 Annotations: api.Annotations{ 1441 Name: "net2", 1442 }, 1443 }, 1444 } 1445 1446 node1 := &api.Node{ 1447 ID: "node1", 1448 } 1449 1450 task1 := &api.Task{ 1451 ID: "task1", 1452 NodeID: node1.ID, 1453 DesiredState: api.TaskStateRunning, 1454 Spec: api.TaskSpec{}, 1455 } 1456 1457 // this task is not yet assigned. we will assign it to node1 after running 1458 // the allocator a 2nd time. we should create it now so that its network 1459 // attachments are allocated. 1460 task2 := &api.Task{ 1461 ID: "task2", 1462 DesiredState: api.TaskStateRunning, 1463 Spec: api.TaskSpec{ 1464 Networks: []*api.NetworkAttachmentConfig{ 1465 { 1466 Target: "net2", 1467 }, 1468 }, 1469 }, 1470 } 1471 1472 // before starting the allocator, populate with these 1473 assert.NoError(t, s.Update(func(tx store.Tx) error { 1474 require.NoError(t, store.CreateNetwork(tx, net1)) 1475 require.NoError(t, store.CreateNetwork(tx, net2)) 1476 require.NoError(t, store.CreateNode(tx, node1)) 1477 require.NoError(t, store.CreateTask(tx, task1)) 1478 require.NoError(t, store.CreateTask(tx, task2)) 1479 return nil 1480 })) 1481 1482 // now start the allocator, let it allocate all of these objects, and then 1483 // stop it. it's easier to do this than to manually assign all of the 1484 // values 1485 1486 nodeWatch, cancel := state.Watch(s.WatchQueue(), api.EventUpdateNode{}, api.EventDeleteNode{}) 1487 defer cancel() 1488 netWatch, cancel := state.Watch(s.WatchQueue(), api.EventUpdateNetwork{}, api.EventDeleteNetwork{}) 1489 defer cancel() 1490 taskWatch, cancel := state.Watch(s.WatchQueue(), api.EventUpdateTask{}) 1491 defer cancel() 1492 1493 ctx, ctxCancel := context.WithCancel(context.Background()) 1494 go func() { 1495 assert.NoError(t, a.Run(ctx)) 1496 }() 1497 1498 // validate that everything gets allocated 1499 watchNetwork(t, netWatch, false, isValidNetwork) 1500 watchNetwork(t, netWatch, false, isValidNetwork) 1501 watchNode(t, nodeWatch, false, isValidNode, node1, []string{"ingress"}) 1502 watchTask(t, s, taskWatch, false, isValidTask) 1503 1504 // once everything is created, go ahead and stop the allocator 1505 a.Stop() 1506 ctxCancel() 1507 1508 // now update task2 to assign it to node1 1509 s.Update(func(tx store.Tx) error { 1510 task := store.GetTask(tx, task2.ID) 1511 require.NotNil(t, task) 1512 // make sure it has 1 network attachment 1513 assert.Len(t, task.Networks, 1) 1514 task.NodeID = node1.ID 1515 require.NoError(t, store.UpdateTask(tx, task)) 1516 return nil 1517 }) 1518 1519 // and now we'll start a new allocator. 1520 a2, err := New(s, nil, nil) 1521 assert.NoError(t, err) 1522 assert.NotNil(t, a2) 1523 1524 ctx2, cancel2 := context.WithCancel(context.Background()) 1525 go func() { 1526 assert.NoError(t, a2.Run(ctx2)) 1527 }() 1528 defer a2.Stop() 1529 defer cancel2() 1530 1531 // now we should see the node get allocated 1532 watchNode(t, nodeWatch, false, isValidNode, node1, []string{"ingress"}) 1533 watchNode(t, nodeWatch, false, isValidNode, node1, []string{"ingress", "net2"}) 1534 } 1535 1536 func isValidNode(t assert.TestingT, originalNode, updatedNode *api.Node, networks []string) bool { 1537 1538 if !assert.Equal(t, originalNode.ID, updatedNode.ID) { 1539 return false 1540 } 1541 1542 if !assert.Equal(t, len(updatedNode.Attachments), len(networks)) { 1543 return false 1544 } 1545 1546 for _, na := range updatedNode.Attachments { 1547 if !assert.Equal(t, len(na.Addresses), 1) { 1548 return false 1549 } 1550 } 1551 1552 return true 1553 } 1554 1555 func isValidNetwork(t assert.TestingT, n *api.Network) bool { 1556 if _, ok := n.Spec.Annotations.Labels["com.docker.swarm.predefined"]; ok { 1557 return true 1558 } 1559 return assert.NotEqual(t, n.IPAM.Configs, nil) && 1560 assert.Equal(t, len(n.IPAM.Configs), 1) && 1561 assert.Equal(t, n.IPAM.Configs[0].Range, "") && 1562 assert.Equal(t, len(n.IPAM.Configs[0].Reserved), 0) && 1563 isValidSubnet(t, n.IPAM.Configs[0].Subnet) && 1564 assert.NotEqual(t, net.ParseIP(n.IPAM.Configs[0].Gateway), nil) 1565 } 1566 1567 func isValidTask(t assert.TestingT, s *store.MemoryStore, task *api.Task) bool { 1568 return isValidNetworkAttachment(t, task) && 1569 isValidEndpoint(t, s, task) && 1570 assert.Equal(t, task.Status.State, api.TaskStatePending) 1571 } 1572 1573 func isValidNetworkAttachment(t assert.TestingT, task *api.Task) bool { 1574 if len(task.Networks) != 0 { 1575 return assert.Equal(t, len(task.Networks[0].Addresses), 1) && 1576 isValidSubnet(t, task.Networks[0].Addresses[0]) 1577 } 1578 1579 return true 1580 } 1581 1582 func isValidEndpoint(t assert.TestingT, s *store.MemoryStore, task *api.Task) bool { 1583 if task.ServiceID != "" { 1584 var service *api.Service 1585 s.View(func(tx store.ReadTx) { 1586 service = store.GetService(tx, task.ServiceID) 1587 }) 1588 1589 if service == nil { 1590 return true 1591 } 1592 1593 return assert.Equal(t, service.Endpoint, task.Endpoint) 1594 1595 } 1596 1597 return true 1598 } 1599 1600 func isValidSubnet(t assert.TestingT, subnet string) bool { 1601 _, _, err := net.ParseCIDR(subnet) 1602 return assert.NoError(t, err) 1603 } 1604 1605 type mockTester struct{} 1606 1607 func (m mockTester) Errorf(format string, args ...interface{}) { 1608 } 1609 1610 // Returns a timeout given whether we should expect a timeout: In the case where we do expect a timeout, 1611 // the timeout should be short, because it's not very useful to wait long amounts of time just in case 1612 // an unexpected event comes in - a short timeout should catch an incorrect event at least often enough 1613 // to make the test flaky and alert us to the problem. But in the cases where we don't expect a timeout, 1614 // the timeout should be on the order of several seconds, so the test doesn't fail just because it's run 1615 // on a relatively slow system, or there's a load spike. 1616 func getWatchTimeout(expectTimeout bool) time.Duration { 1617 if expectTimeout { 1618 return 350 * time.Millisecond 1619 } 1620 return 5 * time.Second 1621 } 1622 1623 func watchNode(t *testing.T, watch chan events.Event, expectTimeout bool, 1624 fn func(t assert.TestingT, originalNode, updatedNode *api.Node, networks []string) bool, 1625 originalNode *api.Node, 1626 networks []string) { 1627 for { 1628 1629 var node *api.Node 1630 select { 1631 case event := <-watch: 1632 if n, ok := event.(api.EventUpdateNode); ok { 1633 node = n.Node.Copy() 1634 if fn == nil || (fn != nil && fn(mockTester{}, originalNode, node, networks)) { 1635 return 1636 } 1637 } 1638 1639 if n, ok := event.(api.EventDeleteNode); ok { 1640 node = n.Node.Copy() 1641 if fn == nil || (fn != nil && fn(mockTester{}, originalNode, node, networks)) { 1642 return 1643 } 1644 } 1645 1646 case <-time.After(getWatchTimeout(expectTimeout)): 1647 if !expectTimeout { 1648 if node != nil && fn != nil { 1649 fn(t, originalNode, node, networks) 1650 } 1651 1652 t.Fatal("timed out before watchNode found expected node state", string(debug.Stack())) 1653 } 1654 1655 return 1656 } 1657 } 1658 } 1659 1660 func watchNetwork(t *testing.T, watch chan events.Event, expectTimeout bool, fn func(t assert.TestingT, n *api.Network) bool) { 1661 for { 1662 var network *api.Network 1663 select { 1664 case event := <-watch: 1665 if n, ok := event.(api.EventUpdateNetwork); ok { 1666 network = n.Network.Copy() 1667 if fn == nil || (fn != nil && fn(mockTester{}, network)) { 1668 return 1669 } 1670 } 1671 1672 if n, ok := event.(api.EventDeleteNetwork); ok { 1673 network = n.Network.Copy() 1674 if fn == nil || (fn != nil && fn(mockTester{}, network)) { 1675 return 1676 } 1677 } 1678 1679 case <-time.After(getWatchTimeout(expectTimeout)): 1680 if !expectTimeout { 1681 if network != nil && fn != nil { 1682 fn(t, network) 1683 } 1684 1685 t.Fatal("timed out before watchNetwork found expected network state", string(debug.Stack())) 1686 } 1687 1688 return 1689 } 1690 } 1691 } 1692 1693 func watchService(t *testing.T, watch chan events.Event, expectTimeout bool, fn func(t assert.TestingT, n *api.Service) bool) { 1694 for { 1695 var service *api.Service 1696 select { 1697 case event := <-watch: 1698 if s, ok := event.(api.EventUpdateService); ok { 1699 service = s.Service.Copy() 1700 if fn == nil || (fn != nil && fn(mockTester{}, service)) { 1701 return 1702 } 1703 } 1704 1705 if s, ok := event.(api.EventDeleteService); ok { 1706 service = s.Service.Copy() 1707 if fn == nil || (fn != nil && fn(mockTester{}, service)) { 1708 return 1709 } 1710 } 1711 1712 case <-time.After(getWatchTimeout(expectTimeout)): 1713 if !expectTimeout { 1714 if service != nil && fn != nil { 1715 fn(t, service) 1716 } 1717 1718 t.Fatalf("timed out before watchService found expected service state\n stack = %s", string(debug.Stack())) 1719 } 1720 1721 return 1722 } 1723 } 1724 } 1725 1726 func watchTask(t *testing.T, s *store.MemoryStore, watch chan events.Event, expectTimeout bool, fn func(t assert.TestingT, s *store.MemoryStore, n *api.Task) bool) { 1727 for { 1728 var task *api.Task 1729 select { 1730 case event := <-watch: 1731 if t, ok := event.(api.EventUpdateTask); ok { 1732 task = t.Task.Copy() 1733 if fn == nil || (fn != nil && fn(mockTester{}, s, task)) { 1734 return 1735 } 1736 } 1737 1738 if t, ok := event.(api.EventDeleteTask); ok { 1739 task = t.Task.Copy() 1740 if fn == nil || (fn != nil && fn(mockTester{}, s, task)) { 1741 return 1742 } 1743 } 1744 1745 case <-time.After(getWatchTimeout(expectTimeout)): 1746 if !expectTimeout { 1747 if task != nil && fn != nil { 1748 fn(t, s, task) 1749 } 1750 1751 t.Fatalf("timed out before watchTask found expected task state %s", debug.Stack()) 1752 } 1753 1754 return 1755 } 1756 } 1757 }