Browse Source

Merge branch 'master' into zones-aliases

pull/592/head
Jonathan Leroy 5 years ago
committed by GitHub
parent
commit
04a2d7a585
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 94 additions and 31 deletions
  1. +1
    -0
      docs/records.md
  2. +2
    -2
      octodns/provider/yaml.py
  3. +10
    -0
      octodns/record/__init__.py
  4. +5
    -0
      tests/config/split/unit.tests./dname.yaml
  5. +4
    -0
      tests/config/unit.tests.yaml
  6. +7
    -7
      tests/test_octodns_manager.py
  7. +1
    -1
      tests/test_octodns_provider_constellix.py
  8. +1
    -1
      tests/test_octodns_provider_digitalocean.py
  9. +1
    -1
      tests/test_octodns_provider_dnsimple.py
  10. +1
    -1
      tests/test_octodns_provider_dnsmadeeasy.py
  11. +1
    -1
      tests/test_octodns_provider_easydns.py
  12. +2
    -2
      tests/test_octodns_provider_powerdns.py
  13. +12
    -11
      tests/test_octodns_provider_yaml.py
  14. +46
    -4
      tests/test_octodns_record.py

+ 1
- 0
docs/records.md View File

@ -7,6 +7,7 @@ OctoDNS supports the following record types:
* `A` * `A`
* `AAAA` * `AAAA`
* `CNAME` * `CNAME`
* `DNAME`
* `MX` * `MX`
* `NAPTR` * `NAPTR`
* `NS` * `NS`


+ 2
- 2
octodns/provider/yaml.py View File

@ -104,8 +104,8 @@ class YamlProvider(BaseProvider):
''' '''
SUPPORTS_GEO = True SUPPORTS_GEO = True
SUPPORTS_DYNAMIC = True SUPPORTS_DYNAMIC = True
SUPPORTS = set(('A', 'AAAA', 'ALIAS', 'CAA', 'CNAME', 'MX', 'NAPTR', 'NS',
'PTR', 'SSHFP', 'SPF', 'SRV', 'TXT'))
SUPPORTS = set(('A', 'AAAA', 'ALIAS', 'CAA', 'CNAME', 'DNAME', 'MX',
'NAPTR', 'NS', 'PTR', 'SSHFP', 'SPF', 'SRV', 'TXT'))
def __init__(self, id, directory, default_ttl=3600, enforce_order=True, def __init__(self, id, directory, default_ttl=3600, enforce_order=True,
populate_should_replace=False, *args, **kwargs): populate_should_replace=False, *args, **kwargs):


+ 10
- 0
octodns/record/__init__.py View File

@ -95,6 +95,7 @@ class Record(EqualityTupleMixin):
'ALIAS': AliasRecord, 'ALIAS': AliasRecord,
'CAA': CaaRecord, 'CAA': CaaRecord,
'CNAME': CnameRecord, 'CNAME': CnameRecord,
'DNAME': DnameRecord,
'MX': MxRecord, 'MX': MxRecord,
'NAPTR': NaptrRecord, 'NAPTR': NaptrRecord,
'NS': NsRecord, 'NS': NsRecord,
@ -759,6 +760,10 @@ class CnameValue(_TargetValue):
pass pass
class DnameValue(_TargetValue):
pass
class ARecord(_DynamicMixin, _GeoMixin, Record): class ARecord(_DynamicMixin, _GeoMixin, Record):
_type = 'A' _type = 'A'
_value_type = Ipv4List _value_type = Ipv4List
@ -842,6 +847,11 @@ class CnameRecord(_DynamicMixin, _ValueMixin, Record):
return reasons return reasons
class DnameRecord(_DynamicMixin, _ValueMixin, Record):
_type = 'DNAME'
_value_type = DnameValue
class MxValue(EqualityTupleMixin): class MxValue(EqualityTupleMixin):
@classmethod @classmethod


+ 5
- 0
tests/config/split/unit.tests./dname.yaml View File

@ -0,0 +1,5 @@
---
dname:
ttl: 300
type: DNAME
value: unit.tests.

+ 4
- 0
tests/config/unit.tests.yaml View File

@ -56,6 +56,10 @@ cname:
ttl: 300 ttl: 300
type: CNAME type: CNAME
value: unit.tests. value: unit.tests.
dname:
ttl: 300
type: DNAME
value: unit.tests.
excluded: excluded:
octodns: octodns:
excluded: excluded:


