github.com/bigcommerce/nomad@v0.9.3-bc/nomad/structs/network_test.go (about) 1 package structs 2 3 import ( 4 "fmt" 5 "net" 6 "reflect" 7 "testing" 8 ) 9 10 func TestNetworkIndex_Overcommitted(t *testing.T) { 11 idx := NewNetworkIndex() 12 13 // Consume some network 14 reserved := &NetworkResource{ 15 Device: "eth0", 16 IP: "192.168.0.100", 17 MBits: 505, 18 ReservedPorts: []Port{{"one", 8000}, {"two", 9000}}, 19 } 20 collide := idx.AddReserved(reserved) 21 if collide { 22 t.Fatalf("bad") 23 } 24 if !idx.Overcommitted() { 25 t.Fatalf("have no resources") 26 } 27 28 // Add resources 29 n := &Node{ 30 NodeResources: &NodeResources{ 31 Networks: []*NetworkResource{ 32 { 33 Device: "eth0", 34 CIDR: "192.168.0.100/32", 35 MBits: 1000, 36 }, 37 }, 38 }, 39 } 40 idx.SetNode(n) 41 if idx.Overcommitted() { 42 t.Fatalf("have resources") 43 } 44 45 // Double up our usage 46 idx.AddReserved(reserved) 47 if !idx.Overcommitted() { 48 t.Fatalf("should be overcommitted") 49 } 50 } 51 52 func TestNetworkIndex_SetNode(t *testing.T) { 53 idx := NewNetworkIndex() 54 n := &Node{ 55 NodeResources: &NodeResources{ 56 Networks: []*NetworkResource{ 57 { 58 Device: "eth0", 59 CIDR: "192.168.0.100/32", 60 IP: "192.168.0.100", 61 MBits: 1000, 62 }, 63 }, 64 }, 65 ReservedResources: &NodeReservedResources{ 66 Networks: NodeReservedNetworkResources{ 67 ReservedHostPorts: "22", 68 }, 69 }, 70 } 71 collide := idx.SetNode(n) 72 if collide { 73 t.Fatalf("bad") 74 } 75 76 if len(idx.AvailNetworks) != 1 { 77 t.Fatalf("Bad") 78 } 79 if idx.AvailBandwidth["eth0"] != 1000 { 80 t.Fatalf("Bad") 81 } 82 if !idx.UsedPorts["192.168.0.100"].Check(22) { 83 t.Fatalf("Bad") 84 } 85 } 86 87 func TestNetworkIndex_AddAllocs(t *testing.T) { 88 idx := NewNetworkIndex() 89 allocs := []*Allocation{ 90 { 91 AllocatedResources: &AllocatedResources{ 92 Tasks: map[string]*AllocatedTaskResources{ 93 "web": { 94 Networks: []*NetworkResource{ 95 { 96 Device: "eth0", 97 IP: "192.168.0.100", 98 MBits: 20, 99 ReservedPorts: []Port{{"one", 8000}, {"two", 9000}}, 100 }, 101 }, 102 }, 103 }, 104 }, 105 }, 106 { 107 AllocatedResources: &AllocatedResources{ 108 Tasks: map[string]*AllocatedTaskResources{ 109 "api": { 110 Networks: []*NetworkResource{ 111 { 112 Device: "eth0", 113 IP: "192.168.0.100", 114 MBits: 50, 115 ReservedPorts: []Port{{"one", 10000}}, 116 }, 117 }, 118 }, 119 }, 120 }, 121 }, 122 } 123 collide := idx.AddAllocs(allocs) 124 if collide { 125 t.Fatalf("bad") 126 } 127 128 if idx.UsedBandwidth["eth0"] != 70 { 129 t.Fatalf("Bad") 130 } 131 if !idx.UsedPorts["192.168.0.100"].Check(8000) { 132 t.Fatalf("Bad") 133 } 134 if !idx.UsedPorts["192.168.0.100"].Check(9000) { 135 t.Fatalf("Bad") 136 } 137 if !idx.UsedPorts["192.168.0.100"].Check(10000) { 138 t.Fatalf("Bad") 139 } 140 } 141 142 func TestNetworkIndex_AddReserved(t *testing.T) { 143 idx := NewNetworkIndex() 144 145 reserved := &NetworkResource{ 146 Device: "eth0", 147 IP: "192.168.0.100", 148 MBits: 20, 149 ReservedPorts: []Port{{"one", 8000}, {"two", 9000}}, 150 } 151 collide := idx.AddReserved(reserved) 152 if collide { 153 t.Fatalf("bad") 154 } 155 156 if idx.UsedBandwidth["eth0"] != 20 { 157 t.Fatalf("Bad") 158 } 159 if !idx.UsedPorts["192.168.0.100"].Check(8000) { 160 t.Fatalf("Bad") 161 } 162 if !idx.UsedPorts["192.168.0.100"].Check(9000) { 163 t.Fatalf("Bad") 164 } 165 166 // Try to reserve the same network 167 collide = idx.AddReserved(reserved) 168 if !collide { 169 t.Fatalf("bad") 170 } 171 } 172 173 // XXX Reserving ports doesn't work when yielding from a CIDR block. This is 174 // okay for now since we do not actually fingerprint CIDR blocks. 175 func TestNetworkIndex_yieldIP(t *testing.T) { 176 idx := NewNetworkIndex() 177 n := &Node{ 178 NodeResources: &NodeResources{ 179 Networks: []*NetworkResource{ 180 { 181 Device: "eth0", 182 CIDR: "192.168.0.100/30", 183 MBits: 1000, 184 }, 185 }, 186 }, 187 } 188 idx.SetNode(n) 189 190 var out []string 191 idx.yieldIP(func(n *NetworkResource, ip net.IP) (stop bool) { 192 out = append(out, ip.String()) 193 return 194 }) 195 196 expect := []string{"192.168.0.100", "192.168.0.101", 197 "192.168.0.102", "192.168.0.103"} 198 if !reflect.DeepEqual(out, expect) { 199 t.Fatalf("bad: %v", out) 200 } 201 } 202 203 func TestNetworkIndex_AssignNetwork(t *testing.T) { 204 idx := NewNetworkIndex() 205 n := &Node{ 206 NodeResources: &NodeResources{ 207 Networks: []*NetworkResource{ 208 { 209 Device: "eth0", 210 CIDR: "192.168.0.100/30", 211 MBits: 1000, 212 }, 213 }, 214 }, 215 } 216 idx.SetNode(n) 217 218 allocs := []*Allocation{ 219 { 220 TaskResources: map[string]*Resources{ 221 "web": { 222 Networks: []*NetworkResource{ 223 { 224 Device: "eth0", 225 IP: "192.168.0.100", 226 MBits: 20, 227 ReservedPorts: []Port{{"one", 8000}, {"two", 9000}}, 228 }, 229 }, 230 }, 231 }, 232 }, 233 { 234 TaskResources: map[string]*Resources{ 235 "api": { 236 Networks: []*NetworkResource{ 237 { 238 Device: "eth0", 239 IP: "192.168.0.100", 240 MBits: 50, 241 ReservedPorts: []Port{{"main", 10000}}, 242 }, 243 }, 244 }, 245 }, 246 }, 247 } 248 idx.AddAllocs(allocs) 249 250 // Ask for a reserved port 251 ask := &NetworkResource{ 252 ReservedPorts: []Port{{"main", 8000}}, 253 } 254 offer, err := idx.AssignNetwork(ask) 255 if err != nil { 256 t.Fatalf("err: %v", err) 257 } 258 if offer == nil { 259 t.Fatalf("bad") 260 } 261 if offer.IP != "192.168.0.101" { 262 t.Fatalf("bad: %#v", offer) 263 } 264 rp := Port{"main", 8000} 265 if len(offer.ReservedPorts) != 1 || offer.ReservedPorts[0] != rp { 266 t.Fatalf("bad: %#v", offer) 267 } 268 269 // Ask for dynamic ports 270 ask = &NetworkResource{ 271 DynamicPorts: []Port{{"http", 0}, {"https", 0}, {"admin", 0}}, 272 } 273 offer, err = idx.AssignNetwork(ask) 274 if err != nil { 275 t.Fatalf("err: %v", err) 276 } 277 if offer == nil { 278 t.Fatalf("bad") 279 } 280 if offer.IP != "192.168.0.100" { 281 t.Fatalf("bad: %#v", offer) 282 } 283 if len(offer.DynamicPorts) != 3 { 284 t.Fatalf("There should be three dynamic ports") 285 } 286 for _, port := range offer.DynamicPorts { 287 if port.Value == 0 { 288 t.Fatalf("Dynamic Port: %v should have been assigned a host port", port.Label) 289 } 290 } 291 292 // Ask for reserved + dynamic ports 293 ask = &NetworkResource{ 294 ReservedPorts: []Port{{"main", 2345}}, 295 DynamicPorts: []Port{{"http", 0}, {"https", 0}, {"admin", 0}}, 296 } 297 offer, err = idx.AssignNetwork(ask) 298 if err != nil { 299 t.Fatalf("err: %v", err) 300 } 301 if offer == nil { 302 t.Fatalf("bad") 303 } 304 if offer.IP != "192.168.0.100" { 305 t.Fatalf("bad: %#v", offer) 306 } 307 308 rp = Port{"main", 2345} 309 if len(offer.ReservedPorts) != 1 || offer.ReservedPorts[0] != rp { 310 t.Fatalf("bad: %#v", offer) 311 } 312 313 // Ask for too much bandwidth 314 ask = &NetworkResource{ 315 MBits: 1000, 316 } 317 offer, err = idx.AssignNetwork(ask) 318 if err.Error() != "bandwidth exceeded" { 319 t.Fatalf("err: %v", err) 320 } 321 if offer != nil { 322 t.Fatalf("bad") 323 } 324 } 325 326 // This test ensures that even with a small domain of available ports we are 327 // able to make a dynamic port allocation. 328 func TestNetworkIndex_AssignNetwork_Dynamic_Contention(t *testing.T) { 329 330 // Create a node that only has one free port 331 idx := NewNetworkIndex() 332 n := &Node{ 333 NodeResources: &NodeResources{ 334 Networks: []*NetworkResource{ 335 { 336 Device: "eth0", 337 CIDR: "192.168.0.100/32", 338 IP: "192.168.0.100", 339 MBits: 1000, 340 }, 341 }, 342 }, 343 ReservedResources: &NodeReservedResources{ 344 Networks: NodeReservedNetworkResources{ 345 ReservedHostPorts: fmt.Sprintf("%d-%d", MinDynamicPort, MaxDynamicPort-1), 346 }, 347 }, 348 } 349 idx.SetNode(n) 350 351 // Ask for dynamic ports 352 ask := &NetworkResource{ 353 DynamicPorts: []Port{{"http", 0}}, 354 } 355 offer, err := idx.AssignNetwork(ask) 356 if err != nil { 357 t.Fatalf("err: %v", err) 358 } 359 if offer == nil { 360 t.Fatalf("bad") 361 } 362 if offer.IP != "192.168.0.100" { 363 t.Fatalf("bad: %#v", offer) 364 } 365 if len(offer.DynamicPorts) != 1 { 366 t.Fatalf("There should be one dynamic ports") 367 } 368 if p := offer.DynamicPorts[0].Value; p != MaxDynamicPort { 369 t.Fatalf("Dynamic Port: should have been assigned %d; got %d", p, MaxDynamicPort) 370 } 371 } 372 373 // COMPAT(0.11): Remove in 0.11 374 func TestNetworkIndex_Overcommitted_Old(t *testing.T) { 375 idx := NewNetworkIndex() 376 377 // Consume some network 378 reserved := &NetworkResource{ 379 Device: "eth0", 380 IP: "192.168.0.100", 381 MBits: 505, 382 ReservedPorts: []Port{{"one", 8000}, {"two", 9000}}, 383 } 384 collide := idx.AddReserved(reserved) 385 if collide { 386 t.Fatalf("bad") 387 } 388 if !idx.Overcommitted() { 389 t.Fatalf("have no resources") 390 } 391 392 // Add resources 393 n := &Node{ 394 Resources: &Resources{ 395 Networks: []*NetworkResource{ 396 { 397 Device: "eth0", 398 CIDR: "192.168.0.100/32", 399 MBits: 1000, 400 }, 401 }, 402 }, 403 } 404 idx.SetNode(n) 405 if idx.Overcommitted() { 406 t.Fatalf("have resources") 407 } 408 409 // Double up our usage 410 idx.AddReserved(reserved) 411 if !idx.Overcommitted() { 412 t.Fatalf("should be overcommitted") 413 } 414 } 415 416 // COMPAT(0.11): Remove in 0.11 417 func TestNetworkIndex_SetNode_Old(t *testing.T) { 418 idx := NewNetworkIndex() 419 n := &Node{ 420 Resources: &Resources{ 421 Networks: []*NetworkResource{ 422 { 423 Device: "eth0", 424 CIDR: "192.168.0.100/32", 425 MBits: 1000, 426 }, 427 }, 428 }, 429 Reserved: &Resources{ 430 Networks: []*NetworkResource{ 431 { 432 Device: "eth0", 433 IP: "192.168.0.100", 434 ReservedPorts: []Port{{"ssh", 22}}, 435 MBits: 1, 436 }, 437 }, 438 }, 439 } 440 collide := idx.SetNode(n) 441 if collide { 442 t.Fatalf("bad") 443 } 444 445 if len(idx.AvailNetworks) != 1 { 446 t.Fatalf("Bad") 447 } 448 if idx.AvailBandwidth["eth0"] != 1000 { 449 t.Fatalf("Bad") 450 } 451 if idx.UsedBandwidth["eth0"] != 1 { 452 t.Fatalf("Bad") 453 } 454 if !idx.UsedPorts["192.168.0.100"].Check(22) { 455 t.Fatalf("Bad") 456 } 457 } 458 459 // COMPAT(0.11): Remove in 0.11 460 func TestNetworkIndex_AddAllocs_Old(t *testing.T) { 461 idx := NewNetworkIndex() 462 allocs := []*Allocation{ 463 { 464 TaskResources: map[string]*Resources{ 465 "web": { 466 Networks: []*NetworkResource{ 467 { 468 Device: "eth0", 469 IP: "192.168.0.100", 470 MBits: 20, 471 ReservedPorts: []Port{{"one", 8000}, {"two", 9000}}, 472 }, 473 }, 474 }, 475 }, 476 }, 477 { 478 TaskResources: map[string]*Resources{ 479 "api": { 480 Networks: []*NetworkResource{ 481 { 482 Device: "eth0", 483 IP: "192.168.0.100", 484 MBits: 50, 485 ReservedPorts: []Port{{"one", 10000}}, 486 }, 487 }, 488 }, 489 }, 490 }, 491 } 492 collide := idx.AddAllocs(allocs) 493 if collide { 494 t.Fatalf("bad") 495 } 496 497 if idx.UsedBandwidth["eth0"] != 70 { 498 t.Fatalf("Bad") 499 } 500 if !idx.UsedPorts["192.168.0.100"].Check(8000) { 501 t.Fatalf("Bad") 502 } 503 if !idx.UsedPorts["192.168.0.100"].Check(9000) { 504 t.Fatalf("Bad") 505 } 506 if !idx.UsedPorts["192.168.0.100"].Check(10000) { 507 t.Fatalf("Bad") 508 } 509 } 510 511 // COMPAT(0.11): Remove in 0.11 512 func TestNetworkIndex_yieldIP_Old(t *testing.T) { 513 idx := NewNetworkIndex() 514 n := &Node{ 515 Resources: &Resources{ 516 Networks: []*NetworkResource{ 517 { 518 Device: "eth0", 519 CIDR: "192.168.0.100/30", 520 MBits: 1000, 521 }, 522 }, 523 }, 524 Reserved: &Resources{ 525 Networks: []*NetworkResource{ 526 { 527 Device: "eth0", 528 IP: "192.168.0.100", 529 ReservedPorts: []Port{{"ssh", 22}}, 530 MBits: 1, 531 }, 532 }, 533 }, 534 } 535 idx.SetNode(n) 536 537 var out []string 538 idx.yieldIP(func(n *NetworkResource, ip net.IP) (stop bool) { 539 out = append(out, ip.String()) 540 return 541 }) 542 543 expect := []string{"192.168.0.100", "192.168.0.101", 544 "192.168.0.102", "192.168.0.103"} 545 if !reflect.DeepEqual(out, expect) { 546 t.Fatalf("bad: %v", out) 547 } 548 } 549 550 // COMPAT(0.11): Remove in 0.11 551 func TestNetworkIndex_AssignNetwork_Old(t *testing.T) { 552 idx := NewNetworkIndex() 553 n := &Node{ 554 Resources: &Resources{ 555 Networks: []*NetworkResource{ 556 { 557 Device: "eth0", 558 CIDR: "192.168.0.100/30", 559 MBits: 1000, 560 }, 561 }, 562 }, 563 Reserved: &Resources{ 564 Networks: []*NetworkResource{ 565 { 566 Device: "eth0", 567 IP: "192.168.0.100", 568 ReservedPorts: []Port{{"ssh", 22}}, 569 MBits: 1, 570 }, 571 }, 572 }, 573 } 574 idx.SetNode(n) 575 576 allocs := []*Allocation{ 577 { 578 TaskResources: map[string]*Resources{ 579 "web": { 580 Networks: []*NetworkResource{ 581 { 582 Device: "eth0", 583 IP: "192.168.0.100", 584 MBits: 20, 585 ReservedPorts: []Port{{"one", 8000}, {"two", 9000}}, 586 }, 587 }, 588 }, 589 }, 590 }, 591 { 592 TaskResources: map[string]*Resources{ 593 "api": { 594 Networks: []*NetworkResource{ 595 { 596 Device: "eth0", 597 IP: "192.168.0.100", 598 MBits: 50, 599 ReservedPorts: []Port{{"main", 10000}}, 600 }, 601 }, 602 }, 603 }, 604 }, 605 } 606 idx.AddAllocs(allocs) 607 608 // Ask for a reserved port 609 ask := &NetworkResource{ 610 ReservedPorts: []Port{{"main", 8000}}, 611 } 612 offer, err := idx.AssignNetwork(ask) 613 if err != nil { 614 t.Fatalf("err: %v", err) 615 } 616 if offer == nil { 617 t.Fatalf("bad") 618 } 619 if offer.IP != "192.168.0.101" { 620 t.Fatalf("bad: %#v", offer) 621 } 622 rp := Port{"main", 8000} 623 if len(offer.ReservedPorts) != 1 || offer.ReservedPorts[0] != rp { 624 t.Fatalf("bad: %#v", offer) 625 } 626 627 // Ask for dynamic ports 628 ask = &NetworkResource{ 629 DynamicPorts: []Port{{"http", 0}, {"https", 0}, {"admin", 0}}, 630 } 631 offer, err = idx.AssignNetwork(ask) 632 if err != nil { 633 t.Fatalf("err: %v", err) 634 } 635 if offer == nil { 636 t.Fatalf("bad") 637 } 638 if offer.IP != "192.168.0.100" { 639 t.Fatalf("bad: %#v", offer) 640 } 641 if len(offer.DynamicPorts) != 3 { 642 t.Fatalf("There should be three dynamic ports") 643 } 644 for _, port := range offer.DynamicPorts { 645 if port.Value == 0 { 646 t.Fatalf("Dynamic Port: %v should have been assigned a host port", port.Label) 647 } 648 } 649 650 // Ask for reserved + dynamic ports 651 ask = &NetworkResource{ 652 ReservedPorts: []Port{{"main", 2345}}, 653 DynamicPorts: []Port{{"http", 0}, {"https", 0}, {"admin", 0}}, 654 } 655 offer, err = idx.AssignNetwork(ask) 656 if err != nil { 657 t.Fatalf("err: %v", err) 658 } 659 if offer == nil { 660 t.Fatalf("bad") 661 } 662 if offer.IP != "192.168.0.100" { 663 t.Fatalf("bad: %#v", offer) 664 } 665 666 rp = Port{"main", 2345} 667 if len(offer.ReservedPorts) != 1 || offer.ReservedPorts[0] != rp { 668 t.Fatalf("bad: %#v", offer) 669 } 670 671 // Ask for too much bandwidth 672 ask = &NetworkResource{ 673 MBits: 1000, 674 } 675 offer, err = idx.AssignNetwork(ask) 676 if err.Error() != "bandwidth exceeded" { 677 t.Fatalf("err: %v", err) 678 } 679 if offer != nil { 680 t.Fatalf("bad") 681 } 682 } 683 684 // COMPAT(0.11): Remove in 0.11 685 // This test ensures that even with a small domain of available ports we are 686 // able to make a dynamic port allocation. 687 func TestNetworkIndex_AssignNetwork_Dynamic_Contention_Old(t *testing.T) { 688 689 // Create a node that only has one free port 690 idx := NewNetworkIndex() 691 n := &Node{ 692 Resources: &Resources{ 693 Networks: []*NetworkResource{ 694 { 695 Device: "eth0", 696 CIDR: "192.168.0.100/32", 697 MBits: 1000, 698 }, 699 }, 700 }, 701 Reserved: &Resources{ 702 Networks: []*NetworkResource{ 703 { 704 Device: "eth0", 705 IP: "192.168.0.100", 706 MBits: 1, 707 }, 708 }, 709 }, 710 } 711 for i := MinDynamicPort; i < MaxDynamicPort; i++ { 712 n.Reserved.Networks[0].ReservedPorts = append(n.Reserved.Networks[0].ReservedPorts, Port{Value: i}) 713 } 714 715 idx.SetNode(n) 716 717 // Ask for dynamic ports 718 ask := &NetworkResource{ 719 DynamicPorts: []Port{{"http", 0}}, 720 } 721 offer, err := idx.AssignNetwork(ask) 722 if err != nil { 723 t.Fatalf("err: %v", err) 724 } 725 if offer == nil { 726 t.Fatalf("bad") 727 } 728 if offer.IP != "192.168.0.100" { 729 t.Fatalf("bad: %#v", offer) 730 } 731 if len(offer.DynamicPorts) != 1 { 732 t.Fatalf("There should be three dynamic ports") 733 } 734 if p := offer.DynamicPorts[0].Value; p != MaxDynamicPort { 735 t.Fatalf("Dynamic Port: should have been assigned %d; got %d", p, MaxDynamicPort) 736 } 737 } 738 739 func TestIntContains(t *testing.T) { 740 l := []int{1, 2, 10, 20} 741 if isPortReserved(l, 50) { 742 t.Fatalf("bad") 743 } 744 if !isPortReserved(l, 20) { 745 t.Fatalf("bad") 746 } 747 if !isPortReserved(l, 1) { 748 t.Fatalf("bad") 749 } 750 }