netbox-plugin-dns 1.0.1__py3-none-any.whl → 1.0.3__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 +6 -2
- netbox_dns/mixins/__init__.py +1 -0
- netbox_dns/mixins/object_modification.py +26 -0
- netbox_dns/models/nameserver.py +4 -5
- netbox_dns/models/record.py +20 -9
- netbox_dns/models/view.py +10 -8
- netbox_dns/models/zone.py +28 -22
- netbox_dns/navigation.py +34 -18
- netbox_dns/tables/view.py +1 -1
- netbox_dns/templates/netbox_dns/record.html +4 -4
- netbox_dns/templates/netbox_dns/zone/child_zone.html +18 -0
- netbox_dns/templates/netbox_dns/zone.html +11 -15
- netbox_dns/urls/zone.py +6 -0
- netbox_dns/utilities/__init__.py +1 -1
- netbox_dns/validators/dns_name.py +49 -28
- netbox_dns/views/zone.py +20 -0
- {netbox_plugin_dns-1.0.1.dist-info → netbox_plugin_dns-1.0.3.dist-info}/LICENSE +2 -1
- {netbox_plugin_dns-1.0.1.dist-info → netbox_plugin_dns-1.0.3.dist-info}/METADATA +2 -1
- {netbox_plugin_dns-1.0.1.dist-info → netbox_plugin_dns-1.0.3.dist-info}/RECORD +20 -17
- {netbox_plugin_dns-1.0.1.dist-info → netbox_plugin_dns-1.0.3.dist-info}/WHEEL +0 -0
netbox_dns/__init__.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
from netbox.plugins import PluginConfig
|
|
2
2
|
|
|
3
|
-
__version__ = "1.0.
|
|
3
|
+
__version__ = "1.0.3"
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
class DNSConfig(PluginConfig):
|
|
@@ -21,7 +21,9 @@ class DNSConfig(PluginConfig):
|
|
|
21
21
|
"zone_soa_expire": 2419200,
|
|
22
22
|
"zone_soa_minimum": 3600,
|
|
23
23
|
"feature_ipam_coupling": False,
|
|
24
|
-
"
|
|
24
|
+
"tolerate_characters_in_zone_labels": "",
|
|
25
|
+
"tolerate_underscores_in_labels": False,
|
|
26
|
+
"tolerate_underscores_in_hostnames": False, # Deprecated, will be removed in 1.2.0
|
|
25
27
|
"tolerate_leading_underscore_types": [
|
|
26
28
|
"TXT",
|
|
27
29
|
"SRV",
|
|
@@ -30,6 +32,8 @@ class DNSConfig(PluginConfig):
|
|
|
30
32
|
"enable_root_zones": False,
|
|
31
33
|
"enforce_unique_records": True,
|
|
32
34
|
"enforce_unique_rrset_ttl": True,
|
|
35
|
+
"menu_name": "NetBox DNS",
|
|
36
|
+
"top_level_menu": True,
|
|
33
37
|
}
|
|
34
38
|
base_url = "netbox-dns"
|
|
35
39
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from .object_modification import *
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
from netbox.models import NetBoxModel
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class ObjectModificationMixin:
|
|
5
|
+
def __init__(self, *args, **kwargs):
|
|
6
|
+
super().__init__(*args, **kwargs)
|
|
7
|
+
|
|
8
|
+
if not hasattr(self.__class__, "check_fields"):
|
|
9
|
+
self.__class__.check_fields = (
|
|
10
|
+
{field.name for field in self._meta.fields}
|
|
11
|
+
- {field.name for field in NetBoxModel._meta.fields}
|
|
12
|
+
- {"id"}
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
@property
|
|
16
|
+
def changed_fields(self):
|
|
17
|
+
if self.pk is None:
|
|
18
|
+
return None
|
|
19
|
+
|
|
20
|
+
saved = self.__class__.objects.get(pk=self.pk)
|
|
21
|
+
|
|
22
|
+
return {
|
|
23
|
+
field
|
|
24
|
+
for field in self.check_fields
|
|
25
|
+
if getattr(self, field) != getattr(saved, field)
|
|
26
|
+
}
|
netbox_dns/models/nameserver.py
CHANGED
|
@@ -14,11 +14,12 @@ from netbox_dns.utilities import (
|
|
|
14
14
|
NameFormatError,
|
|
15
15
|
)
|
|
16
16
|
from netbox_dns.validators import validate_fqdn
|
|
17
|
+
from netbox_dns.mixins import ObjectModificationMixin
|
|
17
18
|
|
|
18
19
|
from .record import Record, RecordTypeChoices
|
|
19
20
|
|
|
20
21
|
|
|
21
|
-
class NameServer(NetBoxModel):
|
|
22
|
+
class NameServer(ObjectModificationMixin, NetBoxModel):
|
|
22
23
|
name = models.CharField(
|
|
23
24
|
unique=True,
|
|
24
25
|
max_length=255,
|
|
@@ -79,14 +80,12 @@ class NameServer(NetBoxModel):
|
|
|
79
80
|
def save(self, *args, **kwargs):
|
|
80
81
|
self.full_clean()
|
|
81
82
|
|
|
82
|
-
|
|
83
|
-
self.pk is not None and self.name != NameServer.objects.get(pk=self.pk).name
|
|
84
|
-
)
|
|
83
|
+
changed_fields = self.changed_fields
|
|
85
84
|
|
|
86
85
|
with transaction.atomic():
|
|
87
86
|
super().save(*args, **kwargs)
|
|
88
87
|
|
|
89
|
-
if
|
|
88
|
+
if changed_fields is not None and "name" in changed_fields:
|
|
90
89
|
soa_zones = self.zones_soa.all()
|
|
91
90
|
for soa_zone in soa_zones:
|
|
92
91
|
soa_zone.update_soa_record()
|
netbox_dns/models/record.py
CHANGED
|
@@ -22,9 +22,10 @@ from netbox_dns.utilities import (
|
|
|
22
22
|
)
|
|
23
23
|
from netbox_dns.validators import (
|
|
24
24
|
validate_fqdn,
|
|
25
|
-
|
|
25
|
+
validate_generic_name,
|
|
26
26
|
validate_domain_name,
|
|
27
27
|
)
|
|
28
|
+
from netbox_dns.mixins import ObjectModificationMixin
|
|
28
29
|
|
|
29
30
|
# +
|
|
30
31
|
# This is a hack designed to break cyclic imports between Record and Zone
|
|
@@ -102,7 +103,7 @@ class RecordStatusChoices(ChoiceSet):
|
|
|
102
103
|
]
|
|
103
104
|
|
|
104
105
|
|
|
105
|
-
class Record(NetBoxModel):
|
|
106
|
+
class Record(ObjectModificationMixin, NetBoxModel):
|
|
106
107
|
ACTIVE_STATUS_LIST = (RecordStatusChoices.STATUS_ACTIVE,)
|
|
107
108
|
|
|
108
109
|
unique_ptr_qs = Q(
|
|
@@ -211,9 +212,12 @@ class Record(NetBoxModel):
|
|
|
211
212
|
|
|
212
213
|
def __str__(self):
|
|
213
214
|
try:
|
|
214
|
-
|
|
215
|
+
fqdn = dns_name.from_text(
|
|
216
|
+
self.name, origin=dns_name.from_text(self.zone.name)
|
|
217
|
+
).relativize(dns_name.root)
|
|
218
|
+
name = fqdn.to_unicode()
|
|
215
219
|
except dns_name.IDNAException:
|
|
216
|
-
name =
|
|
220
|
+
name = fqdn.to_text()
|
|
217
221
|
except dns_name.LabelTooLong:
|
|
218
222
|
name = f"{self.name[:59]}..."
|
|
219
223
|
|
|
@@ -490,7 +494,7 @@ class Record(NetBoxModel):
|
|
|
490
494
|
"netbox_dns", "tolerate_non_rfc1035_types", default=[]
|
|
491
495
|
):
|
|
492
496
|
try:
|
|
493
|
-
|
|
497
|
+
validate_generic_name(
|
|
494
498
|
self.name,
|
|
495
499
|
(
|
|
496
500
|
self.type
|
|
@@ -537,8 +541,7 @@ class Record(NetBoxModel):
|
|
|
537
541
|
)
|
|
538
542
|
|
|
539
543
|
case (
|
|
540
|
-
RecordTypeChoices.
|
|
541
|
-
| RecordTypeChoices.NS
|
|
544
|
+
RecordTypeChoices.NS
|
|
542
545
|
| RecordTypeChoices.HTTPS
|
|
543
546
|
| RecordTypeChoices.SRV
|
|
544
547
|
| RecordTypeChoices.SVCB
|
|
@@ -546,6 +549,12 @@ class Record(NetBoxModel):
|
|
|
546
549
|
_validate_idn(rr.target)
|
|
547
550
|
validate_domain_name(rr.target.to_text(), always_tolerant=True)
|
|
548
551
|
|
|
552
|
+
case RecordTypeChoices.DNAME:
|
|
553
|
+
_validate_idn(rr.target)
|
|
554
|
+
validate_domain_name(
|
|
555
|
+
rr.target.to_text(), always_tolerant=True, zone_name=True
|
|
556
|
+
)
|
|
557
|
+
|
|
549
558
|
case RecordTypeChoices.PTR | RecordTypeChoices.NSAP_PTR:
|
|
550
559
|
_validate_idn(rr.target)
|
|
551
560
|
validate_fqdn(rr.target.to_text(), always_tolerant=True)
|
|
@@ -566,7 +575,7 @@ class Record(NetBoxModel):
|
|
|
566
575
|
|
|
567
576
|
case RecordTypeChoices.NAPTR:
|
|
568
577
|
_validate_idn(rr.replacement)
|
|
569
|
-
|
|
578
|
+
validate_generic_name(
|
|
570
579
|
rr.replacement.to_text(), always_tolerant=True
|
|
571
580
|
)
|
|
572
581
|
|
|
@@ -783,7 +792,9 @@ class Record(NetBoxModel):
|
|
|
783
792
|
self.ptr_record.delete()
|
|
784
793
|
self.ptr_record = None
|
|
785
794
|
|
|
786
|
-
|
|
795
|
+
changed_fields = self.changed_fields
|
|
796
|
+
if changed_fields is None or changed_fields:
|
|
797
|
+
super().save(*args, **kwargs)
|
|
787
798
|
|
|
788
799
|
_zone = self.zone
|
|
789
800
|
if self.type != RecordTypeChoices.SOA and _zone.soa_serial_auto:
|
netbox_dns/models/view.py
CHANGED
|
@@ -7,8 +7,10 @@ from netbox.search import SearchIndex, register_search
|
|
|
7
7
|
from netbox.context import current_request
|
|
8
8
|
from utilities.exceptions import AbortRequest
|
|
9
9
|
|
|
10
|
+
from netbox_dns.mixins import ObjectModificationMixin
|
|
10
11
|
|
|
11
|
-
|
|
12
|
+
|
|
13
|
+
class View(ObjectModificationMixin, NetBoxModel):
|
|
12
14
|
name = models.CharField(
|
|
13
15
|
unique=True,
|
|
14
16
|
max_length=255,
|
|
@@ -53,13 +55,11 @@ class View(NetBoxModel):
|
|
|
53
55
|
super().delete(*args, **kwargs)
|
|
54
56
|
|
|
55
57
|
def clean(self, *args, old_state=None, **kwargs):
|
|
56
|
-
if self.
|
|
58
|
+
if (changed_fields := self.changed_fields) is None:
|
|
57
59
|
return
|
|
58
60
|
|
|
59
|
-
old_state = View.objects.get(pk=self.pk)
|
|
60
|
-
|
|
61
61
|
if (
|
|
62
|
-
|
|
62
|
+
"default_view" in changed_fields
|
|
63
63
|
and not self.default_view
|
|
64
64
|
and not View.objects.filter(default_view=True).exclude(pk=self.pk).exists()
|
|
65
65
|
):
|
|
@@ -74,12 +74,14 @@ class View(NetBoxModel):
|
|
|
74
74
|
def save(self, *args, **kwargs):
|
|
75
75
|
self.clean()
|
|
76
76
|
|
|
77
|
-
|
|
77
|
+
changed_fields = self.changed_fields
|
|
78
78
|
|
|
79
79
|
super().save(*args, **kwargs)
|
|
80
80
|
|
|
81
|
-
if (
|
|
82
|
-
|
|
81
|
+
if (changed_fields is None and self.default_view) or (
|
|
82
|
+
changed_fields is not None
|
|
83
|
+
and self.default_view
|
|
84
|
+
and "default_view" in changed_fields
|
|
83
85
|
):
|
|
84
86
|
other_views = View.objects.filter(default_view=True).exclude(pk=self.pk)
|
|
85
87
|
for view in other_views:
|
netbox_dns/models/zone.py
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import re
|
|
1
2
|
from math import ceil
|
|
2
3
|
from datetime import datetime
|
|
3
4
|
|
|
@@ -35,6 +36,7 @@ from netbox_dns.validators import (
|
|
|
35
36
|
validate_fqdn,
|
|
36
37
|
validate_domain_name,
|
|
37
38
|
)
|
|
39
|
+
from netbox_dns.mixins import ObjectModificationMixin
|
|
38
40
|
|
|
39
41
|
# +
|
|
40
42
|
# This is a hack designed to break cyclic imports between View, Record and Zone
|
|
@@ -77,7 +79,7 @@ class ZoneStatusChoices(ChoiceSet):
|
|
|
77
79
|
]
|
|
78
80
|
|
|
79
81
|
|
|
80
|
-
class Zone(NetBoxModel):
|
|
82
|
+
class Zone(ObjectModificationMixin, NetBoxModel):
|
|
81
83
|
ACTIVE_STATUS_LIST = (ZoneStatusChoices.STATUS_ACTIVE,)
|
|
82
84
|
|
|
83
85
|
view = models.ForeignKey(
|
|
@@ -352,6 +354,22 @@ class Zone(NetBoxModel):
|
|
|
352
354
|
)
|
|
353
355
|
)
|
|
354
356
|
|
|
357
|
+
@property
|
|
358
|
+
def child_zones(self):
|
|
359
|
+
return Zone.objects.filter(
|
|
360
|
+
name__iregex=rf"^[^.]+\.{re.escape(self.name)}$", view=self.view
|
|
361
|
+
)
|
|
362
|
+
|
|
363
|
+
@property
|
|
364
|
+
def parent_zone(self):
|
|
365
|
+
parent_name = (
|
|
366
|
+
dns_name.from_text(self.name).parent().relativize(dns_name.root).to_text()
|
|
367
|
+
)
|
|
368
|
+
try:
|
|
369
|
+
return Zone.objects.get(name=parent_name, view=self.view)
|
|
370
|
+
except Zone.DoesNotExist:
|
|
371
|
+
return None
|
|
372
|
+
|
|
355
373
|
def record_count(self, managed=False):
|
|
356
374
|
return record.Record.objects.filter(zone=self, managed=managed).count()
|
|
357
375
|
|
|
@@ -592,7 +610,7 @@ class Zone(NetBoxModel):
|
|
|
592
610
|
) from None
|
|
593
611
|
|
|
594
612
|
try:
|
|
595
|
-
validate_domain_name(self.name)
|
|
613
|
+
validate_domain_name(self.name, zone_name=True)
|
|
596
614
|
except ValidationError as exc:
|
|
597
615
|
raise ValidationError(
|
|
598
616
|
{
|
|
@@ -683,17 +701,7 @@ class Zone(NetBoxModel):
|
|
|
683
701
|
def save(self, *args, **kwargs):
|
|
684
702
|
self.full_clean()
|
|
685
703
|
|
|
686
|
-
|
|
687
|
-
if not new_zone:
|
|
688
|
-
old_zone = Zone.objects.get(pk=self.pk)
|
|
689
|
-
|
|
690
|
-
name_changed = not new_zone and old_zone.name != self.name
|
|
691
|
-
view_changed = not new_zone and old_zone.view != self.view
|
|
692
|
-
status_changed = not new_zone and old_zone.status != self.status
|
|
693
|
-
rfc2317_changed = not new_zone and (
|
|
694
|
-
old_zone.rfc2317_prefix != self.rfc2317_prefix
|
|
695
|
-
or old_zone.rfc2317_parent_managed != self.rfc2317_parent_managed
|
|
696
|
-
)
|
|
704
|
+
changed_fields = self.changed_fields
|
|
697
705
|
|
|
698
706
|
if self.soa_serial_auto:
|
|
699
707
|
self.soa_serial = self.get_auto_serial()
|
|
@@ -701,7 +709,7 @@ class Zone(NetBoxModel):
|
|
|
701
709
|
super().save(*args, **kwargs)
|
|
702
710
|
|
|
703
711
|
if (
|
|
704
|
-
|
|
712
|
+
changed_fields is None or {"name", "view", "status"} & changed_fields
|
|
705
713
|
) and self.is_reverse_zone:
|
|
706
714
|
zones = Zone.objects.filter(
|
|
707
715
|
view=self.view,
|
|
@@ -733,11 +741,9 @@ class Zone(NetBoxModel):
|
|
|
733
741
|
child_zone.update_rfc2317_parent_zone()
|
|
734
742
|
|
|
735
743
|
if (
|
|
736
|
-
|
|
737
|
-
or
|
|
738
|
-
|
|
739
|
-
or status_changed
|
|
740
|
-
or rfc2317_changed
|
|
744
|
+
changed_fields is None
|
|
745
|
+
or {"name", "view", "status", "rfc2317_prefix", "rfc2317_parent_managed"}
|
|
746
|
+
& changed_fields
|
|
741
747
|
) and self.is_rfc2317_zone:
|
|
742
748
|
zones = Zone.objects.filter(
|
|
743
749
|
view=self.view,
|
|
@@ -763,7 +769,7 @@ class Zone(NetBoxModel):
|
|
|
763
769
|
|
|
764
770
|
self.update_rfc2317_parent_zone()
|
|
765
771
|
|
|
766
|
-
elif
|
|
772
|
+
elif changed_fields is not None and {"name", "view", "status"} & changed_fields:
|
|
767
773
|
for address_record in self.record_set.filter(
|
|
768
774
|
type__in=(record.RecordTypeChoices.A, record.RecordTypeChoices.AAAA)
|
|
769
775
|
):
|
|
@@ -772,7 +778,7 @@ class Zone(NetBoxModel):
|
|
|
772
778
|
# Fix name in IP Address when zone name is changed
|
|
773
779
|
if (
|
|
774
780
|
get_plugin_config("netbox_dns", "feature_ipam_coupling")
|
|
775
|
-
and
|
|
781
|
+
and "name" in changed_fields
|
|
776
782
|
):
|
|
777
783
|
for ip in IPAddress.objects.filter(
|
|
778
784
|
custom_field_data__ipaddress_dns_zone_id=self.pk
|
|
@@ -780,7 +786,7 @@ class Zone(NetBoxModel):
|
|
|
780
786
|
ip.dns_name = f'{ip.custom_field_data["ipaddress_dns_record_name"]}.{self.name}'
|
|
781
787
|
ip.save(update_fields=["dns_name"])
|
|
782
788
|
|
|
783
|
-
if
|
|
789
|
+
if changed_fields is not None and "name" in changed_fields:
|
|
784
790
|
for _record in self.record_set.all():
|
|
785
791
|
_record.save(
|
|
786
792
|
update_fields=["fqdn"],
|
netbox_dns/navigation.py
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
from netbox.plugins import PluginMenuButton, PluginMenuItem, PluginMenu
|
|
2
|
+
from netbox.plugins.utils import get_plugin_config
|
|
3
|
+
|
|
4
|
+
menu_name = get_plugin_config("netbox_dns", "menu_name")
|
|
5
|
+
top_level_menu = get_plugin_config("netbox_dns", "top_level_menu")
|
|
2
6
|
|
|
3
7
|
view_menu_item = PluginMenuItem(
|
|
4
8
|
link="plugins:netbox_dns:view_list",
|
|
@@ -126,26 +130,38 @@ contact_menu_item = PluginMenuItem(
|
|
|
126
130
|
),
|
|
127
131
|
)
|
|
128
132
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
133
|
+
|
|
134
|
+
if top_level_menu:
|
|
135
|
+
menu = PluginMenu(
|
|
136
|
+
label=menu_name,
|
|
137
|
+
groups=(
|
|
134
138
|
(
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
139
|
+
"DNS Configuration",
|
|
140
|
+
(
|
|
141
|
+
view_menu_item,
|
|
142
|
+
zone_menu_item,
|
|
143
|
+
nameserver_menu_item,
|
|
144
|
+
record_menu_item,
|
|
145
|
+
managed_record_menu_item,
|
|
146
|
+
),
|
|
140
147
|
),
|
|
141
|
-
),
|
|
142
|
-
(
|
|
143
|
-
"Domain Registration",
|
|
144
148
|
(
|
|
145
|
-
|
|
146
|
-
|
|
149
|
+
"Domain Registration",
|
|
150
|
+
(
|
|
151
|
+
registrar_menu_item,
|
|
152
|
+
contact_menu_item,
|
|
153
|
+
),
|
|
147
154
|
),
|
|
148
155
|
),
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
156
|
+
icon_class="mdi mdi-dns",
|
|
157
|
+
)
|
|
158
|
+
else:
|
|
159
|
+
menu_items = (
|
|
160
|
+
view_menu_item,
|
|
161
|
+
zone_menu_item,
|
|
162
|
+
nameserver_menu_item,
|
|
163
|
+
record_menu_item,
|
|
164
|
+
managed_record_menu_item,
|
|
165
|
+
registrar_menu_item,
|
|
166
|
+
contact_menu_item,
|
|
167
|
+
)
|
netbox_dns/tables/view.py
CHANGED
|
@@ -10,7 +10,7 @@ class ViewTable(TenancyColumnsMixin, NetBoxTable):
|
|
|
10
10
|
name = tables.Column(
|
|
11
11
|
linkify=True,
|
|
12
12
|
)
|
|
13
|
-
default_view = tables.
|
|
13
|
+
default_view = tables.BooleanColumn(
|
|
14
14
|
verbose_name="Default View",
|
|
15
15
|
)
|
|
16
16
|
tags = TagColumn(url_name="plugins:netbox_dns:view_list")
|
|
@@ -94,25 +94,25 @@
|
|
|
94
94
|
{% if object.ptr_record %}
|
|
95
95
|
<tr>
|
|
96
96
|
<th scope="row">PTR Record</th>
|
|
97
|
-
<td
|
|
97
|
+
<td>{{ object.ptr_record|linkify }}</td>
|
|
98
98
|
</tr>
|
|
99
99
|
{% endif %}
|
|
100
100
|
{% if object.address_record %}
|
|
101
101
|
<tr>
|
|
102
102
|
<th scope="row">Address Record</th>
|
|
103
|
-
<td
|
|
103
|
+
<td>{{ object.address_record|linkify }}</td>
|
|
104
104
|
</tr>
|
|
105
105
|
{% if object.address_record.ipam_ip_address %}
|
|
106
106
|
<tr>
|
|
107
107
|
<th scope="row">IPAM IP Address</th>
|
|
108
|
-
<td
|
|
108
|
+
<td>{{ object.address_record.ipam_ip_address|linkify }}</td>
|
|
109
109
|
</tr>
|
|
110
110
|
{% endif %}
|
|
111
111
|
{% endif %}
|
|
112
112
|
{% if object.ipam_ip_address %}
|
|
113
113
|
<tr>
|
|
114
114
|
<th scope="row">IPAM IP Address</th>
|
|
115
|
-
<td
|
|
115
|
+
<td>{{ object.ipam_ip_address|linkify }}</td>
|
|
116
116
|
</tr>
|
|
117
117
|
{% endif %}
|
|
118
118
|
<tr>
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{% extends 'netbox_dns/zone/base.html' %}
|
|
2
|
+
{% load helpers %}
|
|
3
|
+
{% load render_table from django_tables2 %}
|
|
4
|
+
{% load perms %}
|
|
5
|
+
|
|
6
|
+
{% block content %}
|
|
7
|
+
{% include 'inc/table_controls_htmx.html' with table_modal="ChildZoneTable_config" %}
|
|
8
|
+
<div class="card">
|
|
9
|
+
<div class="htmx-container table-responsive" id="object_list">
|
|
10
|
+
{% include 'htmx/table.html' %}
|
|
11
|
+
</div>
|
|
12
|
+
</div>
|
|
13
|
+
{% endblock %}
|
|
14
|
+
|
|
15
|
+
{% block modals %}
|
|
16
|
+
{{ block.super }}
|
|
17
|
+
{% table_config_form table %}
|
|
18
|
+
{% endblock modals %}
|
|
@@ -20,13 +20,15 @@
|
|
|
20
20
|
<td>{{ unicode_name }}</td>
|
|
21
21
|
</tr>
|
|
22
22
|
{% endif %}
|
|
23
|
+
{% if parent_zone %}
|
|
24
|
+
<tr>
|
|
25
|
+
<th scope="row">Parent Zone</th>
|
|
26
|
+
<td>{{ parent_zone|linkify }}</td>
|
|
27
|
+
</tr>
|
|
28
|
+
{% endif %}
|
|
23
29
|
<tr>
|
|
24
30
|
<th scope="row">View</th>
|
|
25
|
-
<td>
|
|
26
|
-
<a href="{% url 'plugins:netbox_dns:view' pk=object.view.pk %}">
|
|
27
|
-
{{ object.view }}
|
|
28
|
-
</a>
|
|
29
|
-
</td>
|
|
31
|
+
<td>{{ object.view|linkify }}</td>
|
|
30
32
|
</tr>
|
|
31
33
|
{% if object.description %}
|
|
32
34
|
<tr>
|
|
@@ -52,13 +54,7 @@
|
|
|
52
54
|
<td>
|
|
53
55
|
<table>
|
|
54
56
|
{% for nameserver in object.nameservers.all %}
|
|
55
|
-
<tr>
|
|
56
|
-
<td>
|
|
57
|
-
<a href="{% url 'plugins:netbox_dns:nameserver' pk=nameserver.pk %}">
|
|
58
|
-
{{ nameserver }}
|
|
59
|
-
</a>
|
|
60
|
-
</td>
|
|
61
|
-
</tr>
|
|
57
|
+
<tr><td>{{ nameserver|linkify }}</td></tr>
|
|
62
58
|
{% endfor %}
|
|
63
59
|
</table>
|
|
64
60
|
</td>
|
|
@@ -115,7 +111,7 @@
|
|
|
115
111
|
</tr>
|
|
116
112
|
<tr>
|
|
117
113
|
<th scope="row">MName</th>
|
|
118
|
-
<td
|
|
114
|
+
<td>{{ object.soa_mname|linkify }}</td>
|
|
119
115
|
</tr>
|
|
120
116
|
<tr>
|
|
121
117
|
<th scope="row">RName</th>
|
|
@@ -153,7 +149,7 @@
|
|
|
153
149
|
{% if object.rfc2317_prefix %}
|
|
154
150
|
<div class="card">
|
|
155
151
|
<h5 class="card-header">RFC2317</h5>
|
|
156
|
-
<table class="table table-hover
|
|
152
|
+
<table class="table table-hover attr-table">
|
|
157
153
|
<tr>
|
|
158
154
|
<th scope="row">Prefix</th>
|
|
159
155
|
<td>{{ object.rfc2317_prefix }}</td>
|
|
@@ -165,7 +161,7 @@
|
|
|
165
161
|
{% if object.rfc2317_parent_managed %}
|
|
166
162
|
<tr>
|
|
167
163
|
<th scope="row">Parent Zone</th>
|
|
168
|
-
<td
|
|
164
|
+
<td>{{ object.rfc2317_parent_zone|linkify }}</td>
|
|
169
165
|
</tr>
|
|
170
166
|
{% endif %}
|
|
171
167
|
</table>
|
netbox_dns/urls/zone.py
CHANGED
|
@@ -15,6 +15,7 @@ from netbox_dns.views import (
|
|
|
15
15
|
ZoneManagedRecordListView,
|
|
16
16
|
ZoneRegistrationView,
|
|
17
17
|
ZoneRFC2317ChildZoneListView,
|
|
18
|
+
ZoneChildZoneListView,
|
|
18
19
|
)
|
|
19
20
|
|
|
20
21
|
zone_urlpatterns = [
|
|
@@ -37,6 +38,11 @@ zone_urlpatterns = [
|
|
|
37
38
|
ZoneRFC2317ChildZoneListView.as_view(),
|
|
38
39
|
name="zone_rfc2317_child_zones",
|
|
39
40
|
),
|
|
41
|
+
path(
|
|
42
|
+
"zones/<int:pk>/childzones/",
|
|
43
|
+
ZoneChildZoneListView.as_view(),
|
|
44
|
+
name="zone_child_zones",
|
|
45
|
+
),
|
|
40
46
|
path(
|
|
41
47
|
"zones/<int:pk>/registration/",
|
|
42
48
|
ZoneRegistrationView.as_view(),
|
netbox_dns/utilities/__init__.py
CHANGED
|
@@ -4,10 +4,40 @@ from django.core.exceptions import ValidationError
|
|
|
4
4
|
|
|
5
5
|
from netbox.plugins.utils import get_plugin_config
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
7
|
+
import logging
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def _get_label(tolerate_leading_underscores=False, always_tolerant=False):
|
|
11
|
+
tolerate_characters = re.escape(
|
|
12
|
+
get_plugin_config("netbox_dns", "tolerate_characters_in_zone_labels", "")
|
|
13
|
+
)
|
|
14
|
+
label_characters = rf"a-z0-9{tolerate_characters}"
|
|
15
|
+
|
|
16
|
+
if always_tolerant:
|
|
17
|
+
label = rf"[a-z0-9_][a-z0-9_-]*(?<![-_])"
|
|
18
|
+
zone_label = rf"[{label_characters}_][{label_characters}_-]*(?<![-_])"
|
|
19
|
+
|
|
20
|
+
return label, zone_label
|
|
21
|
+
|
|
22
|
+
tolerate_underscores = get_plugin_config(
|
|
23
|
+
"netbox_dns", "tolerate_underscores_in_labels"
|
|
24
|
+
) or get_plugin_config("netbox_dns", "tolerate_underscores_in_hostnames")
|
|
25
|
+
|
|
26
|
+
if tolerate_leading_underscores:
|
|
27
|
+
if tolerate_underscores:
|
|
28
|
+
label = r"[a-z0-9_][a-z0-9_-]*(?<![-_])"
|
|
29
|
+
zone_label = rf"[{label_characters}_][{label_characters}_-]*(?<![-_])"
|
|
30
|
+
else:
|
|
31
|
+
label = rf"[a-z0-9_][a-z0-9-]*(?<!-)"
|
|
32
|
+
zone_label = rf"[{label_characters}_][{label_characters}-]*(?<!-)"
|
|
33
|
+
elif tolerate_underscores:
|
|
34
|
+
label = rf"[a-z0-9][a-z0-9_-]*(?<![-_])"
|
|
35
|
+
zone_label = rf"[{label_characters}][{label_characters}_-]*(?<![-_])"
|
|
36
|
+
else:
|
|
37
|
+
label = rf"[a-z0-9][a-z0-9-]*(?<!-)"
|
|
38
|
+
zone_label = rf"[{label_characters}][{label_characters}-]*(?<!-)"
|
|
39
|
+
|
|
40
|
+
return label, zone_label
|
|
11
41
|
|
|
12
42
|
|
|
13
43
|
def has_invalid_double_dash(name):
|
|
@@ -15,37 +45,29 @@ def has_invalid_double_dash(name):
|
|
|
15
45
|
|
|
16
46
|
|
|
17
47
|
def validate_fqdn(name, always_tolerant=False):
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
):
|
|
21
|
-
regex = rf"^(\*|{TOLERANT_LABEL})(\.{TOLERANT_LABEL})+\.?$"
|
|
22
|
-
else:
|
|
23
|
-
regex = rf"^(\*|{LABEL})(\.{LABEL})+\.?$"
|
|
48
|
+
label, zone_label = _get_label(always_tolerant=always_tolerant)
|
|
49
|
+
regex = rf"^(\*|{label})(\.{zone_label})+\.?$"
|
|
24
50
|
|
|
25
51
|
if not re.match(regex, name, flags=re.IGNORECASE) or has_invalid_double_dash(name):
|
|
26
52
|
raise ValidationError(f"{name} is not a valid fully qualified DNS host name")
|
|
27
53
|
|
|
28
54
|
|
|
29
|
-
def
|
|
55
|
+
def validate_generic_name(
|
|
30
56
|
name, tolerate_leading_underscores=False, always_tolerant=False
|
|
31
57
|
):
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
else:
|
|
38
|
-
regex = rf"^([*@]|(\*\.)?{LEADING_UNDERSCORE_LABEL}(\.{LEADING_UNDERSCORE_LABEL})*\.?)$"
|
|
39
|
-
elif get_plugin_config("netbox_dns", "tolerate_underscores_in_hostnames"):
|
|
40
|
-
regex = rf"^([*@]|(\*\.)?{TOLERANT_LABEL}(\.{TOLERANT_LABEL})*\.?)$"
|
|
41
|
-
else:
|
|
42
|
-
regex = rf"^([*@]|(\*\.)?{LABEL}(\.{LABEL})*\.?)$"
|
|
58
|
+
label, zone_label = _get_label(
|
|
59
|
+
tolerate_leading_underscores=tolerate_leading_underscores,
|
|
60
|
+
always_tolerant=always_tolerant,
|
|
61
|
+
)
|
|
62
|
+
regex = rf"^([*@]|(\*\.)?{label}(\.{zone_label})*\.?)$"
|
|
43
63
|
|
|
44
64
|
if not re.match(regex, name, flags=re.IGNORECASE) or has_invalid_double_dash(name):
|
|
45
65
|
raise ValidationError(f"{name} is not a valid DNS host name")
|
|
46
66
|
|
|
47
67
|
|
|
48
|
-
def validate_domain_name(
|
|
68
|
+
def validate_domain_name(
|
|
69
|
+
name, always_tolerant=False, allow_empty_label=False, zone_name=False
|
|
70
|
+
):
|
|
49
71
|
if name == "@" and allow_empty_label:
|
|
50
72
|
return
|
|
51
73
|
|
|
@@ -54,12 +76,11 @@ def validate_domain_name(name, always_tolerant=False, allow_empty_label=False):
|
|
|
54
76
|
):
|
|
55
77
|
return
|
|
56
78
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
regex = rf"^{TOLERANT_LABEL}(\.{TOLERANT_LABEL})*\.?$"
|
|
79
|
+
label, zone_label = _get_label(always_tolerant=always_tolerant)
|
|
80
|
+
if zone_name:
|
|
81
|
+
regex = rf"^{zone_label}(\.{zone_label})*\.?$"
|
|
61
82
|
else:
|
|
62
|
-
regex = rf"^{
|
|
83
|
+
regex = rf"^{label}(\.{zone_label})*\.?$"
|
|
63
84
|
|
|
64
85
|
if not re.match(regex, name, flags=re.IGNORECASE) or has_invalid_double_dash(name):
|
|
65
86
|
raise ValidationError(f"{name} is not a valid DNS domain name")
|
netbox_dns/views/zone.py
CHANGED
|
@@ -40,6 +40,7 @@ class ZoneView(generic.ObjectView):
|
|
|
40
40
|
context = {
|
|
41
41
|
"nameserver_warnings": ns_warnings,
|
|
42
42
|
"nameserver_errors": ns_errors,
|
|
43
|
+
"parent_zone": instance.parent_zone,
|
|
43
44
|
}
|
|
44
45
|
|
|
45
46
|
name = dns_name.from_text(instance.name)
|
|
@@ -165,3 +166,22 @@ class ZoneRFC2317ChildZoneListView(generic.ObjectChildrenView):
|
|
|
165
166
|
|
|
166
167
|
def get_children(self, request, parent):
|
|
167
168
|
return parent.rfc2317_child_zones.all()
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
@register_model_view(Zone, "child_zones")
|
|
172
|
+
class ZoneChildZoneListView(generic.ObjectChildrenView):
|
|
173
|
+
queryset = Zone.objects.all()
|
|
174
|
+
child_model = Zone
|
|
175
|
+
table = ZoneTable
|
|
176
|
+
filterset = ZoneFilterSet
|
|
177
|
+
template_name = "netbox_dns/zone/child_zone.html"
|
|
178
|
+
|
|
179
|
+
tab = ViewTab(
|
|
180
|
+
label="Child Zones",
|
|
181
|
+
permission="netbox_dns.view_zone",
|
|
182
|
+
badge=lambda obj: obj.child_zones.count(),
|
|
183
|
+
hide_if_empty=True,
|
|
184
|
+
)
|
|
185
|
+
|
|
186
|
+
def get_children(self, request, parent):
|
|
187
|
+
return parent.child_zones
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
MIT License
|
|
2
2
|
|
|
3
|
-
Copyright (c) 2021 Aurora Research Lab
|
|
3
|
+
Copyright (c) 2021-2023 Aurora Research Lab
|
|
4
|
+
Copyright (c) 2023 Peter Eckel
|
|
4
5
|
|
|
5
6
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
7
|
of this software and associated documentation files (the "Software"), to deal
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: netbox-plugin-dns
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.3
|
|
4
4
|
Summary: NetBox DNS is a NetBox plugin for managing DNS data.
|
|
5
5
|
Home-page: https://github.com/peteeckel/netbox-plugin-dns
|
|
6
6
|
License: MIT
|
|
@@ -44,6 +44,7 @@ The main focus of the plugin is to ensure the quality of the data stored in it.
|
|
|
44
44
|
* Validation of record names and values
|
|
45
45
|
* Automatic maintenance of PTR records for IPv6 and IPv4 address records
|
|
46
46
|
* Automatic generation of SOA records, optionally including the serial number of the zone data
|
|
47
|
+
* Validation of changes to the SOA SERIAL number, whether they are done automatically or manually
|
|
47
48
|
* Validation of record types such as CNAME and singletons, to ensure DNS zone validity
|
|
48
49
|
* Support for [RFC 2317](https://datatracker.ietf.org/doc/html/rfc2317) delegation of PTR zones for IPv4 subnets longer than 24 bits
|
|
49
50
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
netbox_dns/__init__.py,sha256=
|
|
1
|
+
netbox_dns/__init__.py,sha256=lhlLlERkb4Bbex6ypL5-ra35zq2Uro7qTZlC95JLmiI,1244
|
|
2
2
|
netbox_dns/api/nested_serializers.py,sha256=kkTU4Hylkbam9-lIniv8E0nTQwE1bz8D_GzIEOUy0Mw,2145
|
|
3
3
|
netbox_dns/api/serializers.py,sha256=C4-TP1luq9QjEHjPS5cW7u2flAEdIFjghpVd_sa5S_Y,249
|
|
4
4
|
netbox_dns/api/serializers_/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -54,14 +54,16 @@ netbox_dns/migrations/0027_alter_registrar_iana_id.py,sha256=QUtRIrqqfkraFmzzeJF
|
|
|
54
54
|
netbox_dns/migrations/0028_rfc2317_fields.py,sha256=D8r43xxBjYXiL6ycmX8RY5_WG7tRYEDjutOeYM1H56I,1364
|
|
55
55
|
netbox_dns/migrations/0029_record_fqdn.py,sha256=UAAU38ekKQyiYDOJlcrz6Qbk4bqZfSHZyAHUZFFQrOw,808
|
|
56
56
|
netbox_dns/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
57
|
+
netbox_dns/mixins/__init__.py,sha256=LxTEfpod_RHCyMtnzDljv0_dwqp2z3Q6tqbXW8LTGD8,35
|
|
58
|
+
netbox_dns/mixins/object_modification.py,sha256=wq01fyCAai2staM2g5wV9BbW1hDUeRdXfJrSSkc2YK8,726
|
|
57
59
|
netbox_dns/models/__init__.py,sha256=Q7UIEe2vGh18AZN4er6CykciwXPQGgUq0L-9718wZqU,182
|
|
58
60
|
netbox_dns/models/contact.py,sha256=xXmNGuM6k1U98jO3mMmp93PXamh1YZQ270JOcy0FFnE,2958
|
|
59
|
-
netbox_dns/models/nameserver.py,sha256=
|
|
60
|
-
netbox_dns/models/record.py,sha256=
|
|
61
|
+
netbox_dns/models/nameserver.py,sha256=5Z0sFTqpxksCFCOExxXZEY_mpEVTKLMtFv5urD9yvdg,3121
|
|
62
|
+
netbox_dns/models/record.py,sha256=BTMt9Tq-3v_fZcNeLZvlkZHfWYpfgwcLbbxdB6F1s5M,26476
|
|
61
63
|
netbox_dns/models/registrar.py,sha256=yidjVCq7WPECsHLKQRRCSzGbvG2jIXu8lqAKox0SU5Q,1502
|
|
62
|
-
netbox_dns/models/view.py,sha256=
|
|
63
|
-
netbox_dns/models/zone.py,sha256=
|
|
64
|
-
netbox_dns/navigation.py,sha256=
|
|
64
|
+
netbox_dns/models/view.py,sha256=HgQSpD8zQCxDpNel0b1_m4GlMYoRBpxiu6-Dtb1YnxI,2712
|
|
65
|
+
netbox_dns/models/zone.py,sha256=eaFNlDdvfNn9Ky6sUUl2HA-_SkcWnYJzExB3GLDaoLo,28655
|
|
66
|
+
netbox_dns/navigation.py,sha256=9NdvJ-0IIFvf3hMccoailepu7QLkVYEk0dpDxfuGo80,4572
|
|
65
67
|
netbox_dns/signals/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
66
68
|
netbox_dns/signals/ipam_coupling.py,sha256=kJUKHUgq5XgWMhxB-312SPaZAYTLIYGgKO0lz2-z_rg,5594
|
|
67
69
|
netbox_dns/tables/__init__.py,sha256=Aw8HrCTjaJfu5JSwJsQRHfOUz4zKwAmZNByT9q6BrFU,136
|
|
@@ -69,35 +71,36 @@ netbox_dns/tables/contact.py,sha256=guT_wC3NJMYbVbXeMOg6nqmmmDcnjfbRI-SkjFDEYdU,
|
|
|
69
71
|
netbox_dns/tables/nameserver.py,sha256=8BfXzDXNuhZHEyHjGlL4EA1LYx7XU3EPGHlby0k33II,767
|
|
70
72
|
netbox_dns/tables/record.py,sha256=VwBWMiZN_Lkl9SXfJLzd8-7TM1CKetwE7azhScF4r7I,3162
|
|
71
73
|
netbox_dns/tables/registrar.py,sha256=6C8XpxvR9O7IoVK0RD5RoZgXjkm-ORSBeKP6KbwcjHA,648
|
|
72
|
-
netbox_dns/tables/view.py,sha256=
|
|
74
|
+
netbox_dns/tables/view.py,sha256=NaZmDVefmrRWF711_zOJqOmguU66LtI6bOZQ9ZdxniA,699
|
|
73
75
|
netbox_dns/tables/zone.py,sha256=4TlTB7lVsztZJ41aetkqr6PWosjZP-xc2sB9gDnw0z8,1886
|
|
74
76
|
netbox_dns/template_content.py,sha256=NmtfseYrYcU3RxzCI5okwCpMTfTEs4d8aJnDYwo4MO8,3801
|
|
75
77
|
netbox_dns/templates/netbox_dns/contact.html,sha256=fMHAQyLXIxohKoCTxFEnKetl9UVXeQgjasfpv_JONaw,2855
|
|
76
78
|
netbox_dns/templates/netbox_dns/nameserver.html,sha256=DpTdetQVV_jKThDbi62LvbhiCay-1QxR-yiJEiPFm4w,1554
|
|
77
79
|
netbox_dns/templates/netbox_dns/record/managed.html,sha256=G6LPG1koUGuzUiwYdv1okdVa4sKaofiQegDBnsFL0kA,89
|
|
78
80
|
netbox_dns/templates/netbox_dns/record/related.html,sha256=Aqor8uGcuHQTHjlX-Xmni2Yp4N7lOBrMOqQiszrQOC0,742
|
|
79
|
-
netbox_dns/templates/netbox_dns/record.html,sha256=
|
|
81
|
+
netbox_dns/templates/netbox_dns/record.html,sha256=WtEkWy_CstGWE9UDFsATxz0bNpP_Gx9joZusAYGHDFQ,5235
|
|
80
82
|
netbox_dns/templates/netbox_dns/registrar.html,sha256=O5veGmW59Pf5yN25ihPLvRIkA2P7xmSGv0G3NrRG8vI,2152
|
|
81
83
|
netbox_dns/templates/netbox_dns/related_dns_objects.html,sha256=KSzlnw1cStrJa3poKkwrt_ycIH0oH0STWIHRNy3ks4g,806
|
|
82
84
|
netbox_dns/templates/netbox_dns/view.html,sha256=XCa7Sg8fjSkhVqjLvw652FINQdWURLWdQqw8is82iaI,1499
|
|
83
85
|
netbox_dns/templates/netbox_dns/zone/base.html,sha256=n_E4aVYdGeZZl-ARE8sb4DgAAgPs92X1UEFepX3xIlM,495
|
|
84
86
|
netbox_dns/templates/netbox_dns/zone/child.html,sha256=kH56PJFBGCjiRdIh7zCtClnZdfOChqN_sYslsyoz5gU,2147
|
|
87
|
+
netbox_dns/templates/netbox_dns/zone/child_zone.html,sha256=b9CSGWEfWT7hLQ80gApMnu7mXM8w2LT-3UaOYe6HIRQ,510
|
|
85
88
|
netbox_dns/templates/netbox_dns/zone/managed_record.html,sha256=LOchMAJyfMZIICE6q0pX1eorRbtgUtOQ1u0VvJKCDZ8,514
|
|
86
89
|
netbox_dns/templates/netbox_dns/zone/record.html,sha256=tu5RFm2eYJ3fjeUxZYDJqJ9qK8tGslXl1iGs60DlRyM,2194
|
|
87
90
|
netbox_dns/templates/netbox_dns/zone/registration.html,sha256=de2Kph-G8Gv5LD_Wf294SLfO0UKPS9NmHeQYRfJf-Ck,1151
|
|
88
91
|
netbox_dns/templates/netbox_dns/zone/rfc2317_child_zone.html,sha256=rWlmb3zRQbLYQ_1dsa0twwu6y1dRj2tfFVEERH07p-s,517
|
|
89
|
-
netbox_dns/templates/netbox_dns/zone.html,sha256=
|
|
92
|
+
netbox_dns/templates/netbox_dns/zone.html,sha256=zPi1sLFnya-ytx8-Pcf_ujc1sKllCRuz48x2E-S1HSo,6285
|
|
90
93
|
netbox_dns/urls/__init__.py,sha256=ky-ertisnz10vB18bi7JGwZwkvbRAeDErAqn621Xmbc,438
|
|
91
94
|
netbox_dns/urls/contact.py,sha256=OSQO-AkAhTaBruAdzVgcC7ip_OuiacvFI_ozgkWlNFU,1549
|
|
92
95
|
netbox_dns/urls/nameserver.py,sha256=BBbY-wqPqCquvLLv1_JhqToj7oDHhPNGCWHt0IfjBNM,1941
|
|
93
96
|
netbox_dns/urls/record.py,sha256=bDprohTso1N0GtPXH4X3TNHnkxopiOSQFXWItifEZ_k,1432
|
|
94
97
|
netbox_dns/urls/registrar.py,sha256=u6B0zGGYNUJIKTo9uGiUeZLPD0QMGaQOAPShGEy4NaA,1728
|
|
95
98
|
netbox_dns/urls/view.py,sha256=8AeBnOHWusXXQs4JXpNfMSHqszXAY1GDXGWmNsMulQ8,1327
|
|
96
|
-
netbox_dns/urls/zone.py,sha256=
|
|
97
|
-
netbox_dns/utilities/__init__.py,sha256
|
|
99
|
+
netbox_dns/urls/zone.py,sha256=rmB1BkzmWNG06ILUf-39Aj6-SBFkwQouyixMQiamqPc,2005
|
|
100
|
+
netbox_dns/utilities/__init__.py,sha256=-6-qmb1yTAt9QEtGtokNFBQV_TSheobkLjbWFKEYpfw,1849
|
|
98
101
|
netbox_dns/utilities/ipam_coupling.py,sha256=6z1Fx8fhesf15gLTHYc0KVqE3_YhJbNPAjqFOvWlqK8,3441
|
|
99
102
|
netbox_dns/validators/__init__.py,sha256=5W8s31R1aT5B_mKJjTRwogEKj-Xun05iCyvRuYVGkdM,47
|
|
100
|
-
netbox_dns/validators/dns_name.py,sha256=
|
|
103
|
+
netbox_dns/validators/dns_name.py,sha256=rb4nd3zfVotoS0lZXfoHL7uTZWN2QPCIuf7uYxXsasg,2991
|
|
101
104
|
netbox_dns/validators/rfc2317.py,sha256=L2Z-z5ghktFyWMLVZPeK8OEVGnQzbXD11fha2xGHM5E,501
|
|
102
105
|
netbox_dns/views/__init__.py,sha256=Aw8HrCTjaJfu5JSwJsQRHfOUz4zKwAmZNByT9q6BrFU,136
|
|
103
106
|
netbox_dns/views/contact.py,sha256=mBWM92UVjoz90JCUGO7kaFUI0_yA7tH4lSHxOZQB3MQ,2253
|
|
@@ -105,8 +108,8 @@ netbox_dns/views/nameserver.py,sha256=Sxl1h8v1W-uP0Qxz-Re0Ei1LgnWJuQGjI7ZaHS7qLe
|
|
|
105
108
|
netbox_dns/views/record.py,sha256=DDHbxQ33P_mduoPquvyXrdrqNT6r79qShLg1uJzU4Ic,4347
|
|
106
109
|
netbox_dns/views/registrar.py,sha256=NK6jTYRwRjaVjYmI7T4Phh_gjXg9yPrxl-7vciZ9doc,2090
|
|
107
110
|
netbox_dns/views/view.py,sha256=a3l6pybhqGb_RMxrRgFT1Gia9tRq8EmXFxPv9WUId0U,1913
|
|
108
|
-
netbox_dns/views/zone.py,sha256=
|
|
109
|
-
netbox_plugin_dns-1.0.
|
|
110
|
-
netbox_plugin_dns-1.0.
|
|
111
|
-
netbox_plugin_dns-1.0.
|
|
112
|
-
netbox_plugin_dns-1.0.
|
|
111
|
+
netbox_dns/views/zone.py,sha256=bOWnHtnlYH8BiB3L7ZKJLqS_VVOYCEFZNnOxbmFmsNY,5161
|
|
112
|
+
netbox_plugin_dns-1.0.3.dist-info/LICENSE,sha256=I3tDu11bZfhFm3EkV4zOD5TmWgLjnUNLEFwrdjniZYs,1112
|
|
113
|
+
netbox_plugin_dns-1.0.3.dist-info/METADATA,sha256=xdA1apPJLWo-Y9QDq5pXYx-acxDhf1vTOynMISktZU8,6146
|
|
114
|
+
netbox_plugin_dns-1.0.3.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
|
115
|
+
netbox_plugin_dns-1.0.3.dist-info/RECORD,,
|
|
File without changes
|