From a64ec99de8e4d92ad2bbd0288ceb846ad4e8a988 Mon Sep 17 00:00:00 2001 From: Pavan Chandrashekar Date: Sat, 4 Apr 2020 01:28:39 -0700 Subject: [PATCH 1/3] Support reuse of default pool in rules in Ns1Provider --- octodns/provider/ns1.py | 125 +++++++++++++++++++---------- tests/test_octodns_provider_ns1.py | 42 +++++++++- 2 files changed, 122 insertions(+), 45 deletions(-) diff --git a/octodns/provider/ns1.py b/octodns/provider/ns1.py index 7e13b28..c9a2874 100644 --- a/octodns/provider/ns1.py +++ b/octodns/provider/ns1.py @@ -468,8 +468,12 @@ class Ns1Provider(BaseProvider): pools = defaultdict(lambda: {'fallback': None, 'values': []}) for answer in record['answers']: # region (group name in the UI) is the pool name + # Shadow pools are a mechanism internal to this provider + # Skip them when constructing octoDNS records from ns1 records pool_name = answer['region'] - pool = pools[answer['region']] + if pool_name.endswith('_shadow'): + continue + pool = pools[pool_name] meta = answer['meta'] value = text_type(answer['answer'][0]) @@ -492,6 +496,11 @@ class Ns1Provider(BaseProvider): # examples currently where it would rules = [] for pool_name, region in sorted(record['regions'].items()): + # Rules that refer to the default dynamic pool would have + # used the shadow pool name. Convert it back to the dynamic + # default pool name by stripping the '_shadow' in the pool name + if pool_name.endswith('_shadow'): + pool_name = pool_name[:-7] meta = region['meta'] notes = self._parse_notes(meta.get('note', '')) @@ -935,6 +944,49 @@ class Ns1Provider(BaseProvider): notify_list_id = monitor['notify_list'] self._client.notifylists_delete(notify_list_id) + def _add_answers_for_pool(self, answers, default_answers, pool_name, + pool_label, pool_answers, pools, priority): + current_pool_name = pool_name + seen = set() + while current_pool_name and current_pool_name not in seen: + seen.add(current_pool_name) + pool = pools[current_pool_name] + for answer in pool_answers[current_pool_name]: + answer = { + 'answer': answer['answer'], + 'meta': { + 'priority': priority, + 'note': self._encode_notes({ + 'from': pool_label, + }), + 'up': { + 'feed': answer['feed_id'], + }, + 'weight': answer['weight'], + }, + 'region': pool_label, # the one we're answering + } + answers.append(answer) + + current_pool_name = pool.data.get('fallback', None) + priority += 1 + + # Static/default + for answer in default_answers: + answer = { + 'answer': answer['answer'], + 'meta': { + 'priority': priority, + 'note': self._encode_notes({ + 'from': '--default--', + }), + 'up': True, + 'weight': 1, + }, + 'region': pool_label, # the one we're answering + } + answers.append(answer) + def _params_for_dynamic_A(self, record): pools = record.dynamic.pools @@ -942,6 +994,16 @@ class Ns1Provider(BaseProvider): has_country = False has_region = False regions = {} + needs_shadow = False + + # Get dynamic default pool name + # It is a pool that has no 'geos' associated with it + dynamic_default_pool_name = None + for i, rule in enumerate(record.dynamic.rules): + pool_name = rule.data['pool'] + if not rule.data.get('geos', []): + dynamic_default_pool_name = pool_name + for i, rule in enumerate(record.dynamic.rules): pool_name = rule.data['pool'] @@ -958,7 +1020,15 @@ class Ns1Provider(BaseProvider): us_state = set() for geo in rule.data.get('geos', []): - + # regions dictionary below is indexed by pool names. If there + # is reuse of a pool name in the rules, the earlier one gets + # overwritten. Reuse of pool names is disallowed but for an + # exception in the case of the dynamic default pool. So, when + # the dynamic default pool name is reused elsewhere, use + # the shadow pool name for the dynamic default pool + if pool_name == dynamic_default_pool_name: + pool_name = '{}_{}'.format(pool_name, 'shadow') + needs_shadow = True n = len(geo) if n == 8: # US state, e.g. NA-US-KY @@ -1029,46 +1099,17 @@ class Ns1Provider(BaseProvider): priority = 1 # Dynamic/health checked - current_pool_name = pool_name - seen = set() - while current_pool_name and current_pool_name not in seen: - seen.add(current_pool_name) - pool = pools[current_pool_name] - for answer in pool_answers[current_pool_name]: - answer = { - 'answer': answer['answer'], - 'meta': { - 'priority': priority, - 'note': self._encode_notes({ - 'from': current_pool_name, - }), - 'up': { - 'feed': answer['feed_id'], - }, - 'weight': answer['weight'], - }, - 'region': pool_name, # the one we're answering - } - answers.append(answer) - - current_pool_name = pool.data.get('fallback', None) - priority += 1 - - # Static/default - for answer in default_answers: - answer = { - 'answer': answer['answer'], - 'meta': { - 'priority': priority, - 'note': self._encode_notes({ - 'from': '--default--', - }), - 'up': True, - 'weight': 1, - }, - 'region': pool_name, # the one we're answering - } - answers.append(answer) + self._add_answers_for_pool(answers, default_answers, pool_name, + pool_name, pool_answers, pools, + priority) + if pool_name == dynamic_default_pool_name and needs_shadow: + # If it is the dynamic default pool, add a shadow pool. + # This will be used in regions when there are rules that refer + # to the dynamic default pool + shadow_pn = '{}_{}'.format(pool_name, 'shadow') + self._add_answers_for_pool(answers, default_answers, pool_name, + shadow_pn, pool_answers, pools, + priority) # Update filters as necessary filters = self._get_updated_filter_chain(has_region, has_country) diff --git a/tests/test_octodns_provider_ns1.py b/tests/test_octodns_provider_ns1.py index fb177c8..ac672aa 100644 --- a/tests/test_octodns_provider_ns1.py +++ b/tests/test_octodns_provider_ns1.py @@ -552,6 +552,11 @@ class TestNs1ProviderDynamic(TestCase): 'NA-US-FL' ], 'pool': 'lhr', + }, { + 'geos': [ + 'AF-ZW', + ], + 'pool': 'iad', }, { 'pool': 'iad', }], @@ -961,13 +966,17 @@ class TestNs1ProviderDynamic(TestCase): ] rule0 = self.record.data['dynamic']['rules'][0] - saved_geos = rule0['geos'] + rule1 = self.record.data['dynamic']['rules'][1] + rule0_saved_geos = rule0['geos'] + rule1_saved_geos = rule1['geos'] rule0['geos'] = ['AF', 'EU'] + rule1['geos'] = ['NA'] ret, _ = provider._params_for_A(self.record) self.assertEquals(ret['filters'], Ns1Provider._FILTER_CHAIN_WITH_REGION(provider, True)) - rule0['geos'] = saved_geos + rule0['geos'] = rule0_saved_geos + rule1['geos'] = rule1_saved_geos @patch('octodns.provider.ns1.Ns1Provider._monitor_sync') @patch('octodns.provider.ns1.Ns1Provider._monitors_for') @@ -1123,6 +1132,21 @@ class TestNs1ProviderDynamic(TestCase): 'note': 'from:--default--', }, 'region': 'iad', + }, { + 'answer': ['2.3.4.5'], + 'meta': { + 'priority': 1, + 'weight': 12, + 'note': 'from:iad_shadow', + }, + 'region': 'iad_shadow', + }, { + 'answer': ['1.2.3.4'], + 'meta': { + 'priority': 2, + 'note': 'from:--default--', + }, + 'region': 'iad_shadow', }], 'domain': 'unit.tests', 'filters': filters, @@ -1135,9 +1159,15 @@ class TestNs1ProviderDynamic(TestCase): 'us_state': ['OR'], }, }, - 'iad': { + 'iad_shadow': { 'meta': { 'note': 'rule-order:2', + 'country': ['ZW'], + }, + }, + 'iad': { + 'meta': { + 'note': 'rule-order:3', }, } }, @@ -1173,6 +1203,12 @@ class TestNs1ProviderDynamic(TestCase): 'pool': 'lhr', }, { '_order': '2', + 'geos': [ + 'AF-ZW', + ], + 'pool': 'iad', + }, { + '_order': '3', 'pool': 'iad', }], }, From 4c21cfd85b59ac46e1254cb9f167e5b3f1d51c19 Mon Sep 17 00:00:00 2001 From: Pavan Chandrashekar Date: Fri, 10 Apr 2020 11:06:19 -0700 Subject: [PATCH 2/3] Address review comments. Introduce catchall poolname --- octodns/provider/ns1.py | 97 +++++++++++++++++------------- tests/test_octodns_provider_ns1.py | 43 ++++++++++--- 2 files changed, 92 insertions(+), 48 deletions(-) diff --git a/octodns/provider/ns1.py b/octodns/provider/ns1.py index c9a2874..0566710 100644 --- a/octodns/provider/ns1.py +++ b/octodns/provider/ns1.py @@ -237,6 +237,7 @@ class Ns1Provider(BaseProvider): 'NS', 'PTR', 'SPF', 'SRV', 'TXT')) ZONE_NOT_FOUND_MESSAGE = 'server error: zone not found' + CATCHALL_PREFIX = 'catchall_' def _update_filter(self, filter, with_disabled): if with_disabled: @@ -468,21 +469,26 @@ class Ns1Provider(BaseProvider): pools = defaultdict(lambda: {'fallback': None, 'values': []}) for answer in record['answers']: # region (group name in the UI) is the pool name - # Shadow pools are a mechanism internal to this provider - # Skip them when constructing octoDNS records from ns1 records pool_name = answer['region'] - if pool_name.endswith('_shadow'): - continue + # Get the actual pool name from the constructed pool name in case + # of the catchall + if pool_name.startswith(self.CATCHALL_PREFIX): + pool_name = pool_name[len(self.CATCHALL_PREFIX):] pool = pools[pool_name] meta = answer['meta'] value = text_type(answer['answer'][0]) if meta['priority'] == 1: # priority 1 means this answer is part of the pools own values - pool['values'].append({ + value_dict = { 'value': value, 'weight': int(meta.get('weight', 1)), - }) + } + # If we have the original pool name and the catchall pool name + # in the answers, they point at the same pool. Add values only + # once + if value_dict not in pool['values']: + pool['values'].append(value_dict) else: # It's a fallback, we only care about it if it's a # final/default @@ -496,11 +502,11 @@ class Ns1Provider(BaseProvider): # examples currently where it would rules = [] for pool_name, region in sorted(record['regions'].items()): - # Rules that refer to the default dynamic pool would have - # used the shadow pool name. Convert it back to the dynamic - # default pool name by stripping the '_shadow' in the pool name - if pool_name.endswith('_shadow'): - pool_name = pool_name[:-7] + # Rules that refer to the catchall pool would have the + # CATCHALL_PREFIX in the pool name. Strip the prefix to get back + # the pool name as in the config + if pool_name.startswith(self.CATCHALL_PREFIX): + pool_name = pool_name[len(self.CATCHALL_PREFIX):] meta = region['meta'] notes = self._parse_notes(meta.get('note', '')) @@ -994,18 +1000,12 @@ class Ns1Provider(BaseProvider): has_country = False has_region = False regions = {} - needs_shadow = False - - # Get dynamic default pool name - # It is a pool that has no 'geos' associated with it - dynamic_default_pool_name = None - for i, rule in enumerate(record.dynamic.rules): - pool_name = rule.data['pool'] - if not rule.data.get('geos', []): - dynamic_default_pool_name = pool_name + catchall_pool_name = None + pool_usage = defaultdict(lambda: 0) for i, rule in enumerate(record.dynamic.rules): pool_name = rule.data['pool'] + pool_usage[pool_name] += 1 notes = { 'rule-order': i, @@ -1020,15 +1020,6 @@ class Ns1Provider(BaseProvider): us_state = set() for geo in rule.data.get('geos', []): - # regions dictionary below is indexed by pool names. If there - # is reuse of a pool name in the rules, the earlier one gets - # overwritten. Reuse of pool names is disallowed but for an - # exception in the case of the dynamic default pool. So, when - # the dynamic default pool name is reused elsewhere, use - # the shadow pool name for the dynamic default pool - if pool_name == dynamic_default_pool_name: - pool_name = '{}_{}'.format(pool_name, 'shadow') - needs_shadow = True n = len(geo) if n == 8: # US state, e.g. NA-US-KY @@ -1064,9 +1055,25 @@ class Ns1Provider(BaseProvider): if us_state: meta['us_state'] = sorted(us_state) - regions[pool_name] = { - 'meta': meta, - } + if not georegion and not country and not us_state: + # This is the catchall pool. Modify the pool name in the record + # being pushed + # NS1 regions are indexed by pool names. Any reuse of pool + # names in the rules will result in overwriting of the pool. + # Reuse of pools is in general disallowed but for the case of + # the catchall pool - to allow legitimate usecases. + # The pool name renaming is done to accommodate for such a + # reuse. + # (We expect only one catchall per record. Any associated + # validation is expected to covered under record validation) + catchall_pool_name = pool_name + regions['{}{}'.format(self.CATCHALL_PREFIX, pool_name)] = { + 'meta': meta, + } + else: + regions[pool_name] = { + 'meta': meta, + } existing_monitors = self._monitors_for(record) active_monitors = set() @@ -1097,18 +1104,26 @@ class Ns1Provider(BaseProvider): answers = [] for pool_name in sorted(pools.keys()): priority = 1 + answers_added = False # Dynamic/health checked - self._add_answers_for_pool(answers, default_answers, pool_name, - pool_name, pool_answers, pools, - priority) - if pool_name == dynamic_default_pool_name and needs_shadow: - # If it is the dynamic default pool, add a shadow pool. - # This will be used in regions when there are rules that refer - # to the dynamic default pool - shadow_pn = '{}_{}'.format(pool_name, 'shadow') + if pool_name == catchall_pool_name: + # For the catchall, use the internal pool name with the prefix + pool_label = '{}{}'.format(self.CATCHALL_PREFIX, pool_name) + self._add_answers_for_pool(answers, default_answers, pool_name, + pool_label, pool_answers, pools, + priority) + answers_added = True + + # If the catchall pool has been reused, we need the original + # pool name too, the creation of which is controlled by the + # answers_added flag + if pool_usage[pool_name] > 1: + answers_added = False + + if not answers_added: self._add_answers_for_pool(answers, default_answers, pool_name, - shadow_pn, pool_answers, pools, + pool_name, pool_answers, pools, priority) # Update filters as necessary diff --git a/tests/test_octodns_provider_ns1.py b/tests/test_octodns_provider_ns1.py index ac672aa..47841ac 100644 --- a/tests/test_octodns_provider_ns1.py +++ b/tests/test_octodns_provider_ns1.py @@ -528,7 +528,7 @@ class TestNs1Provider(TestCase): class TestNs1ProviderDynamic(TestCase): zone = Zone('unit.tests.', []) - record = Record.new(zone, '', { + record_data = { 'dynamic': { 'pools': { 'lhr': { @@ -573,7 +573,8 @@ class TestNs1ProviderDynamic(TestCase): 'type': 'A', 'value': '1.2.3.4', 'meta': {}, - }) + } + record = Record.new(zone, '', record_data) def test_notes(self): provider = Ns1Provider('test', 'api-key') @@ -978,6 +979,34 @@ class TestNs1ProviderDynamic(TestCase): rule0['geos'] = rule0_saved_geos rule1['geos'] = rule1_saved_geos + # Test record with no reuse of the catchall + monitors_for_mock.reset_mock() + monitor_sync_mock.reset_mock() + monitors_for_mock.side_effect = [{ + '3.4.5.6': 'mid-3', + }] + monitor_sync_mock.side_effect = [ + ('mid-1', 'fid-1'), + ('mid-2', 'fid-2'), + ('mid-3', 'fid-3'), + ] + # Modify the record data before creating the Record object + rule0 = self.record_data['dynamic']['rules'][0] + rule0_saved_geos = rule0['geos'] + rule0['geos'] = ['AF', 'EU'] + rule1 = self.record_data['dynamic']['rules'].pop(1) + + # Create a local record object without reuse of catchall + zone = Zone('unit.tests.', []) + record = Record.new(zone, '', self.record_data) + ret, _ = provider._params_for_A(record) + self.assertEquals(ret['filters'], + Ns1Provider._FILTER_CHAIN_WITH_REGION(provider, + True)) + # Restore record_data + rule0['geos'] = rule0_saved_geos + self.record_data['dynamic']['rules'].insert(1, rule1) + @patch('octodns.provider.ns1.Ns1Provider._monitor_sync') @patch('octodns.provider.ns1.Ns1Provider._monitors_for') def test_params_for_dynamic_oceania(self, monitors_for_mock, @@ -1137,16 +1166,16 @@ class TestNs1ProviderDynamic(TestCase): 'meta': { 'priority': 1, 'weight': 12, - 'note': 'from:iad_shadow', + 'note': 'from:catchall_iad', }, - 'region': 'iad_shadow', + 'region': 'catchall_iad', }, { 'answer': ['1.2.3.4'], 'meta': { 'priority': 2, 'note': 'from:--default--', }, - 'region': 'iad_shadow', + 'region': 'catchall_iad', }], 'domain': 'unit.tests', 'filters': filters, @@ -1159,13 +1188,13 @@ class TestNs1ProviderDynamic(TestCase): 'us_state': ['OR'], }, }, - 'iad_shadow': { + 'iad': { 'meta': { 'note': 'rule-order:2', 'country': ['ZW'], }, }, - 'iad': { + 'catchall_iad': { 'meta': { 'note': 'rule-order:3', }, From d93ddddaf26abd174b7dafe7aa5dc2dad754a8c9 Mon Sep 17 00:00:00 2001 From: Pavan Chandrashekar Date: Sat, 11 Apr 2020 02:28:28 -0700 Subject: [PATCH 3/3] Simplify logic, remove unnecessary coverage tests --- octodns/provider/ns1.py | 54 ++++++++++-------------------- tests/test_octodns_provider_ns1.py | 42 ++++------------------- 2 files changed, 25 insertions(+), 71 deletions(-) diff --git a/octodns/provider/ns1.py b/octodns/provider/ns1.py index 0566710..fb0a78f 100644 --- a/octodns/provider/ns1.py +++ b/octodns/provider/ns1.py @@ -237,7 +237,7 @@ class Ns1Provider(BaseProvider): 'NS', 'PTR', 'SPF', 'SRV', 'TXT')) ZONE_NOT_FOUND_MESSAGE = 'server error: zone not found' - CATCHALL_PREFIX = 'catchall_' + CATCHALL_PREFIX = 'catchall__' def _update_filter(self, filter, with_disabled): if with_disabled: @@ -472,8 +472,7 @@ class Ns1Provider(BaseProvider): pool_name = answer['region'] # Get the actual pool name from the constructed pool name in case # of the catchall - if pool_name.startswith(self.CATCHALL_PREFIX): - pool_name = pool_name[len(self.CATCHALL_PREFIX):] + pool_name = pool_name.replace(self.CATCHALL_PREFIX, '') pool = pools[pool_name] meta = answer['meta'] @@ -505,8 +504,7 @@ class Ns1Provider(BaseProvider): # Rules that refer to the catchall pool would have the # CATCHALL_PREFIX in the pool name. Strip the prefix to get back # the pool name as in the config - if pool_name.startswith(self.CATCHALL_PREFIX): - pool_name = pool_name[len(self.CATCHALL_PREFIX):] + pool_name = pool_name.replace(self.CATCHALL_PREFIX, '') meta = region['meta'] notes = self._parse_notes(meta.get('note', '')) @@ -1000,12 +998,9 @@ class Ns1Provider(BaseProvider): has_country = False has_region = False regions = {} - catchall_pool_name = None - pool_usage = defaultdict(lambda: 0) for i, rule in enumerate(record.dynamic.rules): pool_name = rule.data['pool'] - pool_usage[pool_name] += 1 notes = { 'rule-order': i, @@ -1066,14 +1061,11 @@ class Ns1Provider(BaseProvider): # reuse. # (We expect only one catchall per record. Any associated # validation is expected to covered under record validation) - catchall_pool_name = pool_name - regions['{}{}'.format(self.CATCHALL_PREFIX, pool_name)] = { - 'meta': meta, - } - else: - regions[pool_name] = { - 'meta': meta, - } + pool_name = '{}{}'.format(self.CATCHALL_PREFIX, pool_name) + + regions[pool_name] = { + 'meta': meta, + } existing_monitors = self._monitors_for(record) active_monitors = set() @@ -1101,30 +1093,20 @@ class Ns1Provider(BaseProvider): } for v in record.values] # Build our list of answers + # The regions dictionary built above already has the required pool + # names. Iterate over them and add answers. + # In the case of the catchall, original pool name can be obtained + # by stripping the CATCHALL_PREFIX from the pool name answers = [] - for pool_name in sorted(pools.keys()): + for pool_name in sorted(regions.keys()): priority = 1 - answers_added = False # Dynamic/health checked - if pool_name == catchall_pool_name: - # For the catchall, use the internal pool name with the prefix - pool_label = '{}{}'.format(self.CATCHALL_PREFIX, pool_name) - self._add_answers_for_pool(answers, default_answers, pool_name, - pool_label, pool_answers, pools, - priority) - answers_added = True - - # If the catchall pool has been reused, we need the original - # pool name too, the creation of which is controlled by the - # answers_added flag - if pool_usage[pool_name] > 1: - answers_added = False - - if not answers_added: - self._add_answers_for_pool(answers, default_answers, pool_name, - pool_name, pool_answers, pools, - priority) + pool_label = pool_name + pool_name = pool_name.replace(self.CATCHALL_PREFIX, '') + self._add_answers_for_pool(answers, default_answers, pool_name, + pool_label, pool_answers, pools, + priority) # Update filters as necessary filters = self._get_updated_filter_chain(has_region, has_country) diff --git a/tests/test_octodns_provider_ns1.py b/tests/test_octodns_provider_ns1.py index 47841ac..8a0dffb 100644 --- a/tests/test_octodns_provider_ns1.py +++ b/tests/test_octodns_provider_ns1.py @@ -528,7 +528,7 @@ class TestNs1Provider(TestCase): class TestNs1ProviderDynamic(TestCase): zone = Zone('unit.tests.', []) - record_data = { + record = Record.new(zone, '', { 'dynamic': { 'pools': { 'lhr': { @@ -573,8 +573,7 @@ class TestNs1ProviderDynamic(TestCase): 'type': 'A', 'value': '1.2.3.4', 'meta': {}, - } - record = Record.new(zone, '', record_data) + }) def test_notes(self): provider = Ns1Provider('test', 'api-key') @@ -979,34 +978,6 @@ class TestNs1ProviderDynamic(TestCase): rule0['geos'] = rule0_saved_geos rule1['geos'] = rule1_saved_geos - # Test record with no reuse of the catchall - monitors_for_mock.reset_mock() - monitor_sync_mock.reset_mock() - monitors_for_mock.side_effect = [{ - '3.4.5.6': 'mid-3', - }] - monitor_sync_mock.side_effect = [ - ('mid-1', 'fid-1'), - ('mid-2', 'fid-2'), - ('mid-3', 'fid-3'), - ] - # Modify the record data before creating the Record object - rule0 = self.record_data['dynamic']['rules'][0] - rule0_saved_geos = rule0['geos'] - rule0['geos'] = ['AF', 'EU'] - rule1 = self.record_data['dynamic']['rules'].pop(1) - - # Create a local record object without reuse of catchall - zone = Zone('unit.tests.', []) - record = Record.new(zone, '', self.record_data) - ret, _ = provider._params_for_A(record) - self.assertEquals(ret['filters'], - Ns1Provider._FILTER_CHAIN_WITH_REGION(provider, - True)) - # Restore record_data - rule0['geos'] = rule0_saved_geos - self.record_data['dynamic']['rules'].insert(1, rule1) - @patch('octodns.provider.ns1.Ns1Provider._monitor_sync') @patch('octodns.provider.ns1.Ns1Provider._monitors_for') def test_params_for_dynamic_oceania(self, monitors_for_mock, @@ -1123,6 +1094,7 @@ class TestNs1ProviderDynamic(TestCase): # Test out a small, but realistic setup that covers all the options # We have country and region in the test config filters = provider._get_updated_filter_chain(True, True) + catchall_pool_name = '{}{}'.format(provider.CATCHALL_PREFIX, 'iad') ns1_record = { 'answers': [{ 'answer': ['3.4.5.6'], @@ -1166,16 +1138,16 @@ class TestNs1ProviderDynamic(TestCase): 'meta': { 'priority': 1, 'weight': 12, - 'note': 'from:catchall_iad', + 'note': 'from:{}'.format(catchall_pool_name), }, - 'region': 'catchall_iad', + 'region': catchall_pool_name, }, { 'answer': ['1.2.3.4'], 'meta': { 'priority': 2, 'note': 'from:--default--', }, - 'region': 'catchall_iad', + 'region': catchall_pool_name, }], 'domain': 'unit.tests', 'filters': filters, @@ -1194,7 +1166,7 @@ class TestNs1ProviderDynamic(TestCase): 'country': ['ZW'], }, }, - 'catchall_iad': { + catchall_pool_name: { 'meta': { 'note': 'rule-order:3', },