sigs.k8s.io/cluster-api-provider-azure@v1.14.3/api/v1beta1/azurecluster_default_test.go (about) 1 /* 2 Copyright 2021 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package v1beta1 18 19 import ( 20 "encoding/json" 21 "reflect" 22 "testing" 23 24 corev1 "k8s.io/api/core/v1" 25 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 26 "k8s.io/utils/ptr" 27 ) 28 29 func TestResourceGroupDefault(t *testing.T) { 30 cases := map[string]struct { 31 cluster *AzureCluster 32 output *AzureCluster 33 }{ 34 "default empty rg": { 35 cluster: &AzureCluster{ 36 ObjectMeta: metav1.ObjectMeta{ 37 Name: "foo", 38 }, 39 Spec: AzureClusterSpec{}, 40 }, 41 output: &AzureCluster{ 42 ObjectMeta: metav1.ObjectMeta{ 43 Name: "foo", 44 }, 45 Spec: AzureClusterSpec{ 46 ResourceGroup: "foo", 47 }, 48 }, 49 }, 50 "don't change if mismatched": { 51 cluster: &AzureCluster{ 52 ObjectMeta: metav1.ObjectMeta{ 53 Name: "foo", 54 }, 55 Spec: AzureClusterSpec{ 56 ResourceGroup: "bar", 57 }, 58 }, 59 output: &AzureCluster{ 60 ObjectMeta: metav1.ObjectMeta{ 61 Name: "foo", 62 }, 63 Spec: AzureClusterSpec{ 64 ResourceGroup: "bar", 65 }, 66 }, 67 }, 68 } 69 70 for name := range cases { 71 c := cases[name] 72 t.Run(name, func(t *testing.T) { 73 t.Parallel() 74 c.cluster.setResourceGroupDefault() 75 if !reflect.DeepEqual(c.cluster, c.output) { 76 expected, _ := json.MarshalIndent(c.output, "", "\t") 77 actual, _ := json.MarshalIndent(c.cluster, "", "\t") 78 t.Errorf("Expected %s, got %s", string(expected), string(actual)) 79 } 80 }) 81 } 82 } 83 84 func TestVnetDefaults(t *testing.T) { 85 cases := []struct { 86 name string 87 cluster *AzureCluster 88 output *AzureCluster 89 }{ 90 { 91 name: "resource group vnet specified", 92 cluster: createValidCluster(), 93 output: &AzureCluster{ 94 ObjectMeta: metav1.ObjectMeta{ 95 Name: "test-cluster", 96 }, 97 Spec: AzureClusterSpec{ 98 NetworkSpec: NetworkSpec{ 99 Vnet: VnetSpec{ 100 ResourceGroup: "custom-vnet", 101 Name: "my-vnet", 102 VnetClassSpec: VnetClassSpec{ 103 CIDRBlocks: []string{DefaultVnetCIDR}, 104 }, 105 }, 106 Subnets: Subnets{ 107 { 108 SubnetClassSpec: SubnetClassSpec{ 109 Role: SubnetControlPlane, 110 Name: "control-plane-subnet", 111 }, 112 113 SecurityGroup: SecurityGroup{}, 114 RouteTable: RouteTable{}, 115 }, 116 { 117 SubnetClassSpec: SubnetClassSpec{ 118 Role: SubnetNode, 119 Name: "node-subnet", 120 }, 121 SecurityGroup: SecurityGroup{}, 122 RouteTable: RouteTable{}, 123 }, 124 }, 125 APIServerLB: LoadBalancerSpec{ 126 Name: "my-lb", 127 FrontendIPs: []FrontendIP{ 128 { 129 Name: "ip-config", 130 PublicIP: &PublicIPSpec{ 131 Name: "public-ip", 132 DNSName: "myfqdn.azure.com", 133 }, 134 }, 135 }, 136 LoadBalancerClassSpec: LoadBalancerClassSpec{ 137 SKU: SKUStandard, 138 139 Type: Public, 140 }, 141 }, 142 NodeOutboundLB: &LoadBalancerSpec{ 143 FrontendIPsCount: ptr.To[int32](1), 144 }, 145 }, 146 AzureClusterClassSpec: AzureClusterClassSpec{ 147 IdentityRef: &corev1.ObjectReference{ 148 Kind: AzureClusterIdentityKind, 149 }, 150 }, 151 }, 152 }, 153 }, 154 { 155 name: "vnet not specified", 156 cluster: &AzureCluster{ 157 ObjectMeta: metav1.ObjectMeta{ 158 Name: "cluster-test", 159 }, 160 Spec: AzureClusterSpec{ 161 ResourceGroup: "cluster-test", 162 AzureClusterClassSpec: AzureClusterClassSpec{ 163 IdentityRef: &corev1.ObjectReference{ 164 Kind: AzureClusterIdentityKind, 165 }, 166 }, 167 }, 168 }, 169 output: &AzureCluster{ 170 ObjectMeta: metav1.ObjectMeta{ 171 Name: "cluster-test", 172 }, 173 Spec: AzureClusterSpec{ 174 ResourceGroup: "cluster-test", 175 NetworkSpec: NetworkSpec{ 176 Vnet: VnetSpec{ 177 ResourceGroup: "cluster-test", 178 Name: "cluster-test-vnet", 179 VnetClassSpec: VnetClassSpec{ 180 CIDRBlocks: []string{DefaultVnetCIDR}, 181 }, 182 }, 183 }, 184 AzureClusterClassSpec: AzureClusterClassSpec{ 185 IdentityRef: &corev1.ObjectReference{ 186 Kind: AzureClusterIdentityKind, 187 }, 188 }, 189 }, 190 }, 191 }, 192 { 193 name: "custom CIDR", 194 cluster: &AzureCluster{ 195 ObjectMeta: metav1.ObjectMeta{ 196 Name: "cluster-test", 197 }, 198 Spec: AzureClusterSpec{ 199 ResourceGroup: "cluster-test", 200 NetworkSpec: NetworkSpec{ 201 Vnet: VnetSpec{ 202 VnetClassSpec: VnetClassSpec{ 203 CIDRBlocks: []string{"10.0.0.0/16"}, 204 }, 205 }, 206 }, 207 AzureClusterClassSpec: AzureClusterClassSpec{ 208 IdentityRef: &corev1.ObjectReference{ 209 Kind: AzureClusterIdentityKind, 210 }, 211 }, 212 }, 213 }, 214 output: &AzureCluster{ 215 ObjectMeta: metav1.ObjectMeta{ 216 Name: "cluster-test", 217 }, 218 Spec: AzureClusterSpec{ 219 ResourceGroup: "cluster-test", 220 NetworkSpec: NetworkSpec{ 221 Vnet: VnetSpec{ 222 ResourceGroup: "cluster-test", 223 Name: "cluster-test-vnet", 224 VnetClassSpec: VnetClassSpec{ 225 CIDRBlocks: []string{"10.0.0.0/16"}, 226 }, 227 }, 228 }, 229 AzureClusterClassSpec: AzureClusterClassSpec{ 230 IdentityRef: &corev1.ObjectReference{ 231 Kind: AzureClusterIdentityKind, 232 }, 233 }, 234 }, 235 }, 236 }, 237 { 238 name: "IPv6 enabled", 239 cluster: &AzureCluster{ 240 ObjectMeta: metav1.ObjectMeta{ 241 Name: "cluster-test", 242 }, 243 Spec: AzureClusterSpec{ 244 ResourceGroup: "cluster-test", 245 NetworkSpec: NetworkSpec{ 246 Vnet: VnetSpec{ 247 VnetClassSpec: VnetClassSpec{ 248 CIDRBlocks: []string{DefaultVnetCIDR, "2001:1234:5678:9a00::/56"}, 249 }, 250 }, 251 }, 252 AzureClusterClassSpec: AzureClusterClassSpec{ 253 IdentityRef: &corev1.ObjectReference{ 254 Kind: AzureClusterIdentityKind, 255 }, 256 }, 257 }, 258 }, 259 output: &AzureCluster{ 260 ObjectMeta: metav1.ObjectMeta{ 261 Name: "cluster-test", 262 }, 263 Spec: AzureClusterSpec{ 264 ResourceGroup: "cluster-test", 265 NetworkSpec: NetworkSpec{ 266 Vnet: VnetSpec{ 267 ResourceGroup: "cluster-test", 268 Name: "cluster-test-vnet", 269 VnetClassSpec: VnetClassSpec{ 270 CIDRBlocks: []string{DefaultVnetCIDR, "2001:1234:5678:9a00::/56"}, 271 }, 272 }, 273 }, 274 AzureClusterClassSpec: AzureClusterClassSpec{ 275 IdentityRef: &corev1.ObjectReference{ 276 Kind: AzureClusterIdentityKind, 277 }, 278 }, 279 }, 280 }, 281 }, 282 } 283 284 for _, c := range cases { 285 tc := c 286 t.Run(tc.name, func(t *testing.T) { 287 t.Parallel() 288 tc.cluster.setVnetDefaults() 289 if !reflect.DeepEqual(tc.cluster, tc.output) { 290 expected, _ := json.MarshalIndent(tc.output, "", "\t") 291 actual, _ := json.MarshalIndent(tc.cluster, "", "\t") 292 t.Errorf("Expected %s, got %s", string(expected), string(actual)) 293 } 294 }) 295 } 296 } 297 298 func TestSubnetDefaults(t *testing.T) { 299 cases := []struct { 300 name string 301 cluster *AzureCluster 302 output *AzureCluster 303 }{ 304 { 305 name: "no subnets", 306 cluster: &AzureCluster{ 307 ObjectMeta: metav1.ObjectMeta{ 308 Name: "cluster-test", 309 }, 310 Spec: AzureClusterSpec{ 311 NetworkSpec: NetworkSpec{}, 312 }, 313 }, 314 output: &AzureCluster{ 315 ObjectMeta: metav1.ObjectMeta{ 316 Name: "cluster-test", 317 }, 318 Spec: AzureClusterSpec{ 319 NetworkSpec: NetworkSpec{ 320 Subnets: Subnets{ 321 { 322 SubnetClassSpec: SubnetClassSpec{ 323 Role: SubnetControlPlane, 324 CIDRBlocks: []string{DefaultControlPlaneSubnetCIDR}, 325 Name: "cluster-test-controlplane-subnet", 326 }, 327 328 SecurityGroup: SecurityGroup{Name: "cluster-test-controlplane-nsg"}, 329 RouteTable: RouteTable{}, 330 }, 331 { 332 SubnetClassSpec: SubnetClassSpec{ 333 Role: SubnetNode, 334 CIDRBlocks: []string{DefaultNodeSubnetCIDR}, 335 Name: "cluster-test-node-subnet", 336 }, 337 SecurityGroup: SecurityGroup{Name: "cluster-test-node-nsg"}, 338 RouteTable: RouteTable{Name: "cluster-test-node-routetable"}, 339 NatGateway: NatGateway{NatGatewayClassSpec: NatGatewayClassSpec{ 340 Name: "cluster-test-node-natgw", 341 }}, 342 }, 343 }, 344 }, 345 }, 346 }, 347 }, 348 { 349 name: "subnets with custom attributes", 350 cluster: &AzureCluster{ 351 ObjectMeta: metav1.ObjectMeta{ 352 Name: "cluster-test", 353 }, 354 Spec: AzureClusterSpec{ 355 NetworkSpec: NetworkSpec{ 356 Subnets: Subnets{ 357 { 358 SubnetClassSpec: SubnetClassSpec{ 359 Role: SubnetControlPlane, 360 CIDRBlocks: []string{"10.0.0.16/24"}, 361 Name: "my-controlplane-subnet", 362 }, 363 }, 364 { 365 SubnetClassSpec: SubnetClassSpec{ 366 Role: SubnetNode, 367 CIDRBlocks: []string{"10.1.0.16/24"}, 368 Name: "my-node-subnet", 369 }, 370 NatGateway: NatGateway{ 371 NatGatewayClassSpec: NatGatewayClassSpec{ 372 Name: "foo-natgw", 373 }, 374 }, 375 }, 376 }, 377 }, 378 }, 379 }, 380 output: &AzureCluster{ 381 ObjectMeta: metav1.ObjectMeta{ 382 Name: "cluster-test", 383 }, 384 Spec: AzureClusterSpec{ 385 NetworkSpec: NetworkSpec{ 386 Subnets: Subnets{ 387 { 388 SubnetClassSpec: SubnetClassSpec{ 389 Role: SubnetControlPlane, 390 CIDRBlocks: []string{"10.0.0.16/24"}, 391 Name: "my-controlplane-subnet", 392 }, 393 SecurityGroup: SecurityGroup{Name: "cluster-test-controlplane-nsg"}, 394 RouteTable: RouteTable{}, 395 }, 396 { 397 SubnetClassSpec: SubnetClassSpec{ 398 Role: SubnetNode, 399 CIDRBlocks: []string{"10.1.0.16/24"}, 400 Name: "my-node-subnet", 401 }, 402 SecurityGroup: SecurityGroup{Name: "cluster-test-node-nsg"}, 403 RouteTable: RouteTable{Name: "cluster-test-node-routetable"}, 404 NatGateway: NatGateway{ 405 NatGatewayClassSpec: NatGatewayClassSpec{ 406 Name: "foo-natgw", 407 }, 408 NatGatewayIP: PublicIPSpec{ 409 Name: "pip-foo-natgw", 410 }, 411 }, 412 }, 413 }, 414 }, 415 }, 416 }, 417 }, 418 { 419 name: "subnets specified", 420 cluster: &AzureCluster{ 421 ObjectMeta: metav1.ObjectMeta{ 422 Name: "cluster-test", 423 }, 424 Spec: AzureClusterSpec{ 425 NetworkSpec: NetworkSpec{ 426 Subnets: Subnets{ 427 { 428 SubnetClassSpec: SubnetClassSpec{ 429 Role: SubnetControlPlane, 430 Name: "cluster-test-controlplane-subnet", 431 }, 432 }, 433 { 434 SubnetClassSpec: SubnetClassSpec{ 435 Role: SubnetNode, 436 Name: "cluster-test-node-subnet", 437 }, 438 }, 439 }, 440 }, 441 }, 442 }, 443 output: &AzureCluster{ 444 ObjectMeta: metav1.ObjectMeta{ 445 Name: "cluster-test", 446 }, 447 Spec: AzureClusterSpec{ 448 NetworkSpec: NetworkSpec{ 449 Subnets: Subnets{ 450 { 451 SubnetClassSpec: SubnetClassSpec{ 452 Role: SubnetControlPlane, 453 CIDRBlocks: []string{DefaultControlPlaneSubnetCIDR}, 454 Name: "cluster-test-controlplane-subnet", 455 }, 456 457 SecurityGroup: SecurityGroup{Name: "cluster-test-controlplane-nsg"}, 458 RouteTable: RouteTable{}, 459 }, 460 { 461 SubnetClassSpec: SubnetClassSpec{ 462 Role: SubnetNode, 463 CIDRBlocks: []string{DefaultNodeSubnetCIDR}, 464 Name: "cluster-test-node-subnet", 465 }, 466 SecurityGroup: SecurityGroup{Name: "cluster-test-node-nsg"}, 467 RouteTable: RouteTable{Name: "cluster-test-node-routetable"}, 468 NatGateway: NatGateway{ 469 NatGatewayClassSpec: NatGatewayClassSpec{ 470 Name: "cluster-test-node-natgw-1", 471 }, 472 NatGatewayIP: PublicIPSpec{ 473 Name: "pip-cluster-test-node-natgw-1", 474 }, 475 }, 476 }, 477 }, 478 }, 479 }, 480 }, 481 }, 482 { 483 name: "cluster subnet with custom attributes", 484 cluster: &AzureCluster{ 485 ObjectMeta: metav1.ObjectMeta{ 486 Name: "cluster-test", 487 }, 488 Spec: AzureClusterSpec{ 489 NetworkSpec: NetworkSpec{ 490 Subnets: Subnets{ 491 { 492 SubnetClassSpec: SubnetClassSpec{ 493 Role: SubnetCluster, 494 CIDRBlocks: []string{"10.0.0.16/24"}, 495 Name: "my-subnet", 496 }, 497 NatGateway: NatGateway{ 498 NatGatewayClassSpec: NatGatewayClassSpec{ 499 Name: "foo-natgw", 500 }, 501 }, 502 }, 503 }, 504 }, 505 }, 506 }, 507 output: &AzureCluster{ 508 ObjectMeta: metav1.ObjectMeta{ 509 Name: "cluster-test", 510 }, 511 Spec: AzureClusterSpec{ 512 NetworkSpec: NetworkSpec{ 513 Subnets: Subnets{ 514 { 515 SubnetClassSpec: SubnetClassSpec{ 516 Role: SubnetCluster, 517 CIDRBlocks: []string{"10.0.0.16/24"}, 518 Name: "my-subnet", 519 }, 520 SecurityGroup: SecurityGroup{Name: "cluster-test-nsg"}, 521 RouteTable: RouteTable{Name: "cluster-test-routetable"}, 522 NatGateway: NatGateway{ 523 NatGatewayClassSpec: NatGatewayClassSpec{ 524 Name: "foo-natgw", 525 }, 526 NatGatewayIP: PublicIPSpec{ 527 Name: "pip-foo-natgw", 528 }, 529 }, 530 }, 531 }, 532 }, 533 }, 534 }, 535 }, 536 { 537 name: "cluster subnet with subnets specified", 538 cluster: &AzureCluster{ 539 ObjectMeta: metav1.ObjectMeta{ 540 Name: "cluster-test", 541 }, 542 Spec: AzureClusterSpec{ 543 NetworkSpec: NetworkSpec{ 544 Subnets: Subnets{ 545 { 546 SubnetClassSpec: SubnetClassSpec{ 547 Role: SubnetCluster, 548 Name: "cluster-test-subnet", 549 }, 550 }, 551 }, 552 }, 553 }, 554 }, 555 output: &AzureCluster{ 556 ObjectMeta: metav1.ObjectMeta{ 557 Name: "cluster-test", 558 }, 559 Spec: AzureClusterSpec{ 560 NetworkSpec: NetworkSpec{ 561 Subnets: Subnets{ 562 { 563 SubnetClassSpec: SubnetClassSpec{ 564 Role: SubnetCluster, 565 CIDRBlocks: []string{DefaultClusterSubnetCIDR}, 566 Name: "cluster-test-subnet", 567 }, 568 SecurityGroup: SecurityGroup{Name: "cluster-test-nsg"}, 569 RouteTable: RouteTable{Name: "cluster-test-routetable"}, 570 NatGateway: NatGateway{ 571 NatGatewayClassSpec: NatGatewayClassSpec{ 572 Name: "cluster-test-natgw", 573 }, 574 NatGatewayIP: PublicIPSpec{ 575 Name: "pip-cluster-test-natgw", 576 }, 577 }, 578 }, 579 }, 580 }, 581 }, 582 }, 583 }, 584 { 585 name: "subnets route tables specified", 586 cluster: &AzureCluster{ 587 ObjectMeta: metav1.ObjectMeta{ 588 Name: "cluster-test", 589 }, 590 Spec: AzureClusterSpec{ 591 NetworkSpec: NetworkSpec{ 592 Subnets: Subnets{ 593 { 594 SubnetClassSpec: SubnetClassSpec{ 595 Role: SubnetControlPlane, 596 Name: "cluster-test-controlplane-subnet", 597 }, 598 RouteTable: RouteTable{ 599 Name: "control-plane-custom-route-table", 600 }, 601 }, 602 { 603 SubnetClassSpec: SubnetClassSpec{ 604 Role: SubnetNode, 605 Name: "cluster-test-node-subnet", 606 }, 607 }, 608 }, 609 }, 610 }, 611 }, 612 output: &AzureCluster{ 613 ObjectMeta: metav1.ObjectMeta{ 614 Name: "cluster-test", 615 }, 616 Spec: AzureClusterSpec{ 617 NetworkSpec: NetworkSpec{ 618 Subnets: Subnets{ 619 { 620 SubnetClassSpec: SubnetClassSpec{ 621 Role: SubnetControlPlane, 622 CIDRBlocks: []string{DefaultControlPlaneSubnetCIDR}, 623 Name: "cluster-test-controlplane-subnet", 624 }, 625 SecurityGroup: SecurityGroup{Name: "cluster-test-controlplane-nsg"}, 626 RouteTable: RouteTable{Name: "control-plane-custom-route-table"}, 627 }, 628 { 629 SubnetClassSpec: SubnetClassSpec{ 630 Role: SubnetNode, 631 CIDRBlocks: []string{DefaultNodeSubnetCIDR}, 632 Name: "cluster-test-node-subnet", 633 }, 634 SecurityGroup: SecurityGroup{Name: "cluster-test-node-nsg"}, 635 RouteTable: RouteTable{Name: "cluster-test-node-routetable"}, 636 NatGateway: NatGateway{ 637 NatGatewayClassSpec: NatGatewayClassSpec{ 638 Name: "cluster-test-node-natgw-1", 639 }, 640 NatGatewayIP: PublicIPSpec{ 641 Name: "pip-cluster-test-node-natgw-1", 642 }, 643 }, 644 }, 645 }, 646 }, 647 }, 648 }, 649 }, 650 { 651 name: "only node subnet specified", 652 cluster: &AzureCluster{ 653 ObjectMeta: metav1.ObjectMeta{ 654 Name: "cluster-test", 655 }, 656 Spec: AzureClusterSpec{ 657 NetworkSpec: NetworkSpec{ 658 Subnets: Subnets{ 659 { 660 SubnetClassSpec: SubnetClassSpec{ 661 Role: SubnetNode, 662 Name: "my-node-subnet", 663 }, 664 }, 665 }, 666 }, 667 }, 668 }, 669 output: &AzureCluster{ 670 ObjectMeta: metav1.ObjectMeta{ 671 Name: "cluster-test", 672 }, 673 Spec: AzureClusterSpec{ 674 NetworkSpec: NetworkSpec{ 675 Subnets: Subnets{ 676 { 677 SubnetClassSpec: SubnetClassSpec{ 678 Role: SubnetNode, 679 CIDRBlocks: []string{DefaultNodeSubnetCIDR}, 680 Name: "my-node-subnet", 681 }, 682 683 SecurityGroup: SecurityGroup{Name: "cluster-test-node-nsg"}, 684 RouteTable: RouteTable{Name: "cluster-test-node-routetable"}, 685 NatGateway: NatGateway{ 686 NatGatewayClassSpec: NatGatewayClassSpec{ 687 Name: "cluster-test-node-natgw-1", 688 }, 689 NatGatewayIP: PublicIPSpec{ 690 Name: "pip-cluster-test-node-natgw-1", 691 }, 692 }, 693 }, 694 { 695 SubnetClassSpec: SubnetClassSpec{ 696 Role: SubnetControlPlane, 697 CIDRBlocks: []string{DefaultControlPlaneSubnetCIDR}, 698 Name: "cluster-test-controlplane-subnet", 699 }, 700 SecurityGroup: SecurityGroup{Name: "cluster-test-controlplane-nsg"}, 701 RouteTable: RouteTable{}, 702 }, 703 }, 704 }, 705 }, 706 }, 707 }, 708 { 709 name: "subnets specified with IPv6 enabled", 710 cluster: &AzureCluster{ 711 ObjectMeta: metav1.ObjectMeta{ 712 Name: "cluster-test", 713 }, 714 Spec: AzureClusterSpec{ 715 NetworkSpec: NetworkSpec{ 716 Vnet: VnetSpec{ 717 VnetClassSpec: VnetClassSpec{ 718 CIDRBlocks: []string{"2001:be00::1/56"}, 719 }, 720 }, 721 Subnets: Subnets{ 722 { 723 SubnetClassSpec: SubnetClassSpec{ 724 Role: "control-plane", 725 CIDRBlocks: []string{"2001:beef::1/64"}, 726 Name: "cluster-test-controlplane-subnet", 727 }, 728 }, 729 { 730 SubnetClassSpec: SubnetClassSpec{ 731 Role: "node", 732 CIDRBlocks: []string{"2001:beea::1/64"}, 733 Name: "cluster-test-node-subnet", 734 }, 735 }, 736 }, 737 }, 738 }, 739 }, 740 output: &AzureCluster{ 741 ObjectMeta: metav1.ObjectMeta{ 742 Name: "cluster-test", 743 }, 744 Spec: AzureClusterSpec{ 745 NetworkSpec: NetworkSpec{ 746 Vnet: VnetSpec{ 747 VnetClassSpec: VnetClassSpec{ 748 CIDRBlocks: []string{"2001:be00::1/56"}, 749 }, 750 }, 751 Subnets: Subnets{ 752 { 753 SubnetClassSpec: SubnetClassSpec{ 754 Role: SubnetControlPlane, 755 CIDRBlocks: []string{"2001:beef::1/64"}, 756 Name: "cluster-test-controlplane-subnet", 757 }, 758 SecurityGroup: SecurityGroup{Name: "cluster-test-controlplane-nsg"}, 759 RouteTable: RouteTable{}, 760 }, 761 { 762 SubnetClassSpec: SubnetClassSpec{ 763 Role: SubnetNode, 764 CIDRBlocks: []string{"2001:beea::1/64"}, 765 Name: "cluster-test-node-subnet", 766 }, 767 SecurityGroup: SecurityGroup{Name: "cluster-test-node-nsg"}, 768 RouteTable: RouteTable{Name: "cluster-test-node-routetable"}, 769 }, 770 }, 771 }, 772 }, 773 }, 774 }, 775 { 776 name: "subnets with custom security group", 777 cluster: &AzureCluster{ 778 ObjectMeta: metav1.ObjectMeta{ 779 Name: "cluster-test", 780 }, 781 Spec: AzureClusterSpec{ 782 NetworkSpec: NetworkSpec{ 783 Subnets: Subnets{ 784 { 785 SubnetClassSpec: SubnetClassSpec{ 786 Role: "control-plane", 787 Name: "cluster-test-controlplane-subnet", 788 }, 789 SecurityGroup: SecurityGroup{ 790 SecurityGroupClass: SecurityGroupClass{ 791 SecurityRules: []SecurityRule{ 792 { 793 Name: "allow_port_50000", 794 Description: "allow port 50000", 795 Protocol: "*", 796 Priority: 2202, 797 SourcePorts: ptr.To("*"), 798 DestinationPorts: ptr.To("*"), 799 Source: ptr.To("*"), 800 Destination: ptr.To("*"), 801 Action: SecurityRuleActionAllow, 802 }, 803 }, 804 }, 805 Name: "my-custom-sg", 806 }, 807 }, 808 { 809 SubnetClassSpec: SubnetClassSpec{ 810 Role: "node", 811 Name: "cluster-test-node-subnet", 812 }, 813 SecurityGroup: SecurityGroup{ 814 SecurityGroupClass: SecurityGroupClass{ 815 SecurityRules: []SecurityRule{ 816 { 817 Name: "allow_port_50000", 818 Description: "allow port 50000", 819 Protocol: "*", 820 Priority: 2202, 821 SourcePorts: ptr.To("*"), 822 DestinationPorts: ptr.To("*"), 823 Source: ptr.To("*"), 824 Destination: ptr.To("*"), 825 Action: SecurityRuleActionAllow, 826 }, 827 }, 828 }, 829 Name: "my-custom-node-sg", 830 }, 831 }, 832 }, 833 }, 834 }, 835 }, 836 output: &AzureCluster{ 837 ObjectMeta: metav1.ObjectMeta{ 838 Name: "cluster-test", 839 }, 840 Spec: AzureClusterSpec{ 841 NetworkSpec: NetworkSpec{ 842 Subnets: Subnets{ 843 { 844 SubnetClassSpec: SubnetClassSpec{ 845 Role: "control-plane", 846 CIDRBlocks: []string{DefaultControlPlaneSubnetCIDR}, 847 Name: "cluster-test-controlplane-subnet", 848 }, 849 SecurityGroup: SecurityGroup{ 850 SecurityGroupClass: SecurityGroupClass{ 851 SecurityRules: []SecurityRule{ 852 { 853 Name: "allow_port_50000", 854 Description: "allow port 50000", 855 Protocol: "*", 856 Priority: 2202, 857 SourcePorts: ptr.To("*"), 858 DestinationPorts: ptr.To("*"), 859 Source: ptr.To("*"), 860 Destination: ptr.To("*"), 861 Direction: SecurityRuleDirectionInbound, 862 Action: SecurityRuleActionAllow, 863 }, 864 }, 865 }, 866 Name: "my-custom-sg", 867 }, 868 }, 869 { 870 SubnetClassSpec: SubnetClassSpec{ 871 Role: SubnetNode, 872 CIDRBlocks: []string{DefaultNodeSubnetCIDR}, 873 Name: "cluster-test-node-subnet", 874 }, 875 SecurityGroup: SecurityGroup{ 876 Name: "my-custom-node-sg", 877 SecurityGroupClass: SecurityGroupClass{ 878 SecurityRules: []SecurityRule{ 879 { 880 Name: "allow_port_50000", 881 Description: "allow port 50000", 882 Protocol: "*", 883 Priority: 2202, 884 SourcePorts: ptr.To("*"), 885 DestinationPorts: ptr.To("*"), 886 Source: ptr.To("*"), 887 Destination: ptr.To("*"), 888 Direction: SecurityRuleDirectionInbound, 889 Action: SecurityRuleActionAllow, 890 }, 891 }, 892 }, 893 }, 894 RouteTable: RouteTable{Name: "cluster-test-node-routetable"}, 895 NatGateway: NatGateway{ 896 NatGatewayIP: PublicIPSpec{ 897 Name: "pip-cluster-test-node-natgw-1", 898 }, 899 NatGatewayClassSpec: NatGatewayClassSpec{ 900 Name: "cluster-test-node-natgw-1", 901 }, 902 }, 903 }, 904 }, 905 }, 906 }, 907 }, 908 }, 909 { 910 name: "subnets with custom security group to deny port 49999", 911 cluster: &AzureCluster{ 912 ObjectMeta: metav1.ObjectMeta{ 913 Name: "cluster-test", 914 }, 915 Spec: AzureClusterSpec{ 916 NetworkSpec: NetworkSpec{ 917 Subnets: Subnets{ 918 { 919 SubnetClassSpec: SubnetClassSpec{ 920 Role: "control-plane", 921 Name: "cluster-test-controlplane-subnet", 922 }, 923 SecurityGroup: SecurityGroup{ 924 SecurityGroupClass: SecurityGroupClass{ 925 SecurityRules: []SecurityRule{ 926 { 927 Name: "deny_port_49999", 928 Description: "deny port 49999", 929 Protocol: "*", 930 Priority: 2201, 931 SourcePorts: ptr.To("*"), 932 DestinationPorts: ptr.To("*"), 933 Source: ptr.To("*"), 934 Destination: ptr.To("*"), 935 Action: SecurityRuleActionDeny, 936 }, 937 }, 938 }, 939 Name: "my-custom-sg", 940 }, 941 }, 942 }, 943 }, 944 }, 945 }, 946 output: &AzureCluster{ 947 ObjectMeta: metav1.ObjectMeta{ 948 Name: "cluster-test", 949 }, 950 Spec: AzureClusterSpec{ 951 NetworkSpec: NetworkSpec{ 952 Subnets: Subnets{ 953 { 954 SubnetClassSpec: SubnetClassSpec{ 955 Role: "control-plane", 956 CIDRBlocks: []string{DefaultControlPlaneSubnetCIDR}, 957 Name: "cluster-test-controlplane-subnet", 958 }, 959 SecurityGroup: SecurityGroup{ 960 SecurityGroupClass: SecurityGroupClass{ 961 SecurityRules: []SecurityRule{ 962 { 963 Name: "deny_port_49999", 964 Description: "deny port 49999", 965 Protocol: "*", 966 Priority: 2201, 967 SourcePorts: ptr.To("*"), 968 DestinationPorts: ptr.To("*"), 969 Source: ptr.To("*"), 970 Destination: ptr.To("*"), 971 Direction: SecurityRuleDirectionInbound, 972 Action: SecurityRuleActionDeny, 973 }, 974 }, 975 }, 976 Name: "my-custom-sg", 977 }, 978 }, 979 { 980 SubnetClassSpec: SubnetClassSpec{ 981 Role: SubnetNode, 982 CIDRBlocks: []string{DefaultNodeSubnetCIDR}, 983 Name: "cluster-test-node-subnet", 984 }, 985 SecurityGroup: SecurityGroup{Name: "cluster-test-node-nsg"}, 986 RouteTable: RouteTable{Name: "cluster-test-node-routetable"}, 987 NatGateway: NatGateway{ 988 NatGatewayIP: PublicIPSpec{ 989 Name: "", 990 }, 991 NatGatewayClassSpec: NatGatewayClassSpec{ 992 Name: "cluster-test-node-natgw", 993 }, 994 }, 995 }, 996 }, 997 }, 998 }, 999 }, 1000 }, 1001 { 1002 name: "don't default NAT Gateway if subnet already exists", 1003 cluster: &AzureCluster{ 1004 ObjectMeta: metav1.ObjectMeta{ 1005 Name: "cluster-test", 1006 }, 1007 Spec: AzureClusterSpec{ 1008 NetworkSpec: NetworkSpec{ 1009 Subnets: Subnets{ 1010 { 1011 SubnetClassSpec: SubnetClassSpec{ 1012 Role: SubnetControlPlane, 1013 Name: "cluster-test-controlplane-subnet", 1014 }, 1015 ID: "my-subnet-id", 1016 }, 1017 { 1018 SubnetClassSpec: SubnetClassSpec{ 1019 Role: SubnetNode, 1020 Name: "cluster-test-node-subnet", 1021 }, 1022 ID: "my-subnet-id-2", 1023 }, 1024 }, 1025 }, 1026 }, 1027 }, 1028 output: &AzureCluster{ 1029 ObjectMeta: metav1.ObjectMeta{ 1030 Name: "cluster-test", 1031 }, 1032 Spec: AzureClusterSpec{ 1033 NetworkSpec: NetworkSpec{ 1034 Subnets: Subnets{ 1035 { 1036 SubnetClassSpec: SubnetClassSpec{ 1037 Role: SubnetControlPlane, 1038 CIDRBlocks: []string{DefaultControlPlaneSubnetCIDR}, 1039 Name: "cluster-test-controlplane-subnet", 1040 }, 1041 ID: "my-subnet-id", 1042 SecurityGroup: SecurityGroup{Name: "cluster-test-controlplane-nsg"}, 1043 RouteTable: RouteTable{}, 1044 }, 1045 { 1046 SubnetClassSpec: SubnetClassSpec{ 1047 Role: SubnetNode, 1048 CIDRBlocks: []string{DefaultNodeSubnetCIDR}, 1049 Name: "cluster-test-node-subnet", 1050 }, 1051 ID: "my-subnet-id-2", 1052 SecurityGroup: SecurityGroup{Name: "cluster-test-node-nsg"}, 1053 RouteTable: RouteTable{Name: "cluster-test-node-routetable"}, 1054 NatGateway: NatGateway{ 1055 NatGatewayClassSpec: NatGatewayClassSpec{ 1056 Name: "", 1057 }, 1058 NatGatewayIP: PublicIPSpec{ 1059 Name: "", 1060 }, 1061 }, 1062 }, 1063 }, 1064 }, 1065 }, 1066 }, 1067 }, 1068 } 1069 1070 for _, c := range cases { 1071 tc := c 1072 t.Run(tc.name, func(t *testing.T) { 1073 t.Parallel() 1074 tc.cluster.setSubnetDefaults() 1075 if !reflect.DeepEqual(tc.cluster, tc.output) { 1076 expected, _ := json.MarshalIndent(tc.output, "", "\t") 1077 actual, _ := json.MarshalIndent(tc.cluster, "", "\t") 1078 t.Errorf("Expected %s, got %s", string(expected), string(actual)) 1079 } 1080 }) 1081 } 1082 } 1083 1084 func TestVnetPeeringDefaults(t *testing.T) { 1085 cases := []struct { 1086 name string 1087 cluster *AzureCluster 1088 output *AzureCluster 1089 }{ 1090 { 1091 name: "no peering", 1092 cluster: &AzureCluster{ 1093 ObjectMeta: metav1.ObjectMeta{ 1094 Name: "cluster-test", 1095 }, 1096 Spec: AzureClusterSpec{ 1097 NetworkSpec: NetworkSpec{}, 1098 }, 1099 }, 1100 output: &AzureCluster{ 1101 ObjectMeta: metav1.ObjectMeta{ 1102 Name: "cluster-test", 1103 }, 1104 Spec: AzureClusterSpec{ 1105 NetworkSpec: NetworkSpec{}, 1106 }, 1107 }, 1108 }, 1109 { 1110 name: "peering with resource group", 1111 cluster: &AzureCluster{ 1112 ObjectMeta: metav1.ObjectMeta{ 1113 Name: "cluster-test", 1114 }, 1115 Spec: AzureClusterSpec{ 1116 ResourceGroup: "cluster-test", 1117 NetworkSpec: NetworkSpec{ 1118 Vnet: VnetSpec{ 1119 Peerings: VnetPeerings{ 1120 { 1121 VnetPeeringClassSpec: VnetPeeringClassSpec{ 1122 RemoteVnetName: "my-vnet", 1123 ResourceGroup: "cluster-test", 1124 }, 1125 }, 1126 }, 1127 }, 1128 }, 1129 }, 1130 }, 1131 output: &AzureCluster{ 1132 ObjectMeta: metav1.ObjectMeta{ 1133 Name: "cluster-test", 1134 }, 1135 Spec: AzureClusterSpec{ 1136 ResourceGroup: "cluster-test", 1137 NetworkSpec: NetworkSpec{ 1138 Vnet: VnetSpec{ 1139 Peerings: VnetPeerings{ 1140 { 1141 VnetPeeringClassSpec: VnetPeeringClassSpec{ 1142 RemoteVnetName: "my-vnet", 1143 ResourceGroup: "cluster-test", 1144 }, 1145 }, 1146 }, 1147 }, 1148 }, 1149 }, 1150 }, 1151 }, 1152 { 1153 name: "peering without resource group", 1154 cluster: &AzureCluster{ 1155 ObjectMeta: metav1.ObjectMeta{ 1156 Name: "cluster-test", 1157 }, 1158 Spec: AzureClusterSpec{ 1159 ResourceGroup: "cluster-test", 1160 NetworkSpec: NetworkSpec{ 1161 Vnet: VnetSpec{ 1162 Peerings: VnetPeerings{ 1163 { 1164 VnetPeeringClassSpec: VnetPeeringClassSpec{RemoteVnetName: "my-vnet"}, 1165 }, 1166 }, 1167 }, 1168 }, 1169 }, 1170 }, 1171 output: &AzureCluster{ 1172 ObjectMeta: metav1.ObjectMeta{ 1173 Name: "cluster-test", 1174 }, 1175 Spec: AzureClusterSpec{ 1176 ResourceGroup: "cluster-test", 1177 NetworkSpec: NetworkSpec{ 1178 Vnet: VnetSpec{ 1179 Peerings: VnetPeerings{ 1180 { 1181 VnetPeeringClassSpec: VnetPeeringClassSpec{ 1182 RemoteVnetName: "my-vnet", 1183 ResourceGroup: "cluster-test", 1184 }, 1185 }, 1186 }, 1187 }, 1188 }, 1189 }, 1190 }, 1191 }, 1192 } 1193 1194 for _, c := range cases { 1195 tc := c 1196 t.Run(tc.name, func(t *testing.T) { 1197 t.Parallel() 1198 tc.cluster.setVnetPeeringDefaults() 1199 if !reflect.DeepEqual(tc.cluster, tc.output) { 1200 expected, _ := json.MarshalIndent(tc.output, "", "\t") 1201 actual, _ := json.MarshalIndent(tc.cluster, "", "\t") 1202 t.Errorf("Expected %s, got %s", string(expected), string(actual)) 1203 } 1204 }) 1205 } 1206 } 1207 1208 func TestAPIServerLBDefaults(t *testing.T) { 1209 cases := []struct { 1210 name string 1211 cluster *AzureCluster 1212 output *AzureCluster 1213 }{ 1214 { 1215 name: "no lb", 1216 cluster: &AzureCluster{ 1217 ObjectMeta: metav1.ObjectMeta{ 1218 Name: "cluster-test", 1219 }, 1220 Spec: AzureClusterSpec{ 1221 NetworkSpec: NetworkSpec{}, 1222 }, 1223 }, 1224 output: &AzureCluster{ 1225 ObjectMeta: metav1.ObjectMeta{ 1226 Name: "cluster-test", 1227 }, 1228 Spec: AzureClusterSpec{ 1229 NetworkSpec: NetworkSpec{ 1230 APIServerLB: LoadBalancerSpec{ 1231 Name: "cluster-test-public-lb", 1232 FrontendIPs: []FrontendIP{ 1233 { 1234 Name: "cluster-test-public-lb-frontEnd", 1235 PublicIP: &PublicIPSpec{ 1236 Name: "pip-cluster-test-apiserver", 1237 DNSName: "", 1238 }, 1239 }, 1240 }, 1241 BackendPool: BackendPool{ 1242 Name: "cluster-test-public-lb-backendPool", 1243 }, 1244 LoadBalancerClassSpec: LoadBalancerClassSpec{ 1245 SKU: SKUStandard, 1246 Type: Public, 1247 IdleTimeoutInMinutes: ptr.To[int32](DefaultOutboundRuleIdleTimeoutInMinutes), 1248 }, 1249 }, 1250 }, 1251 }, 1252 }, 1253 }, 1254 { 1255 name: "internal lb", 1256 cluster: &AzureCluster{ 1257 ObjectMeta: metav1.ObjectMeta{ 1258 Name: "cluster-test", 1259 }, 1260 Spec: AzureClusterSpec{ 1261 NetworkSpec: NetworkSpec{ 1262 APIServerLB: LoadBalancerSpec{ 1263 LoadBalancerClassSpec: LoadBalancerClassSpec{ 1264 Type: Internal, 1265 }, 1266 }, 1267 }, 1268 }, 1269 }, 1270 output: &AzureCluster{ 1271 ObjectMeta: metav1.ObjectMeta{ 1272 Name: "cluster-test", 1273 }, 1274 Spec: AzureClusterSpec{ 1275 NetworkSpec: NetworkSpec{ 1276 APIServerLB: LoadBalancerSpec{ 1277 FrontendIPs: []FrontendIP{ 1278 { 1279 Name: "cluster-test-internal-lb-frontEnd", 1280 FrontendIPClass: FrontendIPClass{ 1281 PrivateIPAddress: DefaultInternalLBIPAddress, 1282 }, 1283 }, 1284 }, 1285 BackendPool: BackendPool{ 1286 Name: "cluster-test-internal-lb-backendPool", 1287 }, 1288 LoadBalancerClassSpec: LoadBalancerClassSpec{ 1289 SKU: SKUStandard, 1290 Type: Internal, 1291 IdleTimeoutInMinutes: ptr.To[int32](DefaultOutboundRuleIdleTimeoutInMinutes), 1292 }, 1293 Name: "cluster-test-internal-lb", 1294 }, 1295 }, 1296 }, 1297 }, 1298 }, 1299 { 1300 name: "with custom backend pool name", 1301 cluster: &AzureCluster{ 1302 ObjectMeta: metav1.ObjectMeta{ 1303 Name: "cluster-test", 1304 }, 1305 Spec: AzureClusterSpec{ 1306 NetworkSpec: NetworkSpec{ 1307 APIServerLB: LoadBalancerSpec{ 1308 LoadBalancerClassSpec: LoadBalancerClassSpec{ 1309 Type: Internal, 1310 }, 1311 BackendPool: BackendPool{ 1312 Name: "custom-backend-pool", 1313 }, 1314 }, 1315 }, 1316 }, 1317 }, 1318 output: &AzureCluster{ 1319 ObjectMeta: metav1.ObjectMeta{ 1320 Name: "cluster-test", 1321 }, 1322 Spec: AzureClusterSpec{ 1323 NetworkSpec: NetworkSpec{ 1324 APIServerLB: LoadBalancerSpec{ 1325 FrontendIPs: []FrontendIP{ 1326 { 1327 Name: "cluster-test-internal-lb-frontEnd", 1328 FrontendIPClass: FrontendIPClass{ 1329 PrivateIPAddress: DefaultInternalLBIPAddress, 1330 }, 1331 }, 1332 }, 1333 BackendPool: BackendPool{ 1334 Name: "custom-backend-pool", 1335 }, 1336 LoadBalancerClassSpec: LoadBalancerClassSpec{ 1337 SKU: SKUStandard, 1338 Type: Internal, 1339 IdleTimeoutInMinutes: ptr.To[int32](DefaultOutboundRuleIdleTimeoutInMinutes), 1340 }, 1341 Name: "cluster-test-internal-lb", 1342 }, 1343 }, 1344 }, 1345 }, 1346 }, 1347 } 1348 1349 for _, c := range cases { 1350 tc := c 1351 t.Run(tc.name, func(t *testing.T) { 1352 t.Parallel() 1353 tc.cluster.setAPIServerLBDefaults() 1354 if !reflect.DeepEqual(tc.cluster, tc.output) { 1355 expected, _ := json.MarshalIndent(tc.output, "", "\t") 1356 actual, _ := json.MarshalIndent(tc.cluster, "", "\t") 1357 t.Errorf("Expected %s, got %s", string(expected), string(actual)) 1358 } 1359 }) 1360 } 1361 } 1362 1363 func TestAzureEnviromentDefault(t *testing.T) { 1364 cases := map[string]struct { 1365 cluster *AzureCluster 1366 output *AzureCluster 1367 }{ 1368 "default empty azure env": { 1369 cluster: &AzureCluster{ 1370 ObjectMeta: metav1.ObjectMeta{ 1371 Name: "foo", 1372 }, 1373 Spec: AzureClusterSpec{}, 1374 }, 1375 output: &AzureCluster{ 1376 ObjectMeta: metav1.ObjectMeta{ 1377 Name: "foo", 1378 }, 1379 Spec: AzureClusterSpec{ 1380 AzureClusterClassSpec: AzureClusterClassSpec{ 1381 AzureEnvironment: DefaultAzureCloud, 1382 }, 1383 }, 1384 }, 1385 }, 1386 "azure env set to AzurePublicCloud": { 1387 cluster: &AzureCluster{ 1388 ObjectMeta: metav1.ObjectMeta{ 1389 Name: "foo", 1390 }, 1391 Spec: AzureClusterSpec{ 1392 AzureClusterClassSpec: AzureClusterClassSpec{ 1393 AzureEnvironment: DefaultAzureCloud, 1394 }, 1395 }, 1396 }, 1397 output: &AzureCluster{ 1398 ObjectMeta: metav1.ObjectMeta{ 1399 Name: "foo", 1400 }, 1401 Spec: AzureClusterSpec{ 1402 AzureClusterClassSpec: AzureClusterClassSpec{ 1403 AzureEnvironment: DefaultAzureCloud, 1404 }, 1405 }, 1406 }, 1407 }, 1408 "azure env set to AzureGermanCloud": { 1409 cluster: &AzureCluster{ 1410 ObjectMeta: metav1.ObjectMeta{ 1411 Name: "foo", 1412 }, 1413 Spec: AzureClusterSpec{ 1414 AzureClusterClassSpec: AzureClusterClassSpec{ 1415 AzureEnvironment: "AzureGermanCloud", 1416 }, 1417 }, 1418 }, 1419 output: &AzureCluster{ 1420 ObjectMeta: metav1.ObjectMeta{ 1421 Name: "foo", 1422 }, 1423 Spec: AzureClusterSpec{ 1424 AzureClusterClassSpec: AzureClusterClassSpec{ 1425 AzureEnvironment: "AzureGermanCloud", 1426 }, 1427 }, 1428 }, 1429 }, 1430 } 1431 1432 for name := range cases { 1433 c := cases[name] 1434 t.Run(name, func(t *testing.T) { 1435 t.Parallel() 1436 c.cluster.setAzureEnvironmentDefault() 1437 if !reflect.DeepEqual(c.cluster, c.output) { 1438 expected, _ := json.MarshalIndent(c.output, "", "\t") 1439 actual, _ := json.MarshalIndent(c.cluster, "", "\t") 1440 t.Errorf("Expected %s, got %s", string(expected), string(actual)) 1441 } 1442 }) 1443 } 1444 } 1445 1446 func TestNodeOutboundLBDefaults(t *testing.T) { 1447 cases := []struct { 1448 name string 1449 cluster *AzureCluster 1450 output *AzureCluster 1451 }{ 1452 { 1453 name: "default no lb for public clusters", 1454 cluster: &AzureCluster{ 1455 ObjectMeta: metav1.ObjectMeta{ 1456 Name: "cluster-test", 1457 }, 1458 Spec: AzureClusterSpec{ 1459 NetworkSpec: NetworkSpec{ 1460 APIServerLB: LoadBalancerSpec{LoadBalancerClassSpec: LoadBalancerClassSpec{Type: Public}}, 1461 Subnets: Subnets{ 1462 { 1463 SubnetClassSpec: SubnetClassSpec{ 1464 Role: SubnetControlPlane, 1465 Name: "control-plane-subnet", 1466 }, 1467 SecurityGroup: SecurityGroup{}, 1468 RouteTable: RouteTable{}, 1469 }, 1470 { 1471 SubnetClassSpec: SubnetClassSpec{ 1472 Role: SubnetNode, 1473 Name: "node-subnet", 1474 }, 1475 SecurityGroup: SecurityGroup{}, 1476 RouteTable: RouteTable{}, 1477 }, 1478 }, 1479 }, 1480 }, 1481 }, 1482 output: &AzureCluster{ 1483 ObjectMeta: metav1.ObjectMeta{ 1484 Name: "cluster-test", 1485 }, 1486 Spec: AzureClusterSpec{ 1487 NetworkSpec: NetworkSpec{ 1488 Subnets: Subnets{ 1489 { 1490 SubnetClassSpec: SubnetClassSpec{ 1491 Role: SubnetControlPlane, 1492 Name: "control-plane-subnet", 1493 }, 1494 SecurityGroup: SecurityGroup{}, 1495 RouteTable: RouteTable{}, 1496 }, 1497 { 1498 SubnetClassSpec: SubnetClassSpec{ 1499 Role: SubnetNode, 1500 Name: "node-subnet", 1501 }, 1502 SecurityGroup: SecurityGroup{}, 1503 RouteTable: RouteTable{}, 1504 }, 1505 }, 1506 APIServerLB: LoadBalancerSpec{ 1507 LoadBalancerClassSpec: LoadBalancerClassSpec{ 1508 Type: Public, 1509 }, 1510 }, 1511 }, 1512 }, 1513 }, 1514 }, 1515 { 1516 name: "IPv6 enabled", 1517 cluster: &AzureCluster{ 1518 ObjectMeta: metav1.ObjectMeta{ 1519 Name: "cluster-test", 1520 }, 1521 Spec: AzureClusterSpec{ 1522 NetworkSpec: NetworkSpec{ 1523 APIServerLB: LoadBalancerSpec{LoadBalancerClassSpec: LoadBalancerClassSpec{Type: Public}}, 1524 Subnets: Subnets{ 1525 { 1526 SubnetClassSpec: SubnetClassSpec{ 1527 Role: SubnetControlPlane, 1528 Name: "control-plane-subnet", 1529 }, 1530 SecurityGroup: SecurityGroup{}, 1531 RouteTable: RouteTable{}, 1532 }, 1533 { 1534 SubnetClassSpec: SubnetClassSpec{ 1535 Role: "node", 1536 CIDRBlocks: []string{"2001:beea::1/64"}, 1537 Name: "cluster-test-node-subnet", 1538 }, 1539 SecurityGroup: SecurityGroup{}, 1540 RouteTable: RouteTable{}, 1541 }, 1542 }, 1543 }, 1544 }, 1545 }, 1546 output: &AzureCluster{ 1547 ObjectMeta: metav1.ObjectMeta{ 1548 Name: "cluster-test", 1549 }, 1550 Spec: AzureClusterSpec{ 1551 NetworkSpec: NetworkSpec{ 1552 Subnets: Subnets{ 1553 { 1554 SubnetClassSpec: SubnetClassSpec{ 1555 Role: SubnetControlPlane, 1556 Name: "control-plane-subnet", 1557 }, 1558 SecurityGroup: SecurityGroup{}, 1559 RouteTable: RouteTable{}, 1560 }, 1561 { 1562 SubnetClassSpec: SubnetClassSpec{ 1563 Role: "node", 1564 CIDRBlocks: []string{"2001:beea::1/64"}, 1565 Name: "cluster-test-node-subnet", 1566 }, 1567 SecurityGroup: SecurityGroup{}, 1568 RouteTable: RouteTable{}, 1569 }, 1570 }, 1571 APIServerLB: LoadBalancerSpec{ 1572 LoadBalancerClassSpec: LoadBalancerClassSpec{ 1573 Type: Public, 1574 }, 1575 }, 1576 NodeOutboundLB: &LoadBalancerSpec{ 1577 Name: "cluster-test", 1578 FrontendIPs: []FrontendIP{{ 1579 Name: "cluster-test-frontEnd", 1580 PublicIP: &PublicIPSpec{ 1581 Name: "pip-cluster-test-node-outbound", 1582 }, 1583 }}, 1584 BackendPool: BackendPool{ 1585 Name: "cluster-test-outboundBackendPool", 1586 }, 1587 FrontendIPsCount: ptr.To[int32](1), 1588 LoadBalancerClassSpec: LoadBalancerClassSpec{ 1589 SKU: SKUStandard, 1590 Type: Public, 1591 IdleTimeoutInMinutes: ptr.To[int32](DefaultOutboundRuleIdleTimeoutInMinutes), 1592 }, 1593 }, 1594 }, 1595 }, 1596 }, 1597 }, 1598 { 1599 name: "IPv6 enabled on 1 of 2 node subnets", 1600 cluster: &AzureCluster{ 1601 ObjectMeta: metav1.ObjectMeta{ 1602 Name: "cluster-test", 1603 }, 1604 Spec: AzureClusterSpec{ 1605 NetworkSpec: NetworkSpec{ 1606 APIServerLB: LoadBalancerSpec{LoadBalancerClassSpec: LoadBalancerClassSpec{Type: Public}}, 1607 Subnets: Subnets{ 1608 { 1609 SubnetClassSpec: SubnetClassSpec{ 1610 Role: SubnetControlPlane, 1611 Name: "control-plane-subnet", 1612 }, 1613 SecurityGroup: SecurityGroup{}, 1614 RouteTable: RouteTable{}, 1615 }, 1616 { 1617 SubnetClassSpec: SubnetClassSpec{ 1618 Role: SubnetNode, 1619 CIDRBlocks: []string{"2001:beea::1/64"}, 1620 Name: "node-subnet-1", 1621 }, 1622 SecurityGroup: SecurityGroup{}, 1623 RouteTable: RouteTable{}, 1624 }, 1625 { 1626 SubnetClassSpec: SubnetClassSpec{ 1627 Role: SubnetNode, 1628 Name: "node-subnet-2", 1629 }, 1630 SecurityGroup: SecurityGroup{}, 1631 RouteTable: RouteTable{}, 1632 }, 1633 }, 1634 }, 1635 }, 1636 }, 1637 output: &AzureCluster{ 1638 ObjectMeta: metav1.ObjectMeta{ 1639 Name: "cluster-test", 1640 }, 1641 Spec: AzureClusterSpec{ 1642 NetworkSpec: NetworkSpec{ 1643 Subnets: Subnets{ 1644 { 1645 SubnetClassSpec: SubnetClassSpec{ 1646 Role: SubnetControlPlane, 1647 Name: "control-plane-subnet", 1648 }, 1649 SecurityGroup: SecurityGroup{}, 1650 RouteTable: RouteTable{}, 1651 }, 1652 { 1653 SubnetClassSpec: SubnetClassSpec{ 1654 Role: SubnetNode, 1655 CIDRBlocks: []string{"2001:beea::1/64"}, 1656 Name: "node-subnet-1", 1657 }, 1658 SecurityGroup: SecurityGroup{}, 1659 RouteTable: RouteTable{}, 1660 }, 1661 { 1662 SubnetClassSpec: SubnetClassSpec{ 1663 Role: SubnetNode, 1664 Name: "node-subnet-2", 1665 }, 1666 SecurityGroup: SecurityGroup{}, 1667 RouteTable: RouteTable{}, 1668 }, 1669 }, 1670 APIServerLB: LoadBalancerSpec{ 1671 LoadBalancerClassSpec: LoadBalancerClassSpec{ 1672 Type: Public, 1673 }, 1674 }, 1675 NodeOutboundLB: &LoadBalancerSpec{ 1676 Name: "cluster-test", 1677 FrontendIPs: []FrontendIP{{ 1678 Name: "cluster-test-frontEnd", 1679 PublicIP: &PublicIPSpec{ 1680 Name: "pip-cluster-test-node-outbound", 1681 }, 1682 }}, 1683 BackendPool: BackendPool{ 1684 Name: "cluster-test-outboundBackendPool", 1685 }, 1686 FrontendIPsCount: ptr.To[int32](1), 1687 LoadBalancerClassSpec: LoadBalancerClassSpec{ 1688 SKU: SKUStandard, 1689 Type: Public, 1690 IdleTimeoutInMinutes: ptr.To[int32](DefaultOutboundRuleIdleTimeoutInMinutes), 1691 }, 1692 }, 1693 }, 1694 }, 1695 }, 1696 }, 1697 { 1698 name: "multiple node subnets, IPv6 not enabled in any of them", 1699 cluster: &AzureCluster{ 1700 ObjectMeta: metav1.ObjectMeta{ 1701 Name: "cluster-test", 1702 }, 1703 Spec: AzureClusterSpec{ 1704 NetworkSpec: NetworkSpec{ 1705 APIServerLB: LoadBalancerSpec{LoadBalancerClassSpec: LoadBalancerClassSpec{Type: Public}}, 1706 Subnets: Subnets{ 1707 { 1708 SubnetClassSpec: SubnetClassSpec{ 1709 Role: SubnetControlPlane, 1710 Name: "control-plane-subnet", 1711 }, 1712 SecurityGroup: SecurityGroup{}, 1713 RouteTable: RouteTable{}, 1714 }, 1715 { 1716 SubnetClassSpec: SubnetClassSpec{ 1717 Role: SubnetNode, 1718 Name: "node-subnet", 1719 }, 1720 SecurityGroup: SecurityGroup{}, 1721 RouteTable: RouteTable{}, 1722 }, 1723 { 1724 SubnetClassSpec: SubnetClassSpec{ 1725 Role: SubnetNode, 1726 Name: "node-subnet-2", 1727 }, 1728 SecurityGroup: SecurityGroup{}, 1729 RouteTable: RouteTable{}, 1730 }, 1731 { 1732 SubnetClassSpec: SubnetClassSpec{ 1733 Role: SubnetNode, 1734 Name: "node-subnet-3", 1735 }, 1736 SecurityGroup: SecurityGroup{}, 1737 RouteTable: RouteTable{}, 1738 }, 1739 }, 1740 }, 1741 }, 1742 }, 1743 output: &AzureCluster{ 1744 ObjectMeta: metav1.ObjectMeta{ 1745 Name: "cluster-test", 1746 }, 1747 Spec: AzureClusterSpec{ 1748 NetworkSpec: NetworkSpec{ 1749 Subnets: Subnets{ 1750 { 1751 SubnetClassSpec: SubnetClassSpec{ 1752 Role: SubnetControlPlane, 1753 Name: "control-plane-subnet", 1754 }, 1755 SecurityGroup: SecurityGroup{}, 1756 RouteTable: RouteTable{}, 1757 }, 1758 { 1759 SubnetClassSpec: SubnetClassSpec{ 1760 Role: SubnetNode, 1761 Name: "node-subnet", 1762 }, 1763 SecurityGroup: SecurityGroup{}, 1764 RouteTable: RouteTable{}, 1765 }, 1766 { 1767 SubnetClassSpec: SubnetClassSpec{ 1768 Role: SubnetNode, 1769 Name: "node-subnet-2", 1770 }, 1771 SecurityGroup: SecurityGroup{}, 1772 RouteTable: RouteTable{}, 1773 }, 1774 { 1775 SubnetClassSpec: SubnetClassSpec{ 1776 Role: SubnetNode, 1777 Name: "node-subnet-3", 1778 }, 1779 SecurityGroup: SecurityGroup{}, 1780 RouteTable: RouteTable{}, 1781 }, 1782 }, 1783 APIServerLB: LoadBalancerSpec{ 1784 LoadBalancerClassSpec: LoadBalancerClassSpec{ 1785 Type: Public, 1786 }, 1787 }, 1788 }, 1789 }, 1790 }, 1791 }, 1792 { 1793 name: "multiple node subnets, IPv6 enabled on all of them", 1794 cluster: &AzureCluster{ 1795 ObjectMeta: metav1.ObjectMeta{ 1796 Name: "cluster-test", 1797 }, 1798 Spec: AzureClusterSpec{ 1799 NetworkSpec: NetworkSpec{ 1800 APIServerLB: LoadBalancerSpec{LoadBalancerClassSpec: LoadBalancerClassSpec{Type: Public}}, 1801 Subnets: Subnets{ 1802 { 1803 SubnetClassSpec: SubnetClassSpec{ 1804 Role: SubnetControlPlane, 1805 Name: "control-plane-subnet", 1806 }, 1807 SecurityGroup: SecurityGroup{}, 1808 RouteTable: RouteTable{}, 1809 }, 1810 { 1811 SubnetClassSpec: SubnetClassSpec{ 1812 Role: SubnetNode, 1813 CIDRBlocks: []string{"2001:beea::1/64"}, 1814 Name: "node-subnet-1", 1815 }, 1816 SecurityGroup: SecurityGroup{}, 1817 RouteTable: RouteTable{}, 1818 }, 1819 { 1820 SubnetClassSpec: SubnetClassSpec{ 1821 Role: SubnetNode, 1822 CIDRBlocks: []string{"2002:beee::1/64"}, 1823 Name: "node-subnet-2", 1824 }, 1825 SecurityGroup: SecurityGroup{}, 1826 RouteTable: RouteTable{}, 1827 }, 1828 { 1829 SubnetClassSpec: SubnetClassSpec{ 1830 Role: SubnetNode, 1831 CIDRBlocks: []string{"2003:befa::1/64"}, 1832 Name: "node-subnet-3", 1833 }, 1834 SecurityGroup: SecurityGroup{}, 1835 RouteTable: RouteTable{}, 1836 }, 1837 }, 1838 }, 1839 }, 1840 }, 1841 output: &AzureCluster{ 1842 ObjectMeta: metav1.ObjectMeta{ 1843 Name: "cluster-test", 1844 }, 1845 Spec: AzureClusterSpec{ 1846 NetworkSpec: NetworkSpec{ 1847 Subnets: Subnets{ 1848 { 1849 SubnetClassSpec: SubnetClassSpec{ 1850 Role: SubnetControlPlane, 1851 Name: "control-plane-subnet", 1852 }, 1853 SecurityGroup: SecurityGroup{}, 1854 RouteTable: RouteTable{}, 1855 }, 1856 { 1857 SubnetClassSpec: SubnetClassSpec{ 1858 Role: SubnetNode, 1859 CIDRBlocks: []string{"2001:beea::1/64"}, 1860 Name: "node-subnet-1", 1861 }, 1862 SecurityGroup: SecurityGroup{}, 1863 RouteTable: RouteTable{}, 1864 }, 1865 { 1866 SubnetClassSpec: SubnetClassSpec{ 1867 Role: SubnetNode, 1868 CIDRBlocks: []string{"2002:beee::1/64"}, 1869 Name: "node-subnet-2", 1870 }, 1871 SecurityGroup: SecurityGroup{}, 1872 RouteTable: RouteTable{}, 1873 }, 1874 { 1875 SubnetClassSpec: SubnetClassSpec{ 1876 Role: SubnetNode, 1877 CIDRBlocks: []string{"2003:befa::1/64"}, 1878 Name: "node-subnet-3", 1879 }, 1880 SecurityGroup: SecurityGroup{}, 1881 RouteTable: RouteTable{}, 1882 }, 1883 }, 1884 APIServerLB: LoadBalancerSpec{ 1885 LoadBalancerClassSpec: LoadBalancerClassSpec{ 1886 Type: Public, 1887 }, 1888 }, 1889 NodeOutboundLB: &LoadBalancerSpec{ 1890 Name: "cluster-test", 1891 FrontendIPs: []FrontendIP{{ 1892 Name: "cluster-test-frontEnd", 1893 PublicIP: &PublicIPSpec{ 1894 Name: "pip-cluster-test-node-outbound", 1895 }, 1896 }}, 1897 BackendPool: BackendPool{ 1898 Name: "cluster-test-outboundBackendPool", 1899 }, 1900 FrontendIPsCount: ptr.To[int32](1), 1901 LoadBalancerClassSpec: LoadBalancerClassSpec{ 1902 SKU: SKUStandard, 1903 Type: Public, 1904 IdleTimeoutInMinutes: ptr.To[int32](DefaultOutboundRuleIdleTimeoutInMinutes), 1905 }, 1906 }, 1907 }, 1908 }, 1909 }, 1910 }, 1911 { 1912 name: "no lb for private clusters", 1913 cluster: &AzureCluster{ 1914 ObjectMeta: metav1.ObjectMeta{ 1915 Name: "cluster-test", 1916 }, 1917 Spec: AzureClusterSpec{ 1918 NetworkSpec: NetworkSpec{ 1919 APIServerLB: LoadBalancerSpec{LoadBalancerClassSpec: LoadBalancerClassSpec{Type: Internal}}, 1920 }, 1921 }, 1922 }, 1923 output: &AzureCluster{ 1924 ObjectMeta: metav1.ObjectMeta{ 1925 Name: "cluster-test", 1926 }, 1927 Spec: AzureClusterSpec{ 1928 NetworkSpec: NetworkSpec{ 1929 APIServerLB: LoadBalancerSpec{ 1930 LoadBalancerClassSpec: LoadBalancerClassSpec{ 1931 Type: Internal, 1932 }, 1933 }, 1934 }, 1935 }, 1936 }, 1937 }, 1938 { 1939 name: "NodeOutboundLB declared as input with non-default IdleTimeoutInMinutes, FrontendIPsCount, BackendPool values", 1940 cluster: &AzureCluster{ 1941 ObjectMeta: metav1.ObjectMeta{ 1942 Name: "cluster-test", 1943 }, 1944 Spec: AzureClusterSpec{ 1945 NetworkSpec: NetworkSpec{ 1946 APIServerLB: LoadBalancerSpec{LoadBalancerClassSpec: LoadBalancerClassSpec{Type: Public}}, 1947 NodeOutboundLB: &LoadBalancerSpec{ 1948 FrontendIPsCount: ptr.To[int32](2), 1949 BackendPool: BackendPool{ 1950 Name: "custom-backend-pool", 1951 }, 1952 LoadBalancerClassSpec: LoadBalancerClassSpec{ 1953 IdleTimeoutInMinutes: ptr.To[int32](15), 1954 }, 1955 }, 1956 }, 1957 }, 1958 }, 1959 output: &AzureCluster{ 1960 ObjectMeta: metav1.ObjectMeta{ 1961 Name: "cluster-test", 1962 }, 1963 Spec: AzureClusterSpec{ 1964 NetworkSpec: NetworkSpec{ 1965 APIServerLB: LoadBalancerSpec{ 1966 LoadBalancerClassSpec: LoadBalancerClassSpec{ 1967 Type: Public, 1968 }, 1969 }, 1970 NodeOutboundLB: &LoadBalancerSpec{ 1971 FrontendIPs: []FrontendIP{ 1972 { 1973 Name: "cluster-test-frontEnd-1", 1974 PublicIP: &PublicIPSpec{ 1975 Name: "pip-cluster-test-node-outbound-1", 1976 }, 1977 }, 1978 { 1979 Name: "cluster-test-frontEnd-2", 1980 PublicIP: &PublicIPSpec{ 1981 Name: "pip-cluster-test-node-outbound-2", 1982 }, 1983 }, 1984 }, 1985 BackendPool: BackendPool{ 1986 Name: "custom-backend-pool", 1987 }, 1988 FrontendIPsCount: ptr.To[int32](2), // we expect the original value to be respected here 1989 LoadBalancerClassSpec: LoadBalancerClassSpec{ 1990 SKU: SKUStandard, 1991 Type: Public, 1992 IdleTimeoutInMinutes: ptr.To[int32](15), // we expect the original value to be respected here 1993 }, 1994 Name: "cluster-test", 1995 }, 1996 }, 1997 }, 1998 }, 1999 }, 2000 { 2001 name: "ensure that existing lb names are not overwritten", 2002 cluster: &AzureCluster{ 2003 ObjectMeta: metav1.ObjectMeta{ 2004 Name: "cluster-test", 2005 }, 2006 Spec: AzureClusterSpec{ 2007 NetworkSpec: NetworkSpec{ 2008 APIServerLB: LoadBalancerSpec{ 2009 Name: "user-defined-name", 2010 LoadBalancerClassSpec: LoadBalancerClassSpec{ 2011 Type: Public, 2012 }, 2013 }, 2014 Subnets: Subnets{ 2015 { 2016 SubnetClassSpec: SubnetClassSpec{ 2017 Role: SubnetControlPlane, 2018 Name: "control-plane-subnet", 2019 }, 2020 SecurityGroup: SecurityGroup{}, 2021 RouteTable: RouteTable{}, 2022 }, 2023 { 2024 SubnetClassSpec: SubnetClassSpec{ 2025 Role: SubnetNode, 2026 Name: "node-subnet", 2027 }, 2028 SecurityGroup: SecurityGroup{}, 2029 RouteTable: RouteTable{}, 2030 }, 2031 }, 2032 ControlPlaneOutboundLB: &LoadBalancerSpec{ 2033 Name: "user-defined-name", 2034 }, 2035 NodeOutboundLB: &LoadBalancerSpec{ 2036 Name: "user-defined-name", 2037 }, 2038 }, 2039 }, 2040 }, 2041 output: &AzureCluster{ 2042 ObjectMeta: metav1.ObjectMeta{ 2043 Name: "cluster-test", 2044 }, 2045 Spec: AzureClusterSpec{ 2046 NetworkSpec: NetworkSpec{ 2047 Subnets: Subnets{ 2048 { 2049 SubnetClassSpec: SubnetClassSpec{ 2050 Role: SubnetControlPlane, 2051 Name: "control-plane-subnet", 2052 }, 2053 SecurityGroup: SecurityGroup{}, 2054 RouteTable: RouteTable{}, 2055 }, 2056 { 2057 SubnetClassSpec: SubnetClassSpec{ 2058 Role: SubnetNode, 2059 Name: "node-subnet", 2060 }, 2061 SecurityGroup: SecurityGroup{}, 2062 RouteTable: RouteTable{}, 2063 }, 2064 }, 2065 APIServerLB: LoadBalancerSpec{ 2066 Name: "user-defined-name", 2067 LoadBalancerClassSpec: LoadBalancerClassSpec{ 2068 Type: Public, 2069 }, 2070 }, 2071 NodeOutboundLB: &LoadBalancerSpec{ 2072 Name: "user-defined-name", 2073 FrontendIPs: []FrontendIP{{ 2074 Name: "user-defined-name-frontEnd", 2075 PublicIP: &PublicIPSpec{ 2076 Name: "pip-cluster-test-node-outbound", 2077 }, 2078 }}, 2079 BackendPool: BackendPool{ 2080 Name: "user-defined-name-outboundBackendPool", 2081 }, 2082 FrontendIPsCount: ptr.To[int32](1), 2083 LoadBalancerClassSpec: LoadBalancerClassSpec{ 2084 SKU: SKUStandard, 2085 Type: Public, 2086 IdleTimeoutInMinutes: ptr.To[int32](DefaultOutboundRuleIdleTimeoutInMinutes), 2087 }, 2088 }, 2089 ControlPlaneOutboundLB: &LoadBalancerSpec{ 2090 Name: "user-defined-name", 2091 }, 2092 }, 2093 }, 2094 }, 2095 }, 2096 } 2097 2098 for _, c := range cases { 2099 tc := c 2100 t.Run(tc.name, func(t *testing.T) { 2101 t.Parallel() 2102 tc.cluster.SetNodeOutboundLBDefaults() 2103 if !reflect.DeepEqual(tc.cluster, tc.output) { 2104 expected, _ := json.MarshalIndent(tc.output, "", "\t") 2105 actual, _ := json.MarshalIndent(tc.cluster, "", "\t") 2106 t.Errorf("Expected %s, got %s", string(expected), string(actual)) 2107 } 2108 }) 2109 } 2110 } 2111 2112 func TestControlPlaneOutboundLBDefaults(t *testing.T) { 2113 cases := []struct { 2114 name string 2115 cluster *AzureCluster 2116 output *AzureCluster 2117 }{ 2118 { 2119 name: "no cp lb for public clusters", 2120 cluster: &AzureCluster{ 2121 ObjectMeta: metav1.ObjectMeta{ 2122 Name: "cluster-test", 2123 }, 2124 Spec: AzureClusterSpec{ 2125 NetworkSpec: NetworkSpec{ 2126 APIServerLB: LoadBalancerSpec{LoadBalancerClassSpec: LoadBalancerClassSpec{Type: Public}}, 2127 }, 2128 }, 2129 }, 2130 output: &AzureCluster{ 2131 ObjectMeta: metav1.ObjectMeta{ 2132 Name: "cluster-test", 2133 }, 2134 Spec: AzureClusterSpec{ 2135 NetworkSpec: NetworkSpec{ 2136 APIServerLB: LoadBalancerSpec{ 2137 LoadBalancerClassSpec: LoadBalancerClassSpec{ 2138 Type: Public, 2139 }, 2140 }, 2141 }, 2142 }, 2143 }, 2144 }, 2145 { 2146 name: "no cp lb for private clusters", 2147 cluster: &AzureCluster{ 2148 ObjectMeta: metav1.ObjectMeta{ 2149 Name: "cluster-test", 2150 }, 2151 Spec: AzureClusterSpec{ 2152 NetworkSpec: NetworkSpec{ 2153 APIServerLB: LoadBalancerSpec{LoadBalancerClassSpec: LoadBalancerClassSpec{Type: Internal}}, 2154 }, 2155 }, 2156 }, 2157 output: &AzureCluster{ 2158 ObjectMeta: metav1.ObjectMeta{ 2159 Name: "cluster-test", 2160 }, 2161 Spec: AzureClusterSpec{ 2162 NetworkSpec: NetworkSpec{ 2163 APIServerLB: LoadBalancerSpec{ 2164 LoadBalancerClassSpec: LoadBalancerClassSpec{ 2165 Type: Internal, 2166 }, 2167 }, 2168 }, 2169 }, 2170 }, 2171 }, 2172 { 2173 name: "frontendIPsCount > 1", 2174 cluster: &AzureCluster{ 2175 ObjectMeta: metav1.ObjectMeta{ 2176 Name: "cluster-test", 2177 }, 2178 Spec: AzureClusterSpec{ 2179 NetworkSpec: NetworkSpec{ 2180 APIServerLB: LoadBalancerSpec{LoadBalancerClassSpec: LoadBalancerClassSpec{Type: Internal}}, 2181 ControlPlaneOutboundLB: &LoadBalancerSpec{ 2182 FrontendIPsCount: ptr.To[int32](2), 2183 LoadBalancerClassSpec: LoadBalancerClassSpec{ 2184 IdleTimeoutInMinutes: ptr.To[int32](15), 2185 }, 2186 }, 2187 }, 2188 }, 2189 }, 2190 output: &AzureCluster{ 2191 ObjectMeta: metav1.ObjectMeta{ 2192 Name: "cluster-test", 2193 }, 2194 Spec: AzureClusterSpec{ 2195 NetworkSpec: NetworkSpec{ 2196 APIServerLB: LoadBalancerSpec{ 2197 LoadBalancerClassSpec: LoadBalancerClassSpec{ 2198 Type: Internal, 2199 }, 2200 }, 2201 ControlPlaneOutboundLB: &LoadBalancerSpec{ 2202 Name: "cluster-test-outbound-lb", 2203 BackendPool: BackendPool{ 2204 Name: "cluster-test-outbound-lb-outboundBackendPool", 2205 }, 2206 FrontendIPs: []FrontendIP{ 2207 { 2208 Name: "cluster-test-outbound-lb-frontEnd-1", 2209 PublicIP: &PublicIPSpec{ 2210 Name: "pip-cluster-test-controlplane-outbound-1", 2211 }, 2212 }, 2213 { 2214 Name: "cluster-test-outbound-lb-frontEnd-2", 2215 PublicIP: &PublicIPSpec{ 2216 Name: "pip-cluster-test-controlplane-outbound-2", 2217 }, 2218 }, 2219 }, 2220 FrontendIPsCount: ptr.To[int32](2), 2221 LoadBalancerClassSpec: LoadBalancerClassSpec{ 2222 SKU: SKUStandard, 2223 Type: Public, 2224 IdleTimeoutInMinutes: ptr.To[int32](15), 2225 }, 2226 }, 2227 }, 2228 }, 2229 }, 2230 }, 2231 { 2232 name: "custom outbound lb backend pool", 2233 cluster: &AzureCluster{ 2234 ObjectMeta: metav1.ObjectMeta{ 2235 Name: "cluster-test", 2236 }, 2237 Spec: AzureClusterSpec{ 2238 NetworkSpec: NetworkSpec{ 2239 APIServerLB: LoadBalancerSpec{LoadBalancerClassSpec: LoadBalancerClassSpec{Type: Internal}}, 2240 ControlPlaneOutboundLB: &LoadBalancerSpec{ 2241 BackendPool: BackendPool{ 2242 Name: "custom-outbound-lb", 2243 }, 2244 LoadBalancerClassSpec: LoadBalancerClassSpec{ 2245 IdleTimeoutInMinutes: ptr.To[int32](15), 2246 }, 2247 }, 2248 }, 2249 }, 2250 }, 2251 output: &AzureCluster{ 2252 ObjectMeta: metav1.ObjectMeta{ 2253 Name: "cluster-test", 2254 }, 2255 Spec: AzureClusterSpec{ 2256 NetworkSpec: NetworkSpec{ 2257 APIServerLB: LoadBalancerSpec{ 2258 LoadBalancerClassSpec: LoadBalancerClassSpec{ 2259 Type: Internal, 2260 }, 2261 }, 2262 ControlPlaneOutboundLB: &LoadBalancerSpec{ 2263 Name: "cluster-test-outbound-lb", 2264 BackendPool: BackendPool{ 2265 Name: "custom-outbound-lb", 2266 }, 2267 FrontendIPs: []FrontendIP{ 2268 { 2269 Name: "cluster-test-outbound-lb-frontEnd", 2270 PublicIP: &PublicIPSpec{ 2271 Name: "pip-cluster-test-controlplane-outbound", 2272 }, 2273 }, 2274 }, 2275 FrontendIPsCount: ptr.To[int32](1), 2276 LoadBalancerClassSpec: LoadBalancerClassSpec{ 2277 SKU: SKUStandard, 2278 Type: Public, 2279 IdleTimeoutInMinutes: ptr.To[int32](15), 2280 }, 2281 }, 2282 }, 2283 }, 2284 }, 2285 }, 2286 } 2287 2288 for _, c := range cases { 2289 tc := c 2290 t.Run(tc.name, func(t *testing.T) { 2291 t.Parallel() 2292 tc.cluster.SetControlPlaneOutboundLBDefaults() 2293 if !reflect.DeepEqual(tc.cluster, tc.output) { 2294 expected, _ := json.MarshalIndent(tc.output, "", "\t") 2295 actual, _ := json.MarshalIndent(tc.cluster, "", "\t") 2296 t.Errorf("Expected %s, got %s", string(expected), string(actual)) 2297 } 2298 }) 2299 } 2300 } 2301 2302 func TestBastionDefault(t *testing.T) { 2303 cases := map[string]struct { 2304 cluster *AzureCluster 2305 output *AzureCluster 2306 }{ 2307 "no bastion set": { 2308 cluster: &AzureCluster{ 2309 ObjectMeta: metav1.ObjectMeta{ 2310 Name: "foo", 2311 }, 2312 Spec: AzureClusterSpec{}, 2313 }, 2314 output: &AzureCluster{ 2315 ObjectMeta: metav1.ObjectMeta{ 2316 Name: "foo", 2317 }, 2318 Spec: AzureClusterSpec{}, 2319 }, 2320 }, 2321 "azure bastion enabled with no settings": { 2322 cluster: &AzureCluster{ 2323 ObjectMeta: metav1.ObjectMeta{ 2324 Name: "foo", 2325 }, 2326 Spec: AzureClusterSpec{ 2327 BastionSpec: BastionSpec{ 2328 AzureBastion: &AzureBastion{}, 2329 }, 2330 }, 2331 }, 2332 output: &AzureCluster{ 2333 ObjectMeta: metav1.ObjectMeta{ 2334 Name: "foo", 2335 }, 2336 Spec: AzureClusterSpec{ 2337 BastionSpec: BastionSpec{ 2338 AzureBastion: &AzureBastion{ 2339 Name: "foo-azure-bastion", 2340 Subnet: SubnetSpec{ 2341 2342 SubnetClassSpec: SubnetClassSpec{ 2343 CIDRBlocks: []string{DefaultAzureBastionSubnetCIDR}, 2344 Role: DefaultAzureBastionSubnetRole, 2345 Name: "AzureBastionSubnet", 2346 }, 2347 }, 2348 PublicIP: PublicIPSpec{ 2349 Name: "foo-azure-bastion-pip", 2350 }, 2351 }, 2352 }, 2353 }, 2354 }, 2355 }, 2356 "azure bastion enabled with name set": { 2357 cluster: &AzureCluster{ 2358 ObjectMeta: metav1.ObjectMeta{ 2359 Name: "foo", 2360 }, 2361 Spec: AzureClusterSpec{ 2362 BastionSpec: BastionSpec{ 2363 AzureBastion: &AzureBastion{ 2364 Name: "my-fancy-name", 2365 }, 2366 }, 2367 }, 2368 }, 2369 output: &AzureCluster{ 2370 ObjectMeta: metav1.ObjectMeta{ 2371 Name: "foo", 2372 }, 2373 Spec: AzureClusterSpec{ 2374 BastionSpec: BastionSpec{ 2375 AzureBastion: &AzureBastion{ 2376 Name: "my-fancy-name", 2377 Subnet: SubnetSpec{ 2378 2379 SubnetClassSpec: SubnetClassSpec{ 2380 CIDRBlocks: []string{DefaultAzureBastionSubnetCIDR}, 2381 Role: DefaultAzureBastionSubnetRole, 2382 Name: "AzureBastionSubnet", 2383 }, 2384 }, 2385 PublicIP: PublicIPSpec{ 2386 Name: "foo-azure-bastion-pip", 2387 }, 2388 }, 2389 }, 2390 }, 2391 }, 2392 }, 2393 "azure bastion enabled with subnet partially set": { 2394 cluster: &AzureCluster{ 2395 ObjectMeta: metav1.ObjectMeta{ 2396 Name: "foo", 2397 }, 2398 Spec: AzureClusterSpec{ 2399 BastionSpec: BastionSpec{ 2400 AzureBastion: &AzureBastion{ 2401 Subnet: SubnetSpec{}, 2402 }, 2403 }, 2404 }, 2405 }, 2406 output: &AzureCluster{ 2407 ObjectMeta: metav1.ObjectMeta{ 2408 Name: "foo", 2409 }, 2410 Spec: AzureClusterSpec{ 2411 BastionSpec: BastionSpec{ 2412 AzureBastion: &AzureBastion{ 2413 Name: "foo-azure-bastion", 2414 Subnet: SubnetSpec{ 2415 SubnetClassSpec: SubnetClassSpec{ 2416 CIDRBlocks: []string{DefaultAzureBastionSubnetCIDR}, 2417 Role: DefaultAzureBastionSubnetRole, 2418 Name: "AzureBastionSubnet", 2419 }, 2420 }, 2421 PublicIP: PublicIPSpec{ 2422 Name: "foo-azure-bastion-pip", 2423 }, 2424 }, 2425 }, 2426 }, 2427 }, 2428 }, 2429 "azure bastion enabled with subnet fully set": { 2430 cluster: &AzureCluster{ 2431 ObjectMeta: metav1.ObjectMeta{ 2432 Name: "foo", 2433 }, 2434 Spec: AzureClusterSpec{ 2435 BastionSpec: BastionSpec{ 2436 AzureBastion: &AzureBastion{ 2437 Subnet: SubnetSpec{ 2438 SubnetClassSpec: SubnetClassSpec{ 2439 CIDRBlocks: []string{"10.10.0.0/16"}, 2440 Name: "my-superfancy-name", 2441 }, 2442 }, 2443 }, 2444 }, 2445 }, 2446 }, 2447 output: &AzureCluster{ 2448 ObjectMeta: metav1.ObjectMeta{ 2449 Name: "foo", 2450 }, 2451 Spec: AzureClusterSpec{ 2452 BastionSpec: BastionSpec{ 2453 AzureBastion: &AzureBastion{ 2454 Name: "foo-azure-bastion", 2455 Subnet: SubnetSpec{ 2456 SubnetClassSpec: SubnetClassSpec{ 2457 CIDRBlocks: []string{"10.10.0.0/16"}, 2458 Role: DefaultAzureBastionSubnetRole, 2459 Name: "my-superfancy-name", 2460 }, 2461 }, 2462 PublicIP: PublicIPSpec{ 2463 Name: "foo-azure-bastion-pip", 2464 }, 2465 }, 2466 }, 2467 }, 2468 }, 2469 }, 2470 "azure bastion enabled with public IP name set": { 2471 cluster: &AzureCluster{ 2472 ObjectMeta: metav1.ObjectMeta{ 2473 Name: "foo", 2474 }, 2475 Spec: AzureClusterSpec{ 2476 BastionSpec: BastionSpec{ 2477 AzureBastion: &AzureBastion{ 2478 PublicIP: PublicIPSpec{ 2479 Name: "my-ultrafancy-pip-name", 2480 }, 2481 }, 2482 }, 2483 }, 2484 }, 2485 output: &AzureCluster{ 2486 ObjectMeta: metav1.ObjectMeta{ 2487 Name: "foo", 2488 }, 2489 Spec: AzureClusterSpec{ 2490 BastionSpec: BastionSpec{ 2491 AzureBastion: &AzureBastion{ 2492 Name: "foo-azure-bastion", 2493 Subnet: SubnetSpec{ 2494 SubnetClassSpec: SubnetClassSpec{ 2495 CIDRBlocks: []string{DefaultAzureBastionSubnetCIDR}, 2496 Role: DefaultAzureBastionSubnetRole, 2497 Name: "AzureBastionSubnet", 2498 }, 2499 }, 2500 PublicIP: PublicIPSpec{ 2501 Name: "my-ultrafancy-pip-name", 2502 }, 2503 }, 2504 }, 2505 }, 2506 }, 2507 }, 2508 } 2509 2510 for name := range cases { 2511 c := cases[name] 2512 t.Run(name, func(t *testing.T) { 2513 t.Parallel() 2514 c.cluster.setBastionDefaults() 2515 if !reflect.DeepEqual(c.cluster, c.output) { 2516 expected, _ := json.MarshalIndent(c.output, "", "\t") 2517 actual, _ := json.MarshalIndent(c.cluster, "", "\t") 2518 t.Errorf("Expected %s, got %s", string(expected), string(actual)) 2519 } 2520 }) 2521 } 2522 }