sigs.k8s.io/cluster-api-provider-aws@v1.5.5/controllers/awscluster_controller_unit_test.go (about) 1 /* 2 Copyright 2022 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 controllers 18 19 import ( 20 "context" 21 "errors" 22 "fmt" 23 "testing" 24 "time" 25 26 "github.com/golang/mock/gomock" 27 . "github.com/onsi/gomega" 28 corev1 "k8s.io/api/core/v1" 29 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 30 "k8s.io/apimachinery/pkg/types" 31 "k8s.io/client-go/tools/record" 32 ctrl "sigs.k8s.io/controller-runtime" 33 "sigs.k8s.io/controller-runtime/pkg/client" 34 "sigs.k8s.io/controller-runtime/pkg/client/fake" 35 "sigs.k8s.io/controller-runtime/pkg/reconcile" 36 37 infrav1 "sigs.k8s.io/cluster-api-provider-aws/api/v1beta1" 38 "sigs.k8s.io/cluster-api-provider-aws/pkg/cloud/scope" 39 "sigs.k8s.io/cluster-api-provider-aws/pkg/cloud/services" 40 "sigs.k8s.io/cluster-api-provider-aws/pkg/cloud/services/mock_services" 41 clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" 42 "sigs.k8s.io/cluster-api/util" 43 ) 44 45 func TestAWSClusterReconciler_Reconcile(t *testing.T) { 46 testCases := []struct { 47 name string 48 awsCluster *infrav1.AWSCluster 49 ownerCluster *clusterv1.Cluster 50 expectError bool 51 }{ 52 { 53 name: "Should fail Reconcile if owner cluster not found", 54 awsCluster: &infrav1.AWSCluster{ObjectMeta: metav1.ObjectMeta{GenerateName: "aws-test-", OwnerReferences: []metav1.OwnerReference{ 55 { 56 APIVersion: clusterv1.GroupVersion.String(), 57 Kind: "Cluster", 58 Name: "capi-fail-test", 59 UID: "1", 60 }}}}, 61 expectError: true, 62 }, 63 { 64 name: "Should not reconcile if owner reference is not set", 65 awsCluster: &infrav1.AWSCluster{ObjectMeta: metav1.ObjectMeta{GenerateName: "aws-test-"}}, 66 expectError: false, 67 }, 68 { 69 name: "Should not Reconcile if cluster is paused", 70 awsCluster: &infrav1.AWSCluster{ObjectMeta: metav1.ObjectMeta{GenerateName: "aws-test-", Annotations: map[string]string{clusterv1.PausedAnnotation: ""}}}, 71 ownerCluster: &clusterv1.Cluster{ObjectMeta: metav1.ObjectMeta{GenerateName: "capi-test-"}}, 72 expectError: false, 73 }, 74 { 75 name: "Should Reconcile successfully if no AWSCluster found", 76 expectError: false, 77 }, 78 } 79 80 for _, tc := range testCases { 81 t.Run(tc.name, func(t *testing.T) { 82 g := NewWithT(t) 83 reconciler := &AWSClusterReconciler{ 84 Client: testEnv.Client, 85 } 86 87 ns, err := testEnv.CreateNamespace(ctx, fmt.Sprintf("namespace-%s", util.RandomString(5))) 88 g.Expect(err).To(BeNil()) 89 90 if tc.ownerCluster != nil { 91 tc.ownerCluster.Namespace = ns.Name 92 g.Expect(testEnv.Create(ctx, tc.ownerCluster)).To(Succeed()) 93 defer func(do ...client.Object) { 94 g.Expect(testEnv.Cleanup(ctx, do...)).To(Succeed()) 95 }(tc.ownerCluster) 96 tc.awsCluster.OwnerReferences = []metav1.OwnerReference{ 97 { 98 APIVersion: clusterv1.GroupVersion.String(), 99 Kind: "Cluster", 100 Name: tc.ownerCluster.Name, 101 UID: "1", 102 }, 103 } 104 } 105 createCluster(g, tc.awsCluster, ns.Name) 106 defer cleanupCluster(g, tc.awsCluster, ns) 107 108 if tc.awsCluster != nil { 109 _, err := reconciler.Reconcile(ctx, ctrl.Request{ 110 NamespacedName: client.ObjectKey{ 111 Namespace: tc.awsCluster.Namespace, 112 Name: tc.awsCluster.Name, 113 }, 114 }) 115 if tc.expectError { 116 g.Expect(err).ToNot(BeNil()) 117 } else { 118 g.Expect(err).To(BeNil()) 119 } 120 } else { 121 _, err := reconciler.Reconcile(ctx, ctrl.Request{ 122 NamespacedName: client.ObjectKey{ 123 Namespace: ns.Name, 124 Name: "test", 125 }, 126 }) 127 g.Expect(err).To(BeNil()) 128 } 129 }) 130 } 131 } 132 133 func TestAWSClusterReconcileOperations(t *testing.T) { 134 var ( 135 reconciler AWSClusterReconciler 136 mockCtrl *gomock.Controller 137 ec2Svc *mock_services.MockEC2Interface 138 elbSvc *mock_services.MockELBInterface 139 networkSvc *mock_services.MockNetworkInterface 140 sgSvc *mock_services.MockSecurityGroupInterface 141 recorder *record.FakeRecorder 142 ctx context.Context 143 ) 144 145 setup := func(t *testing.T, awsCluster *infrav1.AWSCluster) client.WithWatch { 146 t.Helper() 147 ctx = context.TODO() 148 secret := &corev1.Secret{ 149 ObjectMeta: metav1.ObjectMeta{ 150 Name: "test-secret", 151 Namespace: "capa-system", 152 }, 153 Data: map[string][]byte{ 154 "AccessKeyID": []byte("access-key-id"), 155 "SecretAccessKey": []byte("secret-access-key"), 156 "SessionToken": []byte("session-token"), 157 }, 158 } 159 csClient := fake.NewClientBuilder().WithObjects(awsCluster, secret).Build() 160 161 mockCtrl = gomock.NewController(t) 162 ec2Svc = mock_services.NewMockEC2Interface(mockCtrl) 163 elbSvc = mock_services.NewMockELBInterface(mockCtrl) 164 networkSvc = mock_services.NewMockNetworkInterface(mockCtrl) 165 sgSvc = mock_services.NewMockSecurityGroupInterface(mockCtrl) 166 167 recorder = record.NewFakeRecorder(2) 168 169 reconciler = AWSClusterReconciler{ 170 Client: csClient, 171 ec2ServiceFactory: func(scope.EC2Scope) services.EC2Interface { 172 return ec2Svc 173 }, 174 elbServiceFactory: func(elbScope scope.ELBScope) services.ELBInterface { 175 return elbSvc 176 }, 177 networkServiceFactory: func(clusterScope scope.ClusterScope) services.NetworkInterface { 178 return networkSvc 179 }, 180 securityGroupFactory: func(clusterScope scope.ClusterScope) services.SecurityGroupInterface { 181 return sgSvc 182 }, 183 Recorder: recorder, 184 } 185 return csClient 186 } 187 188 teardown := func() { 189 mockCtrl.Finish() 190 } 191 192 t.Run("Reconciling an AWSCluster", func(t *testing.T) { 193 t.Run("Reconcile success", func(t *testing.T) { 194 t.Run("Should successfully create AWSCluster with Cluster Finalizer and LoadBalancerReady status true on AWSCluster", func(t *testing.T) { 195 g := NewWithT(t) 196 runningCluster := func() { 197 ec2Svc.EXPECT().ReconcileBastion().Return(nil) 198 elbSvc.EXPECT().ReconcileLoadbalancers().Return(nil) 199 networkSvc.EXPECT().ReconcileNetwork().Return(nil) 200 sgSvc.EXPECT().ReconcileSecurityGroups().Return(nil) 201 } 202 203 awsCluster := getAWSCluster("test", "test") 204 csClient := setup(t, &awsCluster) 205 defer teardown() 206 runningCluster() 207 cs, err := scope.NewClusterScope( 208 scope.ClusterScopeParams{ 209 Client: csClient, 210 Cluster: &clusterv1.Cluster{}, 211 AWSCluster: &awsCluster, 212 }, 213 ) 214 g.Expect(err).To(BeNil()) 215 awsCluster.Status.Network.APIServerELB.DNSName = DNSName 216 awsCluster.Status.Network.APIServerELB.AvailabilityZones = []string{"us-east-1a", "us-east-1b", "us-east-1c", "us-east-1d", "us-east-1e"} 217 cs.SetSubnets(infrav1.Subnets{ 218 { 219 ID: "private-subnet-1", 220 AvailabilityZone: "us-east-1b", 221 IsPublic: false, 222 }, 223 { 224 ID: "private-subnet-2", 225 AvailabilityZone: "us-east-1a", 226 IsPublic: false, 227 }, 228 { 229 ID: "private-subnet-3", 230 AvailabilityZone: "us-east-1c", 231 IsPublic: false, 232 }, 233 { 234 ID: "private-subnet-4", 235 AvailabilityZone: "us-east-1d", 236 IsPublic: false, 237 }, 238 { 239 ID: "private-subnet-5", 240 AvailabilityZone: "us-east-1e", 241 IsPublic: false, 242 }, 243 }) 244 _, err = reconciler.reconcileNormal(cs) 245 g.Expect(err).To(BeNil()) 246 expectAWSClusterConditions(g, cs.AWSCluster, []conditionAssertion{{infrav1.LoadBalancerReadyCondition, corev1.ConditionTrue, "", ""}}) 247 g.Expect(awsCluster.GetFinalizers()).To(ContainElement(infrav1.ClusterFinalizer)) 248 }) 249 }) 250 t.Run("Reconcile failure", func(t *testing.T) { 251 expectedErr := errors.New("failed to get resource") 252 t.Run("Should fail AWSCluster create with reconcile network failure", func(t *testing.T) { 253 g := NewWithT(t) 254 awsCluster := getAWSCluster("test", "test") 255 runningCluster := func() { 256 networkSvc.EXPECT().ReconcileNetwork().Return(expectedErr) 257 } 258 csClient := setup(t, &awsCluster) 259 defer teardown() 260 runningCluster() 261 cs, err := scope.NewClusterScope( 262 scope.ClusterScopeParams{ 263 Client: csClient, 264 Cluster: &clusterv1.Cluster{}, 265 AWSCluster: &awsCluster, 266 }, 267 ) 268 g.Expect(err).To(BeNil()) 269 _, err = reconciler.reconcileNormal(cs) 270 g.Expect(err).Should(Equal(expectedErr)) 271 }) 272 t.Run("Should fail AWSCluster create with ClusterSecurityGroupsReadyCondition status false", func(t *testing.T) { 273 g := NewWithT(t) 274 awsCluster := getAWSCluster("test", "test") 275 runningCluster := func() { 276 networkSvc.EXPECT().ReconcileNetwork().Return(nil) 277 sgSvc.EXPECT().ReconcileSecurityGroups().Return(expectedErr) 278 } 279 csClient := setup(t, &awsCluster) 280 defer teardown() 281 runningCluster() 282 cs, err := scope.NewClusterScope( 283 scope.ClusterScopeParams{ 284 Client: csClient, 285 Cluster: &clusterv1.Cluster{}, 286 AWSCluster: &awsCluster, 287 }, 288 ) 289 g.Expect(err).To(BeNil()) 290 _, err = reconciler.reconcileNormal(cs) 291 g.Expect(err).ToNot(BeNil()) 292 expectAWSClusterConditions(g, cs.AWSCluster, []conditionAssertion{{infrav1.ClusterSecurityGroupsReadyCondition, corev1.ConditionFalse, clusterv1.ConditionSeverityWarning, infrav1.ClusterSecurityGroupReconciliationFailedReason}}) 293 }) 294 t.Run("Should fail AWSCluster create with BastionHostReadyCondition status false", func(t *testing.T) { 295 g := NewWithT(t) 296 awsCluster := getAWSCluster("test", "test") 297 runningCluster := func() { 298 networkSvc.EXPECT().ReconcileNetwork().Return(nil) 299 sgSvc.EXPECT().ReconcileSecurityGroups().Return(nil) 300 ec2Svc.EXPECT().ReconcileBastion().Return(expectedErr) 301 } 302 csClient := setup(t, &awsCluster) 303 defer teardown() 304 runningCluster() 305 cs, err := scope.NewClusterScope( 306 scope.ClusterScopeParams{ 307 Client: csClient, 308 Cluster: &clusterv1.Cluster{}, 309 AWSCluster: &awsCluster, 310 }, 311 ) 312 g.Expect(err).To(BeNil()) 313 _, err = reconciler.reconcileNormal(cs) 314 g.Expect(err).ToNot(BeNil()) 315 expectAWSClusterConditions(g, cs.AWSCluster, []conditionAssertion{{infrav1.BastionHostReadyCondition, corev1.ConditionFalse, clusterv1.ConditionSeverityWarning, infrav1.BastionHostFailedReason}}) 316 }) 317 t.Run("Should fail AWSCluster create with failure in LoadBalancer reconciliation", func(t *testing.T) { 318 g := NewWithT(t) 319 awsCluster := getAWSCluster("test", "test") 320 runningCluster := func() { 321 networkSvc.EXPECT().ReconcileNetwork().Return(nil) 322 sgSvc.EXPECT().ReconcileSecurityGroups().Return(nil) 323 ec2Svc.EXPECT().ReconcileBastion().Return(nil) 324 elbSvc.EXPECT().ReconcileLoadbalancers().Return(expectedErr) 325 } 326 csClient := setup(t, &awsCluster) 327 defer teardown() 328 runningCluster() 329 cs, err := scope.NewClusterScope( 330 scope.ClusterScopeParams{ 331 Client: csClient, 332 Cluster: &clusterv1.Cluster{}, 333 AWSCluster: &awsCluster, 334 }, 335 ) 336 g.Expect(err).To(BeNil()) 337 _, err = reconciler.reconcileNormal(cs) 338 g.Expect(err).ToNot(BeNil()) 339 expectAWSClusterConditions(g, cs.AWSCluster, []conditionAssertion{{infrav1.LoadBalancerReadyCondition, corev1.ConditionFalse, clusterv1.ConditionSeverityWarning, infrav1.LoadBalancerFailedReason}}) 340 }) 341 t.Run("Should fail AWSCluster create with LoadBalancer reconcile failure with WaitForDNSName condition as false", func(t *testing.T) { 342 g := NewWithT(t) 343 awsCluster := getAWSCluster("test", "test") 344 runningCluster := func() { 345 networkSvc.EXPECT().ReconcileNetwork().Return(nil) 346 sgSvc.EXPECT().ReconcileSecurityGroups().Return(nil) 347 ec2Svc.EXPECT().ReconcileBastion().Return(nil) 348 elbSvc.EXPECT().ReconcileLoadbalancers().Return(nil) 349 } 350 csClient := setup(t, &awsCluster) 351 defer teardown() 352 runningCluster() 353 cs, err := scope.NewClusterScope( 354 scope.ClusterScopeParams{ 355 Client: csClient, 356 Cluster: &clusterv1.Cluster{}, 357 AWSCluster: &awsCluster, 358 }, 359 ) 360 g.Expect(err).To(BeNil()) 361 _, err = reconciler.reconcileNormal(cs) 362 g.Expect(err).To(BeNil()) 363 expectAWSClusterConditions(g, cs.AWSCluster, []conditionAssertion{{infrav1.LoadBalancerReadyCondition, corev1.ConditionFalse, clusterv1.ConditionSeverityInfo, infrav1.WaitForDNSNameReason}}) 364 }) 365 t.Run("Should fail AWSCluster create with LoadBalancer reconcile failure with WaitForDNSNameResolve condition as false", func(t *testing.T) { 366 g := NewWithT(t) 367 awsCluster := getAWSCluster("test", "test") 368 runningCluster := func() { 369 networkSvc.EXPECT().ReconcileNetwork().Return(nil) 370 sgSvc.EXPECT().ReconcileSecurityGroups().Return(nil) 371 ec2Svc.EXPECT().ReconcileBastion().Return(nil) 372 elbSvc.EXPECT().ReconcileLoadbalancers().Return(nil) 373 } 374 csClient := setup(t, &awsCluster) 375 defer teardown() 376 runningCluster() 377 cs, err := scope.NewClusterScope( 378 scope.ClusterScopeParams{ 379 Client: csClient, 380 Cluster: &clusterv1.Cluster{}, 381 AWSCluster: &awsCluster, 382 }, 383 ) 384 awsCluster.Status.Network.APIServerELB.DNSName = "test-apiserver.us-east-1.aws" 385 g.Expect(err).To(BeNil()) 386 _, err = reconciler.reconcileNormal(cs) 387 g.Expect(err).To(BeNil()) 388 expectAWSClusterConditions(g, cs.AWSCluster, []conditionAssertion{{infrav1.LoadBalancerReadyCondition, corev1.ConditionFalse, clusterv1.ConditionSeverityInfo, infrav1.WaitForDNSNameResolveReason}}) 389 }) 390 }) 391 }) 392 t.Run("Reconcile delete AWSCluster", func(t *testing.T) { 393 t.Run("Reconcile success", func(t *testing.T) { 394 deleteCluster := func() { 395 ec2Svc.EXPECT().DeleteBastion().Return(nil) 396 elbSvc.EXPECT().DeleteLoadbalancers().Return(nil) 397 networkSvc.EXPECT().DeleteNetwork().Return(nil) 398 sgSvc.EXPECT().DeleteSecurityGroups().Return(nil) 399 } 400 t.Run("Should successfully delete AWSCluster with Cluster Finalizer removed", func(t *testing.T) { 401 g := NewWithT(t) 402 awsCluster := getAWSCluster("test", "test") 403 csClient := setup(t, &awsCluster) 404 defer teardown() 405 deleteCluster() 406 cs, err := scope.NewClusterScope( 407 scope.ClusterScopeParams{ 408 Client: csClient, 409 Cluster: &clusterv1.Cluster{}, 410 AWSCluster: &awsCluster, 411 }, 412 ) 413 g.Expect(err).To(BeNil()) 414 _, err = reconciler.reconcileDelete(ctx, cs) 415 g.Expect(err).To(BeNil()) 416 g.Expect(awsCluster.GetFinalizers()).ToNot(ContainElement(infrav1.ClusterFinalizer)) 417 }) 418 }) 419 t.Run("Reconcile failure", func(t *testing.T) { 420 expectedErr := errors.New("failed to get resource") 421 t.Run("Should fail AWSCluster delete with LoadBalancer deletion failed and Cluster Finalizer not removed", func(t *testing.T) { 422 g := NewWithT(t) 423 deleteCluster := func() { 424 t.Helper() 425 elbSvc.EXPECT().DeleteLoadbalancers().Return(expectedErr) 426 } 427 awsCluster := getAWSCluster("test", "test") 428 awsCluster.Finalizers = []string{infrav1.ClusterFinalizer} 429 csClient := setup(t, &awsCluster) 430 defer teardown() 431 deleteCluster() 432 cs, err := scope.NewClusterScope( 433 scope.ClusterScopeParams{ 434 Client: csClient, 435 Cluster: &clusterv1.Cluster{}, 436 AWSCluster: &awsCluster, 437 }, 438 ) 439 g.Expect(err).To(BeNil()) 440 _, err = reconciler.reconcileDelete(ctx, cs) 441 g.Expect(err).ToNot(BeNil()) 442 g.Expect(awsCluster.GetFinalizers()).To(ContainElement(infrav1.ClusterFinalizer)) 443 }) 444 t.Run("Should fail AWSCluster delete with Bastion deletion failed and Cluster Finalizer not removed", func(t *testing.T) { 445 g := NewWithT(t) 446 deleteCluster := func() { 447 ec2Svc.EXPECT().DeleteBastion().Return(expectedErr) 448 elbSvc.EXPECT().DeleteLoadbalancers().Return(nil) 449 } 450 awsCluster := getAWSCluster("test", "test") 451 awsCluster.Finalizers = []string{infrav1.ClusterFinalizer} 452 csClient := setup(t, &awsCluster) 453 defer teardown() 454 deleteCluster() 455 cs, err := scope.NewClusterScope( 456 scope.ClusterScopeParams{ 457 Client: csClient, 458 Cluster: &clusterv1.Cluster{}, 459 AWSCluster: &awsCluster, 460 }, 461 ) 462 g.Expect(err).To(BeNil()) 463 _, err = reconciler.reconcileDelete(ctx, cs) 464 g.Expect(err).ToNot(BeNil()) 465 g.Expect(awsCluster.GetFinalizers()).To(ContainElement(infrav1.ClusterFinalizer)) 466 }) 467 t.Run("Should fail AWSCluster delete with security group deletion failed and Cluster Finalizer not removed", func(t *testing.T) { 468 g := NewWithT(t) 469 deleteCluster := func() { 470 ec2Svc.EXPECT().DeleteBastion().Return(nil) 471 elbSvc.EXPECT().DeleteLoadbalancers().Return(nil) 472 sgSvc.EXPECT().DeleteSecurityGroups().Return(expectedErr) 473 } 474 awsCluster := getAWSCluster("test", "test") 475 awsCluster.Finalizers = []string{infrav1.ClusterFinalizer} 476 csClient := setup(t, &awsCluster) 477 defer teardown() 478 deleteCluster() 479 cs, err := scope.NewClusterScope( 480 scope.ClusterScopeParams{ 481 Client: csClient, 482 Cluster: &clusterv1.Cluster{}, 483 AWSCluster: &awsCluster, 484 }, 485 ) 486 g.Expect(err).To(BeNil()) 487 _, err = reconciler.reconcileDelete(ctx, cs) 488 g.Expect(err).ToNot(BeNil()) 489 g.Expect(awsCluster.GetFinalizers()).To(ContainElement(infrav1.ClusterFinalizer)) 490 }) 491 t.Run("Should fail AWSCluster delete with network deletion failed and Cluster Finalizer not removed", func(t *testing.T) { 492 g := NewWithT(t) 493 deleteCluster := func() { 494 ec2Svc.EXPECT().DeleteBastion().Return(nil) 495 elbSvc.EXPECT().DeleteLoadbalancers().Return(nil) 496 sgSvc.EXPECT().DeleteSecurityGroups().Return(nil) 497 networkSvc.EXPECT().DeleteNetwork().Return(expectedErr) 498 } 499 awsCluster := getAWSCluster("test", "test") 500 awsCluster.Finalizers = []string{infrav1.ClusterFinalizer} 501 csClient := setup(t, &awsCluster) 502 defer teardown() 503 deleteCluster() 504 cs, err := scope.NewClusterScope( 505 scope.ClusterScopeParams{ 506 Client: csClient, 507 Cluster: &clusterv1.Cluster{}, 508 AWSCluster: &awsCluster, 509 }, 510 ) 511 g.Expect(err).To(BeNil()) 512 _, err = reconciler.reconcileDelete(ctx, cs) 513 g.Expect(err).ToNot(BeNil()) 514 g.Expect(awsCluster.GetFinalizers()).To(ContainElement(infrav1.ClusterFinalizer)) 515 }) 516 }) 517 }) 518 } 519 520 func TestAWSClusterReconciler_RequeueAWSClusterForUnpausedCluster(t *testing.T) { 521 testCases := []struct { 522 name string 523 awsCluster *infrav1.AWSCluster 524 ownerCluster *clusterv1.Cluster 525 requeue bool 526 }{ 527 { 528 name: "Should create reconcile request successfully", 529 awsCluster: &infrav1.AWSCluster{ 530 ObjectMeta: metav1.ObjectMeta{GenerateName: "aws-test-"}, TypeMeta: metav1.TypeMeta{Kind: "AWSCluster", APIVersion: infrav1.GroupVersion.String()}, 531 }, 532 ownerCluster: &clusterv1.Cluster{ObjectMeta: metav1.ObjectMeta{Name: "capi-test"}}, 533 requeue: true, 534 }, 535 { 536 name: "Should not create reconcile request if AWSCluster is externally managed", 537 awsCluster: &infrav1.AWSCluster{ 538 ObjectMeta: metav1.ObjectMeta{GenerateName: "aws-test-", Annotations: map[string]string{clusterv1.ManagedByAnnotation: "capi-test"}}, 539 TypeMeta: metav1.TypeMeta{Kind: "AWSCluster", APIVersion: infrav1.GroupVersion.String()}, 540 }, 541 ownerCluster: &clusterv1.Cluster{ObjectMeta: metav1.ObjectMeta{Name: "capi-test"}}, 542 requeue: false, 543 }, 544 { 545 name: "Should not create reconcile request for deleted clusters", 546 ownerCluster: &clusterv1.Cluster{ObjectMeta: metav1.ObjectMeta{Name: "capi-test", DeletionTimestamp: &metav1.Time{Time: time.Now()}}}, 547 requeue: false, 548 }, 549 { 550 name: "Should not create reconcile request if infrastructure ref for AWSCluster on owner cluster is not set", 551 ownerCluster: &clusterv1.Cluster{ObjectMeta: metav1.ObjectMeta{Name: "capi-test"}}, 552 requeue: false, 553 }, 554 { 555 name: "Should not create reconcile request if infrastructure ref type on owner cluster is not AWSCluster", 556 ownerCluster: &clusterv1.Cluster{ObjectMeta: metav1.ObjectMeta{Name: "capi-test"}, Spec: clusterv1.ClusterSpec{InfrastructureRef: &corev1.ObjectReference{ 557 APIVersion: clusterv1.GroupVersion.String(), 558 Kind: "Cluster", 559 Name: "aws-test"}}}, 560 requeue: false, 561 }, 562 { 563 name: "Should not create reconcile request if AWSCluster not found", 564 ownerCluster: &clusterv1.Cluster{ObjectMeta: metav1.ObjectMeta{Name: "capi-test"}, Spec: clusterv1.ClusterSpec{InfrastructureRef: &corev1.ObjectReference{ 565 APIVersion: clusterv1.GroupVersion.String(), 566 Kind: "AWSCluster", 567 Name: "aws-test"}}}, 568 requeue: false, 569 }, 570 } 571 for _, tc := range testCases { 572 t.Run(tc.name, func(t *testing.T) { 573 g := NewWithT(t) 574 log := ctrl.LoggerFrom(ctx) 575 reconciler := &AWSClusterReconciler{ 576 Client: testEnv.Client, 577 } 578 579 ns, err := testEnv.CreateNamespace(ctx, fmt.Sprintf("namespace-%s", util.RandomString(5))) 580 g.Expect(err).To(BeNil()) 581 createCluster(g, tc.awsCluster, ns.Name) 582 defer cleanupCluster(g, tc.awsCluster, ns) 583 584 if tc.ownerCluster != nil { 585 if tc.awsCluster != nil { 586 tc.ownerCluster.Spec = clusterv1.ClusterSpec{InfrastructureRef: &corev1.ObjectReference{ 587 APIVersion: infrav1.GroupVersion.String(), 588 Kind: "AWSCluster", 589 Name: tc.awsCluster.Name, 590 Namespace: ns.Name, 591 }} 592 } 593 tc.ownerCluster.Namespace = ns.Name 594 } 595 handlerFunc := reconciler.requeueAWSClusterForUnpausedCluster(ctx, log) 596 result := handlerFunc(tc.ownerCluster) 597 if tc.requeue { 598 g.Expect(result).To(ContainElement(reconcile.Request{ 599 NamespacedName: types.NamespacedName{ 600 Namespace: ns.Name, 601 Name: tc.awsCluster.Name, 602 }, 603 })) 604 } else { 605 g.Expect(result).To(BeNil()) 606 } 607 }) 608 } 609 } 610 611 func createCluster(g *WithT, awsCluster *infrav1.AWSCluster, namespace string) { 612 if awsCluster != nil { 613 awsCluster.Namespace = namespace 614 g.Expect(testEnv.Create(ctx, awsCluster)).To(Succeed()) 615 g.Eventually(func() bool { 616 cluster := &infrav1.AWSCluster{} 617 key := client.ObjectKey{ 618 Name: awsCluster.Name, 619 Namespace: namespace, 620 } 621 err := testEnv.Get(ctx, key, cluster) 622 return err == nil 623 }, 10*time.Second).Should(Equal(true)) 624 } 625 } 626 627 func cleanupCluster(g *WithT, awsCluster *infrav1.AWSCluster, namespace *corev1.Namespace) { 628 if awsCluster != nil { 629 func(do ...client.Object) { 630 g.Expect(testEnv.Cleanup(ctx, do...)).To(Succeed()) 631 }(awsCluster, namespace) 632 } 633 } 634 635 func TestSecurityGroupRolesForCluster(t *testing.T) { 636 tests := []struct { 637 name string 638 bastionEnabled bool 639 want []infrav1.SecurityGroupRole 640 }{ 641 { 642 name: "Should use bastion security group when bastion is enabled", 643 bastionEnabled: true, 644 want: append(defaultAWSSecurityGroupRoles, infrav1.SecurityGroupBastion), 645 }, 646 { 647 name: "Should not use bastion security group when bastion is not enabled", 648 bastionEnabled: false, 649 want: defaultAWSSecurityGroupRoles, 650 }, 651 } 652 653 for _, tt := range tests { 654 t.Run(tt.name, func(t *testing.T) { 655 g := NewWithT(t) 656 657 c := getAWSCluster("test", "test") 658 c.Spec.Bastion.Enabled = tt.bastionEnabled 659 s, err := getClusterScope(c) 660 g.Expect(err).To(BeNil(), "failed to create cluster scope for test") 661 662 got := securityGroupRolesForCluster(*s) 663 g.Expect(got).To(Equal(tt.want)) 664 }) 665 } 666 }