[cloud] Follow up on FIXMEs in ec2_ami & ec2_ami tests (#32337)

* Several tests were marked as FIXME and should have been fixed with
the boto3 move.

* Improved tags output. Add purge_tags option (default: no)

* Allow description and tags update

* Return launch_permissions

* Allow empty launch permissions for image creation

* Empty launch permissions should work the same way for image
creation as no launch permissions

* Cope with ephemeral devices in AMI block device mapping

* Ephemeral devices can appear in AMI block devices, and this information should be returned

* Fix notation for creating sets from comprehensions
This commit is contained in:
Will Thames 2017-10-30 17:45:11 +10:00 committed by Ryan S. Brown
parent 1eae3b6b59
commit 60b29cf57d
2 changed files with 223 additions and 192 deletions

View file

@ -1,18 +1,9 @@
#!/usr/bin/python #!/usr/bin/python
# This file is part of Ansible # Copyright: Ansible Project
# # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
# Ansible is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by from __future__ import absolute_import, division, print_function
# the Free Software Foundation, either version 3 of the License, or __metaclass__ = type
# (at your option) any later version.
#
# Ansible is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
ANSIBLE_METADATA = {'metadata_version': '1.1', ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['stableinterface'], 'status': ['stableinterface'],
@ -91,10 +82,15 @@ options:
description: description:
- A dictionary of tags to add to the new image; '{"key":"value"}' and '{"key":"value","key":"value"}' - A dictionary of tags to add to the new image; '{"key":"value"}' and '{"key":"value","key":"value"}'
version_added: "2.0" version_added: "2.0"
purge_tags:
description: Whether to remove existing tags that aren't passed in the C(tags) parameter
version_added: "2.5"
default: "no"
launch_permissions: launch_permissions:
description: description:
- Users and groups that should be able to launch the AMI. Expects dictionary with a key of user_ids and/or group_names. user_ids should - Users and groups that should be able to launch the AMI. Expects dictionary with a key of user_ids and/or group_names. user_ids should
be a list of account ids. group_name should be a list of groups, "all" is the only acceptable value currently. be a list of account ids. group_name should be a list of groups, "all" is the only acceptable value currently.
- You must pass all desired launch permissions if you wish to modify existing launch permissions (passing just groups will remove all users)
version_added: "2.0" version_added: "2.0"
image_location: image_location:
description: description:
@ -257,6 +253,12 @@ is_public:
returned: when AMI is created or already exists returned: when AMI is created or already exists
type: bool type: bool
sample: false sample: false
launch_permission:
description: permissions allowing other accounts to access the AMI
returned: when AMI is created or already exists
type: list
sample:
- group: "all"
location: location:
description: location of image description: location of image
returned: when AMI is created or already exists returned: when AMI is created or already exists
@ -315,14 +317,10 @@ snapshots_deleted:
] ]
''' '''
# import module snippets
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.ec2 import ec2_connect, ec2_argument_spec, ansible_dict_to_boto3_tag_list
import time import time
import traceback from ansible.module_utils.ec2 import get_aws_connection_info, ec2_argument_spec, boto3_conn, camel_dict_to_snake_dict
from ansible.module_utils.ec2 import get_aws_connection_info, ec2_argument_spec, ec2_connect, boto3_conn, camel_dict_to_snake_dict, HAS_BOTO3 from ansible.module_utils.ec2 import ansible_dict_to_boto3_tag_list, boto3_tag_list_to_ansible_dict, compare_aws_tags
from ansible.module_utils.basic import AnsibleModule from ansible.module_utils.aws.core import AnsibleAWSModule
try: try:
import botocore import botocore
@ -336,6 +334,7 @@ def get_block_device_mapping(image):
bdm = image.get('block_device_mappings') bdm = image.get('block_device_mappings')
for device in bdm: for device in bdm:
device_name = device.get('device_name') device_name = device.get('device_name')
if 'ebs' in device:
ebs = device.get("ebs") ebs = device.get("ebs")
bdm_dict_item = { bdm_dict_item = {
'size': ebs.get("volume_size"), 'size': ebs.get("volume_size"),
@ -344,6 +343,8 @@ def get_block_device_mapping(image):
'encrypted': ebs.get("encrypted"), 'encrypted': ebs.get("encrypted"),
'delete_on_termination': ebs.get("delete_on_termination") 'delete_on_termination': ebs.get("delete_on_termination")
} }
elif 'virtual_name' in device:
bdm_dict_item = dict(virtual_name=device['virtual_name'])
bdm_dict[device_name] = bdm_dict_item bdm_dict[device_name] = bdm_dict_item
return bdm_dict return bdm_dict
@ -363,9 +364,9 @@ def get_ami_info(camel_image):
ownerId=image.get("owner_id"), ownerId=image.get("owner_id"),
root_device_name=image.get("root_device_name"), root_device_name=image.get("root_device_name"),
root_device_type=image.get("root_device_type"), root_device_type=image.get("root_device_type"),
tags=image.get("tags"),
virtualization_type=image.get("virtualization_type"), virtualization_type=image.get("virtualization_type"),
name=image.get("name"), name=image.get("name"),
tags=boto3_tag_list_to_ansible_dict(image.get('tags')),
platform=image.get("platform"), platform=image.get("platform"),
enhanced_networking=image.get("ena_support"), enhanced_networking=image.get("ena_support"),
image_owner_alias=image.get("image_owner_alias"), image_owner_alias=image.get("image_owner_alias"),
@ -374,11 +375,12 @@ def get_ami_info(camel_image):
product_codes=image.get("product_codes"), product_codes=image.get("product_codes"),
ramdisk_id=image.get("ramdisk_id"), ramdisk_id=image.get("ramdisk_id"),
sriov_net_support=image.get("sriov_net_support"), sriov_net_support=image.get("sriov_net_support"),
state_reason=image.get("state_reason") state_reason=image.get("state_reason"),
launch_permissions=image.get('launch_permissions')
) )
def create_image(module, connection, resource): def create_image(module, connection):
instance_id = module.params.get('instance_id') instance_id = module.params.get('instance_id')
name = module.params.get('name') name = module.params.get('name')
wait = module.params.get('wait') wait = module.params.get('wait')
@ -413,10 +415,6 @@ def create_image(module, connection, resource):
] ]
).get('Images') ).get('Images')
# ensure that launch_permissions are up to date
if images and images[0]:
update_image(module, connection, images[0].get('ImageId'), resource)
block_device_mapping = None block_device_mapping = None
if device_mapping: if device_mapping:
@ -462,39 +460,35 @@ def create_image(module, connection, resource):
if root_device_name: if root_device_name:
params['RootDeviceName'] = root_device_name params['RootDeviceName'] = root_device_name
image_id = connection.register_image(**params).get('ImageId') image_id = connection.register_image(**params).get('ImageId')
except botocore.exceptions.ClientError as e: except (botocore.exceptions.BotoCoreError, botocore.exceptions.ClientError) as e:
module.fail_json(msg="Error registering image - " + str(e), exception=traceback.format_exc(), module.fail_json_aws(e, msg="Error registering image")
**camel_dict_to_snake_dict(e.response))
for i in range(wait_timeout): if wait:
try: waiter = connection.get_waiter('image_available')
image = get_image_by_id(module, connection, image_id) delay = wait_timeout // 30
if image.get('State') == 'available': max_attempts = 30
break waiter.wait(ImageIds=[image_id], WaiterConfig=dict(Delay=delay, MaxAttempts=max_attempts))
elif image.get('State') == 'failed':
module.fail_json(msg="AMI creation failed, please see the AWS console for more details.")
except botocore.exceptions.ClientError as e:
if ('InvalidAMIID.NotFound' not in e.error_code and 'InvalidAMIID.Unavailable' not in e.error_code) and wait and i == wait_timeout - 1:
module.fail_json(msg="Error while trying to find the new image. Using wait=yes and/or a longer wait_timeout may help. %s: %s"
% (e.error_code, e.error_message))
finally:
time.sleep(1)
if tags: if tags:
try: try:
connection.create_tags(Resources=[image_id], Tags=ansible_dict_to_boto3_tag_list(tags)) connection.create_tags(Resources=[image_id], Tags=ansible_dict_to_boto3_tag_list(tags))
except botocore.exceptions.ClientError as e: except (botocore.exceptions.BotoCoreError, botocore.exceptions.ClientError) as e:
module.fail_json(msg="Error tagging image - " + str(e), exception=traceback.format_exc(), **camel_dict_to_snake_dict(e.response)) module.fail_json_aws(e, msg="Error tagging image")
if launch_permissions: if launch_permissions:
try: try:
image = get_image_by_id(module, connection, image_id) params = dict(Attribute='LaunchPermission', ImageId=image_id, LaunchPermission=dict(Add=list()))
image.set_launch_permissions(**launch_permissions) for group_name in launch_permissions.get('group_names', []):
except botocore.exceptions.ClientError as e: params['LaunchPermission']['Add'].append(dict(Group=group_name))
module.fail_json(msg="Error setting launch permissions for image: " + image_id + " - " + str(e), exception=traceback.format_exc(), for user_id in launch_permissions.get('user_ids', []):
**camel_dict_to_snake_dict(e.response)) params['LaunchPermission']['Add'].append(dict(UserId=str(user_id)))
if params['LaunchPermission']['Add']:
connection.modify_image_attribute(**params)
except (botocore.exceptions.BotoCoreError, botocore.exceptions.ClientError) as e:
module.fail_json_aws(e, msg="Error setting launch permissions for image %s" % image_id)
module.exit_json(msg="AMI creation operation complete.", changed=True, **get_ami_info(image)) module.exit_json(msg="AMI creation operation complete.", changed=True,
**get_ami_info(get_image_by_id(module, connection, image_id)))
def deregister_image(module, connection): def deregister_image(module, connection):
@ -505,7 +499,7 @@ def deregister_image(module, connection):
image = get_image_by_id(module, connection, image_id) image = get_image_by_id(module, connection, image_id)
if image is None: if image is None:
module.fail_json(msg="Image %s does not exist." % image_id, changed=False) module.exit_json(changed=False)
# Get all associated snapshot ids before deregistering image otherwise this information becomes unavailable. # Get all associated snapshot ids before deregistering image otherwise this information becomes unavailable.
snapshots = [] snapshots = []
@ -518,9 +512,9 @@ def deregister_image(module, connection):
# When trying to re-deregister an already deregistered image it doesn't raise an exception, it just returns an object without image attributes. # When trying to re-deregister an already deregistered image it doesn't raise an exception, it just returns an object without image attributes.
if 'ImageId' in image: if 'ImageId' in image:
try: try:
res = connection.deregister_image(ImageId=image_id) connection.deregister_image(ImageId=image_id)
except botocore.exceptions.ClientError as e: except (botocore.exceptions.BotoCoreError, botocore.exceptions.ClientError) as e:
module.fail_json(msg="Error deregistering image - " + str(e), exception=traceback.format_exc(), **camel_dict_to_snake_dict(e.response)) module.fail_json_aws(e, msg="Error deregistering image")
else: else:
module.exit_json(msg="Image %s has already been deregistered." % image_id, changed=False) module.exit_json(msg="Image %s has already been deregistered." % image_id, changed=False)
@ -542,69 +536,103 @@ def deregister_image(module, connection):
connection.delete_snapshot(SnapshotId=snapshot_id) connection.delete_snapshot(SnapshotId=snapshot_id)
except botocore.exceptions.ClientError as e: except botocore.exceptions.ClientError as e:
# Don't error out if root volume snapshot was already deregistered as part of deregister_image # Don't error out if root volume snapshot was already deregistered as part of deregister_image
if e.error_code == 'InvalidSnapshot.NotFound': if e.response['Error']['Code'] == 'InvalidSnapshot.NotFound':
pass pass
exit_params['snapshots_deleted'] = snapshots exit_params['snapshots_deleted'] = snapshots
module.exit_json(**exit_params) module.exit_json(**exit_params)
def update_image(module, connection, image_id, resource): def update_image(module, connection, image_id):
launch_permissions = module.params.get('launch_permissions') or [] launch_permissions = module.params.get('launch_permissions')
image = get_image_by_id(module, connection, image_id)
if 'user_ids' in launch_permissions:
launch_permissions['user_ids'] = [str(user_id) for user_id in launch_permissions['user_ids']]
image = resource.Image(image_id)
if image is None: if image is None:
module.fail_json(msg="Image %s does not exist" % image_id, changed=False) module.fail_json(msg="Image %s does not exist" % image_id, changed=False)
changed = False
if launch_permissions is not None:
current_permissions = image['LaunchPermissions']
current_users = set(permission['UserId'] for permission in current_permissions if 'UserId' in permission)
desired_users = set(str(user_id) for user_id in launch_permissions.get('user_ids', []))
current_groups = set(permission['Group'] for permission in current_permissions if 'Group' in permission)
desired_groups = set(launch_permissions.get('group_names', []))
to_add_users = desired_users - current_users
to_remove_users = current_users - desired_users
to_add_groups = desired_groups - current_groups
to_remove_groups = current_groups - desired_groups
to_add = [dict(Group=group) for group in to_add_groups] + [dict(UserId=user_id) for user_id in to_add_users]
to_remove = [dict(Group=group) for group in to_remove_groups] + [dict(UserId=user_id) for user_id in to_remove_users]
if to_add or to_remove:
try: try:
set_permissions = connection.describe_image_attribute(Attribute='launchPermission', ImageId=image_id).get('LaunchPermissions') connection.modify_image_attribute(ImageId=image_id, Attribute='launchPermission',
if set_permissions != launch_permissions: LaunchPermission=dict(Add=to_add, Remove=to_remove))
if ('user_ids' in launch_permissions or 'group_names' in launch_permissions): changed = True
group_names = launch_permissions.get('group_names')[0] if launch_permissions.get('group_names') else None except (botocore.exceptions.BotoCoreError, botocore.exceptions.ClientError) as e:
user_ids = launch_permissions.get('user_ids')[0] if launch_permissions.get('user_ids') else None module.fail_json_aws(e, msg="Error updating launch permissions")
launch_perms_add = {'Add': [{}]}
if group_names: desired_tags = module.params.get('tags')
launch_perms_add['Add'][0]['Group'] = group_names if desired_tags is not None:
if user_ids: current_tags = boto3_tag_list_to_ansible_dict(image.get('Tags'))
launch_perms_add['Add'][0]['UserId'] = user_ids tags_to_add, tags_to_remove = compare_aws_tags(current_tags, desired_tags, purge_tags=module.params.get('purge_tags'))
image.modify_attribute(Attribute='launchPermission', LaunchPermission=launch_perms_add)
elif set_permissions and set_permissions[0].get('UserId') is not None and set_permissions[0].get('Group') is not None: if tags_to_remove:
image.modify_attribute( try:
Attribute='launchPermission', connection.delete_tags(Resources=[image_id], Tags=[dict(Key=tagkey) for tagkey in tags_to_remove])
LaunchPermission={ changed = True
'Remove': [{ except (botocore.exceptions.BotoCoreError, botocore.exceptions.ClientError) as e:
'Group': (set_permissions.get('Group') or ''), module.fail_json_aws(e, msg="Error updating tags")
'UserId': (set_permissions.get('UserId') or '')
}] if tags_to_add:
}) try:
else: connection.create_tags(Resources=[image_id], Tags=ansible_dict_to_boto3_tag_list(tags_to_add))
module.exit_json(msg="AMI not updated.", launch_permissions=set_permissions, changed=False, changed = True
**get_ami_info(get_image_by_id(module, connection, image_id))) except (botocore.exceptions.BotoCoreError, botocore.exceptions.ClientError) as e:
module.exit_json(msg="AMI launch permissions updated.", launch_permissions=launch_permissions, set_perms=set_permissions, changed=True, module.fail_json_aws(e, msg="Error updating tags")
description = module.params.get('description')
if description and description != image['Description']:
try:
connection.modify_image_attribute(Attribute='Description ', ImageId=image_id, Description=dict(Value=description))
changed = True
except (botocore.exceptions.BotoCoreError, botocore.exceptions.ClientError) as e:
module.fail_json_aws(e, msg="Error setting description for image %s" % image_id)
if changed:
module.exit_json(msg="AMI updated.", changed=True,
**get_ami_info(get_image_by_id(module, connection, image_id))) **get_ami_info(get_image_by_id(module, connection, image_id)))
else: else:
module.exit_json(msg="AMI not updated.", launch_permissions=set_permissions, changed=False, module.exit_json(msg="AMI not updated.", changed=False,
**get_ami_info(get_image_by_id(module, connection, image_id))) **get_ami_info(get_image_by_id(module, connection, image_id)))
except botocore.exceptions.ClientError as e:
module.fail_json(msg="Error updating image - " + str(e), exception=traceback.format_exc(), **camel_dict_to_snake_dict(e.response))
def get_image_by_id(module, connection, image_id): def get_image_by_id(module, connection, image_id):
try:
try: try:
images_response = connection.describe_images(ImageIds=[image_id]) images_response = connection.describe_images(ImageIds=[image_id])
except (botocore.exceptions.BotoCoreError, botocore.exceptions.ClientError) as e:
module.fail_json_aws(e, msg="Error retrieving image %s" % image_id)
images = images_response.get('Images') images = images_response.get('Images')
no_images = len(images) no_images = len(images)
if no_images == 0: if no_images == 0:
return None return None
if no_images == 1: if no_images == 1:
return images[0] result = images[0]
module.fail_json(msg="Invalid number of instances (%s) found for image_id: %s." % (str(len(images)), image_id)) try:
result['LaunchPermissions'] = connection.describe_image_attribute(Attribute='launchPermission', ImageId=image_id)['LaunchPermissions']
result['ProductCodes'] = connection.describe_image_attribute(Attribute='productCodes', ImageId=image_id)['ProductCodes']
except botocore.exceptions.ClientError as e: except botocore.exceptions.ClientError as e:
module.fail_json(msg="Error retreiving image by image_id - " + str(e), exception=traceback.format_exc(), **camel_dict_to_snake_dict(e.response)) if e.response['Error']['Code'] != 'InvalidAMIID.Unavailable':
module.fail_json_aws(e, msg="Error retrieving image attributes" % image_id)
except botocore.exceptions.BotoCoreError as e:
module.fail_json_aws(e, msg="Error retrieving image attributes" % image_id)
return result
module.fail_json(msg="Invalid number of instances (%s) found for image_id: %s." % (str(len(images)), image_id))
except (botocore.exceptions.BotoCoreError, botocore.exceptions.ClientError) as e:
module.fail_json_aws(e, msg="Error retrieving image by image_id")
def rename_item_if_exists(dict_object, attribute, new_attribute, child_node=None): def rename_item_if_exists(dict_object, attribute, new_attribute, child_node=None):
@ -641,40 +669,32 @@ def main():
enhanced_networking=dict(type='bool'), enhanced_networking=dict(type='bool'),
billing_products=dict(type='list'), billing_products=dict(type='list'),
ramdisk_id=dict(), ramdisk_id=dict(),
sriov_net_support=dict() sriov_net_support=dict(),
purge_tags=dict(type='bool', default=False)
)) ))
module = AnsibleModule( module = AnsibleAWSModule(
argument_spec=argument_spec, argument_spec=argument_spec,
required_if=[ required_if=[
['state', 'absent', ['image_id']], ['state', 'absent', ['image_id']],
['state', 'present', ['name']], ['state', 'present', ['name']],
] ]
) )
module = AnsibleModule(
argument_spec=argument_spec,
required_if=[('state', 'present', ('name',)),
('state', 'absent', ('image_id',))]
)
if not HAS_BOTO3:
module.fail_json(msg='boto3 required for this module')
try: try:
region, ec2_url, aws_connect_kwargs = get_aws_connection_info(module, boto3=True) region, ec2_url, aws_connect_kwargs = get_aws_connection_info(module, boto3=True)
connection = boto3_conn(module, conn_type='client', resource='ec2', region=region, endpoint=ec2_url, **aws_connect_kwargs) connection = boto3_conn(module, conn_type='client', resource='ec2', region=region, endpoint=ec2_url, **aws_connect_kwargs)
resource = boto3_conn(module, conn_type='resource', resource='ec2', region=region, endpoint=ec2_url, **aws_connect_kwargs)
except botocore.exceptions.NoRegionError: except botocore.exceptions.NoRegionError:
module.fail_json(msg=("Region must be specified as a parameter in AWS_DEFAULT_REGION environment variable or in boto configuration file.")) module.fail_json(msg=("Region must be specified as a parameter in AWS_DEFAULT_REGION environment variable or in boto configuration file."))
if module.params.get('state') == 'absent': if module.params.get('state') == 'absent':
deregister_image(module, connection) deregister_image(module, connection)
elif module.params.get('state') == 'present': elif module.params.get('state') == 'present':
if module.params.get('image_id') and module.params.get('launch_permissions'): if module.params.get('image_id'):
update_image(module, connection, module.params.get('image_id'), resource) update_image(module, connection, module.params.get('image_id'))
if not module.params.get('instance_id') and not module.params.get('device_mapping'): if not module.params.get('instance_id') and not module.params.get('device_mapping'):
module.fail_json(msg="The parameters instance_id or device_mapping (register from EBS snapshot) are required for a new image.") module.fail_json(msg="The parameters instance_id or device_mapping (register from EBS snapshot) are required for a new image.")
create_image(module, connection, resource) create_image(module, connection)
if __name__ == '__main__': if __name__ == '__main__':

