From 592c79e837ff726cd9f25dcc8f8407b3abe7ca71 Mon Sep 17 00:00:00 2001 From: Ross Williams Date: Fri, 20 Jan 2017 04:06:36 +1000 Subject: [PATCH] Add support for registering Amazon Machine Images from EBS snapshots. (#19020) --- lib/ansible/modules/cloud/amazon/ec2_ami.py | 103 ++++++++++++++++---- 1 file changed, 86 insertions(+), 17 deletions(-) diff --git a/lib/ansible/modules/cloud/amazon/ec2_ami.py b/lib/ansible/modules/cloud/amazon/ec2_ami.py index ccd5a1222a0..c3850a54f8d 100644 --- a/lib/ansible/modules/cloud/amazon/ec2_ami.py +++ b/lib/ansible/modules/cloud/amazon/ec2_ami.py @@ -36,6 +36,30 @@ options: - The name of the new AMI. required: false default: null + architecture: + version_added: "2.3" + description: + - The target architecture of the image to register + required: false + default: null + kernel_id: + version_added: "2.3" + description: + - The target kernel id of the image to register + required: false + default: null + virtualization_type: + version_added: "2.3" + description: + - The virtualization type of the image to register + required: false + default: null + root_device_name: + version_added: "2.3" + description: + - The root device name of the image to register + required: false + default: null wait: description: - Wait for the AMI to be in state 'available' before returning. @@ -99,6 +123,7 @@ options: author: - "Evan Duffield (@scicoin-project) " - "Constantin Bugneac (@Constantin07) " + - "Ross Williams (@gunzy83) " extends_documentation_fragment: - aws - ec2 @@ -117,7 +142,7 @@ EXAMPLES = ''' tags: Name: newtest Service: TestService - register: instance + register: image # Basic AMI Creation, without waiting - ec2_ami: @@ -127,7 +152,25 @@ EXAMPLES = ''' instance_id: i-xxxxxx wait: no name: newtest - register: instance + register: image + +# AMI Registration from EBS Snapshot +- ec2_ami: + aws_access_key: xxxxxxxxxxxxxxxxxxxxxxx + aws_secret_key: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + region: xxxxxx + name: newtest + state: present + architecture: x86_64 + virtualization_type: hvm + root_device_name: /dev/xvda + device_mapping: + - device_name: /dev/xvda + size: 8 + snapshot_id: snap-xxxxxxxx + delete_on_termination: true + volume_type: gp2 + register: image # AMI Creation, with a custom root-device size and another EBS attached - ec2_ami: @@ -144,7 +187,7 @@ EXAMPLES = ''' size: YYY delete_on_termination: false volume_type: gp2 - register: instance + register: image # AMI Creation, excluding a volume attached at /dev/sdb - ec2_ami: @@ -159,7 +202,7 @@ EXAMPLES = ''' volume_type: gp2 - device_name: /dev/sdb no_device: yes - register: instance + register: image # Deregister/Delete AMI (keep associated snapshots) - ec2_ami: @@ -234,6 +277,11 @@ hypervisor: returned: when AMI is created or already exists type: string sample: "xen" +image_id: + description: id of the image + returned: when AMI is created or already exists + type: string + sample: "ami-1234abcd" is_public: description: whether image is public returned: when AMI is created or already exists @@ -249,7 +297,7 @@ name: returned: when AMI is created or already exists type: string sample: "nat-server" -owner_id: +ownerId: description: owner of image returned: when AMI is created or already exists type: string @@ -363,22 +411,26 @@ def create_image(module, ec2): wait = module.params.get('wait') wait_timeout = int(module.params.get('wait_timeout')) description = module.params.get('description') + architecture = module.params.get('architecture') + kernel_id = module.params.get('kernel_id') + root_device_name = module.params.get('root_device_name') + virtualization_type = module.params.get('virtualization_type') no_reboot = module.params.get('no_reboot') device_mapping = module.params.get('device_mapping') tags = module.params.get('tags') launch_permissions = module.params.get('launch_permissions') try: - params = {'instance_id': instance_id, - 'name': name, - 'description': description, - 'no_reboot': no_reboot} + params = {'name': name, + 'description': description} images = ec2.get_all_images(filters={'name': name}) if images and images[0]: - module.exit_json(msg="AMI name already present", image_id=images[0].id, state=images[0].state, changed=False) + # ensure that launch_permissions are up to date + update_image(module, ec2, images[0].id) + bdm = None if device_mapping: bdm = BlockDeviceMapping() for device in device_mapping: @@ -388,9 +440,23 @@ def create_image(module, ec2): del device['device_name'] bd = BlockDeviceType(**device) bdm[device_name] = bd - params['block_device_mapping'] = bdm - image_id = ec2.create_image(**params) + if instance_id: + params['instance_id'] = instance_id + params['no_reboot'] = no_reboot + if bdm: + params['block_device_mapping'] = bdm + image_id = ec2.create_image(**params) + else: + params['architecture'] = architecture + params['virtualization_type'] = virtualization_type + if kernel_id: + params['kernel_id'] = kernel_id + if root_device_name: + params['root_device_name'] = root_device_name + if bdm: + params['block_device_map'] = bdm + image_id = ec2.register_image(**params) except boto.exception.BotoServerError as e: module.fail_json(msg="%s: %s" % (e.error_code, e.error_message)) @@ -486,12 +552,11 @@ def deregister_image(module, ec2): module.exit_json(msg="AMI deregister/delete operation complete", changed=True) -def update_image(module, ec2): +def update_image(module, ec2, image_id): """ Updates AMI """ - image_id = module.params.get('image_id') launch_permissions = module.params.get('launch_permissions') or [] if 'user_ids' in launch_permissions: launch_permissions['user_ids'] = [str(user_id) for user_id in launch_permissions['user_ids']] @@ -521,6 +586,10 @@ def main(): argument_spec.update(dict( instance_id = dict(), image_id = dict(), + architecture = dict(default="x86_64"), + kernel_id = dict(), + virtualization_type = dict(default="hvm"), + root_device_name = dict(), delete_snapshot = dict(default=False, type='bool'), name = dict(), wait = dict(type='bool', default=False), @@ -552,11 +621,11 @@ def main(): elif module.params.get('state') == 'present': if module.params.get('image_id') and module.params.get('launch_permissions'): # Update image's launch permissions - update_image(module, ec2) + update_image(module, ec2,module.params.get('image_id')) # Changed is always set to true when provisioning new AMI - if not module.params.get('instance_id'): - module.fail_json(msg='instance_id parameter is required for new image') + if not module.params.get('instance_id') and not module.params.get('device_mapping'): + module.fail_json(msg='instance_id or device_mapping (register from ebs snapshot) parameter is required for new image') if not module.params.get('name'): module.fail_json(msg='name parameter is required for new image') create_image(module, ec2)