netbox-plugin-dns 1.1.0b7__py3-none-any.whl → 1.1.2__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 +3 -2
- netbox_dns/api/nested_serializers.py +17 -16
- netbox_dns/api/serializers.py +1 -1
- netbox_dns/api/serializers_/record.py +1 -0
- netbox_dns/api/serializers_/{contact.py → registration_contact.py} +5 -5
- netbox_dns/api/serializers_/view.py +1 -0
- netbox_dns/api/serializers_/zone.py +5 -5
- netbox_dns/api/serializers_/zone_template.py +5 -5
- netbox_dns/api/urls.py +2 -2
- netbox_dns/api/views.py +7 -35
- netbox_dns/filtersets/__init__.py +1 -1
- netbox_dns/filtersets/nameserver.py +0 -0
- netbox_dns/filtersets/record.py +0 -0
- netbox_dns/filtersets/record_template.py +0 -0
- netbox_dns/filtersets/{contact.py → registration_contact.py} +4 -4
- netbox_dns/filtersets/zone.py +15 -15
- netbox_dns/filtersets/zone_template.py +15 -15
- netbox_dns/forms/__init__.py +1 -1
- netbox_dns/forms/nameserver.py +0 -0
- netbox_dns/forms/record.py +0 -0
- netbox_dns/forms/record_template.py +0 -0
- netbox_dns/forms/{contact.py → registration_contact.py} +16 -16
- netbox_dns/forms/view.py +29 -10
- netbox_dns/forms/zone.py +13 -13
- netbox_dns/forms/zone_template.py +13 -13
- netbox_dns/graphql/__init__.py +2 -2
- netbox_dns/graphql/filters.py +5 -5
- netbox_dns/graphql/schema.py +23 -53
- netbox_dns/graphql/types.py +39 -12
- netbox_dns/migrations/0007_alter_ordering_options.py +25 -0
- netbox_dns/migrations/{0007_view_prefixes.py → 0008_view_prefixes.py} +1 -1
- netbox_dns/migrations/0009_rename_contact_registrationcontact.py +36 -0
- netbox_dns/migrations/0010_view_ip_address_filter.py +18 -0
- netbox_dns/mixins/object_modification.py +30 -8
- netbox_dns/models/__init__.py +1 -1
- netbox_dns/models/nameserver.py +8 -3
- netbox_dns/models/record.py +47 -14
- netbox_dns/models/record_template.py +4 -1
- netbox_dns/models/registrar.py +7 -1
- netbox_dns/models/{contact.py → registration_contact.py} +15 -9
- netbox_dns/models/view.py +49 -2
- netbox_dns/models/zone.py +24 -18
- netbox_dns/models/zone_template.py +12 -9
- netbox_dns/navigation.py +7 -7
- netbox_dns/signals/ipam_dnssync.py +4 -4
- netbox_dns/tables/__init__.py +1 -1
- netbox_dns/tables/nameserver.py +1 -7
- netbox_dns/tables/record.py +10 -35
- netbox_dns/tables/record_template.py +0 -17
- netbox_dns/tables/registrar.py +0 -2
- netbox_dns/tables/{contact.py → registration_contact.py} +5 -6
- netbox_dns/tables/view.py +1 -8
- netbox_dns/tables/zone.py +0 -15
- netbox_dns/tables/zone_template.py +2 -16
- netbox_dns/templates/netbox_dns/{contact.html → registrationcontact.html} +1 -1
- netbox_dns/templates/netbox_dns/view.html +16 -0
- netbox_dns/urls/__init__.py +2 -2
- netbox_dns/urls/nameserver.py +14 -38
- netbox_dns/urls/record.py +7 -19
- netbox_dns/urls/record_template.py +18 -27
- netbox_dns/urls/registrar.py +11 -35
- netbox_dns/urls/registration_contact.py +60 -0
- netbox_dns/urls/view.py +8 -22
- netbox_dns/urls/zone.py +8 -46
- netbox_dns/urls/zone_template.py +16 -26
- netbox_dns/utilities/ipam_dnssync.py +58 -26
- netbox_dns/views/__init__.py +1 -1
- netbox_dns/views/nameserver.py +7 -3
- netbox_dns/views/record.py +12 -3
- netbox_dns/views/record_template.py +1 -1
- netbox_dns/views/registrar.py +0 -1
- netbox_dns/views/registration_contact.py +94 -0
- netbox_dns/views/view.py +6 -1
- netbox_dns/views/zone.py +7 -6
- netbox_dns/views/zone_template.py +2 -2
- {netbox_plugin_dns-1.1.0b7.dist-info → netbox_plugin_dns-1.1.2.dist-info}/METADATA +14 -14
- {netbox_plugin_dns-1.1.0b7.dist-info → netbox_plugin_dns-1.1.2.dist-info}/RECORD +80 -76
- {netbox_plugin_dns-1.1.0b7.dist-info → netbox_plugin_dns-1.1.2.dist-info}/WHEEL +2 -1
- netbox_plugin_dns-1.1.2.dist-info/top_level.txt +1 -0
- netbox_dns/urls/contact.py +0 -51
- netbox_dns/views/contact.py +0 -95
- {netbox_plugin_dns-1.1.0b7.dist-info → netbox_plugin_dns-1.1.2.dist-info}/LICENSE +0 -0
|
@@ -17,15 +17,37 @@ class ObjectModificationMixin:
|
|
|
17
17
|
|
|
18
18
|
self.__class__.check_fields.add("custom_field_data")
|
|
19
19
|
|
|
20
|
+
self._save_field_values()
|
|
21
|
+
|
|
22
|
+
def _save_field_values(self):
|
|
23
|
+
for field in self.check_fields:
|
|
24
|
+
if f"{field}_id" in self.__dict__:
|
|
25
|
+
setattr(self, f"_saved_{field}_id", self.__dict__.get(f"{field}_id"))
|
|
26
|
+
else:
|
|
27
|
+
setattr(self, f"_saved_{field}", self.__dict__.get(field))
|
|
28
|
+
|
|
29
|
+
def save(self, *args, **kwargs):
|
|
30
|
+
super().save(*args, **kwargs)
|
|
31
|
+
|
|
32
|
+
self._save_field_values()
|
|
33
|
+
|
|
20
34
|
@property
|
|
21
35
|
def changed_fields(self):
|
|
22
|
-
if self.
|
|
36
|
+
if self._state.adding:
|
|
23
37
|
return None
|
|
24
38
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
39
|
+
_changed_fields = set()
|
|
40
|
+
for field in self.check_fields:
|
|
41
|
+
if f"_saved_{field}_id" in self.__dict__:
|
|
42
|
+
if self.__dict__.get(f"_saved_{field}_id") != self.__dict__.get(
|
|
43
|
+
f"{field}_id"
|
|
44
|
+
):
|
|
45
|
+
_changed_fields.add(field)
|
|
46
|
+
else:
|
|
47
|
+
if self.__dict__.get(f"_saved_{field}") != self.__dict__.get(field):
|
|
48
|
+
_changed_fields.add(field)
|
|
49
|
+
|
|
50
|
+
return _changed_fields
|
|
51
|
+
|
|
52
|
+
def get_saved_value(self, field):
|
|
53
|
+
return self.__dict__.get(f"_saved_{field}")
|
netbox_dns/models/__init__.py
CHANGED
netbox_dns/models/nameserver.py
CHANGED
|
@@ -7,6 +7,7 @@ from django.urls import reverse
|
|
|
7
7
|
|
|
8
8
|
from netbox.models import NetBoxModel
|
|
9
9
|
from netbox.search import SearchIndex, register_search
|
|
10
|
+
from netbox.models.features import ContactsMixin
|
|
10
11
|
|
|
11
12
|
from netbox_dns.utilities import (
|
|
12
13
|
name_to_unicode,
|
|
@@ -26,7 +27,7 @@ __all__ = (
|
|
|
26
27
|
)
|
|
27
28
|
|
|
28
29
|
|
|
29
|
-
class NameServer(ObjectModificationMixin, NetBoxModel):
|
|
30
|
+
class NameServer(ObjectModificationMixin, ContactsMixin, NetBoxModel):
|
|
30
31
|
name = models.CharField(
|
|
31
32
|
unique=True,
|
|
32
33
|
max_length=255,
|
|
@@ -43,13 +44,17 @@ class NameServer(ObjectModificationMixin, NetBoxModel):
|
|
|
43
44
|
null=True,
|
|
44
45
|
)
|
|
45
46
|
|
|
46
|
-
clone_fields =
|
|
47
|
+
clone_fields = (
|
|
48
|
+
"name",
|
|
49
|
+
"description",
|
|
50
|
+
)
|
|
47
51
|
|
|
48
52
|
class Meta:
|
|
49
|
-
ordering = ("name",)
|
|
50
53
|
verbose_name = "Nameserver"
|
|
51
54
|
verbose_name_plural = "Nameservers"
|
|
52
55
|
|
|
56
|
+
ordering = ("name",)
|
|
57
|
+
|
|
53
58
|
def __str__(self):
|
|
54
59
|
try:
|
|
55
60
|
return dns_name.from_text(self.name, origin=None).to_unicode()
|
netbox_dns/models/record.py
CHANGED
|
@@ -10,12 +10,14 @@ from django.urls import reverse
|
|
|
10
10
|
from django.conf import settings
|
|
11
11
|
|
|
12
12
|
from netbox.models import NetBoxModel
|
|
13
|
+
from ipam.models import IPAddress
|
|
14
|
+
from netbox.models.features import ContactsMixin
|
|
13
15
|
from netbox.search import SearchIndex, register_search
|
|
14
16
|
from netbox.plugins.utils import get_plugin_config
|
|
15
17
|
from utilities.querysets import RestrictedQuerySet
|
|
16
18
|
|
|
17
19
|
from netbox_dns.fields import AddressField
|
|
18
|
-
from netbox_dns.utilities import arpa_to_prefix, name_to_unicode
|
|
20
|
+
from netbox_dns.utilities import arpa_to_prefix, name_to_unicode, get_query_from_filter
|
|
19
21
|
from netbox_dns.validators import validate_generic_name, validate_record_value
|
|
20
22
|
from netbox_dns.mixins import ObjectModificationMixin
|
|
21
23
|
from netbox_dns.choices import RecordTypeChoices, RecordStatusChoices
|
|
@@ -40,6 +42,20 @@ def record_data_from_ip_address(ip_address, zone):
|
|
|
40
42
|
cf_data = ip_address.custom_field_data
|
|
41
43
|
|
|
42
44
|
if cf_data.get("ipaddress_dns_disabled"):
|
|
45
|
+
# +
|
|
46
|
+
# DNS record creation disabled for this address
|
|
47
|
+
# -
|
|
48
|
+
return None
|
|
49
|
+
|
|
50
|
+
if (
|
|
51
|
+
zone.view.ip_address_filter is not None
|
|
52
|
+
and not IPAddress.objects.filter(
|
|
53
|
+
Q(pk=ip_address.pk), get_query_from_filter(zone.view.ip_address_filter)
|
|
54
|
+
).exists()
|
|
55
|
+
):
|
|
56
|
+
# +
|
|
57
|
+
# IP address does not match the filter
|
|
58
|
+
# -
|
|
43
59
|
return None
|
|
44
60
|
|
|
45
61
|
data = {
|
|
@@ -100,7 +116,7 @@ class RecordManager(models.Manager.from_queryset(RestrictedQuerySet)):
|
|
|
100
116
|
)
|
|
101
117
|
|
|
102
118
|
|
|
103
|
-
class Record(ObjectModificationMixin, NetBoxModel):
|
|
119
|
+
class Record(ObjectModificationMixin, ContactsMixin, NetBoxModel):
|
|
104
120
|
ACTIVE_STATUS_LIST = (RecordStatusChoices.STATUS_ACTIVE,)
|
|
105
121
|
|
|
106
122
|
unique_ptr_qs = Q(
|
|
@@ -193,7 +209,7 @@ class Record(ObjectModificationMixin, NetBoxModel):
|
|
|
193
209
|
objects = RecordManager()
|
|
194
210
|
raw_objects = RestrictedQuerySet.as_manager()
|
|
195
211
|
|
|
196
|
-
clone_fields =
|
|
212
|
+
clone_fields = (
|
|
197
213
|
"zone",
|
|
198
214
|
"type",
|
|
199
215
|
"name",
|
|
@@ -202,10 +218,20 @@ class Record(ObjectModificationMixin, NetBoxModel):
|
|
|
202
218
|
"ttl",
|
|
203
219
|
"disable_ptr",
|
|
204
220
|
"description",
|
|
205
|
-
|
|
221
|
+
)
|
|
206
222
|
|
|
207
223
|
class Meta:
|
|
208
|
-
|
|
224
|
+
verbose_name = "Record"
|
|
225
|
+
verbose_name_plural = "Records"
|
|
226
|
+
|
|
227
|
+
ordering = (
|
|
228
|
+
"fqdn",
|
|
229
|
+
"zone",
|
|
230
|
+
"name",
|
|
231
|
+
"type",
|
|
232
|
+
"value",
|
|
233
|
+
"status",
|
|
234
|
+
)
|
|
209
235
|
|
|
210
236
|
def __str__(self):
|
|
211
237
|
try:
|
|
@@ -462,22 +488,29 @@ class Record(ObjectModificationMixin, NetBoxModel):
|
|
|
462
488
|
self.rfc2317_cname_record = None
|
|
463
489
|
|
|
464
490
|
def update_from_ip_address(self, ip_address, zone=None):
|
|
491
|
+
"""
|
|
492
|
+
Update an address record according to data from an IPAddress object.
|
|
493
|
+
|
|
494
|
+
Returns a tuple of two booleans: (update, delete).
|
|
495
|
+
|
|
496
|
+
update: The record was updated and needs to be cleaned and/or saved
|
|
497
|
+
delete: The record is no longer needed and needs to be deleted
|
|
498
|
+
"""
|
|
465
499
|
if zone is None:
|
|
466
500
|
zone = self.zone
|
|
467
501
|
|
|
468
502
|
data = record_data_from_ip_address(ip_address, zone)
|
|
469
503
|
|
|
470
504
|
if data is None:
|
|
471
|
-
|
|
472
|
-
return
|
|
505
|
+
return False, True
|
|
473
506
|
|
|
474
507
|
if all((getattr(self, attr) == data[attr] for attr in data.keys())):
|
|
475
|
-
return
|
|
508
|
+
return False, False
|
|
476
509
|
|
|
477
510
|
for attr, value in data.items():
|
|
478
511
|
setattr(self, attr, value)
|
|
479
512
|
|
|
480
|
-
return
|
|
513
|
+
return True, False
|
|
481
514
|
|
|
482
515
|
@classmethod
|
|
483
516
|
def create_from_ip_address(cls, ip_address, zone):
|
|
@@ -574,7 +607,7 @@ class Record(ObjectModificationMixin, NetBoxModel):
|
|
|
574
607
|
status__in=Record.ACTIVE_STATUS_LIST,
|
|
575
608
|
)
|
|
576
609
|
|
|
577
|
-
if self.
|
|
610
|
+
if not self._state.adding:
|
|
578
611
|
records = records.exclude(pk=self.pk)
|
|
579
612
|
|
|
580
613
|
if records.exists():
|
|
@@ -613,7 +646,7 @@ class Record(ObjectModificationMixin, NetBoxModel):
|
|
|
613
646
|
record.save(update_fields=["status"])
|
|
614
647
|
|
|
615
648
|
def check_unique_rrset_ttl(self):
|
|
616
|
-
if self.
|
|
649
|
+
if not self._state.adding:
|
|
617
650
|
return
|
|
618
651
|
|
|
619
652
|
if not get_plugin_config("netbox_dns", "enforce_unique_rrset_ttl", False):
|
|
@@ -652,7 +685,7 @@ class Record(ObjectModificationMixin, NetBoxModel):
|
|
|
652
685
|
) from None
|
|
653
686
|
|
|
654
687
|
def update_rrset_ttl(self, ttl=None):
|
|
655
|
-
if self.
|
|
688
|
+
if self._state.adding:
|
|
656
689
|
return
|
|
657
690
|
|
|
658
691
|
if not get_plugin_config("netbox_dns", "enforce_unique_rrset_ttl", False):
|
|
@@ -688,7 +721,7 @@ class Record(ObjectModificationMixin, NetBoxModel):
|
|
|
688
721
|
self.validate_name(new_zone=new_zone)
|
|
689
722
|
self.validate_value()
|
|
690
723
|
self.check_unique_record(new_zone=new_zone)
|
|
691
|
-
if self.
|
|
724
|
+
if self._state.adding:
|
|
692
725
|
self.check_unique_rrset_ttl()
|
|
693
726
|
|
|
694
727
|
if not self.is_active:
|
|
@@ -776,7 +809,7 @@ class Record(ObjectModificationMixin, NetBoxModel):
|
|
|
776
809
|
):
|
|
777
810
|
self.full_clean()
|
|
778
811
|
|
|
779
|
-
if self.
|
|
812
|
+
if not self._state.adding and update_rrset_ttl:
|
|
780
813
|
self.update_rrset_ttl()
|
|
781
814
|
|
|
782
815
|
if self.is_ptr_record:
|
netbox_dns/models/registrar.py
CHANGED
|
@@ -59,7 +59,13 @@ class Registrar(NetBoxModel):
|
|
|
59
59
|
return str(self.name)
|
|
60
60
|
|
|
61
61
|
class Meta:
|
|
62
|
-
|
|
62
|
+
verbose_name = "Registrar"
|
|
63
|
+
verbose_name_plural = "Registrars"
|
|
64
|
+
|
|
65
|
+
ordering = (
|
|
66
|
+
"name",
|
|
67
|
+
"iana_id",
|
|
68
|
+
)
|
|
63
69
|
|
|
64
70
|
|
|
65
71
|
@register_search
|
|
@@ -8,12 +8,12 @@ from taggit.managers import TaggableManager
|
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
__all__ = (
|
|
11
|
-
"
|
|
12
|
-
"
|
|
11
|
+
"RegistrationContact",
|
|
12
|
+
"RegistrationContactIndex",
|
|
13
13
|
)
|
|
14
14
|
|
|
15
15
|
|
|
16
|
-
class
|
|
16
|
+
class RegistrationContact(NetBoxModel):
|
|
17
17
|
# +
|
|
18
18
|
# Data fields according to https://www.icann.org/resources/pages/rdds-labeling-policy-2017-02-01-en
|
|
19
19
|
# -
|
|
@@ -87,7 +87,7 @@ class Contact(NetBoxModel):
|
|
|
87
87
|
related_name="netbox_dns_contact_set",
|
|
88
88
|
)
|
|
89
89
|
|
|
90
|
-
clone_fields =
|
|
90
|
+
clone_fields = (
|
|
91
91
|
"name",
|
|
92
92
|
"description",
|
|
93
93
|
"organization",
|
|
@@ -102,10 +102,10 @@ class Contact(NetBoxModel):
|
|
|
102
102
|
"fax_ext",
|
|
103
103
|
"email",
|
|
104
104
|
"tags",
|
|
105
|
-
|
|
105
|
+
)
|
|
106
106
|
|
|
107
107
|
def get_absolute_url(self):
|
|
108
|
-
return reverse("plugins:netbox_dns:
|
|
108
|
+
return reverse("plugins:netbox_dns:registrationcontact", kwargs={"pk": self.pk})
|
|
109
109
|
|
|
110
110
|
def __str__(self):
|
|
111
111
|
if self.name is not None:
|
|
@@ -114,7 +114,13 @@ class Contact(NetBoxModel):
|
|
|
114
114
|
return self.contact_id
|
|
115
115
|
|
|
116
116
|
class Meta:
|
|
117
|
-
|
|
117
|
+
verbose_name = "Registration Contact"
|
|
118
|
+
verbose_name_plural = "Registration Contacts"
|
|
119
|
+
|
|
120
|
+
ordering = (
|
|
121
|
+
"name",
|
|
122
|
+
"contact_id",
|
|
123
|
+
)
|
|
118
124
|
|
|
119
125
|
@property
|
|
120
126
|
def zones(self):
|
|
@@ -127,8 +133,8 @@ class Contact(NetBoxModel):
|
|
|
127
133
|
|
|
128
134
|
|
|
129
135
|
@register_search
|
|
130
|
-
class
|
|
131
|
-
model =
|
|
136
|
+
class RegistrationContactIndex(SearchIndex):
|
|
137
|
+
model = RegistrationContact
|
|
132
138
|
fields = (
|
|
133
139
|
("name", 100),
|
|
134
140
|
("contact_id", 100),
|
netbox_dns/models/view.py
CHANGED
|
@@ -3,11 +3,19 @@ from django.urls import reverse
|
|
|
3
3
|
from django.core.exceptions import ValidationError
|
|
4
4
|
|
|
5
5
|
from netbox.models import NetBoxModel
|
|
6
|
+
from netbox.models.features import ContactsMixin
|
|
6
7
|
from netbox.search import SearchIndex, register_search
|
|
7
8
|
from netbox.context import current_request
|
|
8
9
|
from utilities.exceptions import AbortRequest
|
|
9
10
|
|
|
10
11
|
from netbox_dns.mixins import ObjectModificationMixin
|
|
12
|
+
from netbox_dns.utilities import (
|
|
13
|
+
get_ip_addresses_by_view,
|
|
14
|
+
check_dns_records,
|
|
15
|
+
update_dns_records,
|
|
16
|
+
delete_dns_records,
|
|
17
|
+
get_query_from_filter,
|
|
18
|
+
)
|
|
11
19
|
|
|
12
20
|
|
|
13
21
|
__all__ = (
|
|
@@ -16,7 +24,7 @@ __all__ = (
|
|
|
16
24
|
)
|
|
17
25
|
|
|
18
26
|
|
|
19
|
-
class View(ObjectModificationMixin, NetBoxModel):
|
|
27
|
+
class View(ObjectModificationMixin, ContactsMixin, NetBoxModel):
|
|
20
28
|
name = models.CharField(
|
|
21
29
|
unique=True,
|
|
22
30
|
max_length=255,
|
|
@@ -33,6 +41,11 @@ class View(ObjectModificationMixin, NetBoxModel):
|
|
|
33
41
|
related_name="netbox_dns_views",
|
|
34
42
|
blank=True,
|
|
35
43
|
)
|
|
44
|
+
ip_address_filter = models.JSONField(
|
|
45
|
+
verbose_name="IP Address Filter",
|
|
46
|
+
blank=True,
|
|
47
|
+
null=True,
|
|
48
|
+
)
|
|
36
49
|
tenant = models.ForeignKey(
|
|
37
50
|
to="tenancy.Tenant",
|
|
38
51
|
on_delete=models.PROTECT,
|
|
@@ -41,7 +54,10 @@ class View(ObjectModificationMixin, NetBoxModel):
|
|
|
41
54
|
null=True,
|
|
42
55
|
)
|
|
43
56
|
|
|
44
|
-
clone_fields =
|
|
57
|
+
clone_fields = (
|
|
58
|
+
"name",
|
|
59
|
+
"description",
|
|
60
|
+
)
|
|
45
61
|
|
|
46
62
|
@classmethod
|
|
47
63
|
def get_default_view(cls):
|
|
@@ -54,6 +70,9 @@ class View(ObjectModificationMixin, NetBoxModel):
|
|
|
54
70
|
return str(self.name)
|
|
55
71
|
|
|
56
72
|
class Meta:
|
|
73
|
+
verbose_name = "View"
|
|
74
|
+
verbose_name_plural = "Views"
|
|
75
|
+
|
|
57
76
|
ordering = ("name",)
|
|
58
77
|
|
|
59
78
|
def delete(self, *args, **kwargs):
|
|
@@ -80,6 +99,21 @@ class View(ObjectModificationMixin, NetBoxModel):
|
|
|
80
99
|
}
|
|
81
100
|
)
|
|
82
101
|
|
|
102
|
+
if "ip_address_filter" in changed_fields and self.get_saved_value(
|
|
103
|
+
"ip_address_filter"
|
|
104
|
+
):
|
|
105
|
+
try:
|
|
106
|
+
for ip_address in get_ip_addresses_by_view(self).filter(
|
|
107
|
+
get_query_from_filter(self.ip_address_filter)
|
|
108
|
+
):
|
|
109
|
+
check_dns_records(ip_address, view=self)
|
|
110
|
+
except ValidationError as exc:
|
|
111
|
+
raise ValidationError(
|
|
112
|
+
{
|
|
113
|
+
"ip_address_filter": exc.messages,
|
|
114
|
+
}
|
|
115
|
+
)
|
|
116
|
+
|
|
83
117
|
super().clean(*args, **kwargs)
|
|
84
118
|
|
|
85
119
|
def save(self, *args, **kwargs):
|
|
@@ -99,6 +133,19 @@ class View(ObjectModificationMixin, NetBoxModel):
|
|
|
99
133
|
view.default_view = False
|
|
100
134
|
view.save()
|
|
101
135
|
|
|
136
|
+
if changed_fields is not None and "ip_address_filter" in changed_fields:
|
|
137
|
+
ip_addresses = get_ip_addresses_by_view(self)
|
|
138
|
+
|
|
139
|
+
for ip_address in ip_addresses.exclude(
|
|
140
|
+
get_query_from_filter(self.ip_address_filter)
|
|
141
|
+
):
|
|
142
|
+
delete_dns_records(ip_address, view=self)
|
|
143
|
+
|
|
144
|
+
for ip_address in ip_addresses.filter(
|
|
145
|
+
get_query_from_filter(self.ip_address_filter)
|
|
146
|
+
):
|
|
147
|
+
update_dns_records(ip_address, view=self)
|
|
148
|
+
|
|
102
149
|
|
|
103
150
|
@register_search
|
|
104
151
|
class ViewIndex(SearchIndex):
|
netbox_dns/models/zone.py
CHANGED
|
@@ -5,8 +5,6 @@ from datetime import datetime
|
|
|
5
5
|
from dns import name as dns_name
|
|
6
6
|
from dns.exception import DNSException
|
|
7
7
|
from dns.rdtypes.ANY import SOA
|
|
8
|
-
from dns.exception import DNSException
|
|
9
|
-
|
|
10
8
|
from django.core.validators import (
|
|
11
9
|
MinValueValidator,
|
|
12
10
|
MaxValueValidator,
|
|
@@ -20,6 +18,7 @@ from django.dispatch import receiver
|
|
|
20
18
|
from django.conf import settings
|
|
21
19
|
|
|
22
20
|
from netbox.models import NetBoxModel
|
|
21
|
+
from netbox.models.features import ContactsMixin
|
|
23
22
|
from netbox.search import SearchIndex, register_search
|
|
24
23
|
from netbox.plugins.utils import get_plugin_config
|
|
25
24
|
from utilities.querysets import RestrictedQuerySet
|
|
@@ -37,7 +36,6 @@ from netbox_dns.utilities import (
|
|
|
37
36
|
NameFormatError,
|
|
38
37
|
)
|
|
39
38
|
from netbox_dns.validators import (
|
|
40
|
-
validate_fqdn,
|
|
41
39
|
validate_rname,
|
|
42
40
|
validate_domain_name,
|
|
43
41
|
)
|
|
@@ -71,7 +69,7 @@ class ZoneManager(models.Manager.from_queryset(RestrictedQuerySet)):
|
|
|
71
69
|
)
|
|
72
70
|
|
|
73
71
|
|
|
74
|
-
class Zone(ObjectModificationMixin, NetBoxModel):
|
|
72
|
+
class Zone(ObjectModificationMixin, ContactsMixin, NetBoxModel):
|
|
75
73
|
ACTIVE_STATUS_LIST = (ZoneStatusChoices.STATUS_ACTIVE,)
|
|
76
74
|
|
|
77
75
|
def __init__(self, *args, **kwargs):
|
|
@@ -194,7 +192,7 @@ class Zone(ObjectModificationMixin, NetBoxModel):
|
|
|
194
192
|
null=True,
|
|
195
193
|
)
|
|
196
194
|
registrant = models.ForeignKey(
|
|
197
|
-
to="
|
|
195
|
+
to="RegistrationContact",
|
|
198
196
|
on_delete=models.SET_NULL,
|
|
199
197
|
verbose_name="Registrant",
|
|
200
198
|
help_text="The owner of the domain",
|
|
@@ -202,7 +200,7 @@ class Zone(ObjectModificationMixin, NetBoxModel):
|
|
|
202
200
|
null=True,
|
|
203
201
|
)
|
|
204
202
|
admin_c = models.ForeignKey(
|
|
205
|
-
to="
|
|
203
|
+
to="RegistrationContact",
|
|
206
204
|
on_delete=models.SET_NULL,
|
|
207
205
|
verbose_name="Admin Contact",
|
|
208
206
|
related_name="admin_c_zones",
|
|
@@ -211,16 +209,16 @@ class Zone(ObjectModificationMixin, NetBoxModel):
|
|
|
211
209
|
null=True,
|
|
212
210
|
)
|
|
213
211
|
tech_c = models.ForeignKey(
|
|
214
|
-
to="
|
|
212
|
+
to="RegistrationContact",
|
|
215
213
|
on_delete=models.SET_NULL,
|
|
216
|
-
verbose_name="
|
|
214
|
+
verbose_name="Technical Contact",
|
|
217
215
|
related_name="tech_c_zones",
|
|
218
216
|
help_text="The technical contact for the domain",
|
|
219
217
|
blank=True,
|
|
220
218
|
null=True,
|
|
221
219
|
)
|
|
222
220
|
billing_c = models.ForeignKey(
|
|
223
|
-
to="
|
|
221
|
+
to="RegistrationContact",
|
|
224
222
|
on_delete=models.SET_NULL,
|
|
225
223
|
verbose_name="Billing Contact",
|
|
226
224
|
related_name="billing_c_zones",
|
|
@@ -251,7 +249,7 @@ class Zone(ObjectModificationMixin, NetBoxModel):
|
|
|
251
249
|
|
|
252
250
|
objects = ZoneManager()
|
|
253
251
|
|
|
254
|
-
clone_fields =
|
|
252
|
+
clone_fields = (
|
|
255
253
|
"view",
|
|
256
254
|
"name",
|
|
257
255
|
"status",
|
|
@@ -265,9 +263,12 @@ class Zone(ObjectModificationMixin, NetBoxModel):
|
|
|
265
263
|
"soa_expire",
|
|
266
264
|
"soa_minimum",
|
|
267
265
|
"description",
|
|
268
|
-
|
|
266
|
+
)
|
|
269
267
|
|
|
270
268
|
class Meta:
|
|
269
|
+
verbose_name = "Zone"
|
|
270
|
+
verbose_name_plural = "Zones"
|
|
271
|
+
|
|
271
272
|
ordering = (
|
|
272
273
|
"view",
|
|
273
274
|
"name",
|
|
@@ -648,14 +649,16 @@ class Zone(ObjectModificationMixin, NetBoxModel):
|
|
|
648
649
|
}
|
|
649
650
|
)
|
|
650
651
|
|
|
651
|
-
if self.
|
|
652
|
-
|
|
652
|
+
if not self._state.adding:
|
|
653
|
+
old_soa_serial = self.get_saved_value("soa_serial")
|
|
654
|
+
old_soa_serial_auto = self.get_saved_value("soa_serial_auto")
|
|
655
|
+
|
|
653
656
|
if not self.soa_serial_auto:
|
|
654
|
-
self.check_soa_serial_increment(
|
|
655
|
-
|
|
657
|
+
self.check_soa_serial_increment(old_soa_serial, self.soa_serial)
|
|
658
|
+
elif not old_soa_serial_auto:
|
|
656
659
|
try:
|
|
657
660
|
self.check_soa_serial_increment(
|
|
658
|
-
|
|
661
|
+
old_soa_serial, self.get_auto_serial()
|
|
659
662
|
)
|
|
660
663
|
except ValidationError:
|
|
661
664
|
raise ValidationError(
|
|
@@ -664,10 +667,13 @@ class Zone(ObjectModificationMixin, NetBoxModel):
|
|
|
664
667
|
}
|
|
665
668
|
)
|
|
666
669
|
|
|
670
|
+
old_name = self.get_saved_value("name")
|
|
671
|
+
old_view_id = self.get_saved_value("view_id")
|
|
672
|
+
|
|
667
673
|
if (
|
|
668
674
|
not self.ip_addresses_checked
|
|
669
|
-
and
|
|
670
|
-
or
|
|
675
|
+
and old_name != self.name
|
|
676
|
+
or old_view_id != self.view_id
|
|
671
677
|
):
|
|
672
678
|
ip_addresses = IPAddress.objects.filter(
|
|
673
679
|
netbox_dns_records__in=self.record_set.filter(
|
|
@@ -47,7 +47,7 @@ class ZoneTemplate(NetBoxModel):
|
|
|
47
47
|
null=True,
|
|
48
48
|
)
|
|
49
49
|
registrant = models.ForeignKey(
|
|
50
|
-
to="
|
|
50
|
+
to="RegistrationContact",
|
|
51
51
|
on_delete=models.SET_NULL,
|
|
52
52
|
related_name="+",
|
|
53
53
|
help_text="The owner of the domain",
|
|
@@ -55,7 +55,7 @@ class ZoneTemplate(NetBoxModel):
|
|
|
55
55
|
null=True,
|
|
56
56
|
)
|
|
57
57
|
admin_c = models.ForeignKey(
|
|
58
|
-
to="
|
|
58
|
+
to="RegistrationContact",
|
|
59
59
|
on_delete=models.SET_NULL,
|
|
60
60
|
verbose_name="Admin contact",
|
|
61
61
|
related_name="+",
|
|
@@ -64,7 +64,7 @@ class ZoneTemplate(NetBoxModel):
|
|
|
64
64
|
null=True,
|
|
65
65
|
)
|
|
66
66
|
tech_c = models.ForeignKey(
|
|
67
|
-
to="
|
|
67
|
+
to="RegistrationContact",
|
|
68
68
|
on_delete=models.SET_NULL,
|
|
69
69
|
verbose_name="Tech contact",
|
|
70
70
|
related_name="+",
|
|
@@ -73,7 +73,7 @@ class ZoneTemplate(NetBoxModel):
|
|
|
73
73
|
null=True,
|
|
74
74
|
)
|
|
75
75
|
billing_c = models.ForeignKey(
|
|
76
|
-
to="
|
|
76
|
+
to="RegistrationContact",
|
|
77
77
|
on_delete=models.SET_NULL,
|
|
78
78
|
verbose_name="Billing contact",
|
|
79
79
|
related_name="+",
|
|
@@ -82,7 +82,7 @@ class ZoneTemplate(NetBoxModel):
|
|
|
82
82
|
null=True,
|
|
83
83
|
)
|
|
84
84
|
|
|
85
|
-
clone_fields =
|
|
85
|
+
clone_fields = (
|
|
86
86
|
"description",
|
|
87
87
|
"nameservers",
|
|
88
88
|
"record_templates",
|
|
@@ -92,19 +92,22 @@ class ZoneTemplate(NetBoxModel):
|
|
|
92
92
|
"admin_c",
|
|
93
93
|
"tech_c",
|
|
94
94
|
"billing_c",
|
|
95
|
-
|
|
95
|
+
)
|
|
96
96
|
|
|
97
|
-
template_fields =
|
|
97
|
+
template_fields = (
|
|
98
98
|
"tenant",
|
|
99
99
|
"registrar",
|
|
100
100
|
"registrant",
|
|
101
101
|
"admin_c",
|
|
102
102
|
"tech_c",
|
|
103
103
|
"billing_c",
|
|
104
|
-
|
|
104
|
+
)
|
|
105
105
|
|
|
106
106
|
class Meta:
|
|
107
|
-
|
|
107
|
+
verbose_name = "Zone Template"
|
|
108
|
+
verbose_name_plural = "Zone Templates"
|
|
109
|
+
|
|
110
|
+
ordering = ("name",)
|
|
108
111
|
|
|
109
112
|
def __str__(self):
|
|
110
113
|
return str(self.name)
|
netbox_dns/navigation.py
CHANGED
|
@@ -151,21 +151,21 @@ registrar_menu_item = PluginMenuItem(
|
|
|
151
151
|
)
|
|
152
152
|
|
|
153
153
|
contact_menu_item = PluginMenuItem(
|
|
154
|
-
link="plugins:netbox_dns:
|
|
155
|
-
link_text="Contacts",
|
|
156
|
-
permissions=["netbox_dns.
|
|
154
|
+
link="plugins:netbox_dns:registrationcontact_list",
|
|
155
|
+
link_text="Registration Contacts",
|
|
156
|
+
permissions=["netbox_dns.view_registrationcontact"],
|
|
157
157
|
buttons=(
|
|
158
158
|
PluginMenuButton(
|
|
159
|
-
"plugins:netbox_dns:
|
|
159
|
+
"plugins:netbox_dns:registrationcontact_add",
|
|
160
160
|
"Add",
|
|
161
161
|
"mdi mdi-plus-thick",
|
|
162
|
-
permissions=["netbox_dns.
|
|
162
|
+
permissions=["netbox_dns.add_registrationcontact"],
|
|
163
163
|
),
|
|
164
164
|
PluginMenuButton(
|
|
165
|
-
"plugins:netbox_dns:
|
|
165
|
+
"plugins:netbox_dns:registrationcontact_import",
|
|
166
166
|
"Import",
|
|
167
167
|
"mdi mdi-upload",
|
|
168
|
-
permissions=["netbox_dns.
|
|
168
|
+
permissions=["netbox_dns.add_registrationcontact"],
|
|
169
169
|
),
|
|
170
170
|
),
|
|
171
171
|
)
|