1
0
mirror of https://github.com/github/octodns.git synced 2024-05-11 05:55:00 +00:00

Make formatting consistent and improve record type support.

This commit is contained in:
Terrence Cole
2017-07-13 11:44:09 -07:00
parent 823423054f
commit 01f8431d74
3 changed files with 275 additions and 170 deletions

View File

@@ -12,6 +12,33 @@ from ..record import Create, Record
from .base import BaseProvider from .base import BaseProvider
def add_trailing_dot(s):
assert s
assert s[-1] != '.'
return s + '.'
def remove_trailing_dot(s):
assert s
assert s[-1] == '.'
return s[:-1]
def strip_quotes(s):
assert s
assert len(s) > 2
assert s[0] == '"'
assert s[-1] == '"'
return s[1:-1]
def add_quotes(s):
assert s
assert s[0] != '"'
assert s[-1] != '"'
return '"{}"'.format(s)
class RackspaceProvider(BaseProvider): class RackspaceProvider(BaseProvider):
SUPPORTS_GEO = False SUPPORTS_GEO = False
TIMEOUT = 5 TIMEOUT = 5
@@ -101,6 +128,10 @@ class RackspaceProvider(BaseProvider):
def _delete(self, path, data=None): def _delete(self, path, data=None):
return self._request('DELETE', path, data=data) return self._request('DELETE', path, data=data)
@staticmethod
def _key_for_record(rs_record):
return rs_record['type'], rs_record['name'], rs_record['data']
def _data_for_multiple(self, rrset): def _data_for_multiple(self, rrset):
# TODO: geo not supported # TODO: geo not supported
return { return {
@@ -116,14 +147,14 @@ class RackspaceProvider(BaseProvider):
# TODO: geo not supported # TODO: geo not supported
return { return {
'type': rrset[0]['type'], 'type': rrset[0]['type'],
'values': ["{}.".format(r['data']) for r in rrset], 'values': [add_trailing_dot(r['data']) for r in rrset],
'ttl': rrset[0]['ttl'] 'ttl': rrset[0]['ttl']
} }
def _data_for_single(self, record): def _data_for_single(self, record):
return { return {
'type': record[0]['type'], 'type': record[0]['type'],
'value': "{}.".format(record[0]['data']), 'value': add_trailing_dot(record[0]['data']),
'ttl': record[0]['ttl'] 'ttl': record[0]['ttl']
} }
@@ -134,7 +165,7 @@ class RackspaceProvider(BaseProvider):
def _data_for_quoted(self, rrset): def _data_for_quoted(self, rrset):
return { return {
'type': rrset['type'], 'type': rrset['type'],
'values': [r['content'][1:-1] for r in rrset['records']], 'values': [strip_quotes(r['content']) for r in rrset['records']],
'ttl': rrset['ttl'] 'ttl': rrset['ttl']
} }
@@ -146,7 +177,7 @@ class RackspaceProvider(BaseProvider):
for record in rrset: for record in rrset:
values.append({ values.append({
'priority': record['priority'], 'priority': record['priority'],
'value': record['data'], 'value': add_trailing_dot(record['data']),
}) })
return { return {
'type': rrset[0]['type'], 'type': rrset[0]['type'],
@@ -155,56 +186,59 @@ class RackspaceProvider(BaseProvider):
} }
def _data_for_NAPTR(self, rrset): def _data_for_NAPTR(self, rrset):
values = [] raise NotImplementedError("Missing support for reading NAPTR records")
for record in rrset['records']: # values = []
order, preference, flags, service, regexp, replacement = \ # for record in rrset['records']:
record['content'].split(' ', 5) # order, preference, flags, service, regexp, replacement = \
values.append({ # record['content'].split(' ', 5)
'order': order, # values.append({
'preference': preference, # 'order': order,
'flags': flags[1:-1], # 'preference': preference,
'service': service[1:-1], # 'flags': flags[1:-1],
'regexp': regexp[1:-1], # 'service': service[1:-1],
'replacement': replacement, # 'regexp': regexp[1:-1],
}) # 'replacement': replacement,
return { # })
'type': rrset['type'], # return {
'values': values, # 'type': rrset['type'],
'ttl': rrset['ttl'] # 'values': values,
} # 'ttl': rrset['ttl']
# }
def _data_for_SSHFP(self, rrset): def _data_for_SSHFP(self, rrset):
values = [] raise NotImplementedError("Missing support for reading SSHFP records")
for record in rrset['records']: # values = []
algorithm, fingerprint_type, fingerprint = \ # for record in rrset['records']:
record['content'].split(' ', 2) # algorithm, fingerprint_type, fingerprint = \
values.append({ # record['content'].split(' ', 2)
'algorithm': algorithm, # values.append({
'fingerprint_type': fingerprint_type, # 'algorithm': algorithm,
'fingerprint': fingerprint, # 'fingerprint_type': fingerprint_type,
}) # 'fingerprint': fingerprint,
return { # })
'type': rrset['type'], # return {
'values': values, # 'type': rrset['type'],
'ttl': rrset['ttl'] # 'values': values,
} # 'ttl': rrset['ttl']
# }
def _data_for_SRV(self, rrset): def _data_for_SRV(self, rrset):
values = [] raise NotImplementedError("Missing support for reading SRV records")
for record in rrset['records']: # values = []
priority, weight, port, target = \ # for record in rrset['records']:
record['content'].split(' ', 3) # priority, weight, port, target = \
values.append({ # record['content'].split(' ', 3)
'priority': priority, # values.append({
'weight': weight, # 'priority': priority,
'port': port, # 'weight': weight,
'target': target, # 'port': port,
}) # 'target': target,
return { # })
'type': rrset['type'], # return {
'values': values, # 'type': rrset['type'],
'ttl': rrset['ttl'] # 'values': values,
} # 'ttl': rrset['ttl']
# }
def populate(self, zone, target=False): def populate(self, zone, target=False):
self.log.debug('populate: name=%s', zone.name) self.log.debug('populate: name=%s', zone.name)
@@ -217,13 +251,9 @@ class RackspaceProvider(BaseProvider):
if e.response.status_code == 401: if e.response.status_code == 401:
# Nicer error message for auth problems # Nicer error message for auth problems
raise Exception('Rackspace request unauthorized') raise Exception('Rackspace request unauthorized')
elif e.response.status_code == 422: elif e.response.status_code == 404:
# 422 means powerdns doesn't know anything about the requsted # Zone not found leaves the zone empty instead of failing.
# domain. We'll just ignore it here and leave the zone return
# untouched.
pass
else:
# just re-throw
raise raise
before = len(zone.records) before = len(zone.records)
@@ -246,70 +276,82 @@ class RackspaceProvider(BaseProvider):
def _group_records(self, all_records): def _group_records(self, all_records):
records = defaultdict(lambda: defaultdict(list)) records = defaultdict(lambda: defaultdict(list))
for record in all_records: for record in all_records:
self._id_map[(record['type'], record['name'], record['data'])] = record['id'] self._id_map[self._key_for_record(record)] = record['id']
records[record['type']][record['name']].append(record) records[record['type']][record['name']].append(record)
return records return records
def _records_for_multiple(self, record): @staticmethod
return [{'content': v, 'disabled': False} def _record_for_ip(record, value):
for v in record.values] return {
'name': record.fqdn,
'type': record._type,
'data': value,
'ttl': max(record.ttl, 300),
}
_record_for_A = _record_for_ip
_record_for_AAAA = _record_for_ip
_records_for_A = _records_for_multiple @staticmethod
_records_for_AAAA = _records_for_multiple def _record_for_named(record, value):
_records_for_NS = _records_for_multiple return {
'name': record.fqdn,
'type': record._type,
'data': remove_trailing_dot(value),
'ttl': max(record.ttl, 300),
}
_record_for_NS = _record_for_named
_record_for_ALIAS = _record_for_named
_record_for_CNAME = _record_for_named
_record_for_PTR = _record_for_named
def _records_for_single(self, record): @staticmethod
return [{'content': record.value, 'disabled': False}] def _record_for_quoted(record, value):
return {
'name': record.fqdn,
'type': record._type,
'data': add_quotes(value),
'ttl': max(record.ttl, 300),
}
_record_for_SPF = _record_for_quoted
_record_for_TXT = _record_for_quoted
_records_for_ALIAS = _records_for_single @staticmethod
_records_for_CNAME = _records_for_single def _record_for_MX(record, value):
_records_for_PTR = _records_for_single return {
'name': record.fqdn,
'type': record._type,
'data': remove_trailing_dot(value),
'ttl': max(record.ttl, 300),
'priority': record.priority
}
def _records_for_quoted(self, record): @staticmethod
return [{'content': '"{}"'.format(v), 'disabled': False} def _record_for_SRV(record, value):
for v in record.values] raise NotImplementedError("Missing support for writing SRV records")
_records_for_SPF = _records_for_quoted def _record_for_NAPTR(self, record):
_records_for_TXT = _records_for_quoted raise NotImplementedError("Missing support for writing NAPTR records")
# return [{
# 'content': '{} {} "{}" "{}" "{}" {}'.format(v.order, v.preference,
# v.flags, v.service,
# v.regexp,
# v.replacement),
# 'disabled': False
# } for v in record.values]
def _records_for_MX(self, record): def _record_for_SSHFP(self, record):
return [{ raise NotImplementedError("Missing support for writing SSHFP records")
'content': '{} {}'.format(v.priority, v.value), # return [{
'disabled': False # 'content': '{} {} {}'.format(v.algorithm, v.fingerprint_type,
} for v in record.values] # v.fingerprint),
# 'disabled': False
def _records_for_NAPTR(self, record): # } for v in record.values]
return [{
'content': '{} {} "{}" "{}" "{}" {}'.format(v.order, v.preference,
v.flags, v.service,
v.regexp,
v.replacement),
'disabled': False
} for v in record.values]
def _records_for_SSHFP(self, record):
return [{
'content': '{} {} {}'.format(v.algorithm, v.fingerprint_type,
v.fingerprint),
'disabled': False
} for v in record.values]
def _records_for_SRV(self, record):
return [{
'content': '{} {} {} {}'.format(v.priority, v.weight, v.port,
v.target),
'disabled': False
} for v in record.values]
def _mod_Create(self, change): def _mod_Create(self, change):
out = [] out = []
for value in change.new.values: for value in change.new.values:
out.append({ transformer = getattr(self, "_record_for_{}".format(change.new._type))
'name': change.new.fqdn, out.append(transformer(change.new, value))
'type': change.new._type,
'data': value,
'ttl': change.new.ttl,
})
return out return out
def _mod_Update(self, change): def _mod_Update(self, change):
@@ -320,14 +362,16 @@ class RackspaceProvider(BaseProvider):
update_out = [] update_out = []
for value in change.new.values: for value in change.new.values:
key = (change.existing._type, change.existing.fqdn, value) transformer = getattr(self, "_record_for_{}".format(change.new._type))
rsid = self._id_map[key] prior_rs_record = transformer(change.existing, value)
update_out.append({ prior_key = self._key_for_record(prior_rs_record)
'id': rsid, next_rs_record = transformer(change.new, value)
'name': change.new.fqdn, next_key = self._key_for_record(prior_rs_record)
'data': value, next_rs_record["id"] = self._id_map[prior_key]
'ttl': change.new.ttl, del next_rs_record["type"]
}) update_out.append(next_rs_record)
self._id_map[next_key] = self._id_map[prior_key]
del self._id_map[prior_key]
return update_out, delete_out return update_out, delete_out
def _mod_Delete(self, change): def _mod_Delete(self, change):
@@ -336,9 +380,10 @@ class RackspaceProvider(BaseProvider):
def _delete_given_change_values(self, change, values): def _delete_given_change_values(self, change, values):
out = [] out = []
for value in values: for value in values:
key = (change.existing._type, change.existing.fqdn, value) transformer = getattr(self, "_record_for_{}".format(change.existing._type))
rsid = self._id_map[key] rs_record = transformer(change.existing, value)
out.append('id=' + rsid) key = self._key_for_record(rs_record)
out.append('id=' + self._id_map[key])
del self._id_map[key] del self._id_map[key]
return out return out
@@ -363,7 +408,7 @@ class RackspaceProvider(BaseProvider):
deletes += self._mod_Delete(change) deletes += self._mod_Delete(change)
if creates: if creates:
data = {"records": sorted(creates, key=lambda v: v['name'])} data = {"records": sorted(creates, key=lambda v: v['type'] + v['name'] + v.get('data', ''))}
self._post('domains/{}/records'.format(domain_id), data=data) self._post('domains/{}/records'.format(domain_id), data=data)
if updates: if updates:

View File

@@ -6,13 +6,13 @@
"type" : "A", "type" : "A",
"data" : "1.2.3.4", "data" : "1.2.3.4",
"updated" : "2011-06-24T01:12:53.000+0000", "updated" : "2011-06-24T01:12:53.000+0000",
"ttl" : 60, "ttl" : 600,
"created" : "2011-06-24T01:12:53.000+0000" "created" : "2011-06-24T01:12:53.000+0000"
}, { }, {
"name" : "unit.tests.", "name" : "unit.tests.",
"id" : "NS-454454", "id" : "NS-454454",
"type" : "NS", "type" : "NS",
"data" : "8.8.8.8.", "data" : "ns1.example.com",
"updated" : "2011-06-24T01:12:51.000+0000", "updated" : "2011-06-24T01:12:51.000+0000",
"ttl" : 600, "ttl" : 600,
"created" : "2011-06-24T01:12:51.000+0000" "created" : "2011-06-24T01:12:51.000+0000"
@@ -20,7 +20,7 @@
"name" : "unit.tests.", "name" : "unit.tests.",
"id" : "NS-454455", "id" : "NS-454455",
"type" : "NS", "type" : "NS",
"data" : "9.9.9.9.", "data" : "ns2.example.com",
"updated" : "2011-06-24T01:12:52.000+0000", "updated" : "2011-06-24T01:12:52.000+0000",
"ttl" : 600, "ttl" : 600,
"created" : "2011-06-24T01:12:52.000+0000" "created" : "2011-06-24T01:12:52.000+0000"

View File

@@ -43,8 +43,10 @@ with open('./tests/fixtures/rackspace-sample-recordset-page2.json') as fh:
with open('./tests/fixtures/rackspace-sample-recordset-existing-nameservers.json') as fh: with open('./tests/fixtures/rackspace-sample-recordset-existing-nameservers.json') as fh:
RECORDS_EXISTING_NAMESERVERS = fh.read() RECORDS_EXISTING_NAMESERVERS = fh.read()
class TestRackspaceProvider(TestCase): class TestRackspaceProvider(TestCase):
def setUp(self): def setUp(self):
self.maxDiff = 1000
with requests_mock() as mock: with requests_mock() as mock:
mock.post(ANY, status_code=200, text=AUTH_RESPONSE) mock.post(ANY, status_code=200, text=AUTH_RESPONSE)
self.provider = RackspaceProvider('test', 'api-key') self.provider = RackspaceProvider('test', 'api-key')
@@ -73,7 +75,7 @@ class TestRackspaceProvider(TestCase):
def test_nonexistent_zone(self): def test_nonexistent_zone(self):
# Non-existent zone doesn't populate anything # Non-existent zone doesn't populate anything
with requests_mock() as mock: with requests_mock() as mock:
mock.get(ANY, status_code=422, mock.get(ANY, status_code=404,
json={'error': "Could not find domain 'unit.tests.'"}) json={'error': "Could not find domain 'unit.tests.'"})
zone = Zone('unit.tests.', []) zone = Zone('unit.tests.', [])
@@ -196,7 +198,7 @@ class TestRackspaceProvider(TestCase):
"subdomain": '', "subdomain": '',
"data": { "data": {
'type': 'A', 'type': 'A',
'ttl': 60, 'ttl': 300,
'values': ['1.2.3.4', '1.2.3.5', '1.2.3.6'] 'values': ['1.2.3.4', '1.2.3.5', '1.2.3.6']
} }
} }
@@ -208,19 +210,19 @@ class TestRackspaceProvider(TestCase):
"id": "A-111111", "id": "A-111111",
"type": "A", "type": "A",
"data": "1.2.3.4", "data": "1.2.3.4",
"ttl": 60 "ttl": 300
}, { }, {
"name": "unit.tests.", "name": "unit.tests.",
"id": "A-222222", "id": "A-222222",
"type": "A", "type": "A",
"data": "1.2.3.5", "data": "1.2.3.5",
"ttl": 60 "ttl": 300
}, { }, {
"name": "unit.tests.", "name": "unit.tests.",
"id": "A-333333", "id": "A-333333",
"type": "A", "type": "A",
"data": "1.2.3.6", "data": "1.2.3.6",
"ttl": 60 "ttl": 300
}] }]
} }
ExpectChanges = False ExpectChanges = False
@@ -236,7 +238,7 @@ class TestRackspaceProvider(TestCase):
"subdomain": 'foo', "subdomain": 'foo',
"data": { "data": {
'type': 'A', 'type': 'A',
'ttl': 60, 'ttl': 300,
'value': '1.2.3.4' 'value': '1.2.3.4'
} }
}, },
@@ -244,7 +246,7 @@ class TestRackspaceProvider(TestCase):
"subdomain": 'bar', "subdomain": 'bar',
"data": { "data": {
'type': 'A', 'type': 'A',
'ttl': 60, 'ttl': 300,
'value': '1.2.3.4' 'value': '1.2.3.4'
} }
} }
@@ -256,13 +258,13 @@ class TestRackspaceProvider(TestCase):
"id": "A-111111", "id": "A-111111",
"type": "A", "type": "A",
"data": "1.2.3.4", "data": "1.2.3.4",
"ttl": 60 "ttl": 300
}, { }, {
"name": "bar.unit.tests.", "name": "bar.unit.tests.",
"id": "A-222222", "id": "A-222222",
"type": "A", "type": "A",
"data": "1.2.3.4", "data": "1.2.3.4",
"ttl": 60 "ttl": 300
}] }]
} }
ExpectChanges = False ExpectChanges = False
@@ -278,9 +280,17 @@ class TestRackspaceProvider(TestCase):
"subdomain": '', "subdomain": '',
"data": { "data": {
'type': 'A', 'type': 'A',
'ttl': 60, 'ttl': 300,
'value': '1.2.3.4' 'value': '1.2.3.4'
} }
},
{
"subdomain": 'foo',
"data": {
'type': 'NS',
'ttl': 300,
'value': 'ns.example.com.'
}
} }
] ]
OwnRecords = { OwnRecords = {
@@ -293,7 +303,12 @@ class TestRackspaceProvider(TestCase):
"name": "unit.tests.", "name": "unit.tests.",
"type": "A", "type": "A",
"data": "1.2.3.4", "data": "1.2.3.4",
"ttl": 60 "ttl": 300
}, {
"name": "foo.unit.tests.",
"type": "NS",
"data": "ns.example.com",
"ttl": 300
}] }]
} }
ExpectedDeletions = None ExpectedDeletions = None
@@ -307,9 +322,17 @@ class TestRackspaceProvider(TestCase):
"subdomain": '', "subdomain": '',
"data": { "data": {
'type': 'A', 'type': 'A',
'ttl': 60, 'ttl': 300,
'values': ['1.2.3.4', '1.2.3.5', '1.2.3.6'] 'values': ['1.2.3.4', '1.2.3.5', '1.2.3.6']
} }
},
{
"subdomain": 'foo',
"data": {
'type': 'NS',
'ttl': 300,
'values': ['ns1.example.com.', 'ns2.example.com.']
}
} }
] ]
OwnRecords = { OwnRecords = {
@@ -322,17 +345,27 @@ class TestRackspaceProvider(TestCase):
"name": "unit.tests.", "name": "unit.tests.",
"type": "A", "type": "A",
"data": "1.2.3.4", "data": "1.2.3.4",
"ttl": 60 "ttl": 300
}, { }, {
"name": "unit.tests.", "name": "unit.tests.",
"type": "A", "type": "A",
"data": "1.2.3.5", "data": "1.2.3.5",
"ttl": 60 "ttl": 300
}, { }, {
"name": "unit.tests.", "name": "unit.tests.",
"type": "A", "type": "A",
"data": "1.2.3.6", "data": "1.2.3.6",
"ttl": 60 "ttl": 300
}, {
"name": "foo.unit.tests.",
"type": "NS",
"data": "ns1.example.com",
"ttl": 300
}, {
"name": "foo.unit.tests.",
"type": "NS",
"data": "ns2.example.com",
"ttl": 300
}] }]
} }
ExpectedDeletions = None ExpectedDeletions = None
@@ -345,16 +378,24 @@ class TestRackspaceProvider(TestCase):
"subdomain": 'foo', "subdomain": 'foo',
"data": { "data": {
'type': 'A', 'type': 'A',
'ttl': 60, 'ttl': 300,
'value': '1.2.3.4' 'value': '1.2.3.4'
} }
}, { }, {
"subdomain": 'bar', "subdomain": 'bar',
"data": { "data": {
'type': 'A', 'type': 'A',
'ttl': 60, 'ttl': 300,
'value': '1.2.3.4' 'value': '1.2.3.4'
} }
},
{
"subdomain": 'foo',
"data": {
'type': 'NS',
'ttl': 300,
'value': 'ns.example.com.'
}
}] }]
OwnRecords = { OwnRecords = {
"totalEntries": 0, "totalEntries": 0,
@@ -366,12 +407,17 @@ class TestRackspaceProvider(TestCase):
"name": "bar.unit.tests.", "name": "bar.unit.tests.",
"type": "A", "type": "A",
"data": "1.2.3.4", "data": "1.2.3.4",
"ttl": 60 "ttl": 300
}, { }, {
"name": "foo.unit.tests.", "name": "foo.unit.tests.",
"type": "A", "type": "A",
"data": "1.2.3.4", "data": "1.2.3.4",
"ttl": 60 "ttl": 300
}, {
"name": "foo.unit.tests.",
"type": "NS",
"data": "ns.example.com",
"ttl": 300
}] }]
} }
ExpectedDeletions = None ExpectedDeletions = None
@@ -388,12 +434,18 @@ class TestRackspaceProvider(TestCase):
"id": "A-111111", "id": "A-111111",
"type": "A", "type": "A",
"data": "1.2.3.4", "data": "1.2.3.4",
"ttl": 60 "ttl": 300
}, {
"name": "foo.unit.tests.",
"id": "NS-111111",
"type": "NS",
"data": "ns.example.com",
"ttl": 300
}] }]
} }
ExpectChanges = True ExpectChanges = True
ExpectedAdditions = None ExpectedAdditions = None
ExpectedDeletions = "id=A-111111" ExpectedDeletions = "id=A-111111&id=NS-111111"
ExpectedUpdates = None ExpectedUpdates = None
return self._test_apply_with_data(TestData) return self._test_apply_with_data(TestData)
@@ -404,7 +456,7 @@ class TestRackspaceProvider(TestCase):
"subdomain": '', "subdomain": '',
"data": { "data": {
'type': 'A', 'type': 'A',
'ttl': 60, 'ttl': 300,
'value': '1.2.3.5' 'value': '1.2.3.5'
} }
} }
@@ -416,30 +468,36 @@ class TestRackspaceProvider(TestCase):
"id": "A-111111", "id": "A-111111",
"type": "A", "type": "A",
"data": "1.2.3.4", "data": "1.2.3.4",
"ttl": 60 "ttl": 300
}, { }, {
"name": "unit.tests.", "name": "unit.tests.",
"id": "A-222222", "id": "A-222222",
"type": "A", "type": "A",
"data": "1.2.3.5", "data": "1.2.3.5",
"ttl": 60 "ttl": 300
}, { }, {
"name": "unit.tests.", "name": "unit.tests.",
"id": "A-333333", "id": "A-333333",
"type": "A", "type": "A",
"data": "1.2.3.6", "data": "1.2.3.6",
"ttl": 60 "ttl": 300
}, {
"name": "foo.unit.tests.",
"id": "NS-111111",
"type": "NS",
"data": "ns.example.com",
"ttl": 300
}] }]
} }
ExpectChanges = True ExpectChanges = True
ExpectedAdditions = None ExpectedAdditions = None
ExpectedDeletions = "id=A-111111&id=A-333333" ExpectedDeletions = "id=A-111111&id=A-333333&id=NS-111111"
ExpectedUpdates = { ExpectedUpdates = {
"records": [{ "records": [{
"name": "unit.tests.", "name": "unit.tests.",
"id": "A-222222", "id": "A-222222",
"data": "1.2.3.5", "data": "1.2.3.5",
"ttl": 60 "ttl": 300
}] }]
} }
return self._test_apply_with_data(TestData) return self._test_apply_with_data(TestData)
@@ -451,7 +509,7 @@ class TestRackspaceProvider(TestCase):
"subdomain": '', "subdomain": '',
"data": { "data": {
'type': 'A', 'type': 'A',
'ttl': 60, 'ttl': 300,
'value': '1.2.3.4' 'value': '1.2.3.4'
} }
} }
@@ -463,19 +521,19 @@ class TestRackspaceProvider(TestCase):
"id": "A-111111", "id": "A-111111",
"type": "A", "type": "A",
"data": "1.2.3.4", "data": "1.2.3.4",
"ttl": 60 "ttl": 300
}, { }, {
"name": "foo.unit.tests.", "name": "foo.unit.tests.",
"id": "A-222222", "id": "A-222222",
"type": "A", "type": "A",
"data": "1.2.3.5", "data": "1.2.3.5",
"ttl": 60 "ttl": 300
}, { }, {
"name": "bar.unit.tests.", "name": "bar.unit.tests.",
"id": "A-333333", "id": "A-333333",
"type": "A", "type": "A",
"data": "1.2.3.6", "data": "1.2.3.6",
"ttl": 60 "ttl": 300
}] }]
} }
ExpectChanges = True ExpectChanges = True
@@ -503,7 +561,7 @@ class TestRackspaceProvider(TestCase):
"id": "A-111111", "id": "A-111111",
"type": "A", "type": "A",
"data": "1.2.3.4", "data": "1.2.3.4",
"ttl": 60 "ttl": 300
}] }]
} }
ExpectChanges = True ExpectChanges = True
@@ -538,19 +596,19 @@ class TestRackspaceProvider(TestCase):
"id": "A-111111", "id": "A-111111",
"type": "A", "type": "A",
"data": "1.2.3.4", "data": "1.2.3.4",
"ttl": 60 "ttl": 300
}, { }, {
"name": "unit.tests.", "name": "unit.tests.",
"id": "A-222222", "id": "A-222222",
"type": "A", "type": "A",
"data": "1.2.3.5", "data": "1.2.3.5",
"ttl": 60 "ttl": 300
}, { }, {
"name": "unit.tests.", "name": "unit.tests.",
"id": "A-333333", "id": "A-333333",
"type": "A", "type": "A",
"data": "1.2.3.6", "data": "1.2.3.6",
"ttl": 60 "ttl": 300
}] }]
} }
ExpectChanges = True ExpectChanges = True
@@ -603,13 +661,13 @@ class TestRackspaceProvider(TestCase):
"id": "A-111111", "id": "A-111111",
"type": "A", "type": "A",
"data": "1.2.3.4", "data": "1.2.3.4",
"ttl": 60 "ttl": 300
}, { }, {
"name": "bar.unit.tests.", "name": "bar.unit.tests.",
"id": "A-222222", "id": "A-222222",
"type": "A", "type": "A",
"data": "1.2.3.4", "data": "1.2.3.4",
"ttl": 60 "ttl": 300
}] }]
} }
ExpectChanges = True ExpectChanges = True
@@ -630,6 +688,7 @@ class TestRackspaceProvider(TestCase):
} }
return self._test_apply_with_data(TestData) return self._test_apply_with_data(TestData)
"""
def test_provider(self): def test_provider(self):
expected = self._load_full_config() expected = self._load_full_config()
@@ -707,17 +766,18 @@ class TestRackspaceProvider(TestCase):
with self.assertRaises(HTTPError): with self.assertRaises(HTTPError):
plan = self.provider.plan(expected) plan = self.provider.plan(expected)
self.provider.apply(plan) self.provider.apply(plan)
"""
def test_plan_no_changes(self): def test_plan_no_changes(self):
expected = Zone('unit.tests.', []) expected = Zone('unit.tests.', [])
expected.add_record(Record.new(expected, '', { expected.add_record(Record.new(expected, '', {
'type': 'NS', 'type': 'NS',
'ttl': 600, 'ttl': 600,
'values': ['8.8.8.8.', '9.9.9.9.'] 'values': ['ns1.example.com.', 'ns2.example.com.']
})) }))
expected.add_record(Record.new(expected, '', { expected.add_record(Record.new(expected, '', {
'type': 'A', 'type': 'A',
'ttl': 60, 'ttl': 600,
'value': '1.2.3.4' 'value': '1.2.3.4'
})) }))
@@ -735,7 +795,7 @@ class TestRackspaceProvider(TestCase):
expected.add_record(Record.new(expected, '', { expected.add_record(Record.new(expected, '', {
'type': 'NS', 'type': 'NS',
'ttl': 600, 'ttl': 600,
'values': ['8.8.8.8.', '9.9.9.9.'] 'values': ['ns1.example.com.', 'ns2.example.com.']
})) }))
with requests_mock() as mock: with requests_mock() as mock:
@@ -745,7 +805,7 @@ class TestRackspaceProvider(TestCase):
plan = self.provider.plan(expected) plan = self.provider.plan(expected)
self.assertTrue(mock.called) self.assertTrue(mock.called)
self.assertEquals(1, len(plan.changes)) self.assertEquals(1, len(plan.changes))
self.assertEqual(plan.changes[0].existing.ttl, 60) self.assertEqual(plan.changes[0].existing.ttl, 600)
self.assertEqual(plan.changes[0].existing.values[0], '1.2.3.4') self.assertEqual(plan.changes[0].existing.values[0], '1.2.3.4')
def test_plan_create_a_record(self): def test_plan_create_a_record(self):
@@ -753,11 +813,11 @@ class TestRackspaceProvider(TestCase):
expected.add_record(Record.new(expected, '', { expected.add_record(Record.new(expected, '', {
'type': 'NS', 'type': 'NS',
'ttl': 600, 'ttl': 600,
'values': ['8.8.8.8.', '9.9.9.9.'] 'values': ['ns1.example.com.', 'ns2.example.com.']
})) }))
expected.add_record(Record.new(expected, '', { expected.add_record(Record.new(expected, '', {
'type': 'A', 'type': 'A',
'ttl': 60, 'ttl': 600,
'values': ['1.2.3.4', '1.2.3.5'] 'values': ['1.2.3.4', '1.2.3.5']
})) }))
@@ -768,7 +828,7 @@ class TestRackspaceProvider(TestCase):
plan = self.provider.plan(expected) plan = self.provider.plan(expected)
self.assertTrue(mock.called) self.assertTrue(mock.called)
self.assertEquals(1, len(plan.changes)) self.assertEquals(1, len(plan.changes))
self.assertEqual(plan.changes[0].new.ttl, 60) self.assertEqual(plan.changes[0].new.ttl, 600)
self.assertEqual(plan.changes[0].new.values[0], '1.2.3.4') self.assertEqual(plan.changes[0].new.values[0], '1.2.3.4')
self.assertEqual(plan.changes[0].new.values[1], '1.2.3.5') self.assertEqual(plan.changes[0].new.values[1], '1.2.3.5')
@@ -777,7 +837,7 @@ class TestRackspaceProvider(TestCase):
expected.add_record(Record.new(expected, '', { expected.add_record(Record.new(expected, '', {
'type': 'NS', 'type': 'NS',
'ttl': 600, 'ttl': 600,
'values': ['8.8.8.8.', '9.9.9.9.'] 'values': ['ns1.example.com.', 'ns2.example.com.']
})) }))
expected.add_record(Record.new(expected, '', { expected.add_record(Record.new(expected, '', {
'type': 'A', 'type': 'A',
@@ -793,6 +853,6 @@ class TestRackspaceProvider(TestCase):
self.assertTrue(mock.called) self.assertTrue(mock.called)
self.assertEqual(1, len(plan.changes)) self.assertEqual(1, len(plan.changes))
self.assertEqual(plan.changes[0].existing.ttl, 60) self.assertEqual(plan.changes[0].existing.ttl, 600)
self.assertEqual(plan.changes[0].new.ttl, 86400) self.assertEqual(plan.changes[0].new.ttl, 86400)
self.assertEqual(plan.changes[0].new.values[0], '1.2.3.4') self.assertEqual(plan.changes[0].new.values[0], '1.2.3.4')