@@ -469,73 +469,104 @@ func SetMultitenancyEnvVars(prov client.ConfigProvider) error {
469469func deleteResourcesInCloudFormation (prov client.ConfigProvider , t * cfn_bootstrap.Template ) {
470470 iamSvc := iam .New (prov )
471471 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.
472481 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 :
476484 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" :
491487 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" :
505490 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
525556 }
526557 }
527558 }
528- if val .AWSCloudFormationType () == configservice .ResourceTypeAwsIamGroup {
529- group := val .(* cfn_iam.Group )
530- _ , _ = iamSvc .DeleteGroup (& iam.DeleteGroupInput {GroupName : aws .String (group .GroupName )})
531- }
532559 }
533560}
534561
535562// TODO: remove once test infra accounts are fixed.
536563func 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+ }
539570}
540571
541572// detachAllPoliciesForRole detaches all policies for role.
@@ -564,23 +595,25 @@ func detachAllPoliciesForRole(prov client.ConfigProvider, name string) error {
564595}
565596
566597// 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 {
568599 iamSvc := iam .New (prov )
569600
570601 // if role does not exist, return.
571602 _ , err := iamSvc .GetRole (& iam.GetRoleInput {RoleName : aws .String (name )})
572603 if err != nil {
573- return
604+ return err
574605 }
575606
576607 if err := detachAllPoliciesForRole (prov , name ); err != nil {
577- return
608+ return err
578609 }
579610
580611 _ , err = iamSvc .DeleteRole (& iam.DeleteRoleInput {RoleName : aws .String (name )})
581612 if err != nil {
582- return
613+ return err
583614 }
615+
616+ return nil
584617}
585618
586619func GetPolicyArn (prov client.ConfigProvider , name string ) string {
0 commit comments