github.com/moby/docker@v26.1.3+incompatible/libnetwork/cnmallocator/networkallocator_test.go (about) 1 package cnmallocator 2 3 import ( 4 "fmt" 5 "net" 6 "testing" 7 8 "github.com/docker/docker/libnetwork/types" 9 "github.com/moby/swarmkit/v2/api" 10 "github.com/moby/swarmkit/v2/manager/allocator/networkallocator" 11 "gotest.tools/v3/assert" 12 is "gotest.tools/v3/assert/cmp" 13 ) 14 15 func newNetworkAllocator(t *testing.T) networkallocator.NetworkAllocator { 16 na, err := (&Provider{}).NewAllocator(nil) 17 assert.Check(t, err) 18 assert.Check(t, na != nil) 19 return na 20 } 21 22 func TestNew(t *testing.T) { 23 newNetworkAllocator(t) 24 } 25 26 func TestAllocateInvalidIPAM(t *testing.T) { 27 na := newNetworkAllocator(t) 28 n := &api.Network{ 29 ID: "testID", 30 Spec: api.NetworkSpec{ 31 Annotations: api.Annotations{ 32 Name: "test", 33 }, 34 DriverConfig: &api.Driver{}, 35 IPAM: &api.IPAMOptions{ 36 Driver: &api.Driver{ 37 Name: "invalidipam,", 38 }, 39 }, 40 }, 41 } 42 err := na.Allocate(n) 43 assert.Check(t, is.ErrorContains(err, "")) 44 } 45 46 func TestAllocateInvalidDriver(t *testing.T) { 47 na := newNetworkAllocator(t) 48 n := &api.Network{ 49 ID: "testID", 50 Spec: api.NetworkSpec{ 51 Annotations: api.Annotations{ 52 Name: "test", 53 }, 54 DriverConfig: &api.Driver{ 55 Name: "invaliddriver", 56 }, 57 }, 58 } 59 60 err := na.Allocate(n) 61 assert.Check(t, is.ErrorContains(err, "")) 62 } 63 64 func TestNetworkDoubleAllocate(t *testing.T) { 65 na := newNetworkAllocator(t) 66 n := &api.Network{ 67 ID: "testID", 68 Spec: api.NetworkSpec{ 69 Annotations: api.Annotations{ 70 Name: "test", 71 }, 72 }, 73 } 74 75 err := na.Allocate(n) 76 assert.Check(t, err) 77 78 err = na.Allocate(n) 79 assert.Check(t, is.ErrorContains(err, "")) 80 } 81 82 func TestAllocateEmptyConfig(t *testing.T) { 83 na1 := newNetworkAllocator(t) 84 na2 := newNetworkAllocator(t) 85 n1 := &api.Network{ 86 ID: "testID1", 87 Spec: api.NetworkSpec{ 88 Annotations: api.Annotations{ 89 Name: "test1", 90 }, 91 }, 92 } 93 94 n2 := &api.Network{ 95 ID: "testID2", 96 Spec: api.NetworkSpec{ 97 Annotations: api.Annotations{ 98 Name: "test2", 99 }, 100 }, 101 } 102 103 err := na1.Allocate(n1) 104 assert.Check(t, err) 105 assert.Check(t, n1.IPAM.Configs != nil) 106 assert.Check(t, is.Equal(len(n1.IPAM.Configs), 1)) 107 assert.Check(t, is.Equal(n1.IPAM.Configs[0].Range, "")) 108 assert.Check(t, is.Equal(len(n1.IPAM.Configs[0].Reserved), 0)) 109 110 _, subnet11, err := net.ParseCIDR(n1.IPAM.Configs[0].Subnet) 111 assert.Check(t, err) 112 113 gwip11 := net.ParseIP(n1.IPAM.Configs[0].Gateway) 114 assert.Check(t, gwip11 != nil) 115 116 err = na1.Allocate(n2) 117 assert.Check(t, err) 118 assert.Check(t, n2.IPAM.Configs != nil) 119 assert.Check(t, is.Equal(len(n2.IPAM.Configs), 1)) 120 assert.Check(t, is.Equal(n2.IPAM.Configs[0].Range, "")) 121 assert.Check(t, is.Equal(len(n2.IPAM.Configs[0].Reserved), 0)) 122 123 _, subnet21, err := net.ParseCIDR(n2.IPAM.Configs[0].Subnet) 124 assert.Check(t, err) 125 126 gwip21 := net.ParseIP(n2.IPAM.Configs[0].Gateway) 127 assert.Check(t, gwip21 != nil) 128 129 // Allocate n1 ans n2 with another allocator instance but in 130 // intentionally reverse order. 131 err = na2.Allocate(n2) 132 assert.Check(t, err) 133 assert.Check(t, n2.IPAM.Configs != nil) 134 assert.Check(t, is.Equal(len(n2.IPAM.Configs), 1)) 135 assert.Check(t, is.Equal(n2.IPAM.Configs[0].Range, "")) 136 assert.Check(t, is.Equal(len(n2.IPAM.Configs[0].Reserved), 0)) 137 138 _, subnet22, err := net.ParseCIDR(n2.IPAM.Configs[0].Subnet) 139 assert.Check(t, err) 140 assert.Check(t, is.DeepEqual(subnet21, subnet22)) 141 142 gwip22 := net.ParseIP(n2.IPAM.Configs[0].Gateway) 143 assert.Check(t, is.DeepEqual(gwip21, gwip22)) 144 145 err = na2.Allocate(n1) 146 assert.Check(t, err) 147 assert.Check(t, n1.IPAM.Configs != nil) 148 assert.Check(t, is.Equal(len(n1.IPAM.Configs), 1)) 149 assert.Check(t, is.Equal(n1.IPAM.Configs[0].Range, "")) 150 assert.Check(t, is.Equal(len(n1.IPAM.Configs[0].Reserved), 0)) 151 152 _, subnet12, err := net.ParseCIDR(n1.IPAM.Configs[0].Subnet) 153 assert.Check(t, err) 154 assert.Check(t, is.DeepEqual(subnet11, subnet12)) 155 156 gwip12 := net.ParseIP(n1.IPAM.Configs[0].Gateway) 157 assert.Check(t, is.DeepEqual(gwip11, gwip12)) 158 } 159 160 func TestAllocateWithOneSubnet(t *testing.T) { 161 na := newNetworkAllocator(t) 162 n := &api.Network{ 163 ID: "testID", 164 Spec: api.NetworkSpec{ 165 Annotations: api.Annotations{ 166 Name: "test", 167 }, 168 DriverConfig: &api.Driver{}, 169 IPAM: &api.IPAMOptions{ 170 Driver: &api.Driver{}, 171 Configs: []*api.IPAMConfig{ 172 { 173 Subnet: "192.168.1.0/24", 174 }, 175 }, 176 }, 177 }, 178 } 179 180 err := na.Allocate(n) 181 assert.Check(t, err) 182 assert.Check(t, is.Equal(len(n.IPAM.Configs), 1)) 183 assert.Check(t, is.Equal(n.IPAM.Configs[0].Range, "")) 184 assert.Check(t, is.Equal(len(n.IPAM.Configs[0].Reserved), 0)) 185 assert.Check(t, is.Equal(n.IPAM.Configs[0].Subnet, "192.168.1.0/24")) 186 187 ip := net.ParseIP(n.IPAM.Configs[0].Gateway) 188 assert.Check(t, ip != nil) 189 } 190 191 func TestAllocateWithOneSubnetGateway(t *testing.T) { 192 na := newNetworkAllocator(t) 193 n := &api.Network{ 194 ID: "testID", 195 Spec: api.NetworkSpec{ 196 Annotations: api.Annotations{ 197 Name: "test", 198 }, 199 DriverConfig: &api.Driver{}, 200 IPAM: &api.IPAMOptions{ 201 Driver: &api.Driver{}, 202 Configs: []*api.IPAMConfig{ 203 { 204 Subnet: "192.168.1.0/24", 205 Gateway: "192.168.1.1", 206 }, 207 }, 208 }, 209 }, 210 } 211 212 err := na.Allocate(n) 213 assert.Check(t, err) 214 assert.Check(t, is.Equal(len(n.IPAM.Configs), 1)) 215 assert.Check(t, is.Equal(n.IPAM.Configs[0].Range, "")) 216 assert.Check(t, is.Equal(len(n.IPAM.Configs[0].Reserved), 0)) 217 assert.Check(t, is.Equal(n.IPAM.Configs[0].Subnet, "192.168.1.0/24")) 218 assert.Check(t, is.Equal(n.IPAM.Configs[0].Gateway, "192.168.1.1")) 219 } 220 221 func TestAllocateWithOneSubnetInvalidGateway(t *testing.T) { 222 na := newNetworkAllocator(t) 223 n := &api.Network{ 224 ID: "testID", 225 Spec: api.NetworkSpec{ 226 Annotations: api.Annotations{ 227 Name: "test", 228 }, 229 DriverConfig: &api.Driver{}, 230 IPAM: &api.IPAMOptions{ 231 Driver: &api.Driver{}, 232 Configs: []*api.IPAMConfig{ 233 { 234 Subnet: "192.168.1.0/24", 235 Gateway: "192.168.2.1", 236 }, 237 }, 238 }, 239 }, 240 } 241 242 err := na.Allocate(n) 243 assert.Check(t, is.ErrorContains(err, "")) 244 } 245 246 // TestAllocateWithSmallSubnet validates that /32 subnets don't produce an error, 247 // as /31 and /32 subnets are supported by docker daemon, starting with 248 // https://github.com/moby/moby/commit/3a938df4b570aad3bfb4d5342379582e872fc1a3, 249 func TestAllocateWithSmallSubnet(t *testing.T) { 250 na := newNetworkAllocator(t) 251 n := &api.Network{ 252 ID: "testID", 253 Spec: api.NetworkSpec{ 254 Annotations: api.Annotations{ 255 Name: "test", 256 }, 257 DriverConfig: &api.Driver{}, 258 IPAM: &api.IPAMOptions{ 259 Driver: &api.Driver{}, 260 Configs: []*api.IPAMConfig{ 261 { 262 Subnet: "1.1.1.1/32", 263 }, 264 }, 265 }, 266 }, 267 } 268 269 err := na.Allocate(n) 270 assert.Check(t, err) 271 } 272 273 func TestAllocateWithTwoSubnetsNoGateway(t *testing.T) { 274 na := newNetworkAllocator(t) 275 n := &api.Network{ 276 ID: "testID", 277 Spec: api.NetworkSpec{ 278 Annotations: api.Annotations{ 279 Name: "test", 280 }, 281 DriverConfig: &api.Driver{}, 282 IPAM: &api.IPAMOptions{ 283 Driver: &api.Driver{}, 284 Configs: []*api.IPAMConfig{ 285 { 286 Subnet: "192.168.1.0/24", 287 }, 288 { 289 Subnet: "192.168.2.0/24", 290 }, 291 }, 292 }, 293 }, 294 } 295 296 err := na.Allocate(n) 297 assert.Check(t, err) 298 assert.Check(t, is.Equal(len(n.IPAM.Configs), 2)) 299 assert.Check(t, is.Equal(n.IPAM.Configs[0].Range, "")) 300 assert.Check(t, is.Equal(len(n.IPAM.Configs[0].Reserved), 0)) 301 assert.Check(t, is.Equal(n.IPAM.Configs[0].Subnet, "192.168.1.0/24")) 302 assert.Check(t, is.Equal(n.IPAM.Configs[1].Range, "")) 303 assert.Check(t, is.Equal(len(n.IPAM.Configs[1].Reserved), 0)) 304 assert.Check(t, is.Equal(n.IPAM.Configs[1].Subnet, "192.168.2.0/24")) 305 306 ip := net.ParseIP(n.IPAM.Configs[0].Gateway) 307 assert.Check(t, ip != nil) 308 ip = net.ParseIP(n.IPAM.Configs[1].Gateway) 309 assert.Check(t, ip != nil) 310 } 311 312 func TestFree(t *testing.T) { 313 na := newNetworkAllocator(t) 314 n := &api.Network{ 315 ID: "testID", 316 Spec: api.NetworkSpec{ 317 Annotations: api.Annotations{ 318 Name: "test", 319 }, 320 DriverConfig: &api.Driver{}, 321 IPAM: &api.IPAMOptions{ 322 Driver: &api.Driver{}, 323 Configs: []*api.IPAMConfig{ 324 { 325 Subnet: "192.168.1.0/24", 326 Gateway: "192.168.1.1", 327 }, 328 }, 329 }, 330 }, 331 } 332 333 err := na.Allocate(n) 334 assert.Check(t, err) 335 336 err = na.Deallocate(n) 337 assert.Check(t, err) 338 339 // Reallocate again to make sure it succeeds. 340 err = na.Allocate(n) 341 assert.Check(t, err) 342 } 343 344 func TestAllocateTaskFree(t *testing.T) { 345 na1 := newNetworkAllocator(t) 346 na2 := newNetworkAllocator(t) 347 n1 := &api.Network{ 348 ID: "testID1", 349 Spec: api.NetworkSpec{ 350 Annotations: api.Annotations{ 351 Name: "test1", 352 }, 353 DriverConfig: &api.Driver{}, 354 IPAM: &api.IPAMOptions{ 355 Driver: &api.Driver{}, 356 Configs: []*api.IPAMConfig{ 357 { 358 Subnet: "192.168.1.0/24", 359 Gateway: "192.168.1.1", 360 }, 361 }, 362 }, 363 }, 364 } 365 366 n2 := &api.Network{ 367 ID: "testID2", 368 Spec: api.NetworkSpec{ 369 Annotations: api.Annotations{ 370 Name: "test2", 371 }, 372 DriverConfig: &api.Driver{}, 373 IPAM: &api.IPAMOptions{ 374 Driver: &api.Driver{}, 375 Configs: []*api.IPAMConfig{ 376 { 377 Subnet: "192.168.2.0/24", 378 Gateway: "192.168.2.1", 379 }, 380 }, 381 }, 382 }, 383 } 384 385 task1 := &api.Task{ 386 Networks: []*api.NetworkAttachment{ 387 { 388 Network: n1, 389 }, 390 { 391 Network: n2, 392 }, 393 }, 394 } 395 396 task2 := &api.Task{ 397 Networks: []*api.NetworkAttachment{ 398 { 399 Network: n1, 400 }, 401 { 402 Network: n2, 403 }, 404 }, 405 } 406 407 err := na1.Allocate(n1) 408 assert.Check(t, err) 409 410 err = na1.Allocate(n2) 411 assert.Check(t, err) 412 413 err = na1.AllocateTask(task1) 414 assert.Check(t, err) 415 assert.Check(t, is.Equal(len(task1.Networks[0].Addresses), 1)) 416 assert.Check(t, is.Equal(len(task1.Networks[1].Addresses), 1)) 417 418 _, subnet1, _ := net.ParseCIDR("192.168.1.0/24") 419 _, subnet2, _ := net.ParseCIDR("192.168.2.0/24") 420 421 // variable coding: network/task/allocator 422 ip111, _, err := net.ParseCIDR(task1.Networks[0].Addresses[0]) 423 assert.Check(t, err) 424 425 ip211, _, err := net.ParseCIDR(task1.Networks[1].Addresses[0]) 426 assert.Check(t, err) 427 428 assert.Check(t, is.Equal(subnet1.Contains(ip111), true)) 429 assert.Check(t, is.Equal(subnet2.Contains(ip211), true)) 430 431 err = na1.AllocateTask(task2) 432 assert.Check(t, err) 433 assert.Check(t, is.Equal(len(task2.Networks[0].Addresses), 1)) 434 assert.Check(t, is.Equal(len(task2.Networks[1].Addresses), 1)) 435 436 ip121, _, err := net.ParseCIDR(task2.Networks[0].Addresses[0]) 437 assert.Check(t, err) 438 439 ip221, _, err := net.ParseCIDR(task2.Networks[1].Addresses[0]) 440 assert.Check(t, err) 441 442 assert.Check(t, is.Equal(subnet1.Contains(ip121), true)) 443 assert.Check(t, is.Equal(subnet2.Contains(ip221), true)) 444 445 // Now allocate the same the same tasks in a second allocator 446 // but intentionally in reverse order. 447 err = na2.Allocate(n1) 448 assert.Check(t, err) 449 450 err = na2.Allocate(n2) 451 assert.Check(t, err) 452 453 err = na2.AllocateTask(task2) 454 assert.Check(t, err) 455 assert.Check(t, is.Equal(len(task2.Networks[0].Addresses), 1)) 456 assert.Check(t, is.Equal(len(task2.Networks[1].Addresses), 1)) 457 458 ip122, _, err := net.ParseCIDR(task2.Networks[0].Addresses[0]) 459 assert.Check(t, err) 460 461 ip222, _, err := net.ParseCIDR(task2.Networks[1].Addresses[0]) 462 assert.Check(t, err) 463 464 assert.Check(t, is.Equal(subnet1.Contains(ip122), true)) 465 assert.Check(t, is.Equal(subnet2.Contains(ip222), true)) 466 assert.Check(t, is.DeepEqual(ip121, ip122)) 467 assert.Check(t, is.DeepEqual(ip221, ip222)) 468 469 err = na2.AllocateTask(task1) 470 assert.Check(t, err) 471 assert.Check(t, is.Equal(len(task1.Networks[0].Addresses), 1)) 472 assert.Check(t, is.Equal(len(task1.Networks[1].Addresses), 1)) 473 474 ip112, _, err := net.ParseCIDR(task1.Networks[0].Addresses[0]) 475 assert.Check(t, err) 476 477 ip212, _, err := net.ParseCIDR(task1.Networks[1].Addresses[0]) 478 assert.Check(t, err) 479 480 assert.Check(t, is.Equal(subnet1.Contains(ip112), true)) 481 assert.Check(t, is.Equal(subnet2.Contains(ip212), true)) 482 assert.Check(t, is.DeepEqual(ip111, ip112)) 483 assert.Check(t, is.DeepEqual(ip211, ip212)) 484 485 // Deallocate task 486 err = na1.DeallocateTask(task1) 487 assert.Check(t, err) 488 assert.Check(t, is.Equal(len(task1.Networks[0].Addresses), 0)) 489 assert.Check(t, is.Equal(len(task1.Networks[1].Addresses), 0)) 490 491 // Try allocation after free 492 err = na1.AllocateTask(task1) 493 assert.Check(t, err) 494 assert.Check(t, is.Equal(len(task1.Networks[0].Addresses), 1)) 495 assert.Check(t, is.Equal(len(task1.Networks[1].Addresses), 1)) 496 497 ip111, _, err = net.ParseCIDR(task1.Networks[0].Addresses[0]) 498 assert.Check(t, err) 499 500 ip211, _, err = net.ParseCIDR(task1.Networks[1].Addresses[0]) 501 assert.Check(t, err) 502 503 assert.Check(t, is.Equal(subnet1.Contains(ip111), true)) 504 assert.Check(t, is.Equal(subnet2.Contains(ip211), true)) 505 506 err = na1.DeallocateTask(task1) 507 assert.Check(t, err) 508 assert.Check(t, is.Equal(len(task1.Networks[0].Addresses), 0)) 509 assert.Check(t, is.Equal(len(task1.Networks[1].Addresses), 0)) 510 511 // Try to free endpoints on an already freed task 512 err = na1.DeallocateTask(task1) 513 assert.Check(t, err) 514 } 515 516 func TestAllocateService(t *testing.T) { 517 na := newNetworkAllocator(t) 518 n := &api.Network{ 519 ID: "testID", 520 Spec: api.NetworkSpec{ 521 Annotations: api.Annotations{ 522 Name: "test", 523 }, 524 }, 525 } 526 527 s := &api.Service{ 528 ID: "testID1", 529 Spec: api.ServiceSpec{ 530 Task: api.TaskSpec{ 531 Networks: []*api.NetworkAttachmentConfig{ 532 { 533 Target: "testID", 534 }, 535 }, 536 }, 537 Endpoint: &api.EndpointSpec{ 538 Ports: []*api.PortConfig{ 539 { 540 Name: "http", 541 TargetPort: 80, 542 }, 543 { 544 Name: "https", 545 TargetPort: 443, 546 }, 547 }, 548 }, 549 }, 550 } 551 552 err := na.Allocate(n) 553 assert.Check(t, err) 554 assert.Check(t, n.IPAM.Configs != nil) 555 assert.Check(t, is.Equal(len(n.IPAM.Configs), 1)) 556 assert.Check(t, is.Equal(n.IPAM.Configs[0].Range, "")) 557 assert.Check(t, is.Equal(len(n.IPAM.Configs[0].Reserved), 0)) 558 559 _, subnet, err := net.ParseCIDR(n.IPAM.Configs[0].Subnet) 560 assert.Check(t, err) 561 562 gwip := net.ParseIP(n.IPAM.Configs[0].Gateway) 563 assert.Check(t, gwip != nil) 564 565 err = na.AllocateService(s) 566 assert.Check(t, err) 567 assert.Check(t, is.Len(s.Endpoint.Ports, 0)) // Network allocator is not responsible for allocating ports. 568 569 assert.Check(t, is.Equal(1, len(s.Endpoint.VirtualIPs))) 570 571 assert.Check(t, is.DeepEqual(s.Endpoint.Spec, s.Spec.Endpoint)) 572 573 ip, _, err := net.ParseCIDR(s.Endpoint.VirtualIPs[0].Addr) 574 assert.Check(t, err) 575 576 assert.Check(t, is.Equal(true, subnet.Contains(ip))) 577 } 578 579 func TestDeallocateServiceAllocateIngressMode(t *testing.T) { 580 na := newNetworkAllocator(t) 581 582 n := &api.Network{ 583 ID: "testNetID1", 584 Spec: api.NetworkSpec{ 585 Annotations: api.Annotations{ 586 Name: "test", 587 }, 588 Ingress: true, 589 }, 590 } 591 592 err := na.Allocate(n) 593 assert.Check(t, err) 594 595 s := &api.Service{ 596 ID: "testID1", 597 Spec: api.ServiceSpec{ 598 Endpoint: &api.EndpointSpec{ 599 Ports: []*api.PortConfig{ 600 { 601 Name: "some_tcp", 602 TargetPort: 1234, 603 PublishedPort: 1234, 604 PublishMode: api.PublishModeIngress, 605 }, 606 }, 607 }, 608 }, 609 Endpoint: &api.Endpoint{}, 610 } 611 612 s.Endpoint.VirtualIPs = append(s.Endpoint.VirtualIPs, 613 &api.Endpoint_VirtualIP{NetworkID: n.ID}) 614 615 err = na.AllocateService(s) 616 assert.Check(t, err) 617 assert.Check(t, is.Len(s.Endpoint.VirtualIPs, 1)) 618 619 err = na.DeallocateService(s) 620 assert.Check(t, err) 621 assert.Check(t, is.Len(s.Endpoint.Ports, 0)) 622 assert.Check(t, is.Len(s.Endpoint.VirtualIPs, 0)) 623 // Allocate again. 624 s.Endpoint.VirtualIPs = append(s.Endpoint.VirtualIPs, 625 &api.Endpoint_VirtualIP{NetworkID: n.ID}) 626 627 err = na.AllocateService(s) 628 assert.Check(t, err) 629 assert.Check(t, is.Len(s.Endpoint.VirtualIPs, 1)) 630 } 631 632 func TestServiceNetworkUpdate(t *testing.T) { 633 na := newNetworkAllocator(t) 634 635 n1 := &api.Network{ 636 ID: "testID1", 637 Spec: api.NetworkSpec{ 638 Annotations: api.Annotations{ 639 Name: "test", 640 }, 641 }, 642 } 643 644 n2 := &api.Network{ 645 ID: "testID2", 646 Spec: api.NetworkSpec{ 647 Annotations: api.Annotations{ 648 Name: "test2", 649 }, 650 }, 651 } 652 653 // Allocate both networks 654 err := na.Allocate(n1) 655 assert.Check(t, err) 656 657 err = na.Allocate(n2) 658 assert.Check(t, err) 659 660 // Attach a network to a service spec nd allocate a service 661 s := &api.Service{ 662 ID: "testID1", 663 Spec: api.ServiceSpec{ 664 Task: api.TaskSpec{ 665 Networks: []*api.NetworkAttachmentConfig{ 666 { 667 Target: "testID1", 668 }, 669 }, 670 }, 671 Endpoint: &api.EndpointSpec{ 672 Mode: api.ResolutionModeVirtualIP, 673 }, 674 }, 675 } 676 677 err = na.AllocateService(s) 678 assert.Check(t, err) 679 assert.Check(t, na.IsServiceAllocated(s)) 680 assert.Check(t, is.Len(s.Endpoint.VirtualIPs, 1)) 681 682 // Now update the same service with another network 683 s.Spec.Task.Networks = append(s.Spec.Task.Networks, &api.NetworkAttachmentConfig{Target: "testID2"}) 684 685 assert.Check(t, !na.IsServiceAllocated(s)) 686 err = na.AllocateService(s) 687 assert.Check(t, err) 688 689 assert.Check(t, na.IsServiceAllocated(s)) 690 assert.Check(t, is.Len(s.Endpoint.VirtualIPs, 2)) 691 692 s.Spec.Task.Networks = s.Spec.Task.Networks[:1] 693 694 // Check if service needs update and allocate with updated service spec 695 assert.Check(t, !na.IsServiceAllocated(s)) 696 697 err = na.AllocateService(s) 698 assert.Check(t, err) 699 assert.Check(t, na.IsServiceAllocated(s)) 700 assert.Check(t, is.Len(s.Endpoint.VirtualIPs, 1)) 701 702 s.Spec.Task.Networks = s.Spec.Task.Networks[:0] 703 // Check if service needs update with all the networks removed and allocate with updated service spec 704 assert.Check(t, !na.IsServiceAllocated(s)) 705 706 err = na.AllocateService(s) 707 assert.Check(t, err) 708 assert.Check(t, na.IsServiceAllocated(s)) 709 assert.Check(t, is.Len(s.Endpoint.VirtualIPs, 0)) 710 711 // Attach a network and allocate service 712 s.Spec.Task.Networks = append(s.Spec.Task.Networks, &api.NetworkAttachmentConfig{Target: "testID2"}) 713 assert.Check(t, !na.IsServiceAllocated(s)) 714 715 err = na.AllocateService(s) 716 assert.Check(t, err) 717 718 assert.Check(t, na.IsServiceAllocated(s)) 719 assert.Check(t, is.Len(s.Endpoint.VirtualIPs, 1)) 720 721 } 722 723 type mockIpam struct { 724 actualIpamOptions map[string]string 725 } 726 727 func (a *mockIpam) GetDefaultAddressSpaces() (string, string, error) { 728 return "defaultAS", "defaultAS", nil 729 } 730 731 func (a *mockIpam) RequestPool(addressSpace, pool, subPool string, options map[string]string, v6 bool) (string, *net.IPNet, map[string]string, error) { 732 a.actualIpamOptions = options 733 734 poolCidr, _ := types.ParseCIDR(pool) 735 return fmt.Sprintf("%s/%s", "defaultAS", pool), poolCidr, nil, nil 736 } 737 738 func (a *mockIpam) ReleasePool(poolID string) error { 739 return nil 740 } 741 742 func (a *mockIpam) RequestAddress(poolID string, ip net.IP, opts map[string]string) (*net.IPNet, map[string]string, error) { 743 return nil, nil, nil 744 } 745 746 func (a *mockIpam) ReleaseAddress(poolID string, ip net.IP) error { 747 return nil 748 } 749 750 func (a *mockIpam) IsBuiltIn() bool { 751 return true 752 } 753 754 func TestCorrectlyPassIPAMOptions(t *testing.T) { 755 var err error 756 expectedIpamOptions := map[string]string{"network-name": "freddie"} 757 758 na := newNetworkAllocator(t) 759 ipamDriver := &mockIpam{} 760 761 err = na.(*cnmNetworkAllocator).ipamRegistry.RegisterIpamDriver("mockipam", ipamDriver) 762 assert.Check(t, err) 763 764 n := &api.Network{ 765 ID: "testID", 766 Spec: api.NetworkSpec{ 767 Annotations: api.Annotations{ 768 Name: "test", 769 }, 770 DriverConfig: &api.Driver{}, 771 IPAM: &api.IPAMOptions{ 772 Driver: &api.Driver{ 773 Name: "mockipam", 774 Options: expectedIpamOptions, 775 }, 776 Configs: []*api.IPAMConfig{ 777 { 778 Subnet: "192.168.1.0/24", 779 Gateway: "192.168.1.1", 780 }, 781 }, 782 }, 783 }, 784 } 785 err = na.Allocate(n) 786 787 assert.Check(t, is.DeepEqual(expectedIpamOptions, ipamDriver.actualIpamOptions)) 788 assert.Check(t, err) 789 }