netbox-plugin-dns 0.22.5__py3-none-any.whl → 0.22.8__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.
Potentially problematic release.
This version of netbox-plugin-dns might be problematic. Click here for more details.
- netbox_dns/__init__.py +2 -38
- netbox_dns/api/serializers.py +1 -0
- netbox_dns/filters/record.py +31 -5
- netbox_dns/filters/zone.py +1 -1
- netbox_dns/forms/record.py +11 -4
- netbox_dns/forms/registrar.py +9 -0
- netbox_dns/forms/zone.py +4 -3
- netbox_dns/migrations/0029_record_fqdn.py +30 -0
- netbox_dns/models/record.py +73 -59
- netbox_dns/models/zone.py +9 -0
- netbox_dns/tables/record.py +4 -4
- netbox_dns/templates/netbox_dns/record.html +6 -22
- netbox_dns/views/record.py +76 -2
- {netbox_plugin_dns-0.22.5.dist-info → netbox_plugin_dns-0.22.8.dist-info}/METADATA +1 -1
- {netbox_plugin_dns-0.22.5.dist-info → netbox_plugin_dns-0.22.8.dist-info}/RECORD +17 -16
- {netbox_plugin_dns-0.22.5.dist-info → netbox_plugin_dns-0.22.8.dist-info}/LICENSE +0 -0
- {netbox_plugin_dns-0.22.5.dist-info → netbox_plugin_dns-0.22.8.dist-info}/WHEEL +0 -0
netbox_dns/__init__.py
CHANGED
|
@@ -10,7 +10,7 @@ except ImportError:
|
|
|
10
10
|
# NetBox 3.5.8
|
|
11
11
|
from extras.plugins.utils import get_plugin_config
|
|
12
12
|
|
|
13
|
-
__version__ = "0.22.
|
|
13
|
+
__version__ = "0.22.8"
|
|
14
14
|
|
|
15
15
|
|
|
16
16
|
class DNSConfig(PluginConfig):
|
|
@@ -18,6 +18,7 @@ class DNSConfig(PluginConfig):
|
|
|
18
18
|
verbose_name = "NetBox DNS"
|
|
19
19
|
description = "NetBox plugin for DNS data"
|
|
20
20
|
min_version = "3.5.0"
|
|
21
|
+
max_version = "3.99.0"
|
|
21
22
|
version = __version__
|
|
22
23
|
author = "Peter Eckel"
|
|
23
24
|
author_email = "pete@netbox-dns.org"
|
|
@@ -43,43 +44,6 @@ class DNSConfig(PluginConfig):
|
|
|
43
44
|
}
|
|
44
45
|
base_url = "netbox-dns"
|
|
45
46
|
|
|
46
|
-
def ready(self):
|
|
47
|
-
#
|
|
48
|
-
# Check if required custom fields exist for IPAM coupling
|
|
49
|
-
#
|
|
50
|
-
if get_plugin_config("netbox_dns", "feature_ipam_coupling"):
|
|
51
|
-
from extras.models import CustomField
|
|
52
|
-
from ipam.models import IPAddress
|
|
53
|
-
from django.contrib.contenttypes.models import ContentType
|
|
54
|
-
|
|
55
|
-
try:
|
|
56
|
-
objtype = ContentType.objects.get_for_model(IPAddress)
|
|
57
|
-
required_cf = (
|
|
58
|
-
"ipaddress_dns_record_name",
|
|
59
|
-
"ipaddress_dns_record_ttl",
|
|
60
|
-
"ipaddress_dns_record_disable_ptr",
|
|
61
|
-
"ipaddress_dns_zone_id",
|
|
62
|
-
)
|
|
63
|
-
|
|
64
|
-
if CustomField.objects.filter(
|
|
65
|
-
name__in=required_cf, content_types=objtype
|
|
66
|
-
).count() < len(required_cf):
|
|
67
|
-
print(
|
|
68
|
-
"WARNING: 'feature_ipam_coupling' is enabled, but the required"
|
|
69
|
-
" custom fields for IPAM DNS coupling are missing. Please run"
|
|
70
|
-
" the Django management command 'setup_coupling' to create the"
|
|
71
|
-
" missing custom fields.",
|
|
72
|
-
file=sys.stderr,
|
|
73
|
-
)
|
|
74
|
-
except OperationalError as exc:
|
|
75
|
-
print(
|
|
76
|
-
"WARNING: Unable to connect to PostgreSQL, cannot check custom fields"
|
|
77
|
-
" for feature_ipam_coupling",
|
|
78
|
-
file=sys.stderr,
|
|
79
|
-
)
|
|
80
|
-
|
|
81
|
-
super().ready()
|
|
82
|
-
|
|
83
47
|
|
|
84
48
|
#
|
|
85
49
|
# Initialize plugin config
|
netbox_dns/api/serializers.py
CHANGED
netbox_dns/filters/record.py
CHANGED
|
@@ -3,17 +3,22 @@ from django.db.models import Q
|
|
|
3
3
|
|
|
4
4
|
from netbox.filtersets import NetBoxModelFilterSet
|
|
5
5
|
from tenancy.filtersets import TenancyFilterSet
|
|
6
|
+
from utilities.filters import MultiValueCharFilter
|
|
6
7
|
|
|
7
|
-
from netbox_dns.models import View, Zone, Record, RecordTypeChoices
|
|
8
|
+
from netbox_dns.models import View, Zone, Record, RecordTypeChoices, RecordStatusChoices
|
|
8
9
|
|
|
9
10
|
|
|
10
11
|
class RecordFilter(TenancyFilterSet, NetBoxModelFilterSet):
|
|
11
|
-
|
|
12
|
-
|
|
12
|
+
fqdn = MultiValueCharFilter(
|
|
13
|
+
method="filter_fqdn",
|
|
14
|
+
)
|
|
13
15
|
type = django_filters.MultipleChoiceFilter(
|
|
14
16
|
choices=RecordTypeChoices,
|
|
15
17
|
null_value=None,
|
|
16
18
|
)
|
|
19
|
+
status = django_filters.MultipleChoiceFilter(
|
|
20
|
+
choices=RecordStatusChoices,
|
|
21
|
+
)
|
|
17
22
|
zone_id = django_filters.ModelMultipleChoiceFilter(
|
|
18
23
|
queryset=Zone.objects.all(),
|
|
19
24
|
label="Parent Zone ID",
|
|
@@ -39,10 +44,31 @@ class RecordFilter(TenancyFilterSet, NetBoxModelFilterSet):
|
|
|
39
44
|
|
|
40
45
|
class Meta:
|
|
41
46
|
model = Record
|
|
42
|
-
fields = (
|
|
47
|
+
fields = (
|
|
48
|
+
"id",
|
|
49
|
+
"type",
|
|
50
|
+
"name",
|
|
51
|
+
"fqdn",
|
|
52
|
+
"value",
|
|
53
|
+
"status",
|
|
54
|
+
"zone",
|
|
55
|
+
"managed",
|
|
56
|
+
"tenant",
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
def filter_fqdn(self, queryset, name, value):
|
|
60
|
+
if not value:
|
|
61
|
+
return queryset
|
|
62
|
+
|
|
63
|
+
fqdns = []
|
|
64
|
+
for fqdn in value:
|
|
65
|
+
if not fqdn.endswith("."):
|
|
66
|
+
fqdn = fqdn + "."
|
|
67
|
+
fqdns.append(fqdn)
|
|
68
|
+
|
|
69
|
+
return queryset.filter(fqdn__in=fqdns)
|
|
43
70
|
|
|
44
71
|
def search(self, queryset, name, value):
|
|
45
|
-
"""Perform the filtered search."""
|
|
46
72
|
if not value.strip():
|
|
47
73
|
return queryset
|
|
48
74
|
qs_filter = (
|
netbox_dns/filters/zone.py
CHANGED
|
@@ -8,7 +8,7 @@ from netbox_dns.models import View, Zone, ZoneStatusChoices, Registrar, Contact
|
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
class ZoneFilter(TenancyFilterSet, NetBoxModelFilterSet):
|
|
11
|
-
status = django_filters.
|
|
11
|
+
status = django_filters.MultipleChoiceFilter(
|
|
12
12
|
choices=ZoneStatusChoices,
|
|
13
13
|
)
|
|
14
14
|
view_id = django_filters.ModelMultipleChoiceFilter(
|
netbox_dns/forms/record.py
CHANGED
|
@@ -79,24 +79,31 @@ class RecordFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
|
|
|
79
79
|
model = Record
|
|
80
80
|
fieldsets = (
|
|
81
81
|
(None, ("q", "filter_id", "tag")),
|
|
82
|
-
(
|
|
82
|
+
(
|
|
83
|
+
"Attributes",
|
|
84
|
+
("view_id", "zone_id", "name", "fqdn", "type", "value", "status"),
|
|
85
|
+
),
|
|
83
86
|
("Tenant", ("tenant_group_id", "tenant_id")),
|
|
84
87
|
)
|
|
85
88
|
|
|
86
89
|
type = forms.MultipleChoiceField(
|
|
87
|
-
choices=
|
|
90
|
+
choices=RecordTypeChoices,
|
|
88
91
|
required=False,
|
|
89
92
|
)
|
|
90
93
|
name = forms.CharField(
|
|
91
94
|
required=False,
|
|
92
95
|
label="Name",
|
|
93
96
|
)
|
|
97
|
+
fqdn = forms.CharField(
|
|
98
|
+
required=False,
|
|
99
|
+
label="FQDN",
|
|
100
|
+
)
|
|
94
101
|
value = forms.CharField(
|
|
95
102
|
required=False,
|
|
96
103
|
label="Value",
|
|
97
104
|
)
|
|
98
|
-
status = forms.
|
|
99
|
-
choices=
|
|
105
|
+
status = forms.MultipleChoiceField(
|
|
106
|
+
choices=RecordStatusChoices,
|
|
100
107
|
required=False,
|
|
101
108
|
)
|
|
102
109
|
zone_id = DynamicModelMultipleChoiceField(
|
netbox_dns/forms/registrar.py
CHANGED
|
@@ -83,6 +83,13 @@ class RegistrarImportForm(NetBoxModelImportForm):
|
|
|
83
83
|
class RegistrarBulkEditForm(NetBoxModelBulkEditForm):
|
|
84
84
|
model = Registrar
|
|
85
85
|
|
|
86
|
+
iana_id = forms.IntegerField(
|
|
87
|
+
required=False,
|
|
88
|
+
label="IANA ID",
|
|
89
|
+
)
|
|
90
|
+
address = forms.CharField(
|
|
91
|
+
required=False,
|
|
92
|
+
)
|
|
86
93
|
referral_url = forms.CharField(
|
|
87
94
|
required=False,
|
|
88
95
|
label="Referral URL",
|
|
@@ -104,6 +111,7 @@ class RegistrarBulkEditForm(NetBoxModelBulkEditForm):
|
|
|
104
111
|
(
|
|
105
112
|
None,
|
|
106
113
|
(
|
|
114
|
+
"iana_id",
|
|
107
115
|
"address",
|
|
108
116
|
"referral_url",
|
|
109
117
|
"whois_server",
|
|
@@ -114,6 +122,7 @@ class RegistrarBulkEditForm(NetBoxModelBulkEditForm):
|
|
|
114
122
|
)
|
|
115
123
|
|
|
116
124
|
nullable_fields = (
|
|
125
|
+
"iana_id",
|
|
117
126
|
"address",
|
|
118
127
|
"referral_url",
|
|
119
128
|
"whois_server",
|
netbox_dns/forms/zone.py
CHANGED
|
@@ -258,8 +258,8 @@ class ZoneFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
|
|
|
258
258
|
required=False,
|
|
259
259
|
label="View",
|
|
260
260
|
)
|
|
261
|
-
status = forms.
|
|
262
|
-
choices=
|
|
261
|
+
status = forms.MultipleChoiceField(
|
|
262
|
+
choices=ZoneStatusChoices,
|
|
263
263
|
required=False,
|
|
264
264
|
)
|
|
265
265
|
name = forms.CharField(
|
|
@@ -595,8 +595,9 @@ class ZoneBulkEditForm(NetBoxModelBulkEditForm):
|
|
|
595
595
|
help_text="IPv4 network prefix with a mask length of at least 25 bits",
|
|
596
596
|
validators=[validate_ipv4, validate_prefix, validate_rfc2317],
|
|
597
597
|
)
|
|
598
|
-
rfc2317_parent_managed = forms.
|
|
598
|
+
rfc2317_parent_managed = forms.NullBooleanField(
|
|
599
599
|
required=False,
|
|
600
|
+
widget=BulkEditNullBooleanSelect(),
|
|
600
601
|
label="RFC2317 Parent Managed",
|
|
601
602
|
help_text="IPv4 reverse zone for deletgating the RFC2317 PTR records is managed in NetBox DNS",
|
|
602
603
|
)
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
from dns import name as dns_name
|
|
2
|
+
|
|
3
|
+
from django.db import migrations, models
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def update_record_fqdn(apps, schema_editor):
|
|
7
|
+
Record = apps.get_model("netbox_dns", "Record")
|
|
8
|
+
|
|
9
|
+
for record in Record.objects.filter(fqdn__isnull=True):
|
|
10
|
+
zone = dns_name.from_text(record.zone.name, origin=dns_name.root)
|
|
11
|
+
fqdn = dns_name.from_text(record.name, origin=zone)
|
|
12
|
+
|
|
13
|
+
record.fqdn = fqdn.to_text()
|
|
14
|
+
|
|
15
|
+
record.save()
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class Migration(migrations.Migration):
|
|
19
|
+
dependencies = [
|
|
20
|
+
("netbox_dns", "0028_rfc2317_fields"),
|
|
21
|
+
]
|
|
22
|
+
|
|
23
|
+
operations = [
|
|
24
|
+
migrations.AddField(
|
|
25
|
+
model_name="record",
|
|
26
|
+
name="fqdn",
|
|
27
|
+
field=models.CharField(default=None, max_length=255, null=True, blank=True),
|
|
28
|
+
),
|
|
29
|
+
migrations.RunPython(update_record_fqdn),
|
|
30
|
+
]
|
netbox_dns/models/record.py
CHANGED
|
@@ -114,17 +114,23 @@ class Record(NetBoxModel):
|
|
|
114
114
|
Q(Q(type=RecordTypeChoices.A) | Q(type=RecordTypeChoices.AAAA)),
|
|
115
115
|
)
|
|
116
116
|
|
|
117
|
+
name = models.CharField(
|
|
118
|
+
max_length=255,
|
|
119
|
+
)
|
|
117
120
|
zone = models.ForeignKey(
|
|
118
121
|
"Zone",
|
|
119
122
|
on_delete=models.CASCADE,
|
|
120
123
|
)
|
|
124
|
+
fqdn = models.CharField(
|
|
125
|
+
max_length=255,
|
|
126
|
+
null=True,
|
|
127
|
+
blank=True,
|
|
128
|
+
default=None,
|
|
129
|
+
)
|
|
121
130
|
type = models.CharField(
|
|
122
131
|
choices=RecordTypeChoices,
|
|
123
132
|
max_length=10,
|
|
124
133
|
)
|
|
125
|
-
name = models.CharField(
|
|
126
|
-
max_length=255,
|
|
127
|
-
)
|
|
128
134
|
value = models.CharField(
|
|
129
135
|
max_length=65535,
|
|
130
136
|
)
|
|
@@ -209,14 +215,7 @@ class Record(NetBoxModel):
|
|
|
209
215
|
|
|
210
216
|
def __str__(self):
|
|
211
217
|
try:
|
|
212
|
-
name = (
|
|
213
|
-
dns_name.from_text(
|
|
214
|
-
str(self.name),
|
|
215
|
-
origin=dns_name.from_text(self.zone.name, origin=None),
|
|
216
|
-
)
|
|
217
|
-
.relativize(dns_name.root)
|
|
218
|
-
.to_unicode()
|
|
219
|
-
)
|
|
218
|
+
name = dns_name.from_text(self.fqdn).relativize(dns_name.root).to_unicode()
|
|
220
219
|
except dns_name.IDNAException:
|
|
221
220
|
name = self.name
|
|
222
221
|
except dns_name.LabelTooLong as exc:
|
|
@@ -235,11 +234,14 @@ class Record(NetBoxModel):
|
|
|
235
234
|
return reverse("plugins:netbox_dns:record", kwargs={"pk": self.id})
|
|
236
235
|
|
|
237
236
|
@property
|
|
238
|
-
def
|
|
237
|
+
def value_fqdn(self):
|
|
238
|
+
if self.type != RecordTypeChoices.CNAME:
|
|
239
|
+
return None
|
|
240
|
+
|
|
239
241
|
zone = dns_name.from_text(self.zone.name)
|
|
240
|
-
|
|
242
|
+
value_fqdn = dns_name.from_text(self.value, origin=zone)
|
|
241
243
|
|
|
242
|
-
return
|
|
244
|
+
return value_fqdn.to_text()
|
|
243
245
|
|
|
244
246
|
@property
|
|
245
247
|
def address_from_name(self):
|
|
@@ -383,6 +385,22 @@ class Record(NetBoxModel):
|
|
|
383
385
|
|
|
384
386
|
self.ptr_record = ptr_record
|
|
385
387
|
|
|
388
|
+
def remove_from_rfc2317_cname_record(self, save_zone_serial=True):
|
|
389
|
+
if self.rfc2317_cname_record.pk:
|
|
390
|
+
rfc2317_ptr_records = self.rfc2317_cname_record.rfc2317_ptr_records.exclude(
|
|
391
|
+
pk=self.pk
|
|
392
|
+
)
|
|
393
|
+
|
|
394
|
+
if rfc2317_ptr_records:
|
|
395
|
+
self.rfc2317_cname_record.ttl = rfc2317_ptr_records.aggregate(
|
|
396
|
+
Min("ttl")
|
|
397
|
+
).get("ttl__min")
|
|
398
|
+
self.rfc2317_cname_record.save(
|
|
399
|
+
update_fields=["ttl"], save_zone_serial=save_zone_serial
|
|
400
|
+
)
|
|
401
|
+
else:
|
|
402
|
+
self.rfc2317_cname_record.delete()
|
|
403
|
+
|
|
386
404
|
def update_rfc2317_cname_record(self, save_zone_serial=True):
|
|
387
405
|
if self.zone.rfc2317_parent_managed:
|
|
388
406
|
cname_name = dns_name.from_text(
|
|
@@ -390,48 +408,56 @@ class Record(NetBoxModel):
|
|
|
390
408
|
).relativize(dns_name.from_text(self.zone.rfc2317_parent_zone.name))
|
|
391
409
|
|
|
392
410
|
if self.rfc2317_cname_record is not None:
|
|
393
|
-
self.rfc2317_cname_record.name
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
411
|
+
if self.rfc2317_cname_record.name == cname_name.to_text():
|
|
412
|
+
self.rfc2317_cname_record.zone = self.zone.rfc2317_parent_zone
|
|
413
|
+
self.rfc2317_cname_record.value = self.fqdn
|
|
414
|
+
self.rfc2317_cname_record.ttl = min_ttl(
|
|
415
|
+
self.rfc2317_cname_record.rfc2317_ptr_records.exclude(
|
|
416
|
+
pk=self.pk
|
|
417
|
+
)
|
|
418
|
+
.aggregate(Min("ttl"))
|
|
419
|
+
.get("ttl__min"),
|
|
420
|
+
self.ttl,
|
|
421
|
+
)
|
|
422
|
+
self.rfc2317_cname_record.save(save_zone_serial=save_zone_serial)
|
|
423
|
+
|
|
424
|
+
return
|
|
425
|
+
else:
|
|
426
|
+
self.remove_from_rfc2317_cname_record(
|
|
427
|
+
save_zone_serial=save_zone_serial
|
|
428
|
+
)
|
|
429
|
+
|
|
430
|
+
rfc2317_cname_record = Record.objects.filter(
|
|
431
|
+
name=cname_name,
|
|
432
|
+
type=RecordTypeChoices.CNAME,
|
|
433
|
+
zone=self.zone.rfc2317_parent_zone,
|
|
434
|
+
managed=True,
|
|
435
|
+
value=self.fqdn,
|
|
436
|
+
).first()
|
|
437
|
+
|
|
438
|
+
if rfc2317_cname_record is not None:
|
|
439
|
+
rfc2317_cname_record.ttl = min_ttl(
|
|
440
|
+
rfc2317_cname_record.rfc2317_ptr_records.exclude(pk=self.pk)
|
|
398
441
|
.aggregate(Min("ttl"))
|
|
399
442
|
.get("ttl__min"),
|
|
400
443
|
self.ttl,
|
|
401
444
|
)
|
|
402
|
-
|
|
445
|
+
rfc2317_cname_record.save(
|
|
446
|
+
update_fields=["ttl"], save_zone_serial=save_zone_serial
|
|
447
|
+
)
|
|
448
|
+
|
|
403
449
|
else:
|
|
404
|
-
rfc2317_cname_record = Record
|
|
450
|
+
rfc2317_cname_record = Record(
|
|
405
451
|
name=cname_name,
|
|
406
452
|
type=RecordTypeChoices.CNAME,
|
|
407
453
|
zone=self.zone.rfc2317_parent_zone,
|
|
408
454
|
managed=True,
|
|
409
455
|
value=self.fqdn,
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
rfc2317_cname_record.ttl = min_ttl(
|
|
414
|
-
rfc2317_cname_record.rfc2317_ptr_records.exclude(pk=self.pk)
|
|
415
|
-
.aggregate(Min("ttl"))
|
|
416
|
-
.get("ttl__min"),
|
|
417
|
-
self.ttl,
|
|
418
|
-
)
|
|
419
|
-
rfc2317_cname_record.save(
|
|
420
|
-
update_fields=["ttl"], save_zone_serial=save_zone_serial
|
|
421
|
-
)
|
|
422
|
-
|
|
423
|
-
else:
|
|
424
|
-
rfc2317_cname_record = Record(
|
|
425
|
-
name=cname_name,
|
|
426
|
-
type=RecordTypeChoices.CNAME,
|
|
427
|
-
zone=self.zone.rfc2317_parent_zone,
|
|
428
|
-
managed=True,
|
|
429
|
-
value=self.fqdn,
|
|
430
|
-
ttl=self.ttl,
|
|
431
|
-
)
|
|
432
|
-
rfc2317_cname_record.save(save_zone_serial=save_zone_serial)
|
|
456
|
+
ttl=self.ttl,
|
|
457
|
+
)
|
|
458
|
+
rfc2317_cname_record.save(save_zone_serial=save_zone_serial)
|
|
433
459
|
|
|
434
|
-
|
|
460
|
+
self.rfc2317_cname_record = rfc2317_cname_record
|
|
435
461
|
|
|
436
462
|
else:
|
|
437
463
|
if self.rfc2317_cname_record is not None:
|
|
@@ -448,6 +474,7 @@ class Record(NetBoxModel):
|
|
|
448
474
|
name.to_unicode()
|
|
449
475
|
|
|
450
476
|
self.name = name.relativize(zone).to_text()
|
|
477
|
+
self.fqdn = fqdn.to_text()
|
|
451
478
|
|
|
452
479
|
except dns.exception.DNSException as exc:
|
|
453
480
|
raise ValidationError(
|
|
@@ -715,20 +742,7 @@ class Record(NetBoxModel):
|
|
|
715
742
|
|
|
716
743
|
def delete(self, *args, save_zone_serial=True, **kwargs):
|
|
717
744
|
if self.rfc2317_cname_record:
|
|
718
|
-
|
|
719
|
-
if self.rfc2317_cname_record.rfc2317_ptr_records.count() == 1:
|
|
720
|
-
self.rfc2317_cname_record.delete()
|
|
721
|
-
else:
|
|
722
|
-
self.rfc2317_cname_record.ttl = (
|
|
723
|
-
self.rfc2317_cname_record.rfc2317_ptr_records.exclude(
|
|
724
|
-
pk=self.pk
|
|
725
|
-
)
|
|
726
|
-
.aggregate(Min("ttl"))
|
|
727
|
-
.get("ttl__min")
|
|
728
|
-
)
|
|
729
|
-
self.rfc2317_cname_record.save(
|
|
730
|
-
update_fields=["ttl"], save_zone_serial=save_zone_serial
|
|
731
|
-
)
|
|
745
|
+
self.remove_from_rfc2317_cname_record(save_zone_serial=save_zone_serial)
|
|
732
746
|
|
|
733
747
|
if self.ptr_record:
|
|
734
748
|
self.ptr_record.delete()
|
netbox_dns/models/zone.py
CHANGED
|
@@ -738,6 +738,15 @@ class Zone(NetBoxModel):
|
|
|
738
738
|
ip.dns_name = f'{ip.custom_field_data["ipaddress_dns_record_name"]}.{self.name}'
|
|
739
739
|
ip.save(update_fields=["dns_name"])
|
|
740
740
|
|
|
741
|
+
if name_changed:
|
|
742
|
+
for _record in self.record_set.all():
|
|
743
|
+
_record.save(
|
|
744
|
+
update_fields=["fqdn"],
|
|
745
|
+
save_zone_serial=False,
|
|
746
|
+
update_rrset_ttl=False,
|
|
747
|
+
update_rfc2317_cname=False,
|
|
748
|
+
)
|
|
749
|
+
|
|
741
750
|
self.save_soa_serial()
|
|
742
751
|
self.update_soa_record()
|
|
743
752
|
|
netbox_dns/tables/record.py
CHANGED
|
@@ -61,8 +61,8 @@ class RecordTable(RecordBaseTable):
|
|
|
61
61
|
model = Record
|
|
62
62
|
fields = (
|
|
63
63
|
"pk",
|
|
64
|
-
"zone",
|
|
65
64
|
"name",
|
|
65
|
+
"zone",
|
|
66
66
|
"ttl",
|
|
67
67
|
"type",
|
|
68
68
|
"value",
|
|
@@ -77,8 +77,8 @@ class RecordTable(RecordBaseTable):
|
|
|
77
77
|
"tenant_group",
|
|
78
78
|
)
|
|
79
79
|
default_columns = (
|
|
80
|
-
"zone",
|
|
81
80
|
"name",
|
|
81
|
+
"zone",
|
|
82
82
|
"ttl",
|
|
83
83
|
"type",
|
|
84
84
|
"value",
|
|
@@ -101,8 +101,8 @@ class ManagedRecordTable(RecordBaseTable):
|
|
|
101
101
|
class Meta(NetBoxTable.Meta):
|
|
102
102
|
model = Record
|
|
103
103
|
fields = (
|
|
104
|
-
"zone",
|
|
105
104
|
"name",
|
|
105
|
+
"zone",
|
|
106
106
|
"ttl",
|
|
107
107
|
"type",
|
|
108
108
|
"value",
|
|
@@ -112,8 +112,8 @@ class ManagedRecordTable(RecordBaseTable):
|
|
|
112
112
|
"active",
|
|
113
113
|
)
|
|
114
114
|
default_columns = (
|
|
115
|
-
"zone",
|
|
116
115
|
"name",
|
|
116
|
+
"zone",
|
|
117
117
|
"ttl",
|
|
118
118
|
"type",
|
|
119
119
|
"value",
|
|
@@ -112,12 +112,6 @@
|
|
|
112
112
|
<td><a href="{% url 'ipam:ipaddress' pk=object.ipam_ip_address.pk %}">{{ object.ipam_ip_address }}</td>
|
|
113
113
|
</tr>
|
|
114
114
|
{% endif %}
|
|
115
|
-
{% if object.rfc2317_cname_record %}
|
|
116
|
-
<tr>
|
|
117
|
-
<th scope="row">RFC2317 CNAME Record</th>
|
|
118
|
-
<td><a href="{% url 'plugins:netbox_dns:record' pk=object.rfc2317_cname_record.pk %}">{{ object.rfc2317_cname_record }}</td>
|
|
119
|
-
</tr>
|
|
120
|
-
{% endif %}
|
|
121
115
|
<tr>
|
|
122
116
|
<th scope="row">Status</th>
|
|
123
117
|
<td>{% badge object.get_status_display bg_color=object.get_status_color %}</td>
|
|
@@ -131,23 +125,13 @@
|
|
|
131
125
|
</table>
|
|
132
126
|
</div>
|
|
133
127
|
</div>
|
|
134
|
-
{% if
|
|
128
|
+
{% if cname_target_table and cname_target_table.rows|length > 0 %}
|
|
135
129
|
<div class="card">
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
<th>PTR Record</th>
|
|
142
|
-
</tr>
|
|
143
|
-
{% for record in object.rfc2317_ptr_records.all %}
|
|
144
|
-
<tr>
|
|
145
|
-
<td><a href="{% url 'plugins:netbox_dns:record' pk=record.address_record.pk %}">{{ record.address_record }}</td>
|
|
146
|
-
<td><a href="{% url 'plugins:netbox_dns:record' pk=record.pk %}">{{ record }}</td>
|
|
147
|
-
</td>
|
|
148
|
-
{% endfor %}
|
|
149
|
-
</table>
|
|
150
|
-
</div>
|
|
130
|
+
{% include 'inc/panel_table.html' with table=cname_target_table heading='CNAME Targets' %}
|
|
131
|
+
</div>
|
|
132
|
+
{% elif cname_table and cname_table.rows|length > 0 %}
|
|
133
|
+
<div class="card">
|
|
134
|
+
{% include 'inc/panel_table.html' with table=cname_table heading='CNAMEs' %}
|
|
151
135
|
</div>
|
|
152
136
|
{% endif %}
|
|
153
137
|
{% if not object.managed %}
|
netbox_dns/views/record.py
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
from dns import name as dns_name
|
|
2
2
|
|
|
3
|
+
from django.db.models import Q
|
|
4
|
+
from django.db.models.functions import Length
|
|
5
|
+
|
|
3
6
|
from netbox.views import generic
|
|
4
7
|
|
|
5
8
|
from netbox_dns.filters import RecordFilter
|
|
@@ -9,8 +12,8 @@ from netbox_dns.forms import (
|
|
|
9
12
|
RecordForm,
|
|
10
13
|
RecordBulkEditForm,
|
|
11
14
|
)
|
|
12
|
-
from netbox_dns.models import Record
|
|
13
|
-
from netbox_dns.tables import RecordTable, ManagedRecordTable
|
|
15
|
+
from netbox_dns.models import Record, RecordTypeChoices, Zone
|
|
16
|
+
from netbox_dns.tables import RecordTable, ManagedRecordTable, RelatedRecordTable
|
|
14
17
|
from netbox_dns.utilities import value_to_unicode
|
|
15
18
|
|
|
16
19
|
|
|
@@ -37,6 +40,72 @@ class ManagedRecordListView(generic.ObjectListView):
|
|
|
37
40
|
class RecordView(generic.ObjectView):
|
|
38
41
|
queryset = Record.objects.all().prefetch_related("zone", "ptr_record")
|
|
39
42
|
|
|
43
|
+
def get_value_records(self, instance):
|
|
44
|
+
value_fqdn = dns_name.from_text(instance.value_fqdn)
|
|
45
|
+
value_zone_names = [
|
|
46
|
+
value_fqdn.split(length)[1].to_text().rstrip(".")
|
|
47
|
+
for length in range(2, len(value_fqdn) + 1)
|
|
48
|
+
]
|
|
49
|
+
|
|
50
|
+
value_zone = (
|
|
51
|
+
Zone.objects.filter(instance.zone.view_filter, name__in=value_zone_names)
|
|
52
|
+
.order_by(Length("name").desc())
|
|
53
|
+
.first()
|
|
54
|
+
)
|
|
55
|
+
if not value_zone:
|
|
56
|
+
return None
|
|
57
|
+
|
|
58
|
+
value_name = value_fqdn.relativize(dns_name.from_text(value_zone.name))
|
|
59
|
+
cname_targets = Record.objects.filter(zone=value_zone, name=value_name)
|
|
60
|
+
|
|
61
|
+
if cname_targets:
|
|
62
|
+
return RelatedRecordTable(
|
|
63
|
+
data=cname_targets,
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
return None
|
|
67
|
+
|
|
68
|
+
def get_cname_records(self, instance):
|
|
69
|
+
view_filter = (
|
|
70
|
+
Q(zone__view__isnull=True)
|
|
71
|
+
if instance.zone.view is None
|
|
72
|
+
else Q(zone__view=instance.zone.view)
|
|
73
|
+
)
|
|
74
|
+
cname_records = set(
|
|
75
|
+
Record.objects.filter(
|
|
76
|
+
view_filter, value=instance.fqdn, type=RecordTypeChoices.CNAME
|
|
77
|
+
)
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
fqdn = dns_name.from_text(instance.fqdn)
|
|
81
|
+
parent_zone_names = [
|
|
82
|
+
fqdn.split(length)[1].to_text().rstrip(".")
|
|
83
|
+
for length in range(1, len(fqdn) + 1)
|
|
84
|
+
]
|
|
85
|
+
|
|
86
|
+
parent_zones = Zone.objects.filter(
|
|
87
|
+
instance.zone.view_filter, name__in=parent_zone_names
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
for parent_zone in parent_zones:
|
|
91
|
+
parent_cname_records = Record.objects.filter(
|
|
92
|
+
view_filter, type=RecordTypeChoices.CNAME, zone=parent_zone
|
|
93
|
+
)
|
|
94
|
+
cname_records = cname_records.union(
|
|
95
|
+
set(
|
|
96
|
+
record
|
|
97
|
+
for record in parent_cname_records
|
|
98
|
+
if record.value_fqdn == instance.fqdn
|
|
99
|
+
)
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
if cname_records:
|
|
103
|
+
return RelatedRecordTable(
|
|
104
|
+
data=cname_records,
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
return None
|
|
108
|
+
|
|
40
109
|
def get_extra_context(self, request, instance):
|
|
41
110
|
context = {}
|
|
42
111
|
|
|
@@ -48,6 +117,11 @@ class RecordView(generic.ObjectView):
|
|
|
48
117
|
if instance.value != unicode_value:
|
|
49
118
|
context["unicode_value"] = unicode_value
|
|
50
119
|
|
|
120
|
+
if instance.type == RecordTypeChoices.CNAME:
|
|
121
|
+
context["cname_target_table"] = self.get_value_records(instance)
|
|
122
|
+
else:
|
|
123
|
+
context["cname_table"] = self.get_cname_records(instance)
|
|
124
|
+
|
|
51
125
|
return context
|
|
52
126
|
|
|
53
127
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
netbox_dns/__init__.py,sha256=
|
|
1
|
+
netbox_dns/__init__.py,sha256=ms-dOE6DcI1h8vdO1Ms_jC0aOcUxB8CfLDJsXPiFgV8,1314
|
|
2
2
|
netbox_dns/api/nested_serializers.py,sha256=XB7bcCjVMPYrumJWgRicj06PukQ2UCBjdr84AIUJuVQ,3291
|
|
3
|
-
netbox_dns/api/serializers.py,sha256=
|
|
3
|
+
netbox_dns/api/serializers.py,sha256=mCH6SvluOm9g3vV_hvxtNIyqGxtPAcLEBgLu-stq6AM,8203
|
|
4
4
|
netbox_dns/api/urls.py,sha256=R9VmmWtdrjvr35i5d_SfZK2lGn6JzmPuWEKTQlZ8MJo,575
|
|
5
5
|
netbox_dns/api/views.py,sha256=DjovvTfS4F2Fq2Ahea6f4LBJiWr01ajk-wSZHNTya5I,3527
|
|
6
6
|
netbox_dns/apps.py,sha256=JCW5eS-AQBUubDJve1DjP-IRFKTFGQh1NLGWzJpC5MI,151
|
|
@@ -11,17 +11,17 @@ netbox_dns/fields/rfc2317.py,sha256=Er52Hxghj1trNo41naAgwsLGGLx2NCQ-fGhSaalpoPg,
|
|
|
11
11
|
netbox_dns/filters/__init__.py,sha256=Aw8HrCTjaJfu5JSwJsQRHfOUz4zKwAmZNByT9q6BrFU,136
|
|
12
12
|
netbox_dns/filters/contact.py,sha256=_onZ6G2KKgfvm9Emg_kng2RPETRMfbTyIR8Tvs9d2YM,1027
|
|
13
13
|
netbox_dns/filters/nameserver.py,sha256=sDKsrluSmUZ0aTw_wagYJAh1g5fKzyzHXbJu6DaK1b8,522
|
|
14
|
-
netbox_dns/filters/record.py,sha256=
|
|
14
|
+
netbox_dns/filters/record.py,sha256=WOZQfcUPzDHiCVBbpdZ0Pd_QrVB3ed-Xw8xvZt_EgDo,2256
|
|
15
15
|
netbox_dns/filters/registrar.py,sha256=8UXJXUb0XmkPyPQ2oACAhzhmZtAmvM2c4hTWMDLuBEo,911
|
|
16
16
|
netbox_dns/filters/view.py,sha256=Sji4DKy0VKk8BLEdk8xCe8su3rUBtXeJUsUAee0IsOs,497
|
|
17
|
-
netbox_dns/filters/zone.py,sha256=
|
|
17
|
+
netbox_dns/filters/zone.py,sha256=A8B7sZ1RVzeTrJV0ODCstO0mXiJ1o0Njfn0o1LXH6y0,3564
|
|
18
18
|
netbox_dns/forms/__init__.py,sha256=Aw8HrCTjaJfu5JSwJsQRHfOUz4zKwAmZNByT9q6BrFU,136
|
|
19
19
|
netbox_dns/forms/contact.py,sha256=Z8llYOpcGns8ZerOLsldpY836pfjO7427rmAZ4T8Kyg,4492
|
|
20
20
|
netbox_dns/forms/nameserver.py,sha256=LUYV_tna667flgPdQevDFniMdXZUYRUG8iqCx7HKdxQ,2027
|
|
21
|
-
netbox_dns/forms/record.py,sha256=
|
|
22
|
-
netbox_dns/forms/registrar.py,sha256=
|
|
21
|
+
netbox_dns/forms/record.py,sha256=HAjUQJsaQepnN6qbU9sYJrQQXchecTiiRccWUjEsej0,6266
|
|
22
|
+
netbox_dns/forms/registrar.py,sha256=1YhbOle1gbgd02MfkGLhHJHIqvTd8sxLiu8cafmlT8s,2832
|
|
23
23
|
netbox_dns/forms/view.py,sha256=KEWlUo8-oXP_QsqT5fW_UK-ZoX9g-f4CqRnJ_P6LHco,1627
|
|
24
|
-
netbox_dns/forms/zone.py,sha256=
|
|
24
|
+
netbox_dns/forms/zone.py,sha256=KCRyWPZtQ-awoNOXC0PYBRPUzmJx7qrV8BQlS73WK9o,21740
|
|
25
25
|
netbox_dns/graphql/__init__.py,sha256=v3lLvVoP-JQbEZ1NY49u1TNqvanF-4TqOtjHXrbsTvU,811
|
|
26
26
|
netbox_dns/graphql/contact.py,sha256=2iyuvCxG09CLDUMhan5vR3uFZxCVzKNZBrotr_zoUVY,497
|
|
27
27
|
netbox_dns/graphql/nameserver.py,sha256=mlQw1Po_Ax_fjyyXVBetyxlFLrCqmptYDgOspZvYtP4,527
|
|
@@ -63,21 +63,22 @@ netbox_dns/migrations/0025_ipam_coupling_cf.py,sha256=7uHujclWrsYw5QMLWft0Po78Ow
|
|
|
63
63
|
netbox_dns/migrations/0026_domain_registration.py,sha256=qUJ1oUGHIGGNWD7QRLnxElbM5eNp7dYNNn_OYIw8Xvo,5796
|
|
64
64
|
netbox_dns/migrations/0027_alter_registrar_iana_id.py,sha256=QUtRIrqqfkraFmzzeJFZWAEv4PfrOouoHtrV6FRn8Kc,404
|
|
65
65
|
netbox_dns/migrations/0028_rfc2317_fields.py,sha256=D8r43xxBjYXiL6ycmX8RY5_WG7tRYEDjutOeYM1H56I,1364
|
|
66
|
+
netbox_dns/migrations/0029_record_fqdn.py,sha256=UAAU38ekKQyiYDOJlcrz6Qbk4bqZfSHZyAHUZFFQrOw,808
|
|
66
67
|
netbox_dns/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
67
68
|
netbox_dns/models/__init__.py,sha256=Q7UIEe2vGh18AZN4er6CykciwXPQGgUq0L-9718wZqU,182
|
|
68
69
|
netbox_dns/models/contact.py,sha256=Mzj4SR3fczOE96etWjObJElk0RVQetNuXZVtm8sS1h8,2849
|
|
69
70
|
netbox_dns/models/nameserver.py,sha256=SjKUbMRNE3TSDzmxbKFR9b4AfYPS0UPj0QeO7XpwNRk,2941
|
|
70
|
-
netbox_dns/models/record.py,sha256=
|
|
71
|
+
netbox_dns/models/record.py,sha256=f2NMdMVfsbjfo65uXyYzFCBGimEroLbt3AW9pkECeno,23917
|
|
71
72
|
netbox_dns/models/registrar.py,sha256=ByKHeqH5KfswqOLjya8DZExJ1omSKFHMfCjIIYfnwTo,1416
|
|
72
73
|
netbox_dns/models/view.py,sha256=ljs3Q2xQR63ZOSyja5H7DEdFbm7MX2ZjlR6uNVrAsVo,920
|
|
73
|
-
netbox_dns/models/zone.py,sha256=
|
|
74
|
+
netbox_dns/models/zone.py,sha256=EvNiZb0CfSg_VyjAOkKWVK-CSVDA9h_EYpt21N54C3Q,26637
|
|
74
75
|
netbox_dns/navigation.py,sha256=IutEr_TcPgDGzqTT1ZzV4IUABLSOFU9v364BfpCqbro,4587
|
|
75
76
|
netbox_dns/signals/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
76
77
|
netbox_dns/signals/ipam_coupling.py,sha256=xbb37_77ZqtgT3mKXZp18QRduqZuiAuYGPk8R9d7SVc,5727
|
|
77
78
|
netbox_dns/tables/__init__.py,sha256=Aw8HrCTjaJfu5JSwJsQRHfOUz4zKwAmZNByT9q6BrFU,136
|
|
78
79
|
netbox_dns/tables/contact.py,sha256=HpblHKrlQqQAPC59gvw8wUV3tc6UBAphHPE6CfN2uVM,747
|
|
79
80
|
netbox_dns/tables/nameserver.py,sha256=7Ap0px5gAHtgk5XFMpZCHccy9N-v8UKy19GP7fdWuPc,819
|
|
80
|
-
netbox_dns/tables/record.py,sha256=
|
|
81
|
+
netbox_dns/tables/record.py,sha256=VwBWMiZN_Lkl9SXfJLzd8-7TM1CKetwE7azhScF4r7I,3162
|
|
81
82
|
netbox_dns/tables/registrar.py,sha256=fnClFyukZ5Un-jUigrjDRYK5_2YE2BAtbm6lqctbeJ4,621
|
|
82
83
|
netbox_dns/tables/view.py,sha256=r9CLS96m-KojX3OYZ-k45FbVseHO20nPxRzlKrRrLio,501
|
|
83
84
|
netbox_dns/tables/zone.py,sha256=4TlTB7lVsztZJ41aetkqr6PWosjZP-xc2sB9gDnw0z8,1886
|
|
@@ -86,7 +87,7 @@ netbox_dns/templates/netbox_dns/contact.html,sha256=3qHGChgLYfqUgO3_z9jQ-lFIGS0Z
|
|
|
86
87
|
netbox_dns/templates/netbox_dns/nameserver.html,sha256=3AJVbsuhKg4Jy74rlvwrGSHd_IoDRdLT_XuK4EH3Djg,1623
|
|
87
88
|
netbox_dns/templates/netbox_dns/record/managed.html,sha256=G6LPG1koUGuzUiwYdv1okdVa4sKaofiQegDBnsFL0kA,89
|
|
88
89
|
netbox_dns/templates/netbox_dns/record/related.html,sha256=Aqor8uGcuHQTHjlX-Xmni2Yp4N7lOBrMOqQiszrQOC0,742
|
|
89
|
-
netbox_dns/templates/netbox_dns/record.html,sha256=
|
|
90
|
+
netbox_dns/templates/netbox_dns/record.html,sha256=jq1kueOd5EN1myZt8RbXl4rjoTuxWezBnVv36i74QC8,5835
|
|
90
91
|
netbox_dns/templates/netbox_dns/registrar.html,sha256=rSShbH68nP0r8EUHn0-TZOsUj6pg7hmfvM7h2tqouUA,2130
|
|
91
92
|
netbox_dns/templates/netbox_dns/related_dns_objects.html,sha256=KSzlnw1cStrJa3poKkwrt_ycIH0oH0STWIHRNy3ks4g,806
|
|
92
93
|
netbox_dns/templates/netbox_dns/view.html,sha256=_lDjd2xY3upfGpNpemXXMzgsaKZlX3-PzPPAdYkIjvs,1350
|
|
@@ -106,11 +107,11 @@ netbox_dns/validators/rfc2317.py,sha256=bgqDwdqwpf5d1mt24Wrr8z8t2IYbt5RovNr6l2nv
|
|
|
106
107
|
netbox_dns/views/__init__.py,sha256=Aw8HrCTjaJfu5JSwJsQRHfOUz4zKwAmZNByT9q6BrFU,136
|
|
107
108
|
netbox_dns/views/contact.py,sha256=6-oCfK98-submcUTmi0ejw7QBscNn3S9bnS0oUTXOaY,2235
|
|
108
109
|
netbox_dns/views/nameserver.py,sha256=Wa8CQ19P5uPNLMIYkj_U82wmwdp5gZoBWZnOR4ZExa0,2990
|
|
109
|
-
netbox_dns/views/record.py,sha256=
|
|
110
|
+
netbox_dns/views/record.py,sha256=ocA-xTXAo8xWf20aG_a8NnRportID8CuWdufDIqfxyI,4904
|
|
110
111
|
netbox_dns/views/registrar.py,sha256=aznSKt1L5tILMLGgcZiBR7u7B8rNl-jM1B2-N0fTeK8,2072
|
|
111
112
|
netbox_dns/views/view.py,sha256=uUvtlNEh5MYoEALvWWaCOqj_Zj8dpGOL2PUyg-UPfEA,1895
|
|
112
113
|
netbox_dns/views/zone.py,sha256=SyttTAgrPPzf1jIT1B4RexCLdXYjSmPIZsefO_zog1Q,4587
|
|
113
|
-
netbox_plugin_dns-0.22.
|
|
114
|
-
netbox_plugin_dns-0.22.
|
|
115
|
-
netbox_plugin_dns-0.22.
|
|
116
|
-
netbox_plugin_dns-0.22.
|
|
114
|
+
netbox_plugin_dns-0.22.8.dist-info/LICENSE,sha256=tziMJKpkMbySr09L6bIwsu7Ca9ICoqpMO3yAXgEMQA4,1076
|
|
115
|
+
netbox_plugin_dns-0.22.8.dist-info/METADATA,sha256=2vxCBGxDRbpd83kCHm5eeYScmOB_sV32za7KyiV5IZw,4572
|
|
116
|
+
netbox_plugin_dns-0.22.8.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
|
117
|
+
netbox_plugin_dns-0.22.8.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|