From 49bff426b7ee4d5a4554b2c6e1603e6384d32949 Mon Sep 17 00:00:00 2001 From: Viranch Mehta Date: Thu, 12 Aug 2021 21:43:01 -0700 Subject: [PATCH 1/9] Multi-value PTR records --- octodns/provider/azuredns.py | 4 +-- octodns/provider/ns1.py | 24 ++++++++++++----- octodns/record/__init__.py | 31 ++++++++++++++++++++-- tests/config/split/unit.tests.tst/ptr.yaml | 2 +- tests/config/unit.tests.yaml | 2 +- tests/test_octodns_provider_ns1.py | 17 ++++++++++-- tests/test_octodns_record.py | 12 ++++++++- 7 files changed, 76 insertions(+), 16 deletions(-) diff --git a/octodns/provider/azuredns.py b/octodns/provider/azuredns.py index 6edc1ba..c75ef4b 100644 --- a/octodns/provider/azuredns.py +++ b/octodns/provider/azuredns.py @@ -707,8 +707,8 @@ class AzureProvider(BaseProvider): return {'values': [_check_endswith_dot(val) for val in vals]} def _data_for_PTR(self, azrecord): - ptrdname = azrecord.ptr_records[0].ptrdname - return {'value': _check_endswith_dot(ptrdname)} + vals = [ar.ptrdname for ar in azrecord.ptr_records] + return {'values': [_check_endswith_dot(val) for val in vals]} def _data_for_SRV(self, azrecord): return {'values': [{'priority': ar.priority, 'weight': ar.weight, diff --git a/octodns/provider/ns1.py b/octodns/provider/ns1.py index 0ebb36b..72e0bc9 100644 --- a/octodns/provider/ns1.py +++ b/octodns/provider/ns1.py @@ -20,6 +20,10 @@ from ..record import Record, Update from .base import BaseProvider +def _check_endswith_dot(string): + return string if string.endswith('.') else '{}.'.format(string) + + class Ns1Exception(Exception): pass @@ -717,7 +721,6 @@ class Ns1Provider(BaseProvider): } _data_for_ALIAS = _data_for_CNAME - _data_for_PTR = _data_for_CNAME def _data_for_MX(self, _type, record): values = [] @@ -756,10 +759,11 @@ class Ns1Provider(BaseProvider): return { 'ttl': record['ttl'], 'type': _type, - 'values': [a if a.endswith('.') else '{}.'.format(a) - for a in record['short_answers']], + 'values': record['short_answers'], } + _data_for_PTR = _data_for_NS + def _data_for_SRV(self, _type, record): values = [] for answer in record['short_answers']: @@ -809,9 +813,10 @@ class Ns1Provider(BaseProvider): for record in ns1_zone['records']: if record['type'] in ['ALIAS', 'CNAME', 'MX', 'NS', 'PTR', 'SRV']: - for i, a in enumerate(record['short_answers']): - if not a.endswith('.'): - record['short_answers'][i] = '{}.'.format(a) + record['short_answers'] = [ + _check_endswith_dot(a) + for a in record['short_answers'] + ] if record.get('tier', 1) > 1: # Need to get the full record data for geo records @@ -1297,7 +1302,6 @@ class Ns1Provider(BaseProvider): return {'answers': [record.value], 'ttl': record.ttl}, None _params_for_ALIAS = _params_for_CNAME - _params_for_PTR = _params_for_CNAME def _params_for_MX(self, record): values = [(v.preference, v.exchange) for v in record.values] @@ -1308,6 +1312,12 @@ class Ns1Provider(BaseProvider): v.replacement) for v in record.values] return {'answers': values, 'ttl': record.ttl}, None + def _params_for_PTR(self, record): + return { + 'answers': record.values, + 'ttl': record.ttl, + }, None + def _params_for_SRV(self, record): values = [(v.priority, v.weight, v.port, v.target) for v in record.values] diff --git a/octodns/record/__init__.py b/octodns/record/__init__.py index 7714b27..93f6660 100644 --- a/octodns/record/__init__.py +++ b/octodns/record/__init__.py @@ -1256,13 +1256,40 @@ class NsRecord(_ValuesMixin, Record): class PtrValue(_TargetValue): - pass + @classmethod + def validate(cls, values, _type): + if not isinstance(values, list): + values = [values] + + reasons = [] + + if not values: + reasons.append('missing values') + + for value in values: + reasons.extend(super(PtrValue, cls).validate(value, _type)) + + return reasons -class PtrRecord(_ValueMixin, Record): + @classmethod + def process(cls, values): + return [super(PtrValue, cls).process(v) for v in values] + + +class PtrRecord(_ValuesMixin, Record): _type = 'PTR' _value_type = PtrValue + # This is for backward compatibility with providers that don't support + # multi-value PTR records. + @property + def value(self): + if len(self.values) == 1: + return self.values[0] + + raise AttributeError("Multi-value PTR record has no attribute 'value'") + class SshfpValue(EqualityTupleMixin): VALID_ALGORITHMS = (1, 2, 3, 4) diff --git a/tests/config/split/unit.tests.tst/ptr.yaml b/tests/config/split/unit.tests.tst/ptr.yaml index 0098b57..cffb50b 100644 --- a/tests/config/split/unit.tests.tst/ptr.yaml +++ b/tests/config/split/unit.tests.tst/ptr.yaml @@ -2,4 +2,4 @@ ptr: ttl: 300 type: PTR - value: foo.bar.com. + values: [foo.bar.com.] diff --git a/tests/config/unit.tests.yaml b/tests/config/unit.tests.yaml index c70b20c..aa28ee5 100644 --- a/tests/config/unit.tests.yaml +++ b/tests/config/unit.tests.yaml @@ -152,7 +152,7 @@ naptr: ptr: ttl: 300 type: PTR - value: foo.bar.com. + values: [foo.bar.com.] spf: ttl: 600 type: SPF diff --git a/tests/test_octodns_provider_ns1.py b/tests/test_octodns_provider_ns1.py index 932e4c4..3e239b3 100644 --- a/tests/test_octodns_provider_ns1.py +++ b/tests/test_octodns_provider_ns1.py @@ -120,6 +120,11 @@ class TestNs1Provider(TestCase): 'query': 0, }, })) + expected.add(Record.new(zone, '1.2.3.4', { + 'ttl': 42, + 'type': 'PTR', + 'values': ['one.one.one.one.', 'two.two.two.two.'], + })) ns1_records = [{ 'type': 'A', @@ -180,6 +185,11 @@ class TestNs1Provider(TestCase): 'ttl': 41, 'short_answers': ['/ http://foo.unit.tests 301 2 0'], 'domain': 'urlfwd.unit.tests.', + }, { + 'type': 'PTR', + 'ttl': 42, + 'short_answers': ['one.one.one.one.', 'two.two.two.two.'], + 'domain': '1.2.3.4.unit.tests.', }] @patch('ns1.rest.records.Records.retrieve') @@ -358,10 +368,10 @@ class TestNs1Provider(TestCase): ResourceException('server error: zone not found') zone_create_mock.side_effect = ['foo'] - # Test out the create rate-limit handling, then 9 successes + # Test out the create rate-limit handling, then successes for the rest record_create_mock.side_effect = [ RateLimitException('boo', period=0), - ] + ([None] * 10) + ] + ([None] * len(self.expected)) got_n = provider.apply(plan) self.assertEquals(expected_n, got_n) @@ -379,6 +389,9 @@ class TestNs1Provider(TestCase): call('unit.tests', 'unit.tests', 'MX', answers=[ (10, 'mx1.unit.tests.'), (20, 'mx2.unit.tests.') ], ttl=35), + call('unit.tests', '1.2.3.4.unit.tests', 'PTR', answers=[ + 'one.one.one.one.', 'two.two.two.two.', + ], ttl=42), ]) # Update & delete diff --git a/tests/test_octodns_record.py b/tests/test_octodns_record.py index 3bd48e5..2d8e000 100644 --- a/tests/test_octodns_record.py +++ b/tests/test_octodns_record.py @@ -2733,7 +2733,7 @@ class TestRecordValidation(TestCase): 'type': 'PTR', 'ttl': 600, }) - self.assertEquals(['missing value'], ctx.exception.reasons) + self.assertEquals(['missing values'], ctx.exception.reasons) # not a valid FQDN with self.assertRaises(ValidationError) as ctx: @@ -2755,6 +2755,16 @@ class TestRecordValidation(TestCase): self.assertEquals(['PTR value "foo.bar" missing trailing .'], ctx.exception.reasons) + # multi-value requesting single-value + with self.assertRaises(AttributeError) as ctx: + Record.new(self.zone, '', { + 'type': 'PTR', + 'ttl': 600, + 'values': ['foo.com.', 'bar.net.'], + }).value + self.assertEquals("Multi-value PTR record has no attribute 'value'", + text_type(ctx.exception)) + def test_SSHFP(self): # doesn't blow up Record.new(self.zone, '', { From ec41e0377e9f689ed5865977b32c22cf643a688b Mon Sep 17 00:00:00 2001 From: Viranch Mehta Date: Thu, 12 Aug 2021 22:15:46 -0700 Subject: [PATCH 2/9] multi-value PTR tests for Azure --- octodns/record/__init__.py | 2 +- tests/test_octodns_provider_azuredns.py | 30 +++++++++++++++++++------ 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/octodns/record/__init__.py b/octodns/record/__init__.py index 93f6660..2e17948 100644 --- a/octodns/record/__init__.py +++ b/octodns/record/__init__.py @@ -1286,7 +1286,7 @@ class PtrRecord(_ValuesMixin, Record): @property def value(self): if len(self.values) == 1: - return self.values[0] + return self.data['value'] raise AttributeError("Multi-value PTR record has no attribute 'value'") diff --git a/tests/test_octodns_provider_azuredns.py b/tests/test_octodns_provider_azuredns.py index 0af8665..b3b52e5 100644 --- a/tests/test_octodns_provider_azuredns.py +++ b/tests/test_octodns_provider_azuredns.py @@ -150,6 +150,11 @@ octo_records.append(Record.new(zone, 'txt3', { 'type': 'TXT', 'values': ['txt multiple test', long_txt]})) +octo_records.append(Record.new(zone, 'ptr2', { + 'ttl': 11, + 'type': 'PTR', + 'values': ['ptr21.unit.tests.', 'ptr22.unit.tests.']})) + azure_records = [] _base0 = _AzureRecord('TestAzure', octo_records[0]) _base0.zone_name = 'unit.tests' @@ -338,6 +343,15 @@ _base18.params['txt_records'] = [TxtRecord(value=['txt multiple test']), TxtRecord(value=[long_txt_az1, long_txt_az2])] azure_records.append(_base18) +_base19 = _AzureRecord('TestAzure', octo_records[19]) +_base19.zone_name = 'unit.tests' +_base19.relative_record_set_name = 'ptr2' +_base19.record_type = 'PTR' +_base19.params['ttl'] = 11 +_base19.params['ptr_records'] = [PtrRecord(ptrdname='ptr21.unit.tests.'), + PtrRecord(ptrdname='ptr22.unit.tests.')] +azure_records.append(_base19) + class Test_AzureRecord(TestCase): def test_azure_record(self): @@ -2054,15 +2068,16 @@ class TestAzureDnsProvider(TestCase): def test_apply(self): provider = self._get_provider() - half = int(len(octo_records) / 2) + expected_n = len(octo_records) + half = int(expected_n / 2) changes = [Create(r) for r in octo_records[:half]] + \ [Update(r, r) for r in octo_records[half:]] deletes = [Delete(r) for r in octo_records] - self.assertEquals(19, provider.apply(Plan(None, zone, - changes, True))) - self.assertEquals(19, provider.apply(Plan(zone, zone, - deletes, True))) + self.assertEquals(expected_n, provider.apply(Plan(None, zone, + changes, True))) + self.assertEquals(expected_n, provider.apply(Plan(zone, zone, + deletes, True))) def test_apply_create_dynamic(self): provider = self._get_provider() @@ -2320,8 +2335,9 @@ class TestAzureDnsProvider(TestCase): _get = provider._dns_client.zones.get _get.side_effect = CloudError(Mock(status=404), err_msg) - self.assertEquals(19, provider.apply(Plan(None, desired, changes, - True))) + expected_n = len(octo_records) + self.assertEquals(expected_n, provider.apply(Plan(None, desired, + changes, True))) def test_check_zone_no_create(self): provider = self._get_provider() From 73ad7000cab36088245dfafcae5db1f5b4df85f6 Mon Sep 17 00:00:00 2001 From: Viranch Mehta Date: Thu, 12 Aug 2021 22:33:10 -0700 Subject: [PATCH 3/9] better helper method name --- octodns/provider/ns1.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/octodns/provider/ns1.py b/octodns/provider/ns1.py index 72e0bc9..9209ede 100644 --- a/octodns/provider/ns1.py +++ b/octodns/provider/ns1.py @@ -20,7 +20,7 @@ from ..record import Record, Update from .base import BaseProvider -def _check_endswith_dot(string): +def _ensure_endswith_dot(string): return string if string.endswith('.') else '{}.'.format(string) @@ -814,7 +814,7 @@ class Ns1Provider(BaseProvider): if record['type'] in ['ALIAS', 'CNAME', 'MX', 'NS', 'PTR', 'SRV']: record['short_answers'] = [ - _check_endswith_dot(a) + _ensure_endswith_dot(a) for a in record['short_answers'] ] From 6e9ce3ac3c71ddfa7d56fae4bf295e974c58f492 Mon Sep 17 00:00:00 2001 From: Viranch Mehta Date: Mon, 16 Aug 2021 16:39:23 -0700 Subject: [PATCH 4/9] pick first PTR value instead of erroring out --- octodns/manager.py | 26 ++++++++++++++++++++++++-- octodns/provider/azuredns.py | 1 + octodns/provider/ns1.py | 1 + octodns/record/__init__.py | 5 +---- octodns/source/base.py | 2 ++ tests/test_octodns_record.py | 10 ---------- 6 files changed, 29 insertions(+), 16 deletions(-) diff --git a/octodns/manager.py b/octodns/manager.py index 104e445..a991b4b 100644 --- a/octodns/manager.py +++ b/octodns/manager.py @@ -294,8 +294,30 @@ class Manager(object): for processor in processors: plan = processor.process_plan(plan, sources=sources, target=target) - if plan: - plans.append((target, plan)) + if not plan: + continue + + # Multi value PTR check + for change in plan.changes: + record = change.new + if not record: + # Delete - doesn't need to be checked + continue + + if record._type == 'PTR' and len(record.values) > 1 and not \ + target.SUPPORTS_MUTLIVALUE_PTR: + self.log.warn('target=%s does not support multi-value PTR ' + 'record %s; using %s as its only answer', + target, record.fqdn, record.value) + # Make a new copy of the record so as to not change a + # potentially shared object + change.new = Record.new(record.zone, record.name, { + 'type': record._type, + 'ttl': record.ttl, + 'value': record.value, + }, source=record.source, lenient=lenient) + + plans.append((target, plan)) # Return the zone as it's the desired state return plans, zone diff --git a/octodns/provider/azuredns.py b/octodns/provider/azuredns.py index c75ef4b..20a9d7b 100644 --- a/octodns/provider/azuredns.py +++ b/octodns/provider/azuredns.py @@ -456,6 +456,7 @@ class AzureProvider(BaseProvider): ''' SUPPORTS_GEO = False SUPPORTS_DYNAMIC = True + SUPPORTS_MUTLIVALUE_PTR = True SUPPORTS = set(('A', 'AAAA', 'CAA', 'CNAME', 'MX', 'NS', 'PTR', 'SRV', 'TXT')) diff --git a/octodns/provider/ns1.py b/octodns/provider/ns1.py index 9209ede..3bd0b54 100644 --- a/octodns/provider/ns1.py +++ b/octodns/provider/ns1.py @@ -261,6 +261,7 @@ class Ns1Provider(BaseProvider): ''' SUPPORTS_GEO = True SUPPORTS_DYNAMIC = True + SUPPORTS_MUTLIVALUE_PTR = True SUPPORTS = set(('A', 'AAAA', 'ALIAS', 'CAA', 'CNAME', 'MX', 'NAPTR', 'NS', 'PTR', 'SPF', 'SRV', 'TXT', 'URLFWD')) diff --git a/octodns/record/__init__.py b/octodns/record/__init__.py index 2e17948..77663a5 100644 --- a/octodns/record/__init__.py +++ b/octodns/record/__init__.py @@ -1285,10 +1285,7 @@ class PtrRecord(_ValuesMixin, Record): # multi-value PTR records. @property def value(self): - if len(self.values) == 1: - return self.data['value'] - - raise AttributeError("Multi-value PTR record has no attribute 'value'") + return self.values[0] class SshfpValue(EqualityTupleMixin): diff --git a/octodns/source/base.py b/octodns/source/base.py index 79b5a2a..6094726 100644 --- a/octodns/source/base.py +++ b/octodns/source/base.py @@ -8,6 +8,8 @@ from __future__ import absolute_import, division, print_function, \ class BaseSource(object): + SUPPORTS_MUTLIVALUE_PTR = False + def __init__(self, id): self.id = id if not getattr(self, 'log', False): diff --git a/tests/test_octodns_record.py b/tests/test_octodns_record.py index 2d8e000..886dbfb 100644 --- a/tests/test_octodns_record.py +++ b/tests/test_octodns_record.py @@ -2755,16 +2755,6 @@ class TestRecordValidation(TestCase): self.assertEquals(['PTR value "foo.bar" missing trailing .'], ctx.exception.reasons) - # multi-value requesting single-value - with self.assertRaises(AttributeError) as ctx: - Record.new(self.zone, '', { - 'type': 'PTR', - 'ttl': 600, - 'values': ['foo.com.', 'bar.net.'], - }).value - self.assertEquals("Multi-value PTR record has no attribute 'value'", - text_type(ctx.exception)) - def test_SSHFP(self): # doesn't blow up Record.new(self.zone, '', { From fc39697bddd6149ca50a0f7f11b3e47ca5e235d3 Mon Sep 17 00:00:00 2001 From: Viranch Mehta Date: Mon, 16 Aug 2021 20:33:22 -0700 Subject: [PATCH 5/9] consider only first PTR value for getting changes --- octodns/manager.py | 26 ++------------------------ octodns/provider/base.py | 32 +++++++++++++++++++++++++++++++- 2 files changed, 33 insertions(+), 25 deletions(-) diff --git a/octodns/manager.py b/octodns/manager.py index a991b4b..104e445 100644 --- a/octodns/manager.py +++ b/octodns/manager.py @@ -294,30 +294,8 @@ class Manager(object): for processor in processors: plan = processor.process_plan(plan, sources=sources, target=target) - if not plan: - continue - - # Multi value PTR check - for change in plan.changes: - record = change.new - if not record: - # Delete - doesn't need to be checked - continue - - if record._type == 'PTR' and len(record.values) > 1 and not \ - target.SUPPORTS_MUTLIVALUE_PTR: - self.log.warn('target=%s does not support multi-value PTR ' - 'record %s; using %s as its only answer', - target, record.fqdn, record.value) - # Make a new copy of the record so as to not change a - # potentially shared object - change.new = Record.new(record.zone, record.name, { - 'type': record._type, - 'ttl': record.ttl, - 'value': record.value, - }, source=record.source, lenient=lenient) - - plans.append((target, plan)) + if plan: + plans.append((target, plan)) # Return the zone as it's the desired state return plans, zone diff --git a/octodns/provider/base.py b/octodns/provider/base.py index 729c9ee..fcb557a 100644 --- a/octodns/provider/base.py +++ b/octodns/provider/base.py @@ -7,6 +7,7 @@ from __future__ import absolute_import, division, print_function, \ from six import text_type +from ..record import Record from ..source.base import BaseSource from ..zone import Zone from .plan import Plan @@ -44,6 +45,35 @@ class BaseProvider(BaseSource): ''' return [] + def _process_change(self, change): + ''' + Process/manipulate each change for feature-specific corner cases + ''' + if not self._include_change(change): + return False + + # Multi value PTR records + record = change.new + if record and record._type == 'PTR' and len(record.values) > 1 and \ + not self.SUPPORTS_MUTLIVALUE_PTR: + # replace with a single-value copy + change.new = Record.new(record.zone, record.name, { + 'type': 'PTR', + 'ttl': record.ttl, + 'values': [record.value], + }, source=record.source) + + existing = change.existing + if existing and not existing.changes(change.new, self): + # if new single-value replacement turns out to be the same, + # skip the change + return False + + self.log.warn('does not support multi-value PTR records; will ' + 'use only %s for %s', record.value, record.fqdn) + + return True + def plan(self, desired, processors=[]): self.log.info('plan: desired=%s', desired.name) @@ -63,7 +93,7 @@ class BaseProvider(BaseSource): # allow the provider to filter out false positives before = len(changes) - changes = [c for c in changes if self._include_change(c)] + changes = [c for c in changes if self._process_change(c)] after = len(changes) if before != after: self.log.info('plan: filtered out %s changes', before - after) From 8ddbb389aba255f5f8b5da993b0aff781136cbac Mon Sep 17 00:00:00 2001 From: Viranch Mehta Date: Wed, 18 Aug 2021 11:22:12 -0700 Subject: [PATCH 6/9] method to custom-process desired zone --- octodns/provider/base.py | 50 ++++++++++++++++++---------------------- 1 file changed, 23 insertions(+), 27 deletions(-) diff --git a/octodns/provider/base.py b/octodns/provider/base.py index fcb557a..166f681 100644 --- a/octodns/provider/base.py +++ b/octodns/provider/base.py @@ -7,7 +7,6 @@ from __future__ import absolute_import, division, print_function, \ from six import text_type -from ..record import Record from ..source.base import BaseSource from ..zone import Zone from .plan import Plan @@ -45,34 +44,28 @@ class BaseProvider(BaseSource): ''' return [] - def _process_change(self, change): + def _process_desired_zone(self, desired): ''' - Process/manipulate each change for feature-specific corner cases + Providers can use this method to make any custom changes to the + desired zone. ''' - if not self._include_change(change): - return False - - # Multi value PTR records - record = change.new - if record and record._type == 'PTR' and len(record.values) > 1 and \ - not self.SUPPORTS_MUTLIVALUE_PTR: - # replace with a single-value copy - change.new = Record.new(record.zone, record.name, { - 'type': 'PTR', - 'ttl': record.ttl, - 'values': [record.value], - }, source=record.source) - - existing = change.existing - if existing and not existing.changes(change.new, self): - # if new single-value replacement turns out to be the same, - # skip the change - return False - - self.log.warn('does not support multi-value PTR records; will ' - 'use only %s for %s', record.value, record.fqdn) + if self.SUPPORTS_MUTLIVALUE_PTR: + # nothing do here + return desired - return True + new_desired = Zone(desired.name, desired.sub_zones) + for record in desired.records: + if record._type == 'PTR' and len(record.values) > 1: + # replace with a single-value copy + self.log.warn('does not support multi-value PTR records; ' + 'will use only %s for %s', record.value, + record.fqdn) + record = record.copy() + record.values = [record.values[0]] + + new_desired.add_record(record) + + return new_desired def plan(self, desired, processors=[]): self.log.info('plan: desired=%s', desired.name) @@ -88,12 +81,15 @@ class BaseProvider(BaseSource): for processor in processors: existing = processor.process_target_zone(existing, target=self) + # process desired zone for any custom zone/record modification + desired = self._process_desired_zone(desired) + # compute the changes at the zone/record level changes = existing.changes(desired, self) # allow the provider to filter out false positives before = len(changes) - changes = [c for c in changes if self._process_change(c)] + changes = [c for c in changes if self._include_change(c)] after = len(changes) if before != after: self.log.info('plan: filtered out %s changes', before - after) From 2021fcc00cafe20b7e382fc2e3f9503d7859e4bb Mon Sep 17 00:00:00 2001 From: Viranch Mehta Date: Wed, 18 Aug 2021 11:25:43 -0700 Subject: [PATCH 7/9] yaml supports multi value PTR --- octodns/provider/yaml.py | 1 + 1 file changed, 1 insertion(+) diff --git a/octodns/provider/yaml.py b/octodns/provider/yaml.py index b3dd2d9..803bbd4 100644 --- a/octodns/provider/yaml.py +++ b/octodns/provider/yaml.py @@ -104,6 +104,7 @@ class YamlProvider(BaseProvider): ''' SUPPORTS_GEO = True SUPPORTS_DYNAMIC = True + SUPPORTS_MUTLIVALUE_PTR = True SUPPORTS = set(('A', 'AAAA', 'ALIAS', 'CAA', 'CNAME', 'DNAME', 'LOC', 'MX', 'NAPTR', 'NS', 'PTR', 'SSHFP', 'SPF', 'SRV', 'TXT', 'URLFWD')) From 4517df555d69335e2e6afc8d3d3ee777398e6b1b Mon Sep 17 00:00:00 2001 From: Viranch Mehta Date: Wed, 18 Aug 2021 11:38:38 -0700 Subject: [PATCH 8/9] add tests --- tests/test_octodns_provider_base.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tests/test_octodns_provider_base.py b/tests/test_octodns_provider_base.py index 4dfce48..28abfd3 100644 --- a/tests/test_octodns_provider_base.py +++ b/tests/test_octodns_provider_base.py @@ -230,6 +230,20 @@ class TestBaseProvider(TestCase): # We filtered out the only change self.assertFalse(plan) + def test_process_desired_zone(self): + zone1 = Zone('unit.tests.', []) + record1 = Record.new(zone1, 'ptr', { + 'type': 'PTR', + 'ttl': 3600, + 'values': ['foo.com.', 'bar.com.'], + }) + zone1.add_record(record1) + + zone2 = HelperProvider('hasptr')._process_desired_zone(zone1) + record2 = list(zone2.records)[0] + + self.assertEqual(len(record2.values), 1) + def test_safe_none(self): # No changes is safe Plan(None, None, [], True).raise_if_unsafe() From 7b748de2b3d0dd4b86f015b28bf2c47e3f5cd429 Mon Sep 17 00:00:00 2001 From: Viranch Mehta Date: Wed, 18 Aug 2021 12:14:50 -0700 Subject: [PATCH 9/9] use the PTR value that is shown in logs --- octodns/provider/base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/octodns/provider/base.py b/octodns/provider/base.py index 166f681..c5a8dc9 100644 --- a/octodns/provider/base.py +++ b/octodns/provider/base.py @@ -61,7 +61,7 @@ class BaseProvider(BaseSource): 'will use only %s for %s', record.value, record.fqdn) record = record.copy() - record.values = [record.values[0]] + record.values = [record.value] new_desired.add_record(record)