@@ -469,73 +469,104 @@ func SetMultitenancyEnvVars(prov client.ConfigProvider) error {
469
469
func deleteResourcesInCloudFormation (prov client.ConfigProvider , t * cfn_bootstrap.Template ) {
470
470
iamSvc := iam .New (prov )
471
471
temp := * renderCustomCloudFormation (t )
472
+ var (
473
+ iamRoles []* cfn_iam.Role
474
+ instanceProfiles []* cfn_iam.InstanceProfile
475
+ policies []* cfn_iam.ManagedPolicy
476
+ groups []* cfn_iam.Group
477
+ )
478
+ // the deletion order of these resources is important. Policies need to be last,
479
+ // so they don't have any attached resources which prevents their deletion.
480
+ // temp.Resources is a map. Traversing that directly results in undetermined order.
472
481
for _ , val := range temp .Resources {
473
- By (fmt .Sprintf ("deleting the following resource: %s" , val .AWSCloudFormationType ()))
474
- tayp := val .AWSCloudFormationType ()
475
- if tayp == configservice .ResourceTypeAwsIamRole {
482
+ switch val .AWSCloudFormationType () {
483
+ case configservice .ResourceTypeAwsIamRole :
476
484
role := val .(* cfn_iam.Role )
477
- By (fmt .Sprintf ("cleanup for role with name '%s'" , role .RoleName ))
478
- // added repeat to not keep flooding the logs.
479
- repeat := false
480
- Eventually (func (gomega Gomega ) bool {
481
- _ , err := iamSvc .DeleteRole (& iam.DeleteRoleInput {RoleName : aws .String (role .RoleName )})
482
- if err != nil && ! repeat {
483
- By (fmt .Sprintf ("failed to delete role '%s'; reason: %+v" , role .RoleName , err ))
484
- repeat = true
485
- }
486
- code , ok := awserrors .Code (err )
487
- return err == nil || (ok && code == iam .ErrCodeNoSuchEntityException )
488
- }, 5 * time .Minute , 5 * time .Second ).Should (BeTrue ())
489
- }
490
- if val .AWSCloudFormationType () == "AWS::IAM::InstanceProfile" {
485
+ iamRoles = append (iamRoles , role )
486
+ case "AWS::IAM::InstanceProfile" :
491
487
profile := val .(* cfn_iam.InstanceProfile )
492
- By (fmt .Sprintf ("cleanup for profile with name '%s'" , profile .InstanceProfileName ))
493
- repeat := false
494
- Eventually (func (gomega Gomega ) bool {
495
- _ , err := iamSvc .DeleteInstanceProfile (& iam.DeleteInstanceProfileInput {InstanceProfileName : aws .String (profile .InstanceProfileName )})
496
- if err != nil && ! repeat {
497
- By (fmt .Sprintf ("failed to delete role '%s'; reason: %+v" , profile .InstanceProfileName , err ))
498
- repeat = true
499
- }
500
- code , ok := awserrors .Code (err )
501
- return err == nil || (ok && code == iam .ErrCodeNoSuchEntityException )
502
- }, 5 * time .Minute , 5 * time .Second ).Should (BeTrue ())
503
- }
504
- if val .AWSCloudFormationType () == "AWS::IAM::ManagedPolicy" {
488
+ instanceProfiles = append (instanceProfiles , profile )
489
+ case "AWS::IAM::ManagedPolicy" :
505
490
policy := val .(* cfn_iam.ManagedPolicy )
506
- policies , err := iamSvc .ListPolicies (& iam.ListPoliciesInput {})
507
- Expect (err ).NotTo (HaveOccurred ())
508
- if len (policies .Policies ) > 0 {
509
- for _ , p := range policies .Policies {
510
- if aws .StringValue (p .PolicyName ) == policy .ManagedPolicyName {
511
- By (fmt .Sprintf ("cleanup for policy '%s'" , p .String ()))
512
- repeat := false
513
- Eventually (func (gomega Gomega ) bool {
514
- _ , err := iamSvc .DeletePolicy (& iam.DeletePolicyInput {PolicyArn : p .Arn })
515
- if err != nil && ! repeat {
516
- By (fmt .Sprintf ("failed to delete policy '%s'; reason: %+v" , policy .Description , err ))
517
- repeat = true
518
- }
519
- code , ok := awserrors .Code (err )
520
- return err == nil || (ok && code == iam .ErrCodeNoSuchEntityException )
521
- }, 5 * time .Minute , 5 * time .Second ).Should (BeTrue ())
522
- // TODO: why is there a break here? Don't we want to clean up everything?
523
- break
524
- }
491
+ policies = append (policies , policy )
492
+ case configservice .ResourceTypeAwsIamGroup :
493
+ group := val .(* cfn_iam.Group )
494
+ groups = append (groups , group )
495
+ }
496
+ }
497
+ for _ , role := range iamRoles {
498
+ By (fmt .Sprintf ("deleting the following role: %s" , role .RoleName ))
499
+ repeat := false
500
+ Eventually (func (gomega Gomega ) bool {
501
+ err := DeleteRole (prov , role .RoleName )
502
+ if err != nil && ! repeat {
503
+ By (fmt .Sprintf ("failed to delete role '%s'; reason: %+v" , role .RoleName , err ))
504
+ repeat = true
505
+ }
506
+ code , ok := awserrors .Code (err )
507
+ return err == nil || (ok && code == iam .ErrCodeNoSuchEntityException )
508
+ }, 5 * time .Minute , 5 * time .Second ).Should (BeTrue ())
509
+ }
510
+ for _ , profile := range instanceProfiles {
511
+ By (fmt .Sprintf ("cleanup for profile with name '%s'" , profile .InstanceProfileName ))
512
+ repeat := false
513
+ Eventually (func (gomega Gomega ) bool {
514
+ _ , err := iamSvc .DeleteInstanceProfile (& iam.DeleteInstanceProfileInput {InstanceProfileName : aws .String (profile .InstanceProfileName )})
515
+ if err != nil && ! repeat {
516
+ By (fmt .Sprintf ("failed to delete role '%s'; reason: %+v" , profile .InstanceProfileName , err ))
517
+ repeat = true
518
+ }
519
+ code , ok := awserrors .Code (err )
520
+ return err == nil || (ok && code == iam .ErrCodeNoSuchEntityException )
521
+ }, 5 * time .Minute , 5 * time .Second ).Should (BeTrue ())
522
+ }
523
+ for _ , group := range groups {
524
+ repeat := false
525
+ Eventually (func (gomega Gomega ) bool {
526
+ _ , err := iamSvc .DeleteGroup (& iam.DeleteGroupInput {GroupName : aws .String (group .GroupName )})
527
+ if err != nil && ! repeat {
528
+ By (fmt .Sprintf ("failed to delete group '%s'; reason: %+v" , group .GroupName , err ))
529
+ repeat = true
530
+ }
531
+ code , ok := awserrors .Code (err )
532
+ return err == nil || (ok && code == iam .ErrCodeNoSuchEntityException )
533
+ }, 5 * time .Minute , 5 * time .Second ).Should (BeTrue ())
534
+ }
535
+ for _ , policy := range policies {
536
+ policies , err := iamSvc .ListPolicies (& iam.ListPoliciesInput {})
537
+ Expect (err ).NotTo (HaveOccurred ())
538
+ if len (policies .Policies ) > 0 {
539
+ for _ , p := range policies .Policies {
540
+ if aws .StringValue (p .PolicyName ) == policy .ManagedPolicyName {
541
+ By (fmt .Sprintf ("cleanup for policy '%s'" , p .String ()))
542
+ repeat := false
543
+ Eventually (func (gomega Gomega ) bool {
544
+ response , err := iamSvc .DeletePolicy (& iam.DeletePolicyInput {
545
+ PolicyArn : p .Arn ,
546
+ })
547
+ if err != nil && ! repeat {
548
+ By (fmt .Sprintf ("failed to delete policy '%s'; reason: %+v, response: %s" , policy .Description , err , response .String ()))
549
+ repeat = true
550
+ }
551
+ code , ok := awserrors .Code (err )
552
+ return err == nil || (ok && code == iam .ErrCodeNoSuchEntityException )
553
+ }, 5 * time .Minute , 5 * time .Second ).Should (BeTrue ())
554
+ // TODO: why is there a break here? Don't we want to clean up everything?
555
+ break
525
556
}
526
557
}
527
558
}
528
- if val .AWSCloudFormationType () == configservice .ResourceTypeAwsIamGroup {
529
- group := val .(* cfn_iam.Group )
530
- _ , _ = iamSvc .DeleteGroup (& iam.DeleteGroupInput {GroupName : aws .String (group .GroupName )})
531
- }
532
559
}
533
560
}
534
561
535
562
// TODO: remove once test infra accounts are fixed.
536
563
func deleteMultitenancyRoles (prov client.ConfigProvider ) {
537
- DeleteRole (prov , "multi-tenancy-role" )
538
- DeleteRole (prov , "multi-tenancy-nested-role" )
564
+ if err := DeleteRole (prov , "multi-tenancy-role" ); err != nil {
565
+ By (fmt .Sprintf ("failed to delete role multi-tenancy-role %s" , err ))
566
+ }
567
+ if err := DeleteRole (prov , "multi-tenancy-nested-role" ); err != nil {
568
+ By (fmt .Sprintf ("failed to delete role multi-tenancy-nested-role %s" , err ))
569
+ }
539
570
}
540
571
541
572
// detachAllPoliciesForRole detaches all policies for role.
@@ -564,23 +595,25 @@ func detachAllPoliciesForRole(prov client.ConfigProvider, name string) error {
564
595
}
565
596
566
597
// DeleteRole deletes roles in a best effort manner.
567
- func DeleteRole (prov client.ConfigProvider , name string ) {
598
+ func DeleteRole (prov client.ConfigProvider , name string ) error {
568
599
iamSvc := iam .New (prov )
569
600
570
601
// if role does not exist, return.
571
602
_ , err := iamSvc .GetRole (& iam.GetRoleInput {RoleName : aws .String (name )})
572
603
if err != nil {
573
- return
604
+ return err
574
605
}
575
606
576
607
if err := detachAllPoliciesForRole (prov , name ); err != nil {
577
- return
608
+ return err
578
609
}
579
610
580
611
_ , err = iamSvc .DeleteRole (& iam.DeleteRoleInput {RoleName : aws .String (name )})
581
612
if err != nil {
582
- return
613
+ return err
583
614
}
615
+
616
+ return nil
584
617
}
585
618
586
619
func GetPolicyArn (prov client.ConfigProvider , name string ) string {
0 commit comments