Proposing a wait_for function to ensure elb has been successfully removed

This commit is contained in:
Etherdaemon 2015-11-25 20:36:07 +10:00 committed by Matt Clay
parent bddcf737c9
commit cd3f306518

View file

@ -107,7 +107,6 @@ options:
description: description:
- Wait a specified timeout allowing connections to drain before terminating an instance - Wait a specified timeout allowing connections to drain before terminating an instance
required: false required: false
default: "None"
aliases: [] aliases: []
version_added: "1.8" version_added: "1.8"
idle_timeout: idle_timeout:
@ -128,6 +127,14 @@ options:
- An associative array of stickness policy settings. Policy will be applied to all listeners ( see example ) - An associative array of stickness policy settings. Policy will be applied to all listeners ( see example )
required: false required: false
version_added: "2.0" version_added: "2.0"
wait_for:
description:
- When specified, Ansible will check the status of the load balancer to ensure it has been successfully
removed from AWS.
required: false
default: no
choices: ["yes", "no"]
version_added: 2.0
extends_documentation_fragment: aws extends_documentation_fragment: aws
""" """
@ -201,6 +208,13 @@ EXAMPLES = """
name: "test-please-delete" name: "test-please-delete"
state: absent state: absent
# Ensure ELB is gone and wait for check
- local_action:
module: ec2_elb_lb
name: "test-please-delete"
state: absent
wait_for: yes
# Normally, this module will purge any listeners that exist on the ELB # Normally, this module will purge any listeners that exist on the ELB
# but aren't specified in the listeners parameter. If purge_listeners is # but aren't specified in the listeners parameter. If purge_listeners is
# false it leaves them alone # false it leaves them alone
@ -321,8 +335,9 @@ class ElbManager(object):
zones=None, purge_zones=None, security_group_ids=None, zones=None, purge_zones=None, security_group_ids=None,
health_check=None, subnets=None, purge_subnets=None, health_check=None, subnets=None, purge_subnets=None,
scheme="internet-facing", connection_draining_timeout=None, scheme="internet-facing", connection_draining_timeout=None,
idle_timeout, cross_az_load_balancing=None, access_logs=None, idle_timeout=None,
stickiness=None, region=None, **aws_connect_params): cross_az_load_balancing=None, access_logs=None,
stickiness=None, wait_for=None, region=None, **aws_connect_params):
self.module = module self.module = module
self.name = name self.name = name
@ -340,6 +355,7 @@ class ElbManager(object):
self.cross_az_load_balancing = cross_az_load_balancing self.cross_az_load_balancing = cross_az_load_balancing
self.access_logs = access_logs self.access_logs = access_logs
self.stickiness = stickiness self.stickiness = stickiness
self.wait_for = wait_for
self.aws_connect_params = aws_connect_params self.aws_connect_params = aws_connect_params
self.region = region self.region = region
@ -348,6 +364,7 @@ class ElbManager(object):
self.status = 'gone' self.status = 'gone'
self.elb_conn = self._get_elb_connection() self.elb_conn = self._get_elb_connection()
self.elb = self._get_elb() self.elb = self._get_elb()
self.ec2_conn = self._get_ec2_connection()
def ensure_ok(self): def ensure_ok(self):
"""Create the ELB""" """Create the ELB"""
@ -378,6 +395,14 @@ class ElbManager(object):
"""Destroy the ELB""" """Destroy the ELB"""
if self.elb: if self.elb:
self._delete_elb() self._delete_elb()
if self.wait_for:
elb_removed = self._wait_for_elb_removed()
# Unfortunately even though the ELB itself is removed quickly
# the interfaces take longer so reliant security groups cannot
# be deleted until the interface has registered as removed.
elb_interface_removed = self._wait_for_elb_interface_removed()
if not (elb_removed and elb_interface_removed):
self.module.fail_json(msg='Timed out waiting for removal of load balancer.')
def get_info(self): def get_info(self):
try: try:
@ -478,6 +503,50 @@ class ElbManager(object):
return info return info
def _wait_for_elb_removed(self):
polling_increment_secs = 30
max_retries = 10
status_achieved = False
for x in range(0, max_retries):
try:
result = self.elb_conn.get_all_lb_attributes(self.name)
except (boto.exception.BotoServerError, StandardError), e:
if "LoadBalancerNotFound" in e.code:
status_achieved = True
break
else:
time.sleep(polling_increment_secs)
return status_achieved
def _wait_for_elb_interface_removed(self):
polling_increment_secs = 30
max_retries = 10
status_achieved = False
elb_interfaces = self.ec2_conn.get_all_network_interfaces(
filters={'attachment.instance-owner-id': 'amazon-elb',
'description': 'ELB {0}'.format(self.name) })
for x in range(0, max_retries):
for interface in elb_interfaces:
try:
result = self.ec2_conn.get_all_network_interfaces(interface.id)
if result == []:
status_achieved = True
break
else:
time.sleep(polling_increment_secs)
except (boto.exception.BotoServerError, StandardError), e:
if 'InvalidNetworkInterfaceID' in e.code:
status_achieved = True
break
else:
self.module.fail_json(msg=str(e))
return status_achieved
def _get_elb(self): def _get_elb(self):
elbs = self.elb_conn.get_all_load_balancers() elbs = self.elb_conn.get_all_load_balancers()
for elb in elbs: for elb in elbs:
@ -492,6 +561,13 @@ class ElbManager(object):
except (boto.exception.NoAuthHandlerFound, AnsibleAWSError), e: except (boto.exception.NoAuthHandlerFound, AnsibleAWSError), e:
self.module.fail_json(msg=str(e)) self.module.fail_json(msg=str(e))
def _get_ec2_connection(self):
try:
return connect_to_aws(boto.ec2, self.region,
**self.aws_connect_params)
except (boto.exception.NoAuthHandlerFound, StandardError), e:
self.module.fail_json(msg=str(e))
def _delete_elb(self): def _delete_elb(self):
# True if succeeds, exception raised if not # True if succeeds, exception raised if not
result = self.elb_conn.delete_load_balancer(name=self.name) result = self.elb_conn.delete_load_balancer(name=self.name)
@ -893,7 +969,8 @@ def main():
idle_timeout={'default': None, 'required': False}, idle_timeout={'default': None, 'required': False},
cross_az_load_balancing={'default': None, 'required': False}, cross_az_load_balancing={'default': None, 'required': False},
stickiness={'default': None, 'required': False, 'type': 'dict'}, stickiness={'default': None, 'required': False, 'type': 'dict'},
access_logs={'default': None, 'required': False, 'type': 'dict'} access_logs={'default': None, 'required': False, 'type': 'dict'},
wait_for={'default': False, 'type': 'bool', 'required': False}
) )
) )
@ -926,6 +1003,7 @@ def main():
idle_timeout = module.params['idle_timeout'] idle_timeout = module.params['idle_timeout']
cross_az_load_balancing = module.params['cross_az_load_balancing'] cross_az_load_balancing = module.params['cross_az_load_balancing']
stickiness = module.params['stickiness'] stickiness = module.params['stickiness']
wait_for = module.params['wait_for']
if state == 'present' and not listeners: if state == 'present' and not listeners:
module.fail_json(msg="At least one port is required for ELB creation") module.fail_json(msg="At least one port is required for ELB creation")
@ -952,7 +1030,8 @@ def main():
purge_zones, security_group_ids, health_check, purge_zones, security_group_ids, health_check,
subnets, purge_subnets, scheme, subnets, purge_subnets, scheme,
connection_draining_timeout, idle_timeout, connection_draining_timeout, idle_timeout,
cross_az_load_balancing, access_logs, stickiness, cross_az_load_balancing,
access_logs, stickiness, wait_for,
region=region, **aws_connect_params) region=region, **aws_connect_params)
# check for unsupported attributes for this version of boto # check for unsupported attributes for this version of boto