Skip to content

Commit 2e7ecac

Browse files
Address PR review feedback - rename methods, consolidate export logic, update docs and version to 0.28.0
1 parent c2b75da commit 2e7ecac

5 files changed

Lines changed: 66 additions & 38 deletions

File tree

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
## 0.28.0 (TBD)
2+
3+
ENHANCEMENTS:
4+
* Add zone export functionality to export zones in BIND format for backup/migration
5+
16
## 0.27.1 (December 3rd, 2025)
27

38
FIXED:

examples/zone-export.py

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,21 @@
1515
# to load an alternate configuration file:
1616
# api = NS1(configFile='/etc/ns1/api.json')
1717

18-
# export a zone to BIND format
18+
# Export a zone to BIND format
19+
# The export() method will:
20+
# 1. Initiate the export job
21+
# 2. Poll the status until complete or failed
22+
# 3. Download and return the zone file content
1923
zone = api.loadZone("example.com")
24+
25+
print("Exporting zone example.com...")
2026
zone_file = zone.export()
27+
print("Export complete!")
2128
print(zone_file)
2229

23-
# save to a file
24-
with open("example.com.zone", "w") as f:
30+
# Save to a file
31+
with open("example.com.txt", "w") as f:
2532
f.write(zone_file)
33+
print("Zone file saved to example.com.txt")
34+
35+
# Made with Bob

ns1/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
#
66
from .config import Config
77

8-
version = "0.27.1"
8+
version = "0.28.0"
99

1010

1111
class NS1:

ns1/rest/zones.py

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -188,45 +188,45 @@ def delete_version(self, zone, version_id, callback=None, errback=None):
188188
errback=errback,
189189
)
190190

191-
def export(self, zone, callback=None, errback=None):
191+
def initiate_zonefile_export(self, zone, callback=None, errback=None):
192192
"""
193-
Export zone as BIND-compatible zone file.
193+
Initiate zone export job.
194194
195195
:param str zone: zone name
196-
:return: zone file content as string
196+
:return: export status response
197197
"""
198198
return self._make_request(
199-
"GET",
200-
f"{self.ROOT}/{zone}/export",
199+
"PUT",
200+
f"export/zonefile/{zone}",
201+
body={},
201202
callback=callback,
202203
errback=errback,
203204
)
204205

205-
def initiate_export(self, zone, callback=None, errback=None):
206+
def status_zonefile_export(self, zone, callback=None, errback=None):
206207
"""
207-
Initiate zone export job.
208+
Check zone export status.
208209
209210
:param str zone: zone name
210211
:return: export status response
211212
"""
212213
return self._make_request(
213-
"PUT",
214-
f"export/zonefile/{zone}",
215-
body={},
214+
"GET",
215+
f"export/zonefile/{zone}/status",
216216
callback=callback,
217217
errback=errback,
218218
)
219219

220-
def export_status(self, zone, callback=None, errback=None):
220+
def get_zonefile_export(self, zone, callback=None, errback=None):
221221
"""
222-
Check zone export status.
222+
Download the exported zone file in BIND-compatible format.
223223
224224
:param str zone: zone name
225-
:return: export status response
225+
:return: zone file content as string
226226
"""
227227
return self._make_request(
228228
"GET",
229-
f"export/zonefile/{zone}/status",
229+
f"{self.ROOT}/{zone}/export",
230230
callback=callback,
231231
errback=errback,
232232
)

ns1/zones.py

Lines changed: 33 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -288,36 +288,49 @@ def usage(self, callback=None, errback=None, **kwargs):
288288
zone=self.zone, callback=callback, errback=errback, **kwargs
289289
)
290290

291-
def export(self, callback=None, errback=None):
291+
def export(self, callback=None, errback=None, timeout=300, poll_interval=2):
292292
"""
293293
Export zone as a BIND-compatible zone file.
294+
295+
This method initiates the export, polls the status until complete or failed,
296+
and downloads the zone file.
294297
295298
:param callback: optional callback
296299
:param errback: optional error callback
300+
:param int timeout: maximum time to wait for export completion in seconds (default: 300)
301+
:param int poll_interval: time between status checks in seconds (default: 2)
297302
:return: zone file content as string
303+
:raises ZoneException: if export fails or times out
298304
"""
299-
return self._rest.export(self.zone, callback=callback, errback=errback)
305+
import time
300306

301-
def initiate_export(self, callback=None, errback=None):
302-
"""
303-
Initiate zone export job.
307+
# Initiate the export
308+
self._rest.initiate_zonefile_export(self.zone)
304309

305-
:param callback: optional callback
306-
:param errback: optional error callback
307-
:return: export status response
308-
"""
309-
return self._rest.initiate_export(
310-
self.zone, callback=callback, errback=errback
311-
)
310+
# Poll the status until complete or failed
311+
start_time = time.time()
312+
while True:
313+
if time.time() - start_time > timeout:
314+
raise ZoneException(
315+
f"Zone export timed out after {timeout} seconds"
316+
)
312317

313-
def export_status(self, callback=None, errback=None):
314-
"""
315-
Check zone export status.
318+
status_response = self._rest.status_zonefile_export(self.zone)
319+
status = status_response.get("status")
316320

317-
:param callback: optional callback
318-
:param errback: optional error callback
319-
:return: export status response
320-
"""
321-
return self._rest.export_status(
321+
if status == "COMPLETE":
322+
break
323+
elif status == "FAILED":
324+
error_msg = status_response.get("message", "Unknown error")
325+
raise ZoneException(f"Zone export failed: {error_msg}")
326+
327+
time.sleep(poll_interval)
328+
329+
# Download the zone file
330+
zone_file = self._rest.get_zonefile_export(
322331
self.zone, callback=callback, errback=errback
323332
)
333+
334+
if callback:
335+
return callback(zone_file)
336+
return zone_file

0 commit comments

Comments
 (0)