diff options
author | Ryan S. Brown <sb@ryansb.com> | 2018-04-13 16:28:50 -0400 |
---|---|---|
committer | Ryan S. Brown <sb@ryansb.com> | 2018-04-13 16:28:50 -0400 |
commit | f1ee3f8c0033a892d892e781880107ecb81c3117 (patch) | |
tree | f6239ee65669cc1a329cb8432ec15be487e7aca4 | |
parent | 53a3b8b602610dbf4428ea532a097dc467fcf181 (diff) | |
download | ansible-ec2_instance_role_switching.tar.gz |
[cloud] Add support for updating IAM role with ec2_instance moduleec2_instance_role_switching
-rw-r--r-- | lib/ansible/modules/cloud/amazon/ec2_instance.py | 47 |
1 files changed, 45 insertions, 2 deletions
diff --git a/lib/ansible/modules/cloud/amazon/ec2_instance.py b/lib/ansible/modules/cloud/amazon/ec2_instance.py index 9437afee4a..86c2e7cb1e 100644 --- a/lib/ansible/modules/cloud/amazon/ec2_instance.py +++ b/lib/ansible/modules/cloud/amazon/ec2_instance.py @@ -737,6 +737,47 @@ def build_volume_spec(params): return [ec2_utils.snake_dict_to_camel_dict(v, capitalize_first=True) for v in volumes] +def add_or_update_instance_profile(instance, desired_profile_name): + instance_profile_setting = instance.get('IamInstanceProfile') + if instance_profile_setting and desired_profile_name: + if desired_profile_name in (instance_profile_setting.get('Name'), instance_profile_setting.get('Arn')): + # great, the profile we asked for is what's there + return False + else: + desired_arn = determine_iam_role(desired_profile_name) + if instance_profile_setting.get('Arn') == desired_arn: + return False + # update association + ec2 = module.client('ec2') + try: + association = ec2.describe_iam_instance_profile_associations(Filters=[{'Name': 'instance-id', 'Values': [instance['InstanceId']]}]) + except botocore.exceptions.ClientError as e: + # check for InvalidAssociationID.NotFound + module.fail_json_aws(e, "Could not find instance profile association") + try: + resp = ec2.replace_iam_instance_profile_association( + AssociationId=association['IamInstanceProfileAssociations'][0]['AssociationId'], + IamInstanceProfile={'Arn': determine_iam_role(desired_profile_name)} + ) + return True + except botocore.exceptions.ClientError as e: + module.fail_json_aws(e, "Could not associate instance profile") + + if not instance_profile_setting and desired_profile_name: + # create association + ec2 = module.client('ec2') + try: + resp = ec2.associate_iam_instance_profile( + IamInstanceProfile={'Arn': determine_iam_role(desired_profile_name)}, + InstanceId=instance['InstanceId'] + ) + return True + except botocore.exceptions.ClientError as e: + module.fail_json_aws(e, "Could not associate new instance profile") + + return False + + def build_network_spec(params, ec2=None): """ Returns list of interfaces [complex] @@ -1292,9 +1333,9 @@ def pretty_instance(i): def determine_iam_role(name_or_arn): if re.match(r'^arn:aws:iam::\d+:instance-profile/[\w+=/,.@-]+$', name_or_arn): return name_or_arn - iam = module.client('iam') + iam = module.client('iam', retry_decorator=AWSRetry.jittered_backoff()) try: - role = iam.get_instance_profile(InstanceProfileName=name_or_arn) + role = iam.get_instance_profile(InstanceProfileName=name_or_arn, aws_retry=True) return role['InstanceProfile']['Arn'] except botocore.exceptions.ClientError as e: if e.response['Error']['Code'] == 'NoSuchEntity': @@ -1313,6 +1354,8 @@ def handle_existing(existing_matches, changed, ec2, state): changes = diff_instance_and_params(existing_matches[0], module.params) for c in changes: ec2.modify_instance_attribute(**c) + changed |= bool(changes) + changed |= add_or_update_instance_profile(existing_matches[0], module.params.get('instance_role')) changed |= change_network_attachments(existing_matches[0], module.params, ec2) altered = find_instances(ec2, ids=[i['InstanceId'] for i in existing_matches]) module.exit_json( |