From 6d8edfc35ff469fbc39c52a0b5ec391aa290ae4a Mon Sep 17 00:00:00 2001 From: Robin Miller Date: Tue, 7 Mar 2017 10:27:50 -0600 Subject: [PATCH] Handle throttling and move BotoServerError handling to main. (#22383) Unclear how useful it is to still be catching BotoServerError exceptions generally, especially when we are now hopefully handling most instances of throttling, but kept it as it was already in the code. Moved to main as catching BotoServerErrors inside individual functions will bypass any AWSRetry.backoff decorator. Move additional imports to top. Use python2.6 formatting A bit of cleanup on imports Make one more string interpolation Python 2.6 compatible. --- .../modules/cloud/amazon/ec2_elb_facts.py | 69 ++++++++++--------- 1 file changed, 36 insertions(+), 33 deletions(-) diff --git a/lib/ansible/modules/cloud/amazon/ec2_elb_facts.py b/lib/ansible/modules/cloud/amazon/ec2_elb_facts.py index 5c075372f08..71688fb3392 100644 --- a/lib/ansible/modules/cloud/amazon/ec2_elb_facts.py +++ b/lib/ansible/modules/cloud/amazon/ec2_elb_facts.py @@ -80,6 +80,14 @@ EXAMPLES = ''' import traceback +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.ec2 import ( + AWSRetry, + connect_to_aws, + ec2_argument_spec, + get_aws_connection_info, +) + try: import boto.ec2.elb from boto.ec2.tag import Tag @@ -88,8 +96,9 @@ try: except ImportError: HAS_BOTO = False + class ElbInformation(object): - """ Handles ELB information """ + """Handles ELB information.""" def __init__(self, module, @@ -105,17 +114,12 @@ class ElbInformation(object): def _get_tags(self, elbname): params = {'LoadBalancerNames.member.1': elbname} - try: - elb_tags = self.connection.get_list('DescribeTags', params, [('member', Tag)]) - return dict((tag.Key, tag.Value) for tag in elb_tags if hasattr(tag, 'Key')) - except: - return {} + elb_tags = self.connection.get_list('DescribeTags', params, [('member', Tag)]) + return dict((tag.Key, tag.Value) for tag in elb_tags if hasattr(tag, 'Key')) + @AWSRetry.backoff(tries=5, delay=5, backoff=2.0) def _get_elb_connection(self): - try: - return connect_to_aws(boto.ec2.elb, self.region, **self.aws_connect_params) - except BotoServerError as err: - self.module.fail_json(msg=err.message) + return connect_to_aws(boto.ec2.elb, self.region, **self.aws_connect_params) def _get_elb_listeners(self, listeners): listener_list = [] @@ -143,7 +147,7 @@ class ElbInformation(object): protocol, port_path = health_check.target.split(':') try: port, path = port_path.split('/', 1) - path = '/{}'.format(path) + path = '/{0}'.format(path) except ValueError: port = port_path path = None @@ -161,6 +165,7 @@ class ElbInformation(object): health_check_dict['ping_path'] = path return health_check_dict + @AWSRetry.backoff(tries=5, delay=5, backoff=2.0) def _get_elb_info(self, elb): elb_info = { 'name': elb.name, @@ -188,10 +193,7 @@ class ElbInformation(object): elb_info['vpc_id'] = elb.vpc_id if elb.instances: - try: - instance_health = self.connection.describe_instance_health(elb.name) - except BotoServerError as err: - self.module.fail_json(msg=err.message) + instance_health = self.connection.describe_instance_health(elb.name) elb_info['instances_inservice'] = [inst.instance_id for inst in instance_health if inst.state == 'InService'] elb_info['instances_inservice_count'] = len(elb_info['instances_inservice']) elb_info['instances_outofservice'] = [inst.instance_id for inst in instance_health if inst.state == 'OutOfService'] @@ -210,12 +212,8 @@ class ElbInformation(object): elb_array, token = [], None while True: - try: - all_elbs = self.connection.get_all_load_balancers(marker=token) - token = all_elbs.next_token - except BotoServerError as err: - self.module.fail_json(msg = "%s: %s" % (err.error_code, err.error_message), - exception=traceback.format_exc()) + all_elbs = AWSRetry.backoff(tries=5, delay=5, backoff=2.0)(self.connection.get_all_load_balancers)(marker=token) + token = all_elbs.next_token if all_elbs: if self.names: @@ -232,6 +230,7 @@ class ElbInformation(object): return list(map(self._get_elb_info, elb_array)) + def main(): argument_spec = ec2_argument_spec() argument_spec.update(dict( @@ -244,24 +243,28 @@ def main(): if not HAS_BOTO: module.fail_json(msg='boto required for this module') - region, ec2_url, aws_connect_params = get_aws_connection_info(module) + try: + + region, ec2_url, aws_connect_params = get_aws_connection_info(module) + + if not region: + module.fail_json(msg="region must be specified") - if not region: - module.fail_json(msg="region must be specified") + names = module.params['names'] + elb_information = ElbInformation(module, + names, + region, + **aws_connect_params) - names = module.params['names'] - elb_information = ElbInformation(module, - names, - region, - **aws_connect_params) + ec2_facts_result = dict(changed=False, + elbs=elb_information.list_elbs()) - ec2_facts_result = dict(changed=False, - elbs=elb_information.list_elbs()) + except BotoServerError as err: + self.module.fail_json(msg="{0}: {1}".format(err.error_code, err.error_message), + exception=traceback.format_exc()) module.exit_json(**ec2_facts_result) -from ansible.module_utils.basic import * -from ansible.module_utils.ec2 import * if __name__ == '__main__': main()