Migrate ec2_eip module to boto3 (#61575)

* Migrate ec2_eip module to boto3

This patch is a step towards the integration of several PRs that have
attempted to migrate this code

closes #55190
closes #45478

Follow-up PRs will address the outstanding changes made in #55190
This commit is contained in:
Tim Rupp 2019-09-03 19:46:29 -07:00 committed by Sloane Hertel
parent 00add5b668
commit 2ebeadfc14
2 changed files with 318 additions and 251 deletions

View file

@ -223,163 +223,203 @@ public_ip:
''' '''
try: try:
import boto.exception import botocore.exceptions
from boto.ec2.address import Address
except ImportError: except ImportError:
pass # Taken care of by ec2.HAS_BOTO pass # Taken care of by ec2.HAS_BOTO3
from ansible.module_utils.basic import AnsibleModule from ansible.module_utils.aws.core import AnsibleAWSModule, is_boto3_error_code
from ansible.module_utils.ec2 import HAS_BOTO, ec2_argument_spec, ec2_connect from ansible.module_utils.ec2 import AWSRetry, ansible_dict_to_boto3_filter_list, ec2_argument_spec
class EIPException(Exception): def associate_ip_and_device(ec2, module, address, private_ip_address, device_id, allow_reassociation, check_mode, is_instance=True):
pass if address_is_associated_with_device(ec2, module, address, device_id, is_instance):
def associate_ip_and_device(ec2, address, private_ip_address, device_id, allow_reassociation, check_mode, is_instance=True):
if address_is_associated_with_device(ec2, address, device_id, is_instance):
return {'changed': False} return {'changed': False}
# If we're in check mode, nothing else to do # If we're in check mode, nothing else to do
if not check_mode: if not check_mode:
if is_instance: if is_instance:
if address.domain == "vpc": try:
res = ec2.associate_address(device_id, params = dict(
allocation_id=address.allocation_id, InstanceId=device_id,
private_ip_address=private_ip_address, PrivateIpAddress=private_ip_address,
allow_reassociation=allow_reassociation) AllowReassociation=allow_reassociation,
else: )
res = ec2.associate_address(device_id, if address.domain == "vpc":
public_ip=address.public_ip, params['AllocationId'] = address['AllocationId']
private_ip_address=private_ip_address, else:
allow_reassociation=allow_reassociation) params['PublicIp'] = address['PublicIp']
res = ec2.associate_address(**params)
except (botocore.exceptions.BotoCoreError, botocore.exceptions.ClientError) as e:
msg = "Couldn't associate Elastic IP address with instance '{0}'".format(device_id)
module.fail_json_aws(e, msg=msg)
else: else:
res = ec2.associate_address(network_interface_id=device_id, params = dict(
allocation_id=address.allocation_id, NetworkInterfaceId=device_id,
private_ip_address=private_ip_address, AllocationId=address['AllocationId'],
allow_reassociation=allow_reassociation) AllowReassociation=allow_reassociation,
)
if private_ip_address:
params['PrivateIpAddress'] = private_ip_address
try:
res = ec2.associate_address(aws_retry=True, **params)
except (botocore.exceptions.BotoCoreError, botocore.exceptions.ClientError) as e:
msg = "Couldn't associate Elastic IP address with network interface '{0}'".format(device_id)
module.fail_json_aws(e, msg=msg)
if not res: if not res:
raise EIPException('association failed') module.fail_json_aws(e, msg='Association failed.')
return {'changed': True} return {'changed': True}
def disassociate_ip_and_device(ec2, address, device_id, check_mode, is_instance=True): def disassociate_ip_and_device(ec2, module, address, device_id, check_mode, is_instance=True):
if not address_is_associated_with_device(ec2, address, device_id, is_instance): if not address_is_associated_with_device(ec2, module, address, device_id, is_instance):
return {'changed': False} return {'changed': False}
# If we're in check mode, nothing else to do # If we're in check mode, nothing else to do
if not check_mode: if not check_mode:
if address.domain == 'vpc': try:
res = ec2.disassociate_address( if address['Domain'] == 'vpc':
association_id=address.association_id) res = ec2.disassociate_address(
else: AssociationId=address['AssociationId'], aws_retry=True
res = ec2.disassociate_address(public_ip=address.public_ip) )
else:
if not res: res = ec2.disassociate_address(
raise EIPException('disassociation failed') PublicIp=address['PublicIp'], aws_retry=True
)
except (botocore.exceptions.BotoCoreError, botocore.exceptions.ClientError) as e:
module.fail_json_aws(e, msg="Dissassociation of Elastic IP failed")
return {'changed': True} return {'changed': True}
def _find_address_by_ip(ec2, public_ip): @AWSRetry.jittered_backoff()
try: def find_address(ec2, module, public_ip, device_id, is_instance=True):
return ec2.get_all_addresses([public_ip])[0]
except boto.exception.EC2ResponseError as e:
if "Address '{0}' not found.".format(public_ip) not in e.message:
raise
def _find_address_by_device_id(ec2, device_id, is_instance=True):
if is_instance:
addresses = ec2.get_all_addresses(None, {'instance-id': device_id})
else:
addresses = ec2.get_all_addresses(None, {'network-interface-id': device_id})
if addresses:
return addresses[0]
def find_address(ec2, public_ip, device_id, is_instance=True):
""" Find an existing Elastic IP address """ """ Find an existing Elastic IP address """
filters = []
kwargs = {}
if public_ip: if public_ip:
return _find_address_by_ip(ec2, public_ip) kwargs["PublicIps"] = [public_ip]
elif device_id and is_instance:
return _find_address_by_device_id(ec2, device_id)
elif device_id: elif device_id:
return _find_address_by_device_id(ec2, device_id, is_instance=False) if is_instance:
filters.append({"Name": 'instance-id', "Values": [device_id]})
else:
filters.append({'Name': 'network-interface-id', "Values": [device_id]})
if len(filters) > 0:
kwargs["Filters"] = filters
elif len(filters) == 0 and public_ip is None:
return None
try:
addresses = ec2.describe_addresses(**kwargs)
except is_boto3_error_code('InvalidAddress.NotFound') as e:
module.fail_json_aws(e, msg="Couldn't obtain list of existing Elastic IP addresses")
addresses = addresses["Addresses"]
if len(addresses) == 1:
return addresses[0]
elif len(addresses) > 1:
msg = "Found more than one address using args {0}".format(kwargs)
msg += "Addresses found: {0}".format(addresses)
module.fail_json_aws(botocore.exceptions.ClientError, msg=msg)
def address_is_associated_with_device(ec2, address, device_id, is_instance=True): def address_is_associated_with_device(ec2, module, address, device_id, is_instance=True):
""" Check if the elastic IP is currently associated with the device """ """ Check if the elastic IP is currently associated with the device """
address = ec2.get_all_addresses(address.public_ip) address = find_address(ec2, module, address["PublicIp"], device_id, is_instance)
if address: if address:
if is_instance: if is_instance:
return address and address[0].instance_id == device_id if "InstanceId" in address and address["InstanceId"] == device_id:
return address
else: else:
return address and address[0].network_interface_id == device_id if "NetworkInterfaceId" in address and address["NetworkInterfaceId"] == device_id:
return address
return False return False
def allocate_address(ec2, domain, reuse_existing_ip_allowed, check_mode, tag_dict=None, public_ipv4_pool=None): def allocate_address(ec2, module, domain, reuse_existing_ip_allowed, check_mode, tag_dict=None, public_ipv4_pool=None):
""" Allocate a new elastic IP address (when needed) and return it """ """ Allocate a new elastic IP address (when needed) and return it """
if reuse_existing_ip_allowed: if reuse_existing_ip_allowed:
domain_filter = {'domain': domain or 'standard'} filters = []
if not domain:
domain = 'standard'
filters.append({'Name': 'domain', "Values": [domain]})
if tag_dict is not None: if tag_dict is not None:
domain_filter.update(tag_dict) filters += ansible_dict_to_boto3_filter_list(tag_dict)
all_addresses = ec2.get_all_addresses(filters=domain_filter) try:
all_addresses = ec2.describe_addresses(Filters=filters, aws_retry=True)
except (botocore.exceptions.BotoCoreError, botocore.exceptions.ClientError) as e:
module.fail_json_aws(e, msg="Couldn't obtain list of existing Elastic IP addresses")
all_addresses = all_addresses["Addresses"]
if domain == 'vpc': if domain == 'vpc':
unassociated_addresses = [a for a in all_addresses unassociated_addresses = [a for a in all_addresses
if not a.association_id] if not a.get('AssociationId', None)]
else: else:
unassociated_addresses = [a for a in all_addresses unassociated_addresses = [a for a in all_addresses
if not a.instance_id] if not a['InstanceId']]
if unassociated_addresses: if unassociated_addresses:
return unassociated_addresses[0], False return unassociated_addresses[0], False
if public_ipv4_pool: if public_ipv4_pool:
return allocate_address_from_pool(ec2, domain, check_mode, public_ipv4_pool), True return allocate_address_from_pool(ec2, module, domain, check_mode, public_ipv4_pool), True
return ec2.allocate_address(domain=domain), True try:
result = ec2.allocate_address(Domain=domain, aws_retry=True), True
except (botocore.exceptions.BotoCoreError, botocore.exceptions.ClientError) as e:
module.fail_json_aws(e, msg="Couldn't allocate Elastic IP address")
return result
def release_address(ec2, address, check_mode): def release_address(ec2, module, address, check_mode):
""" Release a previously allocated elastic IP address """ """ Release a previously allocated elastic IP address """
# If we're in check mode, nothing else to do # If we're in check mode, nothing else to do
if not check_mode: if not check_mode:
if not address.release(): try:
raise EIPException('release failed') result = ec2.release_address(AllocationId=address['AllocationId'], aws_retry=True)
except (botocore.exceptions.BotoCoreError, botocore.exceptions.ClientError) as e:
module.fail_json_aws(e, msg="Couldn't release Elastic IP address")
return {'changed': True} return {'changed': True}
@AWSRetry.jittered_backoff()
def describe_eni_with_backoff(ec2, module, device_id):
try:
return ec2.describe_network_interfaces(NetworkInterfaceIds=[device_id])
except is_boto3_error_code('InvalidNetworkInterfaceID.NotFound') as e:
module.fail_json_aws(e, msg="Couldn't get list of network interfaces.")
def find_device(ec2, module, device_id, is_instance=True): def find_device(ec2, module, device_id, is_instance=True):
""" Attempt to find the EC2 instance and return it """ """ Attempt to find the EC2 instance and return it """
if is_instance: if is_instance:
try: try:
reservations = ec2.get_all_reservations(instance_ids=[device_id]) paginator = ec2.get_paginator('describe_instances')
except boto.exception.EC2ResponseError as e: reservations = list(paginator.paginate(InstanceIds=[device_id]).search('Reservations[]'))
module.fail_json(msg=str(e)) except (botocore.exceptions.BotoCoreError, botocore.exceptions.ClientError) as e:
module.fail_json_aws(e, msg="Couldn't get list of instances")
if len(reservations) == 1: if len(reservations) == 1:
instances = reservations[0].instances instances = reservations[0]['Instances']
if len(instances) == 1: if len(instances) == 1:
return instances[0] return instances[0]
else: else:
try: try:
interfaces = ec2.get_all_network_interfaces(network_interface_ids=[device_id]) interfaces = describe_eni_with_backoff(ec2, module, device_id)
except boto.exception.EC2ResponseError as e: except (botocore.exceptions.BotoCoreError, botocore.exceptions.ClientError) as e:
module.fail_json(msg=str(e)) module.fail_json_aws(e, msg="Couldn't get list of network interfaces.")
if len(interfaces) == 1: if len(interfaces) == 1:
return interfaces[0] return interfaces[0]
raise EIPException("could not find instance" + device_id)
def ensure_present(ec2, module, domain, address, private_ip_address, device_id, def ensure_present(ec2, module, domain, address, private_ip_address, device_id,
reuse_existing_ip_allowed, allow_reassociation, check_mode, is_instance=True): reuse_existing_ip_allowed, allow_reassociation, check_mode, is_instance=True):
@ -390,7 +430,7 @@ def ensure_present(ec2, module, domain, address, private_ip_address, device_id,
if check_mode: if check_mode:
return {'changed': True} return {'changed': True}
address, changed = allocate_address(ec2, domain, reuse_existing_ip_allowed, check_mode) address, changed = allocate_address(ec2, module, domain, reuse_existing_ip_allowed, check_mode)
if device_id: if device_id:
# Allocate an IP for instance since no public_ip was provided # Allocate an IP for instance since no public_ip was provided
@ -398,42 +438,47 @@ def ensure_present(ec2, module, domain, address, private_ip_address, device_id,
instance = find_device(ec2, module, device_id) instance = find_device(ec2, module, device_id)
if reuse_existing_ip_allowed: if reuse_existing_ip_allowed:
if instance.vpc_id and len(instance.vpc_id) > 0 and domain is None: if instance.vpc_id and len(instance.vpc_id) > 0 and domain is None:
raise EIPException("You must set 'in_vpc' to true to associate an instance with an existing ip in a vpc") msg = "You must set 'in_vpc' to true to associate an instance with an existing ip in a vpc"
module.fail_json_aws(botocore.exceptions.ClientError, msg=msg)
# Associate address object (provided or allocated) with instance # Associate address object (provided or allocated) with instance
assoc_result = associate_ip_and_device(ec2, address, private_ip_address, device_id, allow_reassociation, assoc_result = associate_ip_and_device(
check_mode) ec2, module, address, private_ip_address, device_id, allow_reassociation,
check_mode
)
else: else:
instance = find_device(ec2, module, device_id, is_instance=False) instance = find_device(ec2, module, device_id, is_instance=False)
# Associate address object (provided or allocated) with instance # Associate address object (provided or allocated) with instance
assoc_result = associate_ip_and_device(ec2, address, private_ip_address, device_id, allow_reassociation, assoc_result = associate_ip_and_device(
check_mode, is_instance=False) ec2, module, address, private_ip_address, device_id, allow_reassociation,
check_mode, is_instance=False
if instance.vpc_id: )
domain = 'vpc'
changed = changed or assoc_result['changed'] changed = changed or assoc_result['changed']
return {'changed': changed, 'public_ip': address.public_ip, 'allocation_id': address.allocation_id} return {'changed': changed, 'public_ip': address['PublicIp'], 'allocation_id': address['AllocationId']}
def ensure_absent(ec2, address, device_id, check_mode, is_instance=True): def ensure_absent(ec2, module, address, device_id, check_mode, is_instance=True):
if not address: if not address:
return {'changed': False} return {'changed': False}
# disassociating address from instance # disassociating address from instance
if device_id: if device_id:
if is_instance: if is_instance:
return disassociate_ip_and_device(ec2, address, device_id, return disassociate_ip_and_device(
check_mode) ec2, module, address, device_id, check_mode
)
else: else:
return disassociate_ip_and_device(ec2, address, device_id, return disassociate_ip_and_device(
check_mode, is_instance=False) ec2, module, address, device_id, check_mode, is_instance=False
)
# releasing address # releasing address
else: else:
return release_address(ec2, address, check_mode) return release_address(ec2, module, address, check_mode)
def allocate_address_from_pool(ec2, domain, check_mode, public_ipv4_pool): def allocate_address_from_pool(ec2, module, domain, check_mode, public_ipv4_pool):
# type: (EC2Connection, str, bool, str) -> Address # type: (EC2Connection, str, bool, str) -> Address
""" Overrides boto's allocate_address function to support BYOIP """ """ Overrides boto's allocate_address function to support BYOIP """
params = {} params = {}
@ -442,13 +487,16 @@ def allocate_address_from_pool(ec2, domain, check_mode, public_ipv4_pool):
params['Domain'] = domain params['Domain'] = domain
if public_ipv4_pool is not None: if public_ipv4_pool is not None:
ec2.APIVersion = "2016-11-15" # Workaround to force amazon to accept this attribute
params['PublicIpv4Pool'] = public_ipv4_pool params['PublicIpv4Pool'] = public_ipv4_pool
if check_mode: if check_mode:
params['DryRun'] = 'true' params['DryRun'] = 'true'
return ec2.get_object('AllocateAddress', params, Address, verb='POST') try:
result = ec2.allocate_address(aws_retry=True, **params)
except (botocore.exceptions.BotoCoreError, botocore.exceptions.ClientError) as e:
module.fail_json_aws(e, msg="Couldn't allocate Elastic IP address")
return result
def generate_tag_dict(module, tag_name, tag_value): def generate_tag_dict(module, tag_name, tag_value):
@ -487,7 +535,7 @@ def main():
public_ipv4_pool=dict() public_ipv4_pool=dict()
)) ))
module = AnsibleModule( module = AnsibleAWSModule(
argument_spec=argument_spec, argument_spec=argument_spec,
supports_check_mode=True, supports_check_mode=True,
required_by={ required_by={
@ -495,10 +543,7 @@ def main():
}, },
) )
if not HAS_BOTO: ec2 = module.client('ec2', retry_decorator=AWSRetry.jittered_backoff())
module.fail_json(msg='boto required for this module')
ec2 = ec2_connect(module)
device_id = module.params.get('device_id') device_id = module.params.get('device_id')
instance_id = module.params.get('instance_id') instance_id = module.params.get('instance_id')
@ -530,36 +575,59 @@ def main():
try: try:
if device_id: if device_id:
address = find_address(ec2, public_ip, device_id, is_instance=is_instance) address = find_address(ec2, module, public_ip, device_id, is_instance=is_instance)
else: else:
address = find_address(ec2, public_ip, None) address = find_address(ec2, module, public_ip, None)
if state == 'present': if state == 'present':
if device_id: if device_id:
result = ensure_present(ec2, module, domain, address, private_ip_address, device_id, result = ensure_present(
reuse_existing_ip_allowed, allow_reassociation, ec2, module, domain, address, private_ip_address, device_id,
module.check_mode, is_instance=is_instance) reuse_existing_ip_allowed, allow_reassociation,
module.check_mode, is_instance=is_instance
)
else: else:
if address: if address:
changed = False changed = False
else: else:
address, changed = allocate_address(ec2, domain, reuse_existing_ip_allowed, module.check_mode, tag_dict, public_ipv4_pool) address, changed = allocate_address(
result = {'changed': changed, 'public_ip': address.public_ip, 'allocation_id': address.allocation_id} ec2, module, domain, reuse_existing_ip_allowed,
module.check_mode, tag_dict, public_ipv4_pool
)
result = {
'changed': changed,
'public_ip': address['PublicIp'],
'allocation_id': address['AllocationId']
}
else: else:
if device_id: if device_id:
disassociated = ensure_absent(ec2, address, device_id, module.check_mode, is_instance=is_instance) disassociated = ensure_absent(
ec2, module, address, device_id, module.check_mode, is_instance=is_instance
)
if release_on_disassociation and disassociated['changed']: if release_on_disassociation and disassociated['changed']:
released = release_address(ec2, address, module.check_mode) released = release_address(ec2, module, address, module.check_mode)
result = {'changed': True, 'disassociated': disassociated, 'released': released} result = {
'changed': True,
'disassociated': disassociated,
'released': released
}
else: else:
result = {'changed': disassociated['changed'], 'disassociated': disassociated, 'released': {'changed': False}} result = {
'changed': disassociated['changed'],
'disassociated': disassociated,
'released': {'changed': False}
}
else: else:
released = release_address(ec2, address, module.check_mode) released = release_address(ec2, module, address, module.check_mode)
result = {'changed': released['changed'], 'disassociated': {'changed': False}, 'released': released} result = {
'changed': released['changed'],
'disassociated': {'changed': False},
'released': released
}
except (boto.exception.EC2ResponseError, EIPException) as e: except (botocore.exceptions.BotoCoreError, botocore.exceptions.ClientError) as e:
module.fail_json(msg=str(e)) module.fail_json_aws(str(e))
if instance_id: if instance_id:
result['warnings'] = warnings result['warnings'] = warnings

