From 9f575374fab8882969c270d9321fc009e499205f Mon Sep 17 00:00:00 2001 From: Jon Simons Date: Tue, 24 Apr 2018 13:40:47 -0700 Subject: [PATCH 01/12] README.md: your -> you're typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5af8e62..39946c1 100644 --- a/README.md +++ b/README.md @@ -98,7 +98,7 @@ There will be other logging information presented on the screen, but successful ### Making changes -**WARNING**: OctoDNS assumes ownership of any domain you point it to. When you tell it to act it will do whatever is necessary to try and match up states including deleting any unexpected records. Be careful when playing around with OctoDNS. It's best to experiment with a fake zone or one without any data that matters until your comfortable with the system. +**WARNING**: OctoDNS assumes ownership of any domain you point it to. When you tell it to act it will do whatever is necessary to try and match up states including deleting any unexpected records. Be careful when playing around with OctoDNS. It's best to experiment with a fake zone or one without any data that matters until you're comfortable with the system. Now it's time to tell OctoDNS to make things happen. We'll invoke it again with the same options and add a `--doit` on the end to tell it this time we actually want it to try and make the specified changes. From ffbca09d8b92fdb3134823e827cb82c7805238ef Mon Sep 17 00:00:00 2001 From: Ross McFarland Date: Mon, 21 May 2018 19:03:15 -0700 Subject: [PATCH 02/12] 0.9.1 version bump and changelog update --- CHANGELOG.md | 6 +++++- octodns/__init__.py | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c3eaae6..6365545 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -## v0.9.1 - UNRELEASED +## v0.9.1 - 2018-05-21 - Going backwards with setup.py ### NOTICE @@ -11,6 +11,10 @@ all health checks are passing before the first sync with `--doit`. See * Major update to geo healthchecks to allow configuring host (header), path, protocol, and port [#67](https://github.com/github/octodns/pull/67) +* SSHFP algorithm type 4 +* NS1 and DNSimple support skipping unsupported record types +* Revert back to old style setup.py & requirements.txt, setup.cfg was + causing too much pita ## v0.9.0 - 2018-03-26 - Way too long since we last met diff --git a/octodns/__init__.py b/octodns/__init__.py index da72790..b45191a 100644 --- a/octodns/__init__.py +++ b/octodns/__init__.py @@ -3,4 +3,4 @@ from __future__ import absolute_import, division, print_function, \ unicode_literals -__VERSION__ = '0.9.0' +__VERSION__ = '0.9.1' From adf7154f6b8fe248757da490e7594c3b36f6055b Mon Sep 17 00:00:00 2001 From: Ross McFarland Date: Wed, 30 May 2018 12:22:35 -0700 Subject: [PATCH 03/12] TDD lenient add_record --- tests/test_octodns_zone.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/tests/test_octodns_zone.py b/tests/test_octodns_zone.py index 94faef3..e90f94c 100644 --- a/tests/test_octodns_zone.py +++ b/tests/test_octodns_zone.py @@ -139,9 +139,9 @@ class TestZone(TestCase): self.assertTrue('missing ending dot' in ctx.exception.message) def test_sub_zones(self): - zone = Zone('unit.tests.', set(['sub', 'barred'])) # NS for exactly the sub is allowed + zone = Zone('unit.tests.', set(['sub', 'barred'])) record = Record.new(zone, 'sub', { 'ttl': 3600, 'type': 'NS', @@ -151,6 +151,7 @@ class TestZone(TestCase): self.assertEquals(set([record]), zone.records) # non-NS for exactly the sub is rejected + zone = Zone('unit.tests.', set(['sub', 'barred'])) record = Record.new(zone, 'sub', { 'ttl': 3600, 'type': 'A', @@ -159,8 +160,12 @@ class TestZone(TestCase): with self.assertRaises(SubzoneRecordException) as ctx: zone.add_record(record) self.assertTrue('not of type NS', ctx.exception.message) + # Can add it w/lenient + zone.add_record(record, lenient=True) + self.assertEquals(set([record]), zone.records) # NS for something below the sub is rejected + zone = Zone('unit.tests.', set(['sub', 'barred'])) record = Record.new(zone, 'foo.sub', { 'ttl': 3600, 'type': 'NS', @@ -169,8 +174,12 @@ class TestZone(TestCase): with self.assertRaises(SubzoneRecordException) as ctx: zone.add_record(record) self.assertTrue('under a managed sub-zone', ctx.exception.message) + # Can add it w/lenient + zone.add_record(record, lenient=True) + self.assertEquals(set([record]), zone.records) # A for something below the sub is rejected + zone = Zone('unit.tests.', set(['sub', 'barred'])) record = Record.new(zone, 'foo.bar.sub', { 'ttl': 3600, 'type': 'A', @@ -179,6 +188,9 @@ class TestZone(TestCase): with self.assertRaises(SubzoneRecordException) as ctx: zone.add_record(record) self.assertTrue('under a managed sub-zone', ctx.exception.message) + # Can add it w/lenient + zone.add_record(record, lenient=True) + self.assertEquals(set([record]), zone.records) def test_ignored_records(self): zone_normal = Zone('unit.tests.', []) From 1103b4c383646178727382e9eef895ad07b32b71 Mon Sep 17 00:00:00 2001 From: Ross McFarland Date: Wed, 30 May 2018 12:30:20 -0700 Subject: [PATCH 04/12] Implement Zone.add_record lenient param/support and more tests --- CHANGELOG.md | 6 ++++++ octodns/zone.py | 8 ++++---- tests/test_octodns_zone.py | 6 ++++++ 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6365545..eebf7bc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## v0.9.2 - Unreleased + +* Add lenient support to Zone.add_record, allows populate from providers that + have allowed/created invalid data and situations where a sub-zone is being + extracted from a parent, but the records still exist in the remote provider. + ## v0.9.1 - 2018-05-21 - Going backwards with setup.py ### NOTICE diff --git a/octodns/zone.py b/octodns/zone.py index e4dc859..916f81b 100644 --- a/octodns/zone.py +++ b/octodns/zone.py @@ -56,11 +56,11 @@ class Zone(object): def hostname_from_fqdn(self, fqdn): return self._name_re.sub('', fqdn) - def add_record(self, record, replace=False): + def add_record(self, record, replace=False, lenient=False): name = record.name last = name.split('.')[-1] - if last in self.sub_zones: + if not lenient and last in self.sub_zones: if name != last: # it's a record for something under a sub-zone raise SubzoneRecordException('Record {} is under a ' @@ -82,8 +82,8 @@ class Zone(object): raise DuplicateRecordException('Duplicate record {}, type {}' .format(record.fqdn, record._type)) - elif ((record._type == 'CNAME' and len(node) > 0) or - ('CNAME' in map(lambda r: r._type, node))): + elif not lenient and (((record._type == 'CNAME' and len(node) > 0) or + ('CNAME' in map(lambda r: r._type, node)))): # We're adding a CNAME to existing records or adding to an existing # CNAME raise InvalidNodeException('Invalid state, CNAME at {} cannot ' diff --git a/tests/test_octodns_zone.py b/tests/test_octodns_zone.py index e90f94c..b371590 100644 --- a/tests/test_octodns_zone.py +++ b/tests/test_octodns_zone.py @@ -242,12 +242,18 @@ class TestZone(TestCase): zone.add_record(a) with self.assertRaises(InvalidNodeException): zone.add_record(cname) + self.assertEquals(set([a]), zone.records) + zone.add_record(cname, lenient=True) + self.assertEquals(set([a, cname]), zone.records) # add a to cname zone = Zone('unit.tests.', []) zone.add_record(cname) with self.assertRaises(InvalidNodeException): zone.add_record(a) + self.assertEquals(set([cname]), zone.records) + zone.add_record(a, lenient=True) + self.assertEquals(set([a, cname]), zone.records) def test_excluded_records(self): zone_normal = Zone('unit.tests.', []) From cee7677ae4738f2f5518dd1d13c0c98047b82f68 Mon Sep 17 00:00:00 2001 From: Ross McFarland Date: Wed, 30 May 2018 12:41:59 -0700 Subject: [PATCH 05/12] Implement Zone.add_record lenient across our providers --- octodns/provider/azuredns.py | 2 +- octodns/provider/cloudflare.py | 2 +- octodns/provider/digitalocean.py | 2 +- octodns/provider/dnsimple.py | 2 +- octodns/provider/dnsmadeeasy.py | 2 +- octodns/provider/dyn.py | 8 ++++---- octodns/provider/googlecloud.py | 2 +- octodns/provider/ns1.py | 2 +- octodns/provider/ovh.py | 2 +- octodns/provider/powerdns.py | 2 +- octodns/provider/rackspace.py | 2 +- octodns/provider/route53.py | 2 +- octodns/provider/yaml.py | 2 +- octodns/source/tinydns.py | 4 ++-- 14 files changed, 18 insertions(+), 18 deletions(-) diff --git a/octodns/provider/azuredns.py b/octodns/provider/azuredns.py index 1f14c4b..b3bff6c 100644 --- a/octodns/provider/azuredns.py +++ b/octodns/provider/azuredns.py @@ -345,7 +345,7 @@ class AzureProvider(BaseProvider): data['type'] = typ data['ttl'] = azrecord.ttl record = Record.new(zone, record_name, data, source=self) - zone.add_record(record) + zone.add_record(record, lenient=lenient) self.log.info('populate: found %s records, exists=%s', len(zone.records) - before, exists) diff --git a/octodns/provider/cloudflare.py b/octodns/provider/cloudflare.py index c51e61c..ecf3e3f 100644 --- a/octodns/provider/cloudflare.py +++ b/octodns/provider/cloudflare.py @@ -253,7 +253,7 @@ class CloudflareProvider(BaseProvider): self.log.info('CDN rewrite %s already in zone', name) continue - zone.add_record(record) + zone.add_record(record, lenient=lenient) self.log.info('populate: found %s records, exists=%s', len(zone.records) - before, exists) diff --git a/octodns/provider/digitalocean.py b/octodns/provider/digitalocean.py index e71e87f..84116a0 100644 --- a/octodns/provider/digitalocean.py +++ b/octodns/provider/digitalocean.py @@ -230,7 +230,7 @@ class DigitalOceanProvider(BaseProvider): data_for = getattr(self, '_data_for_{}'.format(_type)) record = Record.new(zone, name, data_for(_type, records), source=self, lenient=lenient) - zone.add_record(record) + zone.add_record(record, lenient=lenient) exists = zone.name in self._zone_records self.log.info('populate: found %s records, exists=%s', diff --git a/octodns/provider/dnsimple.py b/octodns/provider/dnsimple.py index b696f75..7a9db50 100644 --- a/octodns/provider/dnsimple.py +++ b/octodns/provider/dnsimple.py @@ -270,7 +270,7 @@ class DnsimpleProvider(BaseProvider): data_for = getattr(self, '_data_for_{}'.format(_type)) record = Record.new(zone, name, data_for(_type, records), source=self, lenient=lenient) - zone.add_record(record) + zone.add_record(record, lenient=lenient) exists = zone.name in self._zone_records self.log.info('populate: found %s records, exists=%s', diff --git a/octodns/provider/dnsmadeeasy.py b/octodns/provider/dnsmadeeasy.py index b439931..f8cee1c 100644 --- a/octodns/provider/dnsmadeeasy.py +++ b/octodns/provider/dnsmadeeasy.py @@ -263,7 +263,7 @@ class DnsMadeEasyProvider(BaseProvider): data_for = getattr(self, '_data_for_{}'.format(_type)) record = Record.new(zone, name, data_for(_type, records), source=self, lenient=lenient) - zone.add_record(record) + zone.add_record(record, lenient=lenient) exists = zone.name in self._zone_records self.log.info('populate: found %s records, exists=%s', diff --git a/octodns/provider/dyn.py b/octodns/provider/dyn.py index de430db..166227b 100644 --- a/octodns/provider/dyn.py +++ b/octodns/provider/dyn.py @@ -399,7 +399,7 @@ class DynProvider(BaseProvider): return self._traffic_directors - def _populate_traffic_directors(self, zone): + def _populate_traffic_directors(self, zone, lenient): self.log.debug('_populate_traffic_directors: zone=%s', zone.name) td_records = set() for fqdn, types in self.traffic_directors.items(): @@ -444,7 +444,7 @@ class DynProvider(BaseProvider): name = zone.hostname_from_fqdn(fqdn) record = Record.new(zone, name, data, source=self) - zone.add_record(record) + zone.add_record(record, lenient=lenient) td_records.add(record) return td_records @@ -460,7 +460,7 @@ class DynProvider(BaseProvider): td_records = set() if self.traffic_directors_enabled: - td_records = self._populate_traffic_directors(zone) + td_records = self._populate_traffic_directors(zone, lenient) exists = True dyn_zone = _CachingDynZone.get(zone.name[:-1]) @@ -483,7 +483,7 @@ class DynProvider(BaseProvider): record = Record.new(zone, name, data, source=self, lenient=lenient) if record not in td_records: - zone.add_record(record) + zone.add_record(record, lenient=lenient) self.log.info('populate: found %s records, exists=%s', len(zone.records) - before, exists) diff --git a/octodns/provider/googlecloud.py b/octodns/provider/googlecloud.py index 82a4fcf..74c17a4 100644 --- a/octodns/provider/googlecloud.py +++ b/octodns/provider/googlecloud.py @@ -230,7 +230,7 @@ class GoogleCloudProvider(BaseProvider): self.log.debug('populate: adding record {} records: {!s}' .format(record_name, data)) record = Record.new(zone, record_name, data, source=self) - zone.add_record(record) + zone.add_record(record, lenient=lenient) self.log.info('populate: found %s records, exists=%s', len(zone.records) - before, exists) diff --git a/octodns/provider/ns1.py b/octodns/provider/ns1.py index 37b8d77..31aff47 100644 --- a/octodns/provider/ns1.py +++ b/octodns/provider/ns1.py @@ -211,7 +211,7 @@ class Ns1Provider(BaseProvider): record = Record.new(zone, name, data_for(_type, record), source=self, lenient=lenient) zone_hash[(_type, name)] = record - [zone.add_record(r) for r in zone_hash.values()] + [zone.add_record(r, lenient=lenient) for r in zone_hash.values()] self.log.info('populate: found %s records, exists=%s', len(zone.records) - before, exists) return exists diff --git a/octodns/provider/ovh.py b/octodns/provider/ovh.py index ee1cef9..a74a3cd 100644 --- a/octodns/provider/ovh.py +++ b/octodns/provider/ovh.py @@ -82,7 +82,7 @@ class OvhProvider(BaseProvider): data_for = getattr(self, '_data_for_{}'.format(_type)) record = Record.new(zone, name, data_for(_type, records), source=self, lenient=lenient) - zone.add_record(record) + zone.add_record(record, lenient=lenient) self.log.info('populate: found %s records, exists=%s', len(zone.records) - before, exists) diff --git a/octodns/provider/powerdns.py b/octodns/provider/powerdns.py index 02319e5..30cd01e 100644 --- a/octodns/provider/powerdns.py +++ b/octodns/provider/powerdns.py @@ -199,7 +199,7 @@ class PowerDnsBaseProvider(BaseProvider): record_name = zone.hostname_from_fqdn(rrset['name']) record = Record.new(zone, record_name, data_for(rrset), source=self, lenient=lenient) - zone.add_record(record) + zone.add_record(record, lenient=lenient) self.log.info('populate: found %s records, exists=%s', len(zone.records) - before, exists) diff --git a/octodns/provider/rackspace.py b/octodns/provider/rackspace.py index b9912a3..d2b85f3 100644 --- a/octodns/provider/rackspace.py +++ b/octodns/provider/rackspace.py @@ -215,7 +215,7 @@ class RackspaceProvider(BaseProvider): record = Record.new(zone, record_name, data_for(record_set), source=self) - zone.add_record(record) + zone.add_record(record, lenient=lenient) self.log.info('populate: found %s records, exists=True', len(zone.records) - before) diff --git a/octodns/provider/route53.py b/octodns/provider/route53.py index 5fc0faa..502fa9f 100644 --- a/octodns/provider/route53.py +++ b/octodns/provider/route53.py @@ -489,7 +489,7 @@ class Route53Provider(BaseProvider): data = data[0] record = Record.new(zone, name, data, source=self, lenient=lenient) - zone.add_record(record) + zone.add_record(record, lenient=lenient) self.log.info('populate: found %s records, exists=%s', len(zone.records) - before, exists) diff --git a/octodns/provider/yaml.py b/octodns/provider/yaml.py index 0241d50..287fd3b 100644 --- a/octodns/provider/yaml.py +++ b/octodns/provider/yaml.py @@ -67,7 +67,7 @@ class YamlProvider(BaseProvider): d['ttl'] = self.default_ttl record = Record.new(zone, name, d, source=self, lenient=lenient) - zone.add_record(record) + zone.add_record(record, lenient=lenient) self.log.info('populate: found %s records, exists=False', len(zone.records) - before) diff --git a/octodns/source/tinydns.py b/octodns/source/tinydns.py index 8013cd4..7b06527 100644 --- a/octodns/source/tinydns.py +++ b/octodns/source/tinydns.py @@ -134,7 +134,7 @@ class TinyDnsBaseSource(BaseSource): record = Record.new(zone, name, data, source=self, lenient=lenient) try: - zone.add_record(record) + zone.add_record(record, lenient=lenient) except SubzoneRecordException: self.log.debug('_populate_normal: skipping subzone ' 'record=%s', record) @@ -175,7 +175,7 @@ class TinyDnsBaseSource(BaseSource): 'value': value }, source=self, lenient=lenient) try: - zone.add_record(record) + zone.add_record(record, lenient=lenient) except DuplicateRecordException: self.log.warn('Duplicate PTR record for {}, ' 'skipping'.format(addr)) From 206d77d5a6a9ac3e684a1e17c48e71148b28dc85 Mon Sep 17 00:00:00 2001 From: Ross McFarland Date: Wed, 30 May 2018 12:56:25 -0700 Subject: [PATCH 06/12] Include a provider test of populate w/lenient=True --- tests/test_octodns_provider_base.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/tests/test_octodns_provider_base.py b/tests/test_octodns_provider_base.py index d5ac5b3..22a0ee6 100644 --- a/tests/test_octodns_provider_base.py +++ b/tests/test_octodns_provider_base.py @@ -61,7 +61,7 @@ class TestBaseProvider(TestCase): class HasSupportsGeo(HasLog): SUPPORTS_GEO = False - zone = Zone('unit.tests.', []) + zone = Zone('unit.tests.', ['sub']) with self.assertRaises(NotImplementedError) as ctx: HasSupportsGeo('hassupportsgeo').populate(zone) self.assertEquals('Abstract base class, SUPPORTS property missing', @@ -81,12 +81,17 @@ class TestBaseProvider(TestCase): 'ttl': 60, 'type': 'A', 'value': '2.3.4.5' - })) + }), lenient=lenient) zone.add_record(Record.new(zone, 'going', { 'ttl': 60, 'type': 'A', 'value': '3.4.5.6' - })) + }), lenient=lenient) + zone.add_record(Record.new(zone, 'foo.sub', { + 'ttl': 61, + 'type': 'A', + 'value': '4.5.6.7' + }), lenient=lenient) zone.add_record(Record.new(zone, '', { 'ttl': 60, @@ -98,7 +103,7 @@ class TestBaseProvider(TestCase): .supports(list(zone.records)[0])) plan = HasPopulate('haspopulate').plan(zone) - self.assertEquals(2, len(plan.changes)) + self.assertEquals(3, len(plan.changes)) with self.assertRaises(NotImplementedError) as ctx: HasPopulate('haspopulate').apply(plan) From c54904fa68fd1afb8d29e7942cac7e73af66732d Mon Sep 17 00:00:00 2001 From: Ross McFarland Date: Wed, 30 May 2018 13:28:55 -0700 Subject: [PATCH 07/12] Apply sub-zones before parents --- octodns/manager.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/octodns/manager.py b/octodns/manager.py index 027df54..6497ff2 100644 --- a/octodns/manager.py +++ b/octodns/manager.py @@ -65,6 +65,13 @@ class MainThreadExecutor(object): class Manager(object): log = logging.getLogger('Manager') + @classmethod + def _plan_keyer(cls, p): + try: + return len(p[1].changes[0].record.zone.name) + except (AttributeError, IndexError): + return 0 + def __init__(self, config_file, max_workers=None, include_meta=False): self.log.info('__init__: config_file=%s', config_file) @@ -288,6 +295,13 @@ class Manager(object): # plan pairs. plans = [p for f in futures for p in f.result()] + # Best effort sort plans children first so that we create/update + # children zones before parents which should allow us to more safely + # extract things into sub-zones. Combining a child back into a parent + # can't really be done all that safely in general so we'll optimize for + # this direction. + plans.sort(key=self._plan_keyer, reverse=True) + for output in self.plan_outputs.values(): output.run(plans=plans, log=self.log) From b4176382b53f7309a53632fa115bda3c73cc3c94 Mon Sep 17 00:00:00 2001 From: Ross McFarland Date: Wed, 30 May 2018 13:35:19 -0700 Subject: [PATCH 08/12] Cleaner impl for _plan_keyer --- octodns/manager.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/octodns/manager.py b/octodns/manager.py index 6497ff2..c3fecf4 100644 --- a/octodns/manager.py +++ b/octodns/manager.py @@ -67,10 +67,8 @@ class Manager(object): @classmethod def _plan_keyer(cls, p): - try: - return len(p[1].changes[0].record.zone.name) - except (AttributeError, IndexError): - return 0 + plan = p[1] + return len(plan.changes[0].record.zone.name) if plan.changes else 0 def __init__(self, config_file, max_workers=None, include_meta=False): self.log.info('__init__: config_file=%s', config_file) From 446e8485b3e4b98ac456704aa23291cb672069e5 Mon Sep 17 00:00:00 2001 From: Adam Smith Date: Wed, 13 Jun 2018 21:18:21 -0700 Subject: [PATCH 09/12] if user does not explicitly set Access Key ID and Secret Access Key then use boto3's methods as fallback --- octodns/provider/route53.py | 19 ++++++++++++------- tests/test_octodns_provider_route53.py | 17 +++++++++++++++++ 2 files changed, 29 insertions(+), 7 deletions(-) diff --git a/octodns/provider/route53.py b/octodns/provider/route53.py index 502fa9f..afdebe1 100644 --- a/octodns/provider/route53.py +++ b/octodns/provider/route53.py @@ -232,12 +232,14 @@ class Route53Provider(BaseProvider): # health check config. HEALTH_CHECK_VERSION = '0001' - def __init__(self, id, access_key_id, secret_access_key, max_changes=1000, - client_max_attempts=None, *args, **kwargs): + def __init__(self, id, access_key_id=None, secret_access_key=None, + max_changes=1000, client_max_attempts=None, *args, **kwargs): self.max_changes = max_changes + _msg = 'access_key_id={}, secret_access_key=***'.format(access_key_id) + if access_key_id is None and secret_access_key is None: + _msg = 'auth=fallback' self.log = logging.getLogger('Route53Provider[{}]'.format(id)) - self.log.debug('__init__: id=%s, access_key_id=%s, ' - 'secret_access_key=***', id, access_key_id) + self.log.debug('__init__: id=%s, %s', id, _msg) super(Route53Provider, self).__init__(id, *args, **kwargs) config = None @@ -246,9 +248,12 @@ class Route53Provider(BaseProvider): client_max_attempts) config = Config(retries={'max_attempts': client_max_attempts}) - self._conn = client('route53', aws_access_key_id=access_key_id, - aws_secret_access_key=secret_access_key, - config=config) + if access_key_id is None and secret_access_key is None: + self._conn = client('route53', config=config) + else: + self._conn = client('route53', aws_access_key_id=access_key_id, + aws_secret_access_key=secret_access_key, + config=config) self._r53_zones = None self._r53_rrsets = {} diff --git a/tests/test_octodns_provider_route53.py b/tests/test_octodns_provider_route53.py index aec31cb..75ee991 100644 --- a/tests/test_octodns_provider_route53.py +++ b/tests/test_octodns_provider_route53.py @@ -167,6 +167,23 @@ class TestRoute53Provider(TestCase): return (provider, stubber) + def _get_stubbed_fallback_auth_provider(self): + provider = Route53Provider('test') + + # Use the stubber + stubber = Stubber(provider._conn) + stubber.activate() + + return (provider, stubber) + + def test_populate_with_fallback(self): + provider, stubber = self._get_stubbed_fallback_auth_provider() + + got = Zone('unit.tests.', []) + with self.assertRaises(ClientError): + stubber.add_client_error('list_hosted_zones') + provider.populate(got) + def test_populate(self): provider, stubber = self._get_stubbed_provider() From 16eda53eb37453336c5b1d6a06146725bf585a51 Mon Sep 17 00:00:00 2001 From: Adam Smith Date: Wed, 13 Jun 2018 21:24:29 -0700 Subject: [PATCH 10/12] add note about fallback authentication for route53 provider --- octodns/provider/route53.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/octodns/provider/route53.py b/octodns/provider/route53.py index afdebe1..50c734c 100644 --- a/octodns/provider/route53.py +++ b/octodns/provider/route53.py @@ -217,11 +217,14 @@ class Route53Provider(BaseProvider): route53: class: octodns.provider.route53.Route53Provider - # The AWS access key id (required) + # The AWS access key id access_key_id: - # The AWS secret access key (required) + # The AWS secret access key secret_access_key: + Alternatively, you may leave out access_key_id and secret_access_key, + this will result in boto3 deciding authentication dynamically. + In general the account used will need full permissions on Route53. ''' SUPPORTS_GEO = True From be6019f119142350c2bc7ce5c6e1eae8c9364b2f Mon Sep 17 00:00:00 2001 From: Adam Smith Date: Wed, 13 Jun 2018 22:29:16 -0700 Subject: [PATCH 11/12] change all answers from NS1 to absolute for types that require it --- octodns/provider/ns1.py | 9 +++++++++ tests/test_octodns_provider_ns1.py | 10 +++++----- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/octodns/provider/ns1.py b/octodns/provider/ns1.py index 31aff47..3ae6889 100644 --- a/octodns/provider/ns1.py +++ b/octodns/provider/ns1.py @@ -189,6 +189,15 @@ class Ns1Provider(BaseProvider): try: nsone_zone = self._client.loadZone(zone.name[:-1]) records = nsone_zone.data['records'] + + # change answers for certain types to always be absolute + for record in records: + if record['type'] in ['ALIAS', 'CNAME', 'MX', 'NS', 'PTR', + 'SRV']: + for i, a in enumerate(record['short_answers']): + if not a.endswith('.'): + record['short_answers'][i] = '{}.'.format(a) + geo_records = nsone_zone.search(has_geo=True) exists = True except ResourceException as e: diff --git a/tests/test_octodns_provider_ns1.py b/tests/test_octodns_provider_ns1.py index fc74e9e..8530b62 100644 --- a/tests/test_octodns_provider_ns1.py +++ b/tests/test_octodns_provider_ns1.py @@ -133,12 +133,12 @@ class TestNs1Provider(TestCase): }, { 'type': 'CNAME', 'ttl': 34, - 'short_answers': ['foo.unit.tests.'], + 'short_answers': ['foo.unit.tests'], 'domain': 'cname.unit.tests.', }, { 'type': 'MX', 'ttl': 35, - 'short_answers': ['10 mx1.unit.tests.', '20 mx2.unit.tests.'], + 'short_answers': ['10 mx1.unit.tests.', '20 mx2.unit.tests'], 'domain': 'unit.tests.', }, { 'type': 'NAPTR', @@ -151,18 +151,18 @@ class TestNs1Provider(TestCase): }, { 'type': 'NS', 'ttl': 37, - 'short_answers': ['ns1.unit.tests.', 'ns2.unit.tests.'], + 'short_answers': ['ns1.unit.tests.', 'ns2.unit.tests'], 'domain': 'unit.tests.', }, { 'type': 'SRV', 'ttl': 38, 'short_answers': ['12 30 30 foo-2.unit.tests.', - '10 20 30 foo-1.unit.tests.'], + '10 20 30 foo-1.unit.tests'], 'domain': '_srv._tcp.unit.tests.', }, { 'type': 'NS', 'ttl': 39, - 'short_answers': ['ns3.unit.tests.', 'ns4.unit.tests.'], + 'short_answers': ['ns3.unit.tests.', 'ns4.unit.tests'], 'domain': 'sub.unit.tests.', }, { 'type': 'CAA', From 18e644918b869b3255a4ef1680cd226350e931ae Mon Sep 17 00:00:00 2001 From: Adam Smith Date: Wed, 13 Jun 2018 23:29:47 -0700 Subject: [PATCH 12/12] fix formatting for base provider output --- octodns/provider/base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/octodns/provider/base.py b/octodns/provider/base.py index ada0c7a..2c93e49 100644 --- a/octodns/provider/base.py +++ b/octodns/provider/base.py @@ -17,7 +17,7 @@ class BaseProvider(BaseSource): delete_pcent_threshold=Plan.MAX_SAFE_DELETE_PCENT): super(BaseProvider, self).__init__(id) self.log.debug('__init__: id=%s, apply_disabled=%s, ' - 'update_pcent_threshold=%.2f' + 'update_pcent_threshold=%.2f, ' 'delete_pcent_threshold=%.2f', id, apply_disabled,