Skip to content

Commit 00bc615

Browse files
author
Aaron Sierra
committed
dns: nsone: Use locally-relevant zone and record IDs
Previously, our NsOneDNSDriver.get_record() function performed lookups using a `record_id` format that differed from the ID embedded within the returned Record instance, so the driver leveraged two independent record ID concepts simultaneously. The NS1 API returns an ID when records are created, but that ID has no local relevance. For example, it cannot be used to request the record from the NS1 API. Make the Record class .id value consistent between create_record() and get_record(z.id, r.id). | zone_id | z.id | r.id | record_id | ---------|----------|----------|---------------|---------------| previous | z.domain | random* | random* | r.type | next | z.domain | z.domain | r.type:r.name | r.type:r.name | * no meaning, effectively random
1 parent d0bb79c commit 00bc615

2 files changed

Lines changed: 36 additions & 28 deletions

File tree

libcloud/dns/drivers/nsone.py

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -163,20 +163,22 @@ def get_record(self, zone_id, record_id):
163163
:param zone_id: The id of the zone where to search for
164164
the record (e.g. example.com)
165165
:type zone_id: ``str``
166-
:param record_id: The type of record to search for
167-
(e.g. A, AAA, MX etc)
166+
:param record_id: The record type joined with the record
167+
name by a colon, if non-empty (e.g. A, AAAA:www, MX:mail, etc)
168168
169169
:return: :class:`Record`
170170
"""
171-
action = "/v1/zones/{}/{}/{}".format(zone_id, zone_id, record_id)
171+
zone = self.get_zone(zone_id=zone_id)
172+
parts = self.from_default_id(zone, record_id)
173+
rdomain = zone.hostname(parts.name)
174+
action = f"/v1/zones/{zone.domain}/{rdomain}/{parts.type}"
172175
try:
173176
response = self.connection.request(action=action, method="GET")
174177
except NsOneException as e:
175178
if e.message == "record not found":
176179
raise RecordDoesNotExistError(value=e.message, driver=self, record_id=record_id)
177180
else:
178181
raise e
179-
zone = self.get_zone(zone_id=zone_id)
180182
record = self._to_record(item=response.parse_body(), zone=zone)
181183

182184
return record
@@ -213,7 +215,7 @@ def create_record(self, name, zone, type, data, extra=None):
213215
:type extra: ``dict``
214216
:return: :class:`Record`
215217
"""
216-
record_name = "{}.{}".format(name, zone.domain) if name != "" else zone.domain # noqa
218+
record_name = zone.hostname(name)
217219

218220
action = "/v1/zones/{}/{}/{}".format(zone.domain, record_name, type)
219221
if type == RecordType.MX:
@@ -258,7 +260,7 @@ def update_record(self, record, name, type, data, extra=None):
258260
zone = record.zone
259261
action = "/v1/zones/{}/{}/{}".format(
260262
zone.domain,
261-
"{}.{}".format(name, zone.domain),
263+
zone.hostname(name),
262264
type,
263265
)
264266
raw_data = {"answers": [{"answer": [data]}]}
@@ -300,9 +302,10 @@ def _to_zone(self, item):
300302
if key not in common_attr:
301303
extra[key] = item.get(key)
302304

305+
zdomain = item["zone"]
303306
zone = Zone(
304-
domain=item["zone"],
305-
id=item["id"],
307+
domain=zdomain,
308+
id=zdomain,
306309
type=item.get("type"),
307310
extra=extra,
308311
ttl=extra.get("ttl"),
@@ -328,10 +331,12 @@ def _to_record(self, item, zone):
328331
data = item.get("answers")[0]["answer"]
329332
else:
330333
data = item.get("short_answers")
334+
rdomain = item["domain"]
335+
rtype = item["type"]
331336
record = Record(
332-
id=item["id"],
333-
name=item["domain"],
334-
type=item["type"],
337+
id=self.to_default_id(zone, rdomain, rtype),
338+
name=rdomain,
339+
type=rtype,
335340
data=data,
336341
zone=zone,
337342
driver=self,

libcloud/test/dns/test_nsone.py

Lines changed: 20 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -54,9 +54,9 @@ def setUp(self):
5454
driver=self,
5555
)
5656
self.test_record = Record(
57-
id="13",
57+
id="A",
5858
type=RecordType.A,
59-
name="example.com",
59+
name="test.com",
6060
zone=self.test_zone,
6161
data="127.0.0.1",
6262
driver=self,
@@ -75,13 +75,13 @@ def test_list_zones_success(self):
7575
self.assertEqual(len(zones), 2)
7676

7777
zone = zones[0]
78-
self.assertEqual(zone.id, "520422af9f782d37dffb588b")
78+
self.assertEqual(zone.id, "example.com")
7979
self.assertIsNone(zone.type)
8080
self.assertEqual(zone.domain, "example.com")
8181
self.assertEqual(zone.ttl, 3600)
8282

8383
zone = zones[1]
84-
self.assertEqual(zone.id, "520422c99f782d37dffb5892")
84+
self.assertEqual(zone.id, "nsoneisgreat.com")
8585
self.assertIsNone(zone.type)
8686
self.assertEqual(zone.domain, "nsoneisgreat.com")
8787
self.assertEqual(zone.ttl, 3600)
@@ -115,7 +115,7 @@ def test_create_zone_success(self):
115115
NsOneMockHttp.type = "CREATE_ZONE_SUCCESS"
116116
zone = self.driver.create_zone(domain="newzone.com")
117117

118-
self.assertEqual(zone.id, "52051b2c9f782d58bb4df41b")
118+
self.assertEqual(zone.id, "newzone.com")
119119
self.assertEqual(zone.domain, "newzone.com")
120120
self.assertIsNone(zone.type),
121121
self.assertEqual(zone.ttl, 3600)
@@ -134,17 +134,17 @@ def test_get_record_record_does_not_exist(self):
134134
NsOneMockHttp.type = "GET_RECORD_DOES_NOT_EXIST"
135135

136136
try:
137-
self.driver.get_record(zone_id="getrecord.com", record_id="A")
137+
self.driver.get_record(zone_id="example.com", record_id="A")
138138
except RecordDoesNotExistError as e:
139139
self.assertEqual(e.record_id, "A")
140140
else:
141141
self.fail("Exception was not thrown")
142142

143143
def test_get_record_success(self):
144144
NsOneMockHttp.type = "GET_RECORD_SUCCESS"
145-
record = self.driver.get_record(zone_id="example.com", record_id="520519509f782d58bb4df419")
145+
record = self.driver.get_record(zone_id="example.com", record_id="A:www")
146146

147-
self.assertEqual(record.id, "520519509f782d58bb4df419")
147+
self.assertEqual(record.id, "A:www")
148148
self.assertEqual(record.name, "www.example.com")
149149
self.assertEqual(record.data, ["1.1.1.1"])
150150
self.assertEqual(record.type, RecordType.A)
@@ -171,7 +171,7 @@ def test_list_records_success(self):
171171
self.assertEqual(len(records), 2)
172172

173173
arecord = records[1]
174-
self.assertEqual(arecord.id, "520519509f782d58bb4df419")
174+
self.assertEqual(arecord.id, "A:www")
175175
self.assertEqual(arecord.name, "www.example.com")
176176
self.assertEqual(arecord.type, RecordType.A)
177177
self.assertEqual(arecord.data, ["1.2.3.4"])
@@ -185,7 +185,7 @@ def test_create_record_success(self):
185185
self.test_record.data,
186186
self.test_record.extra,
187187
)
188-
self.assertEqual(arecord.id, "608f9619ebe68600ac9f807d")
188+
self.assertEqual(arecord.id, "A")
189189
self.assertEqual(arecord.name, "test.com")
190190
self.assertEqual(arecord.type, RecordType.A)
191191
self.assertEqual(arecord.data, ["127.0.0.1"])
@@ -297,19 +297,19 @@ def _v1_zones_test_com_LIST_RECORDS_ZONE_DOES_NOT_EXIST(self, method, url, body,
297297

298298
return httplib.OK, body, {}, httplib.responses[httplib.OK]
299299

300-
def _v1_zones_test_com_example_com_A_DELETE_RECORD_RECORD_DOES_NOT_EXIST(
300+
def _v1_zones_test_com_test_com_A_DELETE_RECORD_RECORD_DOES_NOT_EXIST(
301301
self, method, url, body, headers
302302
):
303303
body = self.fixtures.load("record_does_not_exist.json")
304304

305305
return 404, body, {}, httplib.responses[httplib.OK]
306306

307-
def _v1_zones_test_com_example_com_A_DELETE_RECORD_SUCCESS(self, method, url, body, headers):
307+
def _v1_zones_test_com_test_com_A_DELETE_RECORD_SUCCESS(self, method, url, body, headers):
308308
body = self.fixtures.load("delete_record_success.json")
309309

310310
return httplib.OK, body, {}, httplib.responses[httplib.OK]
311311

312-
def _v1_zones_example_com_example_com_520519509f782d58bb4df419_GET_RECORD_SUCCESS(
312+
def _v1_zones_example_com_www_example_com_A_GET_RECORD_SUCCESS(
313313
self, method, url, body, headers
314314
):
315315
body = self.fixtures.load("get_record_success.json")
@@ -321,28 +321,31 @@ def _v1_zones_example_com_GET_RECORD_SUCCESS(self, method, url, body, headers):
321321

322322
return httplib.OK, body, {}, httplib.responses[httplib.OK]
323323

324-
def _v1_zones_getrecord_com_getrecord_com_A_GET_RECORD_DOES_NOT_EXIST(
324+
def _v1_zones_example_com_example_com_A_GET_RECORD_DOES_NOT_EXIST(
325325
self, method, url, body, headers
326326
):
327327
body = self.fixtures.load("record_does_not_exist.json")
328328

329329
return httplib.OK, body, {}, httplib.responses[httplib.OK]
330330

331-
def _v1_zones_test_com_example_com_test_com_A_CREATE_RECORD_SUCCESS(
331+
def _v1_zones_example_com_GET_RECORD_DOES_NOT_EXIST(self, method, url, body, headers):
332+
return self._v1_zones_example_com_GET_RECORD_SUCCESS(method, url, body, headers)
333+
334+
def _v1_zones_test_com_test_com_A_CREATE_RECORD_SUCCESS(
332335
self, method, url, body, headers
333336
):
334337
body = self.fixtures.load("create_record_success.json")
335338

336339
return httplib.OK, body, {}, httplib.responses[httplib.OK]
337340

338-
def _v1_zones_test_com_example_com_test_com_A_CREATE_RECORD_ALREADY_EXISTS(
341+
def _v1_zones_test_com_test_com_A_CREATE_RECORD_ALREADY_EXISTS(
339342
self, method, url, body, headers
340343
):
341344
body = self.fixtures.load("create_record_already_exists.json")
342345

343346
return 404, body, {}, httplib.responses[httplib.OK]
344347

345-
def _v1_zones_test_com_example_com_test_com_A_CREATE_RECORD_ZONE_NOT_FOUND(
348+
def _v1_zones_test_com_test_com_A_CREATE_RECORD_ZONE_NOT_FOUND(
346349
self, method, url, body, headers
347350
):
348351
body = self.fixtures.load("create_record_zone_not_found.json")

0 commit comments

Comments
 (0)