+ 7
- 7
tests/test_octodns_manager.py View File

@ -118,12 +118,12 @@ class TestManager(TestCase):
environ['YAML_TMP_DIR'] = tmpdir.dirname environ['YAML_TMP_DIR'] = tmpdir.dirname
tc = Manager(get_config_filename('simple.yaml')) \ tc = Manager(get_config_filename('simple.yaml')) \
.sync(dry_run=False) .sync(dry_run=False)
self.assertEquals(21, tc)
self.assertEquals(22, tc)
# try with just one of the zones # try with just one of the zones
tc = Manager(get_config_filename('simple.yaml')) \ tc = Manager(get_config_filename('simple.yaml')) \
.sync(dry_run=False, eligible_zones=['unit.tests.']) .sync(dry_run=False, eligible_zones=['unit.tests.'])
self.assertEquals(15, tc)
self.assertEquals(16, tc)
# the subzone, with 2 targets # the subzone, with 2 targets
tc = Manager(get_config_filename('simple.yaml')) \ tc = Manager(get_config_filename('simple.yaml')) \
@ -138,18 +138,18 @@ class TestManager(TestCase):
# Again with force # Again with force
tc = Manager(get_config_filename('simple.yaml')) \ tc = Manager(get_config_filename('simple.yaml')) \
.sync(dry_run=False, force=True) .sync(dry_run=False, force=True)
self.assertEquals(21, tc)
self.assertEquals(22, tc)
# Again with max_workers = 1 # Again with max_workers = 1
tc = Manager(get_config_filename('simple.yaml'), max_workers=1) \ tc = Manager(get_config_filename('simple.yaml'), max_workers=1) \
.sync(dry_run=False, force=True) .sync(dry_run=False, force=True)
self.assertEquals(21, tc)
self.assertEquals(22, tc)
# Include meta # Include meta
tc = Manager(get_config_filename('simple.yaml'), max_workers=1, tc = Manager(get_config_filename('simple.yaml'), max_workers=1,
include_meta=True) \ include_meta=True) \
.sync(dry_run=False, force=True) .sync(dry_run=False, force=True)
self.assertEquals(25, tc)
self.assertEquals(26, tc)
def test_eligible_sources(self): def test_eligible_sources(self):
with TemporaryDirectory() as tmpdir: with TemporaryDirectory() as tmpdir:
@ -183,13 +183,13 @@ class TestManager(TestCase):
fh.write('---\n{}') fh.write('---\n{}')
changes = manager.compare(['in'], ['dump'], 'unit.tests.') changes = manager.compare(['in'], ['dump'], 'unit.tests.')
self.assertEquals(15, len(changes))
self.assertEquals(16, len(changes))
# Compound sources with varying support # Compound sources with varying support
changes = manager.compare(['in', 'nosshfp'], changes = manager.compare(['in', 'nosshfp'],
['dump'], ['dump'],
'unit.tests.') 'unit.tests.')
self.assertEquals(14, len(changes))
self.assertEquals(15, len(changes))
with self.assertRaises(ManagerException) as ctx: with self.assertRaises(ManagerException) as ctx:
manager.compare(['nope'], ['dump'], 'unit.tests.') manager.compare(['nope'], ['dump'], 'unit.tests.')


+ 1
- 1
tests/test_octodns_provider_constellix.py View File

@ -138,7 +138,7 @@ class TestConstellixProvider(TestCase):
plan = provider.plan(self.expected) plan = provider.plan(self.expected)
# No root NS, no ignored, no excluded, no unsupported # No root NS, no ignored, no excluded, no unsupported
n = len(self.expected.records) - 5
n = len(self.expected.records) - 6
self.assertEquals(n, len(plan.changes)) self.assertEquals(n, len(plan.changes))
self.assertEquals(n, provider.apply(plan)) self.assertEquals(n, provider.apply(plan))


+ 1
- 1
tests/test_octodns_provider_digitalocean.py View File

