diff options
author | Brian Coca <bcoca@ansible.com> | 2015-05-08 15:24:20 -0400 |
---|---|---|
committer | Brian Coca <bcoca@ansible.com> | 2015-05-08 15:24:20 -0400 |
commit | bc22ee90692fba2865681686df5ee31d3fef9aac (patch) | |
tree | d192079824b438faa3362e3f093d19b4eeb591e6 | |
parent | 8b4e201772cf94e738bdabae0b4e6b68759cdd85 (diff) | |
parent | 6ce3ef36e3d2ac93441f73ddc84823c54ba1d4aa (diff) | |
download | ansible-modules-core-bc22ee90692fba2865681686df5ee31d3fef9aac.tar.gz |
Merge pull request #1015 from jml/ec2-eip
Make ec2_eip idempotent
-rw-r--r-- | cloud/amazon/ec2_eip.py | 59 |
1 files changed, 46 insertions, 13 deletions
diff --git a/cloud/amazon/ec2_eip.py b/cloud/amazon/ec2_eip.py index 5f84ff24..7258ea04 100644 --- a/cloud/amazon/ec2_eip.py +++ b/cloud/amazon/ec2_eip.py @@ -74,6 +74,9 @@ EXAMPLES = ''' - name: output the IP debug: msg="Allocated IP is {{ eip.public_ip }}" +- name: another way of allocating an elastic IP without associating it to anything + ec2_eip: state='present' + - name: provision new instances with ec2 ec2: keypair=mykey instance_type=c1.medium image=ami-40603AD1 wait=yes group=webserver count=3 register: ec2 @@ -94,7 +97,6 @@ try: except ImportError: HAS_BOTO = False - wait_timeout = 0 def associate_ip_and_instance(ec2, address, instance_id, module): @@ -141,7 +143,7 @@ def disassociate_ip_and_instance(ec2, address, instance_id, module): module.fail_json(msg="disassociation failed") -def find_address(ec2, public_ip, module): +def find_address(ec2, public_ip, module, fail_on_not_found=True): """ Find an existing Elastic IP address """ if wait_timeout != 0: timeout = time.time() + wait_timeout @@ -151,7 +153,8 @@ def find_address(ec2, public_ip, module): break except boto.exception.EC2ResponseError, e: if "Address '%s' not found." % public_ip in e.message : - pass + if not fail_on_not_found: + return None else: module.fail_json(msg=str(e.message)) time.sleep(5) @@ -162,6 +165,9 @@ def find_address(ec2, public_ip, module): try: addresses = ec2.get_all_addresses([public_ip]) except boto.exception.EC2ResponseError, e: + if "Address '%s' not found." % public_ip in e.message : + if not fail_on_not_found: + return None module.fail_json(msg=str(e.message)) return addresses[0] @@ -175,6 +181,16 @@ def ip_is_associated_with_instance(ec2, public_ip, instance_id, module): else: return False +def instance_is_associated(ec2, instance, module): + """ + Check if the given instance object is already associated with an + elastic IP + """ + instance_ip = instance.ip_address + if not instance_ip: + return False + eip = find_address(ec2, instance_ip, module, fail_on_not_found=False) + return (eip and (eip.public_ip == instance_ip)) def allocate_address(ec2, domain, module, reuse_existing_ip_allowed): """ Allocate a new elastic IP address (when needed) and return it """ @@ -189,7 +205,7 @@ def allocate_address(ec2, domain, module, reuse_existing_ip_allowed): domain_filter = { 'domain' : 'standard' } all_addresses = ec2.get_all_addresses(filters=domain_filter) - unassociated_addresses = filter(lambda a: a.instance_id == "", all_addresses) + unassociated_addresses = filter(lambda a: not a.instance_id, all_addresses) if unassociated_addresses: address = unassociated_addresses[0]; else: @@ -232,6 +248,15 @@ def find_instance(ec2, instance_id, module): module.fail_json(msg="could not find instance" + instance_id) +def allocate_eip(ec2, eip_domain, module, reuse_existing_ip_allowed, new_eip_timeout): + # Allocate a new elastic IP + address = allocate_address(ec2, eip_domain, module, reuse_existing_ip_allowed) + # overriding the timeout since this is a a newly provisioned ip + global wait_timeout + wait_timeout = new_eip_timeout + return address + + def main(): argument_spec = ec2_argument_spec() argument_spec.update(dict( @@ -264,24 +289,32 @@ def main(): new_eip_timeout = int(module.params.get('wait_timeout')) if state == 'present': - # Allocate an EIP and exit - if not instance_id and not public_ip: - address = allocate_address(ec2, domain, module, reuse_existing_ip_allowed) + # If both instance_id and public_ip are not specified, allocate a new + # elastic IP, and exit. + if not instance_id and not public_ip: + address = allocate_eip(ec2, domain, module, + reuse_existing_ip_allowed, new_eip_timeout) module.exit_json(changed=True, public_ip=address.public_ip) # Return the EIP object since we've been given a public IP if public_ip: address = find_address(ec2, public_ip, module) - # Allocate an IP for instance since no public_ip was provided - if instance_id and not public_ip: + if instance_id and not public_ip: instance = find_instance(ec2, instance_id, module) + if instance.vpc_id: domain = "vpc" - address = allocate_address(ec2, domain, module, reuse_existing_ip_allowed) - # overriding the timeout since this is a a newly provisioned ip - global wait_timeout - wait_timeout = new_eip_timeout + + # Do nothing if the instance is already associated with an + # elastic IP. + if instance_is_associated(ec2, instance, module): + module.exit_json(changed=False, public_ip=instance.ip_address) + + # If the instance is not already associated with an elastic IP, + # allocate a new one. + address = allocate_eip( + ec2, domain, module, reuse_existing_ip_allowed, new_eip_timeout) # Associate address object (provided or allocated) with instance associate_ip_and_instance(ec2, address, instance_id, module) |