mirror of
				https://github.com/github/octodns.git
				synced 2024-05-11 05:55:00 +00:00 
			
		
		
		
	Handle domains not registred at Gandi or not using Gandi's DNS
This commit is contained in:
		| @@ -41,6 +41,12 @@ class GandiClientNotFound(GandiClientException): | ||||
|         super(GandiClientNotFound, self).__init__(r.text) | ||||
|  | ||||
|  | ||||
| class GandiClientUnknownDomainName(GandiClientException): | ||||
|  | ||||
|     def __init__(self, msg): | ||||
|         super(GandiClientUnknownDomainName, self).__init__(msg) | ||||
|  | ||||
|  | ||||
| class GandiClient(object): | ||||
|  | ||||
|     def __init__(self, token): | ||||
| @@ -63,6 +69,16 @@ class GandiClient(object): | ||||
|         r.raise_for_status() | ||||
|         return r | ||||
|  | ||||
|     def zone(self, zone_name): | ||||
|         return self._request('GET', '/livedns/domains/{}' | ||||
|                                     .format(zone_name)).json() | ||||
|  | ||||
|     def zone_create(self, zone_name): | ||||
|         return self._request('POST', '/livedns/domains', data={ | ||||
|             'fqdn': zone_name, | ||||
|             'zone': {} | ||||
|         }).json() | ||||
|  | ||||
|     def zone_records(self, zone_name): | ||||
|         records = self._request('GET', '/livedns/domains/{}/records' | ||||
|                                 .format(zone_name)).json() | ||||
| @@ -318,9 +334,25 @@ class GandiProvider(BaseProvider): | ||||
|     def _apply(self, plan): | ||||
|         desired = plan.desired | ||||
|         changes = plan.changes | ||||
|         zone = desired.name[:-1] | ||||
|         self.log.debug('_apply: zone=%s, len(changes)=%d', desired.name, | ||||
|                        len(changes)) | ||||
|  | ||||
|         try: | ||||
|             self._client.zone(zone) | ||||
|         except GandiClientNotFound: | ||||
|             self.log.info('_apply: no existing zone, trying to create it') | ||||
|             try: | ||||
|                 self._client.zone_create(zone) | ||||
|                 self.log.info('_apply: zone has been successfully created') | ||||
|             except GandiClientNotFound: | ||||
|                 raise GandiClientUnknownDomainName('This domain is not ' | ||||
|                                                    'registred at Gandi. ' | ||||
|                                                    'Please register or ' | ||||
|                                                    'transfer it here ' | ||||
|                                                    'to be able to manage its ' | ||||
|                                                    'DNS zone.') | ||||
|  | ||||
|         # Force records deletion to be done before creation in order to avoid | ||||
|         # "CNAME record must be the only record" error when an existing CNAME | ||||
|         # record is replaced by an A/AAAA record. | ||||
|   | ||||
							
								
								
									
										7
									
								
								tests/fixtures/gandi-zone.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								tests/fixtures/gandi-zone.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,7 @@ | ||||
| { | ||||
|       "domain_keys_href": "https://api.gandi.net/v5/livedns/domains/unit.tests/keys", | ||||
|       "fqdn": "unit.tests", | ||||
|       "automatic_snapshots": true, | ||||
|       "domain_records_href": "https://api.gandi.net/v5/livedns/domains/unit.tests/records", | ||||
|       "domain_href": "https://api.gandi.net/v5/livedns/domains/unit.tests" | ||||
| } | ||||
| @@ -86,6 +86,18 @@ class TestGandiProvider(TestCase): | ||||
|                 provider.populate(zone) | ||||
|             self.assertIn('"cause":"Forbidden"', text_type(ctx.exception)) | ||||
|  | ||||
|         # 404 - Not Found. | ||||
|         with requests_mock() as mock: | ||||
|             mock.get(ANY, status_code=404, | ||||
|                      text='{"code": 404, "message": "The resource could not ' | ||||
|                           'be found.", "object": "HTTPNotFound", "cause": ' | ||||
|                           '"Not Found"}') | ||||
|  | ||||
|             with self.assertRaises(GandiClientNotFound) as ctx: | ||||
|                 zone = Zone('unit.tests.', []) | ||||
|                 provider._client.zone(zone) | ||||
|             self.assertIn('"cause": "Not Found"', text_type(ctx.exception)) | ||||
|  | ||||
|         # General error | ||||
|         with requests_mock() as mock: | ||||
|             mock.get(ANY, status_code=502, text='Things caught fire') | ||||
| @@ -95,15 +107,6 @@ class TestGandiProvider(TestCase): | ||||
|                 provider.populate(zone) | ||||
|             self.assertEquals(502, ctx.exception.response.status_code) | ||||
|  | ||||
|         # Non-existent zone doesn't populate anything | ||||
|         with requests_mock() as mock: | ||||
|             mock.get(ANY, status_code=404, | ||||
|                      text='{"message": "Domain `foo.bar` not found"}') | ||||
|  | ||||
|             zone = Zone('unit.tests.', []) | ||||
|             provider.populate(zone) | ||||
|             self.assertEquals(set(), zone.records) | ||||
|  | ||||
|         # No diffs == no changes | ||||
|         with requests_mock() as mock: | ||||
|             base = 'https://api.gandi.net/v5/livedns/domains/unit.tests' \ | ||||
| @@ -147,10 +150,14 @@ class TestGandiProvider(TestCase): | ||||
|         resp.json = Mock() | ||||
|         provider._client._request = Mock(return_value=resp) | ||||
|  | ||||
|         with open('tests/fixtures/gandi-zone.json') as fh: | ||||
|             zone = fh.read() | ||||
|  | ||||
|         # non-existent domain | ||||
|         resp.json.side_effect = [ | ||||
|             GandiClientNotFound(resp),  # no zone in populate | ||||
|             GandiClientNotFound(resp),  # no domain during apply | ||||
|             zone | ||||
|         ] | ||||
|         plan = provider.plan(self.expected) | ||||
|  | ||||
| @@ -162,6 +169,11 @@ class TestGandiProvider(TestCase): | ||||
|  | ||||
|         provider._client._request.assert_has_calls([ | ||||
|             call('GET', '/livedns/domains/unit.tests/records'), | ||||
|             call('GET', '/livedns/domains/unit.tests'), | ||||
|             call('POST', '/livedns/domains', data={ | ||||
|                 'fqdn': 'unit.tests', | ||||
|                 'zone': {} | ||||
|             }), | ||||
|             call('POST', '/livedns/domains/unit.tests/records', data={ | ||||
|                 'rrset_name': 'www.sub', | ||||
|                 'rrset_ttl': 300, | ||||
| @@ -258,7 +270,7 @@ class TestGandiProvider(TestCase): | ||||
|             }) | ||||
|         ]) | ||||
|         # expected number of total calls | ||||
|         self.assertEquals(14, provider._client._request.call_count) | ||||
|         self.assertEquals(16, provider._client._request.call_count) | ||||
|  | ||||
|         provider._client._request.reset_mock() | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user