@ -163,7 +163,7 @@ class TestDigitalOceanProvider(TestCase):
plan = provider.plan(self.expected) plan = provider.plan(self.expected)
# No root NS, no ignored, no excluded, no unsupported # No root NS, no ignored, no excluded, no unsupported
n = len(self.expected.records) - 7
n = len(self.expected.records) - 8
self.assertEquals(n, len(plan.changes)) self.assertEquals(n, len(plan.changes))
self.assertEquals(n, provider.apply(plan)) self.assertEquals(n, provider.apply(plan))
self.assertFalse(plan.exists) self.assertFalse(plan.exists)


+ 1
- 1
tests/test_octodns_provider_dnsimple.py View File

@ -137,7 +137,7 @@ class TestDnsimpleProvider(TestCase):
plan = provider.plan(self.expected) plan = provider.plan(self.expected)
# No root NS, no ignored, no excluded # No root NS, no ignored, no excluded
n = len(self.expected.records) - 3
n = len(self.expected.records) - 4
self.assertEquals(n, len(plan.changes)) self.assertEquals(n, len(plan.changes))
self.assertEquals(n, provider.apply(plan)) self.assertEquals(n, provider.apply(plan))
self.assertFalse(plan.exists) self.assertFalse(plan.exists)


+ 1
- 1
tests/test_octodns_provider_dnsmadeeasy.py View File

@ -140,7 +140,7 @@ class TestDnsMadeEasyProvider(TestCase):
plan = provider.plan(self.expected) plan = provider.plan(self.expected)
# No root NS, no ignored, no excluded, no unsupported # No root NS, no ignored, no excluded, no unsupported
n = len(self.expected.records) - 5
n = len(self.expected.records) - 6
self.assertEquals(n, len(plan.changes)) self.assertEquals(n, len(plan.changes))
self.assertEquals(n, provider.apply(plan)) self.assertEquals(n, provider.apply(plan))


+ 1
- 1
tests/test_octodns_provider_easydns.py View File

@ -374,7 +374,7 @@ class TestEasyDNSProvider(TestCase):
plan = provider.plan(self.expected) plan = provider.plan(self.expected)
# No root NS, no ignored, no excluded, no unsupported # No root NS, no ignored, no excluded, no unsupported
n = len(self.expected.records) - 6
n = len(self.expected.records) - 7
self.assertEquals(n, len(plan.changes)) self.assertEquals(n, len(plan.changes))
self.assertEquals(n, provider.apply(plan)) self.assertEquals(n, provider.apply(plan))
self.assertFalse(plan.exists) self.assertFalse(plan.exists)


+ 2
- 2
tests/test_octodns_provider_powerdns.py View File

@ -171,7 +171,7 @@ class TestPowerDnsProvider(TestCase):
expected = Zone('unit.tests.', []) expected = Zone('unit.tests.', [])
source = YamlProvider('test', join(dirname(__file__), 'config')) source = YamlProvider('test', join(dirname(__file__), 'config'))
source.populate(expected) source.populate(expected)
expected_n = len(expected.records) - 2
expected_n = len(expected.records) - 3
self.assertEquals(16, expected_n) self.assertEquals(16, expected_n)
# No diffs == no changes # No diffs == no changes
@ -277,7 +277,7 @@ class TestPowerDnsProvider(TestCase):
expected = Zone('unit.tests.', []) expected = Zone('unit.tests.', [])
source = YamlProvider('test', join(dirname(__file__), 'config')) source = YamlProvider('test', join(dirname(__file__), 'config'))
source.populate(expected) source.populate(expected)
self.assertEquals(18, len(expected.records))
self.assertEquals(19, len(expected.records))
# A small change to a single record # A small change to a single record
with requests_mock() as mock: with requests_mock() as mock:


+ 12
- 11
tests/test_octodns_provider_yaml.py View File