View file

@ -1,145 +1,144 @@
--- ---
- name: Integration testing for ec2_eip - name: Integration testing for ec2_eip
block: block:
- name: set up aws connection info
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
- name: set up aws connection info - name: Allocate a new eip - attempt reusing unallocated ones
set_fact: ec2_eip:
aws_connection_info: &aws_connection_info state: present
aws_access_key: "{{ aws_access_key }}" in_vpc: yes
aws_secret_key: "{{ aws_secret_key }}" reuse_existing_ip_allowed: yes
security_token: "{{ security_token }}" <<: *aws_connection_info
region: "{{ aws_region }}" register: eip
no_log: True
- name: Allocate a new eip - attempt reusing unallocated ones - assert:
ec2_eip: that:
state: present - eip is defined
in_vpc: yes - eip.public_ip is defined and eip.public_ip != ""
reuse_existing_ip_allowed: yes - eip.allocation_id is defined and eip.allocation_id != ""
<<: *aws_connection_info
register: eip
- assert: - name: Allocate a new eip
that: ec2_eip:
- eip is defined state: present
- eip.public_ip is defined and eip.public_ip != "" in_vpc: yes
- eip.allocation_id is defined and eip.allocation_id != "" <<: *aws_connection_info
register: new_eip
- name: Allocate a new eip - assert:
ec2_eip: that:
state: present - new_eip is defined
in_vpc: yes - new_eip is changed
<<: *aws_connection_info - new_eip.public_ip is defined and new_eip.public_ip != ""
register: new_eip - new_eip.allocation_id is defined and new_eip.allocation_id != ""
- assert: - name: Match an existing eip (changed == false)
that: ec2_eip:
- new_eip is defined state: present
- new_eip is changed in_vpc: yes
- new_eip.public_ip is defined and new_eip.public_ip != "" <<: *aws_connection_info
- new_eip.allocation_id is defined and new_eip.allocation_id != "" public_ip: "{{ eip.public_ip }}"
register: existing_eip
- name: Match an existing eip (changed == false) - assert:
ec2_eip: that:
state: present - existing_eip is defined
in_vpc: yes - existing_eip is not changed
<<: *aws_connection_info - existing_eip.public_ip is defined and existing_eip.public_ip != ""
public_ip: "{{ eip.public_ip }}" - existing_eip.allocation_id is defined and existing_eip.allocation_id != ""
register: existing_eip
- assert: - name: attempt reusing an existing eip with a tag (or allocate a new one)
that: ec2_eip:
- existing_eip is defined state: present
- existing_eip is not changed in_vpc: yes
- existing_eip.public_ip is defined and existing_eip.public_ip != "" <<: *aws_connection_info
- existing_eip.allocation_id is defined and existing_eip.allocation_id != "" reuse_existing_ip_allowed: yes
tag_name: Team
register: tagged_eip
- name: attempt reusing an existing eip with a tag (or allocate a new one) - assert:
ec2_eip: that:
state: present - tagged_eip is defined
in_vpc: yes - tagged_eip.public_ip is defined and tagged_eip.public_ip != ""
<<: *aws_connection_info - tagged_eip.allocation_id is defined and tagged_eip.allocation_id != ""
reuse_existing_ip_allowed: yes
tag_name: Team
register: tagged_eip
- assert: - name: attempt reusing an existing eip with a tag and it's value (or allocate a new one)
that: ec2_eip:
- tagged_eip is defined state: present
- tagged_eip.public_ip is defined and tagged_eip.public_ip != "" in_vpc: yes
- tagged_eip.allocation_id is defined and tagged_eip.allocation_id != "" <<: *aws_connection_info
public_ip: "{{ eip.public_ip }}"
reuse_existing_ip_allowed: yes
tag_name: Team
tag_value: Backend
register: backend_eip
- name: attempt reusing an existing eip with a tag and it's value (or allocate a new one) - assert:
ec2_eip: that:
state: present - backend_eip is defined
in_vpc: yes - backend_eip.public_ip is defined and backend_eip.public_ip != ""
<<: *aws_connection_info - backend_eip.allocation_id is defined and backend_eip.allocation_id != ""
public_ip: "{{ eip.public_ip }}"
reuse_existing_ip_allowed: yes
tag_name: Team
tag_value: Backend
register: backend_eip
- assert: - name: attempt reusing an existing eip with a tag and it's value (or allocate a new one from pool)
that: ec2_eip:
- backend_eip is defined state: present
- backend_eip.public_ip is defined and backend_eip.public_ip != "" in_vpc: yes
- backend_eip.allocation_id is defined and backend_eip.allocation_id != "" <<: *aws_connection_info
reuse_existing_ip_allowed: yes
tag_name: Team
tag_value: Backend
public_ipv4_pool: amazon
register: amazon_eip
- name: attempt reusing an existing eip with a tag and it's value (or allocate a new one from pool) - assert:
ec2_eip: that:
state: present - amazon_eip is defined
in_vpc: yes - amazon_eip.public_ip is defined and amazon_eip.public_ip != ""
<<: *aws_connection_info - amazon_eip.allocation_id is defined and amazon_eip.allocation_id != ""
reuse_existing_ip_allowed: yes
tag_name: Team
tag_value: Backend
public_ipv4_pool: amazon
register: amazon_eip
- assert: - name: allocate a new eip from a pool
that: ec2_eip:
- amazon_eip is defined state: present
- amazon_eip.public_ip is defined and amazon_eip.public_ip != "" in_vpc: yes
- amazon_eip.allocation_id is defined and amazon_eip.allocation_id != "" <<: *aws_connection_info
public_ipv4_pool: amazon
register: pool_eip
- name: allocate a new eip from a pool - assert:
ec2_eip: that:
state: present - pool_eip is defined
in_vpc: yes - pool_eip is changed
<<: *aws_connection_info - pool_eip.public_ip is defined and pool_eip.public_ip != ""
public_ipv4_pool: amazon - pool_eip.allocation_id is defined and pool_eip.allocation_id != ""
register: pool_eip always:
- debug:
- assert: msg: "{{ item }}"
that: when: item is defined and item.public_ip is defined and item.allocation_id is defined
- pool_eip is defined loop:
- pool_eip is changed - eip
- pool_eip.public_ip is defined and pool_eip.public_ip != "" - new_eip
- pool_eip.allocation_id is defined and pool_eip.allocation_id != "" - pool_eip
- tagged_eip
always: - backend_eip
- debug: msg="{{ item }}" - amazon_eip
when: item is defined and item.public_ip is defined and item.allocation_id is defined - name: Cleanup newly allocated eip
loop: ec2_eip:
- eip state: absent
- new_eip public_ip: "{{ item.public_ip }}"
- pool_eip in_vpc: yes
- tagged_eip <<: *aws_connection_info
- backend_eip when: item is defined and item is changed and item.public_ip is defined and item.public_ip != ""
- amazon_eip loop:
- name: Cleanup newly allocated eip - "{{ eip }}"
ec2_eip: - "{{ new_eip }}"
state: absent - "{{ pool_eip }}"
public_ip: "{{ item.public_ip }}" - "{{ tagged_eip }}"
in_vpc: yes - "{{ backend_eip }}"
<<: *aws_connection_info - "{{ amazon_eip }}"
when: item is defined and item is changed and item.public_ip is defined and item.public_ip != ""
loop:
- "{{ eip }}"
- "{{ new_eip }}"
- "{{ pool_eip }}"
- "{{ tagged_eip }}"
- "{{ backend_eip }}"
- "{{ amazon_eip }}"
... ...