ansible/test/integration/targets/ec2_eip/tasks/main.yml
Mark Chappell b5f484dcc3 ec2_eip Don't throw an exception when re-releasing an EIP (idempotency) (#62332)
* ec2_eip: (integration tests) move to using module_defaults

* ec2_eip: (integration tests) expand integration tests

Also clean up a little
- Delete EIPs when we finish testing them (reduce the chance of hitting limits)
- Rejig deletion so that it works when runs fail
- Add tests for ec2_eip_info

* ec2_eip: Minor doc tweaks

* ec2_eip: Don't throw an exception when we try to disassociate an already disassociated EIP

* ec2_eip: Add missing IAM policy (manage IGWs)

* ec2_eip: (integration tests) Use the VPC as a crude lock to avoid running parallel tests

We test that untagged EIPs come and go as we expect, if multiple tests are
running in parallel this confuses things

* Fix ec2_eip association
2019-11-13 13:27:35 -07:00

767 lines
25 KiB
YAML

---
# Tests for Elastic IP allocation: ec2_eip and ec2_eip_info
#
# Tests ec2_eip:
# - Basic allocation (no conditions)
# - Allocation matching a Public IP
# - Allocation matching a tag name
# - Allocation matching a tag name + value
# - Allocation from a specific pool
# - Attaching an EIP to an ENI
#
# Tests ec2_eip_info:
# - Listing all eips
# - Searching for a specific eip by public IP
# - Searching for a specific eip by allocation-id
#
# Possible Bugs:
# - check_mode not honoured #62318
#
- name: Integration testing for ec2_eip
module_defaults:
group/aws:
aws_access_key: "{{ aws_access_key }}"
aws_secret_key: "{{ aws_secret_key }}"
security_token: "{{ security_token | default(omit) }}"
region: "{{ aws_region }}"
ec2_eip:
in_vpc: yes
block:
- name: Get the current caller identity facts
aws_caller_info:
register: caller_info
- name: list available AZs
aws_az_info:
register: region_azs
- name: pick an AZ for testing
set_fact:
subnet_az: "{{ region_azs.availability_zones[0].zone_name }}"
- name: create a VPC
ec2_vpc_net:
name: "{{ resource_prefix }}-vpc"
state: present
cidr_block: "{{ vpc_cidr }}"
tags:
AnsibleEIPTest: "Pending"
AnsibleEIPTestPrefix: "{{ resource_prefix }}"
register: vpc_result
- name: create subnet
ec2_vpc_subnet:
cidr: "{{ subnet_cidr }}"
az: "{{ subnet_az }}"
vpc_id: "{{ vpc_result.vpc.id }}"
state: present
register: vpc_subnet_create
- ec2_vpc_igw:
state: present
vpc_id: "{{ vpc_result.vpc.id }}"
register: vpc_igw
# =================================================
# A rough Lock using the VPC...
#
# Because we're testing the behaviour when dealing with objects that are
# both tagged and untagged, we need to know that EIPs aren't being poached
# underneath us. See specifically the behaviour around
# I(reuse_existing_ip_allowed), I(tag_name) and I(tag_value)
#
# We also want to know that things like only 1 EIP was allocated / released.
#
# Because Python 2.x and Python 3.x tests are run concurrently there's a
# high chance of the tests interfering with each other if we don't try to
# perform some kind of locking here.
- name: Look for signs of concurrent EIP tests. Pause if they are running or their prefix comes before ours.
vars:
running_query: "vpcs[?tags.AnsibleEIPTest=='Running']"
pending_query: "vpcs[?tags.AnsibleEIPTest=='Pending'].tags.AnsibleEIPTestPrefix"
ec2_vpc_net_info:
filters:
"tag:AnsibleEIPTest": ["Pending", "Running"]
register: vpc_info
retries: 120
delay: 5
until:
# Anyone else running?
- ( vpc_info | json_query(running_query) | length == 0 )
# Are we first in the queue?
- ( vpc_info | json_query(pending_query) | sort | first == resource_prefix )
- name: Make a crude lock
ec2_vpc_net:
name: "{{ resource_prefix }}-vpc"
state: present
cidr_block: "{{ vpc_cidr }}"
tags:
AnsibleEIPTest: "Running"
AnsibleEIPTestPrefix: "{{ resource_prefix }}"
# =================================================
- name: Get current state of EIPs
ec2_eip_info:
register: eip_info_start
- name: Require that there are no free IPs when we start, otherwise we can't test things properly
assert:
that:
- eip_info_start is defined
- '"addresses" in eip_info_start'
- ( eip_info_start.addresses | length ) == ( eip_info_start | json_query("addresses[].association_id") | length )
#==================================================================
# EIP Creation 'no conditions'
# XXX check_mode not honoured
#- name: Allocate a new eip (CHECK MODE)
# ec2_eip:
# state: present
# register: eip
# check_mode: yes
#- ec2_eip_info:
# register: eip_info
#- assert:
# that:
# - eip is defined
# - eip is changed
# - ( eip_info_start.addresses | length ) == ( eip_info.addresses | length )
- name: Allocate a new eip (no conditions)
ec2_eip:
state: present
register: eip
- ec2_eip_info:
register: eip_info
- assert:
that:
- eip is defined
- eip is changed
- eip.public_ip is defined and ( eip.public_ip | ipaddr )
- eip.allocation_id is defined and eip.allocation_id.startswith("eipalloc-")
- ( eip_info_start.addresses | length ) + 1 == ( eip_info.addresses | length )
# Get the info for our specific eip
- ec2_eip_info:
filters:
public-ip: '{{ eip.public_ip }}'
- assert:
that:
- '"addresses" in eip_info'
- eip_info.addresses | length == 1
- eip_info.addresses[0].allocation_id == eip.allocation_id
- eip_info.addresses[0].domain == "vpc"
- eip_info.addresses[0].public_ip == eip.public_ip
# Get the info for our specific eip
- ec2_eip_info:
filters:
allocation-id: '{{ eip.allocation_id }}'
- assert:
that:
- '"addresses" in eip_info'
- eip_info.addresses | length == 1
- eip_info.addresses[0].allocation_id == eip.allocation_id
- eip_info.addresses[0].domain == "vpc"
- eip_info.addresses[0].public_ip == eip.public_ip
# Clean up EIPs as we go to reduce the risk of hitting limits
- name: Release eip
ec2_eip:
state: absent
public_ip: "{{ eip.public_ip }}"
register: eip_release
- ec2_eip_info:
register: eip_info
- assert:
that:
- eip_release is defined
- eip_release is changed
- ( eip_info_start.addresses | length ) == ( eip_info.addresses | length )
#==================================================================
# EIP Creation: reuse allowed
- name: Allocate a new eip - attempt reusing unallocated ones (none available)
ec2_eip:
state: present
reuse_existing_ip_allowed: yes
register: eip
- ec2_eip_info:
register: eip_info
- assert:
that:
- eip is defined
- eip is changed
- eip.public_ip is defined and ( eip.public_ip | ipaddr )
- eip.allocation_id is defined and eip.allocation_id.startswith("eipalloc-")
- ( eip_info_start.addresses | length ) + 1 == ( eip_info.addresses | length )
- name: Re-Allocate a new eip - attempt reusing unallocated ones (one available)
ec2_eip:
state: present
reuse_existing_ip_allowed: yes
register: reallocate_eip
- ec2_eip_info:
register: eip_info
- assert:
that:
- reallocate_eip is defined
- reallocate_eip is not changed
- reallocate_eip.public_ip is defined and ( reallocate_eip.public_ip | ipaddr )
- reallocate_eip.allocation_id is defined and reallocate_eip.allocation_id.startswith("eipalloc-")
- ( eip_info_start.addresses | length ) + 1 == ( eip_info.addresses | length )
- name: Release eip
ec2_eip:
state: absent
public_ip: "{{ eip.public_ip }}"
register: eip_release
- ec2_eip_info:
register: eip_info
- assert:
that:
- ( eip_info_start.addresses | length ) == ( eip_info.addresses | length )
- eip_release is defined
- eip_release is changed
#==================================================================
# EIP Creation: Matching an existing IP
- name: Allocate a new eip
ec2_eip:
state: present
register: eip
- ec2_eip_info:
register: eip_info
- assert:
that:
- eip is defined
- eip is changed
- eip.public_ip is defined and ( eip.public_ip | ipaddr )
- eip.allocation_id is defined and eip.allocation_id.startswith("eipalloc-")
- ( eip_info_start.addresses | length ) + 1 == ( eip_info.addresses | length )
- name: Match an existing eip (changed == false)
ec2_eip:
state: present
public_ip: "{{ eip.public_ip }}"
register: reallocate_eip
- ec2_eip_info:
register: eip_info
- assert:
that:
- reallocate_eip is defined
- reallocate_eip is not changed
- reallocate_eip.public_ip is defined and ( reallocate_eip.public_ip | ipaddr )
- reallocate_eip.allocation_id is defined and reallocate_eip.allocation_id.startswith("eipalloc-")
- ( eip_info_start.addresses | length ) + 1 == ( eip_info.addresses | length )
- name: Release eip
ec2_eip:
state: absent
public_ip: "{{ eip.public_ip }}"
register: eip_release
- ec2_eip_info:
register: eip_info
- assert:
that:
- eip_release is defined
- eip_release is changed
- ( eip_info_start.addresses | length ) == ( eip_info.addresses | length )
#==================================================================
# EIP Creation: Matching Tags
- name: Allocate a new eip (no tags)
ec2_eip:
state: present
register: eip
- ec2_eip_info:
register: eip_info
- assert:
that:
- eip is defined
- eip is changed
- eip.public_ip is defined and ( eip.public_ip | ipaddr )
- eip.allocation_id is defined and eip.allocation_id.startswith("eipalloc-")
- ( eip_info_start.addresses | length ) + 1 == ( eip_info.addresses | length )
- name: attempt reusing an existing eip with a tag (No match available)
ec2_eip:
state: present
reuse_existing_ip_allowed: yes
tag_name: Team
register: no_tagged_eip
- ec2_eip_info:
register: eip_info
- assert:
that:
- no_tagged_eip is defined
- no_tagged_eip is changed
- no_tagged_eip.public_ip is defined and ( no_tagged_eip.public_ip | ipaddr )
- no_tagged_eip.allocation_id is defined and no_tagged_eip.allocation_id.startswith("eipalloc-")
- ( eip_info_start.addresses | length ) + 2 == ( eip_info.addresses | length )
- name: tag eip so we can try matching it
ec2_tag:
state: present
resource: '{{ eip.allocation_id }}'
tags:
Team: Frontend
- name: attempt reusing an existing eip with a tag (Match available)
ec2_eip:
state: present
reuse_existing_ip_allowed: yes
tag_name: Team
register: reallocate_eip
- ec2_eip_info:
register: eip_info
- assert:
that:
- reallocate_eip is defined
- reallocate_eip is not changed
- reallocate_eip.public_ip is defined and ( reallocate_eip.public_ip | ipaddr )
- reallocate_eip.allocation_id is defined and reallocate_eip.allocation_id.startswith("eipalloc-")
- ( eip_info_start.addresses | length ) + 2 == ( eip_info.addresses | length )
- name: attempt reusing an existing eip with a tag and it's value (no match available)
ec2_eip:
state: present
reuse_existing_ip_allowed: yes
tag_name: Team
tag_value: Backend
register: backend_eip
- ec2_eip_info:
register: eip_info
- assert:
that:
- backend_eip is defined
- backend_eip is changed
- backend_eip.public_ip is defined and ( backend_eip.public_ip | ipaddr )
- backend_eip.allocation_id is defined and backend_eip.allocation_id.startswith("eipalloc-")
- ( eip_info_start.addresses | length ) + 3 == ( eip_info.addresses | length )
- name: tag eip so we can try matching it
ec2_tag:
state: present
resource: '{{ eip.allocation_id }}'
tags:
Team: Backend
- name: attempt reusing an existing eip with a tag and it's value (match available)
ec2_eip:
state: present
reuse_existing_ip_allowed: yes
tag_name: Team
tag_value: Backend
register: reallocate_eip
- ec2_eip_info:
register: eip_info
- assert:
that:
- reallocate_eip is defined
- reallocate_eip is not changed
- reallocate_eip.public_ip is defined and reallocate_eip.public_ip != ""
- reallocate_eip.allocation_id is defined and reallocate_eip.allocation_id != ""
- ( eip_info_start.addresses | length ) + 3 == ( eip_info.addresses | length )
- name: Release backend_eip
ec2_eip:
state: absent
public_ip: "{{ backend_eip.public_ip }}"
register: eip_release
- ec2_eip_info:
register: eip_info
- assert:
that:
- eip_release is defined
- eip_release is changed
- ( eip_info_start.addresses | length ) + 2 == ( eip_info.addresses | length )
- name: Release no_tagged_eip
ec2_eip:
state: absent
public_ip: "{{ no_tagged_eip.public_ip }}"
register: eip_release
- ec2_eip_info:
register: eip_info
- assert:
that:
- eip_release is defined
- eip_release is changed
- ( eip_info_start.addresses | length ) + 1 == ( eip_info.addresses | length )
- name: Release eip
ec2_eip:
state: absent
public_ip: "{{ eip.public_ip }}"
register: eip_release
- ec2_eip_info:
register: eip_info
- assert:
that:
- eip_release is defined
- eip_release is changed
- ( eip_info_start.addresses | length ) == ( eip_info.addresses | length )
#==================================================================
# Allocation from a pool
- name: allocate a new eip from a pool
ec2_eip:
state: present
public_ipv4_pool: amazon
register: eip
- ec2_eip_info:
register: eip_info
- assert:
that:
- eip is defined
- eip is changed
- eip.public_ip is defined and ( eip.public_ip | ipaddr )
- eip.allocation_id is defined and eip.allocation_id.startswith("eipalloc-")
- ( eip_info_start.addresses | length ) + 1 == ( eip_info.addresses | length )
#==================================================================
# Assigning EIP to an ENI
- name: create ENI A
ec2_eni:
subnet_id: '{{ vpc_subnet_create.subnet.id }}'
register: eni_create_a
- name: create ENI B
ec2_eni:
subnet_id: '{{ vpc_subnet_create.subnet.id }}'
register: eni_create_b
# Test attaching EIP to ENI
- name: Attach EIP to ENI A
ec2_eip:
public_ip: "{{ eip.public_ip }}"
device_id: "{{ eni_create_a.interface.id }}"
register: associate_eip
- ec2_eip_info:
filters:
public-ip: '{{ eip.public_ip }}'
register: eip_info
- assert:
that:
- associate_eip is defined
- associate_eip is changed
- eip_info.addresses | length == 1
- associate_eip.public_ip is defined and eip.public_ip == associate_eip.public_ip
- associate_eip.allocation_id is defined and eip.allocation_id == associate_eip.allocation_id
- eip_info.addresses[0].allocation_id == eip.allocation_id
- eip_info.addresses[0].domain == "vpc"
- eip_info.addresses[0].public_ip == eip.public_ip
- eip_info.addresses[0].association_id is defined and eip_info.addresses[0].association_id.startswith("eipassoc-")
- eip_info.addresses[0].network_interface_id == eni_create_a.interface.id
- eip_info.addresses[0].private_ip_address is defined and ( eip_info.addresses[0].private_ip_address | ipaddr )
- eip_info.addresses[0].network_interface_owner_id == caller_info.account
- name: Re-Attach EIP to ENI A (no change)
ec2_eip:
public_ip: "{{ eip.public_ip }}"
device_id: "{{ eni_create_a.interface.id }}"
register: associate_eip
- ec2_eip_info:
filters:
public-ip: '{{ eip.public_ip }}'
register: eip_info
- assert:
that:
- associate_eip is defined
- associate_eip is not changed
- associate_eip.public_ip is defined and eip.public_ip == associate_eip.public_ip
- associate_eip.allocation_id is defined and eip.allocation_id == associate_eip.allocation_id
- eip_info.addresses | length == 1
- eip_info.addresses[0].allocation_id == eip.allocation_id
- eip_info.addresses[0].domain == "vpc"
- eip_info.addresses[0].public_ip == eip.public_ip
- eip_info.addresses[0].association_id is defined and eip_info.addresses[0].association_id.startswith("eipassoc-")
- eip_info.addresses[0].network_interface_id == eni_create_a.interface.id
- eip_info.addresses[0].private_ip_address is defined and ( eip_info.addresses[0].private_ip_address | ipaddr )
# Test attaching EIP to ENI B
- name: Attach EIP to ENI B (should fail, already associated)
ec2_eip:
public_ip: "{{ eip.public_ip }}"
device_id: "{{ eni_create_b.interface.id }}"
register: associate_eip
ignore_errors: yes
- ec2_eip_info:
filters:
public-ip: '{{ eip.public_ip }}'
register: eip_info
- assert:
that:
- associate_eip is defined
- associate_eip is failed
- eip_info.addresses | length == 1
- eip_info.addresses[0].allocation_id == eip.allocation_id
- eip_info.addresses[0].domain == "vpc"
- eip_info.addresses[0].public_ip == eip.public_ip
- eip_info.addresses[0].association_id is defined and eip_info.addresses[0].association_id.startswith("eipassoc-")
- eip_info.addresses[0].network_interface_id == eni_create_a.interface.id
- eip_info.addresses[0].private_ip_address is defined and ( eip_info.addresses[0].private_ip_address | ipaddr )
- name: Attach EIP to ENI B
ec2_eip:
public_ip: "{{ eip.public_ip }}"
device_id: "{{ eni_create_b.interface.id }}"
allow_reassociation: yes
register: associate_eip
- ec2_eip_info:
filters:
public-ip: '{{ eip.public_ip }}'
register: eip_info
- assert:
that:
- associate_eip is defined
- associate_eip is changed
- associate_eip.public_ip is defined and eip.public_ip == associate_eip.public_ip
- associate_eip.allocation_id is defined and eip.allocation_id == associate_eip.allocation_id
- eip_info.addresses | length == 1
- eip_info.addresses[0].allocation_id == eip.allocation_id
- eip_info.addresses[0].domain == "vpc"
- eip_info.addresses[0].public_ip == eip.public_ip
- eip_info.addresses[0].association_id is defined and eip_info.addresses[0].association_id.startswith("eipassoc-")
- eip_info.addresses[0].network_interface_id == eni_create_b.interface.id
- eip_info.addresses[0].private_ip_address is defined and ( eip_info.addresses[0].private_ip_address | ipaddr )
- name: Detach EIP from ENI B, without enabling release on disassociation
ec2_eip:
state: absent
public_ip: "{{ eip.public_ip }}"
device_id: "{{ eni_create_b.interface.id }}"
register: disassociate_eip
- ec2_eip_info:
filters:
public-ip: '{{ eip.public_ip }}'
register: eip_info
- assert:
that:
- associate_eip is defined
- associate_eip is changed
- eip_info.addresses | length == 1
- name: Re-detach EIP from ENI B, without enabling release on disassociation
ec2_eip:
state: absent
public_ip: "{{ eip.public_ip }}"
device_id: "{{ eni_create_b.interface.id }}"
register: associate_eip
- ec2_eip_info:
filters:
public-ip: '{{ eip.public_ip }}'
register: eip_info
- assert:
that:
- associate_eip is defined
- associate_eip is not changed
- eip_info.addresses | length == 1
- name: Attach EIP to ENI A
ec2_eip:
public_ip: "{{ eip.public_ip }}"
device_id: "{{ eni_create_a.interface.id }}"
register: associate_eip
- ec2_eip_info:
filters:
public-ip: '{{ eip.public_ip }}'
register: eip_info
- assert:
that:
- associate_eip is defined
- associate_eip is changed
- associate_eip.public_ip is defined and eip.public_ip == associate_eip.public_ip
- associate_eip.allocation_id is defined and eip.allocation_id == associate_eip.allocation_id
- eip_info.addresses[0].network_interface_id == eni_create_a.interface.id
- name: Detach EIP from ENI A, enabling release on disassociation
ec2_eip:
state: absent
public_ip: "{{ eip.public_ip }}"
device_id: "{{ eni_create_a.interface.id }}"
release_on_disassociation: yes
register: disassociate_eip
- ec2_eip_info:
filters:
public-ip: '{{ eip.public_ip }}'
register: eip_info
- assert:
that:
- associate_eip is defined
- associate_eip is changed
- eip_info.addresses | length == 0
- name: Re-detach EIP from ENI A, enabling release on disassociation
ec2_eip:
state: absent
public_ip: "{{ eip.public_ip }}"
device_id: "{{ eni_create_a.interface.id }}"
release_on_disassociation: yes
register: associate_eip
- ec2_eip_info:
filters:
public-ip: '{{ eip.public_ip }}'
register: eip_info
- assert:
that:
- associate_eip is defined
- associate_eip is not changed
- eip_info.addresses | length == 0
- ec2_eip_info:
register: eip_info
- assert:
that:
- ( eip_info_start.addresses | length ) == ( eip_info.addresses | length )
- name: Cleanup ENI B
ec2_eni:
state: absent
eni_id: "{{ eni_create_b.interface.id }}"
- name: Cleanup ENI A
ec2_eni:
state: absent
eni_id: "{{ eni_create_a.interface.id }}"
- name: Cleanup IGW
ec2_vpc_igw:
state: absent
vpc_id: "{{ vpc_result.vpc.id }}"
register: vpc_igw
- name: Cleanup Subnet
ec2_vpc_subnet:
state: absent
cidr: "{{ subnet_cidr }}"
vpc_id: "{{ vpc_result.vpc.id }}"
- name: Release eip
ec2_eip:
state: absent
public_ip: "{{ eip.public_ip }}"
register: eip_release
ignore_errors: true
#==================================================================
# EIP Deletion
- name: allocate a new eip
ec2_eip:
state: present
register: eip
- ec2_eip_info:
register: eip_info
- assert:
that:
- eip is defined
- eip is changed
- eip.public_ip is defined and ( eip.public_ip | ipaddr )
- eip.allocation_id is defined and eip.allocation_id.startswith("eipalloc-")
- ( eip_info_start.addresses | length ) + 1 == ( eip_info.addresses | length )
- name: Release eip
ec2_eip:
state: absent
public_ip: "{{ eip.public_ip }}"
register: eip_release
- ec2_eip_info:
register: eip_info
- assert:
that:
- eip_release is defined
- eip_release is changed
- ( eip_info_start.addresses | length ) == ( eip_info.addresses | length )
- name: Rerelease eip (no change)
ec2_eip:
state: absent
public_ip: "{{ eip.public_ip }}"
register: eip_release
- ec2_eip_info:
register: eip_info
- assert:
that:
- eip_release is defined
- eip_release is not changed
- ( eip_info_start.addresses | length ) == ( eip_info.addresses | length )
- name: Cleanup VPC
ec2_vpc_net:
state: absent
name: "{{ resource_prefix }}-vpc"
cidr_block: "{{ vpc_cidr }}"
always:
- name: Cleanup ENI A
ec2_eni:
state: absent
eni_id: "{{ eni_create_a.interface.id }}"
ignore_errors: yes
- name: Cleanup ENI B
ec2_eni:
state: absent
eni_id: "{{ eni_create_b.interface.id }}"
ignore_errors: yes
- name: Cleanup IGW
ec2_vpc_igw:
state: absent
vpc_id: "{{ vpc_result.vpc.id }}"
register: vpc_igw
- name: Cleanup Subnet
ec2_vpc_subnet:
state: absent
cidr: "{{ subnet_cidr }}"
vpc_id: "{{ vpc_result.vpc.id }}"
ignore_errors: yes
- name: Cleanup eip
ec2_eip:
state: absent
public_ip: "{{ eip.public_ip }}"
when: eip is changed
ignore_errors: yes
- name: Cleanup reallocate_eip
ec2_eip:
state: absent
public_ip: "{{ reallocate_eip.public_ip }}"
when: reallocate_eip is changed
ignore_errors: yes
- name: Cleanup backend_eip
ec2_eip:
state: absent
public_ip: "{{ backend_eip.public_ip }}"
when: backend_eip is changed
ignore_errors: yes
- name: Cleanup no_tagged_eip
ec2_eip:
state: absent
public_ip: "{{ no_tagged_eip.public_ip }}"
when: no_tagged_eip is changed
ignore_errors: yes
- name: Cleanup VPC
ec2_vpc_net:
state: absent
name: "{{ resource_prefix }}-vpc"
cidr_block: "{{ vpc_cidr }}"
ignore_errors: yes