@ -35,7 +35,7 @@ class TestYamlProvider(TestCase):
# without it we see everything # without it we see everything
source.populate(zone) source.populate(zone)
self.assertEquals(18, len(zone.records))
self.assertEquals(19, len(zone.records))
source.populate(dynamic_zone) source.populate(dynamic_zone)
self.assertEquals(5, len(dynamic_zone.records)) self.assertEquals(5, len(dynamic_zone.records))
@ -58,12 +58,12 @@ class TestYamlProvider(TestCase):
# We add everything # We add everything
plan = target.plan(zone) plan = target.plan(zone)
self.assertEquals(15, len([c for c in plan.changes
self.assertEquals(16, len([c for c in plan.changes
if isinstance(c, Create)])) if isinstance(c, Create)]))
self.assertFalse(isfile(yaml_file)) self.assertFalse(isfile(yaml_file))
# Now actually do it # Now actually do it
self.assertEquals(15, target.apply(plan))
self.assertEquals(16, target.apply(plan))
self.assertTrue(isfile(yaml_file)) self.assertTrue(isfile(yaml_file))
# Dynamic plan # Dynamic plan
@ -87,7 +87,7 @@ class TestYamlProvider(TestCase):
# A 2nd sync should still create everything # A 2nd sync should still create everything
plan = target.plan(zone) plan = target.plan(zone)
self.assertEquals(15, len([c for c in plan.changes
self.assertEquals(16, len([c for c in plan.changes
if isinstance(c, Create)])) if isinstance(c, Create)]))
with open(yaml_file) as fh: with open(yaml_file) as fh:
@ -109,6 +109,7 @@ class TestYamlProvider(TestCase):
# these are stored as singular 'value' # these are stored as singular 'value'
self.assertTrue('value' in data.pop('aaaa')) self.assertTrue('value' in data.pop('aaaa'))
self.assertTrue('value' in data.pop('cname')) self.assertTrue('value' in data.pop('cname'))
self.assertTrue('value' in data.pop('dname'))
self.assertTrue('value' in data.pop('included')) self.assertTrue('value' in data.pop('included'))
self.assertTrue('value' in data.pop('ptr')) self.assertTrue('value' in data.pop('ptr'))
self.assertTrue('value' in data.pop('spf')) self.assertTrue('value' in data.pop('spf'))
@ -237,7 +238,7 @@ class TestSplitYamlProvider(TestCase):
# without it we see everything # without it we see everything
source.populate(zone) source.populate(zone)
self.assertEquals(18, len(zone.records))
self.assertEquals(19, len(zone.records))
source.populate(dynamic_zone) source.populate(dynamic_zone)
self.assertEquals(5, len(dynamic_zone.records)) self.assertEquals(5, len(dynamic_zone.records))
@ -251,12 +252,12 @@ class TestSplitYamlProvider(TestCase):
# We add everything # We add everything
plan = target.plan(zone) plan = target.plan(zone)
self.assertEquals(15, len([c for c in plan.changes
self.assertEquals(16, len([c for c in plan.changes
if isinstance(c, Create)])) if isinstance(c, Create)]))
self.assertFalse(isdir(zone_dir)) self.assertFalse(isdir(zone_dir))
# Now actually do it # Now actually do it
self.assertEquals(15, target.apply(plan))
self.assertEquals(16, target.apply(plan))
# Dynamic plan # Dynamic plan
plan = target.plan(dynamic_zone) plan = target.plan(dynamic_zone)
@ -279,7 +280,7 @@ class TestSplitYamlProvider(TestCase):
# A 2nd sync should still create everything # A 2nd sync should still create everything
plan = target.plan(zone) plan = target.plan(zone)
self.assertEquals(15, len([c for c in plan.changes
self.assertEquals(16, len([c for c in plan.changes
if isinstance(c, Create)])) if isinstance(c, Create)]))
yaml_file = join(zone_dir, '$unit.tests.yaml') yaml_file = join(zone_dir, '$unit.tests.yaml')
@ -302,8 +303,8 @@ class TestSplitYamlProvider(TestCase):
self.assertTrue('values' in data.pop(record_name)) self.assertTrue('values' in data.pop(record_name))
# These are stored as singular "value." Again, check each file. # These are stored as singular "value." Again, check each file.
for record_name in ('aaaa', 'cname', 'included', 'ptr', 'spf',
'www.sub', 'www'):
for record_name in ('aaaa', 'cname', 'dname', 'included', 'ptr',
'spf', 'www.sub', 'www'):
yaml_file = join(zone_dir, '{}.yaml'.format(record_name)) yaml_file = join(zone_dir, '{}.yaml'.format(record_name))
self.assertTrue(isfile(yaml_file)) self.assertTrue(isfile(yaml_file))
with open(yaml_file) as fh: with open(yaml_file) as fh:
@ -387,7 +388,7 @@ class TestOverridingYamlProvider(TestCase):
base.populate(zone) base.populate(zone)
got = {r.name: r for r in zone.records} got = {r.name: r for r in zone.records}
self.assertEquals(5, len(got)) self.assertEquals(5, len(got))
# We get the "dynamic" A from the bae config
# We get the "dynamic" A from the base config
self.assertTrue('dynamic' in got['a'].data) self.assertTrue('dynamic' in got['a'].data)
# No added # No added
self.assertFalse('added' in got) self.assertFalse('added' in got)


