From 0659eda451ed4d8240016ea4f38e21e8ffb1e897 Mon Sep 17 00:00:00 2001 From: Ross McFarland Date: Sat, 6 Jan 2018 16:53:11 -0800 Subject: [PATCH 1/2] Add Cloudflare ALIAS record support Translates them to/from root CNAME --- README.md | 2 +- octodns/provider/cloudflare.py | 14 +++++++- tests/test_octodns_provider_cloudflare.py | 42 +++++++++++++++++++++++ 3 files changed, 56 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 88223e6..cc84cf2 100644 --- a/README.md +++ b/README.md @@ -150,7 +150,7 @@ The above command pulled the existing data out of Route53 and placed the results | Provider | Record Support | GeoDNS Support | Notes | |--|--|--|--| | [AzureProvider](/octodns/provider/azuredns.py) | A, AAAA, CNAME, MX, NS, PTR, SRV, TXT | No | | -| [CloudflareProvider](/octodns/provider/cloudflare.py) | A, AAAA, CAA, CNAME, MX, NS, SPF, TXT | No | CAA tags restricted | +| [CloudflareProvider](/octodns/provider/cloudflare.py) | A, AAAA, ALIAS, CAA, CNAME, MX, NS, SPF, TXT | No | CAA tags restricted | | [DigitalOceanProvider](/octodns/provider/digitalocean.py) | A, AAAA, CAA, CNAME, MX, NS, TXT, SRV | No | CAA tags restricted | | [DnsimpleProvider](/octodns/provider/dnsimple.py) | All | No | CAA tags restricted | | [DynProvider](/octodns/provider/dyn.py) | All | Yes | | diff --git a/octodns/provider/cloudflare.py b/octodns/provider/cloudflare.py index a7ec5d8..9dfef6d 100644 --- a/octodns/provider/cloudflare.py +++ b/octodns/provider/cloudflare.py @@ -37,7 +37,8 @@ class CloudflareProvider(BaseProvider): ''' SUPPORTS_GEO = False # TODO: support SRV - SUPPORTS = set(('A', 'AAAA', 'CAA', 'CNAME', 'MX', 'NS', 'SPF', 'TXT')) + SUPPORTS = set(('ALIAS', 'A', 'AAAA', 'CAA', 'CNAME', 'MX', 'NS', 'SPF', + 'TXT')) MIN_TTL = 120 TIMEOUT = 15 @@ -124,6 +125,8 @@ class CloudflareProvider(BaseProvider): 'value': '{}.'.format(only['content']) } + _data_for_ALIAS = _data_for_CNAME + def _data_for_MX(self, _type, records): values = [] for r in records: @@ -182,6 +185,11 @@ class CloudflareProvider(BaseProvider): for name, types in values.items(): for _type, records in types.items(): + + # Cloudflare supports ALIAS semantics with root CNAMEs + if _type == 'CNAME' and name == '': + _type = 'ALIAS' + data_for = getattr(self, '_data_for_{}'.format(_type)) data = data_for(_type, records) record = Record.new(zone, name, data, source=self, @@ -238,6 +246,10 @@ class CloudflareProvider(BaseProvider): _type = record._type ttl = max(self.MIN_TTL, record.ttl) + # Cloudflare supports ALIAS semantics with a root CNAME + if _type == 'ALIAS': + _type = 'CNAME' + contents_for = getattr(self, '_contents_for_{}'.format(_type)) for content in contents_for(record): content.update({ diff --git a/tests/test_octodns_provider_cloudflare.py b/tests/test_octodns_provider_cloudflare.py index 8a17083..824af9d 100644 --- a/tests/test_octodns_provider_cloudflare.py +++ b/tests/test_octodns_provider_cloudflare.py @@ -442,3 +442,45 @@ class TestCloudflareProvider(TestCase): call('DELETE', '/zones/ff12ab34cd5611334422ab3322997650/' 'dns_records/fc12ab34cd5611334422ab3322997653') ]) + + def test_alias(self): + provider = CloudflareProvider('test', 'email', 'token') + + # A CNAME for us to transform to ALIAS + provider.zone_records = Mock(return_value=[ + { + "id": "fc12ab34cd5611334422ab3322997642", + "type": "CNAME", + "name": "unit.tests", + "content": "www.unit.tests", + "proxiable": True, + "proxied": False, + "ttl": 300, + "locked": False, + "zone_id": "ff12ab34cd5611334422ab3322997650", + "zone_name": "unit.tests", + "modified_on": "2017-03-11T18:01:43.420689Z", + "created_on": "2017-03-11T18:01:43.420689Z", + "meta": { + "auto_added": False + } + }, + ]) + + zone = Zone('unit.tests.', []) + provider.populate(zone) + self.assertEquals(1, len(zone.records)) + record = list(zone.records)[0] + self.assertEquals('', record.name) + self.assertEquals('unit.tests.', record.fqdn) + self.assertEquals('ALIAS', record._type) + self.assertEquals('www.unit.tests.', record.value) + + # Make sure we transform back to CNAME going the other way + contents = provider._gen_contents(record) + self.assertEquals({ + 'content': u'www.unit.tests.', + 'name': 'unit.tests', + 'ttl': 300, + 'type': 'CNAME' + }, list(contents)[0]) From fdea900537cec8fced3120003c338ccd1fe6aead Mon Sep 17 00:00:00 2001 From: Ross McFarland Date: Sat, 6 Jan 2018 16:53:34 -0800 Subject: [PATCH 2/2] Correct total_count in Cloudflare record fixtures --- tests/fixtures/cloudflare-dns_records-page-1.json | 2 +- tests/fixtures/cloudflare-dns_records-page-2.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/fixtures/cloudflare-dns_records-page-1.json b/tests/fixtures/cloudflare-dns_records-page-1.json index eda4de3..3c423e2 100644 --- a/tests/fixtures/cloudflare-dns_records-page-1.json +++ b/tests/fixtures/cloudflare-dns_records-page-1.json @@ -180,7 +180,7 @@ "per_page": 10, "total_pages": 2, "count": 10, - "total_count": 17 + "total_count": 19 }, "success": true, "errors": [], diff --git a/tests/fixtures/cloudflare-dns_records-page-2.json b/tests/fixtures/cloudflare-dns_records-page-2.json index 150951b..de3d760 100644 --- a/tests/fixtures/cloudflare-dns_records-page-2.json +++ b/tests/fixtures/cloudflare-dns_records-page-2.json @@ -163,7 +163,7 @@ "per_page": 10, "total_pages": 2, "count": 9, - "total_count": 20 + "total_count": 19 }, "success": true, "errors": [],