[cloud] Add support for updating IAM role with ec2_instance module (#38812)

* [cloud] Add support for updating IAM role with ec2_instance module

* Add test for updating IAM role
This commit is contained in:
Ryan Brown 2018-04-17 15:02:46 -04:00 committed by GitHub
parent 4117b2dd29
commit 44d06f8858
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 75 additions and 3 deletions

View file

@ -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(

View file

@ -19,6 +19,17 @@
<<: *aws_connection_info
register: iam_role
- name: Create second IAM role for test
iam_role:
name: "{{ resource_prefix }}-test-policy-2"
assume_role_policy_document: "{{ lookup('file','assume-role-policy.json') }}"
state: present
create_instance_profile: yes
managed_policy:
- AmazonEC2ContainerServiceRole
<<: *aws_connection_info
register: iam_role_2
- name: Wait for IAM role to be available, otherwise the next step will fail (Invalid IAM Instance Profile name)
command: sleep 10
@ -36,6 +47,21 @@
that:
- 'instance_with_role.instances[0].iam_instance_profile.arn == iam_role.arn.replace(":role/", ":instance-profile/")'
- name: Update instance with new instance_role
ec2_instance:
name: "{{ resource_prefix }}-test-default-vpc"
image_id: "{{ ec2_ami_image[aws_region] }}"
security_groups: "{{ sg.group_id }}"
instance_type: t2.micro
instance_role: "{{ resource_prefix }}-test-policy-2"
<<: *aws_connection_info
register: instance_with_updated_role
- assert:
that:
- 'instance_with_updated_role.instances[0].iam_instance_profile.arn == iam_role_2.arn.replace(":role/", ":instance-profile/")'
- 'instance_with_updated_role.instances[0].instance_id == instance_with_role.instances[0].instance_id'
always:
- name: Terminate instance
ec2:
@ -49,13 +75,16 @@
- name: Delete IAM role for test
iam_role:
name: "{{ resource_prefix }}-test-policy"
name: "{{ item }}"
assume_role_policy_document: "{{ lookup('file','assume-role-policy.json') }}"
state: absent
create_instance_profile: yes
managed_policy:
- AmazonEC2ContainerServiceRole
<<: *aws_connection_info
loop:
- "{{ resource_prefix }}-test-policy"
- "{{ resource_prefix }}-test-policy-2"
register: removed
until: removed is not failed
ignore_errors: yes