diff --git a/changelogs/fragments/964-ec2_instance-return-instances.yml b/changelogs/fragments/964-ec2_instance-return-instances.yml new file mode 100644 index 00000000000..045d03202a3 --- /dev/null +++ b/changelogs/fragments/964-ec2_instance-return-instances.yml @@ -0,0 +1,2 @@ +minor_changes: +- ec2_instance - more consistently return ``instances`` information (https://github.com/ansible-collections/amazon.aws/pull/964). diff --git a/plugins/modules/ec2_instance.py b/plugins/modules/ec2_instance.py index e1ea424b9ee..5b1c53355bf 100644 --- a/plugins/modules/ec2_instance.py +++ b/plugins/modules/ec2_instance.py @@ -6,7 +6,7 @@ __metaclass__ = type -DOCUMENTATION = r''' +DOCUMENTATION = r""" --- module: ec2_instance version_added: 1.0.0 @@ -378,9 +378,9 @@ - amazon.aws.ec2 - amazon.aws.tags - amazon.aws.boto3 -''' +""" -EXAMPLES = ''' +EXAMPLES = r""" # Note: These examples do not set authentication details, see the AWS Guide for details. - name: Terminate every running instance in a region. Use with EXTREME caution. @@ -534,12 +534,30 @@ state: present tags: foo: bar -''' +""" -RETURN = ''' +RETURN = r""" +instance_ids: + description: a list of ec2 instance IDs matching the provided specification and filters + returned: always + type: list + sample: ["i-0123456789abcdef0", "i-0123456789abcdef1"] + version_added: 5.3.0 +changed_ids: + description: a list of the set of ec2 instance IDs changed by the module action + returned: when instances that must be present are launched + type: list + sample: ["i-0123456789abcdef0"] + version_added: 5.3.0 +terminated_ids: + description: a list of the set of ec2 instance IDs terminated by the module action + returned: when instances that must be absent are terminated + type: list + sample: ["i-0123456789abcdef1"] + version_added: 5.3.0 instances: description: a list of ec2 instances - returned: when wait == true + returned: when wait == true or when matching instances already exist type: complex contains: ami_launch_index: @@ -942,7 +960,7 @@ returned: always type: dict sample: vpc-0011223344 -''' +""" from collections import namedtuple import time @@ -1824,7 +1842,9 @@ def enforce_count(existing_matches, module, desired_module_state): if current_count == exact_count: module.exit_json( changed=False, - msg='{0} instances already running, nothing to do.'.format(exact_count) + instances=[pretty_instance(i) for i in existing_matches], + instance_ids=[i["InstanceId"] for i in existing_matches], + msg=f"{exact_count} instances already running, nothing to do.", ) elif current_count < exact_count: @@ -1843,7 +1863,12 @@ def enforce_count(existing_matches, module, desired_module_state): all_instance_ids = [x['InstanceId'] for x in existing_matches] terminate_ids = all_instance_ids[0:to_terminate] if module.check_mode: - module.exit_json(changed=True, msg='Would have terminated following instances if not in check mode {0}'.format(terminate_ids)) + module.exit_json( + changed=True, + terminated_ids=terminate_ids, + instance_ids=all_instance_ids, + msg=f"Would have terminated following instances if not in check mode {terminate_ids}", + ) # terminate instances try: client.terminate_instances(aws_retry=True, InstanceIds=terminate_ids) @@ -1852,10 +1877,14 @@ def enforce_count(existing_matches, module, desired_module_state): pass except botocore.exceptions.ClientError as e: # pylint: disable=duplicate-except module.fail_json(e, msg='Unable to terminate instances') + # include data for all matched instances in addition to the list of terminations + # allowing for recovery of metadata from the destructive operation module.exit_json( changed=True, msg='Successfully terminated instances.', terminated_ids=terminate_ids, + instance_ids=all_instance_ids, + instances=existing_matches, ) except (botocore.exceptions.BotoCoreError, botocore.exceptions.ClientError) as e: @@ -1872,11 +1901,21 @@ def ensure_present(existing_matches, desired_module_state): instance_spec = build_run_instance_spec(module.params) # If check mode is enabled,suspend 'ensure function'. if module.check_mode: - module.exit_json( - changed=True, - spec=instance_spec, - msg='Would have launched instances if not in check_mode.', - ) + if existing_matches: + instance_ids = [x["InstanceId"] for x in existing_matches] + module.exit_json( + changed=True, + instance_ids=instance_ids, + instances=existing_matches, + spec=instance_spec, + msg="Would have launched instances if not in check_mode.", + ) + else: + module.exit_json( + changed=True, + spec=instance_spec, + msg="Would have launched instances if not in check_mode.", + ) instance_response = run_instances(**instance_spec) instances = instance_response['Instances'] instance_ids = [i['InstanceId'] for i in instances] @@ -1904,22 +1943,43 @@ def ensure_present(existing_matches, desired_module_state): client.modify_instance_attribute(aws_retry=True, **c) except botocore.exceptions.ClientError as e: module.fail_json_aws(e, msg="Could not apply change {0} to new instance.".format(str(c))) + if existing_matches: + # If we came from enforce_count, create a second list to distinguish + # between existing and new instances when returning the entire cohort + all_instance_ids = [x["InstanceId"] for x in existing_matches] + instance_ids + if not module.params.get("wait"): + if existing_matches: + module.exit_json( + changed=True, + changed_ids=instance_ids, + instance_ids=all_instance_ids, + spec=instance_spec, + ) + else: + module.exit_json( + changed=True, + instance_ids=instance_ids, + spec=instance_spec, + ) + await_instances(instance_ids, desired_module_state=desired_module_state) + instances = find_instances(ids=instance_ids) - if not module.params.get('wait'): + if existing_matches: + all_instances = existing_matches + instances + module.exit_json( + changed=True, + changed_ids=instance_ids, + instance_ids=all_instance_ids, + instances=[pretty_instance(i) for i in all_instances], + spec=instance_spec, + ) + else: module.exit_json( changed=True, instance_ids=instance_ids, + instances=[pretty_instance(i) for i in instances], spec=instance_spec, ) - await_instances(instance_ids, desired_module_state=desired_module_state) - instances = find_instances(ids=instance_ids) - - module.exit_json( - changed=True, - instances=[pretty_instance(i) for i in instances], - instance_ids=instance_ids, - spec=instance_spec, - ) except (botocore.exceptions.BotoCoreError, botocore.exceptions.ClientError) as e: module.fail_json_aws(e, msg="Failed to create new EC2 instance") diff --git a/tests/integration/targets/ec2_instance_instance_multiple/tasks/main.yml b/tests/integration/targets/ec2_instance_instance_multiple/tasks/main.yml index 491b58391a3..e3d6efec58e 100644 --- a/tests/integration/targets/ec2_instance_instance_multiple/tasks/main.yml +++ b/tests/integration/targets/ec2_instance_instance_multiple/tasks/main.yml @@ -164,7 +164,8 @@ that: - create_multiple_instances is not failed - create_multiple_instances is not changed - - '"instance_ids" not in create_multiple_instances' + - '"instance_ids" in create_multiple_instances' + - create_multiple_instances.instance_ids | length == 5 - '"ec2:RunInstances" not in create_multiple_instances.resource_actions' - name: "Enforce instance count - launch 5 instances (Idempotency)" @@ -183,7 +184,8 @@ that: - create_multiple_instances is not failed - create_multiple_instances is not changed - - '"instance_ids" not in create_multiple_instances' + - '"instance_ids" in create_multiple_instances' + - create_multiple_instances.instance_ids | length == 5 - '"ec2:RunInstances" not in create_multiple_instances.resource_actions' - name: "Enforce instance count to 3 - Terminate 2 instances (check_mode)" @@ -202,7 +204,10 @@ that: - terminate_multiple_instances is not failed - terminate_multiple_instances is changed - - '"instance_ids" not in terminate_multiple_instances' + - '"instance_ids" in terminate_multiple_instances' + - terminate_multiple_instances.instance_ids | length == 5 + - '"terminated_ids" in terminate_multiple_instances' + - terminate_multiple_instances.terminated_ids | length == 2 - '"ec2:RunInstances" not in terminate_multiple_instances.resource_actions' - name: "Enforce instance count to 3 - Terminate 2 instances" @@ -221,6 +226,8 @@ that: - terminate_multiple_instances is not failed - terminate_multiple_instances is changed + - '"instance_ids" in terminate_multiple_instances' + - terminate_multiple_instances.instance_ids | length == 5 - '"terminated_ids" in terminate_multiple_instances' - terminate_multiple_instances.terminated_ids | length == 2 @@ -240,7 +247,9 @@ that: - terminate_multiple_instances is not failed - terminate_multiple_instances is not changed - - '"instance_ids" not in terminate_multiple_instances' + - '"instance_ids" in terminate_multiple_instances' + - terminate_multiple_instances.instance_ids | length == 3 + - '"terminated_ids" not in terminate_multiple_instances' - '"ec2:TerminateInstances" not in terminate_multiple_instances.resource_actions' - name: "Enforce instance count to 3 - Terminate 2 instances (Idempotency)" @@ -258,7 +267,9 @@ that: - terminate_multiple_instances is not failed - terminate_multiple_instances is not changed - - '"instance_ids" not in terminate_multiple_instances' + - '"instance_ids" in terminate_multiple_instances' + - terminate_multiple_instances.instance_ids | length == 3 + - '"terminated_ids" not in terminate_multiple_instances' - '"ec2:TerminateInstances" not in terminate_multiple_instances.resource_actions' - name: "Enforce instance count to 6 - Launch 3 more instances (check_mode)" @@ -278,7 +289,9 @@ that: - create_multiple_instances is not failed - create_multiple_instances is changed - - '"instance_ids" not in create_multiple_instances' + - '"instance_ids" in create_multiple_instances' + - create_multiple_instances.instance_ids | length == 3 + - '"changed_ids" not in create_multiple_instances' - '"ec2:RunInstances" not in create_multiple_instances.resource_actions' - name: "Enforce instance count to 6 - Launch 3 more instances" @@ -301,7 +314,9 @@ - create_multiple_instances is not failed - create_multiple_instances is changed - '"instance_ids" in create_multiple_instances' - - create_multiple_instances.instance_ids | length == 3 + - create_multiple_instances.instance_ids | length == 6 + - '"changed_ids" in create_multiple_instances' + - create_multiple_instances.changed_ids | length == 3 - name: "Enforce instance count to 6 - Launch 3 more instances (check_mode - Idempotency)" ec2_instance: @@ -320,7 +335,9 @@ that: - create_multiple_instances is not failed - create_multiple_instances is not changed - - '"instance_ids" not in create_multiple_instances' + - '"instance_ids" in create_multiple_instances' + - create_multiple_instances.instance_ids | length == 6 + - '"changed_ids" not in create_multiple_instances' - '"ec2:RunInstances" not in create_multiple_instances.resource_actions' - name: "Enforce instance count to 6 - Launch 3 more instances (Idempotency)" @@ -339,7 +356,9 @@ that: - create_multiple_instances is not failed - create_multiple_instances is not changed - - '"instance_ids" not in create_multiple_instances' + - '"instance_ids" in create_multiple_instances' + - create_multiple_instances.instance_ids | length == 6 + - '"changed_ids" not in create_multiple_instances' - '"ec2:RunInstances" not in create_multiple_instances.resource_actions'