fb-pdnstools 1.0.2__py3-none-any.whl → 1.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- fb_pdnstools/__init__.py +76 -34
- fb_pdnstools/base_handler.py +119 -102
- fb_pdnstools/bulk_rm_app.py +242 -152
- fb_pdnstools/bulk_rm_cfg.py +33 -19
- fb_pdnstools/common.py +13 -13
- fb_pdnstools/errors.py +15 -15
- fb_pdnstools/record.py +407 -241
- fb_pdnstools/server.py +81 -44
- fb_pdnstools/xlate.py +57 -36
- fb_pdnstools/zone.py +600 -369
- fb_pdnstools-1.1.0.data/data/share/locale/de/LC_MESSAGES/fb_pdnstools.mo +0 -0
- fb_pdnstools-1.1.0.data/data/share/locale/en/LC_MESSAGES/fb_pdnstools.mo +0 -0
- fb_pdnstools-1.1.0.dist-info/METADATA +53 -0
- fb_pdnstools-1.1.0.dist-info/RECORD +17 -0
- {fb_pdnstools-1.0.2.dist-info → fb_pdnstools-1.1.0.dist-info}/WHEEL +1 -2
- fb_pdnstools-1.1.0.dist-info/entry_points.txt +3 -0
- fb_pdnstools/local_version.py +0 -17
- fb_pdnstools-1.0.2.data/scripts/pdns-bulk-remove +0 -68
- fb_pdnstools-1.0.2.dist-info/METADATA +0 -40
- fb_pdnstools-1.0.2.dist-info/RECORD +0 -17
- fb_pdnstools-1.0.2.dist-info/top_level.txt +0 -1
- {fb_pdnstools-1.0.2.dist-info → fb_pdnstools-1.1.0.dist-info/licenses}/LICENSE +0 -0
fb_pdnstools/zone.py
CHANGED
|
@@ -16,6 +16,7 @@ import json
|
|
|
16
16
|
import logging
|
|
17
17
|
import re
|
|
18
18
|
from functools import cmp_to_key
|
|
19
|
+
|
|
19
20
|
try:
|
|
20
21
|
from collections.abc import MutableMapping
|
|
21
22
|
except ImportError:
|
|
@@ -48,7 +49,7 @@ from .record import PowerDNSRecordSetList
|
|
|
48
49
|
from .record import PowerDnsSOAData
|
|
49
50
|
from .xlate import XLATOR
|
|
50
51
|
|
|
51
|
-
__version__ =
|
|
52
|
+
__version__ = "1.0.0"
|
|
52
53
|
|
|
53
54
|
LOG = logging.getLogger(__name__)
|
|
54
55
|
|
|
@@ -60,26 +61,53 @@ ngettext = XLATOR.ngettext
|
|
|
60
61
|
class PowerDNSZone(BasePowerDNSHandler):
|
|
61
62
|
"""An encapsulation class for zone objects by PowerDNS API."""
|
|
62
63
|
|
|
63
|
-
re_rev_ipv4 = re.compile(r
|
|
64
|
-
re_rev_ipv6 = re.compile(r
|
|
64
|
+
re_rev_ipv4 = re.compile(r"^((?:\d+\.)*\d+)\.in-addr\.arpa\.?$", re.IGNORECASE)
|
|
65
|
+
re_rev_ipv6 = re.compile(r"^((?:[0-9a-f]\.)*[0-9a-f])\.ip6.arpa.?$", re.IGNORECASE)
|
|
65
66
|
|
|
66
67
|
warn_on_unknown_property = False
|
|
67
68
|
|
|
68
69
|
# -------------------------------------------------------------------------
|
|
69
70
|
def __init__(
|
|
70
|
-
self,
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
71
|
+
self,
|
|
72
|
+
appname=None,
|
|
73
|
+
verbose=0,
|
|
74
|
+
version=__version__,
|
|
75
|
+
base_dir=None,
|
|
76
|
+
account=None,
|
|
77
|
+
dnssec=False,
|
|
78
|
+
edited_serial=None,
|
|
79
|
+
zone_id=None,
|
|
80
|
+
kind=None, # noqa: A002
|
|
81
|
+
last_check=None,
|
|
82
|
+
master_tsig_key_ids=None,
|
|
83
|
+
slave_tsig_key_ids=None,
|
|
84
|
+
masters=None,
|
|
85
|
+
name=None,
|
|
86
|
+
notified_serial=None,
|
|
87
|
+
serial=None,
|
|
88
|
+
url=None,
|
|
89
|
+
soa_edit=None,
|
|
90
|
+
soa_edit_api=None,
|
|
91
|
+
nsec3narrow=None,
|
|
92
|
+
nsec3param=None,
|
|
93
|
+
presigned=None,
|
|
94
|
+
api_rectify=None,
|
|
95
|
+
master_server=None,
|
|
96
|
+
port=DEFAULT_PORT,
|
|
97
|
+
key=None,
|
|
98
|
+
use_https=False,
|
|
99
|
+
timeout=None,
|
|
100
|
+
path_prefix=DEFAULT_API_PREFIX,
|
|
101
|
+
simulate=None,
|
|
102
|
+
force=None,
|
|
103
|
+
terminal_has_colors=False,
|
|
104
|
+
initialized=None,
|
|
105
|
+
**kwargs,
|
|
106
|
+
):
|
|
79
107
|
"""Initialize a PowerDNSZone record."""
|
|
80
108
|
self._account = account
|
|
81
109
|
self._dnssec = dnssec
|
|
82
|
-
self.
|
|
110
|
+
self._zone_id = zone_id
|
|
83
111
|
self._kind = kind
|
|
84
112
|
self._last_check = last_check
|
|
85
113
|
self.masters = []
|
|
@@ -94,7 +122,7 @@ class PowerDNSZone(BasePowerDNSHandler):
|
|
|
94
122
|
if nsec3narrow is not None:
|
|
95
123
|
self._nsec3narrow = to_bool(nsec3narrow)
|
|
96
124
|
self._nsec3param = None
|
|
97
|
-
if nsec3param is not None and str(nsec3param).strip() !=
|
|
125
|
+
if nsec3param is not None and str(nsec3param).strip() != "":
|
|
98
126
|
self._nsec3param = str(nsec3param).strip()
|
|
99
127
|
self._presigned = None
|
|
100
128
|
if presigned is not None:
|
|
@@ -122,17 +150,28 @@ class PowerDNSZone(BasePowerDNSHandler):
|
|
|
122
150
|
self._add_keys = {}
|
|
123
151
|
if kwargs:
|
|
124
152
|
self._add_keys = copy.copy(kwargs)
|
|
125
|
-
msg = _(
|
|
153
|
+
msg = _("Got unknown init parameters:") + "\n" + pp(self._add_keys)
|
|
126
154
|
if self.warn_on_unknown_property:
|
|
127
155
|
LOG.warn(msg)
|
|
128
156
|
else:
|
|
129
157
|
LOG.debug(msg)
|
|
130
158
|
|
|
131
159
|
super(PowerDNSZone, self).__init__(
|
|
132
|
-
appname=appname,
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
160
|
+
appname=appname,
|
|
161
|
+
verbose=verbose,
|
|
162
|
+
version=version,
|
|
163
|
+
base_dir=base_dir,
|
|
164
|
+
master_server=master_server,
|
|
165
|
+
port=port,
|
|
166
|
+
key=key,
|
|
167
|
+
use_https=use_https,
|
|
168
|
+
timeout=timeout,
|
|
169
|
+
path_prefix=path_prefix,
|
|
170
|
+
simulate=simulate,
|
|
171
|
+
force=force,
|
|
172
|
+
terminal_has_colors=terminal_has_colors,
|
|
173
|
+
initialized=False,
|
|
174
|
+
)
|
|
136
175
|
|
|
137
176
|
self.name = name
|
|
138
177
|
|
|
@@ -142,19 +181,31 @@ class PowerDNSZone(BasePowerDNSHandler):
|
|
|
142
181
|
# -----------------------------------------------------------
|
|
143
182
|
@classmethod
|
|
144
183
|
def init_from_dict(
|
|
145
|
-
cls,
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
184
|
+
cls,
|
|
185
|
+
data,
|
|
186
|
+
appname=None,
|
|
187
|
+
verbose=0,
|
|
188
|
+
version=__version__,
|
|
189
|
+
base_dir=None,
|
|
190
|
+
master_server=None,
|
|
191
|
+
port=DEFAULT_PORT,
|
|
192
|
+
key=None,
|
|
193
|
+
use_https=False,
|
|
194
|
+
timeout=None,
|
|
195
|
+
path_prefix=DEFAULT_API_PREFIX,
|
|
196
|
+
simulate=None,
|
|
197
|
+
force=None,
|
|
198
|
+
terminal_has_colors=False,
|
|
199
|
+
initialized=None,
|
|
200
|
+
):
|
|
150
201
|
"""Create a new PowerDNSZone object based on a given dict."""
|
|
151
202
|
if not isinstance(data, dict):
|
|
152
|
-
raise PowerDNSZoneError(_(
|
|
203
|
+
raise PowerDNSZoneError(_("Given data {!r} is not a dict object.").format(data))
|
|
153
204
|
|
|
154
205
|
# { 'account': 'local',
|
|
155
206
|
# 'api_rectify': False,
|
|
156
207
|
# 'dnssec': False,
|
|
157
|
-
# '
|
|
208
|
+
# 'zone_id': 'bla.ai.',
|
|
158
209
|
# 'kind': 'Master',
|
|
159
210
|
# 'last_check': 0,
|
|
160
211
|
# 'masters': [],
|
|
@@ -175,28 +226,28 @@ class PowerDNSZone(BasePowerDNSHandler):
|
|
|
175
226
|
# 'url': 'api/v1/servers/localhost/zones/bla.ai.'},
|
|
176
227
|
|
|
177
228
|
params = {
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
229
|
+
"appname": appname,
|
|
230
|
+
"verbose": verbose,
|
|
231
|
+
"version": version,
|
|
232
|
+
"base_dir": base_dir,
|
|
233
|
+
"master_server": master_server,
|
|
234
|
+
"port": port,
|
|
235
|
+
"key": key,
|
|
236
|
+
"use_https": use_https,
|
|
237
|
+
"timeout": timeout,
|
|
238
|
+
"path_prefix": path_prefix,
|
|
239
|
+
"simulate": simulate,
|
|
240
|
+
"force": force,
|
|
241
|
+
"terminal_has_colors": terminal_has_colors,
|
|
191
242
|
}
|
|
192
243
|
if initialized is not None:
|
|
193
|
-
params[
|
|
244
|
+
params["initialized"] = initialized
|
|
194
245
|
|
|
195
246
|
rrsets = None
|
|
196
|
-
if
|
|
197
|
-
if data[
|
|
198
|
-
rrsets = data[
|
|
199
|
-
del data[
|
|
247
|
+
if "rrsets" in data:
|
|
248
|
+
if data["rrsets"]:
|
|
249
|
+
rrsets = data["rrsets"]
|
|
250
|
+
del data["rrsets"]
|
|
200
251
|
|
|
201
252
|
new_data = {}
|
|
202
253
|
for key in data:
|
|
@@ -211,20 +262,31 @@ class PowerDNSZone(BasePowerDNSHandler):
|
|
|
211
262
|
|
|
212
263
|
if verbose > 3:
|
|
213
264
|
pout = copy.copy(params)
|
|
214
|
-
pout[
|
|
265
|
+
pout["key"] = None
|
|
215
266
|
if key:
|
|
216
|
-
pout[
|
|
217
|
-
LOG.debug(_(
|
|
267
|
+
pout["key"] = "******"
|
|
268
|
+
LOG.debug(_("Params initialisation:") + "\n" + pp(pout))
|
|
218
269
|
|
|
219
270
|
zone = cls(**params)
|
|
220
271
|
|
|
221
272
|
if rrsets:
|
|
222
273
|
for single_rrset in rrsets:
|
|
223
274
|
rrset = PowerDNSRecordSet.init_from_dict(
|
|
224
|
-
single_rrset,
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
275
|
+
single_rrset,
|
|
276
|
+
appname=appname,
|
|
277
|
+
verbose=verbose,
|
|
278
|
+
base_dir=base_dir,
|
|
279
|
+
master_server=master_server,
|
|
280
|
+
port=port,
|
|
281
|
+
key=key,
|
|
282
|
+
use_https=use_https,
|
|
283
|
+
timeout=timeout,
|
|
284
|
+
path_prefix=path_prefix,
|
|
285
|
+
simulate=simulate,
|
|
286
|
+
force=force,
|
|
287
|
+
terminal_has_colors=terminal_has_colors,
|
|
288
|
+
initialized=True,
|
|
289
|
+
)
|
|
228
290
|
zone.rrsets.append(rrset)
|
|
229
291
|
|
|
230
292
|
zone.initialized = True
|
|
@@ -235,11 +297,11 @@ class PowerDNSZone(BasePowerDNSHandler):
|
|
|
235
297
|
@property
|
|
236
298
|
def account(self):
|
|
237
299
|
"""
|
|
238
|
-
|
|
300
|
+
Give the name of the owning account of the zone.
|
|
239
301
|
|
|
240
302
|
Using `internal` to differ local visible zones from all other zones.
|
|
241
303
|
"""
|
|
242
|
-
return getattr(self,
|
|
304
|
+
return getattr(self, "_account", None)
|
|
243
305
|
|
|
244
306
|
@account.setter
|
|
245
307
|
def account(self, value):
|
|
@@ -256,7 +318,7 @@ class PowerDNSZone(BasePowerDNSHandler):
|
|
|
256
318
|
@property
|
|
257
319
|
def dnssec(self):
|
|
258
320
|
"""Is the zone under control of DNSSEC."""
|
|
259
|
-
return getattr(self,
|
|
321
|
+
return getattr(self, "_dnssec", False)
|
|
260
322
|
|
|
261
323
|
@dnssec.setter
|
|
262
324
|
def dnssec(self, value):
|
|
@@ -264,26 +326,26 @@ class PowerDNSZone(BasePowerDNSHandler):
|
|
|
264
326
|
|
|
265
327
|
# -----------------------------------------------------------
|
|
266
328
|
@property
|
|
267
|
-
def
|
|
268
|
-
"""
|
|
269
|
-
return getattr(self,
|
|
329
|
+
def zone_id(self): # noqa: A003
|
|
330
|
+
"""Give the unique idendity of the zone."""
|
|
331
|
+
return getattr(self, "_zone_id", None)
|
|
270
332
|
|
|
271
|
-
@
|
|
272
|
-
def
|
|
333
|
+
@zone_id.setter
|
|
334
|
+
def zone_id(self, value): # noqa: A003
|
|
273
335
|
if value:
|
|
274
336
|
v = to_str(str(value).strip())
|
|
275
337
|
if v:
|
|
276
|
-
self.
|
|
338
|
+
self._zone_id = v
|
|
277
339
|
else:
|
|
278
|
-
self.
|
|
340
|
+
self._zone_id = None
|
|
279
341
|
else:
|
|
280
|
-
self.
|
|
342
|
+
self._zone_id = None
|
|
281
343
|
|
|
282
344
|
# -----------------------------------------------------------
|
|
283
345
|
@property
|
|
284
346
|
def kind(self):
|
|
285
|
-
"""
|
|
286
|
-
return getattr(self,
|
|
347
|
+
"""Give the kind or type of the zone."""
|
|
348
|
+
return getattr(self, "_kind", None)
|
|
287
349
|
|
|
288
350
|
@kind.setter
|
|
289
351
|
def kind(self, value):
|
|
@@ -299,14 +361,14 @@ class PowerDNSZone(BasePowerDNSHandler):
|
|
|
299
361
|
# -----------------------------------------------------------
|
|
300
362
|
@property
|
|
301
363
|
def last_check(self):
|
|
302
|
-
"""
|
|
303
|
-
return getattr(self,
|
|
364
|
+
"""Give the timestamp of the last check of the zone."""
|
|
365
|
+
return getattr(self, "_last_check", None)
|
|
304
366
|
|
|
305
367
|
# -----------------------------------------------------------
|
|
306
368
|
@property
|
|
307
369
|
def name(self):
|
|
308
|
-
"""
|
|
309
|
-
return getattr(self,
|
|
370
|
+
"""Give the name of the zone."""
|
|
371
|
+
return getattr(self, "_name", None)
|
|
310
372
|
|
|
311
373
|
@name.setter
|
|
312
374
|
def name(self, value):
|
|
@@ -344,95 +406,95 @@ class PowerDNSZone(BasePowerDNSHandler):
|
|
|
344
406
|
# -----------------------------------------------------------
|
|
345
407
|
@property
|
|
346
408
|
def reverse_net(self):
|
|
347
|
-
"""
|
|
409
|
+
"""Give an IP network object for the network, for which this is the reverse zone."""
|
|
348
410
|
return self._reverse_net
|
|
349
411
|
|
|
350
412
|
# -----------------------------------------------------------
|
|
351
413
|
@property
|
|
352
414
|
def name_unicode(self):
|
|
353
|
-
"""
|
|
354
|
-
n = getattr(self,
|
|
415
|
+
"""Give name of the zone in unicode, if it is an IDNA encoded zone."""
|
|
416
|
+
n = getattr(self, "_name", None)
|
|
355
417
|
if n is None:
|
|
356
418
|
return None
|
|
357
|
-
if
|
|
358
|
-
return to_utf8(n).decode(
|
|
419
|
+
if "xn--" in n:
|
|
420
|
+
return to_utf8(n).decode("idna")
|
|
359
421
|
return n
|
|
360
422
|
|
|
361
423
|
# -----------------------------------------------------------
|
|
362
424
|
@property
|
|
363
425
|
def notified_serial(self):
|
|
364
|
-
"""
|
|
365
|
-
return getattr(self,
|
|
426
|
+
"""Give the notified serial number of the zone."""
|
|
427
|
+
return getattr(self, "_notified_serial", None)
|
|
366
428
|
|
|
367
429
|
# -----------------------------------------------------------
|
|
368
430
|
@property
|
|
369
431
|
def serial(self):
|
|
370
|
-
"""
|
|
371
|
-
return getattr(self,
|
|
432
|
+
"""Give the serial number of the zone."""
|
|
433
|
+
return getattr(self, "_serial", None)
|
|
372
434
|
|
|
373
435
|
# -----------------------------------------------------------
|
|
374
436
|
@property
|
|
375
437
|
def edited_serial(self):
|
|
376
438
|
"""
|
|
377
|
-
|
|
439
|
+
Give the SOA serial as seen in query responses.
|
|
378
440
|
|
|
379
441
|
Calculated using the SOA-EDIT metadata, default-soa-edit and
|
|
380
442
|
default-soa-edit-signed settings.
|
|
381
443
|
"""
|
|
382
|
-
return getattr(self,
|
|
444
|
+
return getattr(self, "_edited_serial", None)
|
|
383
445
|
|
|
384
446
|
# -----------------------------------------------------------
|
|
385
447
|
@property
|
|
386
448
|
def url(self):
|
|
387
|
-
"""
|
|
388
|
-
return getattr(self,
|
|
449
|
+
"""Give the URL in the API to get the zone object."""
|
|
450
|
+
return getattr(self, "_url", None)
|
|
389
451
|
|
|
390
452
|
# -----------------------------------------------------------
|
|
391
453
|
@property
|
|
392
454
|
def soa_edit(self):
|
|
393
|
-
"""
|
|
394
|
-
return getattr(self,
|
|
455
|
+
"""Give the SOA edit property of the zone object."""
|
|
456
|
+
return getattr(self, "_soa_edit", None)
|
|
395
457
|
|
|
396
458
|
# -----------------------------------------------------------
|
|
397
459
|
@property
|
|
398
460
|
def soa_edit_api(self):
|
|
399
|
-
"""
|
|
400
|
-
return getattr(self,
|
|
461
|
+
"""Give the SOA edit property (API) of the zone object."""
|
|
462
|
+
return getattr(self, "_soa_edit_api", None)
|
|
401
463
|
|
|
402
464
|
# -----------------------------------------------------------
|
|
403
465
|
@property
|
|
404
466
|
def nsec3narrow(self):
|
|
405
|
-
"""
|
|
406
|
-
return getattr(self,
|
|
467
|
+
"""Give some stuff belonging to DNSSEC."""
|
|
468
|
+
return getattr(self, "_nsec3narrow", None)
|
|
407
469
|
|
|
408
470
|
# -----------------------------------------------------------
|
|
409
471
|
@property
|
|
410
472
|
def nsec3param(self):
|
|
411
|
-
"""
|
|
412
|
-
return getattr(self,
|
|
473
|
+
"""Give some stuff belonging to DNSSEC."""
|
|
474
|
+
return getattr(self, "_nsec3param", None)
|
|
413
475
|
|
|
414
476
|
# -----------------------------------------------------------
|
|
415
477
|
@property
|
|
416
478
|
def presigned(self):
|
|
417
|
-
"""
|
|
418
|
-
return getattr(self,
|
|
479
|
+
"""Give some stuff belonging to PowerDNS >= 4.1."""
|
|
480
|
+
return getattr(self, "_presigned", None)
|
|
419
481
|
|
|
420
482
|
# -----------------------------------------------------------
|
|
421
483
|
@property
|
|
422
484
|
def api_rectify(self):
|
|
423
|
-
"""
|
|
424
|
-
return getattr(self,
|
|
485
|
+
"""Give some stuff belonging to PowerDNS >= 4.1."""
|
|
486
|
+
return getattr(self, "_api_rectify", None)
|
|
425
487
|
|
|
426
488
|
# -----------------------------------------------------------
|
|
427
489
|
@property
|
|
428
490
|
def add_keys(self):
|
|
429
|
-
"""
|
|
491
|
+
"""Give additional, unexpected keys on initialisation."""
|
|
430
492
|
return copy.copy(self._add_keys)
|
|
431
493
|
|
|
432
494
|
# -----------------------------------------------------------
|
|
433
495
|
@property
|
|
434
496
|
def master_tsig_key_ids(self):
|
|
435
|
-
"""
|
|
497
|
+
"""Give the id of the TSIG keys used for master operation in this zone."""
|
|
436
498
|
return copy.copy(self._master_tsig_key_ids)
|
|
437
499
|
|
|
438
500
|
@master_tsig_key_ids.setter
|
|
@@ -448,7 +510,7 @@ class PowerDNSZone(BasePowerDNSHandler):
|
|
|
448
510
|
# -----------------------------------------------------------
|
|
449
511
|
@property
|
|
450
512
|
def slave_tsig_key_ids(self):
|
|
451
|
-
"""
|
|
513
|
+
"""Return the id of the TSIG keys used for slave operation in this zone."""
|
|
452
514
|
return copy.copy(self._slave_tsig_key_ids)
|
|
453
515
|
|
|
454
516
|
@slave_tsig_key_ids.setter
|
|
@@ -474,36 +536,36 @@ class PowerDNSZone(BasePowerDNSHandler):
|
|
|
474
536
|
"""
|
|
475
537
|
res = super(PowerDNSZone, self).as_dict(short=short)
|
|
476
538
|
|
|
477
|
-
res[
|
|
478
|
-
res[
|
|
479
|
-
res[
|
|
480
|
-
res[
|
|
481
|
-
res[
|
|
482
|
-
res[
|
|
483
|
-
res[
|
|
484
|
-
res[
|
|
485
|
-
res[
|
|
486
|
-
res[
|
|
487
|
-
res[
|
|
488
|
-
res[
|
|
489
|
-
res[
|
|
490
|
-
res[
|
|
491
|
-
res[
|
|
492
|
-
res[
|
|
493
|
-
res[
|
|
494
|
-
res[
|
|
495
|
-
res[
|
|
496
|
-
res[
|
|
497
|
-
res[
|
|
498
|
-
res[
|
|
499
|
-
res[
|
|
500
|
-
res[
|
|
539
|
+
res["account"] = self.account
|
|
540
|
+
res["dnssec"] = copy.copy(self.dnssec)
|
|
541
|
+
res["zone_id"] = self.zone_id
|
|
542
|
+
res["kind"] = self.kind
|
|
543
|
+
res["last_check"] = self.last_check
|
|
544
|
+
res["masters"] = copy.copy(self.masters)
|
|
545
|
+
res["name"] = self.name
|
|
546
|
+
res["name_unicode"] = self.name_unicode
|
|
547
|
+
res["notified_serial"] = self.notified_serial
|
|
548
|
+
res["edited_serial"] = self.edited_serial
|
|
549
|
+
res["serial"] = self.serial
|
|
550
|
+
res["url"] = self.url
|
|
551
|
+
res["rrsets"] = []
|
|
552
|
+
res["soa_edit"] = self.soa_edit
|
|
553
|
+
res["soa_edit_api"] = self.soa_edit_api
|
|
554
|
+
res["nsec3narrow"] = self.nsec3narrow
|
|
555
|
+
res["nsec3param"] = self.nsec3param
|
|
556
|
+
res["presigned"] = self.presigned
|
|
557
|
+
res["api_rectify"] = self.api_rectify
|
|
558
|
+
res["reverse_zone"] = self.reverse_zone
|
|
559
|
+
res["reverse_net"] = self.reverse_net
|
|
560
|
+
res["add_keys"] = self.add_keys
|
|
561
|
+
res["master_tsig_key_ids"] = self.master_tsig_key_ids
|
|
562
|
+
res["slave_tsig_key_ids"] = self.slave_tsig_key_ids
|
|
501
563
|
|
|
502
564
|
for rrset in self.rrsets:
|
|
503
565
|
if isinstance(rrset, FbBaseObject):
|
|
504
|
-
res[
|
|
566
|
+
res["rrsets"].append(rrset.as_dict(short))
|
|
505
567
|
else:
|
|
506
|
-
res[
|
|
568
|
+
res["rrsets"].append(rrset)
|
|
507
569
|
|
|
508
570
|
return res
|
|
509
571
|
|
|
@@ -527,22 +589,22 @@ class PowerDNSZone(BasePowerDNSHandler):
|
|
|
527
589
|
tokens.append(part)
|
|
528
590
|
|
|
529
591
|
if len(tokens) == 3:
|
|
530
|
-
tokens.append(
|
|
592
|
+
tokens.append("0")
|
|
531
593
|
bitmask = 24
|
|
532
594
|
elif len(tokens) == 2:
|
|
533
|
-
tokens.append(
|
|
534
|
-
tokens.append(
|
|
595
|
+
tokens.append("0")
|
|
596
|
+
tokens.append("0")
|
|
535
597
|
bitmask = 16
|
|
536
598
|
elif len(tokens) == 1:
|
|
537
|
-
tokens.append(
|
|
538
|
-
tokens.append(
|
|
539
|
-
tokens.append(
|
|
599
|
+
tokens.append("0")
|
|
600
|
+
tokens.append("0")
|
|
601
|
+
tokens.append("0")
|
|
540
602
|
bitmask = 8
|
|
541
603
|
else:
|
|
542
|
-
msg = _(
|
|
604
|
+
msg = _("Invalid source tuples for detecting IPv4-network: {!r}.").format(tuples)
|
|
543
605
|
raise ValueError(msg)
|
|
544
606
|
|
|
545
|
-
ip_str = to_unicode(
|
|
607
|
+
ip_str = to_unicode(".".join(tokens) + "/{}".format(bitmask))
|
|
546
608
|
net = ipaddress.ip_network(ip_str)
|
|
547
609
|
|
|
548
610
|
return net
|
|
@@ -554,7 +616,7 @@ class PowerDNSZone(BasePowerDNSHandler):
|
|
|
554
616
|
parts = RE_DOT.split(tuples)
|
|
555
617
|
bitmask = 0
|
|
556
618
|
tokens = []
|
|
557
|
-
token =
|
|
619
|
+
token = ""
|
|
558
620
|
i = 0
|
|
559
621
|
|
|
560
622
|
for part in reversed(parts):
|
|
@@ -563,19 +625,19 @@ class PowerDNSZone(BasePowerDNSHandler):
|
|
|
563
625
|
token += part
|
|
564
626
|
if i >= 4:
|
|
565
627
|
tokens.append(token)
|
|
566
|
-
token =
|
|
628
|
+
token = ""
|
|
567
629
|
i = 0
|
|
568
630
|
|
|
569
|
-
if token !=
|
|
570
|
-
tokens.append(token.ljust(4,
|
|
631
|
+
if token != "":
|
|
632
|
+
tokens.append(token.ljust(4, "0"))
|
|
571
633
|
|
|
572
|
-
ip_str =
|
|
634
|
+
ip_str = ":".join(tokens)
|
|
573
635
|
if len(tokens) < 8:
|
|
574
|
-
ip_str +=
|
|
636
|
+
ip_str += ":"
|
|
575
637
|
if len(tokens) < 7:
|
|
576
|
-
ip_str +=
|
|
638
|
+
ip_str += ":"
|
|
577
639
|
|
|
578
|
-
ip_str += to_unicode(
|
|
640
|
+
ip_str += to_unicode("/{}".format(bitmask))
|
|
579
641
|
net = ipaddress.ip_network(ip_str)
|
|
580
642
|
|
|
581
643
|
return net
|
|
@@ -583,42 +645,62 @@ class PowerDNSZone(BasePowerDNSHandler):
|
|
|
583
645
|
# -------------------------------------------------------------------------
|
|
584
646
|
def __repr__(self):
|
|
585
647
|
"""Typecast into a string for reproduction."""
|
|
586
|
-
out =
|
|
648
|
+
out = "<%s(" % (self.__class__.__name__)
|
|
587
649
|
|
|
588
650
|
fields = []
|
|
589
|
-
fields.append(
|
|
590
|
-
fields.append(
|
|
591
|
-
fields.append(
|
|
592
|
-
fields.append(
|
|
593
|
-
fields.append(
|
|
594
|
-
fields.append(
|
|
595
|
-
fields.append(
|
|
596
|
-
fields.append(
|
|
597
|
-
fields.append(
|
|
598
|
-
fields.append(
|
|
599
|
-
fields.append(
|
|
600
|
-
|
|
601
|
-
out +=
|
|
651
|
+
fields.append("name={!r}".format(self.name))
|
|
652
|
+
fields.append("url={!r}".format(self.url))
|
|
653
|
+
fields.append("reverse_zone={!r}".format(self.reverse_zone))
|
|
654
|
+
fields.append("reverse_net={!r}".format(self.reverse_net))
|
|
655
|
+
fields.append("kind={!r}".format(self.kind))
|
|
656
|
+
fields.append("serial={!r}".format(self.serial))
|
|
657
|
+
fields.append("dnssec={!r}".format(self.dnssec))
|
|
658
|
+
fields.append("account={!r}".format(self.account))
|
|
659
|
+
fields.append("appname={!r}".format(self.appname))
|
|
660
|
+
fields.append("verbose={!r}".format(self.verbose))
|
|
661
|
+
fields.append("version={!r}".format(self.version))
|
|
662
|
+
|
|
663
|
+
out += ", ".join(fields) + ")>"
|
|
602
664
|
return out
|
|
603
665
|
|
|
604
666
|
# -------------------------------------------------------------------------
|
|
605
667
|
def __copy__(self):
|
|
606
668
|
"""Return a new PowerDNSZone as a deep copy of the current object."""
|
|
607
669
|
if self.verbose > 3:
|
|
608
|
-
LOG.debug(
|
|
609
|
-
self.__class__.__name__)
|
|
670
|
+
LOG.debug(
|
|
671
|
+
_("Copying current {}-object into a new one.").format(self.__class__.__name__)
|
|
672
|
+
)
|
|
610
673
|
|
|
611
674
|
zone = self.__class__(
|
|
612
|
-
appname=self.appname,
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
675
|
+
appname=self.appname,
|
|
676
|
+
verbose=self.verbose,
|
|
677
|
+
base_dir=self.base_dir,
|
|
678
|
+
account=self.account,
|
|
679
|
+
dnssec=self.dnssec,
|
|
680
|
+
edited_serial=self.edited_serial,
|
|
681
|
+
zone_id=self.zone_id,
|
|
682
|
+
kind=self.kind,
|
|
683
|
+
last_check=self.last_check,
|
|
684
|
+
masters=self.masters,
|
|
685
|
+
name=self.name,
|
|
686
|
+
notified_serial=self.notified_serial,
|
|
687
|
+
serial=self.serial,
|
|
688
|
+
url=self.url,
|
|
689
|
+
presigned=self.presigned,
|
|
690
|
+
api_rectify=self.api_rectify,
|
|
617
691
|
master_tsig_key_ids=self.master_tsig_key_ids,
|
|
618
692
|
slave_tsig_key_ids=self.slave_tsig_key_ids,
|
|
619
|
-
master_server=self.master_server,
|
|
620
|
-
|
|
621
|
-
|
|
693
|
+
master_server=self.master_server,
|
|
694
|
+
port=self.port,
|
|
695
|
+
key=self.key,
|
|
696
|
+
use_https=self.use_https,
|
|
697
|
+
timeout=self.timeout,
|
|
698
|
+
path_prefix=self.path_prefix,
|
|
699
|
+
simulate=self.simulate,
|
|
700
|
+
force=self.force,
|
|
701
|
+
initialized=False,
|
|
702
|
+
**self._add_keys,
|
|
703
|
+
)
|
|
622
704
|
|
|
623
705
|
zone.rrsets = copy.copy(self.rrsets)
|
|
624
706
|
|
|
@@ -629,113 +711,131 @@ class PowerDNSZone(BasePowerDNSHandler):
|
|
|
629
711
|
def update(self):
|
|
630
712
|
"""Update the records in the zone by requesting the API."""
|
|
631
713
|
if not self.url:
|
|
632
|
-
msg = _(
|
|
714
|
+
msg = _("Cannot update zone {!r}, no API URL defined.").format(self.name)
|
|
633
715
|
raise PowerDNSZoneError(msg)
|
|
634
716
|
|
|
635
|
-
LOG.debug(
|
|
636
|
-
n
|
|
717
|
+
LOG.debug(
|
|
718
|
+
_("Updating data of zone {n!r} from API path {u!r} ...").format(
|
|
719
|
+
n=self.name, u=self.url
|
|
720
|
+
)
|
|
721
|
+
)
|
|
637
722
|
json_response = self.perform_request(self.url)
|
|
638
723
|
|
|
639
|
-
if
|
|
640
|
-
self.account = json_response[
|
|
724
|
+
if "account" in json_response:
|
|
725
|
+
self.account = json_response["account"]
|
|
641
726
|
else:
|
|
642
727
|
self.account = None
|
|
643
728
|
|
|
644
|
-
if
|
|
645
|
-
self.dnssec = json_response[
|
|
729
|
+
if "dnssec" in json_response:
|
|
730
|
+
self.dnssec = json_response["dnssec"]
|
|
646
731
|
else:
|
|
647
732
|
self.dnssec = False
|
|
648
733
|
|
|
649
|
-
if
|
|
650
|
-
self.
|
|
734
|
+
if "id" in json_response:
|
|
735
|
+
self.zone_id = json_response["id"]
|
|
651
736
|
else:
|
|
652
|
-
self.
|
|
737
|
+
self.zone_id = None
|
|
653
738
|
|
|
654
|
-
if
|
|
655
|
-
self.kind = json_response[
|
|
739
|
+
if "kind" in json_response:
|
|
740
|
+
self.kind = json_response["kind"]
|
|
656
741
|
else:
|
|
657
742
|
self.kind = None
|
|
658
743
|
|
|
659
|
-
if
|
|
660
|
-
self._last_check = json_response[
|
|
744
|
+
if "last_check" in json_response:
|
|
745
|
+
self._last_check = json_response["last_check"]
|
|
661
746
|
else:
|
|
662
747
|
self._last_check = None
|
|
663
748
|
|
|
664
|
-
if
|
|
665
|
-
self._notified_serial = json_response[
|
|
749
|
+
if "notified_serial" in json_response:
|
|
750
|
+
self._notified_serial = json_response["notified_serial"]
|
|
666
751
|
else:
|
|
667
752
|
self._notified_serial = None
|
|
668
753
|
|
|
669
|
-
if
|
|
670
|
-
self._serial = json_response[
|
|
754
|
+
if "serial" in json_response:
|
|
755
|
+
self._serial = json_response["serial"]
|
|
671
756
|
else:
|
|
672
757
|
self._serial = None
|
|
673
758
|
|
|
674
|
-
if
|
|
675
|
-
self._edited_serial = json_response[
|
|
759
|
+
if "edited_serial" in json_response:
|
|
760
|
+
self._edited_serial = json_response["edited_serial"]
|
|
676
761
|
else:
|
|
677
762
|
self._edited_serial = None
|
|
678
763
|
|
|
679
|
-
if
|
|
680
|
-
self._nsec3narrow = json_response[
|
|
764
|
+
if "nsec3narrow" in json_response:
|
|
765
|
+
self._nsec3narrow = json_response["nsec3narrow"]
|
|
681
766
|
else:
|
|
682
767
|
self._nsec3narrow = None
|
|
683
768
|
|
|
684
|
-
if
|
|
685
|
-
self._nsec3param = json_response[
|
|
769
|
+
if "nsec3param" in json_response:
|
|
770
|
+
self._nsec3param = json_response["nsec3param"]
|
|
686
771
|
else:
|
|
687
772
|
self._nsec3param = None
|
|
688
773
|
|
|
689
|
-
if
|
|
690
|
-
self._soa_edit = json_response[
|
|
774
|
+
if "soa_edit" in json_response:
|
|
775
|
+
self._soa_edit = json_response["soa_edit"]
|
|
691
776
|
else:
|
|
692
777
|
self._soa_edit = None
|
|
693
778
|
|
|
694
|
-
if
|
|
695
|
-
self._soa_edit_api = json_response[
|
|
779
|
+
if "soa_edit_api" in json_response:
|
|
780
|
+
self._soa_edit_api = json_response["soa_edit_api"]
|
|
696
781
|
else:
|
|
697
782
|
self._soa_edit_api = None
|
|
698
783
|
|
|
699
784
|
self.masters = []
|
|
700
|
-
if
|
|
701
|
-
self.masters = copy.copy(json_response[
|
|
785
|
+
if "masters" in json_response:
|
|
786
|
+
self.masters = copy.copy(json_response["masters"])
|
|
702
787
|
|
|
703
788
|
self._master_tsig_key_ids = []
|
|
704
|
-
if
|
|
705
|
-
self.master_tsig_key_ids = copy.copy(json_response[
|
|
789
|
+
if "master_tsig_key_ids" in json_response:
|
|
790
|
+
self.master_tsig_key_ids = copy.copy(json_response["master_tsig_key_ids"])
|
|
706
791
|
|
|
707
792
|
self._slave_tsig_key_ids = []
|
|
708
|
-
if
|
|
709
|
-
self.slave_tsig_key_ids = copy.copy(json_response[
|
|
793
|
+
if "slave_tsig_key_ids" in json_response:
|
|
794
|
+
self.slave_tsig_key_ids = copy.copy(json_response["slave_tsig_key_ids"])
|
|
710
795
|
|
|
711
796
|
self.rrsets = PowerDNSRecordSetList()
|
|
712
|
-
if
|
|
713
|
-
for single_rrset in json_response[
|
|
797
|
+
if "rrsets" in json_response:
|
|
798
|
+
for single_rrset in json_response["rrsets"]:
|
|
714
799
|
rrset = PowerDNSRecordSet.init_from_dict(
|
|
715
|
-
single_rrset,
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
800
|
+
single_rrset,
|
|
801
|
+
appname=self.appname,
|
|
802
|
+
verbose=self.verbose,
|
|
803
|
+
base_dir=self.base_dir,
|
|
804
|
+
master_server=self.master_server,
|
|
805
|
+
port=self.port,
|
|
806
|
+
key=self.key,
|
|
807
|
+
use_https=self.use_https,
|
|
808
|
+
timeout=self.timeout,
|
|
809
|
+
path_prefix=self.path_prefix,
|
|
810
|
+
simulate=self.simulate,
|
|
811
|
+
force=self.force,
|
|
812
|
+
initialized=True,
|
|
813
|
+
)
|
|
720
814
|
self.rrsets.append(rrset)
|
|
721
815
|
|
|
722
816
|
# -------------------------------------------------------------------------
|
|
723
817
|
def perform_request(
|
|
724
|
-
|
|
818
|
+
self, path, no_prefix=True, method="GET", data=None, headers=None, may_simulate=False
|
|
819
|
+
):
|
|
725
820
|
"""Perform the underlying API request."""
|
|
726
821
|
return super(PowerDNSZone, self).perform_request(
|
|
727
|
-
path=path,
|
|
728
|
-
|
|
822
|
+
path=path,
|
|
823
|
+
no_prefix=no_prefix,
|
|
824
|
+
method=method,
|
|
825
|
+
data=data,
|
|
826
|
+
headers=copy.copy(headers),
|
|
827
|
+
may_simulate=may_simulate,
|
|
828
|
+
)
|
|
729
829
|
|
|
730
830
|
# -------------------------------------------------------------------------
|
|
731
831
|
def patch(self, payload):
|
|
732
832
|
"""Perform a PATCH request with given payload to current zone."""
|
|
733
833
|
if self.verbose > 1:
|
|
734
|
-
LOG.debug(_(
|
|
834
|
+
LOG.debug(_("Patching zone {!r} ...").format(self.name))
|
|
735
835
|
|
|
736
836
|
return self.perform_request(
|
|
737
|
-
self.url, method=
|
|
738
|
-
|
|
837
|
+
self.url, method="PATCH", data=json.dumps(payload), may_simulate=True
|
|
838
|
+
)
|
|
739
839
|
|
|
740
840
|
# -------------------------------------------------------------------------
|
|
741
841
|
def get_soa(self):
|
|
@@ -763,12 +863,17 @@ class PowerDNSZone(BasePowerDNSHandler):
|
|
|
763
863
|
if cmt.valid:
|
|
764
864
|
comment_list.append(copy.copy(cmt))
|
|
765
865
|
else:
|
|
766
|
-
LOG.warn(_(
|
|
866
|
+
LOG.warn(_("Found invalid comment {!r}.").format(str(cmt)))
|
|
767
867
|
else:
|
|
768
868
|
cmt = str(cmt).strip()
|
|
769
869
|
comment = PowerDNSRecordSetComment(
|
|
770
|
-
appname=self.appname,
|
|
771
|
-
|
|
870
|
+
appname=self.appname,
|
|
871
|
+
verbose=self.verbose,
|
|
872
|
+
base_dir=self.base_dir,
|
|
873
|
+
account="unknown",
|
|
874
|
+
content=cmt,
|
|
875
|
+
initialized=True,
|
|
876
|
+
)
|
|
772
877
|
comment_list.append(comment)
|
|
773
878
|
|
|
774
879
|
return comment_list
|
|
@@ -777,8 +882,9 @@ class PowerDNSZone(BasePowerDNSHandler):
|
|
|
777
882
|
def update_soa(self, new_soa, comments=None, ttl=None):
|
|
778
883
|
"""Update the SOA of the zone on the PowerDNS server."""
|
|
779
884
|
if not isinstance(new_soa, PowerDnsSOAData):
|
|
780
|
-
msg = _(
|
|
781
|
-
e=
|
|
885
|
+
msg = _("New SOA must be of type {e}, given {t}: {s!r}").format(
|
|
886
|
+
e="PowerDnsSOAData", t=new_soa.__class__.__name__, s=new_soa
|
|
887
|
+
)
|
|
782
888
|
raise TypeError(msg)
|
|
783
889
|
|
|
784
890
|
if ttl:
|
|
@@ -788,7 +894,7 @@ class PowerDNSZone(BasePowerDNSHandler):
|
|
|
788
894
|
self.update()
|
|
789
895
|
cur_soa_rrset = self.get_soa()
|
|
790
896
|
if not cur_soa_rrset:
|
|
791
|
-
raise RuntimeError(_(
|
|
897
|
+
raise RuntimeError(_("Got no SOA for zone {!r}.").format(self.name))
|
|
792
898
|
ttl = cur_soa_rrset.ttl
|
|
793
899
|
|
|
794
900
|
comment_list = []
|
|
@@ -801,16 +907,19 @@ class PowerDNSZone(BasePowerDNSHandler):
|
|
|
801
907
|
comment_list.append(comment)
|
|
802
908
|
|
|
803
909
|
rrset = new_soa.as_dict(minimal=True)
|
|
804
|
-
rrset[
|
|
805
|
-
rrset[
|
|
806
|
-
for record in rrset[
|
|
807
|
-
record[
|
|
910
|
+
rrset["comments"] = comment_list
|
|
911
|
+
rrset["changetype"] = "REPLACE"
|
|
912
|
+
for record in rrset["records"]:
|
|
913
|
+
record["set-ptr"] = False
|
|
808
914
|
|
|
809
|
-
payload = {
|
|
915
|
+
payload = {"rrsets": [rrset]}
|
|
810
916
|
|
|
811
917
|
if self.verbose > 1:
|
|
812
|
-
LOG.debug(
|
|
813
|
-
s
|
|
918
|
+
LOG.debug(
|
|
919
|
+
_("Setting new SOA {s!r} for zone {z!r}, TTL {t} ...").format(
|
|
920
|
+
s=new_soa.data, z=self.name, t=ttl
|
|
921
|
+
)
|
|
922
|
+
)
|
|
814
923
|
|
|
815
924
|
self.patch(payload)
|
|
816
925
|
|
|
@@ -825,12 +934,20 @@ class PowerDNSZone(BasePowerDNSHandler):
|
|
|
825
934
|
old_serial = soa.serial
|
|
826
935
|
new_serial = soa.increase_serial()
|
|
827
936
|
|
|
828
|
-
LOG.debug(
|
|
829
|
-
z
|
|
937
|
+
LOG.debug(
|
|
938
|
+
_("Increasing serial of zone {z!r} from {o} => {n}.").format(
|
|
939
|
+
z=self.name, o=old_serial, n=new_serial
|
|
940
|
+
)
|
|
941
|
+
)
|
|
830
942
|
|
|
831
943
|
new_soa_record = PowerDNSRecord(
|
|
832
|
-
appname=self.appname,
|
|
833
|
-
|
|
944
|
+
appname=self.appname,
|
|
945
|
+
verbose=self.verbose,
|
|
946
|
+
base_dir=self.base_dir,
|
|
947
|
+
content=soa.data,
|
|
948
|
+
disabled=False,
|
|
949
|
+
initialized=True,
|
|
950
|
+
)
|
|
834
951
|
|
|
835
952
|
soa_rrset.records.clear()
|
|
836
953
|
soa_rrset.records.append(new_soa_record)
|
|
@@ -842,8 +959,9 @@ class PowerDNSZone(BasePowerDNSHandler):
|
|
|
842
959
|
def generate_new_comment_list(self, rrset, comment=None, account=None, append_comments=True):
|
|
843
960
|
"""Create a list of rrset comments from given PowerDNSRecordSet object and update it."""
|
|
844
961
|
if not isinstance(rrset, PowerDNSRecordSet):
|
|
845
|
-
msg = _(
|
|
846
|
-
w=
|
|
962
|
+
msg = _("Parameter {w!r} {a!r} is not a {e} object, but a {c} object instead.").format(
|
|
963
|
+
w="rrset", a=rrset, e="PowerDNSRecordSet", c=rrset.__class__.__name__
|
|
964
|
+
)
|
|
847
965
|
raise TypeError(msg)
|
|
848
966
|
|
|
849
967
|
comment_list = []
|
|
@@ -854,38 +972,45 @@ class PowerDNSZone(BasePowerDNSHandler):
|
|
|
854
972
|
if comment:
|
|
855
973
|
comment = str(comment).strip()
|
|
856
974
|
if comment:
|
|
857
|
-
used_account =
|
|
975
|
+
used_account = ""
|
|
858
976
|
if account:
|
|
859
977
|
used_account = str(account).strip()
|
|
860
978
|
if not used_account:
|
|
861
|
-
used_account =
|
|
979
|
+
used_account = "unknown"
|
|
862
980
|
cmt = PowerDNSRecordSetComment(
|
|
863
|
-
appname=self.appname,
|
|
864
|
-
|
|
981
|
+
appname=self.appname,
|
|
982
|
+
verbose=self.verbose,
|
|
983
|
+
base_dir=self.base_dir,
|
|
984
|
+
account=used_account,
|
|
985
|
+
content=comment,
|
|
986
|
+
)
|
|
865
987
|
comment_list.append(cmt)
|
|
866
988
|
|
|
867
989
|
return comment_list
|
|
868
990
|
|
|
869
991
|
# -------------------------------------------------------------------------
|
|
870
992
|
def replace_rrset(
|
|
871
|
-
|
|
993
|
+
self, rrset, set_ptr=False, comment=None, account=None, append_comments=True
|
|
994
|
+
):
|
|
872
995
|
"""Replace the recordset on the PDNS server."""
|
|
873
996
|
if not isinstance(rrset, PowerDNSRecordSet):
|
|
874
|
-
msg = _(
|
|
875
|
-
w=
|
|
997
|
+
msg = _("Parameter {w!r} {a!r} is not a {e} object, but a {c} object instead.").format(
|
|
998
|
+
w="rrset", a=rrset, e="PowerDNSRecordSet", c=rrset.__class__.__name__
|
|
999
|
+
)
|
|
876
1000
|
raise TypeError(msg)
|
|
877
1001
|
|
|
878
1002
|
comment_list = self.generate_new_comment_list(
|
|
879
|
-
rrset, comment=comment, account=account, append_comments=append_comments
|
|
1003
|
+
rrset, comment=comment, account=account, append_comments=append_comments
|
|
1004
|
+
)
|
|
880
1005
|
rrset.comments = comment_list
|
|
881
1006
|
|
|
882
1007
|
rrset_dict = rrset.as_dict(minimal=True)
|
|
883
|
-
rrset_dict[
|
|
884
|
-
for record in rrset_dict[
|
|
885
|
-
record[
|
|
1008
|
+
rrset_dict["changetype"] = "REPLACE"
|
|
1009
|
+
for record in rrset_dict["records"]:
|
|
1010
|
+
record["set-ptr"] = bool(set_ptr)
|
|
886
1011
|
|
|
887
|
-
payload = {
|
|
888
|
-
LOG.debug(_(
|
|
1012
|
+
payload = {"rrsets": [rrset_dict]}
|
|
1013
|
+
LOG.debug(_("Replacing record set in zone {!r}.").format(self.name))
|
|
889
1014
|
|
|
890
1015
|
self.patch(payload)
|
|
891
1016
|
|
|
@@ -893,27 +1018,37 @@ class PowerDNSZone(BasePowerDNSHandler):
|
|
|
893
1018
|
def delete_rrset(self, rrset):
|
|
894
1019
|
"""Delete the given recordset on the PDNS server."""
|
|
895
1020
|
if not isinstance(rrset, PowerDNSRecordSet):
|
|
896
|
-
msg = _(
|
|
897
|
-
w=
|
|
1021
|
+
msg = _("Parameter {w!r} {a!r} is not a {e} object, but a {c} object instead.").format(
|
|
1022
|
+
w="rrset", a=rrset, e="PowerDNSRecordSet", c=rrset.__class__.__name__
|
|
1023
|
+
)
|
|
898
1024
|
raise TypeError(msg)
|
|
899
1025
|
|
|
900
1026
|
rrset_dict = {
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
1027
|
+
"name": rrset.name,
|
|
1028
|
+
"type": rrset.type,
|
|
1029
|
+
"changetype": "DELETE",
|
|
1030
|
+
"records": [],
|
|
1031
|
+
"comments": [],
|
|
906
1032
|
}
|
|
907
1033
|
|
|
908
|
-
payload = {
|
|
909
|
-
LOG.debug(_(
|
|
1034
|
+
payload = {"rrsets": [rrset_dict]}
|
|
1035
|
+
LOG.debug(_("Deleting record set in zone {!r}.").format(self.name))
|
|
910
1036
|
|
|
911
1037
|
self.patch(payload)
|
|
912
1038
|
|
|
913
1039
|
# -------------------------------------------------------------------------
|
|
914
1040
|
def add_record_to_recordset(
|
|
915
|
-
self,
|
|
916
|
-
|
|
1041
|
+
self,
|
|
1042
|
+
fqdn,
|
|
1043
|
+
rrset_type,
|
|
1044
|
+
content,
|
|
1045
|
+
ttl=None,
|
|
1046
|
+
disabled=False,
|
|
1047
|
+
set_ptr=False,
|
|
1048
|
+
comment=None,
|
|
1049
|
+
account=None,
|
|
1050
|
+
append_comments=True,
|
|
1051
|
+
):
|
|
917
1052
|
"""Add a record to the given recordset on the PDNS server."""
|
|
918
1053
|
fqdn_used = self.verify_fqdn(fqdn)
|
|
919
1054
|
if not fqdn_used:
|
|
@@ -922,8 +1057,9 @@ class PowerDNSZone(BasePowerDNSHandler):
|
|
|
922
1057
|
if not rtype:
|
|
923
1058
|
return None
|
|
924
1059
|
if self.verbose > 2:
|
|
925
|
-
msg = _(
|
|
926
|
-
f=fqdn_used, t=rtype, c=content
|
|
1060
|
+
msg = _("Adding FQDN: {f!r}, type {t!r}, content: {c!r}.").format(
|
|
1061
|
+
f=fqdn_used, t=rtype, c=content
|
|
1062
|
+
)
|
|
927
1063
|
LOG.debug(msg)
|
|
928
1064
|
|
|
929
1065
|
if ttl:
|
|
@@ -932,19 +1068,24 @@ class PowerDNSZone(BasePowerDNSHandler):
|
|
|
932
1068
|
rrset = self.get_rrset(fqdn, rrset_type)
|
|
933
1069
|
if rrset:
|
|
934
1070
|
if self.verbose > 1:
|
|
935
|
-
msg = _(
|
|
936
|
-
f=fqdn_used, t=rtype
|
|
1071
|
+
msg = _("Got an existing rrset for FQDN {f!r}, type {t!r}.").format(
|
|
1072
|
+
f=fqdn_used, t=rtype
|
|
1073
|
+
)
|
|
937
1074
|
LOG.debug(msg)
|
|
938
1075
|
if ttl:
|
|
939
1076
|
rrset.ttl = ttl
|
|
940
1077
|
else:
|
|
941
1078
|
if self.verbose > 1:
|
|
942
|
-
msg = _(
|
|
943
|
-
f=fqdn_used, t=rtype
|
|
1079
|
+
msg = _("Got no existing rrset for FQDN {f!r}, type {t!r}.").format(
|
|
1080
|
+
f=fqdn_used, t=rtype
|
|
1081
|
+
)
|
|
944
1082
|
LOG.debug(msg)
|
|
945
1083
|
rrset = PowerDNSRecordSet(
|
|
946
|
-
appname=self.appname,
|
|
947
|
-
|
|
1084
|
+
appname=self.appname,
|
|
1085
|
+
verbose=self.verbose,
|
|
1086
|
+
base_dir=self.base_dir,
|
|
1087
|
+
initialized=False,
|
|
1088
|
+
)
|
|
948
1089
|
rrset.name = fqdn_used
|
|
949
1090
|
rrset.type = rrset_type
|
|
950
1091
|
if ttl:
|
|
@@ -954,23 +1095,42 @@ class PowerDNSZone(BasePowerDNSHandler):
|
|
|
954
1095
|
rrset.ttl = soa.ttl
|
|
955
1096
|
|
|
956
1097
|
record = PowerDNSRecord(
|
|
957
|
-
appname=self.appname,
|
|
958
|
-
|
|
1098
|
+
appname=self.appname,
|
|
1099
|
+
verbose=self.verbose,
|
|
1100
|
+
base_dir=self.base_dir,
|
|
1101
|
+
content=content,
|
|
1102
|
+
disabled=bool(disabled),
|
|
1103
|
+
initialized=True,
|
|
1104
|
+
)
|
|
959
1105
|
if record in rrset.records:
|
|
960
|
-
msg = _(
|
|
961
|
-
c=content, f=rrset.name, t=rrset.type
|
|
1106
|
+
msg = _("Record {c!r} already contained in record set {f!r} type {t}.").format(
|
|
1107
|
+
c=content, f=rrset.name, t=rrset.type
|
|
1108
|
+
)
|
|
962
1109
|
LOG.warn(msg)
|
|
963
1110
|
return
|
|
964
1111
|
rrset.records.append(record)
|
|
965
1112
|
|
|
966
1113
|
self.replace_rrset(
|
|
967
|
-
rrset,
|
|
968
|
-
|
|
1114
|
+
rrset,
|
|
1115
|
+
set_ptr=set_ptr,
|
|
1116
|
+
comment=comment,
|
|
1117
|
+
account=account,
|
|
1118
|
+
append_comments=bool(append_comments),
|
|
1119
|
+
)
|
|
969
1120
|
|
|
970
1121
|
# -------------------------------------------------------------------------
|
|
971
1122
|
def replace_record_in_recordset(
|
|
972
|
-
self,
|
|
973
|
-
|
|
1123
|
+
self,
|
|
1124
|
+
fqdn,
|
|
1125
|
+
rrset_type,
|
|
1126
|
+
content,
|
|
1127
|
+
ttl=None,
|
|
1128
|
+
disabled=False,
|
|
1129
|
+
set_ptr=False,
|
|
1130
|
+
comment=None,
|
|
1131
|
+
account=None,
|
|
1132
|
+
append_comments=True,
|
|
1133
|
+
):
|
|
974
1134
|
"""Replace a record in the given recordset on the PDNS server."""
|
|
975
1135
|
fqdn_used = self.verify_fqdn(fqdn)
|
|
976
1136
|
if not fqdn_used:
|
|
@@ -979,8 +1139,9 @@ class PowerDNSZone(BasePowerDNSHandler):
|
|
|
979
1139
|
if not rtype:
|
|
980
1140
|
return None
|
|
981
1141
|
if self.verbose > 2:
|
|
982
|
-
msg = _(
|
|
983
|
-
f=fqdn_used, t=rtype, c=content
|
|
1142
|
+
msg = _("Replacing FQDN: {f!r}, type {t!r} by content: {c!r}.").format(
|
|
1143
|
+
f=fqdn_used, t=rtype, c=content
|
|
1144
|
+
)
|
|
984
1145
|
LOG.debug(msg)
|
|
985
1146
|
|
|
986
1147
|
if ttl:
|
|
@@ -989,20 +1150,25 @@ class PowerDNSZone(BasePowerDNSHandler):
|
|
|
989
1150
|
rrset = self.get_rrset(fqdn, rrset_type)
|
|
990
1151
|
if rrset:
|
|
991
1152
|
if self.verbose > 1:
|
|
992
|
-
msg = _(
|
|
993
|
-
f=fqdn_used, t=rtype
|
|
1153
|
+
msg = _("Got an existing rrset for FQDN {f!r}, type {t!r}.").format(
|
|
1154
|
+
f=fqdn_used, t=rtype
|
|
1155
|
+
)
|
|
994
1156
|
LOG.debug(msg)
|
|
995
1157
|
rrset.records.clear()
|
|
996
1158
|
if ttl:
|
|
997
1159
|
rrset.ttl = ttl
|
|
998
1160
|
else:
|
|
999
1161
|
if self.verbose > 1:
|
|
1000
|
-
msg = _(
|
|
1001
|
-
f=fqdn_used, t=rtype
|
|
1162
|
+
msg = _("Got no existing rrset for FQDN {f!r}, type {t!r}.").format(
|
|
1163
|
+
f=fqdn_used, t=rtype
|
|
1164
|
+
)
|
|
1002
1165
|
LOG.debug(msg)
|
|
1003
1166
|
rrset = PowerDNSRecordSet(
|
|
1004
|
-
appname=self.appname,
|
|
1005
|
-
|
|
1167
|
+
appname=self.appname,
|
|
1168
|
+
verbose=self.verbose,
|
|
1169
|
+
base_dir=self.base_dir,
|
|
1170
|
+
initialized=False,
|
|
1171
|
+
)
|
|
1006
1172
|
rrset.name = fqdn_used
|
|
1007
1173
|
rrset.type = rrset_type
|
|
1008
1174
|
if ttl:
|
|
@@ -1012,79 +1178,144 @@ class PowerDNSZone(BasePowerDNSHandler):
|
|
|
1012
1178
|
rrset.ttl = soa.ttl
|
|
1013
1179
|
|
|
1014
1180
|
record = PowerDNSRecord(
|
|
1015
|
-
appname=self.appname,
|
|
1016
|
-
|
|
1181
|
+
appname=self.appname,
|
|
1182
|
+
verbose=self.verbose,
|
|
1183
|
+
base_dir=self.base_dir,
|
|
1184
|
+
content=content,
|
|
1185
|
+
disabled=bool(disabled),
|
|
1186
|
+
initialized=True,
|
|
1187
|
+
)
|
|
1017
1188
|
|
|
1018
1189
|
rrset.records.append(record)
|
|
1019
1190
|
|
|
1020
1191
|
self.replace_rrset(
|
|
1021
|
-
rrset,
|
|
1022
|
-
|
|
1192
|
+
rrset,
|
|
1193
|
+
set_ptr=set_ptr,
|
|
1194
|
+
comment=comment,
|
|
1195
|
+
account=account,
|
|
1196
|
+
append_comments=bool(append_comments),
|
|
1197
|
+
)
|
|
1023
1198
|
|
|
1024
1199
|
# -------------------------------------------------------------------------
|
|
1025
1200
|
def add_address_record(
|
|
1026
|
-
self,
|
|
1027
|
-
|
|
1201
|
+
self,
|
|
1202
|
+
fqdn,
|
|
1203
|
+
address,
|
|
1204
|
+
ttl=None,
|
|
1205
|
+
disabled=False,
|
|
1206
|
+
set_ptr=True,
|
|
1207
|
+
comment=None,
|
|
1208
|
+
account=None,
|
|
1209
|
+
append_comments=False,
|
|
1210
|
+
):
|
|
1028
1211
|
"""Add a PTR record to the current (revertse) zone on the PDNS server."""
|
|
1029
1212
|
if not isinstance(address, (ipaddress.IPv4Address, ipaddress.IPv6Address)):
|
|
1030
1213
|
msg = _(
|
|
1031
|
-
|
|
1032
|
-
|
|
1214
|
+
"Parameter address {a!r} is not an IPv4Address or IPv6Address object, "
|
|
1215
|
+
"but a {c} object instead."
|
|
1216
|
+
).format(a=address, c=address.__class__.__name__)
|
|
1033
1217
|
raise TypeError(msg)
|
|
1034
1218
|
|
|
1035
|
-
record_type =
|
|
1219
|
+
record_type = "A"
|
|
1036
1220
|
if address.version == 6:
|
|
1037
|
-
record_type =
|
|
1038
|
-
LOG.debug(
|
|
1039
|
-
t
|
|
1221
|
+
record_type = "AAAA"
|
|
1222
|
+
LOG.debug(
|
|
1223
|
+
_("Trying to create {t}-record {f!r} => {a!r}.").format(
|
|
1224
|
+
t=record_type, f=fqdn, a=str(address)
|
|
1225
|
+
)
|
|
1226
|
+
)
|
|
1040
1227
|
|
|
1041
1228
|
canon_fqdn = self.canon_name(fqdn)
|
|
1042
1229
|
|
|
1043
1230
|
self.add_record_to_recordset(
|
|
1044
|
-
fqdn=canon_fqdn,
|
|
1045
|
-
|
|
1046
|
-
|
|
1231
|
+
fqdn=canon_fqdn,
|
|
1232
|
+
rrset_type=record_type,
|
|
1233
|
+
content=str(address),
|
|
1234
|
+
ttl=ttl,
|
|
1235
|
+
disabled=disabled,
|
|
1236
|
+
set_ptr=set_ptr,
|
|
1237
|
+
comment=comment,
|
|
1238
|
+
account=account,
|
|
1239
|
+
append_comments=append_comments,
|
|
1240
|
+
)
|
|
1047
1241
|
|
|
1048
1242
|
return True
|
|
1049
1243
|
|
|
1050
1244
|
# -------------------------------------------------------------------------
|
|
1051
1245
|
def set_address_record(
|
|
1052
|
-
self,
|
|
1053
|
-
|
|
1246
|
+
self,
|
|
1247
|
+
fqdn,
|
|
1248
|
+
address,
|
|
1249
|
+
ttl=None,
|
|
1250
|
+
disabled=False,
|
|
1251
|
+
set_ptr=True,
|
|
1252
|
+
comment=None,
|
|
1253
|
+
account=None,
|
|
1254
|
+
append_comments=False,
|
|
1255
|
+
):
|
|
1054
1256
|
"""Replace a PTR record on the current (revertse) zone on the PDNS server."""
|
|
1055
1257
|
if not isinstance(address, (ipaddress.IPv4Address, ipaddress.IPv6Address)):
|
|
1056
1258
|
msg = _(
|
|
1057
|
-
|
|
1058
|
-
|
|
1259
|
+
"Parameter address {a!r} is not an IPv4Address or IPv6Address object, "
|
|
1260
|
+
"but a {c} object instead."
|
|
1261
|
+
).format(a=address, c=address.__class__.__name__)
|
|
1059
1262
|
raise TypeError(msg)
|
|
1060
1263
|
|
|
1061
|
-
record_type =
|
|
1264
|
+
record_type = "A"
|
|
1062
1265
|
if address.version == 6:
|
|
1063
|
-
record_type =
|
|
1064
|
-
LOG.debug(
|
|
1065
|
-
t
|
|
1266
|
+
record_type = "AAAA"
|
|
1267
|
+
LOG.debug(
|
|
1268
|
+
_("Trying to create {t}-record {f!r} => {a!r}.").format(
|
|
1269
|
+
t=record_type, f=fqdn, a=str(address)
|
|
1270
|
+
)
|
|
1271
|
+
)
|
|
1066
1272
|
|
|
1067
1273
|
canon_fqdn = self.canon_name(fqdn)
|
|
1068
1274
|
|
|
1069
1275
|
self.replace_record_in_recordset(
|
|
1070
|
-
fqdn=canon_fqdn,
|
|
1071
|
-
|
|
1072
|
-
|
|
1276
|
+
fqdn=canon_fqdn,
|
|
1277
|
+
rrset_type=record_type,
|
|
1278
|
+
content=str(address),
|
|
1279
|
+
ttl=ttl,
|
|
1280
|
+
disabled=disabled,
|
|
1281
|
+
set_ptr=set_ptr,
|
|
1282
|
+
comment=comment,
|
|
1283
|
+
account=account,
|
|
1284
|
+
append_comments=append_comments,
|
|
1285
|
+
)
|
|
1073
1286
|
|
|
1074
1287
|
return True
|
|
1075
1288
|
|
|
1076
1289
|
# -------------------------------------------------------------------------
|
|
1077
1290
|
def add_ptr_record(
|
|
1078
|
-
self,
|
|
1079
|
-
|
|
1291
|
+
self,
|
|
1292
|
+
pointer,
|
|
1293
|
+
fqdn,
|
|
1294
|
+
ttl=None,
|
|
1295
|
+
disabled=False,
|
|
1296
|
+
comment=None,
|
|
1297
|
+
account=None,
|
|
1298
|
+
append_comments=False,
|
|
1299
|
+
):
|
|
1080
1300
|
"""Add a PTR record to the current (revertse) zone on the PDNS server."""
|
|
1081
1301
|
canon_fqdn = self.canon_name(fqdn)
|
|
1082
|
-
LOG.debug(
|
|
1083
|
-
t
|
|
1302
|
+
LOG.debug(
|
|
1303
|
+
_("Trying to create {t}-record {f!r} => {a!r}.").format(
|
|
1304
|
+
t="PTR", f=pointer, a=canon_fqdn
|
|
1305
|
+
)
|
|
1306
|
+
)
|
|
1084
1307
|
|
|
1085
1308
|
self.replace_record_in_recordset(
|
|
1086
|
-
fqdn=pointer,
|
|
1087
|
-
|
|
1309
|
+
fqdn=pointer,
|
|
1310
|
+
rrset_type="PTR",
|
|
1311
|
+
content=canon_fqdn,
|
|
1312
|
+
ttl=ttl,
|
|
1313
|
+
disabled=disabled,
|
|
1314
|
+
set_ptr=False,
|
|
1315
|
+
comment=comment,
|
|
1316
|
+
account=account,
|
|
1317
|
+
append_comments=append_comments,
|
|
1318
|
+
)
|
|
1088
1319
|
|
|
1089
1320
|
return True
|
|
1090
1321
|
|
|
@@ -1095,11 +1326,11 @@ class PowerDNSZone(BasePowerDNSHandler):
|
|
|
1095
1326
|
rrsets = []
|
|
1096
1327
|
|
|
1097
1328
|
rrset = {
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1329
|
+
"name": self.canon_name(fqdn),
|
|
1330
|
+
"type": rr_type.upper(),
|
|
1331
|
+
"records": [],
|
|
1332
|
+
"comments": [],
|
|
1333
|
+
"changetype": "DELETE",
|
|
1103
1334
|
}
|
|
1104
1335
|
rrsets.append(rrset)
|
|
1105
1336
|
return rrsets
|
|
@@ -1112,53 +1343,54 @@ class PowerDNSZone(BasePowerDNSHandler):
|
|
|
1112
1343
|
|
|
1113
1344
|
self.update()
|
|
1114
1345
|
if self.verbose > 3:
|
|
1115
|
-
LOG.debug(_(
|
|
1346
|
+
LOG.debug(_("Current zone:") + "\n" + pp(self.as_dict()))
|
|
1116
1347
|
|
|
1117
1348
|
rrsets_rm = []
|
|
1118
1349
|
|
|
1119
1350
|
for rrset in rrsets:
|
|
1120
1351
|
found = False
|
|
1121
1352
|
for item in self.rrsets:
|
|
1122
|
-
if item.name == rrset[
|
|
1353
|
+
if item.name == rrset["name"] and item.type == rrset["type"]:
|
|
1123
1354
|
found = True
|
|
1124
1355
|
break
|
|
1125
1356
|
if not found:
|
|
1126
|
-
msg = _(
|
|
1127
|
-
t=rrset[
|
|
1357
|
+
msg = _("DNS {t!r}-record {n!r} is already deleted.").format(
|
|
1358
|
+
t=rrset["type"], n=rrset["name"]
|
|
1359
|
+
)
|
|
1128
1360
|
LOG.warning(msg)
|
|
1129
1361
|
continue
|
|
1130
1362
|
rrsets_rm.append(rrset)
|
|
1131
1363
|
if not rrsets_rm:
|
|
1132
1364
|
raise PDNSNoRecordsToRemove(self.name_unicode)
|
|
1133
1365
|
|
|
1134
|
-
payload = {
|
|
1366
|
+
payload = {"rrsets": rrsets_rm}
|
|
1135
1367
|
count = len(rrsets_rm)
|
|
1136
1368
|
msg = ngettext(
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1369
|
+
"Removing one resource record set from zone {z!r}.",
|
|
1370
|
+
"Removing {c} resource record sets from zone {z!r}.",
|
|
1371
|
+
count,
|
|
1372
|
+
).format(c=count, z=self.name_unicode)
|
|
1140
1373
|
LOG.info(msg)
|
|
1141
1374
|
if self.verbose > 1:
|
|
1142
|
-
LOG.debug(_(
|
|
1375
|
+
LOG.debug(_("Resorce record sets:") + "\n" + pp(payload))
|
|
1143
1376
|
|
|
1144
1377
|
self.patch(payload)
|
|
1145
|
-
LOG.info(_(
|
|
1378
|
+
LOG.info(_("Done."))
|
|
1146
1379
|
|
|
1147
1380
|
return True
|
|
1148
1381
|
|
|
1149
1382
|
# -------------------------------------------------------------------------
|
|
1150
1383
|
def notify(self):
|
|
1151
1384
|
"""Initiate a notify of all secondary servers of current zone."""
|
|
1152
|
-
LOG.info(_(
|
|
1153
|
-
path = self.url +
|
|
1154
|
-
return self.perform_request(path, method=
|
|
1385
|
+
LOG.info(_("Notifying slave servers of zone {!r} ...").format(self.name))
|
|
1386
|
+
path = self.url + "/notify"
|
|
1387
|
+
return self.perform_request(path, method="PUT", may_simulate=True)
|
|
1155
1388
|
|
|
1156
1389
|
# -------------------------------------------------------------------------
|
|
1157
1390
|
def verify_fqdn(self, fqdn, raise_on_error=True):
|
|
1158
1391
|
"""Verify syntax of the given FQDN, and whether it fits into current zone."""
|
|
1159
1392
|
if not isinstance(fqdn, six.string_types):
|
|
1160
|
-
msg = _(
|
|
1161
|
-
w='FQDN', v=fqdn)
|
|
1393
|
+
msg = _("A {w} must be a string type, but is {v!r} instead.").format(w="FQDN", v=fqdn)
|
|
1162
1394
|
if raise_on_error:
|
|
1163
1395
|
raise TypeError(msg)
|
|
1164
1396
|
LOG.error(msg)
|
|
@@ -1166,25 +1398,23 @@ class PowerDNSZone(BasePowerDNSHandler):
|
|
|
1166
1398
|
|
|
1167
1399
|
fqdn_used = to_str(fqdn).strip().lower()
|
|
1168
1400
|
if not fqdn_used:
|
|
1169
|
-
msg = _(
|
|
1401
|
+
msg = _("Invalid, empty FQDN {!r} given.").format(fqdn)
|
|
1170
1402
|
if raise_on_error:
|
|
1171
1403
|
raise ValueError(msg)
|
|
1172
1404
|
LOG.error(msg)
|
|
1173
1405
|
return None
|
|
1174
1406
|
|
|
1175
|
-
if fqdn_used ==
|
|
1407
|
+
if fqdn_used == "@":
|
|
1176
1408
|
return self.name
|
|
1177
1409
|
|
|
1178
1410
|
if fqdn_used == self.name:
|
|
1179
1411
|
return self.name
|
|
1180
1412
|
|
|
1181
|
-
tail =
|
|
1413
|
+
tail = "." + self.name
|
|
1182
1414
|
if self.verbose > 2:
|
|
1183
|
-
LOG.debug(_(
|
|
1184
|
-
f=fqdn_used, t=tail))
|
|
1415
|
+
LOG.debug(_("Checking FQDN {f!r} for ending on {t!r}.").format(f=fqdn_used, t=tail))
|
|
1185
1416
|
if not fqdn_used.endswith(tail):
|
|
1186
|
-
msg = _(
|
|
1187
|
-
f=fqdn, t=tail)
|
|
1417
|
+
msg = _("Invalid FQDN {f!r}, it must end up with {t!r}.").format(f=fqdn, t=tail)
|
|
1188
1418
|
if raise_on_error:
|
|
1189
1419
|
raise ValueError(msg)
|
|
1190
1420
|
LOG.error(msg)
|
|
@@ -1193,11 +1423,10 @@ class PowerDNSZone(BasePowerDNSHandler):
|
|
|
1193
1423
|
idx = fqdn_used.rfind(tail)
|
|
1194
1424
|
head = fqdn_used[:idx]
|
|
1195
1425
|
if self.verbose > 2:
|
|
1196
|
-
LOG.debug(_(
|
|
1197
|
-
f=fqdn_used, h=head))
|
|
1426
|
+
LOG.debug(_("Basename of FQDN {f!r} is {h!r}.").format(f=fqdn_used, h=head))
|
|
1198
1427
|
|
|
1199
1428
|
if not FQDN_REGEX.match(fqdn_used):
|
|
1200
|
-
msg = _(
|
|
1429
|
+
msg = _("Invalid FQDN {!r}.").format(fqdn)
|
|
1201
1430
|
if raise_on_error:
|
|
1202
1431
|
raise ValueError(msg)
|
|
1203
1432
|
LOG.error(msg)
|
|
@@ -1207,7 +1436,7 @@ class PowerDNSZone(BasePowerDNSHandler):
|
|
|
1207
1436
|
|
|
1208
1437
|
# -------------------------------------------------------------------------
|
|
1209
1438
|
def get_rrset(self, fqdn, rrset_type, raise_on_error=True):
|
|
1210
|
-
"""
|
|
1439
|
+
"""Search a record set by given name and type."""
|
|
1211
1440
|
fqdn_used = self.verify_fqdn(fqdn, raise_on_error=raise_on_error)
|
|
1212
1441
|
if not fqdn_used:
|
|
1213
1442
|
return None
|
|
@@ -1215,8 +1444,11 @@ class PowerDNSZone(BasePowerDNSHandler):
|
|
|
1215
1444
|
if not rtype:
|
|
1216
1445
|
return None
|
|
1217
1446
|
|
|
1218
|
-
LOG.debug(
|
|
1219
|
-
f
|
|
1447
|
+
LOG.debug(
|
|
1448
|
+
_("Searching for RecordSet {f!r} of type {t!r} in zone {z!r}.").format(
|
|
1449
|
+
f=fqdn_used, t=rtype, z=self.name
|
|
1450
|
+
)
|
|
1451
|
+
)
|
|
1220
1452
|
|
|
1221
1453
|
if not len(self.rrsets):
|
|
1222
1454
|
self.update()
|
|
@@ -1224,21 +1456,20 @@ class PowerDNSZone(BasePowerDNSHandler):
|
|
|
1224
1456
|
for rrset in self.rrsets:
|
|
1225
1457
|
if rrset.name == fqdn_used and rrset.type == rtype:
|
|
1226
1458
|
if self.verbose > 2:
|
|
1227
|
-
msg = _(
|
|
1228
|
-
msg +=
|
|
1459
|
+
msg = _("Found {} RecordSet:").format(rtype)
|
|
1460
|
+
msg += "\n" + pp(rrset.as_dict(minimal=True))
|
|
1229
1461
|
LOG.debug(msg)
|
|
1230
1462
|
return rrset
|
|
1231
1463
|
|
|
1232
|
-
LOG.debug(_(
|
|
1233
|
-
f=fqdn_used, t=rtype)))
|
|
1464
|
+
LOG.debug(_("Did not found RecordSet {f!r} of type {t!r}.".format(f=fqdn_used, t=rtype)))
|
|
1234
1465
|
return None
|
|
1235
1466
|
|
|
1236
1467
|
# -------------------------------------------------------------------------
|
|
1237
1468
|
def get_soa_rrset(self, raise_on_error=True):
|
|
1238
|
-
"""
|
|
1239
|
-
rrset = self.get_rrset(fqdn=self.name, rrset_type=
|
|
1469
|
+
"""Search for the SOA record set of current zone."""
|
|
1470
|
+
rrset = self.get_rrset(fqdn=self.name, rrset_type="SOA", raise_on_error=raise_on_error)
|
|
1240
1471
|
if not rrset:
|
|
1241
|
-
LOG.warning(_(
|
|
1472
|
+
LOG.warning(_("Did not get SOA for zone {!r}.").format(self.name))
|
|
1242
1473
|
return rrset
|
|
1243
1474
|
|
|
1244
1475
|
|
|
@@ -1254,12 +1485,13 @@ class PowerDNSZoneDict(MutableMapping):
|
|
|
1254
1485
|
zones['pp.com'] returns a PowerDNSZone object for zone 'pp.com'
|
|
1255
1486
|
"""
|
|
1256
1487
|
|
|
1257
|
-
msg_invalid_zone_type = _(
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1488
|
+
msg_invalid_zone_type = _("Invalid item type {{!r}} to set, only {} allowed.").format(
|
|
1489
|
+
"PowerDNSZone"
|
|
1490
|
+
)
|
|
1491
|
+
msg_key_not_name = _("The key {k!r} must be equal to the zone name {n!r}.")
|
|
1492
|
+
msg_none_type_error = _("None type as key is not allowed.")
|
|
1493
|
+
msg_empty_key_error = _("Empty key {!r} is not allowed.")
|
|
1494
|
+
msg_no_zone_dict = _("Object {o!r} is not a {e} object.")
|
|
1263
1495
|
|
|
1264
1496
|
# -------------------------------------------------------------------------
|
|
1265
1497
|
# __init__() method required to create instance from class.
|
|
@@ -1296,7 +1528,7 @@ class PowerDNSZoneDict(MutableMapping):
|
|
|
1296
1528
|
raise TypeError(self.msg_none_type_error)
|
|
1297
1529
|
|
|
1298
1530
|
zone_name = str(key).lower().strip()
|
|
1299
|
-
if zone_name ==
|
|
1531
|
+
if zone_name == "":
|
|
1300
1532
|
raise ValueError(self.msg_empty_key_error.format(key))
|
|
1301
1533
|
|
|
1302
1534
|
return self._map[zone_name]
|
|
@@ -1313,7 +1545,7 @@ class PowerDNSZoneDict(MutableMapping):
|
|
|
1313
1545
|
raise TypeError(self.msg_none_type_error)
|
|
1314
1546
|
|
|
1315
1547
|
zone_name = str(key).lower().strip()
|
|
1316
|
-
if zone_name ==
|
|
1548
|
+
if zone_name == "":
|
|
1317
1549
|
raise ValueError(self.msg_empty_key_error.format(key))
|
|
1318
1550
|
|
|
1319
1551
|
if not strict and zone_name not in self._map:
|
|
@@ -1356,11 +1588,10 @@ class PowerDNSZoneDict(MutableMapping):
|
|
|
1356
1588
|
|
|
1357
1589
|
# -------------------------------------------------------------------------
|
|
1358
1590
|
def __repr__(self):
|
|
1359
|
-
"""Echoes class,
|
|
1360
|
-
return
|
|
1361
|
-
super(PowerDNSZoneDict, self).__repr__(),
|
|
1362
|
-
|
|
1363
|
-
self._map)
|
|
1591
|
+
"""Echoes class, zone_id, & reproducible representation in the REPL."""
|
|
1592
|
+
return "{}, {}({})".format(
|
|
1593
|
+
super(PowerDNSZoneDict, self).__repr__(), self.__class__.__name__, self._map
|
|
1594
|
+
)
|
|
1364
1595
|
|
|
1365
1596
|
# -------------------------------------------------------------------------
|
|
1366
1597
|
def __contains__(self, key):
|
|
@@ -1369,7 +1600,7 @@ class PowerDNSZoneDict(MutableMapping):
|
|
|
1369
1600
|
raise TypeError(self.msg_none_type_error)
|
|
1370
1601
|
|
|
1371
1602
|
zone_name = str(key).lower().strip()
|
|
1372
|
-
if zone_name ==
|
|
1603
|
+
if zone_name == "":
|
|
1373
1604
|
raise ValueError(self.msg_empty_key_error.format(key))
|
|
1374
1605
|
|
|
1375
1606
|
return zone_name in self._map
|
|
@@ -1378,8 +1609,8 @@ class PowerDNSZoneDict(MutableMapping):
|
|
|
1378
1609
|
def keys(self):
|
|
1379
1610
|
"""Return a sorted list of all zone names in this dict."""
|
|
1380
1611
|
return sorted(
|
|
1381
|
-
self._map.keys(),
|
|
1382
|
-
|
|
1612
|
+
self._map.keys(), key=lambda x: cmp_to_key(compare_fqdn)(self._map[x].name_unicode)
|
|
1613
|
+
)
|
|
1383
1614
|
|
|
1384
1615
|
# -------------------------------------------------------------------------
|
|
1385
1616
|
def items(self):
|
|
@@ -1403,7 +1634,7 @@ class PowerDNSZoneDict(MutableMapping):
|
|
|
1403
1634
|
def __eq__(self, other):
|
|
1404
1635
|
"""Magic method for using it as the '=='-operator."""
|
|
1405
1636
|
if not isinstance(other, PowerDNSZoneDict):
|
|
1406
|
-
raise TypeError(self.msg_no_zone_dict.format(o=other, e=
|
|
1637
|
+
raise TypeError(self.msg_no_zone_dict.format(o=other, e="PowerDNSZoneDict"))
|
|
1407
1638
|
|
|
1408
1639
|
return self._map == other._map
|
|
1409
1640
|
|
|
@@ -1411,7 +1642,7 @@ class PowerDNSZoneDict(MutableMapping):
|
|
|
1411
1642
|
def __ne__(self, other):
|
|
1412
1643
|
"""Magic method for using it as the '!='-operator."""
|
|
1413
1644
|
if not isinstance(other, PowerDNSZoneDict):
|
|
1414
|
-
raise TypeError(self.msg_no_zone_dict.format(o=other, e=
|
|
1645
|
+
raise TypeError(self.msg_no_zone_dict.format(o=other, e="PowerDNSZoneDict"))
|
|
1415
1646
|
|
|
1416
1647
|
return self._map != other._map
|
|
1417
1648
|
|
|
@@ -1422,7 +1653,7 @@ class PowerDNSZoneDict(MutableMapping):
|
|
|
1422
1653
|
raise TypeError(self.msg_none_type_error)
|
|
1423
1654
|
|
|
1424
1655
|
zone_name = str(key).lower().strip()
|
|
1425
|
-
if zone_name ==
|
|
1656
|
+
if zone_name == "":
|
|
1426
1657
|
raise ValueError(self.msg_empty_key_error.format(key))
|
|
1427
1658
|
|
|
1428
1659
|
return self._map.pop(zone_name, *args)
|
|
@@ -1454,7 +1685,7 @@ class PowerDNSZoneDict(MutableMapping):
|
|
|
1454
1685
|
raise TypeError(self.msg_none_type_error)
|
|
1455
1686
|
|
|
1456
1687
|
zone_name = str(key).lower().strip()
|
|
1457
|
-
if zone_name ==
|
|
1688
|
+
if zone_name == "":
|
|
1458
1689
|
raise ValueError(self.msg_empty_key_error.format(key))
|
|
1459
1690
|
|
|
1460
1691
|
if not isinstance(default, PowerDNSZone):
|
|
@@ -1498,7 +1729,7 @@ class PowerDNSZoneDict(MutableMapping):
|
|
|
1498
1729
|
|
|
1499
1730
|
# =============================================================================
|
|
1500
1731
|
|
|
1501
|
-
if __name__ ==
|
|
1732
|
+
if __name__ == "__main__":
|
|
1502
1733
|
|
|
1503
1734
|
pass
|
|
1504
1735
|
|