From ab9b07437bcaf7f509561c703ca460fd6641e882 Mon Sep 17 00:00:00 2001 From: Bikouo Aubin <79859644+abikouo@users.noreply.github.com> Date: Mon, 17 Jul 2023 15:14:33 +0200 Subject: [PATCH] ec2_instance_info - add support for include_attributes (#1577) ec2_instance_info - add support for include_attributes SUMMARY include_attributes allows the module to describe specific attributes for an EC2 instance ISSUE TYPE Feature Pull Request COMPONENT NAME ec2_instance_info Reviewed-by: Alina Buzachis Reviewed-by: Bikouo Aubin Reviewed-by: Helen Bailey --- ...c2_instance_info-support-new-attribute.yml | 3 + plugins/modules/ec2_instance_info.py | 79 +++++++++++++++++++ .../targets/ec2_instance_info/aliases | 4 + .../ec2_instance_info/defaults/main.yml | 7 ++ .../targets/ec2_instance_info/meta/main.yml | 4 + .../targets/ec2_instance_info/tasks/main.yml | 76 ++++++++++++++++++ 6 files changed, 173 insertions(+) create mode 100644 changelogs/fragments/ec2_instance_info-support-new-attribute.yml create mode 100644 tests/integration/targets/ec2_instance_info/aliases create mode 100644 tests/integration/targets/ec2_instance_info/defaults/main.yml create mode 100644 tests/integration/targets/ec2_instance_info/meta/main.yml create mode 100644 tests/integration/targets/ec2_instance_info/tasks/main.yml diff --git a/changelogs/fragments/ec2_instance_info-support-new-attribute.yml b/changelogs/fragments/ec2_instance_info-support-new-attribute.yml new file mode 100644 index 00000000000..5025aed21e7 --- /dev/null +++ b/changelogs/fragments/ec2_instance_info-support-new-attribute.yml @@ -0,0 +1,3 @@ +--- +minor_changes: + - ec2_instance_info - add new parameter `include_attributes` to describe instance attributes (https://github.com/ansible-collections/amazon.aws/pull/1577). diff --git a/plugins/modules/ec2_instance_info.py b/plugins/modules/ec2_instance_info.py index 484f54f24c1..6977edb9700 100644 --- a/plugins/modules/ec2_instance_info.py +++ b/plugins/modules/ec2_instance_info.py @@ -36,6 +36,30 @@ required: false aliases: ['uptime'] type: int + include_attributes: + description: + - Describes the specified attributes of the returned instances. + required: false + type: list + elements: str + choices: + - instanceType + - kernel + - ramdisk + - userData + - disableApiTermination + - instanceInitiatedShutdownBehavior + - rootDeviceName + - blockDeviceMapping + - productCodes + - sourceDestCheck + - groupSet + - ebsOptimized + - sriovNetSupport + - enclaveOptions + - disableApiStop + aliases: ['attributes'] + version_added: 6.3.0 extends_documentation_fragment: - amazon.aws.common.modules @@ -77,6 +101,13 @@ "tag:Name": "RHEL-*" instance-state-name: [ "running"] register: ec2_node_info + +- name: Gather information about a particular instance using ID and include kernel attribute + amazon.aws.ec2_instance_info: + instance_ids: + - i-12345678 + include_attributes: + - kernel """ RETURN = r""" @@ -500,6 +531,20 @@ returned: always type: dict sample: vpc-0011223344 + attributes: + description: The details of the instance attribute specified on input. + returned: when include_attribute is specified + type: dict + sample: + { + 'disable_api_termination': { + 'value': True + }, + 'ebs_optimized': { + 'value': True + } + } + version_added: 6.3.0 """ import datetime @@ -549,6 +594,12 @@ def list_ec2_instances(connection, module): for reservation in reservations["Reservations"]: instances = instances + reservation["Instances"] + # include instances attributes + attributes = module.params.get("include_attributes") + if attributes: + for instance in instances: + instance["attributes"] = describe_instance_attributes(connection, instance["InstanceId"], attributes) + # Turn the boto3 result in to ansible_friendly_snaked_names snaked_instances = [camel_dict_to_snake_dict(instance) for instance in instances] @@ -559,11 +610,39 @@ def list_ec2_instances(connection, module): module.exit_json(instances=snaked_instances) +def describe_instance_attributes(connection, instance_id, attributes): + result = {} + for attr in attributes: + response = connection.describe_instance_attribute(Attribute=attr, InstanceId=instance_id) + for key in response: + if key not in ("InstanceId", "ResponseMetadata"): + result[key] = response[key] + return result + + def main(): + instance_attributes = [ + "instanceType", + "kernel", + "ramdisk", + "userData", + "disableApiTermination", + "instanceInitiatedShutdownBehavior", + "rootDeviceName", + "blockDeviceMapping", + "productCodes", + "sourceDestCheck", + "groupSet", + "ebsOptimized", + "sriovNetSupport", + "enclaveOptions", + "disableApiStop", + ] argument_spec = dict( minimum_uptime=dict(required=False, type="int", default=None, aliases=["uptime"]), instance_ids=dict(default=[], type="list", elements="str"), filters=dict(default={}, type="dict"), + include_attributes=dict(type="list", elements="str", aliases=["attributes"], choices=instance_attributes), ) module = AnsibleAWSModule( diff --git a/tests/integration/targets/ec2_instance_info/aliases b/tests/integration/targets/ec2_instance_info/aliases new file mode 100644 index 00000000000..704e2295951 --- /dev/null +++ b/tests/integration/targets/ec2_instance_info/aliases @@ -0,0 +1,4 @@ +time=1m +cloud/aws +ec2_instance_info +ec2_instance diff --git a/tests/integration/targets/ec2_instance_info/defaults/main.yml b/tests/integration/targets/ec2_instance_info/defaults/main.yml new file mode 100644 index 00000000000..5ec6ddfc542 --- /dev/null +++ b/tests/integration/targets/ec2_instance_info/defaults/main.yml @@ -0,0 +1,7 @@ +--- +ec2_instance_type: 't2.micro' +ec2_instance_tag_TestId: '{{ resource_prefix }}-instance-info' +ec2_instance_name: "{{ resource_prefix }}-test-instance-info" +ec2_instance_user_data: | + packages: + - httpd diff --git a/tests/integration/targets/ec2_instance_info/meta/main.yml b/tests/integration/targets/ec2_instance_info/meta/main.yml new file mode 100644 index 00000000000..aefa59ca473 --- /dev/null +++ b/tests/integration/targets/ec2_instance_info/meta/main.yml @@ -0,0 +1,4 @@ +# this just makes sure they're in the right place +dependencies: +- role: setup_ec2_facts +- role: setup_ec2_instance_env diff --git a/tests/integration/targets/ec2_instance_info/tasks/main.yml b/tests/integration/targets/ec2_instance_info/tasks/main.yml new file mode 100644 index 00000000000..2e3aba8095f --- /dev/null +++ b/tests/integration/targets/ec2_instance_info/tasks/main.yml @@ -0,0 +1,76 @@ +--- +- module_defaults: + group/aws: + aws_access_key: "{{ aws_access_key }}" + aws_secret_key: "{{ aws_secret_key }}" + security_token: "{{ security_token | default(omit) }}" + region: "{{ aws_region }}" + block: + - name: "Make instance in the testing subnet created in the test VPC" + ec2_instance: + state: present + name: "{{ ec2_instance_name }}" + image_id: "{{ ec2_ami_id }}" + availability_zone: '{{ subnet_b_az }}' + tags: + TestId: "{{ ec2_instance_tag_TestId }}" + user_data: "{{ ec2_instance_user_data }}" + instance_type: "{{ ec2_instance_type }}" + wait: false + + - name: "Gather {{ ec2_instance_name }} info" + ec2_instance_info: + filters: + "tag:Name": "{{ ec2_instance_name }}" + include_attributes: + - instanceType + - kernel + - ramdisk + - userData + - disableApiTermination + - instanceInitiatedShutdownBehavior + - rootDeviceName + - blockDeviceMapping + - productCodes + - sourceDestCheck + - groupSet + - ebsOptimized + - sriovNetSupport + - enclaveOptions + register: _instance_info + + - name: Validate that returned value contains required attributes + assert: + that: + - _instance_info.instances | length > 0 + - '"attributes" in _instance_info.instances[0]' + # instance type + - _instance_info.instances[0].attributes.instance_type.value == ec2_instance_type + # User data + - _instance_info.instances[0].attributes.user_data.value | b64decode == ec2_instance_user_data + # kernel + - '"kernel_id" in _instance_info.instances[0].attributes' + # Ram disk + - '"ramdisk_id" in _instance_info.instances[0].attributes' + # Disable API termination + - not (_instance_info.instances[0].attributes.disable_api_termination.value | bool) + # Instance Initiated Shutdown Behavior + - '"instance_initiated_shutdown_behavior" in _instance_info.instances[0].attributes' + # Root Device Name + - _instance_info.instances[0].attributes.root_device_name.value == "/dev/sda1" + # Block Device Mapping + - '"block_device_mappings" in _instance_info.instances[0].attributes' + - _instance_info.instances[0].attributes.block_device_mappings[0].device_name == "/dev/sda1" + - '"ebs" in _instance_info.instances[0].attributes.block_device_mappings[0]' + # Product Codes + - '"product_codes" in _instance_info.instances[0].attributes' + # Source Dest Check + - _instance_info.instances[0].attributes.source_dest_check.value | bool + # GroupSet + - '"groups" in _instance_info.instances[0].attributes' + # Ebs Optimized + - not (_instance_info.instances[0].attributes.ebs_optimized.value | bool) + # Sriov Net Support + - '"sriov_net_support" in _instance_info.instances[0].attributes' + # Enclave Options + - not (_instance_info.instances[0].attributes.enclave_options.enabled | bool)