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)
|
super(GandiClientNotFound, self).__init__(r.text)
|
||||||
|
|
||||||
|
|
||||||
|
class GandiClientUnknownDomainName(GandiClientException):
|
||||||
|
|
||||||
|
def __init__(self, msg):
|
||||||
|
super(GandiClientUnknownDomainName, self).__init__(msg)
|
||||||
|
|
||||||
|
|
||||||
class GandiClient(object):
|
class GandiClient(object):
|
||||||
|
|
||||||
def __init__(self, token):
|
def __init__(self, token):
|
||||||
@@ -63,6 +69,16 @@ class GandiClient(object):
|
|||||||
r.raise_for_status()
|
r.raise_for_status()
|
||||||
return r
|
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):
|
def zone_records(self, zone_name):
|
||||||
records = self._request('GET', '/livedns/domains/{}/records'
|
records = self._request('GET', '/livedns/domains/{}/records'
|
||||||
.format(zone_name)).json()
|
.format(zone_name)).json()
|
||||||
@@ -318,9 +334,25 @@ class GandiProvider(BaseProvider):
|
|||||||
def _apply(self, plan):
|
def _apply(self, plan):
|
||||||
desired = plan.desired
|
desired = plan.desired
|
||||||
changes = plan.changes
|
changes = plan.changes
|
||||||
|
zone = desired.name[:-1]
|
||||||
self.log.debug('_apply: zone=%s, len(changes)=%d', desired.name,
|
self.log.debug('_apply: zone=%s, len(changes)=%d', desired.name,
|
||||||
len(changes))
|
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
|
# Force records deletion to be done before creation in order to avoid
|
||||||
# "CNAME record must be the only record" error when an existing CNAME
|
# "CNAME record must be the only record" error when an existing CNAME
|
||||||
# record is replaced by an A/AAAA record.
|
# 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)
|
provider.populate(zone)
|
||||||
self.assertIn('"cause":"Forbidden"', text_type(ctx.exception))
|
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
|
# General error
|
||||||
with requests_mock() as mock:
|
with requests_mock() as mock:
|
||||||
mock.get(ANY, status_code=502, text='Things caught fire')
|
mock.get(ANY, status_code=502, text='Things caught fire')
|
||||||
@@ -95,15 +107,6 @@ class TestGandiProvider(TestCase):
|
|||||||
provider.populate(zone)
|
provider.populate(zone)
|
||||||
self.assertEquals(502, ctx.exception.response.status_code)
|
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
|
# No diffs == no changes
|
||||||
with requests_mock() as mock:
|
with requests_mock() as mock:
|
||||||
base = 'https://api.gandi.net/v5/livedns/domains/unit.tests' \
|
base = 'https://api.gandi.net/v5/livedns/domains/unit.tests' \
|
||||||
@@ -147,10 +150,14 @@ class TestGandiProvider(TestCase):
|
|||||||
resp.json = Mock()
|
resp.json = Mock()
|
||||||
provider._client._request = Mock(return_value=resp)
|
provider._client._request = Mock(return_value=resp)
|
||||||
|
|
||||||
|
with open('tests/fixtures/gandi-zone.json') as fh:
|
||||||
|
zone = fh.read()
|
||||||
|
|
||||||
# non-existent domain
|
# non-existent domain
|
||||||
resp.json.side_effect = [
|
resp.json.side_effect = [
|
||||||
GandiClientNotFound(resp), # no zone in populate
|
GandiClientNotFound(resp), # no zone in populate
|
||||||
GandiClientNotFound(resp), # no domain during apply
|
GandiClientNotFound(resp), # no domain during apply
|
||||||
|
zone
|
||||||
]
|
]
|
||||||
plan = provider.plan(self.expected)
|
plan = provider.plan(self.expected)
|
||||||
|
|
||||||
@@ -162,6 +169,11 @@ class TestGandiProvider(TestCase):
|
|||||||
|
|
||||||
provider._client._request.assert_has_calls([
|
provider._client._request.assert_has_calls([
|
||||||
call('GET', '/livedns/domains/unit.tests/records'),
|
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={
|
call('POST', '/livedns/domains/unit.tests/records', data={
|
||||||
'rrset_name': 'www.sub',
|
'rrset_name': 'www.sub',
|
||||||
'rrset_ttl': 300,
|
'rrset_ttl': 300,
|
||||||
@@ -258,7 +270,7 @@ class TestGandiProvider(TestCase):
|
|||||||
})
|
})
|
||||||
])
|
])
|
||||||
# expected number of total calls
|
# 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()
|
provider._client._request.reset_mock()
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user