From 26c02d9f2f8425d923768d0a0b94e908264efacd Mon Sep 17 00:00:00 2001 From: Pieter Lexis Date: Thu, 30 May 2024 11:00:23 +0200 Subject: [PATCH] feat: Add support to DNAME, DS, and TLSA These record types are supported both by OctoDNS and [NS1](https://www.ibm.com/docs/en/ns1-connect?topic=answers-reference-dns-record-types). --- octodns_ns1/__init__.py | 57 +++++++++++++++++++++++++++++++++ tests/test_provider_ns1.py | 65 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 122 insertions(+) diff --git a/octodns_ns1/__init__.py b/octodns_ns1/__init__.py index c658e21..6ed9a38 100644 --- a/octodns_ns1/__init__.py +++ b/octodns_ns1/__init__.py @@ -310,12 +310,15 @@ class Ns1Provider(BaseProvider): 'ALIAS', 'CAA', 'CNAME', + 'DNAME', + 'DS', 'MX', 'NAPTR', 'NS', 'PTR', 'SPF', 'SRV', + 'TLSA', 'TXT', 'URLFWD', ) @@ -857,6 +860,7 @@ def _data_for_CNAME(self, _type, record): return {'ttl': record['ttl'], 'type': _type, 'value': value} _data_for_ALIAS = _data_for_CNAME + _data_for_DNAME = _data_for_CNAME def _data_for_MX(self, _type, record): values = [] @@ -921,6 +925,39 @@ def _data_for_URLFWD(self, _type, record): ) return {'ttl': record['ttl'], 'type': _type, 'values': values} + def _data_for_DS(self, _type, record): + values = [] + for answer in record['short_answers']: + key_tag, algorithm, digest_type, digest = answer.split(' ', 3) + values.append( + { + 'key_tag': key_tag, + 'algorithm': algorithm, + 'digest_type': digest_type, + 'digest': digest, + } + ) + return {'ttl': record['ttl'], 'type': _type, 'values': values} + + def _data_for_TLSA(self, _type, record): + values = [] + for answer in record['short_answers']: + ( + certificate_usage, + selector, + matching_type, + certificate_association_data, + ) = answer.split(' ', 3) + values.append( + { + 'certificate_usage': certificate_usage, + 'selector': selector, + 'matching_type': matching_type, + 'certificate_association_data': certificate_association_data, + } + ) + return {'ttl': record['ttl'], 'type': _type, 'values': values} + def list_zones(self): return sorted([f'{z["zone"]}.' for z in self._client.zones_list()]) @@ -1636,6 +1673,7 @@ def _params_for_CNAME(self, record): }, None _params_for_ALIAS = _params_for_CNAME + _params_for_DNAME = _params_for_CNAME def _params_for_MX(self, record): values = [(v.preference, v.exchange) for v in record.values] @@ -1664,6 +1702,25 @@ def _params_for_URLFWD(self, record): ] return {'answers': values, 'ttl': record.ttl}, None + def _params_for_DS(self, record): + values = [ + (v.key_tag, v.algorithm, v.digest_type, v.digest) + for v in record.values + ] + return {'answers': values, 'ttl': record.ttl}, None + + def _params_for_TLSA(self, record): + values = [ + ( + v.certificate_usage, + v.selector, + v.matching_type, + v.certificate_association_data, + ) + for v in record.values + ] + return {'answers': values, 'ttl': record.ttl}, None + def _extra_changes(self, desired, changes, **kwargs): self.log.debug('_extra_changes: desired=%s', desired.name) changed = set([c.record for c in changes]) diff --git a/tests/test_provider_ns1.py b/tests/test_provider_ns1.py index b7efa20..91a6c33 100644 --- a/tests/test_provider_ns1.py +++ b/tests/test_provider_ns1.py @@ -182,6 +182,49 @@ class TestNs1Provider(TestCase): }, ) ) + expected.add( + Record.new( + zone, + 'dname', + {'ttl': 43, 'type': 'DNAME', 'value': 'foo.unit.tests.'}, + ) + ) + expected.add( + Record.new( + zone, + 'ds', + { + 'ttl': 44, + 'type': 'DS', + 'values': [ + { + 'key_tag': '60485', + 'algorithm': 5, + 'digest_type': 1, + 'digest': '2BB183AF5F22588179A53B0A98631FAD1A292118', + } + ], + }, + ) + ) + expected.add( + Record.new( + zone, + 'tlsa', + { + 'ttl': 45, + 'type': 'TLSA', + 'values': [ + { + 'certificate_usage': 1, + 'selector': 1, + 'matching_type': 1, + 'certificate_association_data': '8755CDAA8FE24EF16CC0F2C918063185E433FAAF1415664911D9E30A924138C4', + } + ], + }, + ) + ) ns1_records = [ { @@ -262,6 +305,28 @@ class TestNs1Provider(TestCase): 'short_answers': ['one.one.one.one.', 'two.two.two.two.'], 'domain': '1.2.3.4.unit.tests.', }, + { + 'type': 'DNAME', + 'ttl': 43, + 'short_answers': ['foo.unit.tests.'], + 'domain': 'dname.unit.tests.', + }, + { + 'type': 'DS', + 'ttl': 44, + 'short_answers': [ + '60485 5 1 2BB183AF5F22588179A53B0A98631FAD1A292118' + ], + 'domain': 'ds.unit.tests.', + }, + { + 'type': 'TLSA', + 'ttl': 45, + 'short_answers': [ + '1 1 1 8755CDAA8FE24EF16CC0F2C918063185E433FAAF1415664911D9E30A924138C4' + ], + 'domain': 'tlsa.unit.tests.', + }, ] @patch('ns1.rest.records.Records.retrieve')