Browse Source

Merge pull request #753 from octodns/acme-ignoring-processor-with-ownership

Allow octoDNS managed _acme-challenge records to exist by marking them
pull/751/head
Ross McFarland 4 years ago
committed by GitHub
parent
commit
203468b370
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 88 additions and 21 deletions
  1. +20
    -5
      octodns/processor/acme.py
  2. +68
    -16
      tests/test_octodns_processor_acme.py

+ 20
- 5
octodns/processor/acme.py View File

@ -16,18 +16,33 @@ class AcmeIgnoringProcessor(BaseProcessor):
def __init__(self, name): def __init__(self, name):
super(AcmeIgnoringProcessor, self).__init__(name) super(AcmeIgnoringProcessor, self).__init__(name)
def _process(self, zone, *args, **kwargs):
self._owned = set()
def process_source_zone(self, zone, *args, **kwargs):
ret = self._clone_zone(zone)
for record in zone.records:
if record._type == 'TXT' and \
record.name.startswith('_acme-challenge'):
# We have a managed acme challenge record (owned by octoDNS) so
# we should mark it as such
record = record.copy()
record.values.append('*octoDNS*')
record.values.sort()
self._owned.add(record)
ret.add_record(record)
return ret
def process_target_zone(self, zone, *args, **kwargs):
ret = self._clone_zone(zone) ret = self._clone_zone(zone)
for record in zone.records: for record in zone.records:
# Uses a startswith rather than == to ignore subdomain challenges, # Uses a startswith rather than == to ignore subdomain challenges,
# e.g. _acme-challenge.foo.domain.com when managing domain.com # e.g. _acme-challenge.foo.domain.com when managing domain.com
if record._type == 'TXT' and \ if record._type == 'TXT' and \
record.name.startswith('_acme-challenge'):
record.name.startswith('_acme-challenge') and \
'*octoDNS*' not in record.values and \
record not in self._owned:
self.log.info('_process: ignoring %s', record.fqdn) self.log.info('_process: ignoring %s', record.fqdn)
continue continue
ret.add_record(record) ret.add_record(record)
return ret return ret
process_source_zone = _process
process_target_zone = _process

+ 68
- 16
tests/test_octodns_processor_acme.py View File

@ -12,40 +12,92 @@ from octodns.record import Record
from octodns.zone import Zone from octodns.zone import Zone
zone = Zone('unit.tests.', []) zone = Zone('unit.tests.', [])
for record in [
# Will be ignored
Record.new(zone, '_acme-challenge', {
records = {
'root-unowned': Record.new(zone, '_acme-challenge', {
'ttl': 30, 'ttl': 30,
'type': 'TXT', 'type': 'TXT',
'value': 'magic bit', 'value': 'magic bit',
}), }),
# Not TXT so will live
Record.new(zone, '_acme-challenge.aaaa', {
'sub-unowned': Record.new(zone, '_acme-challenge.sub-unowned', {
'ttl': 30,
'type': 'TXT',
'value': 'magic bit',
}),
'not-txt': Record.new(zone, '_acme-challenge.not-txt', {
'ttl': 30, 'ttl': 30,
'type': 'AAAA', 'type': 'AAAA',
'value': '::1', 'value': '::1',
}), }),
# Will be ignored
Record.new(zone, '_acme-challenge.foo', {
'not-acme': Record.new(zone, 'not-acme', {
'ttl': 30,
'type': 'TXT',
'value': 'Hello World!',
}),
'managed': Record.new(zone, '_acme-challenge.managed', {
'ttl': 30, 'ttl': 30,
'type': 'TXT', 'type': 'TXT',
'value': 'magic bit', 'value': 'magic bit',
}), }),
# Not acme-challenge so will live
Record.new(zone, 'txt', {
'owned': Record.new(zone, '_acme-challenge.owned', {
'ttl': 30, 'ttl': 30,
'type': 'TXT', 'type': 'TXT',
'value': 'Hello World!',
'values': ['*octoDNS*', 'magic bit'],
}),
'going-away': Record.new(zone, '_acme-challenge.going-away', {
'ttl': 30,
'type': 'TXT',
'values': ['*octoDNS*', 'magic bit'],
}), }),
]:
zone.add_record(record)
}
class TestAcmeIgnoringProcessor(TestCase): class TestAcmeIgnoringProcessor(TestCase):
def test_basics(self):
def test_process_zones(self):
acme = AcmeIgnoringProcessor('acme') acme = AcmeIgnoringProcessor('acme')
got = acme.process_source_zone(zone)
self.assertEquals(['_acme-challenge.aaaa', 'txt'],
sorted([r.name for r in got.records]))
source = Zone(zone.name, [])
# Unrelated stuff that should be untouched
source.add_record(records['not-txt'])
source.add_record(records['not-acme'])
# A managed acme that will have ownership value added
source.add_record(records['managed'])
got = acme.process_source_zone(source)
self.assertEquals([
'_acme-challenge.managed',
'_acme-challenge.not-txt',
'not-acme',
], sorted([r.name for r in got.records]))
managed = None
for record in got.records:
print(record.name)
if record.name.endswith('managed'):
managed = record
break
self.assertTrue(managed)
# Ownership was marked with an extra value
self.assertEquals(['*octoDNS*', 'magic bit'], record.values)
existing = Zone(zone.name, [])
# Unrelated stuff that should be untouched
existing.add_record(records['not-txt'])
existing.add_record(records['not-acme'])
# Stuff that will be ignored
existing.add_record(records['root-unowned'])
existing.add_record(records['sub-unowned'])
# A managed acme that needs ownership value added
existing.add_record(records['managed'])
# A managed acme that has ownershp managed
existing.add_record(records['owned'])
# A managed acme that needs to go away
existing.add_record(records['going-away'])
got = acme.process_target_zone(existing)
self.assertEquals([
'_acme-challenge.going-away',
'_acme-challenge.managed',
'_acme-challenge.not-txt',
'_acme-challenge.owned',
'not-acme'
], sorted([r.name for r in got.records]))

Loading…
Cancel
Save