+ 46
- 4
tests/test_octodns_record.py View File

@ -9,10 +9,10 @@ from six import text_type
from unittest import TestCase from unittest import TestCase
from octodns.record import ARecord, AaaaRecord, AliasRecord, CaaRecord, \ from octodns.record import ARecord, AaaaRecord, AliasRecord, CaaRecord, \
CaaValue, CnameRecord, Create, Delete, GeoValue, MxRecord, MxValue, \
NaptrRecord, NaptrValue, NsRecord, PtrRecord, Record, SshfpRecord, \
SshfpValue, SpfRecord, SrvRecord, SrvValue, TxtRecord, Update, \
ValidationError, _Dynamic, _DynamicPool, _DynamicRule
CaaValue, CnameRecord, DnameRecord, Create, Delete, GeoValue, MxRecord, \
MxValue, NaptrRecord, NaptrValue, NsRecord, PtrRecord, Record, \
SshfpRecord, SshfpValue, SpfRecord, SrvRecord, SrvValue, TxtRecord, \
Update, ValidationError, _Dynamic, _DynamicPool, _DynamicRule
from octodns.zone import Zone from octodns.zone import Zone
from helpers import DynamicProvider, GeoProvider, SimpleProvider from helpers import DynamicProvider, GeoProvider, SimpleProvider
@ -55,6 +55,19 @@ class TestRecord(TestCase):
}) })
self.assertEquals(upper_record.value, lower_record.value) self.assertEquals(upper_record.value, lower_record.value)
def test_dname_lowering_value(self):
upper_record = DnameRecord(self.zone, 'DnameUppwerValue', {
'ttl': 30,
'type': 'DNAME',
'value': 'GITHUB.COM',
})
lower_record = DnameRecord(self.zone, 'DnameLowerValue', {
'ttl': 30,
'type': 'DNAME',
'value': 'github.com',
})
self.assertEquals(upper_record.value, lower_record.value)
def test_ptr_lowering_value(self): def test_ptr_lowering_value(self):
upper_record = PtrRecord(self.zone, 'PtrUppwerValue', { upper_record = PtrRecord(self.zone, 'PtrUppwerValue', {
'ttl': 30, 'ttl': 30,
@ -362,6 +375,10 @@ class TestRecord(TestCase):
self.assertSingleValue(CnameRecord, 'target.foo.com.', self.assertSingleValue(CnameRecord, 'target.foo.com.',
'other.foo.com.') 'other.foo.com.')
def test_dname(self):
self.assertSingleValue(DnameRecord, 'target.foo.com.',
'other.foo.com.')
def test_mx(self): def test_mx(self):
a_values = [{ a_values = [{
'preference': 10, 'preference': 10,
@ -1825,6 +1842,31 @@ class TestRecordValidation(TestCase):
self.assertEquals(['CNAME value "foo.bar.com" missing trailing .'], self.assertEquals(['CNAME value "foo.bar.com" missing trailing .'],
ctx.exception.reasons) ctx.exception.reasons)
def test_DNAME(self):
# A valid DNAME record.
Record.new(self.zone, 'sub', {
'type': 'DNAME',
'ttl': 600,
'value': 'foo.bar.com.',
})
# A DNAME record can be present at the zone APEX.
Record.new(self.zone, '', {
'type': 'DNAME',
'ttl': 600,
'value': 'foo.bar.com.',
})
# missing trailing .
with self.assertRaises(ValidationError) as ctx:
Record.new(self.zone, 'www', {
'type': 'DNAME',
'ttl': 600,
'value': 'foo.bar.com',
})
self.assertEquals(['DNAME value "foo.bar.com" missing trailing .'],
ctx.exception.reasons)
def test_MX(self): def test_MX(self):
# doesn't blow up # doesn't blow up
Record.new(self.zone, '', { Record.new(self.zone, '', {


Loading…
Cancel
Save