diff --git a/lib/ansible/modules/cloud/amazon/ec2_instance.py b/lib/ansible/modules/cloud/amazon/ec2_instance.py index 805444d6a8..c6db3e9a58 100644 --- a/lib/ansible/modules/cloud/amazon/ec2_instance.py +++ b/lib/ansible/modules/cloud/amazon/ec2_instance.py @@ -1112,6 +1112,11 @@ def await_instances(ids, state='OK'): if not module.params.get('wait', True): # the user asked not to wait for anything return + + if module.check_mode: + # In check mode, there is no change even if you wait. + return + state_opts = { 'OK': 'instance_status_ok', 'STOPPED': 'instance_stopped', @@ -1344,6 +1349,10 @@ def change_instance_state(filters, desired_state, ec2=None): for inst in instances: try: if desired_state == 'TERMINATED': + if module.check_mode: + changed.add(inst['InstanceId']) + continue + # TODO use a client-token to prevent double-sends of these start/stop/terminate commands # https://docs.aws.amazon.com/AWSEC2/latest/APIReference/Run_Instance_Idempotency.html resp = ec2.terminate_instances(InstanceIds=[inst['InstanceId']]) @@ -1352,9 +1361,18 @@ def change_instance_state(filters, desired_state, ec2=None): if inst['State']['Name'] == 'stopping': unchanged.add(inst['InstanceId']) continue + + if module.check_mode: + changed.add(inst['InstanceId']) + continue + resp = ec2.stop_instances(InstanceIds=[inst['InstanceId']]) [changed.add(i['InstanceId']) for i in resp['StoppingInstances']] if desired_state == 'RUNNING': + if module.check_mode: + changed.add(inst['InstanceId']) + continue + resp = ec2.start_instances(InstanceIds=[inst['InstanceId']]) [changed.add(i['InstanceId']) for i in resp['StartingInstances']] except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError): @@ -1423,6 +1441,12 @@ def ensure_present(existing_matches, changed, ec2, state): ) try: 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, + ) instance_response = run_instances(ec2, **instance_spec) instances = instance_response['Instances'] instance_ids = [i['InstanceId'] for i in instances] diff --git a/test/integration/targets/ec2_instance/playbooks/roles/ec2_instance/tasks/block_devices.yml b/test/integration/targets/ec2_instance/playbooks/roles/ec2_instance/tasks/block_devices.yml index 3c775a56e7..3f97b714cf 100644 --- a/test/integration/targets/ec2_instance/playbooks/roles/ec2_instance/tasks/block_devices.yml +++ b/test/integration/targets/ec2_instance/playbooks/roles/ec2_instance/tasks/block_devices.yml @@ -32,3 +32,45 @@ - in_test_vpc.instances[0].block_device_mappings[0] - in_test_vpc.instances[0].block_device_mappings[1] - in_test_vpc.instances[0].block_device_mappings[1].device_name == '/dev/sdb' + +- name: New instance with an extra block device(check mode) + ec2_instance: + name: "{{ resource_prefix }}-test-ebs-vols-checkmode" + image_id: "{{ ec2_ami_image[aws_region] }}" + vpc_subnet_id: "{{ testing_subnet_b.subnet.id }}" + volumes: + - device_name: /dev/sda1 + ebs: + delete_on_termination: true + - device_name: /dev/sdb + ebs: + volume_size: 20 + delete_on_termination: true + volume_type: standard + tags: + TestId: "{{ resource_prefix }}" + instance_type: t2.micro + <<: *aws_connection_info + check_mode: yes + +- name: "fact presented ec2 instance" + ec2_instance_facts: + filters: + "tag:Name": "{{ resource_prefix }}-test-ebs-vols" + "instance-state-name": "running" + <<: *aws_connection_info + register: presented_instance_fact + +- name: "fact checkmode ec2 instance" + ec2_instance_facts: + filters: + "tag:Name": "{{ resource_prefix }}-test-ebs-vols-checkmode" + "instance-state-name": "running" + <<: *aws_connection_info + register: checkmode_instance_fact + +- name: "Confirm whether the check mode is working normally." + assert: + that: + - "{{ presented_instance_fact.instances | length }} > 0" + - "{{ checkmode_instance_fact.instances | length }} == 0" diff --git a/test/integration/targets/ec2_instance/playbooks/roles/ec2_instance/tasks/checkmode_tests.yml b/test/integration/targets/ec2_instance/playbooks/roles/ec2_instance/tasks/checkmode_tests.yml new file mode 100644 index 0000000000..8cd0e7dfcb --- /dev/null +++ b/test/integration/targets/ec2_instance/playbooks/roles/ec2_instance/tasks/checkmode_tests.yml @@ -0,0 +1,187 @@ +- name: set connection information for all tasks + set_fact: + aws_connection_info: &aws_connection_info + aws_access_key: "{{ aws_access_key }}" + aws_secret_key: "{{ aws_secret_key }}" + security_token: "{{ security_token }}" + region: "{{ aws_region }}" + no_log: true + +- block: + - name: Make basic instance + ec2_instance: + name: "{{ resource_prefix }}-checkmode-comparison" + image_id: "{{ ec2_ami_image[aws_region] }}" + security_groups: "{{ sg.group_id }}" + instance_type: t2.micro + vpc_subnet_id: "{{ testing_subnet_a.subnet.id }}" + volumes: + - device_name: /dev/sda1 + ebs: + delete_on_termination: true + <<: *aws_connection_info + register: instance_creation + + - name: Make basic instance(check mode) + ec2_instance: + name: "{{ resource_prefix }}-checkmode-comparison-checkmode" + image_id: "{{ ec2_ami_image[aws_region] }}" + security_groups: "{{ sg.group_id }}" + instance_type: t2.micro + vpc_subnet_id: "{{ testing_subnet_c.subnet.id }}" + volumes: + - device_name: /dev/sda1 + ebs: + delete_on_termination: true + <<: *aws_connection_info + check_mode: yes + + - name: fact presented ec2 instance + ec2_instance_facts: + filters: + "tag:Name": "{{ resource_prefix }}-checkmode-comparison" + "instance-state-name": "running" + <<: *aws_connection_info + register: presented_instance_fact + + - name: fact checkmode ec2 instance + ec2_instance_facts: + filters: + "tag:Name": "{{ resource_prefix }}-checkmode-comparison-checkmode" + "instance-state-name": "running" + <<: *aws_connection_info + register: checkmode_instance_fact + + - name: Confirm whether the check mode is working normally. + assert: + that: + - "{{ presented_instance_fact.instances | length }} > 0" + - "{{ checkmode_instance_fact.instances | length }} == 0" + + - name: Stop instance in check mode. + ec2_instance: + name: "{{ resource_prefix }}-checkmode-comparison" + state: stopped + vpc_subnet_id: "{{ testing_subnet_a.subnet.id }}" + <<: *aws_connection_info + check_mode: yes + + - name: fact ec2 instance + ec2_instance_facts: + filters: + "tag:Name": "{{ resource_prefix }}-checkmode-comparison" + <<: *aws_connection_info + register: confirm_checkmode_stopinstance_fact + + - name: Verify that it was not stopped. + assert: + that: + - '"{{ confirm_checkmode_stopinstance_fact.instances[0].state.name }}" != "stopped"' + + - name: Stop instance in normaly. + ec2_instance: + name: "{{ resource_prefix }}-checkmode-comparison" + state: stopped + vpc_subnet_id: "{{ testing_subnet_a.subnet.id }}" + <<: *aws_connection_info + + - name: fact stopped ec2 instance + ec2_instance_facts: + filters: + "tag:Name": "{{ resource_prefix }}-checkmode-comparison" + <<: *aws_connection_info + register: confirm_stopinstance_fact + + - name: Verify that it was stopped. + assert: + that: + - '"{{ confirm_stopinstance_fact.instances[0].state.name }}" == "stopped"' + + - name: Running instance in check mode. + ec2_instance: + name: "{{ resource_prefix }}-checkmode-comparison" + state: running + vpc_subnet_id: "{{ testing_subnet_a.subnet.id }}" + <<: *aws_connection_info + check_mode: yes + + - name: fact ec2 instance + ec2_instance_facts: + filters: + "tag:Name": "{{ resource_prefix }}-checkmode-comparison" + <<: *aws_connection_info + register: confirm_checkmode_runninginstance_fact + + - name: Verify that it was not running. + assert: + that: + - '"{{ confirm_checkmode_runninginstance_fact.instances[0].state.name }}" != "running"' + + - name: Running instance in normaly. + ec2_instance: + name: "{{ resource_prefix }}-checkmode-comparison" + state: running + vpc_subnet_id: "{{ testing_subnet_a.subnet.id }}" + <<: *aws_connection_info + + - name: fact ec2 instance. + ec2_instance_facts: + filters: + "tag:Name": "{{ resource_prefix }}-checkmode-comparison" + <<: *aws_connection_info + register: confirm_runninginstance_fact + + - name: Verify that it was running. + assert: + that: + - '"{{ confirm_runninginstance_fact.instances[0].state.name }}" == "running"' + + - name: Terminate instance in check mode. + ec2_instance: + name: "{{ resource_prefix }}-checkmode-comparison" + state: absent + vpc_subnet_id: "{{ testing_subnet_a.subnet.id }}" + <<: *aws_connection_info + check_mode: yes + + - name: fact ec2 instance + ec2_instance_facts: + filters: + "tag:Name": "{{ resource_prefix }}-checkmode-comparison" + <<: *aws_connection_info + register: confirm_checkmode_terminatedinstance_fact + + - name: Verify that it was not terminated, + assert: + that: + - '"{{ confirm_checkmode_terminatedinstance_fact.instances[0].state.name }}" != "terminated"' + + - name: Terminate instance in check mode. + ec2_instance: + name: "{{ resource_prefix }}-checkmode-comparison" + state: absent + vpc_subnet_id: "{{ testing_subnet_a.subnet.id }}" + <<: *aws_connection_info + + - name: fact ec2 instance + ec2_instance_facts: + filters: + "tag:Name": "{{ resource_prefix }}-checkmode-comparison" + <<: *aws_connection_info + register: confirm_terminatedinstance_fact + + - name: Verify that it was terminated, + assert: + that: + - '"{{ confirm_terminatedinstance_fact.instances[0].state.name }}" == "terminated"' + + always: + - name: Terminate instance + ec2: + instance_ids: "{{ basic_instance.instance_ids }}" + state: absent + <<: *aws_connection_info + register: removed + until: removed is not failed + ignore_errors: yes + retries: 10 diff --git a/test/integration/targets/ec2_instance/playbooks/roles/ec2_instance/tasks/cpu_options.yml b/test/integration/targets/ec2_instance/playbooks/roles/ec2_instance/tasks/cpu_options.yml index f6edb36c14..6f4adf1fe9 100644 --- a/test/integration/targets/ec2_instance/playbooks/roles/ec2_instance/tasks/cpu_options.yml +++ b/test/integration/targets/ec2_instance/playbooks/roles/ec2_instance/tasks/cpu_options.yml @@ -58,3 +58,43 @@ that: - cpu_options_update is success - cpu_options_update is not changed + +- name: create c4.large instance with cpu_options(check mode) + ec2_instance: + name: "{{ resource_prefix }}-test-c4large-1-threads-per-core-checkmode" + image_id: "{{ ec2_ami_image[aws_region] }}" + tags: + TestId: "{{ resource_prefix }}" + vpc_subnet_id: "{{ testing_subnet_a.subnet.id }}" + instance_type: c4.large + cpu_options: + core_count: 1 + threads_per_core: 1 + volumes: + - device_name: /dev/sda1 + ebs: + delete_on_termination: true + <<: *aws_connection_info + check_mode: yes + +- name: "fact presented ec2 instance" + ec2_instance_facts: + filters: + "tag:Name": "{{ resource_prefix }}-test-c4large-1-threads-per-core" + "instance-state-name": "running" + <<: *aws_connection_info + register: presented_instance_fact + +- name: "fact checkmode ec2 instance" + ec2_instance_facts: + filters: + "tag:Name": "{{ resource_prefix }}-test-c4large-1-threads-per-core-checkmode" + "instance-state-name": "running" + <<: *aws_connection_info + register: checkmode_instance_fact + +- name: "Confirm existence of instance id." + assert: + that: + - "{{ presented_instance_fact.instances | length }} > 0" + - "{{ checkmode_instance_fact.instances | length }} == 0" diff --git a/test/integration/targets/ec2_instance/playbooks/roles/ec2_instance/tasks/default_vpc_tests.yml b/test/integration/targets/ec2_instance/playbooks/roles/ec2_instance/tasks/default_vpc_tests.yml index 85dbf501fc..23bcdb67a8 100644 --- a/test/integration/targets/ec2_instance/playbooks/roles/ec2_instance/tasks/default_vpc_tests.yml +++ b/test/integration/targets/ec2_instance/playbooks/roles/ec2_instance/tasks/default_vpc_tests.yml @@ -20,6 +20,44 @@ delete_on_termination: true <<: *aws_connection_info register: in_default_vpc + +- name: Make instance in a default subnet of the VPC(check mode) + ec2_instance: + name: "{{ resource_prefix }}-test-default-vpc-checkmode" + image_id: "{{ ec2_ami_image[aws_region] }}" + tags: + TestId: "{{ resource_prefix }}" + security_groups: "{{ sg.group_id }}" + instance_type: t2.micro + volumes: + - device_name: /dev/sda1 + ebs: + delete_on_termination: true + <<: *aws_connection_info + check_mode: yes + +- name: "fact presented ec2 instance" + ec2_instance_facts: + filters: + "tag:Name": "{{ resource_prefix }}-test-default-vpc" + "instance-state-name": "running" + <<: *aws_connection_info + register: presented_instance_fact + +- name: "fact checkmode ec2 instance" + ec2_instance_facts: + filters: + "tag:Name": "{{ resource_prefix }}-test-default-vpc-checkmode" + "instance-state-name": "running" + <<: *aws_connection_info + register: checkmode_instance_fact + +- name: "Confirm whether the check mode is working normally." + assert: + that: + - "{{ presented_instance_fact.instances | length }} > 0" + - "{{ checkmode_instance_fact.instances | length }} == 0" + - name: Terminate instance ec2: instance_ids: "{{ in_default_vpc.instance_ids }}" diff --git a/test/integration/targets/ec2_instance/playbooks/roles/ec2_instance/tasks/external_resource_attach.yml b/test/integration/targets/ec2_instance/playbooks/roles/ec2_instance/tasks/external_resource_attach.yml index b11b618d19..bae35eb9a2 100644 --- a/test/integration/targets/ec2_instance/playbooks/roles/ec2_instance/tasks/external_resource_attach.yml +++ b/test/integration/targets/ec2_instance/playbooks/roles/ec2_instance/tasks/external_resource_attach.yml @@ -21,6 +21,13 @@ - "{{ sg.group_id }}" <<: *aws_connection_info register: eni_b +- ec2_eni: + delete_on_termination: true + subnet_id: "{{ testing_subnet_b.subnet.id }}" + security_groups: + - "{{ sg.group_id }}" + <<: *aws_connection_info + register: eni_c - ec2_key: name: "{{ resource_prefix }}_test_key" @@ -63,6 +70,47 @@ instance_type: t2.micro <<: *aws_connection_info +- name: Make instance in the testing subnet created in the test VPC(check mode) + ec2_instance: + name: "{{ resource_prefix }}-test-eni-vpc-checkmode" + key_name: "{{ resource_prefix }}_test_key" + network: + interfaces: + - id: "{{ eni_c.interface.id }}" + image_id: "{{ ec2_ami_image[aws_region] }}" + availability_zone: '{{ aws_region }}b' + tags: + TestId: "{{ resource_prefix }}" + volumes: + - device_name: /dev/sda1 + ebs: + delete_on_termination: true + instance_type: t2.micro + <<: *aws_connection_info + check_mode: yes + +- name: "fact presented ec2 instance" + ec2_instance_facts: + filters: + "tag:Name": "{{ resource_prefix }}-test-eni-vpc" + "instance-state-name": "running" + <<: *aws_connection_info + register: presented_instance_fact + +- name: "fact checkmode ec2 instance" + ec2_instance_facts: + filters: + "tag:Name": "{{ resource_prefix }}-test-eni-vpc-checkmode" + "instance-state-name": "running" + <<: *aws_connection_info + register: checkmode_instance_fact + +- name: "Confirm existence of instance id." + assert: + that: + - "{{ presented_instance_fact.instances | length }} > 0" + - "{{ checkmode_instance_fact.instances | length }} == 0" + - name: Terminate instance ec2_instance: filters: @@ -94,3 +142,4 @@ with_items: - "{{ eni_a.interface.id }}" - "{{ eni_b.interface.id }}" + - "{{ eni_c.interface.id }}" diff --git a/test/integration/targets/ec2_instance/playbooks/roles/ec2_instance/tasks/iam_instance_role.yml b/test/integration/targets/ec2_instance/playbooks/roles/ec2_instance/tasks/iam_instance_role.yml index 6fd27bdfaf..56ac8f50f5 100644 --- a/test/integration/targets/ec2_instance/playbooks/roles/ec2_instance/tasks/iam_instance_role.yml +++ b/test/integration/targets/ec2_instance/playbooks/roles/ec2_instance/tasks/iam_instance_role.yml @@ -48,6 +48,42 @@ that: - 'instance_with_role.instances[0].iam_instance_profile.arn == iam_role.arn.replace(":role/", ":instance-profile/")' + - name: Make instance with an instance_role(check mode) + ec2_instance: + name: "{{ resource_prefix }}-test-instance-role-checkmode" + image_id: "{{ ec2_ami_image[aws_region] }}" + security_groups: "{{ sg.group_id }}" + instance_type: t2.micro + instance_role: "{{ resource_prefix }}-test-policy" + volumes: + - device_name: /dev/sda1 + ebs: + delete_on_termination: true + <<: *aws_connection_info + check_mode: yes + + - name: "fact presented ec2 instance" + ec2_instance_facts: + filters: + "tag:Name": "{{ resource_prefix }}-test-instance-role" + "instance-state-name": "running" + <<: *aws_connection_info + register: presented_instance_fact + + - name: "fact checkmode ec2 instance" + ec2_instance_facts: + filters: + "tag:Name": "{{ resource_prefix }}-test-instance-role-checkmode" + "instance-state-name": "running" + <<: *aws_connection_info + register: checkmode_instance_fact + + - name: "Confirm whether the check mode is working normally." + assert: + that: + - "{{ presented_instance_fact.instances | length }} > 0" + - "{{ checkmode_instance_fact.instances | length }} == 0" + - name: Update instance with new instance_role ec2_instance: name: "{{ resource_prefix }}-test-instance-role" diff --git a/test/integration/targets/ec2_instance/playbooks/roles/ec2_instance/tasks/main.yml b/test/integration/targets/ec2_instance/playbooks/roles/ec2_instance/tasks/main.yml index 43c32fbb5f..4cae24f62a 100644 --- a/test/integration/targets/ec2_instance/playbooks/roles/ec2_instance/tasks/main.yml +++ b/test/integration/targets/ec2_instance/playbooks/roles/ec2_instance/tasks/main.yml @@ -96,6 +96,7 @@ - include_tasks: block_devices.yml - include_tasks: default_vpc_tests.yml - include_tasks: iam_instance_role.yml + - include_tasks: checkmode_tests.yml # ============================================================ diff --git a/test/integration/targets/ec2_instance/playbooks/roles/ec2_instance/tasks/tags_and_vpc_settings.yml b/test/integration/targets/ec2_instance/playbooks/roles/ec2_instance/tasks/tags_and_vpc_settings.yml index 036d92a0ca..e5009a93d8 100644 --- a/test/integration/targets/ec2_instance/playbooks/roles/ec2_instance/tasks/tags_and_vpc_settings.yml +++ b/test/integration/targets/ec2_instance/playbooks/roles/ec2_instance/tasks/tags_and_vpc_settings.yml @@ -29,6 +29,29 @@ <<: *aws_connection_info register: in_test_vpc +- name: Make instance in the testing subnet created in the test VPC(check mode) + ec2_instance: + name: "{{ resource_prefix }}-test-basic-vpc-create-checkmode" + image_id: "{{ ec2_ami_image[aws_region] }}" + user_data: | + #cloud-config + package_upgrade: true + package_update: true + tags: + TestId: "{{ resource_prefix }}" + Something: else + security_groups: "{{ sg.group_id }}" + network: + source_dest_check: false + vpc_subnet_id: "{{ testing_subnet_b.subnet.id }}" + instance_type: t2.micro + volumes: + - device_name: /dev/sda1 + ebs: + delete_on_termination: true + <<: *aws_connection_info + check_mode: yes + - name: Try to re-make the instance, hopefully this shows changed=False ec2_instance: name: "{{ resource_prefix }}-test-basic-vpc-create" @@ -55,6 +78,28 @@ assert: that: 'not remake_in_test_vpc.instances[0].source_dest_check' +- name: "fact presented ec2 instance" + ec2_instance_facts: + filters: + "tag:Name": "{{ resource_prefix }}-test-basic-vpc-create" + "instance-state-name": "running" + <<: *aws_connection_info + register: presented_instance_fact + +- name: "fact checkmode ec2 instance" + ec2_instance_facts: + filters: + "tag:Name": "{{ resource_prefix }}-test-basic-vpc-create-checkmode" + "instance-state-name": "running" + <<: *aws_connection_info + register: checkmode_instance_fact + +- name: "Confirm whether the check mode is working normally." + assert: + that: + - "{{ presented_instance_fact.instances | length }} > 0" + - "{{ checkmode_instance_fact.instances | length }} == 0" + - name: Alter it by adding tags ec2_instance: name: "{{ resource_prefix }}-test-basic-vpc-create" diff --git a/test/integration/targets/ec2_instance/playbooks/roles/ec2_instance/tasks/termination_protection.yml b/test/integration/targets/ec2_instance/playbooks/roles/ec2_instance/tasks/termination_protection.yml index 9ff72c33ef..8008ef878a 100644 --- a/test/integration/targets/ec2_instance/playbooks/roles/ec2_instance/tasks/termination_protection.yml +++ b/test/integration/targets/ec2_instance/playbooks/roles/ec2_instance/tasks/termination_protection.yml @@ -22,6 +22,46 @@ delete_on_termination: true <<: *aws_connection_info register: in_test_vpc + +- name: Make termination-protected instance in the testing subnet created in the test VPC(check mode) + ec2_instance: + name: "{{ resource_prefix }}-test-protected-instance-in-vpc-checkmode" + image_id: "{{ ec2_ami_image[aws_region] }}" + tags: + TestId: "{{ resource_prefix }}" + security_groups: "{{ sg.group_id }}" + vpc_subnet_id: "{{ testing_subnet_b.subnet.id }}" + termination_protection: true + instance_type: t2.micro + volumes: + - device_name: /dev/sda1 + ebs: + delete_on_termination: true + <<: *aws_connection_info + check_mode: yes + +- name: "fact presented ec2 instance" + ec2_instance_facts: + filters: + "tag:Name": "{{ resource_prefix }}-test-protected-instance-in-vpc" + "instance-state-name": "running" + <<: *aws_connection_info + register: presented_instance_fact + +- name: "fact checkmode ec2 instance" + ec2_instance_facts: + filters: + "tag:Name": "{{ resource_prefix }}-test-protected-instance-in-vpc-checkmode" + "instance-state-name": "running" + <<: *aws_connection_info + register: checkmode_instance_fact + +- name: "Confirm whether the check mode is working normally." + assert: + that: + - "{{ presented_instance_fact.instances | length }} > 0" + - "{{ checkmode_instance_fact.instances | length }} == 0" + - name: Try to terminate the instance ec2_instance: state: absent