Skip to content

EC2 destroy.yml will terminate other instances if no match is found #121

Open
@beargiles

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

    # 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:

    - 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.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingec2Amazon EC2

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions