Repository: libcloud Updated Branches: refs/heads/trunk 26d6ac384 -> 624032598
Update worldwidedns provider with tests. Closes #621 Signed-off-by: Tomaz Muraus <[email protected]> Project: http://git-wip-us.apache.org/repos/asf/libcloud/repo Commit: http://git-wip-us.apache.org/repos/asf/libcloud/commit/e9e5f35e Tree: http://git-wip-us.apache.org/repos/asf/libcloud/tree/e9e5f35e Diff: http://git-wip-us.apache.org/repos/asf/libcloud/diff/e9e5f35e Branch: refs/heads/trunk Commit: e9e5f35e6cbdb2821bfb23d4061634a3b4eef592 Parents: 26d6ac3 Author: Alejandro Pereira <[email protected]> Authored: Mon Oct 12 12:26:49 2015 -0300 Committer: Tomaz Muraus <[email protected]> Committed: Sun Nov 1 19:23:26 2015 +0100 ---------------------------------------------------------------------- libcloud/dns/drivers/worldwidedns.py | 87 ++++++++----- ...ify_asp_CREATE_RECORD_MAX_ENTRIES_WITH_ENTRY | 46 +++++++ ...ns_list_domain_asp_CREATE_RECORD_MAX_ENTRIES | 46 +++++++ ...api_dns_list_domain_asp_CREATE_SECOND_RECORD | 46 +++++++ libcloud/test/dns/test_worldwidedns.py | 126 +++++++++++++++---- 5 files changed, 293 insertions(+), 58 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/libcloud/blob/e9e5f35e/libcloud/dns/drivers/worldwidedns.py ---------------------------------------------------------------------- diff --git a/libcloud/dns/drivers/worldwidedns.py b/libcloud/dns/drivers/worldwidedns.py index e3193bd..69373b1 100644 --- a/libcloud/dns/drivers/worldwidedns.py +++ b/libcloud/dns/drivers/worldwidedns.py @@ -144,22 +144,24 @@ class WorldWideDNSDriver(DNSDriver): :param zone_id: ID of the required zone :type zone_id: ``str`` - :param record_id: ID of the required record + :param record_id: ID number of the required record. :type record_id: ``str`` :rtype: :class:`Record` """ zone = self.get_zone(zone_id) - r_entry = [i for i in range(MAX_RECORD_ENTRIES) if - zone.extra.get('S%s' % i) == record_id] - if not r_entry: - raise RecordDoesNotExistError(value="Record doesn't exists", - driver=zone.driver, - record_id=record_id) - entry = r_entry[0] - type = zone.extra.get('T%s' % entry) - data = zone.extra.get('D%s' % entry) - record = self._to_record(record_id, type, data, zone) + try: + if int(record_id) not in range(1, MAX_RECORD_ENTRIES + 1): + raise RecordDoesNotExistError(value="Record doesn't exists", + driver=zone.driver, + record_id=record_id) + except ValueError: + raise WorldWideDNSError( + value="Record id should be a string number", driver=self) + subdomain = zone.extra.get('S%s' % record_id) + type = zone.extra.get('T%s' % record_id) + data = zone.extra.get('D%s' % record_id) + record = self._to_record(record_id, subdomain, type, data, zone) return record def update_zone(self, zone, domain, type='master', ttl=None, extra=None, @@ -259,7 +261,7 @@ class WorldWideDNSDriver(DNSDriver): if (extra is None) or ('entry' not in extra): raise WorldWideDNSError(value="You must enter 'entry' parameter", driver=self) - entry = extra.get('entry') + record_id = extra.get('entry') if name == '': name = '@' if type not in self.RECORD_TYPE_MAP: @@ -267,11 +269,11 @@ class WorldWideDNSDriver(DNSDriver): driver=record.zone.driver, record_id=name) zone = record.zone - extra = {'S%s' % entry: name, - 'T%s' % entry: type, - 'D%s' % entry: data} + extra = {'S%s' % record_id: name, + 'T%s' % record_id: type, + 'D%s' % record_id: data} zone = self.update_zone(zone, zone.domain, extra=extra) - record = self.get_record(zone.id, name) + record = self.get_record(zone.id, record_id) return record def create_zone(self, domain, type='master', ttl=None, extra=None): @@ -323,6 +325,9 @@ class WorldWideDNSDriver(DNSDriver): """ Create a new record. + We can create 40 record per domain. If all slots are full, we can + replace one of them by choosing a specific entry in ``extra`` argument. + :param name: Record name without the domain name (e.g. www). Note: If you want to create a record for a base domain name, you should specify empty string ('') for this @@ -344,20 +349,25 @@ class WorldWideDNSDriver(DNSDriver): :rtype: :class:`Record` """ if (extra is None) or ('entry' not in extra): - raise WorldWideDNSError(value="You must enter 'entry' parameter", - driver=zone.driver) - entry = extra.get('entry') + # If no entry is specified, we look for an available one. If all + # are full, raise error. + record_id = self._get_available_record_entry(zone) + if not record_id: + raise WorldWideDNSError(value="All record entries are full", + driver=zone.driver) + else: + record_id = extra.get('entry') if name == '': name = '@' if type not in self.RECORD_TYPE_MAP: raise RecordError(value="Record type is not allowed", driver=zone.driver, - record_id=name) - extra = {'S%s' % entry: name, - 'T%s' % entry: type, - 'D%s' % entry: data} + record_id=record_id) + extra = {'S%s' % record_id: name, + 'T%s' % record_id: type, + 'D%s' % record_id: data} zone = self.update_zone(zone, zone.domain, extra=extra) - record = self.get_record(zone.id, name) + record = self.get_record(zone.id, record_id) return record def delete_zone(self, zone): @@ -454,6 +464,17 @@ class WorldWideDNSDriver(DNSDriver): params=params) return response.success() + def _get_available_record_entry(self, zone): + """Return an available entry to store a record.""" + entries = zone.extra + for entry in range(1, MAX_RECORD_ENTRIES + 1): + subdomain = entries.get('S%s' % entry) + _type = entries.get('T%s' % entry) + data = entries.get('D%s' % entry) + if not any([subdomain, _type, data]): + return entry + return None + def _to_zones(self, data): domain_list = re.split('\r?\n', data) zones = [] @@ -479,7 +500,8 @@ class WorldWideDNSDriver(DNSDriver): for line in range(MAX_RECORD_ENTRIES): line_data = zone_data[line].split('\x1f') extra['S%s' % (line + 1)] = line_data[0] - extra['T%s' % (line + 1)] = line_data[1] + _type = line_data[1] + extra['T%s' % (line + 1)] = _type if _type != 'NONE' else '' try: extra['D%s' % (line + 1)] = line_data[2] except IndexError: @@ -499,14 +521,15 @@ class WorldWideDNSDriver(DNSDriver): def _to_records(self, zone): records = [] - for entry in range(MAX_RECORD_ENTRIES): - subdomain = zone.extra['S%s' % (entry + 1)] - type = zone.extra['T%s' % (entry + 1)] - data = zone.extra['D%s' % (entry + 1)] + for record_id in range(1, MAX_RECORD_ENTRIES + 1): + subdomain = zone.extra['S%s' % (record_id)] + type = zone.extra['T%s' % (record_id)] + data = zone.extra['D%s' % (record_id)] if subdomain and type and data: - record = self._to_record(subdomain, type, data, zone) + record = self._to_record( + record_id, subdomain, type, data, zone) records.append(record) return records - def _to_record(self, subdomain, type, data, zone): - return Record(subdomain, subdomain, type, data, zone, zone.driver) + def _to_record(self, _id, subdomain, type, data, zone): + return Record(_id, subdomain, type, data, zone, zone.driver) http://git-wip-us.apache.org/repos/asf/libcloud/blob/e9e5f35e/libcloud/test/dns/fixtures/worldwidedns/_api_dns_modify_asp_CREATE_RECORD_MAX_ENTRIES_WITH_ENTRY ---------------------------------------------------------------------- diff --git a/libcloud/test/dns/fixtures/worldwidedns/_api_dns_modify_asp_CREATE_RECORD_MAX_ENTRIES_WITH_ENTRY b/libcloud/test/dns/fixtures/worldwidedns/_api_dns_modify_asp_CREATE_RECORD_MAX_ENTRIES_WITH_ENTRY new file mode 100644 index 0000000..c001c0c --- /dev/null +++ b/libcloud/test/dns/fixtures/worldwidedns/_api_dns_modify_asp_CREATE_RECORD_MAX_ENTRIES_WITH_ENTRY @@ -0,0 +1,46 @@ +hostmaster.niteowebsponsoredthisone.com +21600 +10800 +604800 +43200 + +wwwA0.0.0.0 +domain2A0.0.0.2 +@MX10 niteowebsponsoredthisone.com +domain4A0.0.0.4 +domain5A0.0.0.5 +domain6A0.0.0.6 +domain7A0.0.0.7 +domain8A0.0.0.8 +domain9A0.0.0.9 +domain10A0.0.0.10 +domain11A0.0.0.11 +domain12A0.0.0.12 +domain13A0.0.0.13 +domain14A0.0.0.14 +domain15A0.0.0.15 +domain16A0.0.0.16 +domain17A0.0.0.17 +domain18A0.0.0.18 +domain19A0.0.0.19 +domain20A0.0.0.20 +domain21A0.0.0.21 +domain22A0.0.0.22 +domain23bA0.0.0.41 +domain24A0.0.0.24 +domain25A0.0.0.25 +domain26A0.0.0.26 +domain27A0.0.0.27 +domain28A0.0.0.28 +domain29A0.0.0.29 +domain30A0.0.0.30 +domain31A0.0.0.31 +domain32A0.0.0.32 +domain33A0.0.0.33 +domain34A0.0.0.34 +domain35A0.0.0.35 +domain36A0.0.0.36 +domain37A0.0.0.37 +domain38A0.0.0.38 +domain39A0.0.0.39 +domain40A0.0.0.40 \ No newline at end of file http://git-wip-us.apache.org/repos/asf/libcloud/blob/e9e5f35e/libcloud/test/dns/fixtures/worldwidedns/api_dns_list_domain_asp_CREATE_RECORD_MAX_ENTRIES ---------------------------------------------------------------------- diff --git a/libcloud/test/dns/fixtures/worldwidedns/api_dns_list_domain_asp_CREATE_RECORD_MAX_ENTRIES b/libcloud/test/dns/fixtures/worldwidedns/api_dns_list_domain_asp_CREATE_RECORD_MAX_ENTRIES new file mode 100644 index 0000000..ff570e5 --- /dev/null +++ b/libcloud/test/dns/fixtures/worldwidedns/api_dns_list_domain_asp_CREATE_RECORD_MAX_ENTRIES @@ -0,0 +1,46 @@ +hostmaster.niteowebsponsoredthisone.com +21600 +10800 +604800 +43200 + +wwwA0.0.0.0 +domain2A0.0.0.2 +@MX10 niteowebsponsoredthisone.com +domain4A0.0.0.4 +domain5A0.0.0.5 +domain6A0.0.0.6 +domain7A0.0.0.7 +domain8A0.0.0.8 +domain9A0.0.0.9 +domain10A0.0.0.10 +domain11A0.0.0.11 +domain12A0.0.0.12 +domain13A0.0.0.13 +domain14A0.0.0.14 +domain15A0.0.0.15 +domain16A0.0.0.16 +domain17A0.0.0.17 +domain18A0.0.0.18 +domain19A0.0.0.19 +domain20A0.0.0.20 +domain21A0.0.0.21 +domain22A0.0.0.22 +domain23A0.0.0.23 +domain24A0.0.0.24 +domain25A0.0.0.25 +domain26A0.0.0.26 +domain27A0.0.0.27 +domain28A0.0.0.28 +domain29A0.0.0.29 +domain30A0.0.0.30 +domain31A0.0.0.31 +domain32A0.0.0.32 +domain33A0.0.0.33 +domain34A0.0.0.34 +domain35A0.0.0.35 +domain36A0.0.0.36 +domain37A0.0.0.37 +domain38A0.0.0.38 +domain39A0.0.0.39 +domain40A0.0.0.40 \ No newline at end of file http://git-wip-us.apache.org/repos/asf/libcloud/blob/e9e5f35e/libcloud/test/dns/fixtures/worldwidedns/api_dns_list_domain_asp_CREATE_SECOND_RECORD ---------------------------------------------------------------------- diff --git a/libcloud/test/dns/fixtures/worldwidedns/api_dns_list_domain_asp_CREATE_SECOND_RECORD b/libcloud/test/dns/fixtures/worldwidedns/api_dns_list_domain_asp_CREATE_SECOND_RECORD new file mode 100644 index 0000000..b6b7701 --- /dev/null +++ b/libcloud/test/dns/fixtures/worldwidedns/api_dns_list_domain_asp_CREATE_SECOND_RECORD @@ -0,0 +1,46 @@ +hostmaster.niteowebsponsoredthisone.com +21600 +10800 +604800 +43200 + +wwwA0.0.0.0 +domain2A0.0.0.2 +@MX10 niteowebsponsoredthisone.com +domain4A0.0.0.4 +domain1A0.0.0.1 +NONE +NONE +NONE +NONE +NONE +NONE +NONE +NONE +NONE +NONE +NONE +NONE +NONE +NONE +NONE +NONE +NONE +NONE +NONE +NONE +NONE +NONE +NONE +NONE +NONE +NONE +NONE +NONE +NONE +NONE +NONE +NONE +NONE +NONE +NONE \ No newline at end of file http://git-wip-us.apache.org/repos/asf/libcloud/blob/e9e5f35e/libcloud/test/dns/test_worldwidedns.py ---------------------------------------------------------------------- diff --git a/libcloud/test/dns/test_worldwidedns.py b/libcloud/test/dns/test_worldwidedns.py index 3b19722..388e5c0 100644 --- a/libcloud/test/dns/test_worldwidedns.py +++ b/libcloud/test/dns/test_worldwidedns.py @@ -70,7 +70,7 @@ class WorldWideDNSTests(unittest.TestCase): self.assertEqual(len(records), 3) www = records[0] - self.assertEqual(www.id, 'www') + self.assertEqual(www.id, '1') self.assertEqual(www.name, 'www') self.assertEqual(www.type, RecordType.A) self.assertEqual(www.data, '0.0.0.0') @@ -109,8 +109,8 @@ class WorldWideDNSTests(unittest.TestCase): def test_get_record_success(self): record = self.driver.get_record(zone_id='niteowebsponsoredthisone.com', - record_id='www') - self.assertEqual(record.id, 'www') + record_id='1') + self.assertEqual(record.id, '1') self.assertEqual(record.name, 'www') self.assertEqual(record.type, RecordType.A) self.assertEqual(record.data, '0.0.0.0') @@ -195,56 +195,77 @@ class WorldWideDNSTests(unittest.TestCase): type=RecordType.A, data='0.0.0.4', extra={'entry': 4}) - self.assertEqual(record.id, 'domain4') + self.assertEqual(record.id, '4') self.assertEqual(record.name, 'domain4') self.assertNotEqual(record.zone.extra.get('S4'), zone.extra.get('S4')) self.assertNotEqual(record.zone.extra.get('D4'), zone.extra.get('D4')) self.assertEqual(record.type, RecordType.A) self.assertEqual(record.data, '0.0.0.4') - def test_create_record_missing_entry(self): + def test_create_record_finding_entry(self): zone = self.driver.list_zones()[0] WorldWideDNSMockHttp.type = 'CREATE_RECORD' + record = self.driver.create_record(name='domain4', zone=zone, + type=RecordType.A, data='0.0.0.4') + WorldWideDNSMockHttp.type = 'CREATE_SECOND_RECORD' + zone = record.zone + record2 = self.driver.create_record(name='domain1', zone=zone, + type=RecordType.A, data='0.0.0.1') + self.assertEqual(record.id, '4') + self.assertEqual(record2.id, '5') + + def test_create_record_max_entry_reached(self): + zone = self.driver.list_zones()[0] + WorldWideDNSMockHttp.type = 'CREATE_RECORD_MAX_ENTRIES' + record = self.driver.create_record(name='domain40', zone=zone, + type=RecordType.A, data='0.0.0.40') + WorldWideDNSMockHttp.type = 'CREATE_RECORD' + zone = record.zone try: - self.driver.create_record(name='domain1', zone=zone, - type=RecordType.A, data='0.0.0.1', - extra={'non_entry': 1}) + self.driver.create_record( + name='domain41', zone=zone, type=RecordType.A, data='0.0.0.41') except WorldWideDNSError: e = sys.exc_info()[1] - self.assertEqual(e.value, "You must enter 'entry' parameter") + self.assertEqual(e.value, 'All record entries are full') else: self.fail('Exception was not thrown') + def test_create_record_max_entry_reached_give_entry(self): + WorldWideDNSMockHttp.type = 'CREATE_RECORD_MAX_ENTRIES' + zone = self.driver.list_zones()[0] + record = self.driver.get_record(zone.id, '23') + self.assertEqual(record.id, '23') + self.assertEqual(record.name, 'domain23') + self.assertEqual(record.type, 'A') + self.assertEqual(record.data, '0.0.0.23') + + # No matter if we have all entries full, if we choose a specific + # entry, the record will be replaced with the new one. + WorldWideDNSMockHttp.type = 'CREATE_RECORD_MAX_ENTRIES_WITH_ENTRY' + record = self.driver.create_record(name='domain23b', zone=zone, + type=RecordType.A, data='0.0.0.41', + extra={'entry': 23}) + zone = record.zone + self.assertEqual(record.id, '23') + self.assertEqual(record.name, 'domain23b') + self.assertEqual(record.type, 'A') + self.assertEqual(record.data, '0.0.0.41') + def test_update_record_success(self): zone = self.driver.list_zones()[0] - record = self.driver.get_record(zone.id, 'www') + record = self.driver.get_record(zone.id, '1') WorldWideDNSMockHttp.type = 'UPDATE_RECORD' record = self.driver.update_record(record=record, name='domain1', type=RecordType.A, data='0.0.0.1', extra={'entry': 1}) - self.assertEqual(record.id, 'domain1') + self.assertEqual(record.id, '1') self.assertEqual(record.name, 'domain1') self.assertNotEqual(record.zone.extra.get('S1'), zone.extra.get('S1')) self.assertNotEqual(record.zone.extra.get('D1'), zone.extra.get('D1')) self.assertEqual(record.type, RecordType.A) self.assertEqual(record.data, '0.0.0.1') - def test_update_record_missing_entry(self): - zone = self.driver.list_zones()[0] - record = self.driver.get_record(zone.id, 'www') - WorldWideDNSMockHttp.type = 'UPDATE_RECORD' - try: - record = self.driver.update_record(record=record, name='domain1', - type=RecordType.A, - data='0.0.0.1', - extra={'non_entry': 1}) - except WorldWideDNSError: - e = sys.exc_info()[1] - self.assertEqual(e.value, "You must enter 'entry' parameter") - else: - self.fail('Exception was not thrown') - def test_delete_zone_success(self): zone = self.driver.list_zones()[0] status = self.driver.delete_zone(zone=zone) @@ -323,15 +344,68 @@ class WorldWideDNSMockHttp(MockHttp): body = self.fixtures.load('api_dns_list') return (httplib.OK, body, {}, httplib.responses[httplib.OK]) + def _api_dns_list_asp_CREATE_SECOND_RECORD(self, method, url, body, + headers): + body = self.fixtures.load('api_dns_list') + return (httplib.OK, body, {}, httplib.responses[httplib.OK]) + def _api_dns_modify_asp_CREATE_RECORD(self, method, url, body, headers): return (httplib.OK, '211\r\n212\r\n213', {}, httplib.responses[httplib.OK]) + def _api_dns_modify_asp_CREATE_SECOND_RECORD(self, method, url, body, + headers): + return (httplib.OK, '211\r\n212\r\n213', {}, + httplib.responses[httplib.OK]) + def _api_dns_list_domain_asp_CREATE_RECORD(self, method, url, body, headers): body = self.fixtures.load('api_dns_list_domain_asp_CREATE_RECORD') return (httplib.OK, body, {}, httplib.responses[httplib.OK]) + def _api_dns_list_domain_asp_CREATE_SECOND_RECORD(self, method, url, body, + headers): + body = self.fixtures.load( + 'api_dns_list_domain_asp_CREATE_SECOND_RECORD') + return (httplib.OK, body, {}, httplib.responses[httplib.OK]) + + def _api_dns_list_domain_asp_CREATE_RECORD_MAX_ENTRIES(self, method, url, + body, headers): + body = self.fixtures.load( + 'api_dns_list_domain_asp_CREATE_RECORD_MAX_ENTRIES') + return (httplib.OK, body, {}, httplib.responses[httplib.OK]) + + def _api_dns_modify_asp_CREATE_RECORD_MAX_ENTRIES(self, method, url, body, + headers): + return (httplib.OK, '211\r\n212\r\n213', {}, + httplib.responses[httplib.OK]) + + def _api_dns_list_asp_CREATE_RECORD_MAX_ENTRIES(self, method, url, body, + headers): + body = self.fixtures.load('api_dns_list') + return (httplib.OK, body, {}, httplib.responses[httplib.OK]) + + def _api_dns_list_domain_asp_CREATE_RECORD_MAX_ENTRIES_WITH_ENTRY(self, + method, + url, + body, + headers): + body = self.fixtures.load( + '_api_dns_modify_asp_CREATE_RECORD_MAX_ENTRIES_WITH_ENTRY') + return (httplib.OK, body, {}, httplib.responses[httplib.OK]) + + def _api_dns_modify_asp_CREATE_RECORD_MAX_ENTRIES_WITH_ENTRY(self, method, + url, body, + headers): + return (httplib.OK, '211\r\n212\r\n213', {}, + httplib.responses[httplib.OK]) + + def _api_dns_list_asp_CREATE_RECORD_MAX_ENTRIES_WITH_ENTRY(self, method, + url, body, + headers): + body = self.fixtures.load('api_dns_list') + return (httplib.OK, body, {}, httplib.responses[httplib.OK]) + def _api_dns_list_asp_UPDATE_RECORD(self, method, url, body, headers): body = self.fixtures.load('api_dns_list') return (httplib.OK, body, {}, httplib.responses[httplib.OK])
