mirror of
https://github.com/github/octodns.git
synced 2024-05-11 05:55:00 +00:00
Merge pull request #819 from octodns/route53-dynamic-status-support
Add value status support to Route53 dynamic
This commit is contained in:
@@ -80,9 +80,11 @@ class _Route53Record(EqualityTupleMixin):
|
||||
# be served out according to their weights
|
||||
for i, value in enumerate(pool.data['values']):
|
||||
weight = value['weight']
|
||||
status = value['status']
|
||||
value = value['value']
|
||||
ret.add(_Route53DynamicValue(provider, record, pool_name,
|
||||
value, weight, i, creating))
|
||||
value, weight, status, i,
|
||||
creating))
|
||||
|
||||
# Rules
|
||||
for i, rule in enumerate(record.dynamic.rules):
|
||||
@@ -345,19 +347,21 @@ class _Route53DynamicRule(_Route53Record):
|
||||
|
||||
class _Route53DynamicValue(_Route53Record):
|
||||
|
||||
def __init__(self, provider, record, pool_name, value, weight, index,
|
||||
creating):
|
||||
def __init__(self, provider, record, pool_name, value, weight, status,
|
||||
index, creating):
|
||||
fqdn_override = f'_octodns-{pool_name}-value.{record.fqdn}'
|
||||
super(_Route53DynamicValue, self).__init__(provider, record, creating,
|
||||
fqdn_override=fqdn_override)
|
||||
|
||||
self.pool_name = pool_name
|
||||
self.status = status
|
||||
self.index = index
|
||||
value_convert = getattr(self, f'_value_convert_{record._type}')
|
||||
self.value = value_convert(value, record)
|
||||
self.weight = weight
|
||||
|
||||
self.health_check_id = provider.get_health_check_id(record, self.value,
|
||||
self.status,
|
||||
creating)
|
||||
|
||||
@property
|
||||
@@ -379,10 +383,9 @@ class _Route53DynamicValue(_Route53Record):
|
||||
'ResourceRecordSet': existing,
|
||||
}
|
||||
|
||||
return {
|
||||
ret = {
|
||||
'Action': action,
|
||||
'ResourceRecordSet': {
|
||||
'HealthCheckId': self.health_check_id,
|
||||
'Name': self.fqdn,
|
||||
'ResourceRecords': [{'Value': self.value}],
|
||||
'SetIdentifier': self.identifer,
|
||||
@@ -392,6 +395,11 @@ class _Route53DynamicValue(_Route53Record):
|
||||
}
|
||||
}
|
||||
|
||||
if self.health_check_id:
|
||||
ret['ResourceRecordSet']['HealthCheckId'] = self.health_check_id
|
||||
|
||||
return ret
|
||||
|
||||
def __hash__(self):
|
||||
return f'{self.fqdn}:{self._type}:{self.identifer}'.__hash__()
|
||||
|
||||
@@ -433,7 +441,7 @@ class _Route53GeoRecord(_Route53Record):
|
||||
|
||||
value = geo.values[0]
|
||||
self.health_check_id = provider.get_health_check_id(record, value,
|
||||
creating)
|
||||
'obey', creating)
|
||||
|
||||
def mod(self, action, existing_rrsets):
|
||||
geo = self.geo
|
||||
@@ -599,6 +607,7 @@ class Route53Provider(BaseProvider):
|
||||
'''
|
||||
SUPPORTS_GEO = True
|
||||
SUPPORTS_DYNAMIC = True
|
||||
SUPPORTS_POOL_VALUE_STATUS = True
|
||||
SUPPORTS = set(('A', 'AAAA', 'CAA', 'CNAME', 'MX', 'NAPTR', 'NS', 'PTR',
|
||||
'SPF', 'SRV', 'TXT'))
|
||||
|
||||
@@ -914,7 +923,22 @@ class Route53Provider(BaseProvider):
|
||||
# it's ignored only used to make sure the value is unique
|
||||
pool_name = rrset['SetIdentifier'][:-4]
|
||||
value = rrset['ResourceRecords'][0]['Value']
|
||||
try:
|
||||
health_check_id = rrset.get('HealthCheckId', None)
|
||||
health_check = self.health_checks[health_check_id]
|
||||
health_check_config = health_check['HealthCheckConfig']
|
||||
if health_check_config['Disabled'] and \
|
||||
health_check_config['Inverted']:
|
||||
# disabled and inverted means down
|
||||
status = 'down'
|
||||
else:
|
||||
# otherwise obey
|
||||
status = 'obey'
|
||||
except KeyError:
|
||||
# No healthcheck means status is up
|
||||
status = 'up'
|
||||
pools[pool_name]['values'].append({
|
||||
'status': status,
|
||||
'value': value,
|
||||
'weight': rrset['Weight'],
|
||||
})
|
||||
@@ -1092,7 +1116,8 @@ class Route53Provider(BaseProvider):
|
||||
|
||||
def _health_check_equivalent(self, host, path, protocol, port,
|
||||
measure_latency, request_interval,
|
||||
health_check, value=None):
|
||||
health_check, value=None, disabled=None,
|
||||
inverted=None):
|
||||
config = health_check['HealthCheckConfig']
|
||||
|
||||
# So interestingly Route53 normalizes IPv6 addresses to a funky, but
|
||||
@@ -1115,16 +1140,23 @@ class Route53Provider(BaseProvider):
|
||||
port == config['Port'] and \
|
||||
measure_latency == config['MeasureLatency'] and \
|
||||
request_interval == config['RequestInterval'] and \
|
||||
(disabled is None or disabled == config['Disabled']) and \
|
||||
(inverted is None or inverted == config['Inverted']) and \
|
||||
value == config_ip_address
|
||||
|
||||
def get_health_check_id(self, record, value, create):
|
||||
def get_health_check_id(self, record, value, status, create):
|
||||
# fqdn & the first value are special, we use them to match up health
|
||||
# checks to their records. Route53 health checks check a single ip and
|
||||
# we're going to assume that ips are interchangeable to avoid
|
||||
# health-checking each one independently
|
||||
fqdn = record.fqdn
|
||||
self.log.debug('get_health_check_id: fqdn=%s, type=%s, value=%s',
|
||||
fqdn, record._type, value)
|
||||
self.log.debug('get_health_check_id: fqdn=%s, type=%s, value=%s, '
|
||||
'status=%s', fqdn, record._type, value, status)
|
||||
|
||||
if status == 'up':
|
||||
# status up means no health check
|
||||
self.log.debug('get_health_check_id: status up, no health check')
|
||||
return None
|
||||
|
||||
try:
|
||||
ip_address(str(value))
|
||||
@@ -1140,6 +1172,12 @@ class Route53Provider(BaseProvider):
|
||||
healthcheck_port = record.healthcheck_port
|
||||
healthcheck_latency = self._healthcheck_measure_latency(record)
|
||||
healthcheck_interval = self._healthcheck_request_interval(record)
|
||||
if status == 'down':
|
||||
healthcheck_disabled = True
|
||||
healthcheck_inverted = True
|
||||
else: # obey
|
||||
healthcheck_disabled = False
|
||||
healthcheck_inverted = False
|
||||
|
||||
# we're looking for a healthcheck with the current version & our record
|
||||
# type, we'll ignore anything else
|
||||
@@ -1156,7 +1194,9 @@ class Route53Provider(BaseProvider):
|
||||
healthcheck_latency,
|
||||
healthcheck_interval,
|
||||
health_check,
|
||||
value=value):
|
||||
value=value,
|
||||
disabled=healthcheck_disabled,
|
||||
inverted=healthcheck_inverted):
|
||||
# this is the health check we're looking for
|
||||
self.log.debug('get_health_check_id: found match id=%s', id)
|
||||
return id
|
||||
@@ -1168,6 +1208,8 @@ class Route53Provider(BaseProvider):
|
||||
|
||||
# no existing matches, we need to create a new health check
|
||||
config = {
|
||||
'Disabled': healthcheck_disabled,
|
||||
'Inverted': healthcheck_inverted,
|
||||
'EnableSNI': healthcheck_protocol == 'HTTPS',
|
||||
'FailureThreshold': 6,
|
||||
'MeasureLatency': healthcheck_latency,
|
||||
@@ -1296,10 +1338,11 @@ class Route53Provider(BaseProvider):
|
||||
self._gc_health_checks(change.existing, [])
|
||||
return self._gen_mods('DELETE', existing_records, existing_rrsets)
|
||||
|
||||
def _extra_changes_update_needed(self, record, rrset):
|
||||
def _extra_changes_update_needed(self, record, rrset, statuses={}):
|
||||
value = rrset['ResourceRecords'][0]['Value']
|
||||
if record._type == 'CNAME':
|
||||
# For CNAME, healthcheck host by default points to the CNAME value
|
||||
healthcheck_host = rrset['ResourceRecords'][0]['Value']
|
||||
healthcheck_host = value
|
||||
else:
|
||||
healthcheck_host = record.healthcheck_host()
|
||||
|
||||
@@ -1309,6 +1352,17 @@ class Route53Provider(BaseProvider):
|
||||
healthcheck_latency = self._healthcheck_measure_latency(record)
|
||||
healthcheck_interval = self._healthcheck_request_interval(record)
|
||||
|
||||
status = statuses.get(value, 'obey')
|
||||
if status == 'up':
|
||||
if 'HealthCheckId' in rrset:
|
||||
self.log.info('_extra_changes_update_needed: health-check '
|
||||
'found for status="up", causing update of %s:%s',
|
||||
record.fqdn, record._type)
|
||||
return True
|
||||
else:
|
||||
# No health check needed
|
||||
return False
|
||||
|
||||
try:
|
||||
health_check_id = rrset['HealthCheckId']
|
||||
health_check = self.health_checks[health_check_id]
|
||||
@@ -1364,6 +1418,12 @@ class Route53Provider(BaseProvider):
|
||||
fqdn = record.fqdn
|
||||
_type = record._type
|
||||
|
||||
# map values to statuses
|
||||
statuses = {}
|
||||
for pool in record.dynamic.pools.values():
|
||||
for value in pool.data['values']:
|
||||
statuses[value['value']] = value.get('status', 'obey')
|
||||
|
||||
# loop through all the r53 rrsets
|
||||
for rrset in self._load_records(zone_id):
|
||||
name = rrset['Name']
|
||||
@@ -1382,7 +1442,7 @@ class Route53Provider(BaseProvider):
|
||||
# rrset isn't for the current record
|
||||
continue
|
||||
|
||||
if self._extra_changes_update_needed(record, rrset):
|
||||
if self._extra_changes_update_needed(record, rrset, statuses):
|
||||
# no good, doesn't have the right health check, needs an update
|
||||
self.log.info('_extra_changes_dynamic_needs_update: '
|
||||
'health-check caused update of %s:%s',
|
||||
|
||||
@@ -58,7 +58,6 @@ dynamic_rrsets = [{
|
||||
'Type': 'A',
|
||||
'Weight': 2
|
||||
}, {
|
||||
'HealthCheckId': '09',
|
||||
'Name': '_octodns-ap-southeast-1-value.unit.tests.',
|
||||
'ResourceRecords': [{'Value': '1.4.1.2'}],
|
||||
'SetIdentifier': 'ap-southeast-1-001',
|
||||
@@ -192,6 +191,20 @@ dynamic_rrsets = [{
|
||||
'SetIdentifier': '3-us-east-1-None',
|
||||
'Type': 'A',
|
||||
}]
|
||||
dynamic_health_checks = {
|
||||
'76': {
|
||||
'HealthCheckConfig': {
|
||||
'Disabled': False,
|
||||
'Inverted': False,
|
||||
}
|
||||
},
|
||||
'ab': {
|
||||
'HealthCheckConfig': {
|
||||
'Disabled': True,
|
||||
'Inverted': True,
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
dynamic_record_data = {
|
||||
'dynamic': {
|
||||
@@ -199,24 +212,24 @@ dynamic_record_data = {
|
||||
'ap-southeast-1': {
|
||||
'fallback': 'us-east-1',
|
||||
'values': [{
|
||||
'weight': 2, 'value': '1.4.1.1'
|
||||
'weight': 2, 'value': '1.4.1.1', 'status': 'obey',
|
||||
}, {
|
||||
'weight': 2, 'value': '1.4.1.2'
|
||||
'weight': 2, 'value': '1.4.1.2', 'status': 'up',
|
||||
}]
|
||||
},
|
||||
'eu-central-1': {
|
||||
'fallback': 'us-east-1',
|
||||
'values': [{
|
||||
'weight': 1, 'value': '1.3.1.1'
|
||||
'weight': 1, 'value': '1.3.1.1', 'status': 'down',
|
||||
}, {
|
||||
'weight': 1, 'value': '1.3.1.2'
|
||||
'weight': 1, 'value': '1.3.1.2', 'status': 'up',
|
||||
}],
|
||||
},
|
||||
'us-east-1': {
|
||||
'values': [{
|
||||
'weight': 1, 'value': '1.5.1.1'
|
||||
'weight': 1, 'value': '1.5.1.1', 'status': 'up',
|
||||
}, {
|
||||
'weight': 1, 'value': '1.5.1.2'
|
||||
'weight': 1, 'value': '1.5.1.2', 'status': 'up',
|
||||
}],
|
||||
}
|
||||
},
|
||||
@@ -296,6 +309,9 @@ class TestRoute53Provider(TestCase):
|
||||
'Id': '42',
|
||||
'CallerReference': caller_ref,
|
||||
'HealthCheckConfig': {
|
||||
'Disabled': False,
|
||||
'EnableSNI': True,
|
||||
'Inverted': False,
|
||||
'Type': 'HTTPS',
|
||||
'FullyQualifiedDomainName': 'unit.tests',
|
||||
'IPAddress': '4.2.3.4',
|
||||
@@ -310,6 +326,9 @@ class TestRoute53Provider(TestCase):
|
||||
'Id': 'ignored-also',
|
||||
'CallerReference': 'something-else',
|
||||
'HealthCheckConfig': {
|
||||
'Disabled': False,
|
||||
'EnableSNI': True,
|
||||
'Inverted': False,
|
||||
'Type': 'HTTPS',
|
||||
'FullyQualifiedDomainName': 'unit.tests',
|
||||
'IPAddress': '5.2.3.4',
|
||||
@@ -324,6 +343,9 @@ class TestRoute53Provider(TestCase):
|
||||
'Id': '43',
|
||||
'CallerReference': caller_ref,
|
||||
'HealthCheckConfig': {
|
||||
'Disabled': False,
|
||||
'EnableSNI': True,
|
||||
'Inverted': False,
|
||||
'Type': 'HTTPS',
|
||||
'FullyQualifiedDomainName': 'unit.tests',
|
||||
'IPAddress': '5.2.3.4',
|
||||
@@ -338,6 +360,9 @@ class TestRoute53Provider(TestCase):
|
||||
'Id': '44',
|
||||
'CallerReference': caller_ref,
|
||||
'HealthCheckConfig': {
|
||||
'Disabled': False,
|
||||
'EnableSNI': True,
|
||||
'Inverted': False,
|
||||
'Type': 'HTTPS',
|
||||
'FullyQualifiedDomainName': 'unit.tests',
|
||||
'IPAddress': '7.2.3.4',
|
||||
@@ -353,6 +378,9 @@ class TestRoute53Provider(TestCase):
|
||||
# won't match anything based on type
|
||||
'CallerReference': caller_ref.replace(':A:', ':AAAA:'),
|
||||
'HealthCheckConfig': {
|
||||
'Disabled': False,
|
||||
'EnableSNI': True,
|
||||
'Inverted': False,
|
||||
'Type': 'HTTPS',
|
||||
'FullyQualifiedDomainName': 'unit.tests',
|
||||
'IPAddress': '7.2.3.4',
|
||||
@@ -1161,6 +1189,9 @@ class TestRoute53Provider(TestCase):
|
||||
'Id': '42',
|
||||
'CallerReference': self.caller_ref,
|
||||
'HealthCheckConfig': {
|
||||
'Disabled': False,
|
||||
'EnableSNI': True,
|
||||
'Inverted': False,
|
||||
'Type': 'HTTPS',
|
||||
'FullyQualifiedDomainName': 'unit.tests',
|
||||
'IPAddress': '4.2.3.4',
|
||||
@@ -1175,6 +1206,9 @@ class TestRoute53Provider(TestCase):
|
||||
'Id': '43',
|
||||
'CallerReference': 'abc123',
|
||||
'HealthCheckConfig': {
|
||||
'Disabled': False,
|
||||
'EnableSNI': True,
|
||||
'Inverted': False,
|
||||
'Type': 'HTTPS',
|
||||
'FullyQualifiedDomainName': 'unit.tests',
|
||||
'IPAddress': '9.2.3.4',
|
||||
@@ -1199,6 +1233,9 @@ class TestRoute53Provider(TestCase):
|
||||
'Id': '44',
|
||||
'CallerReference': self.caller_ref,
|
||||
'HealthCheckConfig': {
|
||||
'Disabled': False,
|
||||
'EnableSNI': True,
|
||||
'Inverted': False,
|
||||
'Type': 'HTTPS',
|
||||
'FullyQualifiedDomainName': 'unit.tests',
|
||||
'IPAddress': '8.2.3.4',
|
||||
@@ -1235,9 +1272,109 @@ class TestRoute53Provider(TestCase):
|
||||
}
|
||||
})
|
||||
value = record.geo['AF'].values[0]
|
||||
id = provider.get_health_check_id(record, value, True)
|
||||
id = provider.get_health_check_id(record, value, 'obey', True)
|
||||
self.assertEquals('42', id)
|
||||
|
||||
def test_health_check_status_support(self):
|
||||
provider, stubber = self._get_stubbed_provider()
|
||||
|
||||
health_checks = [{
|
||||
'Id': '42',
|
||||
'CallerReference': self.caller_ref,
|
||||
'HealthCheckConfig': {
|
||||
'Disabled': False,
|
||||
'EnableSNI': True,
|
||||
'Inverted': False,
|
||||
'Type': 'HTTPS',
|
||||
'FullyQualifiedDomainName': 'unit.tests',
|
||||
'IPAddress': '1.1.1.1',
|
||||
'ResourcePath': '/_dns',
|
||||
'Type': 'HTTPS',
|
||||
'Port': 443,
|
||||
'MeasureLatency': True,
|
||||
'RequestInterval': 10,
|
||||
},
|
||||
'HealthCheckVersion': 2,
|
||||
}, {
|
||||
'Id': '43',
|
||||
'CallerReference': self.caller_ref,
|
||||
'HealthCheckConfig': {
|
||||
'Disabled': True,
|
||||
'EnableSNI': True,
|
||||
'Inverted': False,
|
||||
'Type': 'HTTPS',
|
||||
'FullyQualifiedDomainName': 'unit.tests',
|
||||
'IPAddress': '2.2.2.2',
|
||||
'ResourcePath': '/_dns',
|
||||
'Type': 'HTTPS',
|
||||
'Port': 443,
|
||||
'MeasureLatency': True,
|
||||
'RequestInterval': 10,
|
||||
},
|
||||
'HealthCheckVersion': 2,
|
||||
}, {
|
||||
'Id': '44',
|
||||
'CallerReference': self.caller_ref,
|
||||
'HealthCheckConfig': {
|
||||
'Disabled': True,
|
||||
'EnableSNI': True,
|
||||
'Inverted': True,
|
||||
'Type': 'HTTPS',
|
||||
'FullyQualifiedDomainName': 'unit.tests',
|
||||
'IPAddress': '3.3.3.3',
|
||||
'ResourcePath': '/_dns',
|
||||
'Type': 'HTTPS',
|
||||
'Port': 443,
|
||||
'MeasureLatency': True,
|
||||
'RequestInterval': 10,
|
||||
},
|
||||
'HealthCheckVersion': 2,
|
||||
}]
|
||||
stubber.add_response('list_health_checks',
|
||||
{
|
||||
'HealthChecks': health_checks,
|
||||
'IsTruncated': False,
|
||||
'MaxItems': '20',
|
||||
'Marker': '',
|
||||
})
|
||||
|
||||
health_checks = provider.health_checks
|
||||
|
||||
# get without create
|
||||
record = Record.new(self.expected, '', {
|
||||
'ttl': 61,
|
||||
'type': 'A',
|
||||
'value': '5.5.5.5',
|
||||
'dynamic': {
|
||||
'pools': {
|
||||
'main': {
|
||||
'values': [{
|
||||
'value': '6.6.6.6',
|
||||
}]
|
||||
}
|
||||
},
|
||||
'rules': [{
|
||||
'pool': 'main',
|
||||
}]
|
||||
}
|
||||
})
|
||||
self.assertEquals('42',
|
||||
provider.get_health_check_id(record, '1.1.1.1',
|
||||
'obey', False))
|
||||
self.assertEquals(None,
|
||||
provider.get_health_check_id(record, '2.2.2.2',
|
||||
'up', False))
|
||||
self.assertEquals('44',
|
||||
provider.get_health_check_id(record, '3.3.3.3',
|
||||
'down', False))
|
||||
|
||||
# If we're not allowed to create we won't find a health check for
|
||||
# 1.1.1.1 with status up or down
|
||||
self.assertFalse(provider.get_health_check_id(record, '1.1.1.1',
|
||||
'up', False))
|
||||
self.assertFalse(provider.get_health_check_id(record, '1.1.1.1',
|
||||
'down', False))
|
||||
|
||||
def test_health_check_create(self):
|
||||
provider, stubber = self._get_stubbed_provider()
|
||||
|
||||
@@ -1248,6 +1385,9 @@ class TestRoute53Provider(TestCase):
|
||||
# No match based on version
|
||||
'CallerReference': '9999:A:foo1234',
|
||||
'HealthCheckConfig': {
|
||||
'Disabled': False,
|
||||
'EnableSNI': True,
|
||||
'Inverted': False,
|
||||
'Type': 'HTTPS',
|
||||
'FullyQualifiedDomainName': 'unit.tests',
|
||||
'IPAddress': '4.2.3.4',
|
||||
@@ -1262,6 +1402,9 @@ class TestRoute53Provider(TestCase):
|
||||
'Id': '43',
|
||||
'CallerReference': caller_ref,
|
||||
'HealthCheckConfig': {
|
||||
'Disabled': False,
|
||||
'EnableSNI': True,
|
||||
'Inverted': False,
|
||||
'Type': 'HTTPS',
|
||||
'FullyQualifiedDomainName': 'unit.tests',
|
||||
'IPAddress': '4.2.3.4',
|
||||
@@ -1281,7 +1424,9 @@ class TestRoute53Provider(TestCase):
|
||||
})
|
||||
|
||||
health_check_config = {
|
||||
'Disabled': False,
|
||||
'EnableSNI': False,
|
||||
'Inverted': False,
|
||||
'FailureThreshold': 6,
|
||||
'FullyQualifiedDomainName': 'foo.bar.com',
|
||||
'IPAddress': '4.2.3.4',
|
||||
@@ -1306,7 +1451,9 @@ class TestRoute53Provider(TestCase):
|
||||
stubber.add_response('change_tags_for_resource', {})
|
||||
|
||||
health_check_config = {
|
||||
'Disabled': False,
|
||||
'EnableSNI': False,
|
||||
'Inverted': False,
|
||||
'FailureThreshold': 6,
|
||||
'FullyQualifiedDomainName': '4.2.3.4',
|
||||
'IPAddress': '4.2.3.4',
|
||||
@@ -1349,23 +1496,25 @@ class TestRoute53Provider(TestCase):
|
||||
|
||||
# if not allowed to create returns none
|
||||
value = record.geo['AF'].values[0]
|
||||
id = provider.get_health_check_id(record, value, False)
|
||||
id = provider.get_health_check_id(record, value, 'obey', False)
|
||||
self.assertFalse(id)
|
||||
|
||||
# when allowed to create we do
|
||||
id = provider.get_health_check_id(record, value, True)
|
||||
id = provider.get_health_check_id(record, value, 'obey', True)
|
||||
self.assertEquals('42', id)
|
||||
|
||||
# when allowed to create and when host is None
|
||||
record._octodns['healthcheck']['host'] = None
|
||||
id = provider.get_health_check_id(record, value, True)
|
||||
id = provider.get_health_check_id(record, value, 'obey', True)
|
||||
self.assertEquals('43', id)
|
||||
stubber.assert_no_pending_responses()
|
||||
|
||||
# A CNAME style healthcheck, without a value
|
||||
|
||||
health_check_config = {
|
||||
'Disabled': False,
|
||||
'EnableSNI': False,
|
||||
'Inverted': False,
|
||||
'FailureThreshold': 6,
|
||||
'FullyQualifiedDomainName': 'target-1.unit.tests.',
|
||||
'MeasureLatency': True,
|
||||
@@ -1388,14 +1537,17 @@ class TestRoute53Provider(TestCase):
|
||||
})
|
||||
stubber.add_response('change_tags_for_resource', {})
|
||||
|
||||
id = provider.get_health_check_id(record, 'target-1.unit.tests.', True)
|
||||
id = provider.get_health_check_id(record, 'target-1.unit.tests.',
|
||||
'obey', True)
|
||||
self.assertEquals('42', id)
|
||||
stubber.assert_no_pending_responses()
|
||||
|
||||
# TCP health check
|
||||
|
||||
health_check_config = {
|
||||
'Disabled': False,
|
||||
'EnableSNI': False,
|
||||
'Inverted': False,
|
||||
'FailureThreshold': 6,
|
||||
'MeasureLatency': True,
|
||||
'Port': 8080,
|
||||
@@ -1417,7 +1569,8 @@ class TestRoute53Provider(TestCase):
|
||||
stubber.add_response('change_tags_for_resource', {})
|
||||
|
||||
record._octodns['healthcheck']['protocol'] = 'TCP'
|
||||
id = provider.get_health_check_id(record, 'target-1.unit.tests.', True)
|
||||
id = provider.get_health_check_id(record, 'target-1.unit.tests.',
|
||||
'obey', True)
|
||||
self.assertEquals('42', id)
|
||||
stubber.assert_no_pending_responses()
|
||||
|
||||
@@ -1494,7 +1647,9 @@ class TestRoute53Provider(TestCase):
|
||||
provider, stubber = self._get_stubbed_provider()
|
||||
|
||||
health_check_config = {
|
||||
'Disabled': False,
|
||||
'EnableSNI': True,
|
||||
'Inverted': False,
|
||||
'FailureThreshold': 6,
|
||||
'FullyQualifiedDomainName': 'a.unit.tests',
|
||||
'IPAddress': '1.2.3.4',
|
||||
@@ -1547,7 +1702,7 @@ class TestRoute53Provider(TestCase):
|
||||
})
|
||||
|
||||
value = record.geo['AF'].values[0]
|
||||
id = provider.get_health_check_id(record, value, True)
|
||||
id = provider.get_health_check_id(record, value, 'obey', True)
|
||||
ml = provider.health_checks[id]['HealthCheckConfig']['MeasureLatency']
|
||||
ri = provider.health_checks[id]['HealthCheckConfig']['RequestInterval']
|
||||
self.assertFalse(ml)
|
||||
@@ -1636,6 +1791,9 @@ class TestRoute53Provider(TestCase):
|
||||
'Id': '42',
|
||||
'CallerReference': self.caller_ref,
|
||||
'HealthCheckConfig': {
|
||||
'Disabled': False,
|
||||
'EnableSNI': True,
|
||||
'Inverted': False,
|
||||
'Type': 'HTTPS',
|
||||
'FullyQualifiedDomainName': 'unit.tests',
|
||||
'IPAddress': '4.2.3.4',
|
||||
@@ -1650,6 +1808,9 @@ class TestRoute53Provider(TestCase):
|
||||
'Id': '43',
|
||||
'CallerReference': old_caller_ref,
|
||||
'HealthCheckConfig': {
|
||||
'Disabled': False,
|
||||
'EnableSNI': True,
|
||||
'Inverted': False,
|
||||
'Type': 'HTTPS',
|
||||
'FullyQualifiedDomainName': 'unit.tests',
|
||||
'IPAddress': '4.2.3.4',
|
||||
@@ -1664,6 +1825,9 @@ class TestRoute53Provider(TestCase):
|
||||
'Id': '44',
|
||||
'CallerReference': old_caller_ref,
|
||||
'HealthCheckConfig': {
|
||||
'Disabled': False,
|
||||
'EnableSNI': True,
|
||||
'Inverted': False,
|
||||
'Type': 'HTTPS',
|
||||
'FullyQualifiedDomainName': 'other.unit.tests',
|
||||
'IPAddress': '4.2.3.4',
|
||||
@@ -2105,6 +2269,9 @@ class TestRoute53Provider(TestCase):
|
||||
'Id': '42',
|
||||
'CallerReference': 'foo',
|
||||
'HealthCheckConfig': {
|
||||
'Disabled': False,
|
||||
'EnableSNI': True,
|
||||
'Inverted': False,
|
||||
'Type': 'HTTPS',
|
||||
'FullyQualifiedDomainName': 'unit.tests',
|
||||
'IPAddress': '2.2.3.4',
|
||||
@@ -2210,6 +2377,9 @@ class TestRoute53Provider(TestCase):
|
||||
'Id': '42',
|
||||
'CallerReference': self.caller_ref,
|
||||
'HealthCheckConfig': {
|
||||
'Disabled': False,
|
||||
'EnableSNI': True,
|
||||
'Inverted': False,
|
||||
'Type': 'HTTPS',
|
||||
'FullyQualifiedDomainName': 'a.unit.tests',
|
||||
'IPAddress': '2.2.3.4',
|
||||
@@ -2359,6 +2529,9 @@ class TestRoute53Provider(TestCase):
|
||||
'Id': '42',
|
||||
'CallerReference': self.caller_ref,
|
||||
'HealthCheckConfig': {
|
||||
'Disabled': False,
|
||||
'EnableSNI': True,
|
||||
'Inverted': False,
|
||||
'Type': 'HTTPS',
|
||||
'FullyQualifiedDomainName': 'a.unit.tests',
|
||||
'IPAddress': '2.2.3.4',
|
||||
@@ -2394,6 +2567,48 @@ class TestRoute53Provider(TestCase):
|
||||
self.assertEquals(1, len(extra))
|
||||
stubber.assert_no_pending_responses()
|
||||
|
||||
def test_extra_change_dyamic_status_up(self):
|
||||
provider, stubber = self._get_stubbed_provider()
|
||||
|
||||
zone = Zone('unit.tests.', [])
|
||||
record = Record.new(zone, 'a', {
|
||||
'ttl': 30,
|
||||
'type': 'A',
|
||||
'value': '1.1.1.1',
|
||||
'dynamic': {
|
||||
'pools': {
|
||||
'one': {
|
||||
'values': [{
|
||||
'status': 'up',
|
||||
'value': '1.2.3.4',
|
||||
}],
|
||||
},
|
||||
},
|
||||
'rules': [{
|
||||
'pool': 'one',
|
||||
}],
|
||||
},
|
||||
})
|
||||
|
||||
# status up and no health check so we're good
|
||||
rrset = {
|
||||
'ResourceRecords': [{'Value': '1.2.3.4'}],
|
||||
}
|
||||
statuses = {'1.2.3.4': 'up'}
|
||||
self.assertFalse(
|
||||
provider._extra_changes_update_needed(record, rrset, statuses)
|
||||
)
|
||||
|
||||
# status up and has a health check so update needed
|
||||
rrset = {
|
||||
'ResourceRecords': [{'Value': '1.2.3.4'}],
|
||||
'HealthCheckId': 'foo',
|
||||
}
|
||||
statuses = {'1.2.3.4': 'up'}
|
||||
self.assertTrue(
|
||||
provider._extra_changes_update_needed(record, rrset, statuses)
|
||||
)
|
||||
|
||||
def test_extra_change_dynamic_has_health_check_cname(self):
|
||||
provider, stubber = self._get_stubbed_provider()
|
||||
|
||||
@@ -2517,6 +2732,9 @@ class TestRoute53Provider(TestCase):
|
||||
'Id': '42',
|
||||
'CallerReference': self.caller_ref,
|
||||
'HealthCheckConfig': {
|
||||
'Disabled': False,
|
||||
'EnableSNI': True,
|
||||
'Inverted': False,
|
||||
'Type': 'HTTPS',
|
||||
'FullyQualifiedDomainName': 'one.cname.unit.tests.',
|
||||
'ResourcePath': '/_dns',
|
||||
@@ -2695,6 +2913,7 @@ class TestRoute53Provider(TestCase):
|
||||
|
||||
def test_data_for_dynamic(self):
|
||||
provider = Route53Provider('test', 'abc', '123')
|
||||
provider._health_checks = dynamic_health_checks
|
||||
|
||||
data = provider._data_for_dynamic('', 'A', dynamic_rrsets)
|
||||
self.assertEquals(dynamic_record_data, data)
|
||||
@@ -2703,6 +2922,7 @@ class TestRoute53Provider(TestCase):
|
||||
@patch('octodns.provider.route53.Route53Provider._load_records')
|
||||
def test_dynamic_populate(self, load_records_mock, get_zone_id_mock):
|
||||
provider = Route53Provider('test', 'abc', '123')
|
||||
provider._health_checks = {}
|
||||
|
||||
get_zone_id_mock.side_effect = ['z44']
|
||||
load_records_mock.side_effect = [dynamic_rrsets]
|
||||
@@ -2724,25 +2944,25 @@ class TestRoute53Provider(TestCase):
|
||||
'ap-southeast-1': {
|
||||
'fallback': 'us-east-1',
|
||||
'values': [{
|
||||
'weight': 2, 'value': '1.4.1.1', 'status': 'obey',
|
||||
'weight': 2, 'value': '1.4.1.1', 'status': 'up',
|
||||
}, {
|
||||
'weight': 2, 'value': '1.4.1.2', 'status': 'obey',
|
||||
'weight': 2, 'value': '1.4.1.2', 'status': 'up',
|
||||
}]
|
||||
},
|
||||
'eu-central-1': {
|
||||
'fallback': 'us-east-1',
|
||||
'values': [{
|
||||
'weight': 1, 'value': '1.3.1.1', 'status': 'obey',
|
||||
'weight': 1, 'value': '1.3.1.1', 'status': 'up',
|
||||
}, {
|
||||
'weight': 1, 'value': '1.3.1.2', 'status': 'obey',
|
||||
'weight': 1, 'value': '1.3.1.2', 'status': 'up',
|
||||
}],
|
||||
},
|
||||
'us-east-1': {
|
||||
'fallback': None,
|
||||
'values': [{
|
||||
'weight': 1, 'value': '1.5.1.1', 'status': 'obey',
|
||||
'weight': 1, 'value': '1.5.1.1', 'status': 'up',
|
||||
}, {
|
||||
'weight': 1, 'value': '1.5.1.2', 'status': 'obey',
|
||||
'weight': 1, 'value': '1.5.1.2', 'status': 'up',
|
||||
}],
|
||||
}
|
||||
}, {k: v.data for k, v in record.dynamic.pools.items()})
|
||||
@@ -2905,7 +3125,7 @@ class TestRoute53Records(TestCase):
|
||||
def test_dynamic_value_delete(self):
|
||||
provider = DummyProvider()
|
||||
geo = _Route53DynamicValue(provider, self.record_a, 'iad', '2.2.2.2',
|
||||
1, 0, False)
|
||||
1, 'obey', 0, False)
|
||||
|
||||
rrset = {
|
||||
'HealthCheckId': 'x12346z',
|
||||
@@ -2944,7 +3164,7 @@ class TestRoute53Records(TestCase):
|
||||
|
||||
# If we don't provide the candidate rrsets we get back exactly what we
|
||||
# put in minus the healthcheck
|
||||
rrset['HealthCheckId'] = None
|
||||
del rrset['HealthCheckId']
|
||||
mod = geo.mod('DELETE', [])
|
||||
self.assertEquals(rrset, mod['ResourceRecordSet'])
|
||||
|
||||
@@ -3008,7 +3228,7 @@ class TestRoute53Records(TestCase):
|
||||
# thoroughly tested elsewhere
|
||||
provider._health_checks = {}
|
||||
# When asked for a healthcheck return dummy info
|
||||
provider.get_health_check_id = lambda r, v, c: 'hc42'
|
||||
provider.get_health_check_id = lambda r, v, s, c: 'hc42'
|
||||
|
||||
zone = Zone('unit.tests.', [])
|
||||
record = Record.new(zone, '', dynamic_record_data)
|
||||
|
||||
Reference in New Issue
Block a user