github.com/anth0d/nomad@v0.0.0-20221214183521-ae3a0a2cad06/nomad/structs/network_test.go (about) 1 package structs 2 3 import ( 4 "fmt" 5 "net" 6 "reflect" 7 "testing" 8 9 "github.com/hashicorp/nomad/ci" 10 "github.com/stretchr/testify/assert" 11 "github.com/stretchr/testify/require" 12 ) 13 14 func TestNetworkIndex_Copy(t *testing.T) { 15 ci.Parallel(t) 16 17 n := &Node{ 18 NodeResources: &NodeResources{ 19 Networks: []*NetworkResource{ 20 { 21 Device: "eth0", 22 CIDR: "192.168.0.100/32", 23 IP: "192.168.0.100", 24 MBits: 1000, 25 }, 26 }, 27 NodeNetworks: []*NodeNetworkResource{ 28 { 29 Mode: "host", 30 Device: "eth0", 31 Speed: 1000, 32 Addresses: []NodeNetworkAddress{ 33 { 34 Alias: "default", 35 Address: "192.168.0.100", 36 Family: NodeNetworkAF_IPv4, 37 }, 38 }, 39 }, 40 }, 41 }, 42 Reserved: &Resources{ 43 Networks: []*NetworkResource{ 44 { 45 Device: "eth0", 46 IP: "192.168.0.100", 47 ReservedPorts: []Port{{Label: "ssh", Value: 22}}, 48 MBits: 1, 49 }, 50 }, 51 }, 52 ReservedResources: &NodeReservedResources{ 53 Networks: NodeReservedNetworkResources{ 54 ReservedHostPorts: "22", 55 }, 56 }, 57 } 58 59 allocs := []*Allocation{ 60 { 61 AllocatedResources: &AllocatedResources{ 62 Tasks: map[string]*AllocatedTaskResources{ 63 "web": { 64 Networks: []*NetworkResource{ 65 { 66 Device: "eth0", 67 IP: "192.168.0.100", 68 MBits: 20, 69 ReservedPorts: []Port{{"one", 8000, 0, ""}, {"two", 9000, 0, ""}}, 70 }, 71 }, 72 }, 73 }, 74 }, 75 }, 76 { 77 AllocatedResources: &AllocatedResources{ 78 Tasks: map[string]*AllocatedTaskResources{ 79 "api": { 80 Networks: []*NetworkResource{ 81 { 82 Device: "eth0", 83 IP: "192.168.0.100", 84 MBits: 50, 85 ReservedPorts: []Port{{"one", 10000, 0, ""}}, 86 }, 87 }, 88 }, 89 }, 90 }, 91 }, 92 } 93 94 netIdx := NewNetworkIndex() 95 netIdx.SetNode(n) 96 netIdx.AddAllocs(allocs) 97 98 // Copy must be equal. 99 netIdxCopy := netIdx.Copy() 100 require.Equal(t, netIdx, netIdxCopy) 101 102 // Modifying copy should not affect original value. 103 n.NodeResources.Networks[0].Device = "eth1" 104 n.ReservedResources.Networks.ReservedHostPorts = "22,80" 105 allocs = append(allocs, &Allocation{ 106 AllocatedResources: &AllocatedResources{ 107 Tasks: map[string]*AllocatedTaskResources{ 108 "db": { 109 Networks: []*NetworkResource{ 110 { 111 Device: "eth1", 112 IP: "192.168.0.104", 113 MBits: 50, 114 ReservedPorts: []Port{{"one", 4567, 0, ""}}, 115 }, 116 }, 117 }, 118 }, 119 }, 120 }) 121 netIdxCopy.SetNode(n) 122 netIdxCopy.AddAllocs(allocs) 123 netIdxCopy.MinDynamicPort = 1000 124 netIdxCopy.MaxDynamicPort = 2000 125 require.NotEqual(t, netIdx, netIdxCopy) 126 } 127 128 func TestNetworkIndex_Overcommitted(t *testing.T) { 129 t.Skip() 130 ci.Parallel(t) 131 idx := NewNetworkIndex() 132 133 // Consume some network 134 reserved := &NetworkResource{ 135 Device: "eth0", 136 IP: "192.168.0.100", 137 MBits: 505, 138 ReservedPorts: []Port{{"one", 8000, 0, ""}, {"two", 9000, 0, ""}}, 139 } 140 collide, reasons := idx.AddReserved(reserved) 141 if collide || len(reasons) != 0 { 142 t.Fatalf("bad") 143 } 144 if !idx.Overcommitted() { 145 t.Fatalf("have no resources") 146 } 147 148 // Add resources 149 n := &Node{ 150 NodeResources: &NodeResources{ 151 Networks: []*NetworkResource{ 152 { 153 Device: "eth0", 154 CIDR: "192.168.0.100/32", 155 MBits: 1000, 156 }, 157 }, 158 }, 159 } 160 idx.SetNode(n) 161 if idx.Overcommitted() { 162 t.Fatalf("have resources") 163 } 164 165 // Double up our usage 166 idx.AddReserved(reserved) 167 if !idx.Overcommitted() { 168 t.Fatalf("should be overcommitted") 169 } 170 } 171 172 func TestNetworkIndex_SetNode(t *testing.T) { 173 ci.Parallel(t) 174 175 idx := NewNetworkIndex() 176 n := &Node{ 177 NodeResources: &NodeResources{ 178 Networks: []*NetworkResource{ 179 { 180 Device: "eth0", 181 CIDR: "192.168.0.100/32", 182 IP: "192.168.0.100", 183 MBits: 1000, 184 }, 185 }, 186 }, 187 ReservedResources: &NodeReservedResources{ 188 Networks: NodeReservedNetworkResources{ 189 ReservedHostPorts: "22", 190 }, 191 }, 192 } 193 require.NoError(t, idx.SetNode(n)) 194 require.Len(t, idx.TaskNetworks, 1) 195 require.Equal(t, 1000, idx.AvailBandwidth["eth0"]) 196 require.True(t, idx.UsedPorts["192.168.0.100"].Check(22)) 197 } 198 199 func TestNetworkIndex_AddAllocs(t *testing.T) { 200 ci.Parallel(t) 201 202 idx := NewNetworkIndex() 203 allocs := []*Allocation{ 204 { 205 ClientStatus: AllocClientStatusRunning, 206 DesiredStatus: AllocDesiredStatusRun, 207 AllocatedResources: &AllocatedResources{ 208 Tasks: map[string]*AllocatedTaskResources{ 209 "web": { 210 Networks: []*NetworkResource{ 211 { 212 Device: "eth0", 213 IP: "192.168.0.100", 214 MBits: 20, 215 ReservedPorts: []Port{{"one", 8000, 0, ""}, {"two", 9000, 0, ""}}, 216 }, 217 }, 218 }, 219 }, 220 }, 221 }, 222 { 223 ClientStatus: AllocClientStatusRunning, 224 DesiredStatus: AllocDesiredStatusRun, 225 AllocatedResources: &AllocatedResources{ 226 Tasks: map[string]*AllocatedTaskResources{ 227 "api": { 228 Networks: []*NetworkResource{ 229 { 230 Device: "eth0", 231 IP: "192.168.0.100", 232 MBits: 50, 233 ReservedPorts: []Port{{"one", 10000, 0, ""}}, 234 }, 235 }, 236 }, 237 }, 238 }, 239 }, 240 { 241 // Allocations running on clients should have their 242 // ports counted even if their DesiredStatus=stop 243 ClientStatus: AllocClientStatusRunning, 244 DesiredStatus: AllocDesiredStatusStop, 245 AllocatedResources: &AllocatedResources{ 246 Tasks: map[string]*AllocatedTaskResources{ 247 "api": { 248 Networks: []*NetworkResource{ 249 { 250 Device: "eth0", 251 IP: "192.168.0.100", 252 MBits: 50, 253 ReservedPorts: []Port{{"one", 10001, 0, ""}}, 254 }, 255 }, 256 }, 257 }, 258 }, 259 }, 260 { 261 // Allocations *not* running on clients should *not* 262 // have their ports counted even if their 263 // DesiredStatus=run 264 ClientStatus: AllocClientStatusFailed, 265 DesiredStatus: AllocDesiredStatusRun, 266 AllocatedResources: &AllocatedResources{ 267 Tasks: map[string]*AllocatedTaskResources{ 268 "api": { 269 Networks: []*NetworkResource{ 270 { 271 Device: "eth0", 272 IP: "192.168.0.100", 273 MBits: 50, 274 ReservedPorts: []Port{{"one", 10001, 0, ""}}, 275 }, 276 }, 277 }, 278 }, 279 }, 280 }, 281 } 282 collide, reason := idx.AddAllocs(allocs) 283 assert.False(t, collide) 284 assert.Empty(t, reason) 285 286 assert.True(t, idx.UsedPorts["192.168.0.100"].Check(8000)) 287 assert.True(t, idx.UsedPorts["192.168.0.100"].Check(9000)) 288 assert.True(t, idx.UsedPorts["192.168.0.100"].Check(10000)) 289 assert.True(t, idx.UsedPorts["192.168.0.100"].Check(10001)) 290 } 291 292 func TestNetworkIndex_AddReserved(t *testing.T) { 293 ci.Parallel(t) 294 295 idx := NewNetworkIndex() 296 297 reserved := &NetworkResource{ 298 Device: "eth0", 299 IP: "192.168.0.100", 300 MBits: 20, 301 ReservedPorts: []Port{{"one", 8000, 0, ""}, {"two", 9000, 0, ""}}, 302 } 303 collide, reasons := idx.AddReserved(reserved) 304 if collide || len(reasons) > 0 { 305 t.Fatalf("bad") 306 } 307 308 if idx.UsedBandwidth["eth0"] != 20 { 309 t.Fatalf("Bad") 310 } 311 if !idx.UsedPorts["192.168.0.100"].Check(8000) { 312 t.Fatalf("Bad") 313 } 314 if !idx.UsedPorts["192.168.0.100"].Check(9000) { 315 t.Fatalf("Bad") 316 } 317 318 // Try to reserve the same network 319 collide, reasons = idx.AddReserved(reserved) 320 if !collide || len(reasons) == 0 { 321 t.Fatalf("bad") 322 } 323 } 324 325 // XXX Reserving ports doesn't work when yielding from a CIDR block. This is 326 // okay for now since we do not actually fingerprint CIDR blocks. 327 func TestNetworkIndex_yieldIP(t *testing.T) { 328 ci.Parallel(t) 329 330 idx := NewNetworkIndex() 331 n := &Node{ 332 NodeResources: &NodeResources{ 333 Networks: []*NetworkResource{ 334 { 335 Device: "eth0", 336 CIDR: "192.168.0.100/30", 337 MBits: 1000, 338 }, 339 }, 340 }, 341 } 342 idx.SetNode(n) 343 344 var out []string 345 idx.yieldIP(func(n *NetworkResource, ip net.IP) (stop bool) { 346 out = append(out, ip.String()) 347 return 348 }) 349 350 expect := []string{"192.168.0.100", "192.168.0.101", 351 "192.168.0.102", "192.168.0.103"} 352 if !reflect.DeepEqual(out, expect) { 353 t.Fatalf("bad: %v", out) 354 } 355 } 356 357 func TestNetworkIndex_AssignTaskNetwork(t *testing.T) { 358 ci.Parallel(t) 359 idx := NewNetworkIndex() 360 n := &Node{ 361 NodeResources: &NodeResources{ 362 Networks: []*NetworkResource{ 363 { 364 Device: "eth0", 365 CIDR: "192.168.0.100/30", 366 MBits: 1000, 367 }, 368 }, 369 }, 370 } 371 idx.SetNode(n) 372 373 allocs := []*Allocation{ 374 { 375 TaskResources: map[string]*Resources{ 376 "web": { 377 Networks: []*NetworkResource{ 378 { 379 Device: "eth0", 380 IP: "192.168.0.100", 381 MBits: 20, 382 ReservedPorts: []Port{{"one", 8000, 0, ""}, {"two", 9000, 0, ""}}, 383 }, 384 }, 385 }, 386 }, 387 }, 388 { 389 TaskResources: map[string]*Resources{ 390 "api": { 391 Networks: []*NetworkResource{ 392 { 393 Device: "eth0", 394 IP: "192.168.0.100", 395 MBits: 50, 396 ReservedPorts: []Port{{"main", 10000, 0, ""}}, 397 }, 398 }, 399 }, 400 }, 401 }, 402 } 403 idx.AddAllocs(allocs) 404 405 // Ask for a reserved port 406 ask := &NetworkResource{ 407 ReservedPorts: []Port{{"main", 8000, 0, ""}}, 408 } 409 offer, err := idx.AssignTaskNetwork(ask) 410 require.NoError(t, err) 411 require.NotNil(t, offer) 412 require.Equal(t, "192.168.0.101", offer.IP) 413 rp := Port{"main", 8000, 0, ""} 414 require.Len(t, offer.ReservedPorts, 1) 415 require.Exactly(t, rp, offer.ReservedPorts[0]) 416 417 // Ask for dynamic ports 418 ask = &NetworkResource{ 419 DynamicPorts: []Port{{"http", 0, 80, ""}, {"https", 0, 443, ""}, {"admin", 0, -1, ""}}, 420 } 421 offer, err = idx.AssignTaskNetwork(ask) 422 require.NoError(t, err) 423 require.NotNil(t, offer) 424 require.Equal(t, "192.168.0.100", offer.IP) 425 require.Len(t, offer.DynamicPorts, 3) 426 var adminPort Port 427 for _, port := range offer.DynamicPorts { 428 require.NotZero(t, port.Value) 429 if port.Label == "admin" { 430 adminPort = port 431 } 432 } 433 require.Equal(t, adminPort.Value, adminPort.To) 434 435 // Ask for reserved + dynamic ports 436 ask = &NetworkResource{ 437 ReservedPorts: []Port{{"main", 2345, 0, ""}}, 438 DynamicPorts: []Port{{"http", 0, 80, ""}, {"https", 0, 443, ""}, {"admin", 0, 8080, ""}}, 439 } 440 offer, err = idx.AssignTaskNetwork(ask) 441 require.NoError(t, err) 442 require.NotNil(t, offer) 443 require.Equal(t, "192.168.0.100", offer.IP) 444 445 rp = Port{"main", 2345, 0, ""} 446 require.Len(t, offer.ReservedPorts, 1) 447 require.Exactly(t, rp, offer.ReservedPorts[0]) 448 449 // Ask for too much bandwidth 450 ask = &NetworkResource{ 451 MBits: 1000, 452 } 453 offer, err = idx.AssignTaskNetwork(ask) 454 require.Error(t, err) 455 require.Equal(t, "bandwidth exceeded", err.Error()) 456 require.Nil(t, offer) 457 } 458 459 // This test ensures that even with a small domain of available ports we are 460 // able to make a dynamic port allocation. 461 func TestNetworkIndex_AssignTaskNetwork_Dynamic_Contention(t *testing.T) { 462 ci.Parallel(t) 463 464 // Create a node that only has one free port 465 idx := NewNetworkIndex() 466 n := &Node{ 467 NodeResources: &NodeResources{ 468 Networks: []*NetworkResource{ 469 { 470 Device: "eth0", 471 CIDR: "192.168.0.100/32", 472 IP: "192.168.0.100", 473 MBits: 1000, 474 }, 475 }, 476 }, 477 ReservedResources: &NodeReservedResources{ 478 Networks: NodeReservedNetworkResources{ 479 ReservedHostPorts: fmt.Sprintf("%d-%d", idx.MinDynamicPort, idx.MaxDynamicPort-1), 480 }, 481 }, 482 } 483 idx.SetNode(n) 484 485 // Ask for dynamic ports 486 ask := &NetworkResource{ 487 DynamicPorts: []Port{{"http", 0, 80, ""}}, 488 } 489 offer, err := idx.AssignTaskNetwork(ask) 490 if err != nil { 491 t.Fatalf("err: %v", err) 492 } 493 if offer == nil { 494 t.Fatalf("bad") 495 } 496 if offer.IP != "192.168.0.100" { 497 t.Fatalf("bad: %#v", offer) 498 } 499 if len(offer.DynamicPorts) != 1 { 500 t.Fatalf("There should be one dynamic ports") 501 } 502 if p := offer.DynamicPorts[0].Value; p != idx.MaxDynamicPort { 503 t.Fatalf("Dynamic Port: should have been assigned %d; got %d", p, idx.MaxDynamicPort) 504 } 505 } 506 507 // COMPAT(0.11): Remove in 0.11 508 func TestNetworkIndex_SetNode_Old(t *testing.T) { 509 ci.Parallel(t) 510 511 idx := NewNetworkIndex() 512 n := &Node{ 513 Resources: &Resources{ 514 Networks: []*NetworkResource{ 515 { 516 Device: "eth0", 517 CIDR: "192.168.0.100/32", 518 MBits: 1000, 519 }, 520 }, 521 }, 522 Reserved: &Resources{ 523 Networks: []*NetworkResource{ 524 { 525 Device: "eth0", 526 IP: "192.168.0.100", 527 ReservedPorts: []Port{{"ssh", 22, 0, ""}}, 528 MBits: 1, 529 }, 530 }, 531 }, 532 } 533 require.NoError(t, idx.SetNode(n)) 534 require.Len(t, idx.TaskNetworks, 1) 535 require.Equal(t, 1000, idx.AvailBandwidth["eth0"]) 536 require.Equal(t, 1, idx.UsedBandwidth["eth0"]) 537 require.True(t, idx.UsedPorts["192.168.0.100"].Check(22)) 538 } 539 540 // COMPAT(0.11): Remove in 0.11 541 func TestNetworkIndex_AddAllocs_Old(t *testing.T) { 542 ci.Parallel(t) 543 544 idx := NewNetworkIndex() 545 allocs := []*Allocation{ 546 { 547 TaskResources: map[string]*Resources{ 548 "web": { 549 Networks: []*NetworkResource{ 550 { 551 Device: "eth0", 552 IP: "192.168.0.100", 553 MBits: 20, 554 ReservedPorts: []Port{{"one", 8000, 0, ""}, {"two", 9000, 0, ""}}, 555 }, 556 }, 557 }, 558 }, 559 }, 560 { 561 TaskResources: map[string]*Resources{ 562 "api": { 563 Networks: []*NetworkResource{ 564 { 565 Device: "eth0", 566 IP: "192.168.0.100", 567 MBits: 50, 568 ReservedPorts: []Port{{"one", 10000, 0, ""}}, 569 }, 570 }, 571 }, 572 }, 573 }, 574 } 575 collide, reason := idx.AddAllocs(allocs) 576 if collide || reason != "" { 577 t.Fatalf("bad") 578 } 579 580 if idx.UsedBandwidth["eth0"] != 70 { 581 t.Fatalf("Bad") 582 } 583 if !idx.UsedPorts["192.168.0.100"].Check(8000) { 584 t.Fatalf("Bad") 585 } 586 if !idx.UsedPorts["192.168.0.100"].Check(9000) { 587 t.Fatalf("Bad") 588 } 589 if !idx.UsedPorts["192.168.0.100"].Check(10000) { 590 t.Fatalf("Bad") 591 } 592 } 593 594 // COMPAT(0.11): Remove in 0.11 595 func TestNetworkIndex_yieldIP_Old(t *testing.T) { 596 ci.Parallel(t) 597 598 idx := NewNetworkIndex() 599 n := &Node{ 600 Resources: &Resources{ 601 Networks: []*NetworkResource{ 602 { 603 Device: "eth0", 604 CIDR: "192.168.0.100/30", 605 MBits: 1000, 606 }, 607 }, 608 }, 609 Reserved: &Resources{ 610 Networks: []*NetworkResource{ 611 { 612 Device: "eth0", 613 IP: "192.168.0.100", 614 ReservedPorts: []Port{{"ssh", 22, 0, ""}}, 615 MBits: 1, 616 }, 617 }, 618 }, 619 } 620 idx.SetNode(n) 621 622 var out []string 623 idx.yieldIP(func(n *NetworkResource, ip net.IP) (stop bool) { 624 out = append(out, ip.String()) 625 return 626 }) 627 628 expect := []string{"192.168.0.100", "192.168.0.101", 629 "192.168.0.102", "192.168.0.103"} 630 if !reflect.DeepEqual(out, expect) { 631 t.Fatalf("bad: %v", out) 632 } 633 } 634 635 // COMPAT(0.11): Remove in 0.11 636 func TestNetworkIndex_AssignTaskNetwork_Old(t *testing.T) { 637 ci.Parallel(t) 638 639 idx := NewNetworkIndex() 640 n := &Node{ 641 Resources: &Resources{ 642 Networks: []*NetworkResource{ 643 { 644 Device: "eth0", 645 CIDR: "192.168.0.100/30", 646 MBits: 1000, 647 }, 648 }, 649 }, 650 Reserved: &Resources{ 651 Networks: []*NetworkResource{ 652 { 653 Device: "eth0", 654 IP: "192.168.0.100", 655 ReservedPorts: []Port{{"ssh", 22, 0, ""}}, 656 MBits: 1, 657 }, 658 }, 659 }, 660 } 661 idx.SetNode(n) 662 663 allocs := []*Allocation{ 664 { 665 TaskResources: map[string]*Resources{ 666 "web": { 667 Networks: []*NetworkResource{ 668 { 669 Device: "eth0", 670 IP: "192.168.0.100", 671 MBits: 20, 672 ReservedPorts: []Port{{"one", 8000, 0, ""}, {"two", 9000, 0, ""}}, 673 }, 674 }, 675 }, 676 }, 677 }, 678 { 679 TaskResources: map[string]*Resources{ 680 "api": { 681 Networks: []*NetworkResource{ 682 { 683 Device: "eth0", 684 IP: "192.168.0.100", 685 MBits: 50, 686 ReservedPorts: []Port{{"main", 10000, 0, ""}}, 687 }, 688 }, 689 }, 690 }, 691 }, 692 } 693 idx.AddAllocs(allocs) 694 695 // Ask for a reserved port 696 ask := &NetworkResource{ 697 ReservedPorts: []Port{{"main", 8000, 0, ""}}, 698 } 699 offer, err := idx.AssignTaskNetwork(ask) 700 if err != nil { 701 t.Fatalf("err: %v", err) 702 } 703 if offer == nil { 704 t.Fatalf("bad") 705 } 706 if offer.IP != "192.168.0.101" { 707 t.Fatalf("bad: %#v", offer) 708 } 709 rp := Port{"main", 8000, 0, ""} 710 if len(offer.ReservedPorts) != 1 || offer.ReservedPorts[0] != rp { 711 t.Fatalf("bad: %#v", offer) 712 } 713 714 // Ask for dynamic ports 715 ask = &NetworkResource{ 716 DynamicPorts: []Port{{"http", 0, 80, ""}, {"https", 0, 443, ""}, {"admin", 0, 8080, ""}}, 717 } 718 offer, err = idx.AssignTaskNetwork(ask) 719 if err != nil { 720 t.Fatalf("err: %v", err) 721 } 722 if offer == nil { 723 t.Fatalf("bad") 724 } 725 if offer.IP != "192.168.0.100" { 726 t.Fatalf("bad: %#v", offer) 727 } 728 if len(offer.DynamicPorts) != 3 { 729 t.Fatalf("There should be three dynamic ports") 730 } 731 for _, port := range offer.DynamicPorts { 732 if port.Value == 0 { 733 t.Fatalf("Dynamic Port: %v should have been assigned a host port", port.Label) 734 } 735 } 736 737 // Ask for reserved + dynamic ports 738 ask = &NetworkResource{ 739 ReservedPorts: []Port{{"main", 2345, 0, ""}}, 740 DynamicPorts: []Port{{"http", 0, 80, ""}, {"https", 0, 443, ""}, {"admin", 0, 8080, ""}}, 741 } 742 offer, err = idx.AssignTaskNetwork(ask) 743 if err != nil { 744 t.Fatalf("err: %v", err) 745 } 746 if offer == nil { 747 t.Fatalf("bad") 748 } 749 if offer.IP != "192.168.0.100" { 750 t.Fatalf("bad: %#v", offer) 751 } 752 753 rp = Port{"main", 2345, 0, ""} 754 if len(offer.ReservedPorts) != 1 || offer.ReservedPorts[0] != rp { 755 t.Fatalf("bad: %#v", offer) 756 } 757 758 // Ask for too much bandwidth 759 ask = &NetworkResource{ 760 MBits: 1000, 761 } 762 offer, err = idx.AssignTaskNetwork(ask) 763 if err.Error() != "bandwidth exceeded" { 764 t.Fatalf("err: %v", err) 765 } 766 if offer != nil { 767 t.Fatalf("bad") 768 } 769 } 770 771 // COMPAT(0.11): Remove in 0.11 772 // This test ensures that even with a small domain of available ports we are 773 // able to make a dynamic port allocation. 774 func TestNetworkIndex_AssignTaskNetwork_Dynamic_Contention_Old(t *testing.T) { 775 ci.Parallel(t) 776 777 // Create a node that only has one free port 778 idx := NewNetworkIndex() 779 n := &Node{ 780 Resources: &Resources{ 781 Networks: []*NetworkResource{ 782 { 783 Device: "eth0", 784 CIDR: "192.168.0.100/32", 785 MBits: 1000, 786 }, 787 }, 788 }, 789 Reserved: &Resources{ 790 Networks: []*NetworkResource{ 791 { 792 Device: "eth0", 793 IP: "192.168.0.100", 794 MBits: 1, 795 }, 796 }, 797 }, 798 } 799 for i := idx.MinDynamicPort; i < idx.MaxDynamicPort; i++ { 800 n.Reserved.Networks[0].ReservedPorts = append(n.Reserved.Networks[0].ReservedPorts, Port{Value: i}) 801 } 802 803 idx.SetNode(n) 804 805 // Ask for dynamic ports 806 ask := &NetworkResource{ 807 DynamicPorts: []Port{{"http", 0, 80, ""}}, 808 } 809 offer, err := idx.AssignTaskNetwork(ask) 810 if err != nil { 811 t.Fatalf("err: %v", err) 812 } 813 if offer == nil { 814 t.Fatalf("bad") 815 } 816 if offer.IP != "192.168.0.100" { 817 t.Fatalf("bad: %#v", offer) 818 } 819 if len(offer.DynamicPorts) != 1 { 820 t.Fatalf("There should be three dynamic ports") 821 } 822 if p := offer.DynamicPorts[0].Value; p != idx.MaxDynamicPort { 823 t.Fatalf("Dynamic Port: should have been assigned %d; got %d", p, idx.MaxDynamicPort) 824 } 825 } 826 827 func TestIntContains(t *testing.T) { 828 ci.Parallel(t) 829 830 l := []int{1, 2, 10, 20} 831 if isPortReserved(l, 50) { 832 t.Fatalf("bad") 833 } 834 if !isPortReserved(l, 20) { 835 t.Fatalf("bad") 836 } 837 if !isPortReserved(l, 1) { 838 t.Fatalf("bad") 839 } 840 } 841 842 func TestNetworkIndex_SetNode_HostNets(t *testing.T) { 843 ci.Parallel(t) 844 845 idx := NewNetworkIndex() 846 n := &Node{ 847 NodeResources: &NodeResources{ 848 Networks: []*NetworkResource{ 849 // As of Nomad v1.3 bridge networks get 850 // registered with only their mode set. 851 { 852 Mode: "bridge", 853 }, 854 855 // Localhost (agent interface) 856 { 857 CIDR: "127.0.0.1/32", 858 Device: "lo", 859 IP: "127.0.0.1", 860 MBits: 1000, 861 Mode: "host", 862 }, 863 { 864 CIDR: "::1/128", 865 Device: "lo", 866 IP: "::1", 867 MBits: 1000, 868 Mode: "host", 869 }, 870 871 // Node.NodeResources.Networks does *not* 872 // contain host_networks. 873 }, 874 NodeNetworks: []*NodeNetworkResource{ 875 // As of Nomad v1.3 bridge networks get 876 // registered with only their mode set. 877 { 878 Mode: "bridge", 879 }, 880 { 881 Addresses: []NodeNetworkAddress{ 882 { 883 Address: "127.0.0.1", 884 Alias: "default", 885 Family: "ipv4", 886 }, 887 { 888 Address: "::1", 889 Alias: "default", 890 Family: "ipv6", 891 }, 892 }, 893 Device: "lo", 894 Mode: "host", 895 Speed: 1000, 896 }, 897 { 898 Addresses: []NodeNetworkAddress{ 899 { 900 Address: "192.168.0.1", 901 Alias: "eth0", 902 Family: "ipv4", 903 ReservedPorts: "22", 904 }, 905 }, 906 Device: "enxaaaaaaaaaaaa", 907 MacAddress: "aa:aa:aa:aa:aa:aa", 908 Mode: "host", 909 Speed: 1000, 910 }, 911 { 912 Addresses: []NodeNetworkAddress{ 913 { 914 Address: "192.168.1.1", 915 Alias: "eth1", 916 Family: "ipv4", 917 ReservedPorts: "80", 918 }, 919 }, 920 Device: "enxbbbbbbbbbbbb", 921 MacAddress: "bb:bb:bb:bb:bb:bb", 922 Mode: "host", 923 Speed: 1000, 924 }, 925 }, 926 }, 927 ReservedResources: &NodeReservedResources{ 928 Networks: NodeReservedNetworkResources{ 929 ReservedHostPorts: "22", 930 }, 931 }, 932 } 933 934 require.NoError(t, idx.SetNode(n)) 935 936 // TaskNetworks should only contain the bridge and agent network 937 require.Len(t, idx.TaskNetworks, 2) 938 939 // Ports should be used across all 4 IPs 940 require.Equal(t, 4, len(idx.UsedPorts)) 941 942 // 22 should be reserved on all IPs 943 require.True(t, idx.UsedPorts["127.0.0.1"].Check(22)) 944 require.True(t, idx.UsedPorts["::1"].Check(22)) 945 require.True(t, idx.UsedPorts["192.168.0.1"].Check(22)) 946 require.True(t, idx.UsedPorts["192.168.1.1"].Check(22)) 947 948 // 80 should only be reserved on eth1's address 949 require.False(t, idx.UsedPorts["127.0.0.1"].Check(80)) 950 require.False(t, idx.UsedPorts["::1"].Check(80)) 951 require.False(t, idx.UsedPorts["192.168.0.1"].Check(80)) 952 require.True(t, idx.UsedPorts["192.168.1.1"].Check(80)) 953 }