diff --git a/changelogs/fragments/1918-ec2_instance-add-support-to-modify-metadata-options.yml b/changelogs/fragments/1918-ec2_instance-add-support-to-modify-metadata-options.yml new file mode 100644 index 00000000000..022f44ad12c --- /dev/null +++ b/changelogs/fragments/1918-ec2_instance-add-support-to-modify-metadata-options.yml @@ -0,0 +1,3 @@ +--- +minor_changes: + - ec2_instance - Add support for modifying metadata options of an existing instance (https://github.com/ansible-collections/amazon.aws/pull/1918). diff --git a/plugins/modules/ec2_instance.py b/plugins/modules/ec2_instance.py index 7eb5feebbeb..06089e4fec9 100644 --- a/plugins/modules/ec2_instance.py +++ b/plugins/modules/ec2_instance.py @@ -1630,6 +1630,46 @@ def value_wrapper(v): return changes_to_apply +def change_instance_metadata_options(instance, params): + metadata_options_to_apply = params.get("metadata_options") + + if metadata_options_to_apply is None: + return False + + existing_metadata_options = camel_dict_to_snake_dict(instance.get("MetadataOptions")) + + changes_to_apply = { + key: metadata_options_to_apply[key] + for key in set(existing_metadata_options) & set(metadata_options_to_apply) + if existing_metadata_options[key] != metadata_options_to_apply[key] + } + + if not changes_to_apply: + return False + + request_args = { + "InstanceId": instance["InstanceId"], + "HttpTokens": changes_to_apply.get("http_tokens") or existing_metadata_options.get("http_tokens"), + "HttpPutResponseHopLimit": changes_to_apply.get("http_put_response_hop_limit") + or existing_metadata_options.get("http_put_response_hop_limit"), + "HttpEndpoint": changes_to_apply.get("http_endpoint") or existing_metadata_options.get("http_endpoint"), + "HttpProtocolIpv6": changes_to_apply.get("http_protocol_ipv6") + or existing_metadata_options.get("http_protocol_ipv6"), + "InstanceMetadataTags": changes_to_apply.get("instance_metadata_tags") + or existing_metadata_options.get("instance_metadata_tags"), + } + + if module.check_mode: + return True + try: + client.modify_instance_metadata_options(aws_retry=True, **request_args) + except (botocore.exceptions.BotoCoreError, botocore.exceptions.ClientError) as e: + module.fail_json_aws( + e, msg=f"Failed to update instance metadata options for instance ID: {instance['InstanceId']}" + ) + return True + + def change_network_attachments(instance, params): if (params.get("network") or {}).get("interfaces") is not None: new_ids = [] @@ -1959,6 +1999,9 @@ def handle_existing(existing_matches, state, filters): for instance in existing_matches: changed |= ensure_ec2_tags(client, module, instance["InstanceId"], tags=tags, purge_tags=purge_tags) + + changed |= change_instance_metadata_options(instance, module.params) + changes = diff_instance_and_params(instance, module.params) for c in changes: if not module.check_mode: diff --git a/tests/integration/targets/ec2_instance_metadata_options/tasks/main.yml b/tests/integration/targets/ec2_instance_metadata_options/tasks/main.yml index e56eb491544..03dc5943b64 100644 --- a/tests/integration/targets/ec2_instance_metadata_options/tasks/main.yml +++ b/tests/integration/targets/ec2_instance_metadata_options/tasks/main.yml @@ -7,20 +7,21 @@ session_token: "{{ security_token | default(omit) }}" region: "{{ aws_region }}" block: - - name: create t3.nano instance with metadata_options + + - name: Create a new instance amazon.aws.ec2_instance: - state: present - name: "{{ resource_prefix }}-test-t3nano-enabled-required" + state: running + name: "{{ resource_prefix }}-test-basic" + instance_type: "{{ ec2_instance_type }}" image_id: "{{ ec2_ami_id }}" tags: TestId: "{{ ec2_instance_tag_TestId }}" - vpc_subnet_id: "{{ testing_subnet_a.subnet.id }}" - instance_type: t3.nano metadata_options: http_endpoint: enabled http_tokens: required instance_metadata_tags: enabled - wait: false + http_put_response_hop_limit: 2 + wait: true register: instance_creation - name: instance with metadata_options created with the right options @@ -31,6 +32,7 @@ - instance_creation.spec.MetadataOptions.HttpEndpoint == 'enabled' - instance_creation.spec.MetadataOptions.HttpTokens == 'required' - instance_creation.spec.MetadataOptions.InstanceMetadataTags == 'enabled' + - instance_creation.spec.MetadataOptions.HttpPutResponseHopLimit == 2 - name: modify metadata_options on existing instance amazon.aws.ec2_instance: @@ -44,9 +46,9 @@ metadata_options: http_endpoint: enabled http_tokens: optional + http_put_response_hop_limit: 4 wait: false register: metadata_options_update - ignore_errors: true - name: fact presented ec2 instance amazon.aws.ec2_instance_info: @@ -54,12 +56,13 @@ tag:Name: "{{ resource_prefix }}-test-t3nano-enabled-required" register: presented_instance_fact - - name: modify metadata_options has no effect on existing instance + - name: Assert that instance metadata options have been modified successfully ansible.builtin.assert: that: - metadata_options_update is success - - metadata_options_update is not changed + - metadata_options_update is changed - presented_instance_fact.instances | length > 0 - presented_instance_fact.instances.0.state.name in ['running','pending'] - presented_instance_fact.instances.0.metadata_options.http_endpoint == 'enabled' - - presented_instance_fact.instances.0.metadata_options.http_tokens == 'required' + - presented_instance_fact.instances.0.metadata_options.http_tokens == 'optional' + - presented_instance_fact.instances.0.metadata_options.http_put_response_hop_limit == 4