Merge pull request #26267 from fictivekin/avoid_rate_limit_boto_route53

Allow (and default to) retries when Route53 changes are throttled by the AWS API
This commit is contained in:
Nicole Thomas 2015-08-14 09:53:19 -06:00
commit be10f2c7a3

View File

@ -61,6 +61,7 @@ try:
#pylint: disable=unused-import
import boto
import boto.route53
from boto.route53.exception import DNSServerError
#pylint: enable=unused-import
logging.getLogger('boto').setLevel(logging.CRITICAL)
HAS_BOTO = True
@ -99,7 +100,8 @@ def _get_split_zone(zone, _conn, private_zone):
return False
def zone_exists(zone, region=None, key=None, keyid=None, profile=None):
def zone_exists(zone, region=None, key=None, keyid=None, profile=None,
retry_on_rate_limit=True, rate_limit_retries=5):
'''
Check for the existence of a Route53 hosted zone.
@ -111,8 +113,19 @@ def zone_exists(zone, region=None, key=None, keyid=None, profile=None):
'''
conn = _get_conn(region=region, key=key, keyid=keyid, profile=profile)
while rate_limit_retries > 0:
try:
return bool(conn.get_zone(zone))
except DNSServerError as e:
# if rate limit, retry:
if retry_on_rate_limit and 'Throttling' == e.code:
log.debug('Throttled by AWS API.')
time.sleep(2)
rate_limit_retries -= 1
continue # the while True; try again if not out of retries
raise e
def create_zone(zone, private=False, vpc_id=None, vpc_region=None, region=None,
key=None, keyid=None, profile=None):
@ -166,7 +179,8 @@ def _decode_name(name):
def get_record(name, zone, record_type, fetch_all=False, region=None, key=None,
keyid=None, profile=None, split_dns=False, private_zone=False):
keyid=None, profile=None, split_dns=False, private_zone=False,
retry_on_rate_limit=True, rate_limit_retries=5):
'''
Get a record from a zone.
@ -176,6 +190,8 @@ def get_record(name, zone, record_type, fetch_all=False, region=None, key=None,
'''
conn = _get_conn(region=region, key=key, keyid=keyid, profile=profile)
while rate_limit_retries > 0:
try:
if split_dns:
_zone = _get_split_zone(zone, conn, private_zone)
else:
@ -197,6 +213,17 @@ def get_record(name, zone, record_type, fetch_all=False, region=None, key=None,
else:
_record = _zone.find_records(name, _type, all=fetch_all)
break # the while True
except DNSServerError as e:
# if rate limit, retry:
if retry_on_rate_limit and 'Throttling' == e.code:
log.debug('Throttled by AWS API.')
time.sleep(2)
rate_limit_retries -= 1
continue # the while True; try again if not out of retries
raise e
if _record:
ret['name'] = _decode_name(_record.name)
ret['value'] = _record.to_print()
@ -208,7 +235,8 @@ def get_record(name, zone, record_type, fetch_all=False, region=None, key=None,
def add_record(name, value, zone, record_type, identifier=None, ttl=None,
region=None, key=None, keyid=None, profile=None,
wait_for_sync=True, split_dns=False, private_zone=False):
wait_for_sync=True, split_dns=False, private_zone=False,
retry_on_rate_limit=True, rate_limit_retries=5):
'''
Add a record to a zone.
@ -218,6 +246,8 @@ def add_record(name, value, zone, record_type, identifier=None, ttl=None,
'''
conn = _get_conn(region=region, key=key, keyid=keyid, profile=profile)
while rate_limit_retries > 0:
try:
if split_dns:
_zone = _get_split_zone(zone, conn, private_zone)
else:
@ -227,7 +257,19 @@ def add_record(name, value, zone, record_type, identifier=None, ttl=None,
log.error(msg)
return False
_type = record_type.upper()
break
except DNSServerError as e:
# if rate limit, retry:
if retry_on_rate_limit and 'Throttling' == e.code:
log.debug('Throttled by AWS API.')
time.sleep(2)
rate_limit_retries -= 1
continue # the while True; try again if not out of retries
raise e
while rate_limit_retries > 0:
try:
if _type == 'A':
status = _zone.add_a(name, value, ttl, identifier)
return _wait_for_sync(status.id, conn, wait_for_sync)
@ -244,10 +286,20 @@ def add_record(name, value, zone, record_type, identifier=None, ttl=None,
status = _zone.add_record(_type, name, value, ttl, identifier)
return _wait_for_sync(status.id, conn, wait_for_sync)
except DNSServerError as e:
# if rate limit, retry:
if retry_on_rate_limit and 'Throttling' == e.code:
log.debug('Throttled by AWS API.')
time.sleep(2)
rate_limit_retries -= 1
continue # the while True; try again if not out of retries
raise e
def update_record(name, value, zone, record_type, identifier=None, ttl=None,
region=None, key=None, keyid=None, profile=None,
wait_for_sync=True, split_dns=False, private_zone=False):
wait_for_sync=True, split_dns=False, private_zone=False,
retry_on_rate_limit=True, rate_limit_retries=5):
'''
Modify a record in a zone.
@ -267,6 +319,8 @@ def update_record(name, value, zone, record_type, identifier=None, ttl=None,
return False
_type = record_type.upper()
while rate_limit_retries > 0:
try:
if _type == 'A':
status = _zone.update_a(name, value, ttl, identifier)
return _wait_for_sync(status.id, conn, wait_for_sync)
@ -283,10 +337,20 @@ def update_record(name, value, zone, record_type, identifier=None, ttl=None,
status = _zone.update_record(old_record, value, ttl, identifier)
return _wait_for_sync(status.id, conn, wait_for_sync)
except DNSServerError as e:
# if rate limit, retry:
if retry_on_rate_limit and 'Throttling' == e.code:
log.debug('Throttled by AWS API.')
time.sleep(2)
rate_limit_retries -= 1
continue # the while True; try again if not out of retries
raise e
def delete_record(name, zone, record_type, identifier=None, all_records=False,
region=None, key=None, keyid=None, profile=None,
wait_for_sync=True, split_dns=False, private_zone=False):
wait_for_sync=True, split_dns=False, private_zone=False,
retry_on_rate_limit=True, rate_limit_retries=5):
'''
Modify a record in a zone.
@ -306,6 +370,8 @@ def delete_record(name, zone, record_type, identifier=None, all_records=False,
return False
_type = record_type.upper()
while rate_limit_retries > 0:
try:
if _type == 'A':
status = _zone.delete_a(name, identifier, all_records)
return _wait_for_sync(status.id, conn, wait_for_sync)
@ -322,6 +388,15 @@ def delete_record(name, zone, record_type, identifier=None, all_records=False,
status = _zone.delete_record(old_record)
return _wait_for_sync(status.id, conn, wait_for_sync)
except DNSServerError as e:
# if rate limit, retry:
if retry_on_rate_limit and 'Throttling' == e.code:
log.debug('Throttled by AWS API.')
time.sleep(2)
rate_limit_retries -= 1
continue # the while True; try again if not out of retries
raise e
def _wait_for_sync(status, conn, wait_for_sync):
if not wait_for_sync: