ansible-community / ansible-community/molecule-plugins
EC2 destroy.yml will terminate other instances if no match is found
- Dominant language
- Python
- Stars
- 164
- Forks
- 113
- Avg merge
- 4d 20h
- Merged PRs (30d)
- 1
Description
The EC2 driver maintains information about the instances it creates then uses that information to destroy the instance.
This isn't a problem (usually) when running molecule tests to completion. However when using test-driven development (TDD) you may routinely run the test to 'converge', do a bit more work, and then complete the molecule tests to see if the results have improved. There's a significant downside to this - the longer this instance is running the greater the risk that another process will terminate the instance. It might be a local process, it might be another process interacting with EC2.
When this happens (ouch) the code blocks
```yml
# Merging defaults into a list of dicts is, it turns out, not straightforward
platforms: >-
{{ [platform_defaults | dict2items]
| product(molecule_yml.platforms | map('dict2items') | list)
| map('flatten', levels=1)
| list
| map('items2dict')
| list }}
- name: Validate discovered information
assert:
that: platform.vpc_id or (subnet_info.results[index].subnets | length > 0)
quiet: true
loop: "{{ platforms }}"
loop_control:
loop_var: platform
index_var: index
label: "{{ platform.name }}"
- name: Destroy ephemeral EC2 instances
ec2_instance:
profile: "{{ item.aws_profile | default(omit) }}"
region: "{{ item.region | default(omit) }}"
instance_ids: "{{ instance_config | map(attribute='instance_ids') | flatten }}"
state: absent
loop: "{{ platforms }}"
loop_control:
label: "{{ item.name }}"
register: ec2_instances_async
async: 7200
poll: 0
```
will quietly set `instance_ids` to null instead of failing. That means the play will match *all* EC2 instances matching that profile and region.
I suspect the playbook had originally verified that the instance(s) was still running as part of the creation of the `platforms` list and that list would have been empty if the instance(s) was no longer running but that's no longer the case.
Fortunately there's a simple fix:
```yml
- ansible.builtin.set_facts:
instance_ids: "{{ instance_ids | default(instance_config) | map(attribute='instance_ids') }}"
loop: "{{ platforms }}"
- amazon.aws.ec2_instance:
instance_ids: '{{ instance_ids | flatten }}'
...
when: instance_ids is defined and instance_ids[0] is defined
```
with related updates below. (This isn't the final code - just a demonstration that it's easy to check whether the list will be empty.)
PR to follow.
Contributor guide
No contributing guide indexed for this repository
Research direction
Start in destroy.yml at the “Destroy ephemeral EC2 instances” task and review how instance_ids is built before the amazon.aws.ec2_instance call. Ensure the task does not run when no instance IDs were discovered, then exercise the Molecule converge and completion flow to confirm unrelated EC2 instances are not terminated.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- ansible, aws
- Domain
- cloud, infrastructure
- Issue type
- Bug
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 38/100