sigs.k8s.io/cluster-api-provider-azure@v1.17.0/azure/scope/cluster_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 scope 18 19 import ( 20 "context" 21 "fmt" 22 "reflect" 23 "strings" 24 "testing" 25 26 asonetworkv1api20201101 "github.com/Azure/azure-service-operator/v2/api/network/v1api20201101" 27 asonetworkv1api20220701 "github.com/Azure/azure-service-operator/v2/api/network/v1api20220701" 28 asoresourcesv1 "github.com/Azure/azure-service-operator/v2/api/resources/v1api20200601" 29 "github.com/Azure/go-autorest/autorest/azure/auth" 30 "github.com/google/go-cmp/cmp" 31 . "github.com/onsi/gomega" 32 corev1 "k8s.io/api/core/v1" 33 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 34 "k8s.io/apimachinery/pkg/runtime" 35 "k8s.io/utils/ptr" 36 infrav1 "sigs.k8s.io/cluster-api-provider-azure/api/v1beta1" 37 "sigs.k8s.io/cluster-api-provider-azure/azure" 38 "sigs.k8s.io/cluster-api-provider-azure/azure/services/bastionhosts" 39 "sigs.k8s.io/cluster-api-provider-azure/azure/services/groups" 40 "sigs.k8s.io/cluster-api-provider-azure/azure/services/loadbalancers" 41 "sigs.k8s.io/cluster-api-provider-azure/azure/services/natgateways" 42 "sigs.k8s.io/cluster-api-provider-azure/azure/services/privateendpoints" 43 "sigs.k8s.io/cluster-api-provider-azure/azure/services/publicips" 44 "sigs.k8s.io/cluster-api-provider-azure/azure/services/routetables" 45 "sigs.k8s.io/cluster-api-provider-azure/azure/services/securitygroups" 46 "sigs.k8s.io/cluster-api-provider-azure/azure/services/subnets" 47 "sigs.k8s.io/cluster-api-provider-azure/azure/services/vnetpeerings" 48 clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" 49 "sigs.k8s.io/controller-runtime/pkg/client/fake" 50 ) 51 52 const fakeClientID = "fake-client-id" 53 const fakeTenantID = "fake-tenant-id" 54 55 func specToString(spec any) string { 56 var sb strings.Builder 57 sb.WriteString("{ ") 58 sb.WriteString(fmt.Sprintf("%+v ", spec)) 59 sb.WriteString("}") 60 return sb.String() 61 } 62 63 func specArrayToString[T any](specs []T) string { 64 var sb strings.Builder 65 sb.WriteString("[\n") 66 for _, spec := range specs { 67 sb.WriteString(fmt.Sprintf("\t%+v\n", specToString(spec))) 68 } 69 sb.WriteString("]") 70 71 return sb.String() 72 } 73 74 func TestAPIServerHost(t *testing.T) { 75 fakeSubscriptionID := "123" 76 77 tests := []struct { 78 name string 79 azureCluster infrav1.AzureCluster 80 want string 81 }{ 82 { 83 name: "public apiserver lb (user-defined dns)", 84 azureCluster: infrav1.AzureCluster{ 85 Spec: infrav1.AzureClusterSpec{ 86 AzureClusterClassSpec: infrav1.AzureClusterClassSpec{ 87 SubscriptionID: fakeSubscriptionID, 88 IdentityRef: &corev1.ObjectReference{ 89 Kind: infrav1.AzureClusterIdentityKind, 90 }, 91 }, 92 NetworkSpec: infrav1.NetworkSpec{ 93 APIServerLB: infrav1.LoadBalancerSpec{ 94 FrontendIPs: []infrav1.FrontendIP{ 95 { 96 PublicIP: &infrav1.PublicIPSpec{ 97 DNSName: "my-cluster-apiserver.example.com", 98 }, 99 }, 100 }, 101 LoadBalancerClassSpec: infrav1.LoadBalancerClassSpec{ 102 Type: infrav1.Public, 103 }, 104 }, 105 }, 106 }, 107 }, 108 want: "my-cluster-apiserver.example.com", 109 }, 110 { 111 name: "private apiserver lb (default private dns zone)", 112 azureCluster: infrav1.AzureCluster{ 113 Spec: infrav1.AzureClusterSpec{ 114 AzureClusterClassSpec: infrav1.AzureClusterClassSpec{ 115 SubscriptionID: fakeSubscriptionID, 116 IdentityRef: &corev1.ObjectReference{ 117 Kind: infrav1.AzureClusterIdentityKind, 118 }, 119 }, 120 NetworkSpec: infrav1.NetworkSpec{ 121 APIServerLB: infrav1.LoadBalancerSpec{ 122 FrontendIPs: []infrav1.FrontendIP{ 123 { 124 PublicIP: &infrav1.PublicIPSpec{ 125 DNSName: "my-cluster-apiserver.capz.io", 126 }, 127 }, 128 }, 129 LoadBalancerClassSpec: infrav1.LoadBalancerClassSpec{ 130 Type: infrav1.Public, 131 }, 132 }, 133 }, 134 }, 135 }, 136 want: "my-cluster-apiserver.capz.io", 137 }, 138 { 139 name: "private apiserver (user-defined private dns zone)", 140 azureCluster: infrav1.AzureCluster{ 141 Spec: infrav1.AzureClusterSpec{ 142 AzureClusterClassSpec: infrav1.AzureClusterClassSpec{ 143 SubscriptionID: fakeSubscriptionID, 144 IdentityRef: &corev1.ObjectReference{ 145 Kind: infrav1.AzureClusterIdentityKind, 146 }, 147 }, 148 NetworkSpec: infrav1.NetworkSpec{ 149 NetworkClassSpec: infrav1.NetworkClassSpec{ 150 PrivateDNSZoneName: "example.private", 151 }, 152 APIServerLB: infrav1.LoadBalancerSpec{ 153 LoadBalancerClassSpec: infrav1.LoadBalancerClassSpec{ 154 Type: infrav1.Internal, 155 }, 156 }, 157 }, 158 }, 159 }, 160 want: "apiserver.example.private", 161 }, 162 } 163 164 for _, tc := range tests { 165 tc := tc 166 g := NewWithT(t) 167 scheme := runtime.NewScheme() 168 _ = clusterv1.AddToScheme(scheme) 169 _ = infrav1.AddToScheme(scheme) 170 _ = corev1.AddToScheme(scheme) 171 172 cluster := &clusterv1.Cluster{ 173 ObjectMeta: metav1.ObjectMeta{ 174 Name: "my-cluster", 175 Namespace: "default", 176 }, 177 } 178 179 tc.azureCluster.ObjectMeta = metav1.ObjectMeta{ 180 Name: cluster.Name, 181 OwnerReferences: []metav1.OwnerReference{ 182 { 183 APIVersion: "cluster.x-k8s.io/v1beta1", 184 Kind: "Cluster", 185 Name: "my-cluster", 186 }, 187 }, 188 } 189 tc.azureCluster.Default() 190 191 fakeIdentity := &infrav1.AzureClusterIdentity{ 192 Spec: infrav1.AzureClusterIdentitySpec{ 193 Type: infrav1.ServicePrincipal, 194 ClientID: fakeClientID, 195 TenantID: fakeTenantID, 196 }, 197 } 198 fakeSecret := &corev1.Secret{Data: map[string][]byte{"clientSecret": []byte("fooSecret")}} 199 200 initObjects := []runtime.Object{cluster, &tc.azureCluster, fakeIdentity, fakeSecret} 201 fakeClient := fake.NewClientBuilder().WithScheme(scheme).WithRuntimeObjects(initObjects...).Build() 202 203 clusterScope, err := NewClusterScope(context.TODO(), ClusterScopeParams{ 204 Cluster: cluster, 205 AzureCluster: &tc.azureCluster, 206 Client: fakeClient, 207 }) 208 g.Expect(err).NotTo(HaveOccurred()) 209 210 g.Expect(clusterScope.APIServerHost()).Should(Equal(tc.want)) 211 } 212 } 213 214 func TestGettingSecurityRules(t *testing.T) { 215 g := NewWithT(t) 216 scheme := runtime.NewScheme() 217 _ = clusterv1.AddToScheme(scheme) 218 _ = infrav1.AddToScheme(scheme) 219 _ = corev1.AddToScheme(scheme) 220 221 cluster := &clusterv1.Cluster{ 222 ObjectMeta: metav1.ObjectMeta{ 223 Name: "my-cluster", 224 Namespace: "default", 225 }, 226 } 227 228 azureCluster := &infrav1.AzureCluster{ 229 ObjectMeta: metav1.ObjectMeta{ 230 Name: "my-azure-cluster", 231 OwnerReferences: []metav1.OwnerReference{ 232 { 233 APIVersion: "cluster.x-k8s.io/v1beta1", 234 Kind: "Cluster", 235 Name: "my-cluster", 236 }, 237 }, 238 }, 239 Spec: infrav1.AzureClusterSpec{ 240 AzureClusterClassSpec: infrav1.AzureClusterClassSpec{ 241 SubscriptionID: "123", 242 IdentityRef: &corev1.ObjectReference{ 243 Kind: infrav1.AzureClusterIdentityKind, 244 }, 245 }, 246 NetworkSpec: infrav1.NetworkSpec{ 247 Subnets: infrav1.Subnets{ 248 { 249 SubnetClassSpec: infrav1.SubnetClassSpec{ 250 Role: infrav1.SubnetNode, 251 Name: "node", 252 }, 253 }, 254 }, 255 }, 256 }, 257 } 258 azureCluster.Default() 259 260 fakeIdentity := &infrav1.AzureClusterIdentity{ 261 Spec: infrav1.AzureClusterIdentitySpec{ 262 Type: infrav1.ServicePrincipal, 263 ClientID: fakeClientID, 264 TenantID: fakeTenantID, 265 }, 266 } 267 fakeSecret := &corev1.Secret{Data: map[string][]byte{"clientSecret": []byte("fooSecret")}} 268 269 initObjects := []runtime.Object{cluster, azureCluster, fakeIdentity, fakeSecret} 270 fakeClient := fake.NewClientBuilder().WithScheme(scheme).WithRuntimeObjects(initObjects...).Build() 271 272 clusterScope, err := NewClusterScope(context.TODO(), ClusterScopeParams{ 273 Cluster: cluster, 274 AzureCluster: azureCluster, 275 Client: fakeClient, 276 }) 277 g.Expect(err).NotTo(HaveOccurred()) 278 279 clusterScope.SetControlPlaneSecurityRules() 280 281 subnet, err := clusterScope.AzureCluster.Spec.NetworkSpec.GetControlPlaneSubnet() 282 g.Expect(err).NotTo(HaveOccurred()) 283 g.Expect(subnet.SecurityGroup.SecurityRules).To(HaveLen(2)) 284 } 285 286 func TestPublicIPSpecs(t *testing.T) { 287 tests := []struct { 288 name string 289 azureCluster *infrav1.AzureCluster 290 expectedPublicIPSpec []azure.ResourceSpecGetter 291 }{ 292 { 293 name: "Azure cluster with internal type LB and nil frontend IP count", 294 azureCluster: &infrav1.AzureCluster{ 295 ObjectMeta: metav1.ObjectMeta{ 296 Name: "my-cluster", 297 OwnerReferences: []metav1.OwnerReference{ 298 { 299 APIVersion: "cluster.x-k8s.io/v1beta1", 300 Kind: "Cluster", 301 Name: "my-cluster", 302 }, 303 }, 304 }, 305 Status: infrav1.AzureClusterStatus{ 306 FailureDomains: map[string]clusterv1.FailureDomainSpec{ 307 "failure-domain-id-1": {}, 308 "failure-domain-id-2": {}, 309 "failure-domain-id-3": {}, 310 }, 311 }, 312 Spec: infrav1.AzureClusterSpec{ 313 ResourceGroup: "my-rg", 314 AzureClusterClassSpec: infrav1.AzureClusterClassSpec{ 315 SubscriptionID: "123", 316 Location: "centralIndia", 317 AdditionalTags: infrav1.Tags{ 318 "Name": "my-publicip-ipv6", 319 "sigs.k8s.io_cluster-api-provider-azure_cluster_my-cluster": "owned", 320 }, 321 IdentityRef: &corev1.ObjectReference{ 322 Kind: infrav1.AzureClusterIdentityKind, 323 }, 324 }, 325 NetworkSpec: infrav1.NetworkSpec{ 326 APIServerLB: infrav1.LoadBalancerSpec{ 327 LoadBalancerClassSpec: infrav1.LoadBalancerClassSpec{ 328 Type: infrav1.Internal, 329 }, 330 }, 331 }, 332 }, 333 }, 334 expectedPublicIPSpec: nil, 335 }, 336 { 337 name: "Azure cluster with internal type LB and 0 frontend IP count", 338 azureCluster: &infrav1.AzureCluster{ 339 ObjectMeta: metav1.ObjectMeta{ 340 Name: "my-cluster", 341 OwnerReferences: []metav1.OwnerReference{ 342 { 343 APIVersion: "cluster.x-k8s.io/v1beta1", 344 Kind: "Cluster", 345 Name: "my-cluster", 346 }, 347 }, 348 }, 349 Status: infrav1.AzureClusterStatus{ 350 FailureDomains: map[string]clusterv1.FailureDomainSpec{ 351 "failure-domain-id-1": {}, 352 "failure-domain-id-2": {}, 353 "failure-domain-id-3": {}, 354 }, 355 }, 356 Spec: infrav1.AzureClusterSpec{ 357 ResourceGroup: "my-rg", 358 AzureClusterClassSpec: infrav1.AzureClusterClassSpec{ 359 SubscriptionID: "123", 360 Location: "centralIndia", 361 AdditionalTags: infrav1.Tags{ 362 "Name": "my-publicip-ipv6", 363 "sigs.k8s.io_cluster-api-provider-azure_cluster_my-cluster": "owned", 364 }, 365 IdentityRef: &corev1.ObjectReference{ 366 Kind: infrav1.AzureClusterIdentityKind, 367 }, 368 }, 369 NetworkSpec: infrav1.NetworkSpec{ 370 ControlPlaneOutboundLB: &infrav1.LoadBalancerSpec{ 371 FrontendIPsCount: ptr.To[int32](0), 372 }, 373 APIServerLB: infrav1.LoadBalancerSpec{ 374 LoadBalancerClassSpec: infrav1.LoadBalancerClassSpec{ 375 Type: infrav1.Internal, 376 }, 377 }, 378 }, 379 }, 380 }, 381 expectedPublicIPSpec: nil, 382 }, 383 { 384 name: "Azure cluster with internal type apiserver LB and 1 frontend IP count", 385 azureCluster: &infrav1.AzureCluster{ 386 ObjectMeta: metav1.ObjectMeta{ 387 Name: "my-cluster", 388 OwnerReferences: []metav1.OwnerReference{ 389 { 390 APIVersion: "cluster.x-k8s.io/v1beta1", 391 Kind: "Cluster", 392 Name: "my-cluster", 393 }, 394 }, 395 }, 396 Status: infrav1.AzureClusterStatus{ 397 FailureDomains: map[string]clusterv1.FailureDomainSpec{ 398 "failure-domain-id-1": {}, 399 "failure-domain-id-2": {}, 400 "failure-domain-id-3": {}, 401 }, 402 }, 403 Spec: infrav1.AzureClusterSpec{ 404 ResourceGroup: "my-rg", 405 AzureClusterClassSpec: infrav1.AzureClusterClassSpec{ 406 SubscriptionID: "123", 407 Location: "centralIndia", 408 AdditionalTags: infrav1.Tags{ 409 "Name": "my-publicip-ipv6", 410 "sigs.k8s.io_cluster-api-provider-azure_cluster_my-cluster": "owned", 411 }, 412 IdentityRef: &corev1.ObjectReference{ 413 Kind: infrav1.AzureClusterIdentityKind, 414 }, 415 }, 416 NetworkSpec: infrav1.NetworkSpec{ 417 ControlPlaneOutboundLB: &infrav1.LoadBalancerSpec{ 418 FrontendIPsCount: ptr.To[int32](1), 419 FrontendIPs: []infrav1.FrontendIP{ 420 { 421 Name: "my-frontend-ip", 422 PublicIP: &infrav1.PublicIPSpec{ 423 Name: "pip-my-cluster-controlplane-outbound", 424 }, 425 }, 426 }, 427 LoadBalancerClassSpec: infrav1.LoadBalancerClassSpec{}, 428 }, 429 APIServerLB: infrav1.LoadBalancerSpec{ 430 LoadBalancerClassSpec: infrav1.LoadBalancerClassSpec{ 431 Type: infrav1.Internal, 432 }, 433 }, 434 }, 435 }, 436 }, 437 expectedPublicIPSpec: []azure.ResourceSpecGetter{ 438 &publicips.PublicIPSpec{ 439 Name: "pip-my-cluster-controlplane-outbound", 440 ResourceGroup: "my-rg", 441 DNSName: "", 442 IsIPv6: false, 443 ClusterName: "my-cluster", 444 Location: "centralIndia", 445 FailureDomains: []*string{ptr.To("failure-domain-id-1"), ptr.To("failure-domain-id-2"), ptr.To("failure-domain-id-3")}, 446 AdditionalTags: infrav1.Tags{ 447 "Name": "my-publicip-ipv6", 448 "sigs.k8s.io_cluster-api-provider-azure_cluster_my-cluster": "owned", 449 }, 450 }, 451 }, 452 }, 453 { 454 name: "Azure cluster with internal type apiserver LB and many frontend IP count", 455 azureCluster: &infrav1.AzureCluster{ 456 ObjectMeta: metav1.ObjectMeta{ 457 Name: "my-cluster", 458 OwnerReferences: []metav1.OwnerReference{ 459 { 460 APIVersion: "cluster.x-k8s.io/v1beta1", 461 Kind: "Cluster", 462 Name: "my-cluster", 463 }, 464 }, 465 }, 466 Status: infrav1.AzureClusterStatus{ 467 FailureDomains: map[string]clusterv1.FailureDomainSpec{ 468 "failure-domain-id-1": {}, 469 "failure-domain-id-2": {}, 470 "failure-domain-id-3": {}, 471 }, 472 }, 473 Spec: infrav1.AzureClusterSpec{ 474 ResourceGroup: "my-rg", 475 AzureClusterClassSpec: infrav1.AzureClusterClassSpec{ 476 SubscriptionID: "123", 477 Location: "centralIndia", 478 AdditionalTags: infrav1.Tags{ 479 "Name": "my-publicip-ipv6", 480 "sigs.k8s.io_cluster-api-provider-azure_cluster_my-cluster": "owned", 481 }, 482 IdentityRef: &corev1.ObjectReference{ 483 Kind: infrav1.AzureClusterIdentityKind, 484 }, 485 }, 486 NetworkSpec: infrav1.NetworkSpec{ 487 ControlPlaneOutboundLB: &infrav1.LoadBalancerSpec{ 488 FrontendIPsCount: ptr.To[int32](3), 489 FrontendIPs: []infrav1.FrontendIP{ 490 { 491 Name: "my-frontend-ip-1", 492 PublicIP: &infrav1.PublicIPSpec{ 493 Name: "pip-my-cluster-controlplane-outbound-1", 494 }, 495 }, 496 { 497 Name: "my-frontend-ip-2", 498 PublicIP: &infrav1.PublicIPSpec{ 499 Name: "pip-my-cluster-controlplane-outbound-2", 500 }, 501 }, 502 { 503 Name: "my-frontend-ip-3", 504 PublicIP: &infrav1.PublicIPSpec{ 505 Name: "pip-my-cluster-controlplane-outbound-3", 506 }, 507 }, 508 }, 509 LoadBalancerClassSpec: infrav1.LoadBalancerClassSpec{}, 510 }, 511 APIServerLB: infrav1.LoadBalancerSpec{ 512 LoadBalancerClassSpec: infrav1.LoadBalancerClassSpec{ 513 Type: infrav1.Internal, 514 }, 515 }, 516 }, 517 }, 518 }, 519 expectedPublicIPSpec: []azure.ResourceSpecGetter{ 520 &publicips.PublicIPSpec{ 521 Name: "pip-my-cluster-controlplane-outbound-1", 522 ResourceGroup: "my-rg", 523 DNSName: "", 524 IsIPv6: false, 525 ClusterName: "my-cluster", 526 Location: "centralIndia", 527 FailureDomains: []*string{ptr.To("failure-domain-id-1"), ptr.To("failure-domain-id-2"), ptr.To("failure-domain-id-3")}, 528 AdditionalTags: infrav1.Tags{ 529 "Name": "my-publicip-ipv6", 530 "sigs.k8s.io_cluster-api-provider-azure_cluster_my-cluster": "owned", 531 }, 532 }, 533 &publicips.PublicIPSpec{ 534 Name: "pip-my-cluster-controlplane-outbound-2", 535 ResourceGroup: "my-rg", 536 DNSName: "", 537 IsIPv6: false, 538 ClusterName: "my-cluster", 539 Location: "centralIndia", 540 FailureDomains: []*string{ptr.To("failure-domain-id-1"), ptr.To("failure-domain-id-2"), ptr.To("failure-domain-id-3")}, 541 AdditionalTags: infrav1.Tags{ 542 "Name": "my-publicip-ipv6", 543 "sigs.k8s.io_cluster-api-provider-azure_cluster_my-cluster": "owned", 544 }, 545 }, 546 &publicips.PublicIPSpec{ 547 Name: "pip-my-cluster-controlplane-outbound-3", 548 ResourceGroup: "my-rg", 549 DNSName: "", 550 IsIPv6: false, 551 ClusterName: "my-cluster", 552 Location: "centralIndia", 553 FailureDomains: []*string{ptr.To("failure-domain-id-1"), ptr.To("failure-domain-id-2"), ptr.To("failure-domain-id-3")}, 554 AdditionalTags: infrav1.Tags{ 555 "Name": "my-publicip-ipv6", 556 "sigs.k8s.io_cluster-api-provider-azure_cluster_my-cluster": "owned", 557 }, 558 }, 559 }, 560 }, 561 { 562 name: "Azure cluster with public type apiserver LB", 563 azureCluster: &infrav1.AzureCluster{ 564 ObjectMeta: metav1.ObjectMeta{ 565 Name: "my-cluster", 566 OwnerReferences: []metav1.OwnerReference{ 567 { 568 APIVersion: "cluster.x-k8s.io/v1beta1", 569 Kind: "Cluster", 570 Name: "my-cluster", 571 }, 572 }, 573 }, 574 Status: infrav1.AzureClusterStatus{ 575 FailureDomains: map[string]clusterv1.FailureDomainSpec{ 576 "failure-domain-id-1": {}, 577 "failure-domain-id-2": {}, 578 "failure-domain-id-3": {}, 579 }, 580 }, 581 Spec: infrav1.AzureClusterSpec{ 582 ResourceGroup: "my-rg", 583 AzureClusterClassSpec: infrav1.AzureClusterClassSpec{ 584 SubscriptionID: "123", 585 Location: "centralIndia", 586 AdditionalTags: infrav1.Tags{ 587 "Name": "my-publicip-ipv6", 588 "sigs.k8s.io_cluster-api-provider-azure_cluster_my-cluster": "owned", 589 }, 590 IdentityRef: &corev1.ObjectReference{ 591 Kind: infrav1.AzureClusterIdentityKind, 592 }, 593 }, 594 NetworkSpec: infrav1.NetworkSpec{ 595 ControlPlaneOutboundLB: &infrav1.LoadBalancerSpec{ 596 LoadBalancerClassSpec: infrav1.LoadBalancerClassSpec{}, 597 }, 598 APIServerLB: infrav1.LoadBalancerSpec{ 599 LoadBalancerClassSpec: infrav1.LoadBalancerClassSpec{}, 600 FrontendIPs: []infrav1.FrontendIP{ 601 { 602 PublicIP: &infrav1.PublicIPSpec{ 603 Name: "40.60.89.22", 604 DNSName: "fake-dns", 605 }, 606 }, 607 }, 608 }, 609 }, 610 }, 611 }, 612 expectedPublicIPSpec: []azure.ResourceSpecGetter{ 613 &publicips.PublicIPSpec{ 614 Name: "40.60.89.22", 615 ResourceGroup: "my-rg", 616 DNSName: "fake-dns", 617 IsIPv6: false, 618 ClusterName: "my-cluster", 619 Location: "centralIndia", 620 FailureDomains: []*string{ptr.To("failure-domain-id-1"), ptr.To("failure-domain-id-2"), ptr.To("failure-domain-id-3")}, 621 AdditionalTags: infrav1.Tags{ 622 "Name": "my-publicip-ipv6", 623 "sigs.k8s.io_cluster-api-provider-azure_cluster_my-cluster": "owned", 624 }, 625 }, 626 }, 627 }, 628 { 629 name: "Azure cluster with public type apiserver LB and public node outbound lb", 630 azureCluster: &infrav1.AzureCluster{ 631 ObjectMeta: metav1.ObjectMeta{ 632 Name: "my-cluster", 633 OwnerReferences: []metav1.OwnerReference{ 634 { 635 APIVersion: "cluster.x-k8s.io/v1beta1", 636 Kind: "Cluster", 637 Name: "my-cluster", 638 }, 639 }, 640 }, 641 Status: infrav1.AzureClusterStatus{ 642 FailureDomains: map[string]clusterv1.FailureDomainSpec{ 643 "failure-domain-id-1": {}, 644 "failure-domain-id-2": {}, 645 "failure-domain-id-3": {}, 646 }, 647 }, 648 Spec: infrav1.AzureClusterSpec{ 649 ResourceGroup: "my-rg", 650 AzureClusterClassSpec: infrav1.AzureClusterClassSpec{ 651 SubscriptionID: "123", 652 Location: "centralIndia", 653 AdditionalTags: infrav1.Tags{ 654 "Name": "my-publicip-ipv6", 655 "sigs.k8s.io_cluster-api-provider-azure_cluster_my-cluster": "owned", 656 }, 657 IdentityRef: &corev1.ObjectReference{ 658 Kind: infrav1.AzureClusterIdentityKind, 659 }, 660 }, 661 NetworkSpec: infrav1.NetworkSpec{ 662 ControlPlaneOutboundLB: &infrav1.LoadBalancerSpec{ 663 LoadBalancerClassSpec: infrav1.LoadBalancerClassSpec{}, 664 }, 665 NodeOutboundLB: &infrav1.LoadBalancerSpec{ 666 LoadBalancerClassSpec: infrav1.LoadBalancerClassSpec{}, 667 }, 668 APIServerLB: infrav1.LoadBalancerSpec{ 669 FrontendIPs: []infrav1.FrontendIP{ 670 { 671 PublicIP: &infrav1.PublicIPSpec{ 672 Name: "40.60.89.22", 673 DNSName: "fake-dns", 674 }, 675 }, 676 }, 677 LoadBalancerClassSpec: infrav1.LoadBalancerClassSpec{}, 678 }, 679 }, 680 }, 681 }, 682 expectedPublicIPSpec: []azure.ResourceSpecGetter{ 683 &publicips.PublicIPSpec{ 684 Name: "40.60.89.22", 685 ResourceGroup: "my-rg", 686 DNSName: "fake-dns", 687 IsIPv6: false, 688 ClusterName: "my-cluster", 689 Location: "centralIndia", 690 FailureDomains: []*string{ptr.To("failure-domain-id-1"), ptr.To("failure-domain-id-2"), ptr.To("failure-domain-id-3")}, 691 AdditionalTags: infrav1.Tags{ 692 "Name": "my-publicip-ipv6", 693 "sigs.k8s.io_cluster-api-provider-azure_cluster_my-cluster": "owned", 694 }, 695 }, 696 }, 697 }, 698 { 699 name: "Azure cluster with public type apiserver LB and public node outbound lb, NAT gateways and bastions", 700 azureCluster: &infrav1.AzureCluster{ 701 ObjectMeta: metav1.ObjectMeta{ 702 Name: "my-cluster", 703 OwnerReferences: []metav1.OwnerReference{ 704 { 705 APIVersion: "cluster.x-k8s.io/v1beta1", 706 Kind: "Cluster", 707 Name: "my-cluster", 708 }, 709 }, 710 }, 711 Status: infrav1.AzureClusterStatus{ 712 FailureDomains: map[string]clusterv1.FailureDomainSpec{ 713 "failure-domain-id-1": {}, 714 "failure-domain-id-2": {}, 715 "failure-domain-id-3": {}, 716 }, 717 }, 718 Spec: infrav1.AzureClusterSpec{ 719 ResourceGroup: "my-rg", 720 BastionSpec: infrav1.BastionSpec{ 721 AzureBastion: &infrav1.AzureBastion{ 722 PublicIP: infrav1.PublicIPSpec{ 723 Name: "fake-bastion-public-ip", 724 DNSName: "fake-bastion-dns-name", 725 }, 726 }, 727 }, 728 AzureClusterClassSpec: infrav1.AzureClusterClassSpec{ 729 SubscriptionID: "123", 730 Location: "centralIndia", 731 AdditionalTags: infrav1.Tags{ 732 "Name": "my-publicip-ipv6", 733 "sigs.k8s.io_cluster-api-provider-azure_cluster_my-cluster": "owned", 734 }, 735 IdentityRef: &corev1.ObjectReference{ 736 Kind: infrav1.AzureClusterIdentityKind, 737 }, 738 }, 739 NetworkSpec: infrav1.NetworkSpec{ 740 Subnets: infrav1.Subnets{ 741 infrav1.SubnetSpec{ 742 SubnetClassSpec: infrav1.SubnetClassSpec{ 743 Role: infrav1.SubnetNode, 744 }, 745 NatGateway: infrav1.NatGateway{ 746 NatGatewayIP: infrav1.PublicIPSpec{ 747 Name: "fake-public-ip", 748 DNSName: "fake-dns-name", 749 }, 750 }, 751 }, 752 }, 753 ControlPlaneOutboundLB: &infrav1.LoadBalancerSpec{ 754 LoadBalancerClassSpec: infrav1.LoadBalancerClassSpec{}, 755 }, 756 NodeOutboundLB: &infrav1.LoadBalancerSpec{ 757 LoadBalancerClassSpec: infrav1.LoadBalancerClassSpec{}, 758 }, 759 APIServerLB: infrav1.LoadBalancerSpec{ 760 FrontendIPs: []infrav1.FrontendIP{ 761 { 762 PublicIP: &infrav1.PublicIPSpec{ 763 Name: "40.60.89.22", 764 DNSName: "fake-dns", 765 }, 766 }, 767 }, 768 LoadBalancerClassSpec: infrav1.LoadBalancerClassSpec{}, 769 }, 770 }, 771 }, 772 }, 773 expectedPublicIPSpec: []azure.ResourceSpecGetter{ 774 &publicips.PublicIPSpec{ 775 Name: "40.60.89.22", 776 ResourceGroup: "my-rg", 777 DNSName: "fake-dns", 778 IsIPv6: false, 779 ClusterName: "my-cluster", 780 Location: "centralIndia", 781 FailureDomains: []*string{ptr.To("failure-domain-id-1"), ptr.To("failure-domain-id-2"), ptr.To("failure-domain-id-3")}, 782 AdditionalTags: infrav1.Tags{ 783 "Name": "my-publicip-ipv6", 784 "sigs.k8s.io_cluster-api-provider-azure_cluster_my-cluster": "owned", 785 }, 786 }, 787 &publicips.PublicIPSpec{ 788 Name: "fake-bastion-public-ip", 789 ResourceGroup: "my-rg", 790 DNSName: "fake-bastion-dns-name", 791 IsIPv6: false, 792 ClusterName: "my-cluster", 793 Location: "centralIndia", 794 FailureDomains: []*string{ptr.To("failure-domain-id-1"), ptr.To("failure-domain-id-2"), ptr.To("failure-domain-id-3")}, 795 AdditionalTags: infrav1.Tags{ 796 "Name": "my-publicip-ipv6", 797 "sigs.k8s.io_cluster-api-provider-azure_cluster_my-cluster": "owned", 798 }, 799 }, 800 }, 801 }, 802 } 803 804 for _, tc := range tests { 805 t.Run(tc.name, func(t *testing.T) { 806 g := NewWithT(t) 807 scheme := runtime.NewScheme() 808 _ = infrav1.AddToScheme(scheme) 809 _ = clusterv1.AddToScheme(scheme) 810 _ = corev1.AddToScheme(scheme) 811 812 cluster := &clusterv1.Cluster{ 813 ObjectMeta: metav1.ObjectMeta{ 814 Name: tc.azureCluster.Name, 815 Namespace: "default", 816 }, 817 } 818 fakeIdentity := &infrav1.AzureClusterIdentity{ 819 Spec: infrav1.AzureClusterIdentitySpec{ 820 Type: infrav1.ServicePrincipal, 821 ClientID: fakeClientID, 822 TenantID: fakeTenantID, 823 }, 824 } 825 fakeSecret := &corev1.Secret{Data: map[string][]byte{"clientSecret": []byte("fooSecret")}} 826 827 initObjects := []runtime.Object{cluster, tc.azureCluster, fakeIdentity, fakeSecret} 828 fakeClient := fake.NewClientBuilder().WithScheme(scheme).WithRuntimeObjects(initObjects...).Build() 829 clusterScope, err := NewClusterScope(context.TODO(), ClusterScopeParams{ 830 Cluster: cluster, 831 AzureCluster: tc.azureCluster, 832 Client: fakeClient, 833 }) 834 g.Expect(err).NotTo(HaveOccurred()) 835 836 if got := clusterScope.PublicIPSpecs(); !reflect.DeepEqual(got, tc.expectedPublicIPSpec) { 837 t.Errorf("PublicIPSpecs() diff between expected result and actual result (%v): %s", got, cmp.Diff(tc.expectedPublicIPSpec, got)) 838 } 839 }) 840 } 841 } 842 843 func TestRouteTableSpecs(t *testing.T) { 844 tests := []struct { 845 name string 846 clusterScope ClusterScope 847 want []azure.ResourceSpecGetter 848 }{ 849 { 850 name: "returns nil if no subnets are specified", 851 clusterScope: ClusterScope{ 852 AzureCluster: &infrav1.AzureCluster{ 853 Spec: infrav1.AzureClusterSpec{ 854 NetworkSpec: infrav1.NetworkSpec{ 855 Subnets: infrav1.Subnets{}, 856 }, 857 }, 858 }, 859 cache: &ClusterCache{}, 860 }, 861 want: nil, 862 }, 863 { 864 name: "returns specified route tables if present", 865 clusterScope: ClusterScope{ 866 Cluster: &clusterv1.Cluster{ 867 ObjectMeta: metav1.ObjectMeta{ 868 Name: "my-cluster", 869 }, 870 }, 871 AzureCluster: &infrav1.AzureCluster{ 872 Spec: infrav1.AzureClusterSpec{ 873 AzureClusterClassSpec: infrav1.AzureClusterClassSpec{ 874 Location: "centralIndia", 875 IdentityRef: &corev1.ObjectReference{ 876 Kind: infrav1.AzureClusterIdentityKind, 877 }, 878 }, 879 NetworkSpec: infrav1.NetworkSpec{ 880 Vnet: infrav1.VnetSpec{ 881 ResourceGroup: "my-rg", 882 }, 883 Subnets: infrav1.Subnets{ 884 { 885 RouteTable: infrav1.RouteTable{ 886 ID: "fake-route-table-id-1", 887 Name: "fake-route-table-1", 888 }, 889 }, 890 { 891 RouteTable: infrav1.RouteTable{ 892 ID: "fake-route-table-id-2", 893 Name: "fake-route-table-2", 894 }, 895 }, 896 }, 897 }, 898 }, 899 }, 900 cache: &ClusterCache{}, 901 }, 902 want: []azure.ResourceSpecGetter{ 903 &routetables.RouteTableSpec{ 904 Name: "fake-route-table-1", 905 ResourceGroup: "my-rg", 906 Location: "centralIndia", 907 ClusterName: "my-cluster", 908 AdditionalTags: make(infrav1.Tags), 909 }, 910 &routetables.RouteTableSpec{ 911 Name: "fake-route-table-2", 912 ResourceGroup: "my-rg", 913 Location: "centralIndia", 914 ClusterName: "my-cluster", 915 AdditionalTags: make(infrav1.Tags), 916 }, 917 }, 918 }, 919 } 920 921 for _, tt := range tests { 922 tt := tt 923 t.Run(tt.name, func(t *testing.T) { 924 t.Parallel() 925 if got := tt.clusterScope.RouteTableSpecs(); !reflect.DeepEqual(got, tt.want) { 926 t.Errorf("RouteTableSpecs() = %s, want %s", specArrayToString(got), specArrayToString(tt.want)) 927 } 928 }) 929 } 930 } 931 932 func TestNatGatewaySpecs(t *testing.T) { 933 scheme := runtime.NewScheme() 934 _ = asonetworkv1api20201101.AddToScheme(scheme) 935 _ = corev1.AddToScheme(scheme) 936 _ = infrav1.AddToScheme(scheme) 937 938 tests := []struct { 939 name string 940 clusterScope ClusterScope 941 vnet asonetworkv1api20201101.VirtualNetwork 942 want []azure.ASOResourceSpecGetter[*asonetworkv1api20220701.NatGateway] 943 }{ 944 { 945 name: "returns nil if no subnets are specified", 946 clusterScope: ClusterScope{ 947 AzureCluster: &infrav1.AzureCluster{ 948 Spec: infrav1.AzureClusterSpec{ 949 NetworkSpec: infrav1.NetworkSpec{ 950 Subnets: infrav1.Subnets{}, 951 }, 952 }, 953 }, 954 cache: &ClusterCache{}, 955 }, 956 want: nil, 957 }, 958 { 959 name: "returns specified node NAT gateway if present", 960 clusterScope: ClusterScope{ 961 Cluster: &clusterv1.Cluster{ 962 ObjectMeta: metav1.ObjectMeta{ 963 Name: "my-cluster", 964 }, 965 }, 966 AzureClients: AzureClients{ 967 EnvironmentSettings: auth.EnvironmentSettings{ 968 Values: map[string]string{ 969 auth.SubscriptionID: "123", 970 }, 971 }, 972 }, 973 AzureCluster: &infrav1.AzureCluster{ 974 Spec: infrav1.AzureClusterSpec{ 975 ResourceGroup: "my-rg", 976 AzureClusterClassSpec: infrav1.AzureClusterClassSpec{ 977 Location: "centralIndia", 978 IdentityRef: &corev1.ObjectReference{ 979 Kind: infrav1.AzureClusterIdentityKind, 980 }, 981 }, 982 NetworkSpec: infrav1.NetworkSpec{ 983 Subnets: infrav1.Subnets{ 984 { 985 SubnetClassSpec: infrav1.SubnetClassSpec{ 986 Role: infrav1.SubnetNode, 987 }, 988 RouteTable: infrav1.RouteTable{ 989 ID: "fake-route-table-id-1", 990 Name: "fake-route-table-1", 991 }, 992 NatGateway: infrav1.NatGateway{ 993 NatGatewayIP: infrav1.PublicIPSpec{ 994 Name: "44.78.67.90", 995 }, 996 NatGatewayClassSpec: infrav1.NatGatewayClassSpec{ 997 Name: "fake-nat-gateway-1", 998 }, 999 }, 1000 }, 1001 }, 1002 Vnet: infrav1.VnetSpec{ 1003 Name: "fake-vnet-1", 1004 }, 1005 }, 1006 }, 1007 }, 1008 cache: &ClusterCache{}, 1009 }, 1010 vnet: asonetworkv1api20201101.VirtualNetwork{ 1011 ObjectMeta: metav1.ObjectMeta{ 1012 Name: "fake-vnet-1", 1013 }, 1014 Status: asonetworkv1api20201101.VirtualNetwork_STATUS{ 1015 Tags: map[string]string{ 1016 "sigs.k8s.io_cluster-api-provider-azure_cluster_my-cluster": "owned", 1017 }, 1018 }, 1019 }, 1020 want: []azure.ASOResourceSpecGetter[*asonetworkv1api20220701.NatGateway]{ 1021 &natgateways.NatGatewaySpec{ 1022 Name: "fake-nat-gateway-1", 1023 ResourceGroup: "my-rg", 1024 Location: "centralIndia", 1025 SubscriptionID: "123", 1026 ClusterName: "my-cluster", 1027 NatGatewayIP: infrav1.PublicIPSpec{ 1028 Name: "44.78.67.90", 1029 }, 1030 AdditionalTags: make(infrav1.Tags), 1031 IsVnetManaged: true, 1032 }, 1033 }, 1034 }, 1035 { 1036 name: "returns specified node NAT gateway if present and ignores duplicate", 1037 clusterScope: ClusterScope{ 1038 Cluster: &clusterv1.Cluster{ 1039 ObjectMeta: metav1.ObjectMeta{ 1040 Name: "my-cluster", 1041 }, 1042 }, 1043 AzureClients: AzureClients{ 1044 EnvironmentSettings: auth.EnvironmentSettings{ 1045 Values: map[string]string{ 1046 auth.SubscriptionID: "123", 1047 }, 1048 }, 1049 }, 1050 AzureCluster: &infrav1.AzureCluster{ 1051 Spec: infrav1.AzureClusterSpec{ 1052 ResourceGroup: "my-rg", 1053 AzureClusterClassSpec: infrav1.AzureClusterClassSpec{ 1054 Location: "centralIndia", 1055 IdentityRef: &corev1.ObjectReference{ 1056 Kind: infrav1.AzureClusterIdentityKind, 1057 }, 1058 }, 1059 NetworkSpec: infrav1.NetworkSpec{ 1060 Subnets: infrav1.Subnets{ 1061 { 1062 SubnetClassSpec: infrav1.SubnetClassSpec{ 1063 Role: infrav1.SubnetNode, 1064 }, 1065 RouteTable: infrav1.RouteTable{ 1066 ID: "fake-route-table-id-1", 1067 Name: "fake-route-table-1", 1068 }, 1069 NatGateway: infrav1.NatGateway{ 1070 NatGatewayIP: infrav1.PublicIPSpec{ 1071 Name: "44.78.67.90", 1072 }, 1073 NatGatewayClassSpec: infrav1.NatGatewayClassSpec{ 1074 Name: "fake-nat-gateway-1", 1075 }, 1076 }, 1077 }, 1078 // Duplicate Entry 1079 { 1080 SubnetClassSpec: infrav1.SubnetClassSpec{ 1081 Role: infrav1.SubnetNode, 1082 }, 1083 RouteTable: infrav1.RouteTable{ 1084 ID: "fake-route-table-id-1", 1085 Name: "fake-route-table-1", 1086 }, 1087 NatGateway: infrav1.NatGateway{ 1088 NatGatewayIP: infrav1.PublicIPSpec{ 1089 Name: "44.78.67.90", 1090 }, 1091 NatGatewayClassSpec: infrav1.NatGatewayClassSpec{ 1092 Name: "fake-nat-gateway-1", 1093 }, 1094 }, 1095 }, 1096 }, 1097 Vnet: infrav1.VnetSpec{ 1098 Name: "fake-vnet-1", 1099 }, 1100 }, 1101 }, 1102 }, 1103 cache: &ClusterCache{}, 1104 }, 1105 vnet: asonetworkv1api20201101.VirtualNetwork{ 1106 ObjectMeta: metav1.ObjectMeta{ 1107 Name: "fake-vnet-1", 1108 }, 1109 Status: asonetworkv1api20201101.VirtualNetwork_STATUS{ 1110 Tags: map[string]string{ 1111 "sigs.k8s.io_cluster-api-provider-azure_cluster_my-cluster": "owned", 1112 }, 1113 }, 1114 }, 1115 want: []azure.ASOResourceSpecGetter[*asonetworkv1api20220701.NatGateway]{ 1116 &natgateways.NatGatewaySpec{ 1117 Name: "fake-nat-gateway-1", 1118 ResourceGroup: "my-rg", 1119 Location: "centralIndia", 1120 SubscriptionID: "123", 1121 ClusterName: "my-cluster", 1122 NatGatewayIP: infrav1.PublicIPSpec{ 1123 Name: "44.78.67.90", 1124 }, 1125 AdditionalTags: make(infrav1.Tags), 1126 IsVnetManaged: true, 1127 }, 1128 }, 1129 }, 1130 { 1131 name: "returns specified node NAT gateway if present and ignores control plane nat gateway", 1132 clusterScope: ClusterScope{ 1133 Cluster: &clusterv1.Cluster{ 1134 ObjectMeta: metav1.ObjectMeta{ 1135 Name: "my-cluster", 1136 }, 1137 }, 1138 AzureClients: AzureClients{ 1139 EnvironmentSettings: auth.EnvironmentSettings{ 1140 Values: map[string]string{ 1141 auth.SubscriptionID: "123", 1142 }, 1143 }, 1144 }, 1145 AzureCluster: &infrav1.AzureCluster{ 1146 Spec: infrav1.AzureClusterSpec{ 1147 ResourceGroup: "my-rg", 1148 AzureClusterClassSpec: infrav1.AzureClusterClassSpec{ 1149 Location: "centralIndia", 1150 IdentityRef: &corev1.ObjectReference{ 1151 Kind: infrav1.AzureClusterIdentityKind, 1152 }, 1153 }, 1154 NetworkSpec: infrav1.NetworkSpec{ 1155 Subnets: infrav1.Subnets{ 1156 { 1157 SubnetClassSpec: infrav1.SubnetClassSpec{ 1158 Role: infrav1.SubnetNode, 1159 }, 1160 RouteTable: infrav1.RouteTable{ 1161 ID: "fake-route-table-id-1", 1162 Name: "fake-route-table-1", 1163 }, 1164 NatGateway: infrav1.NatGateway{ 1165 NatGatewayIP: infrav1.PublicIPSpec{ 1166 Name: "44.78.67.90", 1167 }, 1168 NatGatewayClassSpec: infrav1.NatGatewayClassSpec{ 1169 Name: "fake-nat-gateway-1", 1170 }, 1171 }, 1172 }, 1173 { 1174 SubnetClassSpec: infrav1.SubnetClassSpec{ 1175 Role: infrav1.SubnetControlPlane, 1176 }, 1177 RouteTable: infrav1.RouteTable{ 1178 ID: "fake-route-table-id-2", 1179 Name: "fake-route-table-2", 1180 }, 1181 NatGateway: infrav1.NatGateway{ 1182 NatGatewayIP: infrav1.PublicIPSpec{ 1183 Name: "44.78.67.91", 1184 }, 1185 NatGatewayClassSpec: infrav1.NatGatewayClassSpec{ 1186 Name: "fake-nat-gateway-2", 1187 }, 1188 }, 1189 }, 1190 }, 1191 Vnet: infrav1.VnetSpec{ 1192 Name: "fake-vnet-1", 1193 }, 1194 }, 1195 }, 1196 }, 1197 cache: &ClusterCache{}, 1198 }, 1199 vnet: asonetworkv1api20201101.VirtualNetwork{ 1200 ObjectMeta: metav1.ObjectMeta{ 1201 Name: "fake-vnet-1", 1202 }, 1203 Status: asonetworkv1api20201101.VirtualNetwork_STATUS{ 1204 Tags: map[string]string{ 1205 "sigs.k8s.io_cluster-api-provider-azure_cluster_my-cluster": "owned", 1206 }, 1207 }, 1208 }, 1209 want: []azure.ASOResourceSpecGetter[*asonetworkv1api20220701.NatGateway]{ 1210 &natgateways.NatGatewaySpec{ 1211 Name: "fake-nat-gateway-1", 1212 ResourceGroup: "my-rg", 1213 Location: "centralIndia", 1214 SubscriptionID: "123", 1215 ClusterName: "my-cluster", 1216 NatGatewayIP: infrav1.PublicIPSpec{ 1217 Name: "44.78.67.90", 1218 }, 1219 AdditionalTags: make(infrav1.Tags), 1220 IsVnetManaged: true, 1221 }, 1222 }, 1223 }, 1224 } 1225 1226 for _, tt := range tests { 1227 tt := tt 1228 t.Run(tt.name, func(t *testing.T) { 1229 t.Parallel() 1230 fakeIdentity := &infrav1.AzureClusterIdentity{ 1231 ObjectMeta: metav1.ObjectMeta{ 1232 Name: "fake-identity", 1233 Namespace: "default", 1234 }, 1235 Spec: infrav1.AzureClusterIdentitySpec{ 1236 Type: infrav1.ServicePrincipal, 1237 ClientID: fakeClientID, 1238 TenantID: fakeTenantID, 1239 }, 1240 } 1241 fakeSecret := &corev1.Secret{Data: map[string][]byte{"clientSecret": []byte("fooSecret")}} 1242 1243 initObjects := []runtime.Object{&tt.vnet, fakeIdentity, fakeSecret} 1244 fakeClient := fake.NewClientBuilder().WithScheme(scheme).WithRuntimeObjects(initObjects...).Build() 1245 tt.clusterScope.Client = fakeClient 1246 1247 if got := tt.clusterScope.NatGatewaySpecs(); !reflect.DeepEqual(got, tt.want) { 1248 t.Errorf("NatGatewaySpecs() = %s, want %s", specArrayToString(got), specArrayToString(tt.want)) 1249 } 1250 }) 1251 } 1252 } 1253 1254 func TestSetNatGatewayIDInSubnets(t *testing.T) { 1255 tests := []struct { 1256 name string 1257 clusterScope ClusterScope 1258 asoNatgateway *asonetworkv1api20220701.NatGateway 1259 }{ 1260 { 1261 name: "sets nat gateway id in the matching subnet", 1262 clusterScope: ClusterScope{ 1263 Cluster: &clusterv1.Cluster{ 1264 ObjectMeta: metav1.ObjectMeta{ 1265 Name: "my-cluster", 1266 }, 1267 }, 1268 AzureCluster: &infrav1.AzureCluster{ 1269 Spec: infrav1.AzureClusterSpec{ 1270 NetworkSpec: infrav1.NetworkSpec{ 1271 Subnets: infrav1.Subnets{ 1272 { 1273 SubnetClassSpec: infrav1.SubnetClassSpec{ 1274 Name: "fake-subnet-1", 1275 }, 1276 NatGateway: infrav1.NatGateway{ 1277 NatGatewayClassSpec: infrav1.NatGatewayClassSpec{ 1278 Name: "fake-nat-gateway-1", 1279 }, 1280 }, 1281 }, 1282 { 1283 SubnetClassSpec: infrav1.SubnetClassSpec{ 1284 Name: "fake-subnet-2", 1285 }, 1286 NatGateway: infrav1.NatGateway{ 1287 NatGatewayClassSpec: infrav1.NatGatewayClassSpec{ 1288 Name: "fake-nat-gateway-2", 1289 }, 1290 }, 1291 }, 1292 }, 1293 }, 1294 }, 1295 }, 1296 cache: &ClusterCache{}, 1297 }, 1298 asoNatgateway: &asonetworkv1api20220701.NatGateway{ 1299 ObjectMeta: metav1.ObjectMeta{ 1300 Name: "fake-nat-gateway-1", 1301 }, 1302 Status: asonetworkv1api20220701.NatGateway_STATUS{ 1303 Id: ptr.To("dummy-id-1"), 1304 }, 1305 }, 1306 }, 1307 } 1308 1309 for _, tt := range tests { 1310 tt := tt 1311 t.Run(tt.name, func(t *testing.T) { 1312 g := NewWithT(t) 1313 t.Parallel() 1314 tt.clusterScope.SetNatGatewayIDInSubnets(tt.asoNatgateway.Name, *tt.asoNatgateway.Status.Id) 1315 for _, subnet := range tt.clusterScope.AzureCluster.Spec.NetworkSpec.Subnets { 1316 if subnet.NatGateway.Name == tt.asoNatgateway.Name { 1317 g.Expect(subnet.NatGateway.ID).To(Equal(*tt.asoNatgateway.Status.Id)) 1318 } else { 1319 g.Expect(subnet.NatGateway.ID).To(Equal("")) 1320 } 1321 } 1322 }) 1323 } 1324 } 1325 1326 func TestNSGSpecs(t *testing.T) { 1327 tests := []struct { 1328 name string 1329 clusterScope ClusterScope 1330 want []azure.ResourceSpecGetter 1331 }{ 1332 { 1333 name: "returns empty if no subnets are specified", 1334 clusterScope: ClusterScope{ 1335 AzureCluster: &infrav1.AzureCluster{ 1336 Spec: infrav1.AzureClusterSpec{ 1337 NetworkSpec: infrav1.NetworkSpec{ 1338 Subnets: infrav1.Subnets{}, 1339 }, 1340 }, 1341 }, 1342 }, 1343 want: []azure.ResourceSpecGetter{}, 1344 }, 1345 { 1346 name: "returns specified security groups if present", 1347 clusterScope: ClusterScope{ 1348 Cluster: &clusterv1.Cluster{ 1349 ObjectMeta: metav1.ObjectMeta{ 1350 Name: "my-cluster", 1351 }, 1352 }, 1353 AzureCluster: &infrav1.AzureCluster{ 1354 Spec: infrav1.AzureClusterSpec{ 1355 AzureClusterClassSpec: infrav1.AzureClusterClassSpec{ 1356 Location: "centralIndia", 1357 IdentityRef: &corev1.ObjectReference{ 1358 Kind: infrav1.AzureClusterIdentityKind, 1359 }, 1360 }, 1361 NetworkSpec: infrav1.NetworkSpec{ 1362 Vnet: infrav1.VnetSpec{ 1363 ResourceGroup: "my-rg", 1364 }, 1365 Subnets: infrav1.Subnets{ 1366 { 1367 SecurityGroup: infrav1.SecurityGroup{ 1368 Name: "fake-security-group-1", 1369 SecurityGroupClass: infrav1.SecurityGroupClass{ 1370 SecurityRules: infrav1.SecurityRules{ 1371 { 1372 Name: "fake-rule-1", 1373 }, 1374 }, 1375 }, 1376 }, 1377 }, 1378 }, 1379 }, 1380 }, 1381 }, 1382 cache: &ClusterCache{}, 1383 }, 1384 want: []azure.ResourceSpecGetter{ 1385 &securitygroups.NSGSpec{ 1386 Name: "fake-security-group-1", 1387 SecurityRules: infrav1.SecurityRules{ 1388 { 1389 Name: "fake-rule-1", 1390 }, 1391 }, 1392 ResourceGroup: "my-rg", 1393 Location: "centralIndia", 1394 ClusterName: "my-cluster", 1395 AdditionalTags: make(infrav1.Tags), 1396 LastAppliedSecurityRules: map[string]interface{}{}, 1397 }, 1398 }, 1399 }, 1400 } 1401 1402 for _, tt := range tests { 1403 tt := tt 1404 t.Run(tt.name, func(t *testing.T) { 1405 t.Parallel() 1406 if got := tt.clusterScope.NSGSpecs(); !reflect.DeepEqual(got, tt.want) { 1407 t.Errorf("RouteTableSpecs() = %s, want %s", specArrayToString(got), specArrayToString(tt.want)) 1408 } 1409 }) 1410 } 1411 } 1412 1413 func TestSubnetSpecs(t *testing.T) { 1414 scheme := runtime.NewScheme() 1415 _ = asonetworkv1api20201101.AddToScheme(scheme) 1416 _ = corev1.AddToScheme(scheme) 1417 _ = infrav1.AddToScheme(scheme) 1418 1419 tests := []struct { 1420 name string 1421 clusterScope ClusterScope 1422 vnet asonetworkv1api20201101.VirtualNetwork 1423 want []azure.ASOResourceSpecGetter[*asonetworkv1api20201101.VirtualNetworksSubnet] 1424 }{ 1425 { 1426 name: "returns empty if no subnets are specified", 1427 clusterScope: ClusterScope{ 1428 AzureCluster: &infrav1.AzureCluster{ 1429 Spec: infrav1.AzureClusterSpec{ 1430 NetworkSpec: infrav1.NetworkSpec{ 1431 Subnets: infrav1.Subnets{}, 1432 }, 1433 }, 1434 }, 1435 cache: &ClusterCache{}, 1436 }, 1437 want: []azure.ASOResourceSpecGetter[*asonetworkv1api20201101.VirtualNetworksSubnet]{}, 1438 }, 1439 { 1440 name: "returns specified subnet spec", 1441 clusterScope: ClusterScope{ 1442 Cluster: &clusterv1.Cluster{ 1443 ObjectMeta: metav1.ObjectMeta{ 1444 Name: "my-cluster", 1445 }, 1446 }, 1447 AzureClients: AzureClients{ 1448 EnvironmentSettings: auth.EnvironmentSettings{ 1449 Values: map[string]string{ 1450 auth.SubscriptionID: "123", 1451 }, 1452 }, 1453 }, 1454 AzureCluster: &infrav1.AzureCluster{ 1455 Spec: infrav1.AzureClusterSpec{ 1456 ResourceGroup: "my-rg", 1457 AzureClusterClassSpec: infrav1.AzureClusterClassSpec{ 1458 Location: "centralIndia", 1459 IdentityRef: &corev1.ObjectReference{ 1460 Kind: infrav1.AzureClusterIdentityKind, 1461 }, 1462 }, 1463 NetworkSpec: infrav1.NetworkSpec{ 1464 Vnet: infrav1.VnetSpec{ 1465 ID: "fake-vnet-id-1", 1466 Name: "fake-vnet-1", 1467 ResourceGroup: "my-rg-vnet", 1468 }, 1469 Subnets: infrav1.Subnets{ 1470 { 1471 SubnetClassSpec: infrav1.SubnetClassSpec{ 1472 Role: infrav1.SubnetNode, 1473 CIDRBlocks: []string{"192.168.1.1/16"}, 1474 Name: "fake-subnet-1", 1475 }, 1476 NatGateway: infrav1.NatGateway{ 1477 NatGatewayClassSpec: infrav1.NatGatewayClassSpec{ 1478 Name: "fake-natgateway-1", 1479 }, 1480 }, 1481 RouteTable: infrav1.RouteTable{ 1482 ID: "fake-route-table-id-1", 1483 Name: "fake-route-table-1", 1484 }, 1485 SecurityGroup: infrav1.SecurityGroup{ 1486 Name: "fake-security-group-1", 1487 SecurityGroupClass: infrav1.SecurityGroupClass{ 1488 SecurityRules: infrav1.SecurityRules{ 1489 { 1490 Name: "fake-rule-1", 1491 }, 1492 }, 1493 }, 1494 }, 1495 }, 1496 }, 1497 }, 1498 }, 1499 }, 1500 cache: &ClusterCache{}, 1501 }, 1502 vnet: asonetworkv1api20201101.VirtualNetwork{ 1503 ObjectMeta: metav1.ObjectMeta{ 1504 Name: "fake-vnet-1", 1505 }, 1506 }, 1507 want: []azure.ASOResourceSpecGetter[*asonetworkv1api20201101.VirtualNetworksSubnet]{ 1508 &subnets.SubnetSpec{ 1509 Name: "fake-subnet-1", 1510 ResourceGroup: "my-rg", 1511 SubscriptionID: "123", 1512 CIDRs: []string{"192.168.1.1/16"}, 1513 VNetName: "fake-vnet-1", 1514 VNetResourceGroup: "my-rg-vnet", 1515 IsVNetManaged: false, 1516 RouteTableName: "fake-route-table-1", 1517 SecurityGroupName: "fake-security-group-1", 1518 NatGatewayName: "fake-natgateway-1", 1519 }, 1520 }, 1521 }, 1522 1523 { 1524 name: "returns specified subnet spec and bastion spec if enabled", 1525 clusterScope: ClusterScope{ 1526 Cluster: &clusterv1.Cluster{ 1527 ObjectMeta: metav1.ObjectMeta{ 1528 Name: "my-cluster", 1529 }, 1530 }, 1531 AzureClients: AzureClients{ 1532 EnvironmentSettings: auth.EnvironmentSettings{ 1533 Values: map[string]string{ 1534 auth.SubscriptionID: "123", 1535 }, 1536 }, 1537 }, 1538 AzureCluster: &infrav1.AzureCluster{ 1539 Spec: infrav1.AzureClusterSpec{ 1540 BastionSpec: infrav1.BastionSpec{ 1541 AzureBastion: &infrav1.AzureBastion{ 1542 Name: "fake-azure-bastion", 1543 Subnet: infrav1.SubnetSpec{ 1544 SubnetClassSpec: infrav1.SubnetClassSpec{ 1545 Role: infrav1.SubnetBastion, 1546 CIDRBlocks: []string{"172.122.1.1./16"}, 1547 Name: "fake-bastion-subnet-1", 1548 }, 1549 RouteTable: infrav1.RouteTable{ 1550 ID: "fake-bastion-route-table-id-1", 1551 Name: "fake-bastion-route-table-1", 1552 }, 1553 SecurityGroup: infrav1.SecurityGroup{ 1554 Name: "fake-bastion-security-group-1", 1555 SecurityGroupClass: infrav1.SecurityGroupClass{ 1556 SecurityRules: infrav1.SecurityRules{ 1557 { 1558 Name: "fake-rule-1", 1559 }, 1560 }, 1561 }, 1562 }, 1563 }, 1564 }, 1565 }, 1566 ResourceGroup: "my-rg", 1567 AzureClusterClassSpec: infrav1.AzureClusterClassSpec{ 1568 Location: "centralIndia", 1569 IdentityRef: &corev1.ObjectReference{ 1570 Kind: infrav1.AzureClusterIdentityKind, 1571 }, 1572 }, 1573 NetworkSpec: infrav1.NetworkSpec{ 1574 Vnet: infrav1.VnetSpec{ 1575 ID: "fake-vnet-id-1", 1576 Name: "fake-vnet-1", 1577 ResourceGroup: "my-rg-vnet", 1578 }, 1579 Subnets: infrav1.Subnets{ 1580 { 1581 SubnetClassSpec: infrav1.SubnetClassSpec{ 1582 Role: infrav1.SubnetNode, 1583 CIDRBlocks: []string{"192.168.1.1/16"}, 1584 Name: "fake-subnet-1", 1585 }, 1586 NatGateway: infrav1.NatGateway{ 1587 NatGatewayClassSpec: infrav1.NatGatewayClassSpec{ 1588 Name: "fake-natgateway-1", 1589 }, 1590 }, 1591 RouteTable: infrav1.RouteTable{ 1592 ID: "fake-route-table-id-1", 1593 Name: "fake-route-table-1", 1594 }, 1595 SecurityGroup: infrav1.SecurityGroup{ 1596 Name: "fake-security-group-1", 1597 SecurityGroupClass: infrav1.SecurityGroupClass{ 1598 SecurityRules: infrav1.SecurityRules{ 1599 { 1600 Name: "fake-rule-1", 1601 }, 1602 }, 1603 }, 1604 }, 1605 }, 1606 }, 1607 }, 1608 }, 1609 }, 1610 cache: &ClusterCache{}, 1611 }, 1612 vnet: asonetworkv1api20201101.VirtualNetwork{ 1613 ObjectMeta: metav1.ObjectMeta{ 1614 Name: "fake-vnet-1", 1615 }, 1616 }, 1617 want: []azure.ASOResourceSpecGetter[*asonetworkv1api20201101.VirtualNetworksSubnet]{ 1618 &subnets.SubnetSpec{ 1619 Name: "fake-subnet-1", 1620 ResourceGroup: "my-rg", 1621 SubscriptionID: "123", 1622 CIDRs: []string{"192.168.1.1/16"}, 1623 VNetName: "fake-vnet-1", 1624 VNetResourceGroup: "my-rg-vnet", 1625 IsVNetManaged: false, 1626 RouteTableName: "fake-route-table-1", 1627 SecurityGroupName: "fake-security-group-1", 1628 NatGatewayName: "fake-natgateway-1", 1629 }, 1630 &subnets.SubnetSpec{ 1631 Name: "fake-bastion-subnet-1", 1632 ResourceGroup: "my-rg", 1633 SubscriptionID: "123", 1634 CIDRs: []string{"172.122.1.1./16"}, 1635 VNetName: "fake-vnet-1", 1636 VNetResourceGroup: "my-rg-vnet", 1637 IsVNetManaged: false, 1638 SecurityGroupName: "fake-bastion-security-group-1", 1639 RouteTableName: "fake-bastion-route-table-1", 1640 }, 1641 }, 1642 }, 1643 } 1644 1645 for _, tt := range tests { 1646 tt := tt 1647 t.Run(tt.name, func(t *testing.T) { 1648 t.Parallel() 1649 fakeIdentity := &infrav1.AzureClusterIdentity{ 1650 ObjectMeta: metav1.ObjectMeta{ 1651 Name: "fake-identity", 1652 Namespace: "default", 1653 }, 1654 Spec: infrav1.AzureClusterIdentitySpec{ 1655 Type: infrav1.ServicePrincipal, 1656 ClientID: fakeClientID, 1657 TenantID: fakeTenantID, 1658 }, 1659 } 1660 fakeSecret := &corev1.Secret{Data: map[string][]byte{"clientSecret": []byte("fooSecret")}} 1661 1662 initObjects := []runtime.Object{&tt.vnet, fakeIdentity, fakeSecret} 1663 fakeClient := fake.NewClientBuilder().WithScheme(scheme).WithRuntimeObjects(initObjects...).Build() 1664 tt.clusterScope.Client = fakeClient 1665 1666 if got := tt.clusterScope.SubnetSpecs(); !reflect.DeepEqual(got, tt.want) { 1667 t.Errorf("SubnetSpecs() = \n%s, want \n%s", specArrayToString(got), specArrayToString(tt.want)) 1668 } 1669 }) 1670 } 1671 } 1672 1673 func TestIsVnetManaged(t *testing.T) { 1674 scheme := runtime.NewScheme() 1675 _ = asonetworkv1api20201101.AddToScheme(scheme) 1676 _ = corev1.AddToScheme(scheme) 1677 _ = infrav1.AddToScheme(scheme) 1678 1679 tests := []struct { 1680 name string 1681 clusterScope ClusterScope 1682 vnet asonetworkv1api20201101.VirtualNetwork 1683 want bool 1684 }{ 1685 { 1686 name: "Wrong tags", 1687 clusterScope: ClusterScope{ 1688 Cluster: &clusterv1.Cluster{ 1689 ObjectMeta: metav1.ObjectMeta{ 1690 Name: "my-cluster", 1691 }, 1692 }, 1693 AzureCluster: &infrav1.AzureCluster{ 1694 Spec: infrav1.AzureClusterSpec{ 1695 NetworkSpec: infrav1.NetworkSpec{ 1696 Vnet: infrav1.VnetSpec{ 1697 Name: "fake-vnet-1", 1698 }, 1699 }, 1700 }, 1701 }, 1702 cache: &ClusterCache{}, 1703 }, 1704 vnet: asonetworkv1api20201101.VirtualNetwork{ 1705 ObjectMeta: metav1.ObjectMeta{ 1706 Name: "fake-vnet-1", 1707 }, 1708 Status: asonetworkv1api20201101.VirtualNetwork_STATUS{ 1709 Tags: map[string]string{ 1710 "key": "value", 1711 }, 1712 }, 1713 }, 1714 want: false, 1715 }, 1716 { 1717 name: "Has owning tags", 1718 clusterScope: ClusterScope{ 1719 Cluster: &clusterv1.Cluster{ 1720 ObjectMeta: metav1.ObjectMeta{ 1721 Name: "my-cluster", 1722 }, 1723 }, 1724 AzureCluster: &infrav1.AzureCluster{ 1725 Spec: infrav1.AzureClusterSpec{ 1726 NetworkSpec: infrav1.NetworkSpec{ 1727 Vnet: infrav1.VnetSpec{ 1728 Name: "fake-vnet-1", 1729 }, 1730 }, 1731 }, 1732 }, 1733 cache: &ClusterCache{}, 1734 }, 1735 vnet: asonetworkv1api20201101.VirtualNetwork{ 1736 ObjectMeta: metav1.ObjectMeta{ 1737 Name: "fake-vnet-1", 1738 }, 1739 Status: asonetworkv1api20201101.VirtualNetwork_STATUS{ 1740 Tags: map[string]string{ 1741 "sigs.k8s.io_cluster-api-provider-azure_cluster_my-cluster": "owned", 1742 }, 1743 }, 1744 }, 1745 want: true, 1746 }, 1747 { 1748 name: "Has cached value of false", 1749 clusterScope: ClusterScope{ 1750 AzureCluster: &infrav1.AzureCluster{ 1751 Spec: infrav1.AzureClusterSpec{}, 1752 }, 1753 cache: &ClusterCache{ 1754 isVnetManaged: ptr.To(false), 1755 }, 1756 }, 1757 want: false, 1758 }, 1759 { 1760 name: "Has cached value of true", 1761 clusterScope: ClusterScope{ 1762 AzureCluster: &infrav1.AzureCluster{ 1763 Spec: infrav1.AzureClusterSpec{}, 1764 }, 1765 cache: &ClusterCache{ 1766 isVnetManaged: ptr.To(true), 1767 }, 1768 }, 1769 want: true, 1770 }, 1771 } 1772 1773 for _, tt := range tests { 1774 tt := tt 1775 t.Run(tt.name, func(t *testing.T) { 1776 t.Parallel() 1777 fakeIdentity := &infrav1.AzureClusterIdentity{ 1778 ObjectMeta: metav1.ObjectMeta{ 1779 Name: "fake-identity", 1780 Namespace: "default", 1781 }, 1782 Spec: infrav1.AzureClusterIdentitySpec{ 1783 Type: infrav1.ServicePrincipal, 1784 ClientID: fakeClientID, 1785 TenantID: fakeTenantID, 1786 }, 1787 } 1788 fakeSecret := &corev1.Secret{Data: map[string][]byte{"clientSecret": []byte("fooSecret")}} 1789 1790 initObjects := []runtime.Object{&tt.vnet, fakeIdentity, fakeSecret} 1791 fakeClient := fake.NewClientBuilder().WithScheme(scheme).WithRuntimeObjects(initObjects...).Build() 1792 tt.clusterScope.Client = fakeClient 1793 1794 got := tt.clusterScope.IsVnetManaged() 1795 if !reflect.DeepEqual(got, tt.want) { 1796 t.Errorf("IsVnetManaged() = \n%t, want \n%t", got, tt.want) 1797 } 1798 if ptr.Deref(tt.clusterScope.cache.isVnetManaged, false) != got { 1799 t.Errorf("IsVnetManaged() = \n%t, cache = \n%t", got, ptr.Deref(tt.clusterScope.cache.isVnetManaged, false)) 1800 } 1801 }) 1802 } 1803 } 1804 1805 func TestAzureBastionSpec(t *testing.T) { 1806 tests := []struct { 1807 name string 1808 clusterScope ClusterScope 1809 want azure.ASOResourceSpecGetter[*asonetworkv1api20220701.BastionHost] 1810 }{ 1811 { 1812 name: "returns nil if no subnets are specified", 1813 clusterScope: ClusterScope{ 1814 AzureCluster: &infrav1.AzureCluster{ 1815 Spec: infrav1.AzureClusterSpec{ 1816 NetworkSpec: infrav1.NetworkSpec{ 1817 Subnets: infrav1.Subnets{}, 1818 }, 1819 }, 1820 }, 1821 }, 1822 want: nil, 1823 }, 1824 { 1825 name: "returns bastion spec if enabled", 1826 clusterScope: ClusterScope{ 1827 Cluster: &clusterv1.Cluster{ 1828 ObjectMeta: metav1.ObjectMeta{ 1829 Name: "my-cluster", 1830 }, 1831 }, 1832 AzureClients: AzureClients{ 1833 EnvironmentSettings: auth.EnvironmentSettings{ 1834 Values: map[string]string{ 1835 auth.SubscriptionID: "123", 1836 }, 1837 }, 1838 }, 1839 AzureCluster: &infrav1.AzureCluster{ 1840 Spec: infrav1.AzureClusterSpec{ 1841 BastionSpec: infrav1.BastionSpec{ 1842 AzureBastion: &infrav1.AzureBastion{ 1843 Name: "fake-azure-bastion-1", 1844 Subnet: infrav1.SubnetSpec{ 1845 SubnetClassSpec: infrav1.SubnetClassSpec{ 1846 Role: infrav1.SubnetBastion, 1847 CIDRBlocks: []string{"172.122.1.1./16"}, 1848 Name: "fake-bastion-subnet-1", 1849 }, 1850 RouteTable: infrav1.RouteTable{ 1851 ID: "fake-bastion-route-table-id-1", 1852 Name: "fake-bastion-route-table-1", 1853 }, 1854 SecurityGroup: infrav1.SecurityGroup{ 1855 Name: "fake-bastion-security-group-1", 1856 SecurityGroupClass: infrav1.SecurityGroupClass{ 1857 SecurityRules: infrav1.SecurityRules{ 1858 { 1859 Name: "fake-rule-1", 1860 }, 1861 }, 1862 }, 1863 }, 1864 }, 1865 PublicIP: infrav1.PublicIPSpec{ 1866 Name: "fake-public-ip-1", 1867 }, 1868 }, 1869 }, 1870 ResourceGroup: "my-rg", 1871 AzureClusterClassSpec: infrav1.AzureClusterClassSpec{ 1872 Location: "centralIndia", 1873 IdentityRef: &corev1.ObjectReference{ 1874 Kind: infrav1.AzureClusterIdentityKind, 1875 }, 1876 }, 1877 NetworkSpec: infrav1.NetworkSpec{ 1878 Vnet: infrav1.VnetSpec{ 1879 ID: "fake-vnet-id-1", 1880 Name: "fake-vnet-1", 1881 ResourceGroup: "my-rg-vnet", 1882 }, 1883 Subnets: infrav1.Subnets{ 1884 { 1885 SubnetClassSpec: infrav1.SubnetClassSpec{ 1886 Role: infrav1.SubnetNode, 1887 CIDRBlocks: []string{"192.168.1.1/16"}, 1888 Name: "fake-subnet-1", 1889 }, 1890 NatGateway: infrav1.NatGateway{ 1891 NatGatewayClassSpec: infrav1.NatGatewayClassSpec{ 1892 Name: "fake-natgateway-1", 1893 }, 1894 }, 1895 RouteTable: infrav1.RouteTable{ 1896 ID: "fake-route-table-id-1", 1897 Name: "fake-route-table-1", 1898 }, 1899 SecurityGroup: infrav1.SecurityGroup{ 1900 Name: "fake-security-group-1", 1901 SecurityGroupClass: infrav1.SecurityGroupClass{ 1902 SecurityRules: infrav1.SecurityRules{ 1903 { 1904 Name: "fake-rule-1", 1905 }, 1906 }, 1907 }, 1908 }, 1909 }, 1910 }, 1911 }, 1912 }, 1913 }, 1914 cache: &ClusterCache{}, 1915 }, 1916 want: &bastionhosts.AzureBastionSpec{ 1917 Name: "fake-azure-bastion-1", 1918 ResourceGroup: "my-rg", 1919 Location: "centralIndia", 1920 ClusterName: "my-cluster", 1921 SubnetID: fmt.Sprintf("/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Network/"+ 1922 "virtualNetworks/%s/subnets/%s", "123", "my-rg-vnet", "fake-vnet-1", "fake-bastion-subnet-1"), 1923 PublicIPID: fmt.Sprintf("/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Network/"+ 1924 "publicIPAddresses/%s", "123", "my-rg", "fake-public-ip-1"), 1925 }, 1926 }, 1927 } 1928 1929 for _, tt := range tests { 1930 tt := tt 1931 t.Run(tt.name, func(t *testing.T) { 1932 t.Parallel() 1933 if got := tt.clusterScope.AzureBastionSpec(); !reflect.DeepEqual(got, tt.want) { 1934 t.Errorf("AzureBastionSpec() = \n%s, want \n%s", specToString(got), specToString(tt.want)) 1935 } 1936 }) 1937 } 1938 } 1939 1940 func TestSubnet(t *testing.T) { 1941 tests := []struct { 1942 clusterName string 1943 subnetName string 1944 azureClusterNetworkSpec infrav1.NetworkSpec 1945 expectSubnet infrav1.SubnetSpec 1946 }{ 1947 { 1948 clusterName: "my-cluster-1", 1949 subnetName: "subnet-1", 1950 azureClusterNetworkSpec: infrav1.NetworkSpec{}, 1951 expectSubnet: infrav1.SubnetSpec{}, 1952 }, 1953 { 1954 clusterName: "my-cluster-1", 1955 subnetName: "subnet-1", 1956 azureClusterNetworkSpec: infrav1.NetworkSpec{ 1957 Subnets: infrav1.Subnets{ 1958 infrav1.SubnetSpec{ 1959 SubnetClassSpec: infrav1.SubnetClassSpec{ 1960 Name: "subnet-1", 1961 }, 1962 ID: "subnet-1-id", 1963 }, 1964 infrav1.SubnetSpec{ 1965 SubnetClassSpec: infrav1.SubnetClassSpec{ 1966 Name: "subnet-2", 1967 }, 1968 ID: "subnet-1-id", 1969 }, 1970 infrav1.SubnetSpec{ 1971 SubnetClassSpec: infrav1.SubnetClassSpec{ 1972 Name: "subnet-3", 1973 }, 1974 ID: "subnet-2-id", 1975 }, 1976 }, 1977 }, 1978 expectSubnet: infrav1.SubnetSpec{ 1979 SubnetClassSpec: infrav1.SubnetClassSpec{ 1980 Name: "subnet-1", 1981 }, 1982 ID: "subnet-1-id", 1983 }, 1984 }, 1985 } 1986 for _, tc := range tests { 1987 t.Run(tc.clusterName, func(t *testing.T) { 1988 g := NewWithT(t) 1989 scheme := runtime.NewScheme() 1990 _ = infrav1.AddToScheme(scheme) 1991 _ = clusterv1.AddToScheme(scheme) 1992 _ = corev1.AddToScheme(scheme) 1993 1994 cluster := &clusterv1.Cluster{ 1995 ObjectMeta: metav1.ObjectMeta{ 1996 Name: tc.clusterName, 1997 Namespace: "default", 1998 }, 1999 } 2000 azureCluster := &infrav1.AzureCluster{ 2001 ObjectMeta: metav1.ObjectMeta{ 2002 Name: tc.clusterName, 2003 OwnerReferences: []metav1.OwnerReference{ 2004 { 2005 APIVersion: "cluster.x-k8s.io/v1beta1", 2006 Kind: "Cluster", 2007 Name: "my-cluster", 2008 }, 2009 }, 2010 }, 2011 Spec: infrav1.AzureClusterSpec{ 2012 NetworkSpec: tc.azureClusterNetworkSpec, 2013 AzureClusterClassSpec: infrav1.AzureClusterClassSpec{ 2014 SubscriptionID: "123", 2015 IdentityRef: &corev1.ObjectReference{ 2016 Kind: infrav1.AzureClusterIdentityKind, 2017 }, 2018 }, 2019 }, 2020 } 2021 fakeIdentity := &infrav1.AzureClusterIdentity{ 2022 Spec: infrav1.AzureClusterIdentitySpec{ 2023 Type: infrav1.ServicePrincipal, 2024 ClientID: fakeClientID, 2025 TenantID: fakeTenantID, 2026 }, 2027 } 2028 fakeSecret := &corev1.Secret{Data: map[string][]byte{"clientSecret": []byte("fooSecret")}} 2029 2030 initObjects := []runtime.Object{cluster, azureCluster, fakeIdentity, fakeSecret} 2031 fakeClient := fake.NewClientBuilder().WithScheme(scheme).WithRuntimeObjects(initObjects...).Build() 2032 2033 clusterScope, err := NewClusterScope(context.TODO(), ClusterScopeParams{ 2034 Cluster: cluster, 2035 AzureCluster: azureCluster, 2036 Client: fakeClient, 2037 }) 2038 g.Expect(err).NotTo(HaveOccurred()) 2039 got := clusterScope.Subnet(tc.subnetName) 2040 g.Expect(tc.expectSubnet).Should(Equal(got)) 2041 }) 2042 } 2043 } 2044 2045 func TestControlPlaneRouteTable(t *testing.T) { 2046 tests := []struct { 2047 clusterName string 2048 azureClusterNetworkSpec infrav1.NetworkSpec 2049 expectRouteTable infrav1.RouteTable 2050 }{ 2051 { 2052 clusterName: "my-cluster-1", 2053 azureClusterNetworkSpec: infrav1.NetworkSpec{}, 2054 expectRouteTable: infrav1.RouteTable{}, 2055 }, 2056 { 2057 clusterName: "my-cluster-2", 2058 azureClusterNetworkSpec: infrav1.NetworkSpec{ 2059 Subnets: infrav1.Subnets{ 2060 infrav1.SubnetSpec{ 2061 RouteTable: infrav1.RouteTable{ 2062 ID: "fake-id-1", 2063 Name: "route-tb-1", 2064 }, 2065 SubnetClassSpec: infrav1.SubnetClassSpec{ 2066 Role: infrav1.SubnetNode, 2067 }, 2068 }, 2069 infrav1.SubnetSpec{ 2070 RouteTable: infrav1.RouteTable{ 2071 ID: "fake-id-2", 2072 Name: "route-tb-2", 2073 }, 2074 SubnetClassSpec: infrav1.SubnetClassSpec{ 2075 Role: infrav1.SubnetControlPlane, 2076 }, 2077 }, 2078 infrav1.SubnetSpec{ 2079 RouteTable: infrav1.RouteTable{ 2080 ID: "fake-id-3", 2081 Name: "route-tb-3", 2082 }, 2083 SubnetClassSpec: infrav1.SubnetClassSpec{ 2084 Role: infrav1.SubnetBastion, 2085 }, 2086 }, 2087 }, 2088 }, 2089 expectRouteTable: infrav1.RouteTable{ 2090 ID: "fake-id-2", 2091 Name: "route-tb-2", 2092 }, 2093 }, 2094 } 2095 for _, tc := range tests { 2096 t.Run(tc.clusterName, func(t *testing.T) { 2097 g := NewWithT(t) 2098 scheme := runtime.NewScheme() 2099 _ = infrav1.AddToScheme(scheme) 2100 _ = clusterv1.AddToScheme(scheme) 2101 _ = corev1.AddToScheme(scheme) 2102 2103 cluster := &clusterv1.Cluster{ 2104 ObjectMeta: metav1.ObjectMeta{ 2105 Name: tc.clusterName, 2106 Namespace: "default", 2107 }, 2108 } 2109 azureCluster := &infrav1.AzureCluster{ 2110 ObjectMeta: metav1.ObjectMeta{ 2111 Name: tc.clusterName, 2112 OwnerReferences: []metav1.OwnerReference{ 2113 { 2114 APIVersion: "cluster.x-k8s.io/v1beta1", 2115 Kind: "Cluster", 2116 Name: "my-cluster", 2117 }, 2118 }, 2119 }, 2120 Spec: infrav1.AzureClusterSpec{ 2121 NetworkSpec: tc.azureClusterNetworkSpec, 2122 AzureClusterClassSpec: infrav1.AzureClusterClassSpec{ 2123 SubscriptionID: "123", 2124 IdentityRef: &corev1.ObjectReference{ 2125 Kind: infrav1.AzureClusterIdentityKind, 2126 }, 2127 }, 2128 }, 2129 } 2130 fakeIdentity := &infrav1.AzureClusterIdentity{ 2131 Spec: infrav1.AzureClusterIdentitySpec{ 2132 Type: infrav1.ServicePrincipal, 2133 ClientID: fakeClientID, 2134 TenantID: fakeTenantID, 2135 }, 2136 } 2137 fakeSecret := &corev1.Secret{Data: map[string][]byte{"clientSecret": []byte("fooSecret")}} 2138 2139 initObjects := []runtime.Object{cluster, azureCluster, fakeIdentity, fakeSecret} 2140 fakeClient := fake.NewClientBuilder().WithScheme(scheme).WithRuntimeObjects(initObjects...).Build() 2141 2142 clusterScope, err := NewClusterScope(context.TODO(), ClusterScopeParams{ 2143 Cluster: cluster, 2144 AzureCluster: azureCluster, 2145 Client: fakeClient, 2146 }) 2147 g.Expect(err).NotTo(HaveOccurred()) 2148 got := clusterScope.ControlPlaneRouteTable() 2149 g.Expect(tc.expectRouteTable).Should(Equal(got)) 2150 }) 2151 } 2152 } 2153 2154 func TestGetPrivateDNSZoneName(t *testing.T) { 2155 tests := []struct { 2156 clusterName string 2157 azureClusterNetworkSpec infrav1.NetworkSpec 2158 expectPrivateDNSZoneName string 2159 }{ 2160 { 2161 clusterName: "my-cluster-1", 2162 azureClusterNetworkSpec: infrav1.NetworkSpec{ 2163 NetworkClassSpec: infrav1.NetworkClassSpec{ 2164 PrivateDNSZoneName: "fake-privateDNSZoneName", 2165 }, 2166 }, 2167 expectPrivateDNSZoneName: "fake-privateDNSZoneName", 2168 }, 2169 { 2170 clusterName: "my-cluster-2", 2171 expectPrivateDNSZoneName: "my-cluster-2.capz.io", 2172 }, 2173 } 2174 for _, tc := range tests { 2175 t.Run(tc.clusterName, func(t *testing.T) { 2176 g := NewWithT(t) 2177 scheme := runtime.NewScheme() 2178 _ = infrav1.AddToScheme(scheme) 2179 _ = clusterv1.AddToScheme(scheme) 2180 _ = corev1.AddToScheme(scheme) 2181 2182 cluster := &clusterv1.Cluster{ 2183 ObjectMeta: metav1.ObjectMeta{ 2184 Name: tc.clusterName, 2185 Namespace: "default", 2186 }, 2187 } 2188 azureCluster := &infrav1.AzureCluster{ 2189 ObjectMeta: metav1.ObjectMeta{ 2190 Name: tc.clusterName, 2191 OwnerReferences: []metav1.OwnerReference{ 2192 { 2193 APIVersion: "cluster.x-k8s.io/v1beta1", 2194 Kind: "Cluster", 2195 Name: "my-cluster", 2196 }, 2197 }, 2198 }, 2199 Spec: infrav1.AzureClusterSpec{ 2200 NetworkSpec: tc.azureClusterNetworkSpec, 2201 AzureClusterClassSpec: infrav1.AzureClusterClassSpec{ 2202 SubscriptionID: "123", 2203 IdentityRef: &corev1.ObjectReference{ 2204 Kind: infrav1.AzureClusterIdentityKind, 2205 }, 2206 }, 2207 }, 2208 } 2209 fakeIdentity := &infrav1.AzureClusterIdentity{ 2210 Spec: infrav1.AzureClusterIdentitySpec{ 2211 Type: infrav1.ServicePrincipal, 2212 ClientID: fakeClientID, 2213 TenantID: fakeTenantID, 2214 }, 2215 } 2216 fakeSecret := &corev1.Secret{Data: map[string][]byte{"clientSecret": []byte("fooSecret")}} 2217 2218 initObjects := []runtime.Object{cluster, azureCluster, fakeIdentity, fakeSecret} 2219 fakeClient := fake.NewClientBuilder().WithScheme(scheme).WithRuntimeObjects(initObjects...).Build() 2220 2221 clusterScope, err := NewClusterScope(context.TODO(), ClusterScopeParams{ 2222 Cluster: cluster, 2223 AzureCluster: azureCluster, 2224 Client: fakeClient, 2225 }) 2226 g.Expect(err).NotTo(HaveOccurred()) 2227 got := clusterScope.GetPrivateDNSZoneName() 2228 g.Expect(tc.expectPrivateDNSZoneName).Should(Equal(got)) 2229 }) 2230 } 2231 } 2232 2233 func TestAPIServerLBPoolName(t *testing.T) { 2234 tests := []struct { 2235 lbName string 2236 clusterName string 2237 expectLBpoolName string 2238 }{ 2239 { 2240 lbName: "fake-lb-1", 2241 clusterName: "my-cluster-1", 2242 expectLBpoolName: "fake-lb-1-backendPool", 2243 }, 2244 { 2245 lbName: "fake-lb-2", 2246 clusterName: "my-cluster-2", 2247 expectLBpoolName: "fake-lb-2-backendPool", 2248 }, 2249 } 2250 for _, tc := range tests { 2251 t.Run(tc.lbName, func(t *testing.T) { 2252 g := NewWithT(t) 2253 scheme := runtime.NewScheme() 2254 _ = infrav1.AddToScheme(scheme) 2255 _ = clusterv1.AddToScheme(scheme) 2256 _ = corev1.AddToScheme(scheme) 2257 2258 cluster := &clusterv1.Cluster{ 2259 ObjectMeta: metav1.ObjectMeta{ 2260 Name: tc.clusterName, 2261 Namespace: "default", 2262 }, 2263 } 2264 azureCluster := &infrav1.AzureCluster{ 2265 ObjectMeta: metav1.ObjectMeta{ 2266 Name: tc.clusterName, 2267 OwnerReferences: []metav1.OwnerReference{ 2268 { 2269 APIVersion: "cluster.x-k8s.io/v1beta1", 2270 Kind: "Cluster", 2271 Name: "my-cluster", 2272 }, 2273 }, 2274 }, 2275 Spec: infrav1.AzureClusterSpec{ 2276 NetworkSpec: infrav1.NetworkSpec{ 2277 APIServerLB: infrav1.LoadBalancerSpec{ 2278 Name: tc.lbName, 2279 }, 2280 }, 2281 AzureClusterClassSpec: infrav1.AzureClusterClassSpec{ 2282 SubscriptionID: "123", 2283 IdentityRef: &corev1.ObjectReference{ 2284 Kind: infrav1.AzureClusterIdentityKind, 2285 }, 2286 }, 2287 }, 2288 } 2289 fakeIdentity := &infrav1.AzureClusterIdentity{ 2290 Spec: infrav1.AzureClusterIdentitySpec{ 2291 Type: infrav1.ServicePrincipal, 2292 ClientID: fakeClientID, 2293 TenantID: fakeTenantID, 2294 }, 2295 } 2296 fakeSecret := &corev1.Secret{Data: map[string][]byte{"clientSecret": []byte("fooSecret")}} 2297 2298 initObjects := []runtime.Object{cluster, azureCluster, fakeIdentity, fakeSecret} 2299 fakeClient := fake.NewClientBuilder().WithScheme(scheme).WithRuntimeObjects(initObjects...).Build() 2300 2301 clusterScope, err := NewClusterScope(context.TODO(), ClusterScopeParams{ 2302 Cluster: cluster, 2303 AzureCluster: azureCluster, 2304 Client: fakeClient, 2305 }) 2306 clusterScope.AzureCluster.SetBackendPoolNameDefault() 2307 g.Expect(err).NotTo(HaveOccurred()) 2308 got := clusterScope.APIServerLBPoolName() 2309 g.Expect(tc.expectLBpoolName).Should(Equal(got)) 2310 }) 2311 } 2312 } 2313 2314 func TestOutboundLBName(t *testing.T) { 2315 tests := []struct { 2316 clusterName string 2317 name string 2318 role string 2319 apiServerLB *infrav1.LoadBalancerSpec 2320 controlPlaneOutboundLB *infrav1.LoadBalancerSpec 2321 nodeOutboundLB *infrav1.LoadBalancerSpec 2322 expected string 2323 }{ 2324 { 2325 clusterName: "my-cluster", 2326 name: "public cluster node outbound lb", 2327 role: "node", 2328 expected: "", 2329 }, 2330 { 2331 clusterName: "my-cluster", 2332 name: "public cluster control plane outbound lb", 2333 role: "control-plane", 2334 expected: "my-cluster-public-lb", 2335 }, 2336 { 2337 clusterName: "my-cluster", 2338 name: "private cluster with node outbound lb", 2339 role: "node", 2340 nodeOutboundLB: &infrav1.LoadBalancerSpec{}, 2341 apiServerLB: &infrav1.LoadBalancerSpec{ 2342 LoadBalancerClassSpec: infrav1.LoadBalancerClassSpec{ 2343 Type: "Internal", 2344 }}, 2345 expected: "my-cluster", 2346 }, 2347 { 2348 clusterName: "my-cluster", 2349 name: "private cluster without node outbound lb", 2350 role: "node", 2351 apiServerLB: &infrav1.LoadBalancerSpec{ 2352 LoadBalancerClassSpec: infrav1.LoadBalancerClassSpec{ 2353 Type: "Internal", 2354 }}, 2355 expected: "", 2356 }, 2357 { 2358 clusterName: "my-cluster", 2359 name: "private cluster with control plane outbound lb", 2360 role: "control-plane", 2361 controlPlaneOutboundLB: &infrav1.LoadBalancerSpec{Name: "cp-outbound-lb"}, 2362 apiServerLB: &infrav1.LoadBalancerSpec{ 2363 LoadBalancerClassSpec: infrav1.LoadBalancerClassSpec{ 2364 Type: "Internal", 2365 }}, 2366 expected: "cp-outbound-lb", 2367 }, 2368 { 2369 clusterName: "my-cluster", 2370 name: "private cluster without control plane outbound lb", 2371 role: "control-plane", 2372 apiServerLB: &infrav1.LoadBalancerSpec{ 2373 LoadBalancerClassSpec: infrav1.LoadBalancerClassSpec{ 2374 Type: "Internal", 2375 }}, 2376 expected: "", 2377 }, 2378 } 2379 2380 for _, tc := range tests { 2381 t.Run(tc.name, func(t *testing.T) { 2382 g := NewWithT(t) 2383 scheme := runtime.NewScheme() 2384 _ = infrav1.AddToScheme(scheme) 2385 _ = clusterv1.AddToScheme(scheme) 2386 _ = corev1.AddToScheme(scheme) 2387 2388 cluster := &clusterv1.Cluster{ 2389 ObjectMeta: metav1.ObjectMeta{ 2390 Name: tc.clusterName, 2391 Namespace: "default", 2392 }, 2393 } 2394 2395 azureCluster := &infrav1.AzureCluster{ 2396 ObjectMeta: metav1.ObjectMeta{ 2397 Name: tc.clusterName, 2398 OwnerReferences: []metav1.OwnerReference{ 2399 { 2400 APIVersion: "cluster.x-k8s.io/v1beta1", 2401 Kind: "Cluster", 2402 Name: "my-cluster", 2403 }, 2404 }, 2405 }, 2406 Spec: infrav1.AzureClusterSpec{ 2407 AzureClusterClassSpec: infrav1.AzureClusterClassSpec{ 2408 SubscriptionID: "123", 2409 IdentityRef: &corev1.ObjectReference{ 2410 Kind: infrav1.AzureClusterIdentityKind, 2411 }, 2412 }, 2413 NetworkSpec: infrav1.NetworkSpec{ 2414 Subnets: infrav1.Subnets{ 2415 { 2416 SubnetClassSpec: infrav1.SubnetClassSpec{ 2417 Name: "node", 2418 Role: infrav1.SubnetNode, 2419 }, 2420 }, 2421 }, 2422 }, 2423 }, 2424 } 2425 2426 if tc.apiServerLB != nil { 2427 azureCluster.Spec.NetworkSpec.APIServerLB = *tc.apiServerLB 2428 } 2429 2430 if tc.controlPlaneOutboundLB != nil { 2431 azureCluster.Spec.NetworkSpec.ControlPlaneOutboundLB = tc.controlPlaneOutboundLB 2432 } 2433 2434 if tc.nodeOutboundLB != nil { 2435 azureCluster.Spec.NetworkSpec.NodeOutboundLB = tc.nodeOutboundLB 2436 } 2437 2438 azureCluster.Default() 2439 2440 fakeIdentity := &infrav1.AzureClusterIdentity{ 2441 Spec: infrav1.AzureClusterIdentitySpec{ 2442 Type: infrav1.ServicePrincipal, 2443 ClientID: fakeClientID, 2444 TenantID: fakeTenantID, 2445 }, 2446 } 2447 fakeSecret := &corev1.Secret{Data: map[string][]byte{"clientSecret": []byte("fooSecret")}} 2448 2449 initObjects := []runtime.Object{cluster, azureCluster, fakeIdentity, fakeSecret} 2450 fakeClient := fake.NewClientBuilder().WithScheme(scheme).WithRuntimeObjects(initObjects...).Build() 2451 2452 clusterScope, err := NewClusterScope(context.TODO(), ClusterScopeParams{ 2453 Cluster: cluster, 2454 AzureCluster: azureCluster, 2455 Client: fakeClient, 2456 }) 2457 clusterScope.AzureCluster.SetBackendPoolNameDefault() 2458 g.Expect(err).NotTo(HaveOccurred()) 2459 got := clusterScope.OutboundLBName(tc.role) 2460 g.Expect(tc.expected).Should(Equal(got)) 2461 }) 2462 } 2463 } 2464 2465 func TestBackendPoolName(t *testing.T) { 2466 tests := []struct { 2467 name string 2468 clusterName string 2469 2470 customAPIServerBackendPoolName string 2471 customNodeBackendPoolName string 2472 customControlPlaneBackendPoolName string 2473 2474 expectedAPIServerBackendPoolName string 2475 expectedNodeBackendPoolName string 2476 expectedControlPlaneBackendPoolName string 2477 }{ 2478 { 2479 name: "With default backend pool names", 2480 clusterName: "my-cluster", 2481 expectedAPIServerBackendPoolName: "APIServerLBName-backendPool", 2482 expectedNodeBackendPoolName: "NodeOutboundLBName-outboundBackendPool", 2483 expectedControlPlaneBackendPoolName: "my-cluster-outbound-lb-outboundBackendPool", 2484 }, 2485 { 2486 name: "With custom node backend pool name", 2487 clusterName: "my-cluster", 2488 2489 // setting custom name for node pool name only, others should stay the same 2490 customNodeBackendPoolName: "custom-node-poolname", 2491 2492 expectedAPIServerBackendPoolName: "APIServerLBName-backendPool", 2493 expectedNodeBackendPoolName: "custom-node-poolname", 2494 expectedControlPlaneBackendPoolName: "my-cluster-outbound-lb-outboundBackendPool", 2495 }, 2496 { 2497 name: "With custom backends pool name", 2498 clusterName: "my-cluster", 2499 2500 // setting custom names for all backends pools 2501 customAPIServerBackendPoolName: "custom-api-server-poolname", 2502 customNodeBackendPoolName: "custom-node-poolname", 2503 customControlPlaneBackendPoolName: "custom-control-plane-poolname", 2504 2505 expectedAPIServerBackendPoolName: "custom-api-server-poolname", 2506 expectedNodeBackendPoolName: "custom-node-poolname", 2507 expectedControlPlaneBackendPoolName: "custom-control-plane-poolname", 2508 }, 2509 } 2510 for _, tc := range tests { 2511 t.Run(tc.name, func(t *testing.T) { 2512 g := NewWithT(t) 2513 scheme := runtime.NewScheme() 2514 _ = infrav1.AddToScheme(scheme) 2515 _ = clusterv1.AddToScheme(scheme) 2516 _ = corev1.AddToScheme(scheme) 2517 2518 cluster := &clusterv1.Cluster{ 2519 ObjectMeta: metav1.ObjectMeta{ 2520 Name: tc.clusterName, 2521 Namespace: "default", 2522 }, 2523 } 2524 2525 azureCluster := &infrav1.AzureCluster{ 2526 ObjectMeta: metav1.ObjectMeta{ 2527 Name: tc.clusterName, 2528 OwnerReferences: []metav1.OwnerReference{ 2529 { 2530 APIVersion: "cluster.x-k8s.io/v1beta1", 2531 Kind: "Cluster", 2532 Name: tc.clusterName, 2533 }, 2534 }, 2535 }, 2536 Spec: infrav1.AzureClusterSpec{ 2537 AzureClusterClassSpec: infrav1.AzureClusterClassSpec{ 2538 SubscriptionID: "123", 2539 IdentityRef: &corev1.ObjectReference{ 2540 Kind: infrav1.AzureClusterIdentityKind, 2541 }, 2542 }, 2543 NetworkSpec: infrav1.NetworkSpec{ 2544 Subnets: infrav1.Subnets{ 2545 { 2546 SubnetClassSpec: infrav1.SubnetClassSpec{ 2547 Role: infrav1.SubnetNode, 2548 Name: "node", 2549 }, 2550 }, 2551 }, 2552 APIServerLB: infrav1.LoadBalancerSpec{ 2553 Name: "APIServerLBName", 2554 }, 2555 ControlPlaneOutboundLB: &infrav1.LoadBalancerSpec{ 2556 Name: "ControlPlaneOutboundLBName", 2557 }, 2558 NodeOutboundLB: &infrav1.LoadBalancerSpec{ 2559 Name: "NodeOutboundLBName", 2560 }, 2561 }, 2562 }, 2563 } 2564 2565 azureCluster.Default() 2566 2567 fakeIdentity := &infrav1.AzureClusterIdentity{ 2568 Spec: infrav1.AzureClusterIdentitySpec{ 2569 Type: infrav1.ServicePrincipal, 2570 ClientID: fakeClientID, 2571 TenantID: fakeTenantID, 2572 }, 2573 } 2574 fakeSecret := &corev1.Secret{Data: map[string][]byte{"clientSecret": []byte("fooSecret")}} 2575 2576 if tc.customAPIServerBackendPoolName != "" { 2577 azureCluster.Spec.NetworkSpec.APIServerLB.BackendPool.Name = tc.customAPIServerBackendPoolName 2578 } 2579 2580 if tc.customNodeBackendPoolName != "" { 2581 azureCluster.Spec.NetworkSpec.NodeOutboundLB.BackendPool.Name = tc.customNodeBackendPoolName 2582 } 2583 2584 if tc.customControlPlaneBackendPoolName != "" { 2585 azureCluster.Spec.NetworkSpec.ControlPlaneOutboundLB.BackendPool.Name = tc.customControlPlaneBackendPoolName 2586 } 2587 2588 initObjects := []runtime.Object{cluster, azureCluster, fakeIdentity, fakeSecret} 2589 fakeClient := fake.NewClientBuilder().WithScheme(scheme).WithRuntimeObjects(initObjects...).Build() 2590 2591 clusterScope, err := NewClusterScope(context.TODO(), ClusterScopeParams{ 2592 Cluster: cluster, 2593 AzureCluster: azureCluster, 2594 Client: fakeClient, 2595 }) 2596 clusterScope.AzureCluster.SetBackendPoolNameDefault() 2597 g.Expect(err).NotTo(HaveOccurred()) 2598 got := clusterScope.LBSpecs() 2599 g.Expect(got).To(HaveLen(3)) 2600 2601 // API server backend pool name 2602 apiServerLBSpec := got[0].(*loadbalancers.LBSpec) 2603 g.Expect(apiServerLBSpec.BackendPoolName).To(Equal(tc.expectedAPIServerBackendPoolName)) 2604 g.Expect(apiServerLBSpec.Role).To(Equal(infrav1.APIServerRole)) 2605 2606 // Node backend pool name 2607 NodeLBSpec := got[1].(*loadbalancers.LBSpec) 2608 g.Expect(NodeLBSpec.BackendPoolName).To(Equal(tc.expectedNodeBackendPoolName)) 2609 g.Expect(NodeLBSpec.Role).To(Equal(infrav1.NodeOutboundRole)) 2610 2611 // Control Plane backend pool name 2612 controlPlaneLBSpec := got[2].(*loadbalancers.LBSpec) 2613 g.Expect(controlPlaneLBSpec.BackendPoolName).To(Equal(tc.expectedControlPlaneBackendPoolName)) 2614 g.Expect(controlPlaneLBSpec.Role).To(Equal(infrav1.ControlPlaneOutboundRole)) 2615 }) 2616 } 2617 } 2618 2619 func TestOutboundPoolName(t *testing.T) { 2620 tests := []struct { 2621 name string 2622 clusterName string 2623 loadBalancerName string 2624 expectOutboundPoolName string 2625 }{ 2626 { 2627 name: "Empty loadBalancerName", 2628 clusterName: "my-cluster", 2629 loadBalancerName: "", 2630 expectOutboundPoolName: "", 2631 }, 2632 { 2633 name: "Non empty loadBalancerName", 2634 clusterName: "my-cluster", 2635 loadBalancerName: "my-loadbalancer", 2636 expectOutboundPoolName: "my-loadbalancer-outboundBackendPool", 2637 }, 2638 } 2639 for _, tc := range tests { 2640 t.Run(tc.name, func(t *testing.T) { 2641 g := NewWithT(t) 2642 scheme := runtime.NewScheme() 2643 _ = infrav1.AddToScheme(scheme) 2644 _ = clusterv1.AddToScheme(scheme) 2645 _ = corev1.AddToScheme(scheme) 2646 2647 cluster := &clusterv1.Cluster{ 2648 ObjectMeta: metav1.ObjectMeta{ 2649 Name: tc.clusterName, 2650 Namespace: "default", 2651 }, 2652 } 2653 azureCluster := &infrav1.AzureCluster{ 2654 ObjectMeta: metav1.ObjectMeta{ 2655 Name: tc.clusterName, 2656 OwnerReferences: []metav1.OwnerReference{ 2657 { 2658 APIVersion: "cluster.x-k8s.io/v1beta1", 2659 Kind: "Cluster", 2660 Name: "my-cluster", 2661 }, 2662 }, 2663 }, 2664 Spec: infrav1.AzureClusterSpec{ 2665 AzureClusterClassSpec: infrav1.AzureClusterClassSpec{ 2666 SubscriptionID: "123", 2667 IdentityRef: &corev1.ObjectReference{ 2668 Kind: infrav1.AzureClusterIdentityKind, 2669 }, 2670 }, 2671 }, 2672 } 2673 fakeIdentity := &infrav1.AzureClusterIdentity{ 2674 Spec: infrav1.AzureClusterIdentitySpec{ 2675 Type: infrav1.ServicePrincipal, 2676 ClientID: fakeClientID, 2677 TenantID: fakeTenantID, 2678 }, 2679 } 2680 fakeSecret := &corev1.Secret{Data: map[string][]byte{"clientSecret": []byte("fooSecret")}} 2681 2682 if tc.loadBalancerName != "" { 2683 azureCluster.Spec.NetworkSpec.NodeOutboundLB = &infrav1.LoadBalancerSpec{ 2684 Name: tc.loadBalancerName, 2685 } 2686 } 2687 2688 initObjects := []runtime.Object{cluster, azureCluster, fakeIdentity, fakeSecret} 2689 azureCluster.Default() 2690 2691 fakeClient := fake.NewClientBuilder().WithScheme(scheme).WithRuntimeObjects(initObjects...).Build() 2692 2693 clusterScope, err := NewClusterScope(context.TODO(), ClusterScopeParams{ 2694 Cluster: cluster, 2695 AzureCluster: azureCluster, 2696 Client: fakeClient, 2697 }) 2698 clusterScope.AzureCluster.SetBackendPoolNameDefault() 2699 g.Expect(err).NotTo(HaveOccurred()) 2700 got := clusterScope.OutboundPoolName(infrav1.Node) 2701 g.Expect(tc.expectOutboundPoolName).Should(Equal(got)) 2702 }) 2703 } 2704 } 2705 2706 func TestGenerateFQDN(t *testing.T) { 2707 tests := []struct { 2708 clusterName string 2709 ipName string 2710 subscriptionID string 2711 resourceGroup string 2712 location string 2713 expectFQDN string 2714 }{ 2715 { 2716 clusterName: "my-cluster", 2717 ipName: "172.123.45.78", 2718 subscriptionID: "123", 2719 resourceGroup: "my-rg", 2720 location: "eastus", 2721 }, 2722 { 2723 clusterName: "my-cluster-1", 2724 ipName: "172.123.45.79", 2725 subscriptionID: "567", 2726 resourceGroup: "my-rg-1", 2727 location: "westus", 2728 }, 2729 { 2730 clusterName: "my-cluster-2", 2731 ipName: "172.123.45.80", 2732 subscriptionID: "183", 2733 resourceGroup: "my-rg-2", 2734 location: "centralasia", 2735 }, 2736 } 2737 for _, tc := range tests { 2738 t.Run(tc.clusterName, func(t *testing.T) { 2739 g := NewWithT(t) 2740 scheme := runtime.NewScheme() 2741 _ = infrav1.AddToScheme(scheme) 2742 _ = clusterv1.AddToScheme(scheme) 2743 _ = corev1.AddToScheme(scheme) 2744 2745 cluster := &clusterv1.Cluster{ 2746 ObjectMeta: metav1.ObjectMeta{ 2747 Name: tc.clusterName, 2748 Namespace: "default", 2749 }, 2750 } 2751 azureCluster := &infrav1.AzureCluster{ 2752 ObjectMeta: metav1.ObjectMeta{ 2753 Name: tc.clusterName, 2754 OwnerReferences: []metav1.OwnerReference{ 2755 { 2756 APIVersion: "cluster.x-k8s.io/v1beta1", 2757 Kind: "Cluster", 2758 Name: "my-cluster", 2759 }, 2760 }, 2761 }, 2762 Spec: infrav1.AzureClusterSpec{ 2763 AzureClusterClassSpec: infrav1.AzureClusterClassSpec{ 2764 SubscriptionID: "123", 2765 Location: tc.location, 2766 IdentityRef: &corev1.ObjectReference{ 2767 Kind: infrav1.AzureClusterIdentityKind, 2768 }, 2769 }, 2770 ResourceGroup: tc.resourceGroup, 2771 }, 2772 } 2773 fakeIdentity := &infrav1.AzureClusterIdentity{ 2774 Spec: infrav1.AzureClusterIdentitySpec{ 2775 Type: infrav1.ServicePrincipal, 2776 ClientID: fakeClientID, 2777 TenantID: fakeTenantID, 2778 }, 2779 } 2780 fakeSecret := &corev1.Secret{Data: map[string][]byte{"clientSecret": []byte("fooSecret")}} 2781 2782 initObjects := []runtime.Object{cluster, azureCluster, fakeIdentity, fakeSecret} 2783 fakeClient := fake.NewClientBuilder().WithScheme(scheme).WithRuntimeObjects(initObjects...).Build() 2784 2785 clusterScope, err := NewClusterScope(context.TODO(), ClusterScopeParams{ 2786 Cluster: cluster, 2787 AzureCluster: azureCluster, 2788 Client: fakeClient, 2789 }) 2790 g.Expect(err).NotTo(HaveOccurred()) 2791 got := clusterScope.GenerateFQDN(tc.ipName) 2792 g.Expect(got).Should(ContainSubstring(tc.clusterName)) 2793 g.Expect(got).Should(ContainSubstring(tc.location)) 2794 }) 2795 } 2796 } 2797 2798 func TestAdditionalTags(t *testing.T) { 2799 tests := []struct { 2800 name string 2801 clusterName string 2802 azureClusterAdditionalTags infrav1.Tags 2803 expectTags infrav1.Tags 2804 }{ 2805 { 2806 name: "Nil tags", 2807 clusterName: "my-cluster", 2808 expectTags: infrav1.Tags{}, 2809 }, 2810 2811 { 2812 name: "Single tag present in azure cluster spec", 2813 clusterName: "my-cluster", 2814 azureClusterAdditionalTags: infrav1.Tags{ 2815 "fake-id-1": "fake-value-1", 2816 }, 2817 expectTags: infrav1.Tags{ 2818 "fake-id-1": "fake-value-1", 2819 }, 2820 }, 2821 { 2822 name: "Multiple tags present in azure cluster spec", 2823 clusterName: "my-cluster", 2824 azureClusterAdditionalTags: infrav1.Tags{ 2825 "fake-id-1": "fake-value-1", 2826 "fake-id-2": "fake-value-2", 2827 "fake-id-3": "fake-value-3", 2828 }, 2829 expectTags: infrav1.Tags{ 2830 "fake-id-1": "fake-value-1", 2831 "fake-id-2": "fake-value-2", 2832 "fake-id-3": "fake-value-3", 2833 }, 2834 }, 2835 } 2836 for _, tc := range tests { 2837 t.Run(tc.name, func(t *testing.T) { 2838 g := NewWithT(t) 2839 scheme := runtime.NewScheme() 2840 _ = infrav1.AddToScheme(scheme) 2841 _ = clusterv1.AddToScheme(scheme) 2842 _ = corev1.AddToScheme(scheme) 2843 2844 cluster := &clusterv1.Cluster{ 2845 ObjectMeta: metav1.ObjectMeta{ 2846 Name: tc.clusterName, 2847 Namespace: "default", 2848 }, 2849 } 2850 azureCluster := &infrav1.AzureCluster{ 2851 ObjectMeta: metav1.ObjectMeta{ 2852 Name: tc.clusterName, 2853 OwnerReferences: []metav1.OwnerReference{ 2854 { 2855 APIVersion: "cluster.x-k8s.io/v1beta1", 2856 Kind: "Cluster", 2857 Name: "my-cluster", 2858 }, 2859 }, 2860 }, 2861 Spec: infrav1.AzureClusterSpec{ 2862 AzureClusterClassSpec: infrav1.AzureClusterClassSpec{ 2863 SubscriptionID: "123", 2864 AdditionalTags: tc.azureClusterAdditionalTags, 2865 IdentityRef: &corev1.ObjectReference{ 2866 Kind: infrav1.AzureClusterIdentityKind, 2867 }, 2868 }, 2869 }, 2870 } 2871 fakeIdentity := &infrav1.AzureClusterIdentity{ 2872 Spec: infrav1.AzureClusterIdentitySpec{ 2873 Type: infrav1.ServicePrincipal, 2874 ClientID: fakeClientID, 2875 TenantID: fakeTenantID, 2876 }, 2877 } 2878 fakeSecret := &corev1.Secret{Data: map[string][]byte{"clientSecret": []byte("fooSecret")}} 2879 2880 initObjects := []runtime.Object{cluster, azureCluster, fakeIdentity, fakeSecret} 2881 fakeClient := fake.NewClientBuilder().WithScheme(scheme).WithRuntimeObjects(initObjects...).Build() 2882 2883 clusterScope, err := NewClusterScope(context.TODO(), ClusterScopeParams{ 2884 Cluster: cluster, 2885 AzureCluster: azureCluster, 2886 Client: fakeClient, 2887 }) 2888 g.Expect(err).NotTo(HaveOccurred()) 2889 got := clusterScope.AdditionalTags() 2890 g.Expect(tc.expectTags).Should(Equal(got)) 2891 }) 2892 } 2893 } 2894 2895 func TestAPIServerPort(t *testing.T) { 2896 tests := []struct { 2897 name string 2898 clusterName string 2899 clusterNetowrk *clusterv1.ClusterNetwork 2900 expectAPIServerPort int32 2901 }{ 2902 { 2903 name: "Nil cluster network", 2904 clusterName: "my-cluster", 2905 expectAPIServerPort: 6443, 2906 }, 2907 2908 { 2909 name: "Non nil cluster network but nil apiserverport", 2910 clusterName: "my-cluster", 2911 clusterNetowrk: &clusterv1.ClusterNetwork{}, 2912 expectAPIServerPort: 6443, 2913 }, 2914 { 2915 name: "Non nil cluster network and non nil apiserverport", 2916 clusterName: "my-cluster", 2917 clusterNetowrk: &clusterv1.ClusterNetwork{ 2918 APIServerPort: ptr.To[int32](7000), 2919 }, 2920 expectAPIServerPort: 7000, 2921 }, 2922 } 2923 for _, tc := range tests { 2924 t.Run(tc.name, func(t *testing.T) { 2925 g := NewWithT(t) 2926 scheme := runtime.NewScheme() 2927 _ = infrav1.AddToScheme(scheme) 2928 _ = clusterv1.AddToScheme(scheme) 2929 _ = corev1.AddToScheme(scheme) 2930 2931 cluster := &clusterv1.Cluster{ 2932 ObjectMeta: metav1.ObjectMeta{ 2933 Name: tc.clusterName, 2934 Namespace: "default", 2935 }, 2936 Spec: clusterv1.ClusterSpec{ 2937 ClusterNetwork: tc.clusterNetowrk, 2938 }, 2939 } 2940 azureCluster := &infrav1.AzureCluster{ 2941 ObjectMeta: metav1.ObjectMeta{ 2942 Name: tc.clusterName, 2943 OwnerReferences: []metav1.OwnerReference{ 2944 { 2945 APIVersion: "cluster.x-k8s.io/v1beta1", 2946 Kind: "Cluster", 2947 Name: "my-cluster", 2948 }, 2949 }, 2950 }, 2951 Spec: infrav1.AzureClusterSpec{ 2952 AzureClusterClassSpec: infrav1.AzureClusterClassSpec{ 2953 SubscriptionID: "123", 2954 IdentityRef: &corev1.ObjectReference{ 2955 Kind: infrav1.AzureClusterIdentityKind, 2956 }, 2957 }, 2958 }, 2959 } 2960 fakeIdentity := &infrav1.AzureClusterIdentity{ 2961 Spec: infrav1.AzureClusterIdentitySpec{ 2962 Type: infrav1.ServicePrincipal, 2963 ClientID: fakeClientID, 2964 TenantID: fakeTenantID, 2965 }, 2966 } 2967 fakeSecret := &corev1.Secret{Data: map[string][]byte{"clientSecret": []byte("fooSecret")}} 2968 2969 initObjects := []runtime.Object{cluster, azureCluster, fakeIdentity, fakeSecret} 2970 fakeClient := fake.NewClientBuilder().WithScheme(scheme).WithRuntimeObjects(initObjects...).Build() 2971 2972 clusterScope, err := NewClusterScope(context.TODO(), ClusterScopeParams{ 2973 Cluster: cluster, 2974 AzureCluster: azureCluster, 2975 Client: fakeClient, 2976 }) 2977 g.Expect(err).NotTo(HaveOccurred()) 2978 got := clusterScope.APIServerPort() 2979 g.Expect(tc.expectAPIServerPort).Should(Equal(got)) 2980 }) 2981 } 2982 } 2983 2984 func TestFailureDomains(t *testing.T) { 2985 tests := []struct { 2986 name string 2987 expectFailureDomains []*string 2988 clusterName string 2989 azureClusterStatus infrav1.AzureClusterStatus 2990 }{ 2991 { 2992 name: "Empty azure cluster status", 2993 expectFailureDomains: []*string{}, 2994 clusterName: "my-cluster", 2995 }, 2996 2997 { 2998 name: "Single failure domain present in azure cluster status", 2999 expectFailureDomains: []*string{ptr.To("failure-domain-id")}, 3000 clusterName: "my-cluster", 3001 azureClusterStatus: infrav1.AzureClusterStatus{ 3002 FailureDomains: map[string]clusterv1.FailureDomainSpec{ 3003 "failure-domain-id": {}, 3004 }, 3005 }, 3006 }, 3007 { 3008 name: "Multiple failure domains present in azure cluster status", 3009 expectFailureDomains: []*string{ptr.To("failure-domain-id-1"), ptr.To("failure-domain-id-2"), ptr.To("failure-domain-id-3")}, 3010 clusterName: "my-cluster", 3011 azureClusterStatus: infrav1.AzureClusterStatus{ 3012 FailureDomains: map[string]clusterv1.FailureDomainSpec{ 3013 "failure-domain-id-1": {}, 3014 "failure-domain-id-2": {}, 3015 "failure-domain-id-3": {}, 3016 }, 3017 }, 3018 }, 3019 } 3020 for _, tc := range tests { 3021 t.Run(tc.name, func(t *testing.T) { 3022 g := NewWithT(t) 3023 scheme := runtime.NewScheme() 3024 _ = infrav1.AddToScheme(scheme) 3025 _ = clusterv1.AddToScheme(scheme) 3026 _ = corev1.AddToScheme(scheme) 3027 3028 cluster := &clusterv1.Cluster{ 3029 ObjectMeta: metav1.ObjectMeta{ 3030 Name: tc.clusterName, 3031 Namespace: "default", 3032 }, 3033 } 3034 azureCluster := &infrav1.AzureCluster{ 3035 ObjectMeta: metav1.ObjectMeta{ 3036 Name: tc.clusterName, 3037 OwnerReferences: []metav1.OwnerReference{ 3038 { 3039 APIVersion: "cluster.x-k8s.io/v1beta1", 3040 Kind: "Cluster", 3041 Name: "my-cluster", 3042 }, 3043 }, 3044 }, 3045 Spec: infrav1.AzureClusterSpec{ 3046 AzureClusterClassSpec: infrav1.AzureClusterClassSpec{ 3047 SubscriptionID: "123", 3048 IdentityRef: &corev1.ObjectReference{ 3049 Kind: infrav1.AzureClusterIdentityKind, 3050 }, 3051 }, 3052 }, 3053 Status: tc.azureClusterStatus, 3054 } 3055 fakeIdentity := &infrav1.AzureClusterIdentity{ 3056 Spec: infrav1.AzureClusterIdentitySpec{ 3057 Type: infrav1.ServicePrincipal, 3058 ClientID: fakeClientID, 3059 TenantID: fakeTenantID, 3060 }, 3061 } 3062 fakeSecret := &corev1.Secret{Data: map[string][]byte{"clientSecret": []byte("fooSecret")}} 3063 3064 initObjects := []runtime.Object{cluster, azureCluster, fakeIdentity, fakeSecret} 3065 fakeClient := fake.NewClientBuilder().WithScheme(scheme).WithRuntimeObjects(initObjects...).Build() 3066 3067 clusterScope, err := NewClusterScope(context.TODO(), ClusterScopeParams{ 3068 Cluster: cluster, 3069 AzureCluster: azureCluster, 3070 Client: fakeClient, 3071 }) 3072 g.Expect(err).NotTo(HaveOccurred()) 3073 got := clusterScope.FailureDomains() 3074 g.Expect(tc.expectFailureDomains).Should(ConsistOf(got)) 3075 }) 3076 } 3077 } 3078 3079 func TestClusterScope_LBSpecs(t *testing.T) { 3080 tests := []struct { 3081 name string 3082 azureCluster *infrav1.AzureCluster 3083 want []azure.ResourceSpecGetter 3084 }{ 3085 { 3086 name: "API Server LB, Control Plane Oubound LB, and Node Outbound LB", 3087 azureCluster: &infrav1.AzureCluster{ 3088 ObjectMeta: metav1.ObjectMeta{ 3089 Name: "my-cluster", 3090 }, 3091 Spec: infrav1.AzureClusterSpec{ 3092 AzureClusterClassSpec: infrav1.AzureClusterClassSpec{ 3093 AdditionalTags: infrav1.Tags{ 3094 "foo": "bar", 3095 }, 3096 SubscriptionID: "123", 3097 Location: "westus2", 3098 IdentityRef: &corev1.ObjectReference{ 3099 Kind: infrav1.AzureClusterIdentityKind, 3100 }, 3101 }, 3102 ResourceGroup: "my-rg", 3103 NetworkSpec: infrav1.NetworkSpec{ 3104 Vnet: infrav1.VnetSpec{ 3105 Name: "my-vnet", 3106 ResourceGroup: "my-rg", 3107 }, 3108 Subnets: []infrav1.SubnetSpec{ 3109 { 3110 SubnetClassSpec: infrav1.SubnetClassSpec{ 3111 Name: "cp-subnet", 3112 Role: infrav1.SubnetControlPlane, 3113 }, 3114 }, 3115 { 3116 SubnetClassSpec: infrav1.SubnetClassSpec{ 3117 Name: "node-subnet", 3118 Role: infrav1.SubnetNode, 3119 }, 3120 }, 3121 }, 3122 APIServerLB: infrav1.LoadBalancerSpec{ 3123 Name: "api-server-lb", 3124 BackendPool: infrav1.BackendPool{ 3125 Name: "api-server-lb-backend-pool", 3126 }, 3127 LoadBalancerClassSpec: infrav1.LoadBalancerClassSpec{ 3128 Type: infrav1.Public, 3129 IdleTimeoutInMinutes: ptr.To[int32](30), 3130 SKU: infrav1.SKUStandard, 3131 }, 3132 FrontendIPs: []infrav1.FrontendIP{ 3133 { 3134 Name: "api-server-lb-frontend-ip", 3135 PublicIP: &infrav1.PublicIPSpec{ 3136 Name: "api-server-lb-frontend-ip", 3137 }, 3138 }, 3139 }, 3140 }, 3141 ControlPlaneOutboundLB: &infrav1.LoadBalancerSpec{ 3142 Name: "cp-outbound-lb", 3143 BackendPool: infrav1.BackendPool{ 3144 Name: "cp-outbound-backend-pool", 3145 }, 3146 LoadBalancerClassSpec: infrav1.LoadBalancerClassSpec{ 3147 Type: infrav1.Public, 3148 IdleTimeoutInMinutes: ptr.To[int32](15), 3149 SKU: infrav1.SKUStandard, 3150 }, 3151 FrontendIPs: []infrav1.FrontendIP{ 3152 { 3153 Name: "cp-outbound-lb-frontend-ip", 3154 PublicIP: &infrav1.PublicIPSpec{ 3155 Name: "cp-outbound-lb-frontend-ip", 3156 }, 3157 }, 3158 }, 3159 }, 3160 NodeOutboundLB: &infrav1.LoadBalancerSpec{ 3161 Name: "node-outbound-lb", 3162 BackendPool: infrav1.BackendPool{ 3163 Name: "node-outbound-backend-pool", 3164 }, 3165 LoadBalancerClassSpec: infrav1.LoadBalancerClassSpec{ 3166 Type: infrav1.Public, 3167 IdleTimeoutInMinutes: ptr.To[int32](50), 3168 SKU: infrav1.SKUStandard, 3169 }, 3170 FrontendIPs: []infrav1.FrontendIP{ 3171 { 3172 Name: "node-outbound-lb-frontend-ip", 3173 PublicIP: &infrav1.PublicIPSpec{ 3174 Name: "node-outbound-lb-frontend-ip", 3175 }, 3176 }, 3177 }, 3178 }, 3179 }, 3180 }, 3181 }, 3182 want: []azure.ResourceSpecGetter{ 3183 &loadbalancers.LBSpec{ 3184 Name: "api-server-lb", 3185 ResourceGroup: "my-rg", 3186 SubscriptionID: "123", 3187 ClusterName: "my-cluster", 3188 Location: "westus2", 3189 VNetName: "my-vnet", 3190 VNetResourceGroup: "my-rg", 3191 SubnetName: "cp-subnet", 3192 FrontendIPConfigs: []infrav1.FrontendIP{ 3193 { 3194 Name: "api-server-lb-frontend-ip", 3195 PublicIP: &infrav1.PublicIPSpec{ 3196 Name: "api-server-lb-frontend-ip", 3197 }, 3198 }, 3199 }, 3200 APIServerPort: 6443, 3201 Type: infrav1.Public, 3202 SKU: infrav1.SKUStandard, 3203 Role: infrav1.APIServerRole, 3204 BackendPoolName: "api-server-lb-backend-pool", 3205 IdleTimeoutInMinutes: ptr.To[int32](30), 3206 AdditionalTags: infrav1.Tags{ 3207 "foo": "bar", 3208 }, 3209 }, 3210 &loadbalancers.LBSpec{ 3211 Name: "node-outbound-lb", 3212 ResourceGroup: "my-rg", 3213 SubscriptionID: "123", 3214 ClusterName: "my-cluster", 3215 Location: "westus2", 3216 VNetName: "my-vnet", 3217 VNetResourceGroup: "my-rg", 3218 FrontendIPConfigs: []infrav1.FrontendIP{ 3219 { 3220 Name: "node-outbound-lb-frontend-ip", 3221 PublicIP: &infrav1.PublicIPSpec{ 3222 Name: "node-outbound-lb-frontend-ip", 3223 }, 3224 }, 3225 }, 3226 Type: infrav1.Public, 3227 SKU: infrav1.SKUStandard, 3228 Role: infrav1.NodeOutboundRole, 3229 BackendPoolName: "node-outbound-backend-pool", 3230 IdleTimeoutInMinutes: ptr.To[int32](50), 3231 AdditionalTags: infrav1.Tags{ 3232 "foo": "bar", 3233 }, 3234 }, 3235 &loadbalancers.LBSpec{ 3236 Name: "cp-outbound-lb", 3237 ResourceGroup: "my-rg", 3238 SubscriptionID: "123", 3239 ClusterName: "my-cluster", 3240 Location: "westus2", 3241 VNetName: "my-vnet", 3242 VNetResourceGroup: "my-rg", 3243 FrontendIPConfigs: []infrav1.FrontendIP{ 3244 { 3245 Name: "cp-outbound-lb-frontend-ip", 3246 PublicIP: &infrav1.PublicIPSpec{ 3247 Name: "cp-outbound-lb-frontend-ip", 3248 }, 3249 }, 3250 }, 3251 Type: infrav1.Public, 3252 SKU: infrav1.SKUStandard, 3253 BackendPoolName: "cp-outbound-backend-pool", 3254 IdleTimeoutInMinutes: ptr.To[int32](15), 3255 Role: infrav1.ControlPlaneOutboundRole, 3256 AdditionalTags: infrav1.Tags{ 3257 "foo": "bar", 3258 }, 3259 }, 3260 }, 3261 }, 3262 { 3263 name: "Private API Server LB", 3264 azureCluster: &infrav1.AzureCluster{ 3265 ObjectMeta: metav1.ObjectMeta{ 3266 Name: "my-cluster", 3267 }, 3268 Spec: infrav1.AzureClusterSpec{ 3269 AzureClusterClassSpec: infrav1.AzureClusterClassSpec{ 3270 SubscriptionID: "123", 3271 Location: "westus2", 3272 IdentityRef: &corev1.ObjectReference{ 3273 Kind: infrav1.AzureClusterIdentityKind, 3274 }, 3275 }, 3276 ResourceGroup: "my-rg", 3277 NetworkSpec: infrav1.NetworkSpec{ 3278 Vnet: infrav1.VnetSpec{ 3279 Name: "my-vnet", 3280 ResourceGroup: "my-rg", 3281 }, 3282 Subnets: []infrav1.SubnetSpec{ 3283 { 3284 SubnetClassSpec: infrav1.SubnetClassSpec{ 3285 Name: "cp-subnet", 3286 Role: infrav1.SubnetControlPlane, 3287 }, 3288 }, 3289 { 3290 SubnetClassSpec: infrav1.SubnetClassSpec{ 3291 Name: "node-subnet", 3292 Role: infrav1.SubnetNode, 3293 }, 3294 }, 3295 }, 3296 APIServerLB: infrav1.LoadBalancerSpec{ 3297 Name: "api-server-lb", 3298 BackendPool: infrav1.BackendPool{ 3299 Name: "api-server-lb-backend-pool", 3300 }, 3301 LoadBalancerClassSpec: infrav1.LoadBalancerClassSpec{ 3302 Type: infrav1.Internal, 3303 IdleTimeoutInMinutes: ptr.To[int32](30), 3304 SKU: infrav1.SKUStandard, 3305 }, 3306 }, 3307 }, 3308 }, 3309 }, 3310 want: []azure.ResourceSpecGetter{ 3311 &loadbalancers.LBSpec{ 3312 Name: "api-server-lb", 3313 ResourceGroup: "my-rg", 3314 SubscriptionID: "123", 3315 ClusterName: "my-cluster", 3316 Location: "westus2", 3317 VNetName: "my-vnet", 3318 VNetResourceGroup: "my-rg", 3319 SubnetName: "cp-subnet", 3320 APIServerPort: 6443, 3321 Type: infrav1.Internal, 3322 SKU: infrav1.SKUStandard, 3323 Role: infrav1.APIServerRole, 3324 BackendPoolName: "api-server-lb-backend-pool", 3325 IdleTimeoutInMinutes: ptr.To[int32](30), 3326 AdditionalTags: infrav1.Tags{}, 3327 }, 3328 }, 3329 }, 3330 } 3331 for _, tc := range tests { 3332 tc := tc 3333 t.Run(tc.name, func(t *testing.T) { 3334 t.Parallel() 3335 g := NewWithT(t) 3336 scheme := runtime.NewScheme() 3337 _ = infrav1.AddToScheme(scheme) 3338 _ = clusterv1.AddToScheme(scheme) 3339 _ = corev1.AddToScheme(scheme) 3340 3341 cluster := &clusterv1.Cluster{ 3342 ObjectMeta: metav1.ObjectMeta{ 3343 Name: tc.azureCluster.Name, 3344 Namespace: "default", 3345 }, 3346 } 3347 fakeIdentity := &infrav1.AzureClusterIdentity{ 3348 Spec: infrav1.AzureClusterIdentitySpec{ 3349 Type: infrav1.ServicePrincipal, 3350 ClientID: fakeClientID, 3351 TenantID: fakeTenantID, 3352 }, 3353 } 3354 fakeSecret := &corev1.Secret{Data: map[string][]byte{"clientSecret": []byte("fooSecret")}} 3355 3356 initObjects := []runtime.Object{cluster, tc.azureCluster, fakeIdentity, fakeSecret} 3357 fakeClient := fake.NewClientBuilder().WithScheme(scheme).WithRuntimeObjects(initObjects...).Build() 3358 3359 clusterScope, err := NewClusterScope(context.TODO(), ClusterScopeParams{ 3360 Cluster: cluster, 3361 AzureCluster: tc.azureCluster, 3362 Client: fakeClient, 3363 }) 3364 g.Expect(err).NotTo(HaveOccurred()) 3365 if got := clusterScope.LBSpecs(); !reflect.DeepEqual(got, tc.want) { 3366 t.Errorf("LBSpecs() diff between expected result and actual result (%v): %s", got, cmp.Diff(tc.want, got)) 3367 } 3368 }) 3369 } 3370 } 3371 3372 func TestExtendedLocationName(t *testing.T) { 3373 tests := []struct { 3374 name string 3375 clusterName string 3376 extendedLocation infrav1.ExtendedLocationSpec 3377 }{ 3378 { 3379 name: "Empty extendedLocatioName", 3380 clusterName: "my-cluster", 3381 extendedLocation: infrav1.ExtendedLocationSpec{ 3382 Name: "", 3383 Type: "", 3384 }, 3385 }, 3386 { 3387 name: "Non empty extendedLocationName", 3388 clusterName: "my-cluster", 3389 extendedLocation: infrav1.ExtendedLocationSpec{ 3390 Name: "ex-loc-name", 3391 Type: "ex-loc-type", 3392 }, 3393 }, 3394 } 3395 for _, tc := range tests { 3396 t.Run(tc.name, func(t *testing.T) { 3397 g := NewWithT(t) 3398 scheme := runtime.NewScheme() 3399 _ = infrav1.AddToScheme(scheme) 3400 _ = clusterv1.AddToScheme(scheme) 3401 _ = corev1.AddToScheme(scheme) 3402 3403 cluster := &clusterv1.Cluster{ 3404 ObjectMeta: metav1.ObjectMeta{ 3405 Name: tc.clusterName, 3406 Namespace: "default", 3407 }, 3408 } 3409 3410 azureCluster := &infrav1.AzureCluster{ 3411 ObjectMeta: metav1.ObjectMeta{ 3412 Name: tc.clusterName, 3413 OwnerReferences: []metav1.OwnerReference{ 3414 { 3415 APIVersion: "cluster.x-k8s.io/v1beta1", 3416 Kind: "Cluster", 3417 Name: "my-cluster", 3418 }, 3419 }, 3420 }, 3421 Spec: infrav1.AzureClusterSpec{ 3422 AzureClusterClassSpec: infrav1.AzureClusterClassSpec{ 3423 SubscriptionID: "123", 3424 ExtendedLocation: &infrav1.ExtendedLocationSpec{ 3425 Name: tc.extendedLocation.Name, 3426 Type: tc.extendedLocation.Type, 3427 }, 3428 IdentityRef: &corev1.ObjectReference{ 3429 Kind: infrav1.AzureClusterIdentityKind, 3430 }, 3431 }, 3432 }, 3433 } 3434 fakeIdentity := &infrav1.AzureClusterIdentity{ 3435 Spec: infrav1.AzureClusterIdentitySpec{ 3436 Type: infrav1.ServicePrincipal, 3437 ClientID: fakeClientID, 3438 TenantID: fakeTenantID, 3439 }, 3440 } 3441 fakeSecret := &corev1.Secret{Data: map[string][]byte{"clientSecret": []byte("fooSecret")}} 3442 3443 initObjects := []runtime.Object{cluster, azureCluster, fakeIdentity, fakeSecret} 3444 fakeClient := fake.NewClientBuilder().WithScheme(scheme).WithRuntimeObjects(initObjects...).Build() 3445 3446 clusterScope, err := NewClusterScope(context.TODO(), ClusterScopeParams{ 3447 Cluster: cluster, 3448 AzureCluster: azureCluster, 3449 Client: fakeClient, 3450 }) 3451 3452 g.Expect(err).NotTo(HaveOccurred()) 3453 got := clusterScope.ExtendedLocationName() 3454 g.Expect(tc.extendedLocation.Name).Should(Equal(got)) 3455 }) 3456 } 3457 } 3458 3459 func TestExtendedLocationType(t *testing.T) { 3460 tests := []struct { 3461 name string 3462 clusterName string 3463 extendedLocation infrav1.ExtendedLocationSpec 3464 }{ 3465 { 3466 name: "Empty extendedLocatioType", 3467 clusterName: "my-cluster", 3468 extendedLocation: infrav1.ExtendedLocationSpec{ 3469 Name: "", 3470 Type: "", 3471 }, 3472 }, 3473 { 3474 name: "Non empty extendedLocationType", 3475 clusterName: "my-cluster", 3476 extendedLocation: infrav1.ExtendedLocationSpec{ 3477 Name: "ex-loc-name", 3478 Type: "ex-loc-type", 3479 }, 3480 }, 3481 } 3482 for _, tc := range tests { 3483 t.Run(tc.name, func(t *testing.T) { 3484 g := NewWithT(t) 3485 scheme := runtime.NewScheme() 3486 _ = infrav1.AddToScheme(scheme) 3487 _ = clusterv1.AddToScheme(scheme) 3488 _ = corev1.AddToScheme(scheme) 3489 3490 cluster := &clusterv1.Cluster{ 3491 ObjectMeta: metav1.ObjectMeta{ 3492 Name: tc.clusterName, 3493 Namespace: "default", 3494 }, 3495 } 3496 3497 azureCluster := &infrav1.AzureCluster{ 3498 ObjectMeta: metav1.ObjectMeta{ 3499 Name: tc.clusterName, 3500 OwnerReferences: []metav1.OwnerReference{ 3501 { 3502 APIVersion: "cluster.x-k8s.io/v1beta1", 3503 Kind: "Cluster", 3504 Name: "my-cluster", 3505 }, 3506 }, 3507 }, 3508 Spec: infrav1.AzureClusterSpec{ 3509 AzureClusterClassSpec: infrav1.AzureClusterClassSpec{ 3510 SubscriptionID: "123", 3511 ExtendedLocation: &infrav1.ExtendedLocationSpec{ 3512 Name: tc.extendedLocation.Name, 3513 Type: tc.extendedLocation.Type, 3514 }, 3515 IdentityRef: &corev1.ObjectReference{ 3516 Kind: infrav1.AzureClusterIdentityKind, 3517 }, 3518 }, 3519 }, 3520 } 3521 fakeIdentity := &infrav1.AzureClusterIdentity{ 3522 Spec: infrav1.AzureClusterIdentitySpec{ 3523 Type: infrav1.ServicePrincipal, 3524 ClientID: fakeClientID, 3525 TenantID: fakeTenantID, 3526 }, 3527 } 3528 fakeSecret := &corev1.Secret{Data: map[string][]byte{"clientSecret": []byte("fooSecret")}} 3529 3530 initObjects := []runtime.Object{cluster, azureCluster, fakeIdentity, fakeSecret} 3531 fakeClient := fake.NewClientBuilder().WithScheme(scheme).WithRuntimeObjects(initObjects...).Build() 3532 3533 clusterScope, err := NewClusterScope(context.TODO(), ClusterScopeParams{ 3534 Cluster: cluster, 3535 AzureCluster: azureCluster, 3536 Client: fakeClient, 3537 }) 3538 3539 g.Expect(err).NotTo(HaveOccurred()) 3540 got := clusterScope.ExtendedLocationType() 3541 g.Expect(tc.extendedLocation.Type).Should(Equal(got)) 3542 }) 3543 } 3544 } 3545 3546 func TestVNetPeerings(t *testing.T) { 3547 fakeSubscriptionID := "123" 3548 3549 tests := []struct { 3550 name string 3551 subscriptionID string 3552 azureClusterVNetSpec infrav1.VnetSpec 3553 want []azure.ResourceSpecGetter 3554 }{ 3555 { 3556 name: "VNet peerings are not specified", 3557 subscriptionID: fakeSubscriptionID, 3558 azureClusterVNetSpec: infrav1.VnetSpec{ 3559 ResourceGroup: "rg1", 3560 Name: "vnet1", 3561 }, 3562 want: []azure.ResourceSpecGetter{}, 3563 }, 3564 { 3565 name: "One VNet peering is specified", 3566 subscriptionID: fakeSubscriptionID, 3567 azureClusterVNetSpec: infrav1.VnetSpec{ 3568 ResourceGroup: "rg1", 3569 Name: "vnet1", 3570 Peerings: infrav1.VnetPeerings{ 3571 { 3572 VnetPeeringClassSpec: infrav1.VnetPeeringClassSpec{ 3573 ResourceGroup: "rg2", 3574 RemoteVnetName: "vnet2", 3575 }, 3576 }, 3577 }, 3578 }, 3579 want: []azure.ResourceSpecGetter{ 3580 &vnetpeerings.VnetPeeringSpec{ 3581 PeeringName: "vnet1-To-vnet2", 3582 SourceResourceGroup: "rg1", 3583 SourceVnetName: "vnet1", 3584 RemoteResourceGroup: "rg2", 3585 RemoteVnetName: "vnet2", 3586 SubscriptionID: fakeSubscriptionID, 3587 }, 3588 &vnetpeerings.VnetPeeringSpec{ 3589 PeeringName: "vnet2-To-vnet1", 3590 SourceResourceGroup: "rg2", 3591 SourceVnetName: "vnet2", 3592 RemoteResourceGroup: "rg1", 3593 RemoteVnetName: "vnet1", 3594 SubscriptionID: fakeSubscriptionID, 3595 }, 3596 }, 3597 }, 3598 { 3599 name: "One VNet peering with optional properties is specified", 3600 subscriptionID: fakeSubscriptionID, 3601 azureClusterVNetSpec: infrav1.VnetSpec{ 3602 ResourceGroup: "rg1", 3603 Name: "vnet1", 3604 Peerings: infrav1.VnetPeerings{ 3605 { 3606 VnetPeeringClassSpec: infrav1.VnetPeeringClassSpec{ 3607 ResourceGroup: "rg2", 3608 RemoteVnetName: "vnet2", 3609 ForwardPeeringProperties: infrav1.VnetPeeringProperties{ 3610 AllowForwardedTraffic: ptr.To(true), 3611 AllowGatewayTransit: ptr.To(false), 3612 UseRemoteGateways: ptr.To(true), 3613 }, 3614 ReversePeeringProperties: infrav1.VnetPeeringProperties{ 3615 AllowForwardedTraffic: ptr.To(true), 3616 AllowGatewayTransit: ptr.To(true), 3617 UseRemoteGateways: ptr.To(false), 3618 }, 3619 }, 3620 }, 3621 }, 3622 }, 3623 want: []azure.ResourceSpecGetter{ 3624 &vnetpeerings.VnetPeeringSpec{ 3625 PeeringName: "vnet1-To-vnet2", 3626 SourceResourceGroup: "rg1", 3627 SourceVnetName: "vnet1", 3628 RemoteResourceGroup: "rg2", 3629 RemoteVnetName: "vnet2", 3630 SubscriptionID: fakeSubscriptionID, 3631 AllowForwardedTraffic: ptr.To(true), 3632 AllowGatewayTransit: ptr.To(false), 3633 UseRemoteGateways: ptr.To(true), 3634 }, 3635 &vnetpeerings.VnetPeeringSpec{ 3636 PeeringName: "vnet2-To-vnet1", 3637 SourceResourceGroup: "rg2", 3638 SourceVnetName: "vnet2", 3639 RemoteResourceGroup: "rg1", 3640 RemoteVnetName: "vnet1", 3641 SubscriptionID: fakeSubscriptionID, 3642 AllowForwardedTraffic: ptr.To(true), 3643 AllowGatewayTransit: ptr.To(true), 3644 UseRemoteGateways: ptr.To(false), 3645 }, 3646 }, 3647 }, 3648 { 3649 name: "Two VNet peerings are specified", 3650 subscriptionID: fakeSubscriptionID, 3651 azureClusterVNetSpec: infrav1.VnetSpec{ 3652 ResourceGroup: "rg1", 3653 Name: "vnet1", 3654 Peerings: infrav1.VnetPeerings{ 3655 { 3656 VnetPeeringClassSpec: infrav1.VnetPeeringClassSpec{ 3657 ResourceGroup: "rg2", 3658 RemoteVnetName: "vnet2", 3659 ForwardPeeringProperties: infrav1.VnetPeeringProperties{ 3660 AllowForwardedTraffic: ptr.To(true), 3661 AllowGatewayTransit: ptr.To(false), 3662 UseRemoteGateways: ptr.To(true), 3663 }, 3664 ReversePeeringProperties: infrav1.VnetPeeringProperties{ 3665 AllowForwardedTraffic: ptr.To(true), 3666 AllowGatewayTransit: ptr.To(true), 3667 UseRemoteGateways: ptr.To(false), 3668 }, 3669 }, 3670 }, 3671 { 3672 VnetPeeringClassSpec: infrav1.VnetPeeringClassSpec{ 3673 ResourceGroup: "rg3", 3674 RemoteVnetName: "vnet3", 3675 }, 3676 }, 3677 }, 3678 }, 3679 want: []azure.ResourceSpecGetter{ 3680 &vnetpeerings.VnetPeeringSpec{ 3681 PeeringName: "vnet1-To-vnet2", 3682 SourceResourceGroup: "rg1", 3683 SourceVnetName: "vnet1", 3684 RemoteResourceGroup: "rg2", 3685 RemoteVnetName: "vnet2", 3686 SubscriptionID: fakeSubscriptionID, 3687 AllowForwardedTraffic: ptr.To(true), 3688 AllowGatewayTransit: ptr.To(false), 3689 UseRemoteGateways: ptr.To(true), 3690 }, 3691 &vnetpeerings.VnetPeeringSpec{ 3692 PeeringName: "vnet2-To-vnet1", 3693 SourceResourceGroup: "rg2", 3694 SourceVnetName: "vnet2", 3695 RemoteResourceGroup: "rg1", 3696 RemoteVnetName: "vnet1", 3697 SubscriptionID: fakeSubscriptionID, 3698 AllowForwardedTraffic: ptr.To(true), 3699 AllowGatewayTransit: ptr.To(true), 3700 UseRemoteGateways: ptr.To(false), 3701 }, 3702 &vnetpeerings.VnetPeeringSpec{ 3703 PeeringName: "vnet1-To-vnet3", 3704 SourceResourceGroup: "rg1", 3705 SourceVnetName: "vnet1", 3706 RemoteResourceGroup: "rg3", 3707 RemoteVnetName: "vnet3", 3708 SubscriptionID: fakeSubscriptionID, 3709 }, 3710 &vnetpeerings.VnetPeeringSpec{ 3711 PeeringName: "vnet3-To-vnet1", 3712 SourceResourceGroup: "rg3", 3713 SourceVnetName: "vnet3", 3714 RemoteResourceGroup: "rg1", 3715 RemoteVnetName: "vnet1", 3716 SubscriptionID: fakeSubscriptionID, 3717 }, 3718 }, 3719 }, 3720 } 3721 3722 for _, tc := range tests { 3723 t.Run(tc.name, func(t *testing.T) { 3724 g := NewWithT(t) 3725 scheme := runtime.NewScheme() 3726 _ = infrav1.AddToScheme(scheme) 3727 _ = clusterv1.AddToScheme(scheme) 3728 _ = corev1.AddToScheme(scheme) 3729 3730 clusterName := "my-cluster" 3731 clusterNamespace := "default" 3732 3733 cluster := &clusterv1.Cluster{ 3734 ObjectMeta: metav1.ObjectMeta{ 3735 Name: clusterName, 3736 Namespace: clusterNamespace, 3737 }, 3738 } 3739 azureCluster := &infrav1.AzureCluster{ 3740 ObjectMeta: metav1.ObjectMeta{ 3741 Name: clusterName, 3742 Namespace: clusterNamespace, 3743 OwnerReferences: []metav1.OwnerReference{ 3744 { 3745 APIVersion: "cluster.x-k8s.io/v1beta1", 3746 Kind: "Cluster", 3747 Name: clusterName, 3748 }, 3749 }, 3750 }, 3751 Spec: infrav1.AzureClusterSpec{ 3752 ResourceGroup: "rg1", 3753 AzureClusterClassSpec: infrav1.AzureClusterClassSpec{ 3754 SubscriptionID: tc.subscriptionID, 3755 IdentityRef: &corev1.ObjectReference{ 3756 Kind: infrav1.AzureClusterIdentityKind, 3757 Namespace: clusterNamespace, 3758 }, 3759 }, 3760 NetworkSpec: infrav1.NetworkSpec{ 3761 Vnet: tc.azureClusterVNetSpec, 3762 }, 3763 }, 3764 } 3765 fakeIdentity := &infrav1.AzureClusterIdentity{ 3766 ObjectMeta: metav1.ObjectMeta{ 3767 Namespace: clusterNamespace, 3768 }, 3769 Spec: infrav1.AzureClusterIdentitySpec{ 3770 Type: infrav1.ServicePrincipal, 3771 ClientID: fakeClientID, 3772 TenantID: fakeTenantID, 3773 }, 3774 } 3775 fakeSecret := &corev1.Secret{Data: map[string][]byte{"clientSecret": []byte("fooSecret")}} 3776 3777 initObjects := []runtime.Object{cluster, azureCluster, fakeIdentity, fakeSecret} 3778 fakeClient := fake.NewClientBuilder().WithScheme(scheme).WithRuntimeObjects(initObjects...).Build() 3779 3780 clusterScope, err := NewClusterScope(context.TODO(), ClusterScopeParams{ 3781 Cluster: cluster, 3782 AzureCluster: azureCluster, 3783 Client: fakeClient, 3784 }) 3785 g.Expect(err).NotTo(HaveOccurred()) 3786 got := clusterScope.VnetPeeringSpecs() 3787 g.Expect(tc.want).To(Equal(got)) 3788 }) 3789 } 3790 } 3791 3792 func TestPrivateEndpointSpecs(t *testing.T) { 3793 tests := []struct { 3794 name string 3795 clusterScope ClusterScope 3796 want []azure.ASOResourceSpecGetter[*asonetworkv1api20220701.PrivateEndpoint] 3797 }{ 3798 { 3799 name: "returns empty private endpoints list if no subnets are specified", 3800 clusterScope: ClusterScope{ 3801 AzureCluster: &infrav1.AzureCluster{ 3802 Spec: infrav1.AzureClusterSpec{ 3803 NetworkSpec: infrav1.NetworkSpec{ 3804 Subnets: infrav1.Subnets{}, 3805 }, 3806 }, 3807 }, 3808 cache: &ClusterCache{}, 3809 }, 3810 want: make([]azure.ASOResourceSpecGetter[*asonetworkv1api20220701.PrivateEndpoint], 0), 3811 }, 3812 { 3813 name: "returns empty private endpoints list if no private endpoints are specified", 3814 clusterScope: ClusterScope{ 3815 AzureCluster: &infrav1.AzureCluster{ 3816 Spec: infrav1.AzureClusterSpec{ 3817 NetworkSpec: infrav1.NetworkSpec{ 3818 Subnets: []infrav1.SubnetSpec{ 3819 { 3820 SubnetClassSpec: infrav1.SubnetClassSpec{ 3821 PrivateEndpoints: infrav1.PrivateEndpoints{}, 3822 }, 3823 }, 3824 }, 3825 }, 3826 }, 3827 }, 3828 cache: &ClusterCache{}, 3829 }, 3830 want: make([]azure.ASOResourceSpecGetter[*asonetworkv1api20220701.PrivateEndpoint], 0), 3831 }, 3832 { 3833 name: "returns list of private endpoint specs if private endpoints are specified", 3834 clusterScope: ClusterScope{ 3835 Cluster: &clusterv1.Cluster{ 3836 ObjectMeta: metav1.ObjectMeta{ 3837 Name: "my-cluster", 3838 Namespace: "dummy-ns", 3839 }, 3840 }, 3841 AzureCluster: &infrav1.AzureCluster{ 3842 Spec: infrav1.AzureClusterSpec{ 3843 ResourceGroup: "dummy-rg", 3844 NetworkSpec: infrav1.NetworkSpec{ 3845 Subnets: []infrav1.SubnetSpec{ 3846 { 3847 ID: "dummy-subnet-id", 3848 SubnetClassSpec: infrav1.SubnetClassSpec{ 3849 PrivateEndpoints: []infrav1.PrivateEndpointSpec{ 3850 { 3851 Name: "my-private-endpoint", 3852 Location: "westus2", 3853 CustomNetworkInterfaceName: "my-custom-nic", 3854 PrivateIPAddresses: []string{ 3855 "IP1", 3856 "IP2", 3857 }, 3858 ApplicationSecurityGroups: []string{ 3859 "ASG1", 3860 "ASG2", 3861 }, 3862 PrivateLinkServiceConnections: []infrav1.PrivateLinkServiceConnection{ 3863 { 3864 Name: "my-pls-connection", 3865 RequestMessage: "my-request-message", 3866 PrivateLinkServiceID: "my-pls-id", 3867 GroupIDs: []string{ 3868 "my-group-id-1", 3869 }, 3870 }, 3871 }, 3872 }, 3873 { 3874 Name: "my-private-endpoint-2", 3875 Location: "westus2", 3876 CustomNetworkInterfaceName: "my-custom-nic-2", 3877 PrivateIPAddresses: []string{ 3878 "IP3", 3879 "IP4", 3880 }, 3881 ApplicationSecurityGroups: []string{ 3882 "ASG3", 3883 "ASG4", 3884 }, 3885 PrivateLinkServiceConnections: []infrav1.PrivateLinkServiceConnection{ 3886 { 3887 Name: "my-pls-connection", 3888 RequestMessage: "my-request-message", 3889 PrivateLinkServiceID: "my-pls-id", 3890 GroupIDs: []string{ 3891 "my-group-id-1", 3892 }, 3893 }, 3894 }, 3895 }, 3896 }, 3897 }, 3898 }, 3899 { 3900 ID: "dummy-subnet-id-2", 3901 SubnetClassSpec: infrav1.SubnetClassSpec{ 3902 PrivateEndpoints: []infrav1.PrivateEndpointSpec{ 3903 { 3904 Name: "my-private-endpoint-3", 3905 Location: "westus2", 3906 CustomNetworkInterfaceName: "my-custom-nic-3", 3907 PrivateIPAddresses: []string{ 3908 "IP5", 3909 "IP6", 3910 }, 3911 ApplicationSecurityGroups: []string{ 3912 "ASG5", 3913 "ASG6", 3914 }, 3915 PrivateLinkServiceConnections: []infrav1.PrivateLinkServiceConnection{ 3916 { 3917 Name: "my-pls-connection", 3918 RequestMessage: "my-request-message", 3919 PrivateLinkServiceID: "my-pls-id", 3920 GroupIDs: []string{ 3921 "my-group-id-1", 3922 }, 3923 }, 3924 }, 3925 }, 3926 }, 3927 }, 3928 }, 3929 }, 3930 }, 3931 }, 3932 }, 3933 cache: &ClusterCache{}, 3934 }, 3935 want: []azure.ASOResourceSpecGetter[*asonetworkv1api20220701.PrivateEndpoint]{ 3936 &privateendpoints.PrivateEndpointSpec{ 3937 Name: "my-private-endpoint", 3938 ResourceGroup: "dummy-rg", 3939 Location: "westus2", 3940 CustomNetworkInterfaceName: "my-custom-nic", 3941 PrivateIPAddresses: []string{ 3942 "IP1", 3943 "IP2", 3944 }, 3945 SubnetID: "dummy-subnet-id", 3946 ApplicationSecurityGroups: []string{ 3947 "ASG1", 3948 "ASG2", 3949 }, 3950 ClusterName: "my-cluster", 3951 PrivateLinkServiceConnections: []privateendpoints.PrivateLinkServiceConnection{ 3952 { 3953 Name: "my-pls-connection", 3954 RequestMessage: "my-request-message", 3955 PrivateLinkServiceID: "my-pls-id", 3956 GroupIDs: []string{ 3957 "my-group-id-1", 3958 }, 3959 }, 3960 }, 3961 AdditionalTags: make(infrav1.Tags, 0), 3962 }, 3963 &privateendpoints.PrivateEndpointSpec{ 3964 Name: "my-private-endpoint-2", 3965 ResourceGroup: "dummy-rg", 3966 Location: "westus2", 3967 CustomNetworkInterfaceName: "my-custom-nic-2", 3968 PrivateIPAddresses: []string{ 3969 "IP3", 3970 "IP4", 3971 }, 3972 SubnetID: "dummy-subnet-id", 3973 ApplicationSecurityGroups: []string{ 3974 "ASG3", 3975 "ASG4", 3976 }, 3977 ClusterName: "my-cluster", 3978 PrivateLinkServiceConnections: []privateendpoints.PrivateLinkServiceConnection{ 3979 { 3980 Name: "my-pls-connection", 3981 RequestMessage: "my-request-message", 3982 PrivateLinkServiceID: "my-pls-id", 3983 GroupIDs: []string{ 3984 "my-group-id-1", 3985 }, 3986 }, 3987 }, 3988 AdditionalTags: make(infrav1.Tags, 0), 3989 }, 3990 &privateendpoints.PrivateEndpointSpec{ 3991 Name: "my-private-endpoint-3", 3992 ResourceGroup: "dummy-rg", 3993 Location: "westus2", 3994 CustomNetworkInterfaceName: "my-custom-nic-3", 3995 PrivateIPAddresses: []string{ 3996 "IP5", 3997 "IP6", 3998 }, 3999 SubnetID: "dummy-subnet-id-2", 4000 ApplicationSecurityGroups: []string{ 4001 "ASG5", 4002 "ASG6", 4003 }, 4004 ClusterName: "my-cluster", 4005 PrivateLinkServiceConnections: []privateendpoints.PrivateLinkServiceConnection{ 4006 { 4007 Name: "my-pls-connection", 4008 RequestMessage: "my-request-message", 4009 PrivateLinkServiceID: "my-pls-id", 4010 GroupIDs: []string{ 4011 "my-group-id-1", 4012 }, 4013 }, 4014 }, 4015 AdditionalTags: make(infrav1.Tags, 0), 4016 }, 4017 }, 4018 }, 4019 } 4020 4021 for _, tt := range tests { 4022 tt := tt 4023 t.Run(tt.name, func(t *testing.T) { 4024 t.Parallel() 4025 if got := tt.clusterScope.PrivateEndpointSpecs(); !reflect.DeepEqual(got, tt.want) { 4026 t.Errorf("PrivateEndpointSpecs() = %s, want %s", specArrayToString(got), specArrayToString(tt.want)) 4027 } 4028 }) 4029 } 4030 } 4031 4032 func TestSetFailureDomain(t *testing.T) { 4033 t.Parallel() 4034 4035 cases := map[string]struct { 4036 discoveredFDs clusterv1.FailureDomains 4037 specifiedFDs clusterv1.FailureDomains 4038 expectedFDs clusterv1.FailureDomains 4039 }{ 4040 "no failure domains specified": { 4041 discoveredFDs: clusterv1.FailureDomains{ 4042 "fd1": clusterv1.FailureDomainSpec{ControlPlane: true}, 4043 "fd2": clusterv1.FailureDomainSpec{ControlPlane: false}, 4044 }, 4045 expectedFDs: clusterv1.FailureDomains{ 4046 "fd1": clusterv1.FailureDomainSpec{ControlPlane: true}, 4047 "fd2": clusterv1.FailureDomainSpec{ControlPlane: false}, 4048 }, 4049 }, 4050 "no failure domains discovered": { 4051 specifiedFDs: clusterv1.FailureDomains{"fd1": clusterv1.FailureDomainSpec{ControlPlane: true}}, 4052 }, 4053 "failure domain specified without intersection": { 4054 discoveredFDs: clusterv1.FailureDomains{"fd1": clusterv1.FailureDomainSpec{ControlPlane: true}}, 4055 specifiedFDs: clusterv1.FailureDomains{"fd2": clusterv1.FailureDomainSpec{ControlPlane: false}}, 4056 expectedFDs: clusterv1.FailureDomains{"fd1": clusterv1.FailureDomainSpec{ControlPlane: true}}, 4057 }, 4058 "failure domain override to false succeeds": { 4059 discoveredFDs: clusterv1.FailureDomains{"fd1": clusterv1.FailureDomainSpec{ControlPlane: true}}, 4060 specifiedFDs: clusterv1.FailureDomains{"fd1": clusterv1.FailureDomainSpec{ControlPlane: false}}, 4061 expectedFDs: clusterv1.FailureDomains{"fd1": clusterv1.FailureDomainSpec{ControlPlane: false}}, 4062 }, 4063 "failure domain override to true fails": { 4064 discoveredFDs: clusterv1.FailureDomains{"fd1": clusterv1.FailureDomainSpec{ControlPlane: false}}, 4065 specifiedFDs: clusterv1.FailureDomains{"fd1": clusterv1.FailureDomainSpec{ControlPlane: true}}, 4066 expectedFDs: clusterv1.FailureDomains{"fd1": clusterv1.FailureDomainSpec{ControlPlane: false}}, 4067 }, 4068 } 4069 4070 for name, tc := range cases { 4071 tc := tc 4072 t.Run(name, func(t *testing.T) { 4073 t.Parallel() 4074 g := NewWithT(t) 4075 4076 c := ClusterScope{ 4077 AzureCluster: &infrav1.AzureCluster{ 4078 Spec: infrav1.AzureClusterSpec{ 4079 AzureClusterClassSpec: infrav1.AzureClusterClassSpec{ 4080 FailureDomains: tc.specifiedFDs, 4081 IdentityRef: &corev1.ObjectReference{ 4082 Kind: infrav1.AzureClusterIdentityKind, 4083 }, 4084 }, 4085 }, 4086 }, 4087 } 4088 4089 for fdName, fd := range tc.discoveredFDs { 4090 c.SetFailureDomain(fdName, fd) 4091 } 4092 4093 for fdName, fd := range tc.expectedFDs { 4094 g.Expect(fdName).Should(BeKeyOf(c.AzureCluster.Status.FailureDomains)) 4095 g.Expect(c.AzureCluster.Status.FailureDomains[fdName].ControlPlane).To(Equal(fd.ControlPlane)) 4096 4097 delete(c.AzureCluster.Status.FailureDomains, fdName) 4098 } 4099 4100 g.Expect(c.AzureCluster.Status.FailureDomains).To(BeEmpty()) 4101 }) 4102 } 4103 } 4104 4105 func TestGroupSpecs(t *testing.T) { 4106 cases := []struct { 4107 name string 4108 input ClusterScope 4109 expected []azure.ASOResourceSpecGetter[*asoresourcesv1.ResourceGroup] 4110 }{ 4111 { 4112 name: "virtualNetwork belongs to a different resource group", 4113 input: ClusterScope{ 4114 Cluster: &clusterv1.Cluster{ 4115 ObjectMeta: metav1.ObjectMeta{ 4116 Name: "cluster1", 4117 }, 4118 }, 4119 AzureCluster: &infrav1.AzureCluster{ 4120 Spec: infrav1.AzureClusterSpec{ 4121 ResourceGroup: "dummy-rg", 4122 NetworkSpec: infrav1.NetworkSpec{ 4123 Vnet: infrav1.VnetSpec{ 4124 ResourceGroup: "different-rg", 4125 }, 4126 }, 4127 }, 4128 }, 4129 }, 4130 expected: []azure.ASOResourceSpecGetter[*asoresourcesv1.ResourceGroup]{ 4131 &groups.GroupSpec{ 4132 Name: "dummy-rg", 4133 AzureName: "dummy-rg", 4134 ClusterName: "cluster1", 4135 Location: "", 4136 AdditionalTags: make(infrav1.Tags, 0), 4137 }, 4138 &groups.GroupSpec{ 4139 Name: "different-rg", 4140 AzureName: "different-rg", 4141 ClusterName: "cluster1", 4142 Location: "", 4143 AdditionalTags: make(infrav1.Tags, 0), 4144 }, 4145 }, 4146 }, 4147 { 4148 name: "virtualNetwork belongs to a same resource group", 4149 input: ClusterScope{ 4150 Cluster: &clusterv1.Cluster{ 4151 ObjectMeta: metav1.ObjectMeta{ 4152 Name: "cluster1", 4153 }, 4154 }, 4155 AzureCluster: &infrav1.AzureCluster{ 4156 Spec: infrav1.AzureClusterSpec{ 4157 ResourceGroup: "dummy-rg", 4158 NetworkSpec: infrav1.NetworkSpec{ 4159 Vnet: infrav1.VnetSpec{ 4160 ResourceGroup: "dummy-rg", 4161 }, 4162 }, 4163 }, 4164 }, 4165 }, 4166 expected: []azure.ASOResourceSpecGetter[*asoresourcesv1.ResourceGroup]{ 4167 &groups.GroupSpec{ 4168 Name: "dummy-rg", 4169 AzureName: "dummy-rg", 4170 ClusterName: "cluster1", 4171 Location: "", 4172 AdditionalTags: make(infrav1.Tags, 0), 4173 }, 4174 }, 4175 }, 4176 { 4177 name: "virtualNetwork resource group not specified", 4178 input: ClusterScope{ 4179 Cluster: &clusterv1.Cluster{ 4180 ObjectMeta: metav1.ObjectMeta{ 4181 Name: "cluster1", 4182 Namespace: "default", 4183 }, 4184 }, 4185 AzureCluster: &infrav1.AzureCluster{ 4186 Spec: infrav1.AzureClusterSpec{ 4187 ResourceGroup: "dummy-rg", 4188 NetworkSpec: infrav1.NetworkSpec{ 4189 Vnet: infrav1.VnetSpec{ 4190 Name: "vnet1", 4191 }, 4192 }, 4193 }, 4194 }, 4195 }, 4196 expected: []azure.ASOResourceSpecGetter[*asoresourcesv1.ResourceGroup]{ 4197 &groups.GroupSpec{ 4198 Name: "dummy-rg", 4199 AzureName: "dummy-rg", 4200 ClusterName: "cluster1", 4201 Location: "", 4202 AdditionalTags: make(infrav1.Tags, 0), 4203 }, 4204 }, 4205 }, 4206 { 4207 name: "virtualNetwork belongs to different resource group with non-k8s name", 4208 input: ClusterScope{ 4209 Cluster: &clusterv1.Cluster{ 4210 ObjectMeta: metav1.ObjectMeta{ 4211 Name: "cluster1", 4212 Namespace: "default", 4213 }, 4214 }, 4215 AzureCluster: &infrav1.AzureCluster{ 4216 Spec: infrav1.AzureClusterSpec{ 4217 ResourceGroup: "dummy-rg", 4218 NetworkSpec: infrav1.NetworkSpec{ 4219 Vnet: infrav1.VnetSpec{ 4220 ResourceGroup: "my_custom_rg", 4221 Name: "vnet1", 4222 }, 4223 }, 4224 }, 4225 }, 4226 }, 4227 expected: []azure.ASOResourceSpecGetter[*asoresourcesv1.ResourceGroup]{ 4228 &groups.GroupSpec{ 4229 Name: "dummy-rg", 4230 AzureName: "dummy-rg", 4231 ClusterName: "cluster1", 4232 Location: "", 4233 AdditionalTags: make(infrav1.Tags, 0), 4234 }, 4235 &groups.GroupSpec{ 4236 Name: "my-custom-rg", 4237 AzureName: "my_custom_rg", 4238 ClusterName: "cluster1", 4239 Location: "", 4240 AdditionalTags: make(infrav1.Tags, 0), 4241 }, 4242 }, 4243 }, 4244 } 4245 4246 for _, c := range cases { 4247 c := c 4248 t.Run(c.name, func(t *testing.T) { 4249 s := &ClusterScope{ 4250 AzureCluster: c.input.AzureCluster, 4251 Cluster: c.input.Cluster, 4252 } 4253 if got := s.GroupSpecs(); !reflect.DeepEqual(got, c.expected) { 4254 t.Errorf("GroupSpecs() = %s, want %s", specArrayToString(got), specArrayToString(c.expected)) 4255 } 4256 }) 4257 } 4258 }