View file

@ -101,7 +101,6 @@
Name: '{{ ec2_ami_name }}_ami' Name: '{{ ec2_ami_name }}_ami'
wait: yes wait: yes
root_device_name: /dev/xvda root_device_name: /dev/xvda
ignore_errors: true
register: result register: result
- name: assert that image has been created - name: assert that image has been created
@ -109,8 +108,7 @@
that: that:
- "result.changed" - "result.changed"
- "result.image_id.startswith('ami-')" - "result.image_id.startswith('ami-')"
# FIXME: tags are not currently shown in the results - "'Name' in result.tags and result.tags.Name == ec2_ami_name + '_ami'"
#- "result.tags == '{Name: {{ ec2_ami_name }}_ami}'"
- name: set image id fact for deletion later - name: set image id fact for deletion later
set_fact: set_fact:
@ -188,6 +186,8 @@
name: '{{ ec2_ami_name }}_ami' name: '{{ ec2_ami_name }}_ami'
description: '{{ ec2_ami_description }}' description: '{{ ec2_ami_description }}'
state: present state: present
launch_permissions:
user_ids: []
tags: tags:
Name: '{{ ec2_ami_name }}_ami' Name: '{{ ec2_ami_name }}_ami'
root_device_name: /dev/xvda root_device_name: /dev/xvda
@ -213,39 +213,37 @@
# ============================================================ # ============================================================
# FIXME: this only works if launch permissions are specified and if they are not an empty list - name: test default launch permissions idempotence
# - name: test idempotence ec2_ami:
# ec2_ami: ec2_region: '{{ec2_region}}'
# ec2_region: '{{ec2_region}}' ec2_access_key: '{{ec2_access_key}}'
# ec2_access_key: '{{ec2_access_key}}' ec2_secret_key: '{{ec2_secret_key}}'
# ec2_secret_key: '{{ec2_secret_key}}' security_token: '{{security_token}}'
# security_token: '{{security_token}}' description: '{{ ec2_ami_description }}'
# description: '{{ ec2_ami_description }}' state: present
# state: present name: '{{ ec2_ami_name }}_ami'
# tags: tags:
# Name: '{{ ec2_ami_name }}_ami' Name: '{{ ec2_ami_name }}_ami'
# root_device_name: /dev/xvda root_device_name: /dev/xvda
# image_id: '{{ result.image_id }}' image_id: '{{ result.image_id }}'
# launch_permissions: launch_permissions:
# user_ids: user_ids: []
# - device_mapping:
# device_mapping: - device_name: /dev/xvda
# - device_name: /dev/xvda volume_type: gp2
# volume_type: gp2 size: 8
# size: 8 delete_on_termination: true
# delete_on_termination: true snapshot_id: '{{ setup_snapshot.snapshot_id }}'
# snapshot_id: '{{ setup_snapshot.snapshot_id }}' register: result
# register: result
# - name: assert a new ami has been created - name: assert a new ami has not been created
# assert: assert:
# that: that:
# - "not result.changed" - "not result.changed"
# - "result.image_id.startswith('ami-')" - "result.image_id.startswith('ami-')"
# ============================================================ # ============================================================
# FIXME: tags are not currently shown in the results
- name: add a tag to the AMI - name: add a tag to the AMI
ec2_ami: ec2_ami:
ec2_region: '{{ec2_region}}' ec2_region: '{{ec2_region}}'
@ -258,14 +256,34 @@
name: '{{ ec2_ami_name }}_ami' name: '{{ ec2_ami_name }}_ami'
tags: tags:
New: Tag New: Tag
launch_permissions:
group_names: ['all']
register: result register: result
#
# - name: assert a tag was added - name: assert a tag was added
# assert: assert:
# that: that:
# - "result.tags == '{Name: {{ ec2_ami_name }}_ami}, New: Tag'" - "'Name' in result.tags and result.tags.Name == ec2_ami_name + '_ami'"
- "'New' in result.tags and result.tags.New == 'Tag'"
- name: use purge_tags to remove a tag from the AMI
ec2_ami:
ec2_region: '{{ec2_region}}'
ec2_access_key: '{{ec2_access_key}}'
ec2_secret_key: '{{ec2_secret_key}}'
security_token: '{{security_token}}'
state: present
description: '{{ ec2_ami_description }}'
image_id: '{{ result.image_id }}'
name: '{{ ec2_ami_name }}_ami'
tags:
New: Tag
purge_tags: yes
register: result
- name: assert a tag was removed
assert:
that:
- "'Name' not in result.tags"
- "'New' in result.tags and result.tags.New == 'Tag'"
# ============================================================ # ============================================================
@ -315,29 +333,25 @@
# ============================================================ # ============================================================
# FIXME: currently the module doesn't remove launch permissions correctly - name: remove public launch permissions
# - name: remove public launch permissions ec2_ami:
# ec2_ami: ec2_region: '{{ec2_region}}'
# ec2_region: '{{ec2_region}}' ec2_access_key: '{{ec2_access_key}}'
# ec2_access_key: '{{ec2_access_key}}' ec2_secret_key: '{{ec2_secret_key}}'
# ec2_secret_key: '{{ec2_secret_key}}' security_token: '{{security_token}}'
# security_token: '{{security_token}}' state: present
# state: present image_id: '{{ result.image_id }}'
# image_id: '{{ result.image_id }}' name: '{{ ec2_ami_name }}_ami'
# name: '{{ ec2_ami_name }}_ami' tags:
# tags: Name: '{{ ec2_ami_name }}_ami'
# Name: '{{ ec2_ami_name }}_ami' launch_permissions:
# launch_permissions: group_names: []
# group_names: register: result
# -
# - name: assert launch permissions were updated
# register: result assert:
# ignore_errors: true that:
# - "result.changed"
# - name: assert launch permissions were updated
# assert:
# that:
# - "result.changed"
# ============================================================ # ============================================================
@ -391,16 +405,13 @@
tags: tags:
Name: '{{ ec2_ami_name }}_ami' Name: '{{ ec2_ami_name }}_ami'
wait: yes wait: yes
ignore_errors: true
register: result register: result
# FIXME: currently deleting an already deleted image fails - name: assert that image does not exist
# It should succeed, with changed: false assert:
# - name: assert that image does not exist that:
# assert: - not result.changed
# that: - not result.failed
# - not result.changed
# - not result.failed
# ============================================================ # ============================================================