@ -221,28 +221,17 @@ def compare_assume_role_policy_doc(current_policy_doc, new_policy_doc):
return False
return False
def compare_attached_role_policies ( current_attached_policies , new_attached_policies ) :
@AWSRetry.jittered_backoff ( )
def _list_policies ( connection ) :
# If new_attached_policies is None it means we want to remove all policies
paginator = connection . get_paginator ( ' list_policies ' )
if len ( current_attached_policies ) > 0 and new_attached_policies is None :
policies = paginator . paginate ( ) . build_full_result ( ) [ ' Policies ' ]
return False
current_attached_policies_arn_list = [ ]
for policy in current_attached_policies :
current_attached_policies_arn_list . append ( policy [ ' PolicyArn ' ] )
if set ( current_attached_policies_arn_list ) == set ( new_attached_policies ) :
return True
else :
return False
def convert_friendly_names_to_arns ( connection , module , policy_names ) :
def convert_friendly_names_to_arns ( connection , module , policy_names ) :
if not any ( [ not policy . startswith ( ' arn: ' ) for policy in policy_names ] ) :
if not any ( [ not policy . startswith ( ' arn: ' ) for policy in policy_names ] ) :
return policy_names
return policy_names
allpolicies = { }
allpolicies = { }
paginator = connection . get_paginator ( ' list_policies ' )
policies = _list_policies ( connection )
policies = paginator . paginate ( ) . build_full_result ( ) [ ' Policies ' ]
for policy in policies :
for policy in policies :
allpolicies [ policy [ ' PolicyName ' ] ] = policy [ ' Arn ' ]
allpolicies [ policy [ ' PolicyName ' ] ] = policy [ ' Arn ' ]
@ -253,244 +242,310 @@ def convert_friendly_names_to_arns(connection, module, policy_names):
module . fail_json_aws ( e , msg = " Couldn ' t find policy " )
module . fail_json_aws ( e , msg = " Couldn ' t find policy " )
def attach_policies ( connection , module , policies_to_attach , params ) :
changed = False
for policy_arn in policies_to_attach :
try :
if not module . check_mode :
connection . attach_role_policy ( RoleName = params [ ' RoleName ' ] , PolicyArn = policy_arn , aws_retry = True )
except ( BotoCoreError , ClientError ) as e :
module . fail_json_aws ( e , msg = " Unable to attach policy {0} to role {1} " . format ( policy_arn , params [ ' RoleName ' ] ) )
changed = True
return changed
def remove_policies ( connection , module , policies_to_remove , params ) :
def remove_policies ( connection , module , policies_to_remove , params ) :
changed = False
changed = False
for policy in policies_to_remove :
for policy in policies_to_remove :
try :
try :
if not module . check_mode :
if not module . check_mode :
connection . detach_role_policy ( RoleName = params [ ' RoleName ' ] , PolicyArn = policy )
connection . detach_role_policy ( RoleName = params [ ' RoleName ' ] , PolicyArn = policy , aws_retry = True )
except ClientError as e :
except ( BotoCoreError , ClientError ) as e :
module . fail_json_aws ( e , msg = " Unable to detach policy {0} from {1} " . format ( policy , params [ ' RoleName ' ] ) )
except BotoCoreError as e :
module . fail_json_aws ( e , msg = " Unable to detach policy {0} from {1} " . format ( policy , params [ ' RoleName ' ] ) )
module . fail_json_aws ( e , msg = " Unable to detach policy {0} from {1} " . format ( policy , params [ ' RoleName ' ] ) )
changed = True
changed = True
return changed
return changed
def create_or_update_role( connection , module ) :
def generate_create_params( module ) :
params = dict ( )
params = dict ( )
params [ ' Path ' ] = module . params . get ( ' path ' )
params [ ' Path ' ] = module . params . get ( ' path ' )
params [ ' RoleName ' ] = module . params . get ( ' name ' )
params [ ' RoleName ' ] = module . params . get ( ' name ' )
params [ ' AssumeRolePolicyDocument ' ] = module . params . get ( ' assume_role_policy_document ' )
params [ ' AssumeRolePolicyDocument ' ] = module . params . get ( ' assume_role_policy_document ' )
if module . params . get ( ' max_session_duration ' ) is not None :
params [ ' MaxSessionDuration ' ] = module . params . get ( ' max_session_duration ' )
if module . params . get ( ' description ' ) is not None :
if module . params . get ( ' description ' ) is not None :
params [ ' Description ' ] = module . params . get ( ' description ' )
params [ ' Description ' ] = module . params . get ( ' description ' )
if module . params . get ( ' max_session_duration ' ) is not None :
params [ ' MaxSessionDuration ' ] = module . params . get ( ' max_session_duration ' )
if module . params . get ( ' boundary ' ) is not None :
if module . params . get ( ' boundary ' ) is not None :
params [ ' PermissionsBoundary ' ] = module . params . get ( ' boundary ' )
params [ ' PermissionsBoundary ' ] = module . params . get ( ' boundary ' )
managed_policies = module . params . get ( ' managed_policies ' )
if module . params . get ( ' tags ' ) is not None :
params [ ' Tags ' ] = ansible_dict_to_boto3_tag_list ( module . params . get ( ' tags ' ) )
return params
def create_basic_role ( connection , module , params ) :
"""
Perform the Role creation .
Assumes tests for the role existing have already been performed .
"""
try :
if not module . check_mode :
role = connection . create_role ( aws_retry = True , * * params )
# 'Description' is documented as key of the role returned by create_role
# but appears to be an AWS bug (the value is not returned using the AWS CLI either).
# Get the role after creating it.
role = get_role_with_backoff ( connection , module , params [ ' RoleName ' ] )
else :
role = { ' MadeInCheckMode ' : True }
role [ ' AssumeRolePolicyDocument ' ] = json . loads ( params [ ' AssumeRolePolicyDocument ' ] )
except ( BotoCoreError , ClientError ) as e :
module . fail_json_aws ( e , msg = " Unable to create role " )
return role
def update_role_assumed_policy ( connection , module , params , role ) :
# Check Assumed Policy document
if compare_assume_role_policy_doc ( role [ ' AssumeRolePolicyDocument ' ] , params [ ' AssumeRolePolicyDocument ' ] ) :
return False
if module . check_mode :
return True
try :
connection . update_assume_role_policy (
RoleName = params [ ' RoleName ' ] ,
PolicyDocument = json . dumps ( json . loads ( params [ ' AssumeRolePolicyDocument ' ] ) ) ,
aws_retry = True )
except ( BotoCoreError , ClientError ) as e :
module . fail_json_aws ( e , msg = " Unable to update assume role policy for role {0} " . format ( params [ ' RoleName ' ] ) )
return True
def update_role_description ( connection , module , params , role ) :
# Check Description update
if params . get ( ' Description ' ) is None :
return False
if role . get ( ' Description ' ) == params [ ' Description ' ] :
return False
if module . check_mode :
return True
try :
connection . update_role_description ( RoleName = params [ ' RoleName ' ] , Description = params [ ' Description ' ] , aws_retry = True )
except ( BotoCoreError , ClientError ) as e :
module . fail_json_aws ( e , msg = " Unable to update description for role {0} " . format ( params [ ' RoleName ' ] ) )
return True
def update_role_max_session_duration ( connection , module , params , role ) :
# Check MaxSessionDuration update
if params . get ( ' MaxSessionDuration ' ) is None :
return False
if role . get ( ' MaxSessionDuration ' ) == params [ ' MaxSessionDuration ' ] :
return False
if module . check_mode :
return True
try :
connection . update_role ( RoleName = params [ ' RoleName ' ] , MaxSessionDuration = params [ ' MaxSessionDuration ' ] , aws_retry = True )
except ( BotoCoreError , ClientError ) as e :
module . fail_json_aws ( e , msg = " Unable to update maximum session duration for role {0} " . format ( params [ ' RoleName ' ] ) )
return True
def update_role_permissions_boundary ( connection , module , params , role ) :
# Check PermissionsBoundary
if params . get ( ' PermissionsBoundary ' ) is None :
return False
if params . get ( ' PermissionsBoundary ' ) == role . get ( ' PermissionsBoundary ' , { } ) . get ( ' PermissionsBoundaryArn ' , ' ' ) :
return False
if module . check_mode :
return True
if params . get ( ' PermissionsBoundary ' ) == ' ' :
try :
connection . delete_role_permissions_boundary ( RoleName = params [ ' RoleName ' ] , aws_retry = True )
except ( BotoCoreError , ClientError ) as e :
module . fail_json_aws ( e , msg = " Unable to remove permission boundary for role {0} " . format ( params [ ' RoleName ' ] ) )
else :
try :
connection . put_role_permissions_boundary ( RoleName = params [ ' RoleName ' ] , PermissionsBoundary = params [ ' PermissionsBoundary ' ] , aws_retry = True )
except ( BotoCoreError , ClientError ) as e :
module . fail_json_aws ( e , msg = " Unable to update permission boundary for role {0} " . format ( params [ ' RoleName ' ] ) )
return True
def update_managed_policies ( connection , module , params , role , managed_policies , purge_policies ) :
# Check Managed Policies
if managed_policies is None :
return False
# If we're manipulating a fake role
if role . get ( ' MadeInCheckMode ' , False ) :
role [ ' AttachedPolicies ' ] = list ( map ( lambda x : { ' PolicyArn ' : x , ' PolicyName ' : x . split ( ' : ' ) [ 5 ] } , managed_policies ) )
return True
# Get list of current attached managed policies
current_attached_policies = get_attached_policy_list ( connection , module , params [ ' RoleName ' ] )
current_attached_policies_arn_list = [ policy [ ' PolicyArn ' ] for policy in current_attached_policies ]
if len ( managed_policies ) == 1 and managed_policies [ 0 ] is None :
managed_policies = [ ]
policies_to_remove = set ( current_attached_policies_arn_list ) - set ( managed_policies )
policies_to_attach = set ( managed_policies ) - set ( current_attached_policies_arn_list )
changed = False
if purge_policies :
changed | = remove_policies ( connection , module , policies_to_remove , params )
changed | = attach_policies ( connection , module , policies_to_attach , params )
return changed
def create_or_update_role ( connection , module ) :
params = generate_create_params ( module )
role_name = params [ ' RoleName ' ]
create_instance_profile = module . params . get ( ' create_instance_profile ' )
purge_policies = module . params . get ( ' purge_policies ' )
purge_policies = module . params . get ( ' purge_policies ' )
if purge_policies is None :
if purge_policies is None :
purge_policies = True
purge_policies = True
create_instance_profile = module . params . get ( ' create_instance_profile ' )
managed_policies = module . params . get ( ' managed_policies ' )
if managed_policies :
if managed_policies :
# Attempt to list the policies early so we don't leave things behind if we can't find them.
managed_policies = convert_friendly_names_to_arns ( connection , module , managed_policies )
managed_policies = convert_friendly_names_to_arns ( connection , module , managed_policies )
changed = False
changed = False
# Get role
# Get role
role = get_role ( connection , module , params [ ' RoleName ' ] )
role = get_role ( connection , module , role_name )
# If role is None, create it
# If role is None, create it
if role is None :
if role is None :
try :
role = create_basic_role ( connection , module , params )
if not module . check_mode :
changed = True
role = connection . create_role ( * * params )
# 'Description' is documented as key of the role returned by create_role
# but appears to be an AWS bug (the value is not returned using the AWS CLI either).
# Get the role after creating it.
role = get_role_with_backoff ( connection , module , params [ ' RoleName ' ] )
else :
role = { ' MadeInCheckMode ' : True }
role [ ' AssumeRolePolicyDocument ' ] = json . loads ( params [ ' AssumeRolePolicyDocument ' ] )
changed = True
except ClientError as e :
module . fail_json_aws ( e , msg = " Unable to create role " )
except BotoCoreError as e :
module . fail_json_aws ( e , msg = " Unable to create role " )
else :
else :
# Check Assumed Policy document
changed | = update_role_tags ( connection , module , params , role )
if not compare_assume_role_policy_doc ( role [ ' AssumeRolePolicyDocument ' ] , params [ ' AssumeRolePolicyDocument ' ] ) :
changed | = update_role_assumed_policy ( connection , module , params , role )
try :
changed | = update_role_description ( connection , module , params , role )
if not module . check_mode :
changed | = update_role_max_session_duration ( connection , module , params , role )
connection . update_assume_role_policy ( RoleName = params [ ' RoleName ' ] , PolicyDocument = json . dumps ( json . loads ( params [ ' AssumeRolePolicyDocument ' ] ) ) )
changed | = update_role_permissions_boundary ( connection , module , params , role )
changed = True
except ClientError as e :
module . fail_json_aws ( e , msg = " Unable to update assume role policy for role {0} " . format ( params [ ' RoleName ' ] ) )
except BotoCoreError as e :
module . fail_json_aws ( e , msg = " Unable to update assume role policy for role {0} " . format ( params [ ' RoleName ' ] ) )
if managed_policies is not None :
# Get list of current attached managed policies
current_attached_policies = get_attached_policy_list ( connection , module , params [ ' RoleName ' ] )
current_attached_policies_arn_list = [ policy [ ' PolicyArn ' ] for policy in current_attached_policies ]
# If a single empty list item then all managed policies to be removed
if len ( managed_policies ) == 1 and not managed_policies [ 0 ] and purge_policies :
# Detach policies not present
if remove_policies ( connection , module , set ( current_attached_policies_arn_list ) - set ( managed_policies ) , params ) :
changed = True
else :
# Make a list of the ARNs from the attached policies
# Detach roles not defined in task
if purge_policies :
if remove_policies ( connection , module , set ( current_attached_policies_arn_list ) - set ( managed_policies ) , params ) :
changed = True
# Attach roles not already attached
for policy_arn in set ( managed_policies ) - set ( current_attached_policies_arn_list ) :
try :
if not module . check_mode :
connection . attach_role_policy ( RoleName = params [ ' RoleName ' ] , PolicyArn = policy_arn )
except ClientError as e :
module . fail_json_aws ( e , msg = " Unable to attach policy {0} to role {1} " . format ( policy_arn , params [ ' RoleName ' ] ) )
except BotoCoreError as e :
module . fail_json_aws ( e , msg = " Unable to attach policy {0} to role {1} " . format ( policy_arn , params [ ' RoleName ' ] ) )
changed = True
# Instance profile
if create_instance_profile and not role . get ( ' MadeInCheckMode ' , False ) :
try :
instance_profiles = connection . list_instance_profiles_for_role ( RoleName = params [ ' RoleName ' ] ) [ ' InstanceProfiles ' ]
except ClientError as e :
module . fail_json_aws ( e , msg = " Unable to list instance profiles for role {0} " . format ( params [ ' RoleName ' ] ) )
except BotoCoreError as e :
module . fail_json_aws ( e , msg = " Unable to list instance profiles for role {0} " . format ( params [ ' RoleName ' ] ) )
if not any ( p [ ' InstanceProfileName ' ] == params [ ' RoleName ' ] for p in instance_profiles ) :
# Make sure an instance profile is attached
try :
if not module . check_mode :
connection . create_instance_profile ( InstanceProfileName = params [ ' RoleName ' ] , Path = params [ ' Path ' ] )
changed = True
except ClientError as e :
# If the profile already exists, no problem, move on
if e . response [ ' Error ' ] [ ' Code ' ] == ' EntityAlreadyExists ' :
pass
else :
module . fail_json_aws ( e , msg = " Unable to create instance profile for role {0} " . format ( params [ ' RoleName ' ] ) )
except BotoCoreError as e :
module . fail_json_aws ( e , msg = " Unable to create instance profile for role {0} " . format ( params [ ' RoleName ' ] ) )
if not module . check_mode :
connection . add_role_to_instance_profile ( InstanceProfileName = params [ ' RoleName ' ] , RoleName = params [ ' RoleName ' ] )
# Check Description update
if create_instance_profile :
if not role . get ( ' MadeInCheckMode ' ) and params . get ( ' Description ' ) and role . get ( ' Description ' ) != params [ ' Description ' ] :
changed | = create_instance_profiles ( connection , module , params , role )
try :
if not module . check_mode :
connection . update_role_description ( RoleName = params [ ' RoleName ' ] , Description = params [ ' Description ' ] )
changed = True
changed | = update_managed_policies ( connection , module , params , role , managed_policies , purge_policies )
except ( BotoCoreError , ClientError ) as e :
module . fail_json_aws ( e , msg = " Unable to update description for role {0} " . format ( params [ ' RoleName ' ] ) )
# Check MaxSessionDuration update
if not role . get ( ' MadeInCheckMode ' ) and params . get ( ' MaxSessionDuration ' ) and role . get ( ' MaxSessionDuration ' ) != params [ ' MaxSessionDuration ' ] :
try :
if not module . check_mode :
connection . update_role ( RoleName = params [ ' RoleName ' ] , MaxSessionDuration = params [ ' MaxSessionDuration ' ] )
changed = True
except ( BotoCoreError , ClientError ) as e :
module . fail_json_aws ( e , msg = " Unable to update maximum session duration for role {0} " . format ( params [ ' RoleName ' ] ) )
# Check if permission boundary needs update
if not role . get ( ' MadeInCheckMode ' ) and (
( role . get ( ' PermissionsBoundary ' ) or { } ) . get ( ' PermissionsBoundaryArn ' ) or
params . get ( ' PermissionsBoundary ' ) is not None ) :
# the existing role has a boundary
if module . params . get ( ' boundary ' ) is None :
pass
elif module . params . get ( ' boundary ' ) == ' ' :
if ( role . get ( ' PermissionsBoundary ' ) or { } ) . get ( ' PermissionsBoundaryArn ' ) :
try :
if not module . check_mode :
connection . delete_role_permissions_boundary ( RoleName = params [ ' RoleName ' ] )
changed = True
except ( BotoCoreError , ClientError ) as e :
module . fail_json_aws ( e , msg = " Unable to remove permission boundary for role {0} " . format ( params [ ' RoleName ' ] ) )
elif ( role . get ( ' PermissionsBoundary ' ) or { } ) . get ( ' PermissionsBoundaryArn ' ) != params [ ' PermissionsBoundary ' ] :
try :
if not module . check_mode :
connection . put_role_permissions_boundary ( RoleName = params [ ' RoleName ' ] , PermissionsBoundary = params [ ' PermissionsBoundary ' ] )
changed = True
except ( BotoCoreError , ClientError ) as e :
module . fail_json_aws ( e , msg = " Unable to update permission boundary for role {0} " . format ( params [ ' RoleName ' ] ) )
# Get the role again
# Get the role again
if not role . get ( ' MadeInCheckMode ' , False ) :
if not role . get ( ' MadeInCheckMode ' , False ) :
role = get_role ( connection , module , params [ ' RoleName ' ] )
role = get_role ( connection , module , params [ ' RoleName ' ] )
role [ ' attached_policies ' ] = get_attached_policy_list ( connection , module , params [ ' RoleName ' ] )
role [ ' AttachedPolicies ' ] = get_attached_policy_list ( connection , module , params [ ' RoleName ' ] )
role [ ' tags ' ] = get_role_tags ( connection , module )
# Manage tags
module . exit_json (
tags_changed = update_role_tags ( connection , module )
changed = changed , iam_role = camel_dict_to_snake_dict ( role , ignore_list = [ ' tags ' ] ) ,
changed | = tags_changed
* * camel_dict_to_snake_dict ( role , ignore_list = [ ' tags ' ] ) )
role [ ' tags ' ] = get_role_tags ( connection , module )
module . exit_json ( changed = changed , iam_role = camel_dict_to_snake_dict ( role , ignore_list = [ ' tags ' ] ) , * * camel_dict_to_snake_dict ( role , ignore_list = [ ' tags ' ] ) )
def create_instance_profiles ( connection , module , params , role ) :
def destroy_role ( connection , module ) :
if role . get ( ' MadeInCheckMode ' , False ) :
return False
params = dict ( )
# Fetch existing Profiles
params [ ' RoleName ' ] = module . params . get ( ' name ' )
try :
instance_profiles = connection . list_instance_profiles_for_role ( RoleName = params [ ' RoleName ' ] , aws_retry = True ) [ ' InstanceProfiles ' ]
except ( BotoCoreError , ClientError ) as e :
module . fail_json_aws ( e , msg = " Unable to list instance profiles for role {0} " . format ( params [ ' RoleName ' ] ) )
role = get_role ( connection , module , params [ ' RoleName ' ] )
# Profile already exists
if any ( p [ ' InstanceProfileName ' ] == params [ ' RoleName ' ] for p in instance_profiles ) :
return False
if role :
if module . check_mode :
return True
# We need to remove any instance profiles from the role before we delete it
# Make sure an instance profile is created
try :
try :
instance_profiles = connection . list_instance_profiles_for_role ( RoleName = params [ ' RoleName ' ] ) [ ' InstanceProfiles ' ]
connection . create_instance_profile ( InstanceProfileName = params [ ' RoleName ' ] , Path = params [ ' Path ' ] , aws_retry = True )
except ClientError as e :
except ClientError as e :
module . fail_json_aws ( e , msg = " Unable to list instance profiles for role {0} " . format ( params [ ' RoleName ' ] ) )
# If the profile already exists, no problem, move on.
except BotoCoreError as e :
# Implies someone's changing things at the same time...
module . fail_json_aws ( e , msg = " Unable to list instance profiles for role {0} " . format ( params [ ' RoleName ' ] ) )
if e . response [ ' Error ' ] [ ' Code ' ] == ' EntityAlreadyExists ' :
return False
if role . get ( ' PermissionsBoundary ' ) is not None :
else :
try :
module . fail_json_aws ( e , msg = " Unable to create instance profile for role {0} " . format ( params [ ' RoleName ' ] ) )
connection . delete_role_permissions_boundary ( RoleName = params [ ' RoleName ' ] )
except BotoCoreError as e :
except ( ClientError , BotoCoreError ) as e :
module . fail_json_aws ( e , msg = " Unable to create instance profile for role {0} " . format ( params [ ' RoleName ' ] ) )
module . fail_json_aws ( e , msg = " Could not delete role permission boundary on role {0} " . format ( params [ ' RoleName ' ] ) )
# And attach the role to the profile
# Now remove the role from the instance profile(s)
try :
for profile in instance_profiles :
connection . add_role_to_instance_profile ( InstanceProfileName = params [ ' RoleName ' ] , RoleName = params [ ' RoleName ' ] , aws_retry = True )
try :
except ( BotoCoreError , ClientError ) as e :
if not module . check_mode :
module . fail_json_aws ( e , msg = " Unable to attach role {0} to instance profile {0} " . format ( params [ ' RoleName ' ] ) )
connection . remove_role_from_instance_profile ( InstanceProfileName = profile [ ' InstanceProfileName ' ] , RoleName = params [ ' RoleName ' ] )
if profile [ ' InstanceProfileName ' ] == params [ ' RoleName ' ] :
return True
if module . params . get ( " delete_instance_profile " ) :
try :
connection . delete_instance_profile ( InstanceProfileName = profile [ ' InstanceProfileName ' ] )
def remove_instance_profiles ( connection , module , role_params , role ) :
except ClientError as e :
role_name = module . params . get ( ' name ' )
module . fail_json_aws ( e , msg = " Unable to remove instance profile {0} " . format ( profile [ ' InstanceProfileName ' ] ) )
delete_profiles = module . params . get ( " delete_instance_profile " )
except ClientError as e :
module . fail_json_aws ( e , msg = " Unable to remove role {0} from instance profile {1} " . format (
try :
params [ ' RoleName ' ] , profile [ ' InstanceProfileName ' ] ) )
instance_profiles = connection . list_instance_profiles_for_role ( aws_retry = True , * * role_params ) [ ' InstanceProfiles ' ]
except BotoCoreError as e :
except ( BotoCoreError , ClientError ) as e :
module . fail_json_aws ( e , msg = " Unable to remove role {0} from instance profile {1} " . format (
module . fail_json_aws ( e , msg = " Unable to list instance profiles for role {0} " . format ( role_name ) )
params [ ' RoleName ' ] , profile [ ' InstanceProfileName ' ] ) )
# Now remove any attached policies otherwise deletion fails
try :
for policy in get_attached_policy_list ( connection , module , params [ ' RoleName ' ] ) :
if not module . check_mode :
connection . detach_role_policy ( RoleName = params [ ' RoleName ' ] , PolicyArn = policy [ ' PolicyArn ' ] )
except ClientError as e :
module . fail_json_aws ( e , msg = " Unable to detach policy {0} from role {1} " . format ( policy [ ' PolicyArn ' ] , params [ ' RoleName ' ] ) )
except BotoCoreError as e :
module . fail_json_aws ( e , msg = " Unable to detach policy {0} from role {1} " . format ( policy [ ' PolicyArn ' ] , params [ ' RoleName ' ] ) )
# Remove the role from the instance profile(s)
for profile in instance_profiles :
profile_name = profile [ ' InstanceProfileName ' ]
try :
try :
if not module . check_mode :
if not module . check_mode :
connection . delete_role ( * * params )
connection . remove_role_from_instance_profile ( aws_retry = True , InstanceProfileName = profile_name , * * role_params )
except ClientError as e :
if profile_name == role_name :
module . fail_json_aws ( e , msg = " Unable to delete role " )
if delete_profiles :
except BotoCoreError as e :
try :
module . fail_json_aws ( e , msg = " Unable to delete role " )
connection . delete_instance_profile ( InstanceProfileName = profile_name , aws_retry = True )
else :
except ( BotoCoreError , ClientError ) as e :
module . fail_json_aws ( e , msg = " Unable to remove instance profile {0} " . format ( profile_name ) )
except ( BotoCoreError , ClientError ) as e :
module . fail_json_aws ( e , msg = " Unable to remove role {0} from instance profile {1} " . format ( role_name , profile_name ) )
def destroy_role ( connection , module ) :
role_name = module . params . get ( ' name ' )
role = get_role ( connection , module , role_name )
role_params = dict ( )
role_params [ ' RoleName ' ] = role_name
boundary_params = dict ( role_params )
boundary_params [ ' PermissionsBoundary ' ] = ' '
if role is None :
module . exit_json ( changed = False )
module . exit_json ( changed = False )
# Before we try to delete the role we need to remove any
# - attached instance profiles
# - attached managed policies
# - permissions boundary
remove_instance_profiles ( connection , module , role_params , role )
update_managed_policies ( connection , module , role_params , role , [ ] , True )
update_role_permissions_boundary ( connection , module , boundary_params , role )
try :
if not module . check_mode :
connection . delete_role ( aws_retry = True , * * role_params )
except ( BotoCoreError , ClientError ) as e :
module . fail_json_aws ( e , msg = " Unable to delete role " )
module . exit_json ( changed = True )
module . exit_json ( changed = True )
@ -503,7 +558,7 @@ def get_role_with_backoff(connection, module, name):
def get_role ( connection , module , name ) :
def get_role ( connection , module , name ) :
try :
try :
return connection . get_role ( RoleName = name )[ ' Role ' ]
return connection . get_role ( RoleName = name , aws_retry = True )[ ' Role ' ]
except ClientError as e :
except ClientError as e :
if e . response [ ' Error ' ] [ ' Code ' ] == ' NoSuchEntity ' :
if e . response [ ' Error ' ] [ ' Code ' ] == ' NoSuchEntity ' :
return None
return None
@ -514,15 +569,9 @@ def get_role(connection, module, name):
def get_attached_policy_list ( connection , module , name ) :
def get_attached_policy_list ( connection , module , name ) :
try :
try :
return connection . list_attached_role_policies ( RoleName = name ) [ ' AttachedPolicies ' ]
return connection . list_attached_role_policies ( RoleName = name , aws_retry = True ) [ ' AttachedPolicies ' ]
except ClientError as e :
except ( ClientError , BotoCoreError ) as e :
if e . response [ ' Error ' ] [ ' Code ' ] == ' NoSuchEntity ' :
return [ ]
else :
module . fail_json_aws ( e , msg = " Unable to list attached policies for role {0} " . format ( name ) )
except BotoCoreError as e :
module . fail_json_aws ( e , msg = " Unable to list attached policies for role {0} " . format ( name ) )
module . fail_json_aws ( e , msg = " Unable to list attached policies for role {0} " . format ( name ) )
@ -531,21 +580,22 @@ def get_role_tags(connection, module):
if not hasattr ( connection , ' list_role_tags ' ) :
if not hasattr ( connection , ' list_role_tags ' ) :
return { }
return { }
try :
try :
return boto3_tag_list_to_ansible_dict ( connection . list_role_tags ( RoleName = role_name )[ ' Tags ' ] )
return boto3_tag_list_to_ansible_dict ( connection . list_role_tags ( RoleName = role_name , aws_retry = True )[ ' Tags ' ] )
except ClientError :
except ( ClientError , BotoCoreError ) as e :
return { }
module . fail_json_aws ( e , msg = " Unable to list tags for role {0} " . format ( role_name ) )
def update_role_tags ( connection , module ):
def update_role_tags ( connection , module , params , role ):
new_tags = module. params. get ( ' t ags' )
new_tags = params. get ( ' T ags' )
if new_tags is None :
if new_tags is None :
return False
return False
new_tags = boto3_tag_list_to_ansible_dict ( new_tags )
role_name = module . params . get ( ' name ' )
role_name = module . params . get ( ' name ' )
purge_tags = module . params . get ( ' purge_tags ' )
purge_tags = module . params . get ( ' purge_tags ' )
try :
try :
existing_tags = boto3_tag_list_to_ansible_dict ( connection . list_role_tags ( RoleName = role_name )[ ' Tags ' ] )
existing_tags = boto3_tag_list_to_ansible_dict ( connection . list_role_tags ( RoleName = role_name , aws_retry = True )[ ' Tags ' ] )
except ( ClientError , KeyError ) :
except ( ClientError , KeyError ) :
existing_tags = { }
existing_tags = { }
@ -554,9 +604,9 @@ def update_role_tags(connection, module):
if not module . check_mode :
if not module . check_mode :
try :
try :
if tags_to_remove :
if tags_to_remove :
connection . untag_role ( RoleName = role_name , TagKeys = tags_to_remove )
connection . untag_role ( RoleName = role_name , TagKeys = tags_to_remove , aws_retry = True )
if tags_to_add :
if tags_to_add :
connection . tag_role ( RoleName = role_name , Tags = ansible_dict_to_boto3_tag_list ( tags_to_add ) )
connection . tag_role ( RoleName = role_name , Tags = ansible_dict_to_boto3_tag_list ( tags_to_add ) , aws_retry = True )
except ( ClientError , BotoCoreError ) as e :
except ( ClientError , BotoCoreError ) as e :
module . fail_json_aws ( e , msg = ' Unable to set tags for role %s ' % role_name )
module . fail_json_aws ( e , msg = ' Unable to set tags for role %s ' % role_name )
@ -609,7 +659,7 @@ def main():
if not path . endswith ( ' / ' ) or not path . startswith ( ' / ' ) :
if not path . endswith ( ' / ' ) or not path . startswith ( ' / ' ) :
module . fail_json ( msg = " path must begin and end with / " )
module . fail_json ( msg = " path must begin and end with / " )
connection = module . client ( ' iam ' )
connection = module . client ( ' iam ' , retry_decorator = AWSRetry . jittered_backoff ( ) )
state = module . params . get ( " state " )
state = module . params . get ( " state " )