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