diff --git a/octodns/provider/route53.py b/octodns/provider/route53.py index a6a3105..3359f3e 100644 --- a/octodns/provider/route53.py +++ b/octodns/provider/route53.py @@ -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', diff --git a/tests/test_octodns_provider_route53.py b/tests/test_octodns_provider_route53.py index 56362a0..680c9ce 100644 --- a/tests/test_octodns_provider_route53.py +++ b/tests/test_octodns_provider_route53.py @@ -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)