diff --git a/octodns/provider/cloudflare.py b/octodns/provider/cloudflare.py index 6a42668..b6df5c4 100644 --- a/octodns/provider/cloudflare.py +++ b/octodns/provider/cloudflare.py @@ -417,6 +417,24 @@ class CloudflareProvider(BaseProvider): # could be done atomically, but that's not available so we made the # best of it... + # However, there are record types like CNAME that can only have a + # single value. B/c of that our create and then delete approach isn't + # actually viable. To address this we'll convert as many creates & + # deletes as we can to updates. This will have a minor upside of + # resulting in fewer ops and in the case of things like CNAME where + # there's a single create and delete result in a single update instead. + create_keys = sorted(creates.keys()) + delete_keys = sorted(deletes.keys()) + for i in range(0, min(len(create_keys), len(delete_keys))): + create_key = create_keys[i] + create_data = creates.pop(create_key) + delete_info = deletes.pop(delete_keys[i]) + updates[create_key] = { + 'record_id': delete_info['record_id'], + 'data': create_data, + 'old_data': delete_info['data'], + } + # The sorts ensure a consistent order of operations, they're not # otherwise required, just makes things deterministic diff --git a/tests/test_octodns_provider_cloudflare.py b/tests/test_octodns_provider_cloudflare.py index 71a7e92..f03f87c 100644 --- a/tests/test_octodns_provider_cloudflare.py +++ b/tests/test_octodns_provider_cloudflare.py @@ -289,14 +289,13 @@ class TestCloudflareProvider(TestCase): self.assertTrue(plan.exists) # creates a the new value and then deletes all the old provider._request.assert_has_calls([ - call('POST', '/zones/42/dns_records', data={ - 'content': '3.2.3.4', - 'type': 'A', - 'name': 'ttl.unit.tests', - 'ttl': 300 - }), - call('DELETE', - '/zones/42/dns_records/fc12ab34cd5611334422ab3322997655'), + call('PUT', '/zones/42/dns_records/' + 'fc12ab34cd5611334422ab3322997655', data={ + 'content': '3.2.3.4', + 'type': 'A', + 'name': 'ttl.unit.tests', + 'ttl': 300 + }), call('DELETE', '/zones/ff12ab34cd5611334422ab3322997650/' 'dns_records/fc12ab34cd5611334422ab3322997653'), call('DELETE', '/zones/ff12ab34cd5611334422ab3322997650/' @@ -383,12 +382,6 @@ class TestCloudflareProvider(TestCase): 'jump_start': False, 'name': 'unit.tests' }), - call('POST', '/zones/42/dns_records', data={ - 'content': '3.3.3.3', - 'type': 'A', - 'name': 'a.unit.tests', - 'ttl': 300 - }), call('POST', '/zones/42/dns_records', data={ 'content': '4.4.4.4', 'type': 'A', @@ -402,8 +395,13 @@ class TestCloudflareProvider(TestCase): 'name': 'a.unit.tests', 'ttl': 300 }), - call('DELETE', '/zones/42/dns_records/' - 'fc12ab34cd5611334422ab3322997653') + call('PUT', '/zones/42/dns_records/' + 'fc12ab34cd5611334422ab3322997653', data={ + 'content': '3.3.3.3', + 'type': 'A', + 'name': 'a.unit.tests', + 'ttl': 300 + }), ]) def test_update_delete(self):