From 79b2a2568460d0a97810320e7b1b3a94d317cd25 Mon Sep 17 00:00:00 2001 From: William Gauthier Date: Wed, 17 Apr 2024 19:33:25 +0200 Subject: [PATCH 1/6] Add a priority option to AutoArpa --- docs/auto_arpa.md | 2 + docs/records.md | 11 +++++ octodns/processor/arpa.py | 16 +++++-- tests/test_octodns_processor_arpa.py | 65 +++++++++++++++++++--------- 4 files changed, 70 insertions(+), 24 deletions(-) diff --git a/docs/auto_arpa.md b/docs/auto_arpa.md index 9f7eb61..a5411c2 100644 --- a/docs/auto_arpa.md +++ b/docs/auto_arpa.md @@ -19,6 +19,8 @@ manager: populate_should_replace: false # Explicitly set the TTL of auto-created records, default is 3600s, 1hr ttl: 1800 + # Set how many PTR records will be created for the same IP, default: 999 + max_auto_arpa: 1 ``` Once enabled, a singleton `AutoArpa` instance, `auto-arpa`, will be added to the pool of providers and globally configured to run as the very last global processor so that it will see all records as they will be seen by targets. Further all zones ending with `arpa.` will be held back and processed after all other zones have been completed so that all `A` and `AAAA` records will have been seen prior to planning the `arpa.` zones. diff --git a/docs/records.md b/docs/records.md index d0100d3..e3b878e 100644 --- a/docs/records.md +++ b/docs/records.md @@ -94,6 +94,17 @@ octoDNS is fairly strict in terms of standards compliance and is opinionated in It's best to think of the `lenient` flag as "I know what I'm doing and accept any problems I run across." The main reason being is that some providers may allow the non-compliant setup and others may not. The behavior of the non-compliant records may even vary from one provider to another. Caveat emptor. +#### Record priority for AutoArpa +When multiple A or AAAA records point to the same IP, it is possible to set an optional priority on each record. The records with the lowest priority will have the highest preference when being processed by AutoArpa. The AutoArpa provider will create PTR records in order of preference, up to a set limit defined by the `max_auto_arpa` option in the provider configuration. + +```yaml +test: +- type: A + value: 1.2.3.4 + octodns: + auto_arpa_priority: 1 +``` + #### octodns-dump If you're trying to import a zone into octoDNS config file using `octodns-dump` which fails due to validation errors you can supply the `--lenient` argument to tell octoDNS that you acknowledge that things aren't lining up with its expectations, but you'd like it to go ahead anyway. This will do its best to populate the zone and dump the results out into an octoDNS zone file and include the non-compliant bits. If you go to use that config file octoDNS will again complain about the validation problems. You can correct them in cases where that makes sense, but if you need to preserve the non-compliant records read on for options. diff --git a/octodns/processor/arpa.py b/octodns/processor/arpa.py index 960fb55..1e121eb 100644 --- a/octodns/processor/arpa.py +++ b/octodns/processor/arpa.py @@ -11,17 +11,19 @@ from .base import BaseProcessor class AutoArpa(BaseProcessor): - def __init__(self, name, ttl=3600, populate_should_replace=False): + def __init__(self, name, ttl=3600, populate_should_replace=False, max_auto_arpa=999): super().__init__(name) self.log = getLogger(f'AutoArpa[{name}]') self.log.info( - '__init__: ttl=%d, populate_should_replace=%s', + '__init__: ttl=%d, populate_should_replace=%s, max_auto_arpa=%d', ttl, populate_should_replace, + max_auto_arpa ) self.ttl = ttl self.populate_should_replace = populate_should_replace - self._records = defaultdict(set) + self.max_auto_arpa = max_auto_arpa + self._records = defaultdict(list) def process_source_zone(self, desired, sources): for record in desired.records: @@ -37,7 +39,10 @@ class AutoArpa(BaseProcessor): for ip in ips: ptr = ip_address(ip).reverse_pointer - self._records[f'{ptr}.'].add(record.fqdn) + auto_arpa_priority = record.octodns.get('auto_arpa_priority', 999) + self._records[f'{ptr}.'].append((auto_arpa_priority, record.fqdn)) + unique_list = list(set(self._records[f'{ptr}.'])) + self._records[f'{ptr}.'] = unique_list return desired @@ -57,6 +62,9 @@ class AutoArpa(BaseProcessor): if arpa.endswith(f'.{zone_name}'): name = arpa[:-n] fqdns = sorted(fqdns) + fqdns = [d[1] for d in fqdns] + fqdns = fqdns[:self.max_auto_arpa] + record = Record.new( zone, name, diff --git a/tests/test_octodns_processor_arpa.py b/tests/test_octodns_processor_arpa.py index 32fc49d..124ca0a 100644 --- a/tests/test_octodns_processor_arpa.py +++ b/tests/test_octodns_processor_arpa.py @@ -27,7 +27,7 @@ class TestAutoArpa(TestCase): aa = AutoArpa('auto-arpa') aa.process_source_zone(zone, []) self.assertEqual( - {'4.3.2.1.in-addr.arpa.': {'a.unit.tests.'}}, aa._records + {'4.3.2.1.in-addr.arpa.': [(999, 'a.unit.tests.')]}, aa._records ) # matching zone @@ -56,8 +56,8 @@ class TestAutoArpa(TestCase): aa.process_source_zone(zone, []) self.assertEqual( { - '4.3.2.1.in-addr.arpa.': {'a.unit.tests.'}, - '5.3.2.1.in-addr.arpa.': {'a.unit.tests.'}, + '4.3.2.1.in-addr.arpa.': [(999, 'a.unit.tests.')], + '5.3.2.1.in-addr.arpa.': [(999, 'a.unit.tests.')], }, aa._records, ) @@ -81,7 +81,7 @@ class TestAutoArpa(TestCase): aa = AutoArpa('auto-arpa') aa.process_source_zone(zone, []) ip6_arpa = '2.0.0.0.4.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.c.0.0.0.f.f.0.0.ip6.arpa.' - self.assertEqual({ip6_arpa: {'aaaa.unit.tests.'}}, aa._records) + self.assertEqual({ip6_arpa: [(999, 'aaaa.unit.tests.')]}, aa._records) # matching zone arpa = Zone('c.0.0.0.f.f.0.0.ip6.arpa.', []) @@ -117,13 +117,13 @@ class TestAutoArpa(TestCase): aa.process_source_zone(zone, []) self.assertEqual( { - '1.1.1.1.in-addr.arpa.': {'geo.unit.tests.'}, - '2.2.2.2.in-addr.arpa.': {'geo.unit.tests.'}, - '3.3.3.3.in-addr.arpa.': {'geo.unit.tests.'}, - '4.4.4.4.in-addr.arpa.': {'geo.unit.tests.'}, - '5.5.5.5.in-addr.arpa.': {'geo.unit.tests.'}, - '4.3.2.1.in-addr.arpa.': {'geo.unit.tests.'}, - '5.3.2.1.in-addr.arpa.': {'geo.unit.tests.'}, + '4.3.2.1.in-addr.arpa.': [(999, 'geo.unit.tests.')], + '5.3.2.1.in-addr.arpa.': [(999, 'geo.unit.tests.')], + '1.1.1.1.in-addr.arpa.': [(999, 'geo.unit.tests.')], + '2.2.2.2.in-addr.arpa.': [(999, 'geo.unit.tests.')], + '3.3.3.3.in-addr.arpa.': [(999, 'geo.unit.tests.')], + '4.4.4.4.in-addr.arpa.': [(999, 'geo.unit.tests.')], + '5.5.5.5.in-addr.arpa.': [(999, 'geo.unit.tests.')] }, aa._records, ) @@ -167,11 +167,11 @@ class TestAutoArpa(TestCase): aa.process_source_zone(zone, []) self.assertEqual( { - '3.3.3.3.in-addr.arpa.': {'dynamic.unit.tests.'}, - '4.4.4.4.in-addr.arpa.': {'dynamic.unit.tests.'}, - '5.5.5.5.in-addr.arpa.': {'dynamic.unit.tests.'}, - '4.3.2.1.in-addr.arpa.': {'dynamic.unit.tests.'}, - '5.3.2.1.in-addr.arpa.': {'dynamic.unit.tests.'}, + '4.3.2.1.in-addr.arpa.': [(999, 'dynamic.unit.tests.')], + '5.3.2.1.in-addr.arpa.': [(999, 'dynamic.unit.tests.')], + '3.3.3.3.in-addr.arpa.': [(999, 'dynamic.unit.tests.')], + '4.4.4.4.in-addr.arpa.': [(999, 'dynamic.unit.tests.')], + '5.5.5.5.in-addr.arpa.': [(999, 'dynamic.unit.tests.')], }, aa._records, ) @@ -188,11 +188,13 @@ class TestAutoArpa(TestCase): zone.add_record(record2) aa = AutoArpa('auto-arpa') aa.process_source_zone(zone, []) + sorted_records = sorted(aa._records['4.3.2.1.in-addr.arpa.']) self.assertEqual( - {'4.3.2.1.in-addr.arpa.': {'a1.unit.tests.', 'a2.unit.tests.'}}, - aa._records, + {'4.3.2.1.in-addr.arpa.': [(999, 'a1.unit.tests.'), (999, 'a2.unit.tests.')]}, + {'4.3.2.1.in-addr.arpa.': sorted_records } ) + # matching zone arpa = Zone('3.2.1.in-addr.arpa.', []) aa.populate(arpa) @@ -211,7 +213,7 @@ class TestAutoArpa(TestCase): aa = AutoArpa('auto-arpa') aa.process_source_zone(zone, []) self.assertEqual( - {'4.3.20.10.in-addr.arpa.': {'a.unit.tests.'}}, aa._records + {'4.3.20.10.in-addr.arpa.': [(999, 'a.unit.tests.')]}, aa._records ) # matching zone @@ -251,7 +253,7 @@ class TestAutoArpa(TestCase): aa = AutoArpa('auto-arpa') aa.process_source_zone(zone, []) self.assertEqual( - {'4.3.2.1.in-addr.arpa.': {'a with spaces.unit.tests.'}}, + {'4.3.2.1.in-addr.arpa.': [(999, 'a with spaces.unit.tests.')]}, aa._records, ) @@ -263,3 +265,26 @@ class TestAutoArpa(TestCase): self.assertEqual('4.3.2.1.in-addr.arpa.', ptr.fqdn) self.assertEqual(record.fqdn, ptr.value) self.assertEqual(3600, ptr.ttl) + + def test_arpa_priority(self): + zone = Zone('unit.tests.', []) + record = Record.new( + zone, + 'a', + {'ttl': 32, 'type': 'A', 'value': '1.2.3.4'}, + ) + zone.add_record(record) + record2 = Record.new( + zone, + 'b', + {'ttl': 32, 'type': 'A', 'value': '1.2.3.4', 'octodns': { 'auto_arpa_priority': 1}}, + ) + zone.add_record(record2) + + aa = AutoArpa('auto-arpa', ttl=1600, populate_should_replace=False, max_auto_arpa=1) + aa.process_source_zone(zone, []) + + arpa = Zone('3.2.1.in-addr.arpa.', []) + aa.populate(arpa) + (ptr), = arpa.records + self.assertEqual(record2.fqdn, ptr.value) From f26b7c1a43ee4348238445beb68b6134d7a7c1ab Mon Sep 17 00:00:00 2001 From: William Gauthier Date: Wed, 17 Apr 2024 22:39:27 +0200 Subject: [PATCH 2/6] Make things unique in populate instead of process_source_zone --- octodns/processor/arpa.py | 3 +-- tests/test_octodns_processor_arpa.py | 1 + 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/octodns/processor/arpa.py b/octodns/processor/arpa.py index 1e121eb..7df1d1e 100644 --- a/octodns/processor/arpa.py +++ b/octodns/processor/arpa.py @@ -41,8 +41,6 @@ class AutoArpa(BaseProcessor): ptr = ip_address(ip).reverse_pointer auto_arpa_priority = record.octodns.get('auto_arpa_priority', 999) self._records[f'{ptr}.'].append((auto_arpa_priority, record.fqdn)) - unique_list = list(set(self._records[f'{ptr}.'])) - self._records[f'{ptr}.'] = unique_list return desired @@ -61,6 +59,7 @@ class AutoArpa(BaseProcessor): for arpa, fqdns in self._records.items(): if arpa.endswith(f'.{zone_name}'): name = arpa[:-n] + fqdns = list(set(fqdns)) fqdns = sorted(fqdns) fqdns = [d[1] for d in fqdns] fqdns = fqdns[:self.max_auto_arpa] diff --git a/tests/test_octodns_processor_arpa.py b/tests/test_octodns_processor_arpa.py index 124ca0a..7152857 100644 --- a/tests/test_octodns_processor_arpa.py +++ b/tests/test_octodns_processor_arpa.py @@ -165,6 +165,7 @@ class TestAutoArpa(TestCase): zone.add_record(record) aa = AutoArpa('auto-arpa') aa.process_source_zone(zone, []) + aa._records = list(set(aa._records)) self.assertEqual( { '4.3.2.1.in-addr.arpa.': [(999, 'dynamic.unit.tests.')], From aa85f7e533385ae87fd8c3bfb54c04682699fdcb Mon Sep 17 00:00:00 2001 From: William Gauthier Date: Thu, 18 Apr 2024 16:46:52 +0200 Subject: [PATCH 3/6] Added suggestions from comments --- octodns/processor/arpa.py | 21 +++++++++--- tests/test_octodns_processor_arpa.py | 48 +++++++++++----------------- 2 files changed, 34 insertions(+), 35 deletions(-) diff --git a/octodns/processor/arpa.py b/octodns/processor/arpa.py index 7df1d1e..1acbc59 100644 --- a/octodns/processor/arpa.py +++ b/octodns/processor/arpa.py @@ -44,6 +44,20 @@ class AutoArpa(BaseProcessor): return desired + def _order_and_unique_fqdns(self, fqdns, max_auto_arpa): + fqdns = sorted(fqdns) + seen = set() + ordered = sorted(fqdns) + fqdns = [] + for _, fqdn in ordered: + if fqdn in seen: + continue + fqdns.append(fqdn) + seen.add(fqdn) + if len(seen) >= max_auto_arpa: + break + return fqdns + def populate(self, zone, target=False, lenient=False): self.log.debug( 'populate: name=%s, target=%s, lenient=%s', @@ -59,11 +73,8 @@ class AutoArpa(BaseProcessor): for arpa, fqdns in self._records.items(): if arpa.endswith(f'.{zone_name}'): name = arpa[:-n] - fqdns = list(set(fqdns)) - fqdns = sorted(fqdns) - fqdns = [d[1] for d in fqdns] - fqdns = fqdns[:self.max_auto_arpa] - + # Note: this takes a list of (priority, fqdn) tuples and returns the ordered and uniqified list of fqdns. + fqdns = self._order_and_unique_fqdns(fqdns, self.max_auto_arpa) record = Record.new( zone, name, diff --git a/tests/test_octodns_processor_arpa.py b/tests/test_octodns_processor_arpa.py index 7152857..d8eddd0 100644 --- a/tests/test_octodns_processor_arpa.py +++ b/tests/test_octodns_processor_arpa.py @@ -165,17 +165,13 @@ class TestAutoArpa(TestCase): zone.add_record(record) aa = AutoArpa('auto-arpa') aa.process_source_zone(zone, []) - aa._records = list(set(aa._records)) - self.assertEqual( - { - '4.3.2.1.in-addr.arpa.': [(999, 'dynamic.unit.tests.')], - '5.3.2.1.in-addr.arpa.': [(999, 'dynamic.unit.tests.')], - '3.3.3.3.in-addr.arpa.': [(999, 'dynamic.unit.tests.')], - '4.4.4.4.in-addr.arpa.': [(999, 'dynamic.unit.tests.')], - '5.5.5.5.in-addr.arpa.': [(999, 'dynamic.unit.tests.')], - }, - aa._records, - ) + zones = ['4.3.2.1.in-addr.arpa.', '5.3.2.1.in-addr.arpa.', '3.3.3.3.in-addr.arpa.', '4.4.4.4.in-addr.arpa.', '5.5.5.5.in-addr.arpa.'] + for zone in zones: + unique_values = aa._order_and_unique_fqdns(aa._records[f'{zone}'], 999) + self.assertEqual( + [('dynamic.unit.tests.')], + unique_values + ) def test_multiple_names(self): zone = Zone('unit.tests.', []) @@ -268,24 +264,16 @@ class TestAutoArpa(TestCase): self.assertEqual(3600, ptr.ttl) def test_arpa_priority(self): - zone = Zone('unit.tests.', []) - record = Record.new( - zone, - 'a', - {'ttl': 32, 'type': 'A', 'value': '1.2.3.4'}, - ) - zone.add_record(record) - record2 = Record.new( - zone, - 'b', - {'ttl': 32, 'type': 'A', 'value': '1.2.3.4', 'octodns': { 'auto_arpa_priority': 1}}, - ) - zone.add_record(record2) + aa = AutoArpa('auto-arpa') - aa = AutoArpa('auto-arpa', ttl=1600, populate_should_replace=False, max_auto_arpa=1) - aa.process_source_zone(zone, []) + duplicate_values = [(999, 'a.unit.tests.'), (1, 'a.unit.tests.')] + self.assertEqual(['a.unit.tests.'], aa._order_and_unique_fqdns(duplicate_values, max_auto_arpa=999)) - arpa = Zone('3.2.1.in-addr.arpa.', []) - aa.populate(arpa) - (ptr), = arpa.records - self.assertEqual(record2.fqdn, ptr.value) + duplicate_values_2 = [(999, 'a.unit.tests.'), (999, 'a.unit.tests.')] + self.assertEqual(['a.unit.tests.'], aa._order_and_unique_fqdns(duplicate_values_2, max_auto_arpa=999)) + + ordered_values = [(999, 'a.unit.tests.'), (1, 'b.unit.tests.')] + self.assertEqual(['b.unit.tests.', 'a.unit.tests.'], aa._order_and_unique_fqdns(ordered_values, max_auto_arpa=999)) + + max_one_value = [(999, 'a.unit.tests.'), (1, 'b.unit.tests.')] + self.assertEqual(['b.unit.tests.'], aa._order_and_unique_fqdns(max_one_value, max_auto_arpa=1)) From a84ad6fe44d7034459e6e719e4991400374e5607 Mon Sep 17 00:00:00 2001 From: Ross McFarland Date: Thu, 18 Apr 2024 08:03:38 -0700 Subject: [PATCH 4/6] Fix auto arpa formatting --- octodns/processor/arpa.py | 14 ++++++--- tests/test_octodns_processor_arpa.py | 47 ++++++++++++++++++++-------- 2 files changed, 44 insertions(+), 17 deletions(-) diff --git a/octodns/processor/arpa.py b/octodns/processor/arpa.py index 1acbc59..3b98761 100644 --- a/octodns/processor/arpa.py +++ b/octodns/processor/arpa.py @@ -11,14 +11,16 @@ from .base import BaseProcessor class AutoArpa(BaseProcessor): - def __init__(self, name, ttl=3600, populate_should_replace=False, max_auto_arpa=999): + def __init__( + self, name, ttl=3600, populate_should_replace=False, max_auto_arpa=999 + ): super().__init__(name) self.log = getLogger(f'AutoArpa[{name}]') self.log.info( '__init__: ttl=%d, populate_should_replace=%s, max_auto_arpa=%d', ttl, populate_should_replace, - max_auto_arpa + max_auto_arpa, ) self.ttl = ttl self.populate_should_replace = populate_should_replace @@ -39,8 +41,12 @@ class AutoArpa(BaseProcessor): for ip in ips: ptr = ip_address(ip).reverse_pointer - auto_arpa_priority = record.octodns.get('auto_arpa_priority', 999) - self._records[f'{ptr}.'].append((auto_arpa_priority, record.fqdn)) + auto_arpa_priority = record.octodns.get( + 'auto_arpa_priority', 999 + ) + self._records[f'{ptr}.'].append( + (auto_arpa_priority, record.fqdn) + ) return desired diff --git a/tests/test_octodns_processor_arpa.py b/tests/test_octodns_processor_arpa.py index d8eddd0..ccdb70f 100644 --- a/tests/test_octodns_processor_arpa.py +++ b/tests/test_octodns_processor_arpa.py @@ -123,7 +123,7 @@ class TestAutoArpa(TestCase): '2.2.2.2.in-addr.arpa.': [(999, 'geo.unit.tests.')], '3.3.3.3.in-addr.arpa.': [(999, 'geo.unit.tests.')], '4.4.4.4.in-addr.arpa.': [(999, 'geo.unit.tests.')], - '5.5.5.5.in-addr.arpa.': [(999, 'geo.unit.tests.')] + '5.5.5.5.in-addr.arpa.': [(999, 'geo.unit.tests.')], }, aa._records, ) @@ -165,13 +165,18 @@ class TestAutoArpa(TestCase): zone.add_record(record) aa = AutoArpa('auto-arpa') aa.process_source_zone(zone, []) - zones = ['4.3.2.1.in-addr.arpa.', '5.3.2.1.in-addr.arpa.', '3.3.3.3.in-addr.arpa.', '4.4.4.4.in-addr.arpa.', '5.5.5.5.in-addr.arpa.'] + zones = [ + '4.3.2.1.in-addr.arpa.', + '5.3.2.1.in-addr.arpa.', + '3.3.3.3.in-addr.arpa.', + '4.4.4.4.in-addr.arpa.', + '5.5.5.5.in-addr.arpa.', + ] for zone in zones: - unique_values = aa._order_and_unique_fqdns(aa._records[f'{zone}'], 999) - self.assertEqual( - [('dynamic.unit.tests.')], - unique_values + unique_values = aa._order_and_unique_fqdns( + aa._records[f'{zone}'], 999 ) + self.assertEqual([('dynamic.unit.tests.')], unique_values) def test_multiple_names(self): zone = Zone('unit.tests.', []) @@ -187,11 +192,15 @@ class TestAutoArpa(TestCase): aa.process_source_zone(zone, []) sorted_records = sorted(aa._records['4.3.2.1.in-addr.arpa.']) self.assertEqual( - {'4.3.2.1.in-addr.arpa.': [(999, 'a1.unit.tests.'), (999, 'a2.unit.tests.')]}, - {'4.3.2.1.in-addr.arpa.': sorted_records } + { + '4.3.2.1.in-addr.arpa.': [ + (999, 'a1.unit.tests.'), + (999, 'a2.unit.tests.'), + ] + }, + {'4.3.2.1.in-addr.arpa.': sorted_records}, ) - # matching zone arpa = Zone('3.2.1.in-addr.arpa.', []) aa.populate(arpa) @@ -267,13 +276,25 @@ class TestAutoArpa(TestCase): aa = AutoArpa('auto-arpa') duplicate_values = [(999, 'a.unit.tests.'), (1, 'a.unit.tests.')] - self.assertEqual(['a.unit.tests.'], aa._order_and_unique_fqdns(duplicate_values, max_auto_arpa=999)) + self.assertEqual( + ['a.unit.tests.'], + aa._order_and_unique_fqdns(duplicate_values, max_auto_arpa=999), + ) duplicate_values_2 = [(999, 'a.unit.tests.'), (999, 'a.unit.tests.')] - self.assertEqual(['a.unit.tests.'], aa._order_and_unique_fqdns(duplicate_values_2, max_auto_arpa=999)) + self.assertEqual( + ['a.unit.tests.'], + aa._order_and_unique_fqdns(duplicate_values_2, max_auto_arpa=999), + ) ordered_values = [(999, 'a.unit.tests.'), (1, 'b.unit.tests.')] - self.assertEqual(['b.unit.tests.', 'a.unit.tests.'], aa._order_and_unique_fqdns(ordered_values, max_auto_arpa=999)) + self.assertEqual( + ['b.unit.tests.', 'a.unit.tests.'], + aa._order_and_unique_fqdns(ordered_values, max_auto_arpa=999), + ) max_one_value = [(999, 'a.unit.tests.'), (1, 'b.unit.tests.')] - self.assertEqual(['b.unit.tests.'], aa._order_and_unique_fqdns(max_one_value, max_auto_arpa=1)) + self.assertEqual( + ['b.unit.tests.'], + aa._order_and_unique_fqdns(max_one_value, max_auto_arpa=1), + ) From 16a6bb4f8ad1eb7c044ece9600e9d775a23ac18d Mon Sep 17 00:00:00 2001 From: Ross McFarland Date: Thu, 18 Apr 2024 08:08:00 -0700 Subject: [PATCH 5/6] Remove duplicative sort and add a more robust test. --- octodns/processor/arpa.py | 2 +- tests/test_octodns_processor_arpa.py | 17 +++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/octodns/processor/arpa.py b/octodns/processor/arpa.py index 3b98761..bd56ec9 100644 --- a/octodns/processor/arpa.py +++ b/octodns/processor/arpa.py @@ -51,8 +51,8 @@ class AutoArpa(BaseProcessor): return desired def _order_and_unique_fqdns(self, fqdns, max_auto_arpa): - fqdns = sorted(fqdns) seen = set() + # order the fqdns making a copy so we can reset the list below ordered = sorted(fqdns) fqdns = [] for _, fqdn in ordered: diff --git a/tests/test_octodns_processor_arpa.py b/tests/test_octodns_processor_arpa.py index ccdb70f..328d05f 100644 --- a/tests/test_octodns_processor_arpa.py +++ b/tests/test_octodns_processor_arpa.py @@ -281,6 +281,23 @@ class TestAutoArpa(TestCase): aa._order_and_unique_fqdns(duplicate_values, max_auto_arpa=999), ) + duplicate_values = [ + (50, 'd.unit.tests.'), + (999, 'dup.unit.tests.'), + (3, 'a.unit.tests.'), + (1, 'dup.unit.tests.'), + (2, 'c.unit.tests.'), + ] + self.assertEqual( + [ + 'dup.unit.tests.', + 'c.unit.tests.', + 'a.unit.tests.', + 'd.unit.tests.', + ], + aa._order_and_unique_fqdns(duplicate_values, max_auto_arpa=999), + ) + duplicate_values_2 = [(999, 'a.unit.tests.'), (999, 'a.unit.tests.')] self.assertEqual( ['a.unit.tests.'], From a2c3c453594df61286fe13052758e2f4640b1e81 Mon Sep 17 00:00:00 2001 From: Ross McFarland Date: Thu, 18 Apr 2024 08:12:05 -0700 Subject: [PATCH 6/6] AutoArpa prioritization changelog entry --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e10c072..b8f99c1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ * Support for specifying per-zone change thresholds, to allow for zones where lots of changes are expected frequently to live along side zones where little or no churn is expected. +* AutoArpa gained support for prioritizing values ## v1.6.1 - 2024-03-17 - Didn't we do this already