mirror of
https://github.com/github/octodns.git
synced 2024-05-11 05:55:00 +00:00
Add support for included and excluded records
`Included` and `Excluded` can be used to filter records for one or more specific provider(s). This can be extremely useful when certain record types are not supported by a provider and you want only that provider to receive an alternative record. See also: https://github.com/github/octodns/issues/26
This commit is contained in:
@@ -124,6 +124,8 @@ class Record(object):
|
|||||||
|
|
||||||
octodns = data.get('octodns', {})
|
octodns = data.get('octodns', {})
|
||||||
self.ignored = octodns.get('ignored', False)
|
self.ignored = octodns.get('ignored', False)
|
||||||
|
self.excluded = octodns.get('excluded', [])
|
||||||
|
self.included = octodns.get('included', [])
|
||||||
|
|
||||||
def _data(self):
|
def _data(self):
|
||||||
return {'ttl': self.ttl}
|
return {'ttl': self.ttl}
|
||||||
|
@@ -110,10 +110,29 @@ class Zone(object):
|
|||||||
for record in filter(_is_eligible, self.records):
|
for record in filter(_is_eligible, self.records):
|
||||||
if record.ignored:
|
if record.ignored:
|
||||||
continue
|
continue
|
||||||
|
elif len(record.included) > 0 and \
|
||||||
|
target.__class__.__name__ not in record.included:
|
||||||
|
self.log.debug('changes: skipping record=%s %s - %s not'
|
||||||
|
' included ', record.fqdn, record._type,
|
||||||
|
target.id)
|
||||||
|
continue
|
||||||
|
elif target.__class__.__name__ in record.excluded:
|
||||||
|
self.log.debug('changes: skipping record=%s %s - %s '
|
||||||
|
'excluded ', record.fqdn, record._type,
|
||||||
|
target.id)
|
||||||
|
continue
|
||||||
try:
|
try:
|
||||||
desired_record = desired_records[record]
|
desired_record = desired_records[record]
|
||||||
if desired_record.ignored:
|
if desired_record.ignored:
|
||||||
continue
|
continue
|
||||||
|
elif len(record.included) > 0 and \
|
||||||
|
target.__class__.__name__ not in record.included:
|
||||||
|
self.log.debug('changes: skipping record=%s %s - %s'
|
||||||
|
'not included ', record.fqdn, record._type,
|
||||||
|
target.id)
|
||||||
|
continue
|
||||||
|
elif target.__class__.__name__ in record.excluded:
|
||||||
|
continue
|
||||||
except KeyError:
|
except KeyError:
|
||||||
if not target.supports(record):
|
if not target.supports(record):
|
||||||
self.log.debug('changes: skipping record=%s %s - %s does '
|
self.log.debug('changes: skipping record=%s %s - %s does '
|
||||||
@@ -141,6 +160,18 @@ class Zone(object):
|
|||||||
for record in filter(_is_eligible, desired.records - self.records):
|
for record in filter(_is_eligible, desired.records - self.records):
|
||||||
if record.ignored:
|
if record.ignored:
|
||||||
continue
|
continue
|
||||||
|
elif len(record.included) > 0 and \
|
||||||
|
target.__class__.__name__ not in record.included:
|
||||||
|
self.log.debug('changes: skipping record=%s %s - %s not'
|
||||||
|
' included ', record.fqdn, record._type,
|
||||||
|
target.id)
|
||||||
|
continue
|
||||||
|
elif target.__class__.__name__ in record.excluded:
|
||||||
|
self.log.debug('changes: skipping record=%s %s - %s '
|
||||||
|
'excluded ', record.fqdn, record._type,
|
||||||
|
target.id)
|
||||||
|
continue
|
||||||
|
|
||||||
if not target.supports(record):
|
if not target.supports(record):
|
||||||
self.log.debug('changes: skipping record=%s %s - %s does not '
|
self.log.debug('changes: skipping record=%s %s - %s does not '
|
||||||
'support it', record.fqdn, record._type,
|
'support it', record.fqdn, record._type,
|
||||||
|
@@ -56,11 +56,23 @@ cname:
|
|||||||
ttl: 300
|
ttl: 300
|
||||||
type: CNAME
|
type: CNAME
|
||||||
value: unit.tests.
|
value: unit.tests.
|
||||||
|
excluded:
|
||||||
|
octodns:
|
||||||
|
excluded:
|
||||||
|
- CloudflareProvider
|
||||||
|
type: CNAME
|
||||||
|
value: excluded.unit.tests.
|
||||||
ignored:
|
ignored:
|
||||||
octodns:
|
octodns:
|
||||||
ignored: true
|
ignored: true
|
||||||
type: A
|
type: A
|
||||||
value: 9.9.9.9
|
value: 9.9.9.9
|
||||||
|
included:
|
||||||
|
octodns:
|
||||||
|
included:
|
||||||
|
- DnsimpleProvider
|
||||||
|
type: CNAME
|
||||||
|
value: included.unit.tests.
|
||||||
mx:
|
mx:
|
||||||
ttl: 300
|
ttl: 300
|
||||||
type: MX
|
type: MX
|
||||||
|
32
tests/fixtures/dnsimple-page-2.json
vendored
32
tests/fixtures/dnsimple-page-2.json
vendored
@@ -175,6 +175,38 @@
|
|||||||
"system_record": false,
|
"system_record": false,
|
||||||
"created_at": "2017-03-09T15:55:09Z",
|
"created_at": "2017-03-09T15:55:09Z",
|
||||||
"updated_at": "2017-03-09T15:55:09Z"
|
"updated_at": "2017-03-09T15:55:09Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 12188804,
|
||||||
|
"zone_id": "unit.tests",
|
||||||
|
"parent_id": null,
|
||||||
|
"name": "excluded",
|
||||||
|
"content": "excluded.unit.tests",
|
||||||
|
"ttl": 3600,
|
||||||
|
"priority": null,
|
||||||
|
"type": "CNAME",
|
||||||
|
"regions": [
|
||||||
|
"global"
|
||||||
|
],
|
||||||
|
"system_record": false,
|
||||||
|
"created_at": "2017-03-09T15:55:09Z",
|
||||||
|
"updated_at": "2017-03-09T15:55:09Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 12188805,
|
||||||
|
"zone_id": "unit.tests",
|
||||||
|
"parent_id": null,
|
||||||
|
"name": "included",
|
||||||
|
"content": "included.unit.tests",
|
||||||
|
"ttl": 3600,
|
||||||
|
"priority": null,
|
||||||
|
"type": "CNAME",
|
||||||
|
"regions": [
|
||||||
|
"global"
|
||||||
|
],
|
||||||
|
"system_record": false,
|
||||||
|
"created_at": "2017-03-09T15:55:09Z",
|
||||||
|
"updated_at": "2017-03-09T15:55:09Z"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"pagination": {
|
"pagination": {
|
||||||
|
12
tests/fixtures/powerdns-full-data.json
vendored
12
tests/fixtures/powerdns-full-data.json
vendored
@@ -242,6 +242,18 @@
|
|||||||
],
|
],
|
||||||
"ttl": 3600,
|
"ttl": 3600,
|
||||||
"type": "CAA"
|
"type": "CAA"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"comments": [],
|
||||||
|
"name": "excluded.unit.tests.",
|
||||||
|
"records": [
|
||||||
|
{
|
||||||
|
"content": "excluded.unit.tests.",
|
||||||
|
"disabled": false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"ttl": 3600,
|
||||||
|
"type": "CNAME"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"serial": 2017012803,
|
"serial": 2017012803,
|
||||||
|
@@ -101,12 +101,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(19, tc)
|
self.assertEquals(20, 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(13, tc)
|
self.assertEquals(14, 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')) \
|
||||||
@@ -121,18 +121,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(19, tc)
|
self.assertEquals(20, 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(19, tc)
|
self.assertEquals(20, 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(23, tc)
|
self.assertEquals(24, tc)
|
||||||
|
|
||||||
def test_eligible_targets(self):
|
def test_eligible_targets(self):
|
||||||
with TemporaryDirectory() as tmpdir:
|
with TemporaryDirectory() as tmpdir:
|
||||||
@@ -158,13 +158,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(13, len(changes))
|
self.assertEquals(14, 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(12, len(changes))
|
self.assertEquals(13, len(changes))
|
||||||
|
|
||||||
with self.assertRaises(Exception) as ctx:
|
with self.assertRaises(Exception) as ctx:
|
||||||
manager.compare(['nope'], ['dump'], 'unit.tests.')
|
manager.compare(['nope'], ['dump'], 'unit.tests.')
|
||||||
|
@@ -78,14 +78,14 @@ class TestDnsimpleProvider(TestCase):
|
|||||||
|
|
||||||
zone = Zone('unit.tests.', [])
|
zone = Zone('unit.tests.', [])
|
||||||
provider.populate(zone)
|
provider.populate(zone)
|
||||||
self.assertEquals(15, len(zone.records))
|
self.assertEquals(17, len(zone.records))
|
||||||
changes = self.expected.changes(zone, provider)
|
changes = self.expected.changes(zone, provider)
|
||||||
self.assertEquals(0, len(changes))
|
self.assertEquals(0, len(changes))
|
||||||
|
|
||||||
# 2nd populate makes no network calls/all from cache
|
# 2nd populate makes no network calls/all from cache
|
||||||
again = Zone('unit.tests.', [])
|
again = Zone('unit.tests.', [])
|
||||||
provider.populate(again)
|
provider.populate(again)
|
||||||
self.assertEquals(15, len(again.records))
|
self.assertEquals(17, len(again.records))
|
||||||
|
|
||||||
# bust the cache
|
# bust the cache
|
||||||
del provider._zone_records[zone.name]
|
del provider._zone_records[zone.name]
|
||||||
@@ -147,7 +147,7 @@ class TestDnsimpleProvider(TestCase):
|
|||||||
}),
|
}),
|
||||||
])
|
])
|
||||||
# expected number of total calls
|
# expected number of total calls
|
||||||
self.assertEquals(27, provider._client._request.call_count)
|
self.assertEquals(29, provider._client._request.call_count)
|
||||||
|
|
||||||
provider._client._request.reset_mock()
|
provider._client._request.reset_mock()
|
||||||
|
|
||||||
|
@@ -78,8 +78,8 @@ 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) - 1
|
expected_n = len(expected.records) - 2
|
||||||
self.assertEquals(15, expected_n)
|
self.assertEquals(16, expected_n)
|
||||||
|
|
||||||
# No diffs == no changes
|
# No diffs == no changes
|
||||||
with requests_mock() as mock:
|
with requests_mock() as mock:
|
||||||
@@ -87,7 +87,7 @@ class TestPowerDnsProvider(TestCase):
|
|||||||
|
|
||||||
zone = Zone('unit.tests.', [])
|
zone = Zone('unit.tests.', [])
|
||||||
provider.populate(zone)
|
provider.populate(zone)
|
||||||
self.assertEquals(15, len(zone.records))
|
self.assertEquals(16, len(zone.records))
|
||||||
changes = expected.changes(zone, provider)
|
changes = expected.changes(zone, provider)
|
||||||
self.assertEquals(0, len(changes))
|
self.assertEquals(0, len(changes))
|
||||||
|
|
||||||
@@ -167,7 +167,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(16, len(expected.records))
|
self.assertEquals(18, 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:
|
||||||
|
@@ -30,7 +30,7 @@ class TestYamlProvider(TestCase):
|
|||||||
|
|
||||||
# without it we see everything
|
# without it we see everything
|
||||||
source.populate(zone)
|
source.populate(zone)
|
||||||
self.assertEquals(16, len(zone.records))
|
self.assertEquals(18, len(zone.records))
|
||||||
|
|
||||||
# Assumption here is that a clean round-trip means that everything
|
# Assumption here is that a clean round-trip means that everything
|
||||||
# worked as expected, data that went in came back out and could be
|
# worked as expected, data that went in came back out and could be
|
||||||
@@ -49,12 +49,12 @@ class TestYamlProvider(TestCase):
|
|||||||
|
|
||||||
# We add everything
|
# We add everything
|
||||||
plan = target.plan(zone)
|
plan = target.plan(zone)
|
||||||
self.assertEquals(13, len(filter(lambda c: isinstance(c, Create),
|
self.assertEquals(14, len(filter(lambda c: isinstance(c, Create),
|
||||||
plan.changes)))
|
plan.changes)))
|
||||||
self.assertFalse(isfile(yaml_file))
|
self.assertFalse(isfile(yaml_file))
|
||||||
|
|
||||||
# Now actually do it
|
# Now actually do it
|
||||||
self.assertEquals(13, target.apply(plan))
|
self.assertEquals(14, target.apply(plan))
|
||||||
self.assertTrue(isfile(yaml_file))
|
self.assertTrue(isfile(yaml_file))
|
||||||
|
|
||||||
# There should be no changes after the round trip
|
# There should be no changes after the round trip
|
||||||
@@ -64,7 +64,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(13, len(filter(lambda c: isinstance(c, Create),
|
self.assertEquals(14, len(filter(lambda c: isinstance(c, Create),
|
||||||
plan.changes)))
|
plan.changes)))
|
||||||
|
|
||||||
with open(yaml_file) as fh:
|
with open(yaml_file) as fh:
|
||||||
|
Reference in New Issue
Block a user