netbox-plugin-dns 0.22.9__py3-none-any.whl → 1.0.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.
Potentially problematic release.
This version of netbox-plugin-dns might be problematic. Click here for more details.
- netbox_dns/__init__.py +4 -15
- netbox_dns/api/nested_serializers.py +4 -60
- netbox_dns/api/serializers.py +8 -314
- netbox_dns/api/serializers_/__init__.py +0 -0
- netbox_dns/api/serializers_/contact.py +37 -0
- netbox_dns/api/serializers_/nameserver.py +39 -0
- netbox_dns/api/serializers_/record.py +90 -0
- netbox_dns/api/serializers_/registrar.py +31 -0
- netbox_dns/api/serializers_/view.py +34 -0
- netbox_dns/api/serializers_/zone.py +159 -0
- netbox_dns/api/views.py +13 -13
- netbox_dns/fields/network.py +21 -22
- netbox_dns/fields/rfc2317.py +3 -3
- netbox_dns/{filters → filtersets}/contact.py +2 -1
- netbox_dns/filtersets/nameserver.py +37 -0
- netbox_dns/{filters → filtersets}/record.py +51 -6
- netbox_dns/{filters → filtersets}/registrar.py +2 -1
- netbox_dns/{filters → filtersets}/view.py +2 -2
- netbox_dns/filtersets/zone.py +205 -0
- netbox_dns/forms/contact.py +61 -33
- netbox_dns/forms/nameserver.py +21 -8
- netbox_dns/forms/record.py +65 -38
- netbox_dns/forms/registrar.py +45 -15
- netbox_dns/forms/view.py +23 -9
- netbox_dns/forms/zone.py +182 -188
- netbox_dns/graphql/__init__.py +17 -27
- netbox_dns/graphql/filters.py +49 -0
- netbox_dns/graphql/schema.py +66 -7
- netbox_dns/graphql/types.py +143 -0
- netbox_dns/management/commands/cleanup_database.py +0 -4
- netbox_dns/management/commands/cleanup_rrset_ttl.py +2 -4
- netbox_dns/management/commands/setup_coupling.py +15 -15
- netbox_dns/management/commands/update_soa.py +1 -1
- netbox_dns/migrations/0001_squashed_netbox_dns_0_15.py +0 -27
- netbox_dns/migrations/0001_squashed_netbox_dns_0_22.py +558 -0
- netbox_dns/migrations/{0013_add_nameserver_zone_record_description.py → 0002_contact_description_registrar_description.py} +4 -9
- netbox_dns/migrations/0003_default_view.py +15 -0
- netbox_dns/migrations/0004_create_and_assign_default_view.py +26 -0
- netbox_dns/migrations/0005_alter_zone_view_not_null.py +18 -0
- netbox_dns/migrations/0020_netbox_3_4.py +1 -1
- netbox_dns/models/contact.py +6 -1
- netbox_dns/models/nameserver.py +2 -0
- netbox_dns/models/record.py +28 -33
- netbox_dns/models/registrar.py +5 -1
- netbox_dns/models/view.py +54 -1
- netbox_dns/models/zone.py +68 -54
- netbox_dns/navigation.py +1 -15
- netbox_dns/signals/ipam_coupling.py +3 -9
- netbox_dns/tables/contact.py +1 -0
- netbox_dns/tables/nameserver.py +0 -2
- netbox_dns/tables/registrar.py +1 -0
- netbox_dns/tables/view.py +9 -2
- netbox_dns/template_content.py +4 -8
- netbox_dns/templates/netbox_dns/contact.html +60 -56
- netbox_dns/templates/netbox_dns/nameserver.html +27 -27
- netbox_dns/templates/netbox_dns/record.html +92 -94
- netbox_dns/templates/netbox_dns/registrar.html +38 -36
- netbox_dns/templates/netbox_dns/view.html +25 -21
- netbox_dns/templates/netbox_dns/zone/base.html +5 -3
- netbox_dns/templates/netbox_dns/zone/child.html +3 -3
- netbox_dns/templates/netbox_dns/zone/managed_record.html +1 -1
- netbox_dns/templates/netbox_dns/zone/record.html +3 -3
- netbox_dns/templates/netbox_dns/zone/registration.html +26 -27
- netbox_dns/templates/netbox_dns/zone/rfc2317_child_zone.html +1 -1
- netbox_dns/templates/netbox_dns/zone.html +148 -149
- netbox_dns/urls/__init__.py +17 -0
- netbox_dns/urls/contact.py +51 -0
- netbox_dns/urls/nameserver.py +69 -0
- netbox_dns/urls/record.py +41 -0
- netbox_dns/urls/registrar.py +63 -0
- netbox_dns/urls/view.py +39 -0
- netbox_dns/urls/zone.py +57 -0
- netbox_dns/utilities/__init__.py +1 -6
- netbox_dns/utilities/ipam_coupling.py +2 -7
- netbox_dns/validators/dns_name.py +4 -9
- netbox_dns/validators/rfc2317.py +2 -2
- netbox_dns/views/contact.py +4 -4
- netbox_dns/views/nameserver.py +5 -5
- netbox_dns/views/record.py +15 -23
- netbox_dns/views/registrar.py +4 -4
- netbox_dns/views/view.py +4 -4
- netbox_dns/views/zone.py +7 -8
- {netbox_plugin_dns-0.22.9.dist-info → netbox_plugin_dns-1.0.0.dist-info}/METADATA +27 -13
- netbox_plugin_dns-1.0.0.dist-info/RECORD +112 -0
- netbox_dns/filters/nameserver.py +0 -18
- netbox_dns/filters/zone.py +0 -112
- netbox_dns/graphql/contact.py +0 -19
- netbox_dns/graphql/nameserver.py +0 -19
- netbox_dns/graphql/record.py +0 -19
- netbox_dns/graphql/registrar.py +0 -19
- netbox_dns/graphql/view.py +0 -19
- netbox_dns/graphql/zone.py +0 -19
- netbox_dns/migrations/0001_initial.py +0 -115
- netbox_dns/migrations/0002_zone_default_ttl.py +0 -18
- netbox_dns/migrations/0003_soa_managed_records.py +0 -112
- netbox_dns/migrations/0004_create_ptr_for_a_aaaa_records.py +0 -80
- netbox_dns/migrations/0005_update_ns_records.py +0 -41
- netbox_dns/migrations/0006_zone_soa_serial_auto.py +0 -29
- netbox_dns/migrations/0007_alter_zone_soa_serial_auto.py +0 -17
- netbox_dns/migrations/0008_zone_status_names.py +0 -21
- netbox_dns/migrations/0009_netbox32.py +0 -71
- netbox_dns/migrations/0010_update_soa_records.py +0 -58
- netbox_dns/migrations/0011_add_view_model.py +0 -70
- netbox_dns/migrations/0012_adjust_zone_and_record.py +0 -17
- netbox_dns/migrations/0014_add_view_description.py +0 -16
- netbox_dns/migrations/0015_add_record_status.py +0 -17
- netbox_dns/migrations/0016_cleanup_ptr_records.py +0 -38
- netbox_dns/migrations/0017_alter_record_ttl.py +0 -17
- netbox_dns/migrations/0018_zone_arpa_network.py +0 -51
- netbox_dns/migrations/0019_update_ns_ttl.py +0 -19
- netbox_dns/urls.py +0 -297
- netbox_plugin_dns-0.22.9.dist-info/RECORD +0 -117
- /netbox_dns/{filters → filtersets}/__init__.py +0 -0
- {netbox_plugin_dns-0.22.9.dist-info → netbox_plugin_dns-1.0.0.dist-info}/LICENSE +0 -0
- {netbox_plugin_dns-0.22.9.dist-info → netbox_plugin_dns-1.0.0.dist-info}/WHEEL +0 -0
netbox_dns/models/record.py
CHANGED
|
@@ -7,21 +7,14 @@ from dns import name as dns_name
|
|
|
7
7
|
from django.core.exceptions import ValidationError
|
|
8
8
|
from django.db import transaction, models
|
|
9
9
|
from django.db.models import Q, ExpressionWrapper, BooleanField, Min
|
|
10
|
-
from django.db.models.functions import Length
|
|
11
10
|
from django.urls import reverse
|
|
12
11
|
|
|
13
12
|
from netbox.models import NetBoxModel
|
|
14
13
|
from netbox.search import SearchIndex, register_search
|
|
14
|
+
from netbox.plugins.utils import get_plugin_config
|
|
15
15
|
from utilities.querysets import RestrictedQuerySet
|
|
16
16
|
from utilities.choices import ChoiceSet
|
|
17
17
|
|
|
18
|
-
try:
|
|
19
|
-
# NetBox 3.5.0 - 3.5.7, 3.5.9+
|
|
20
|
-
from extras.plugins import get_plugin_config
|
|
21
|
-
except ImportError:
|
|
22
|
-
# NetBox 3.5.8
|
|
23
|
-
from extras.plugins.utils import get_plugin_config
|
|
24
|
-
|
|
25
18
|
from netbox_dns.fields import AddressField
|
|
26
19
|
from netbox_dns.utilities import (
|
|
27
20
|
arpa_to_prefix,
|
|
@@ -43,7 +36,9 @@ def min_ttl(*ttl_list):
|
|
|
43
36
|
|
|
44
37
|
|
|
45
38
|
class RecordManager(models.Manager.from_queryset(RestrictedQuerySet)):
|
|
46
|
-
"""
|
|
39
|
+
"""
|
|
40
|
+
Custom manager for records providing the activity status annotation
|
|
41
|
+
"""
|
|
47
42
|
|
|
48
43
|
def get_queryset(self):
|
|
49
44
|
return (
|
|
@@ -218,7 +213,7 @@ class Record(NetBoxModel):
|
|
|
218
213
|
name = dns_name.from_text(self.fqdn).relativize(dns_name.root).to_unicode()
|
|
219
214
|
except dns_name.IDNAException:
|
|
220
215
|
name = self.name
|
|
221
|
-
except dns_name.LabelTooLong
|
|
216
|
+
except dns_name.LabelTooLong:
|
|
222
217
|
name = f"{self.name[:59]}..."
|
|
223
218
|
|
|
224
219
|
return f"{name} [{self.type}]"
|
|
@@ -231,15 +226,15 @@ class Record(NetBoxModel):
|
|
|
231
226
|
return RecordStatusChoices.colors.get(self.status)
|
|
232
227
|
|
|
233
228
|
def get_absolute_url(self):
|
|
234
|
-
return reverse("plugins:netbox_dns:record", kwargs={"pk": self.
|
|
229
|
+
return reverse("plugins:netbox_dns:record", kwargs={"pk": self.pk})
|
|
235
230
|
|
|
236
231
|
@property
|
|
237
232
|
def value_fqdn(self):
|
|
238
233
|
if self.type != RecordTypeChoices.CNAME:
|
|
239
234
|
return None
|
|
240
235
|
|
|
241
|
-
|
|
242
|
-
value_fqdn = dns_name.from_text(self.value, origin=
|
|
236
|
+
_zone = dns_name.from_text(self.zone.name)
|
|
237
|
+
value_fqdn = dns_name.from_text(self.value, origin=_zone)
|
|
243
238
|
|
|
244
239
|
return value_fqdn.to_text()
|
|
245
240
|
|
|
@@ -291,12 +286,14 @@ class Record(NetBoxModel):
|
|
|
291
286
|
dns_name.from_text(self.ptr_record.zone.rfc2317_parent_zone.name)
|
|
292
287
|
)
|
|
293
288
|
|
|
289
|
+
return None
|
|
290
|
+
|
|
294
291
|
@property
|
|
295
292
|
def ptr_zone(self):
|
|
296
293
|
if self.type == RecordTypeChoices.A:
|
|
297
294
|
ptr_zone = (
|
|
298
295
|
zone.Zone.objects.filter(
|
|
299
|
-
self.zone.
|
|
296
|
+
view=self.zone.view,
|
|
300
297
|
rfc2317_prefix__net_contains=self.value,
|
|
301
298
|
)
|
|
302
299
|
.order_by("rfc2317_prefix__net_mask_length")
|
|
@@ -308,7 +305,7 @@ class Record(NetBoxModel):
|
|
|
308
305
|
|
|
309
306
|
ptr_zone = (
|
|
310
307
|
zone.Zone.objects.filter(
|
|
311
|
-
self.zone.
|
|
308
|
+
view=self.zone.view, arpa_network__net_contains=self.value
|
|
312
309
|
)
|
|
313
310
|
.order_by("arpa_network__net_mask_length")
|
|
314
311
|
.last()
|
|
@@ -422,10 +419,8 @@ class Record(NetBoxModel):
|
|
|
422
419
|
self.rfc2317_cname_record.save(save_zone_serial=save_zone_serial)
|
|
423
420
|
|
|
424
421
|
return
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
save_zone_serial=save_zone_serial
|
|
428
|
-
)
|
|
422
|
+
|
|
423
|
+
self.remove_from_rfc2317_cname_record(save_zone_serial=save_zone_serial)
|
|
429
424
|
|
|
430
425
|
rfc2317_cname_record = Record.objects.filter(
|
|
431
426
|
name=cname_name,
|
|
@@ -466,14 +461,14 @@ class Record(NetBoxModel):
|
|
|
466
461
|
|
|
467
462
|
def validate_name(self):
|
|
468
463
|
try:
|
|
469
|
-
|
|
464
|
+
_zone = dns_name.from_text(self.zone.name, origin=dns_name.root)
|
|
470
465
|
name = dns_name.from_text(self.name, origin=None)
|
|
471
|
-
fqdn = dns_name.from_text(self.name, origin=
|
|
466
|
+
fqdn = dns_name.from_text(self.name, origin=_zone)
|
|
472
467
|
|
|
473
|
-
|
|
468
|
+
_zone.to_unicode()
|
|
474
469
|
name.to_unicode()
|
|
475
470
|
|
|
476
|
-
self.name = name.relativize(
|
|
471
|
+
self.name = name.relativize(_zone).to_text()
|
|
477
472
|
self.fqdn = fqdn.to_text()
|
|
478
473
|
|
|
479
474
|
except dns.exception.DNSException as exc:
|
|
@@ -483,7 +478,7 @@ class Record(NetBoxModel):
|
|
|
483
478
|
}
|
|
484
479
|
)
|
|
485
480
|
|
|
486
|
-
if not fqdn.is_subdomain(
|
|
481
|
+
if not fqdn.is_subdomain(_zone):
|
|
487
482
|
raise ValidationError(
|
|
488
483
|
{
|
|
489
484
|
"name": f"{self.name} is not a name in {self.zone.name}",
|
|
@@ -491,7 +486,7 @@ class Record(NetBoxModel):
|
|
|
491
486
|
)
|
|
492
487
|
|
|
493
488
|
if self.type not in get_plugin_config(
|
|
494
|
-
"netbox_dns", "tolerate_non_rfc1035_types", default=
|
|
489
|
+
"netbox_dns", "tolerate_non_rfc1035_types", default=[]
|
|
495
490
|
):
|
|
496
491
|
try:
|
|
497
492
|
validate_extended_hostname(
|
|
@@ -501,7 +496,7 @@ class Record(NetBoxModel):
|
|
|
501
496
|
in get_plugin_config(
|
|
502
497
|
"netbox_dns",
|
|
503
498
|
"tolerate_leading_underscore_types",
|
|
504
|
-
default=
|
|
499
|
+
default=[],
|
|
505
500
|
)
|
|
506
501
|
),
|
|
507
502
|
)
|
|
@@ -669,7 +664,7 @@ class Record(NetBoxModel):
|
|
|
669
664
|
if self.type == RecordTypeChoices.SOA and self.name != "@":
|
|
670
665
|
raise ValidationError(
|
|
671
666
|
{
|
|
672
|
-
"name":
|
|
667
|
+
"name": "SOA records are only allowed with name @ and are created automatically by NetBox DNS"
|
|
673
668
|
}
|
|
674
669
|
) from None
|
|
675
670
|
|
|
@@ -738,9 +733,9 @@ class Record(NetBoxModel):
|
|
|
738
733
|
|
|
739
734
|
super().save(*args, **kwargs)
|
|
740
735
|
|
|
741
|
-
|
|
742
|
-
if self.type != RecordTypeChoices.SOA and
|
|
743
|
-
|
|
736
|
+
_zone = self.zone
|
|
737
|
+
if self.type != RecordTypeChoices.SOA and _zone.soa_serial_auto:
|
|
738
|
+
_zone.update_serial(save_zone_serial=save_zone_serial)
|
|
744
739
|
|
|
745
740
|
def delete(self, *args, save_zone_serial=True, **kwargs):
|
|
746
741
|
if self.rfc2317_cname_record:
|
|
@@ -751,9 +746,9 @@ class Record(NetBoxModel):
|
|
|
751
746
|
|
|
752
747
|
super().delete(*args, **kwargs)
|
|
753
748
|
|
|
754
|
-
|
|
755
|
-
if
|
|
756
|
-
|
|
749
|
+
_zone = self.zone
|
|
750
|
+
if _zone.soa_serial_auto:
|
|
751
|
+
_zone.update_serial(save_zone_serial=save_zone_serial)
|
|
757
752
|
|
|
758
753
|
|
|
759
754
|
@register_search
|
netbox_dns/models/registrar.py
CHANGED
|
@@ -13,6 +13,10 @@ class Registrar(NetBoxModel):
|
|
|
13
13
|
unique=True,
|
|
14
14
|
max_length=255,
|
|
15
15
|
)
|
|
16
|
+
description = models.CharField(
|
|
17
|
+
blank=True,
|
|
18
|
+
max_length=200,
|
|
19
|
+
)
|
|
16
20
|
iana_id = models.IntegerField(
|
|
17
21
|
verbose_name="IANA ID",
|
|
18
22
|
null=True,
|
|
@@ -43,7 +47,7 @@ class Registrar(NetBoxModel):
|
|
|
43
47
|
)
|
|
44
48
|
|
|
45
49
|
def get_absolute_url(self):
|
|
46
|
-
return reverse("plugins:netbox_dns:registrar", kwargs={"pk": self.
|
|
50
|
+
return reverse("plugins:netbox_dns:registrar", kwargs={"pk": self.pk})
|
|
47
51
|
|
|
48
52
|
def __str__(self):
|
|
49
53
|
return str(self.name)
|
netbox_dns/models/view.py
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
from django.db import models
|
|
2
2
|
from django.urls import reverse
|
|
3
|
+
from django.core.exceptions import ValidationError
|
|
3
4
|
|
|
4
5
|
from netbox.models import NetBoxModel
|
|
5
6
|
from netbox.search import SearchIndex, register_search
|
|
7
|
+
from netbox.context import current_request
|
|
8
|
+
from utilities.exceptions import AbortRequest
|
|
6
9
|
|
|
7
10
|
|
|
8
11
|
class View(NetBoxModel):
|
|
@@ -14,6 +17,9 @@ class View(NetBoxModel):
|
|
|
14
17
|
max_length=200,
|
|
15
18
|
blank=True,
|
|
16
19
|
)
|
|
20
|
+
default_view = models.BooleanField(
|
|
21
|
+
default=False,
|
|
22
|
+
)
|
|
17
23
|
tenant = models.ForeignKey(
|
|
18
24
|
to="tenancy.Tenant",
|
|
19
25
|
on_delete=models.PROTECT,
|
|
@@ -24,8 +30,12 @@ class View(NetBoxModel):
|
|
|
24
30
|
|
|
25
31
|
clone_fields = ["name", "description"]
|
|
26
32
|
|
|
33
|
+
@classmethod
|
|
34
|
+
def get_default_view(cls):
|
|
35
|
+
return cls.objects.get(default_view=True)
|
|
36
|
+
|
|
27
37
|
def get_absolute_url(self):
|
|
28
|
-
return reverse("plugins:netbox_dns:view", kwargs={"pk": self.
|
|
38
|
+
return reverse("plugins:netbox_dns:view", kwargs={"pk": self.pk})
|
|
29
39
|
|
|
30
40
|
def __str__(self):
|
|
31
41
|
return str(self.name)
|
|
@@ -33,6 +43,49 @@ class View(NetBoxModel):
|
|
|
33
43
|
class Meta:
|
|
34
44
|
ordering = ("name",)
|
|
35
45
|
|
|
46
|
+
def delete(self, *args, **kwargs):
|
|
47
|
+
if self.default_view:
|
|
48
|
+
if current_request.get() is not None:
|
|
49
|
+
raise AbortRequest("The default view cannot be deleted")
|
|
50
|
+
|
|
51
|
+
raise ValidationError("The default view cannot be deleted")
|
|
52
|
+
|
|
53
|
+
super().delete(*args, **kwargs)
|
|
54
|
+
|
|
55
|
+
def clean(self, *args, old_state=None, **kwargs):
|
|
56
|
+
if self.pk is None:
|
|
57
|
+
return
|
|
58
|
+
|
|
59
|
+
old_state = View.objects.get(pk=self.pk)
|
|
60
|
+
|
|
61
|
+
if (
|
|
62
|
+
old_state.default_view
|
|
63
|
+
and not self.default_view
|
|
64
|
+
and not View.objects.filter(default_view=True).exclude(pk=self.pk).exists()
|
|
65
|
+
):
|
|
66
|
+
raise ValidationError(
|
|
67
|
+
{
|
|
68
|
+
"default_view": "Please select a different view as default view to change this setting!"
|
|
69
|
+
}
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
super().clean(*args, **kwargs)
|
|
73
|
+
|
|
74
|
+
def save(self, *args, **kwargs):
|
|
75
|
+
self.clean()
|
|
76
|
+
|
|
77
|
+
old_state = None if self.pk is None else View.objects.get(pk=self.pk)
|
|
78
|
+
|
|
79
|
+
super().save(*args, **kwargs)
|
|
80
|
+
|
|
81
|
+
if (old_state is None and self.default_view) or (
|
|
82
|
+
old_state is not None and self.default_view and not old_state.default_view
|
|
83
|
+
):
|
|
84
|
+
other_views = View.objects.filter(default_view=True).exclude(pk=self.pk)
|
|
85
|
+
for view in other_views:
|
|
86
|
+
view.default_view = False
|
|
87
|
+
view.save()
|
|
88
|
+
|
|
36
89
|
|
|
37
90
|
@register_search
|
|
38
91
|
class ViewIndex(SearchIndex):
|
netbox_dns/models/zone.py
CHANGED
|
@@ -15,20 +15,15 @@ from django.db.models import Q, Max, ExpressionWrapper, BooleanField
|
|
|
15
15
|
from django.urls import reverse
|
|
16
16
|
from django.db.models.signals import m2m_changed
|
|
17
17
|
from django.dispatch import receiver
|
|
18
|
+
from django.conf import settings
|
|
18
19
|
|
|
19
20
|
from netbox.models import NetBoxModel
|
|
20
21
|
from netbox.search import SearchIndex, register_search
|
|
22
|
+
from netbox.plugins.utils import get_plugin_config
|
|
21
23
|
from utilities.querysets import RestrictedQuerySet
|
|
22
24
|
from utilities.choices import ChoiceSet
|
|
23
25
|
from ipam.models import IPAddress
|
|
24
26
|
|
|
25
|
-
try:
|
|
26
|
-
# NetBox 3.5.0 - 3.5.7, 3.5.9+
|
|
27
|
-
from extras.plugins import get_plugin_config
|
|
28
|
-
except ImportError:
|
|
29
|
-
# NetBox 3.5.8
|
|
30
|
-
from extras.plugins.utils import get_plugin_config
|
|
31
|
-
|
|
32
27
|
from netbox_dns.fields import NetworkField, RFC2317NetworkField
|
|
33
28
|
from netbox_dns.utilities import (
|
|
34
29
|
arpa_to_prefix,
|
|
@@ -42,13 +37,17 @@ from netbox_dns.validators import (
|
|
|
42
37
|
)
|
|
43
38
|
|
|
44
39
|
# +
|
|
45
|
-
# This is a hack designed to break cyclic imports between Record and Zone
|
|
40
|
+
# This is a hack designed to break cyclic imports between View, Record and Zone
|
|
46
41
|
# -
|
|
47
42
|
import netbox_dns.models.record as record
|
|
43
|
+
import netbox_dns.models.view as view
|
|
44
|
+
import netbox_dns.models.nameserver as nameserver
|
|
48
45
|
|
|
49
46
|
|
|
50
47
|
class ZoneManager(models.Manager.from_queryset(RestrictedQuerySet)):
|
|
51
|
-
"""
|
|
48
|
+
"""
|
|
49
|
+
Custom manager for zones providing the activity status annotation
|
|
50
|
+
"""
|
|
52
51
|
|
|
53
52
|
def get_queryset(self):
|
|
54
53
|
return (
|
|
@@ -84,8 +83,7 @@ class Zone(NetBoxModel):
|
|
|
84
83
|
view = models.ForeignKey(
|
|
85
84
|
to="View",
|
|
86
85
|
on_delete=models.PROTECT,
|
|
87
|
-
|
|
88
|
-
null=True,
|
|
86
|
+
null=False,
|
|
89
87
|
)
|
|
90
88
|
name = models.CharField(
|
|
91
89
|
max_length=255,
|
|
@@ -288,11 +286,20 @@ class Zone(NetBoxModel):
|
|
|
288
286
|
except dns_name.IDNAException:
|
|
289
287
|
name = self.name
|
|
290
288
|
|
|
291
|
-
if self.view:
|
|
289
|
+
if not self.view.default_view:
|
|
292
290
|
return f"[{self.view}] {name}"
|
|
293
291
|
|
|
294
292
|
return str(name)
|
|
295
293
|
|
|
294
|
+
@staticmethod
|
|
295
|
+
def get_defaults():
|
|
296
|
+
return {
|
|
297
|
+
field[5:]: value
|
|
298
|
+
for field, value in settings.PLUGINS_CONFIG.get("netbox_dns").items()
|
|
299
|
+
if field.startswith("zone_")
|
|
300
|
+
and field not in ("zone_soa_mname", "zone_nameservers")
|
|
301
|
+
}
|
|
302
|
+
|
|
296
303
|
@property
|
|
297
304
|
def display_name(self):
|
|
298
305
|
return name_to_unicode(self.name)
|
|
@@ -320,11 +327,11 @@ class Zone(NetBoxModel):
|
|
|
320
327
|
|
|
321
328
|
def get_rfc2317_parent_zone(self):
|
|
322
329
|
if not self.is_rfc2317_zone:
|
|
323
|
-
return
|
|
330
|
+
return None
|
|
324
331
|
|
|
325
332
|
return (
|
|
326
333
|
Zone.objects.filter(
|
|
327
|
-
self.
|
|
334
|
+
view=self.view,
|
|
328
335
|
arpa_network__net_contains=self.rfc2317_prefix,
|
|
329
336
|
)
|
|
330
337
|
.order_by("arpa_network__net_mask_length")
|
|
@@ -345,12 +352,6 @@ class Zone(NetBoxModel):
|
|
|
345
352
|
)
|
|
346
353
|
)
|
|
347
354
|
|
|
348
|
-
@property
|
|
349
|
-
def view_filter(self):
|
|
350
|
-
if self.view is None:
|
|
351
|
-
return Q(view__isnull=True)
|
|
352
|
-
return Q(view=self.view)
|
|
353
|
-
|
|
354
355
|
def record_count(self, managed=False):
|
|
355
356
|
return record.Record.objects.filter(zone=self, managed=managed).count()
|
|
356
357
|
|
|
@@ -420,19 +421,15 @@ class Zone(NetBoxModel):
|
|
|
420
421
|
if not nameservers:
|
|
421
422
|
ns_errors.append(f"No nameservers are configured for zone {self}")
|
|
422
423
|
|
|
423
|
-
for
|
|
424
|
-
name = dns_name.from_text(
|
|
424
|
+
for _nameserver in nameservers:
|
|
425
|
+
name = dns_name.from_text(_nameserver.name, origin=None)
|
|
425
426
|
parent = name.parent()
|
|
426
427
|
|
|
427
428
|
if len(parent) < 2:
|
|
428
429
|
continue
|
|
429
430
|
|
|
430
|
-
view_condition = (
|
|
431
|
-
Q(view__isnull=True) if self.view is None else Q(view_id=self.view.pk)
|
|
432
|
-
)
|
|
433
|
-
|
|
434
431
|
try:
|
|
435
|
-
ns_zone = Zone.objects.get(
|
|
432
|
+
ns_zone = Zone.objects.get(view_id=self.view.pk, name=parent.to_text())
|
|
436
433
|
except ObjectDoesNotExist:
|
|
437
434
|
continue
|
|
438
435
|
|
|
@@ -440,7 +437,7 @@ class Zone(NetBoxModel):
|
|
|
440
437
|
address_records = record.Record.objects.filter(
|
|
441
438
|
Q(zone=ns_zone),
|
|
442
439
|
Q(status__in=record.Record.ACTIVE_STATUS_LIST),
|
|
443
|
-
Q(Q(name=f"{
|
|
440
|
+
Q(Q(name=f"{_nameserver.name}.") | Q(name=relative_name)),
|
|
444
441
|
Q(
|
|
445
442
|
Q(type=record.RecordTypeChoices.A)
|
|
446
443
|
| Q(type=record.RecordTypeChoices.AAAA)
|
|
@@ -449,13 +446,13 @@ class Zone(NetBoxModel):
|
|
|
449
446
|
|
|
450
447
|
if not address_records:
|
|
451
448
|
ns_warnings.append(
|
|
452
|
-
f"Nameserver {
|
|
449
|
+
f"Nameserver {_nameserver.name} does not have an active address record in zone {ns_zone}"
|
|
453
450
|
)
|
|
454
451
|
|
|
455
452
|
return ns_warnings, ns_errors
|
|
456
453
|
|
|
457
454
|
def get_auto_serial(self):
|
|
458
|
-
records = record.Record.objects.filter(
|
|
455
|
+
records = record.Record.objects.filter(zone_id=self.pk).exclude(
|
|
459
456
|
type=record.RecordTypeChoices.SOA
|
|
460
457
|
)
|
|
461
458
|
if records:
|
|
@@ -495,19 +492,6 @@ class Zone(NetBoxModel):
|
|
|
495
492
|
def network_from_name(self):
|
|
496
493
|
return arpa_to_prefix(self.name)
|
|
497
494
|
|
|
498
|
-
def check_name_conflict(self):
|
|
499
|
-
if self.view is None:
|
|
500
|
-
if (
|
|
501
|
-
Zone.objects.exclude(pk=self.pk)
|
|
502
|
-
.filter(name=self.name.rstrip("."), view__isnull=True)
|
|
503
|
-
.exists()
|
|
504
|
-
):
|
|
505
|
-
raise ValidationError(
|
|
506
|
-
{
|
|
507
|
-
"name": f"A zone with name {self.name} and no view already exists."
|
|
508
|
-
}
|
|
509
|
-
)
|
|
510
|
-
|
|
511
495
|
def update_rfc2317_parent_zone(self):
|
|
512
496
|
if not self.is_rfc2317_zone:
|
|
513
497
|
return
|
|
@@ -558,8 +542,33 @@ class Zone(NetBoxModel):
|
|
|
558
542
|
ptr_zone.save_soa_serial()
|
|
559
543
|
ptr_zone.update_soa_record()
|
|
560
544
|
|
|
545
|
+
def clean_fields(self, exclude=None):
|
|
546
|
+
defaults = settings.PLUGINS_CONFIG.get("netbox_dns")
|
|
547
|
+
|
|
548
|
+
if self.view_id is None:
|
|
549
|
+
self.view_id = view.View.get_default_view().pk
|
|
550
|
+
|
|
551
|
+
for field, value in self.get_defaults().items():
|
|
552
|
+
if getattr(self, field) in (None, ""):
|
|
553
|
+
if value not in (None, ""):
|
|
554
|
+
setattr(self, field, value)
|
|
555
|
+
|
|
556
|
+
if self.soa_mname_id is None:
|
|
557
|
+
default_soa_mname = defaults.get("zone_soa_mname")
|
|
558
|
+
try:
|
|
559
|
+
self.soa_mname = nameserver.NameServer.objects.get(
|
|
560
|
+
name=default_soa_mname
|
|
561
|
+
)
|
|
562
|
+
except nameserver.NameServer.DoesNotExist:
|
|
563
|
+
raise ValidationError(
|
|
564
|
+
f"Default soa_mname instance {default_soa_mname} does not exist"
|
|
565
|
+
)
|
|
566
|
+
|
|
567
|
+
super().clean_fields(exclude=exclude)
|
|
568
|
+
|
|
561
569
|
def clean(self, *args, **kwargs):
|
|
562
|
-
self.
|
|
570
|
+
if self.soa_ttl is None:
|
|
571
|
+
self.soa_ttl = self.default_ttl
|
|
563
572
|
|
|
564
573
|
try:
|
|
565
574
|
self.name = normalize_name(self.name)
|
|
@@ -579,6 +588,8 @@ class Zone(NetBoxModel):
|
|
|
579
588
|
}
|
|
580
589
|
) from None
|
|
581
590
|
|
|
591
|
+
if self.soa_rname in (None, ""):
|
|
592
|
+
raise ValidationError("soa_rname not set and no default value defined")
|
|
582
593
|
try:
|
|
583
594
|
dns_name.from_text(self.soa_rname, origin=dns_name.root)
|
|
584
595
|
validate_fqdn(self.soa_rname)
|
|
@@ -589,12 +600,13 @@ class Zone(NetBoxModel):
|
|
|
589
600
|
}
|
|
590
601
|
) from None
|
|
591
602
|
|
|
592
|
-
if
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
603
|
+
if not self.soa_serial_auto:
|
|
604
|
+
if self.soa_serial is None:
|
|
605
|
+
raise ValidationError(
|
|
606
|
+
{
|
|
607
|
+
"soa_serial": f"soa_serial is not defined and soa_serial_auto is disabled for zone {self.name}."
|
|
608
|
+
}
|
|
609
|
+
)
|
|
598
610
|
|
|
599
611
|
if self.is_reverse_zone:
|
|
600
612
|
self.arpa_network = self.network_from_name
|
|
@@ -603,7 +615,7 @@ class Zone(NetBoxModel):
|
|
|
603
615
|
if self.arpa_network is not None:
|
|
604
616
|
raise ValidationError(
|
|
605
617
|
{
|
|
606
|
-
"rfc2317_prefix":
|
|
618
|
+
"rfc2317_prefix": "A regular reverse zone can not be used as an RFC2317 zone."
|
|
607
619
|
}
|
|
608
620
|
)
|
|
609
621
|
|
|
@@ -622,7 +634,7 @@ class Zone(NetBoxModel):
|
|
|
622
634
|
self.rfc2317_parent_zone = None
|
|
623
635
|
|
|
624
636
|
overlapping_zones = Zone.objects.filter(
|
|
625
|
-
self.
|
|
637
|
+
view=self.view,
|
|
626
638
|
rfc2317_prefix__net_overlap=self.rfc2317_prefix,
|
|
627
639
|
active=True,
|
|
628
640
|
).exclude(pk=self.pk)
|
|
@@ -638,6 +650,8 @@ class Zone(NetBoxModel):
|
|
|
638
650
|
self.rfc2317_parent_managed = False
|
|
639
651
|
self.rfc2317_parent_zone = None
|
|
640
652
|
|
|
653
|
+
super().clean(*args, **kwargs)
|
|
654
|
+
|
|
641
655
|
def save(self, *args, **kwargs):
|
|
642
656
|
self.full_clean()
|
|
643
657
|
|
|
@@ -662,7 +676,7 @@ class Zone(NetBoxModel):
|
|
|
662
676
|
new_zone or name_changed or view_changed or status_changed
|
|
663
677
|
) and self.is_reverse_zone:
|
|
664
678
|
zones = Zone.objects.filter(
|
|
665
|
-
self.
|
|
679
|
+
view=self.view,
|
|
666
680
|
arpa_network__net_contains_or_equals=self.arpa_network,
|
|
667
681
|
)
|
|
668
682
|
address_records = record.Record.objects.filter(
|
|
@@ -698,7 +712,7 @@ class Zone(NetBoxModel):
|
|
|
698
712
|
or rfc2317_changed
|
|
699
713
|
) and self.is_rfc2317_zone:
|
|
700
714
|
zones = Zone.objects.filter(
|
|
701
|
-
self.
|
|
715
|
+
view=self.view,
|
|
702
716
|
arpa_network__net_contains=self.rfc2317_prefix,
|
|
703
717
|
)
|
|
704
718
|
address_records = record.Record.objects.filter(
|
netbox_dns/navigation.py
CHANGED
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
from
|
|
2
|
-
from extras.plugins import PluginMenu
|
|
3
|
-
from utilities.choices import ButtonColorChoices
|
|
1
|
+
from netbox.plugins import PluginMenuButton, PluginMenuItem, PluginMenu
|
|
4
2
|
|
|
5
3
|
view_menu_item = PluginMenuItem(
|
|
6
4
|
link="plugins:netbox_dns:view_list",
|
|
@@ -11,14 +9,12 @@ view_menu_item = PluginMenuItem(
|
|
|
11
9
|
"plugins:netbox_dns:view_add",
|
|
12
10
|
"Add",
|
|
13
11
|
"mdi mdi-plus-thick",
|
|
14
|
-
ButtonColorChoices.GREEN,
|
|
15
12
|
permissions=["netbox_dns.add_view"],
|
|
16
13
|
),
|
|
17
14
|
PluginMenuButton(
|
|
18
15
|
"plugins:netbox_dns:view_import",
|
|
19
16
|
"Import",
|
|
20
17
|
"mdi mdi-upload",
|
|
21
|
-
ButtonColorChoices.CYAN,
|
|
22
18
|
permissions=["netbox_dns.add_view"],
|
|
23
19
|
),
|
|
24
20
|
),
|
|
@@ -33,14 +29,12 @@ zone_menu_item = PluginMenuItem(
|
|
|
33
29
|
"plugins:netbox_dns:zone_add",
|
|
34
30
|
"Add",
|
|
35
31
|
"mdi mdi-plus-thick",
|
|
36
|
-
ButtonColorChoices.GREEN,
|
|
37
32
|
permissions=["netbox_dns.add_zone"],
|
|
38
33
|
),
|
|
39
34
|
PluginMenuButton(
|
|
40
35
|
"plugins:netbox_dns:zone_import",
|
|
41
36
|
"Import",
|
|
42
37
|
"mdi mdi-upload",
|
|
43
|
-
ButtonColorChoices.CYAN,
|
|
44
38
|
permissions=["netbox_dns.add_zone"],
|
|
45
39
|
),
|
|
46
40
|
),
|
|
@@ -55,14 +49,12 @@ nameserver_menu_item = PluginMenuItem(
|
|
|
55
49
|
"plugins:netbox_dns:nameserver_add",
|
|
56
50
|
"Add",
|
|
57
51
|
"mdi mdi-plus-thick",
|
|
58
|
-
ButtonColorChoices.GREEN,
|
|
59
52
|
permissions=["netbox_dns.add_nameserver"],
|
|
60
53
|
),
|
|
61
54
|
PluginMenuButton(
|
|
62
55
|
"plugins:netbox_dns:nameserver_import",
|
|
63
56
|
"Import",
|
|
64
57
|
"mdi mdi-upload",
|
|
65
|
-
ButtonColorChoices.CYAN,
|
|
66
58
|
permissions=["netbox_dns.add_nameserver"],
|
|
67
59
|
),
|
|
68
60
|
),
|
|
@@ -77,14 +69,12 @@ record_menu_item = PluginMenuItem(
|
|
|
77
69
|
"plugins:netbox_dns:record_add",
|
|
78
70
|
"Add",
|
|
79
71
|
"mdi mdi-plus-thick",
|
|
80
|
-
ButtonColorChoices.GREEN,
|
|
81
72
|
permissions=["netbox_dns.add_record"],
|
|
82
73
|
),
|
|
83
74
|
PluginMenuButton(
|
|
84
75
|
"plugins:netbox_dns:record_import",
|
|
85
76
|
"Import",
|
|
86
77
|
"mdi mdi-upload",
|
|
87
|
-
ButtonColorChoices.CYAN,
|
|
88
78
|
permissions=["netbox_dns.add_record"],
|
|
89
79
|
),
|
|
90
80
|
),
|
|
@@ -105,14 +95,12 @@ registrar_menu_item = PluginMenuItem(
|
|
|
105
95
|
"plugins:netbox_dns:registrar_add",
|
|
106
96
|
"Add",
|
|
107
97
|
"mdi mdi-plus-thick",
|
|
108
|
-
ButtonColorChoices.GREEN,
|
|
109
98
|
permissions=["netbox_dns.add_registrar"],
|
|
110
99
|
),
|
|
111
100
|
PluginMenuButton(
|
|
112
101
|
"plugins:netbox_dns:registrar_import",
|
|
113
102
|
"Import",
|
|
114
103
|
"mdi mdi-upload",
|
|
115
|
-
ButtonColorChoices.CYAN,
|
|
116
104
|
permissions=["netbox_dns.add_registrar"],
|
|
117
105
|
),
|
|
118
106
|
),
|
|
@@ -127,14 +115,12 @@ contact_menu_item = PluginMenuItem(
|
|
|
127
115
|
"plugins:netbox_dns:contact_add",
|
|
128
116
|
"Add",
|
|
129
117
|
"mdi mdi-plus-thick",
|
|
130
|
-
ButtonColorChoices.GREEN,
|
|
131
118
|
permissions=["netbox_dns.add_contact"],
|
|
132
119
|
),
|
|
133
120
|
PluginMenuButton(
|
|
134
121
|
"plugins:netbox_dns:contact_import",
|
|
135
122
|
"Import",
|
|
136
123
|
"mdi mdi-upload",
|
|
137
|
-
ButtonColorChoices.CYAN,
|
|
138
124
|
permissions=["netbox_dns.add_contact"],
|
|
139
125
|
),
|
|
140
126
|
),
|
|
@@ -5,6 +5,7 @@ from rest_framework.exceptions import PermissionDenied as APIPermissionDenied
|
|
|
5
5
|
|
|
6
6
|
from netbox.signals import post_clean
|
|
7
7
|
from netbox.context import current_request
|
|
8
|
+
from netbox.plugins.utils import get_plugin_config
|
|
8
9
|
from ipam.models import IPAddress
|
|
9
10
|
|
|
10
11
|
from netbox_dns.models import Zone
|
|
@@ -18,13 +19,6 @@ from netbox_dns.utilities.ipam_coupling import (
|
|
|
18
19
|
DNSPermissionDenied,
|
|
19
20
|
)
|
|
20
21
|
|
|
21
|
-
try:
|
|
22
|
-
# NetBox 3.5.0 - 3.5.7, 3.5.9+
|
|
23
|
-
from extras.plugins import get_plugin_config
|
|
24
|
-
except ImportError:
|
|
25
|
-
# NetBox 3.5.8
|
|
26
|
-
from extras.plugins.utils import get_plugin_config
|
|
27
|
-
|
|
28
22
|
|
|
29
23
|
@receiver(post_clean, sender=IPAddress)
|
|
30
24
|
def ip_address_check_permissions_save(instance, **kwargs):
|
|
@@ -39,14 +33,14 @@ def ip_address_check_permissions_save(instance, **kwargs):
|
|
|
39
33
|
return
|
|
40
34
|
|
|
41
35
|
try:
|
|
42
|
-
if instance.
|
|
36
|
+
if instance.pk is None:
|
|
43
37
|
record = new_address_record(instance)
|
|
44
38
|
if record is not None:
|
|
45
39
|
record.full_clean()
|
|
46
40
|
check_permission(request, "netbox_dns.add_record", record)
|
|
47
41
|
|
|
48
42
|
else:
|
|
49
|
-
if not dns_changed(IPAddress.objects.get(pk=instance.
|
|
43
|
+
if not dns_changed(IPAddress.objects.get(pk=instance.pk), instance):
|
|
50
44
|
return
|
|
51
45
|
|
|
52
46
|
record = get_address_record(instance)
|