netbox-plugin-dns 1.1.0b1__py3-none-any.whl → 1.1.0b2__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/forms/view.py +5 -4
- netbox_dns/management/commands/setup_autodns.py +35 -19
- netbox_dns/models/record.py +35 -1
- netbox_dns/models/zone.py +14 -0
- netbox_dns/signals/ipam_autodns.py +43 -11
- netbox_dns/templates/netbox_dns/view.html +2 -6
- netbox_dns/utilities/ipam_autodns.py +67 -16
- {netbox_plugin_dns-1.1.0b1.dist-info → netbox_plugin_dns-1.1.0b2.dist-info}/METADATA +2 -2
- {netbox_plugin_dns-1.1.0b1.dist-info → netbox_plugin_dns-1.1.0b2.dist-info}/RECORD +12 -12
- {netbox_plugin_dns-1.1.0b1.dist-info → netbox_plugin_dns-1.1.0b2.dist-info}/LICENSE +0 -0
- {netbox_plugin_dns-1.1.0b1.dist-info → netbox_plugin_dns-1.1.0b2.dist-info}/WHEEL +0 -0
netbox_dns/__init__.py
CHANGED
|
@@ -5,14 +5,14 @@ from ipam.choices import IPAddressStatusChoices
|
|
|
5
5
|
|
|
6
6
|
from netbox_dns.choices import RecordTypeChoices
|
|
7
7
|
|
|
8
|
-
__version__ = "1.1.
|
|
8
|
+
__version__ = "1.1.0b2"
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
class DNSConfig(PluginConfig):
|
|
12
12
|
name = "netbox_dns"
|
|
13
13
|
verbose_name = "NetBox DNS"
|
|
14
14
|
description = "NetBox plugin for DNS data"
|
|
15
|
-
min_version = "4.
|
|
15
|
+
min_version = "4.0.0"
|
|
16
16
|
version = __version__
|
|
17
17
|
author = "Peter Eckel"
|
|
18
18
|
author_email = "pete@netbox-dns.org"
|
|
@@ -31,6 +31,7 @@ class DNSConfig(PluginConfig):
|
|
|
31
31
|
IPAddressStatusChoices.STATUS_DHCP,
|
|
32
32
|
IPAddressStatusChoices.STATUS_SLAAC,
|
|
33
33
|
],
|
|
34
|
+
"autodns_conflict_deactivate": False,
|
|
34
35
|
"tolerate_characters_in_zone_labels": "",
|
|
35
36
|
"tolerate_underscores_in_labels": False,
|
|
36
37
|
"tolerate_underscores_in_hostnames": False, # Deprecated, will be removed in 1.2.0
|
netbox_dns/forms/view.py
CHANGED
|
@@ -25,8 +25,9 @@ from ipam.models import Prefix
|
|
|
25
25
|
from netbox_dns.models import View
|
|
26
26
|
from netbox_dns.fields import PrefixDynamicModelMultipleChoiceField
|
|
27
27
|
from netbox_dns.utilities import (
|
|
28
|
-
|
|
28
|
+
check_dns_records,
|
|
29
29
|
update_dns_records,
|
|
30
|
+
get_ip_addresses_by_prefix,
|
|
30
31
|
get_views_by_prefix,
|
|
31
32
|
)
|
|
32
33
|
|
|
@@ -52,7 +53,7 @@ class ViewPrefixUpdateMixin:
|
|
|
52
53
|
for prefix in prefixes.difference(old_prefixes):
|
|
53
54
|
for ip_address in get_ip_addresses_by_prefix(prefix, check_view=False):
|
|
54
55
|
try:
|
|
55
|
-
|
|
56
|
+
check_dns_records(ip_address, view=self.instance)
|
|
56
57
|
except ValidationError as exc:
|
|
57
58
|
self.add_error("prefixes", exc.messages)
|
|
58
59
|
|
|
@@ -74,7 +75,7 @@ class ViewPrefixUpdateMixin:
|
|
|
74
75
|
# parent. If that's the case, the IP addresses need to be checked.
|
|
75
76
|
# -
|
|
76
77
|
if (parent := check_prefix.get_parents().last()) is None:
|
|
77
|
-
|
|
78
|
+
continue
|
|
78
79
|
|
|
79
80
|
for view in get_views_by_prefix(parent):
|
|
80
81
|
if view == self.instance:
|
|
@@ -84,7 +85,7 @@ class ViewPrefixUpdateMixin:
|
|
|
84
85
|
check_prefix, check_view=False
|
|
85
86
|
):
|
|
86
87
|
try:
|
|
87
|
-
|
|
88
|
+
check_dns_records(ip_address, view=view)
|
|
88
89
|
except ValidationError as exc:
|
|
89
90
|
self.add_error("prefixes", exc.messages)
|
|
90
91
|
|
|
@@ -29,7 +29,7 @@ class Command(BaseCommand):
|
|
|
29
29
|
CustomField.objects.get(
|
|
30
30
|
name=cf, object_types=ipaddress_object_type
|
|
31
31
|
).delete()
|
|
32
|
-
if options.get("verbosity")
|
|
32
|
+
if options.get("verbosity"):
|
|
33
33
|
self.stdout.write(f"Custom field '{cf}' removed")
|
|
34
34
|
except CustomField.DoesNotExist:
|
|
35
35
|
pass
|
|
@@ -38,7 +38,7 @@ class Command(BaseCommand):
|
|
|
38
38
|
# +
|
|
39
39
|
# Remove pre-existing IPAM Coupling custom fields
|
|
40
40
|
# -
|
|
41
|
-
if options.get("verbosity"):
|
|
41
|
+
if options.get("verbosity") >= 2:
|
|
42
42
|
self.stdout.write(f"Trying to remove obsolete IPAM Coupling custom fields")
|
|
43
43
|
for cf in (
|
|
44
44
|
"ipaddress_dns_record_name",
|
|
@@ -48,12 +48,12 @@ class Command(BaseCommand):
|
|
|
48
48
|
CustomField.objects.get(
|
|
49
49
|
name=cf, object_types=ipaddress_object_type
|
|
50
50
|
).delete()
|
|
51
|
-
if options.get("verbosity")
|
|
51
|
+
if options.get("verbosity"):
|
|
52
52
|
self.stdout.write(f"Removed custom field '{cf}'")
|
|
53
53
|
except CustomField.DoesNotExist:
|
|
54
54
|
pass
|
|
55
55
|
|
|
56
|
-
if options.get("verbosity"):
|
|
56
|
+
if options.get("verbosity") >= 2:
|
|
57
57
|
self.stdout.write(f"Creating IPAM AutoDNS custom fields")
|
|
58
58
|
|
|
59
59
|
if not CustomField.objects.filter(
|
|
@@ -61,7 +61,7 @@ class Command(BaseCommand):
|
|
|
61
61
|
type=CustomFieldTypeChoices.TYPE_BOOLEAN,
|
|
62
62
|
object_types=ipaddress_object_type,
|
|
63
63
|
).exists():
|
|
64
|
-
|
|
64
|
+
cf_autodns_disabled = CustomField.objects.create(
|
|
65
65
|
name="ipaddress_dns_disabled",
|
|
66
66
|
label="Disable AutoDNS",
|
|
67
67
|
description="Disable DNS address and pointer record generation for this address",
|
|
@@ -72,15 +72,22 @@ class Command(BaseCommand):
|
|
|
72
72
|
is_cloneable=True,
|
|
73
73
|
weight=100,
|
|
74
74
|
)
|
|
75
|
-
|
|
76
|
-
if options.get("verbosity")
|
|
75
|
+
cf_autodns_disabled.object_types.set([ipaddress_object_type])
|
|
76
|
+
if options.get("verbosity"):
|
|
77
77
|
self.stdout.write("Created custom field 'ipaddress_dns_disabled'")
|
|
78
78
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
79
|
+
try:
|
|
80
|
+
cf_ttl = CustomField.objects.get(
|
|
81
|
+
name="ipaddress_dns_record_ttl",
|
|
82
|
+
type=CustomFieldTypeChoices.TYPE_INTEGER,
|
|
83
|
+
object_types=ipaddress_object_type,
|
|
84
|
+
)
|
|
85
|
+
if cf_ttl.group_name != "AutoDNS":
|
|
86
|
+
cf_ttl.group_name = "AutoDNS"
|
|
87
|
+
cf_ttl.save()
|
|
88
|
+
if options.get("verbosity"):
|
|
89
|
+
self.stdout.write("Updated custom field 'ipaddress_dns_record_ttl'")
|
|
90
|
+
except CustomField.DoesNotExist:
|
|
84
91
|
cf_ttl = CustomField.objects.create(
|
|
85
92
|
name="ipaddress_dns_record_ttl",
|
|
86
93
|
description="TTL for DNS records created for this address",
|
|
@@ -94,14 +101,23 @@ class Command(BaseCommand):
|
|
|
94
101
|
weight=200,
|
|
95
102
|
)
|
|
96
103
|
cf_ttl.object_types.set([ipaddress_object_type])
|
|
97
|
-
if options.get("verbosity")
|
|
104
|
+
if options.get("verbosity"):
|
|
98
105
|
self.stdout.write("Created custom field 'ipaddress_dns_record_ttl'")
|
|
99
106
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
107
|
+
try:
|
|
108
|
+
cf_disable_ptr = CustomField.objects.get(
|
|
109
|
+
name="ipaddress_dns_record_disable_ptr",
|
|
110
|
+
type=CustomFieldTypeChoices.TYPE_BOOLEAN,
|
|
111
|
+
object_types=ipaddress_object_type,
|
|
112
|
+
)
|
|
113
|
+
if cf_disable_ptr.group_name != "AutoDNS":
|
|
114
|
+
cf_disable_ptr.group_name = "AutoDNS"
|
|
115
|
+
cf_disable_ptr.save()
|
|
116
|
+
if options.get("verbosity"):
|
|
117
|
+
self.stdout.write(
|
|
118
|
+
"Updated custom field 'ipaddress_dns_record_disable_ptr'"
|
|
119
|
+
)
|
|
120
|
+
except CustomField.DoesNotExist:
|
|
105
121
|
cf_disable_ptr = CustomField.objects.create(
|
|
106
122
|
name="ipaddress_dns_record_disable_ptr",
|
|
107
123
|
description="Disable DNS PTR record generation for this address",
|
|
@@ -114,7 +130,7 @@ class Command(BaseCommand):
|
|
|
114
130
|
weight=300,
|
|
115
131
|
)
|
|
116
132
|
cf_disable_ptr.object_types.set([ipaddress_object_type])
|
|
117
|
-
if options.get("verbosity")
|
|
133
|
+
if options.get("verbosity"):
|
|
118
134
|
self.stdout.write(
|
|
119
135
|
"Created custom field 'ipaddress_dns_record_disable_ptr'"
|
|
120
136
|
)
|
netbox_dns/models/record.py
CHANGED
|
@@ -562,13 +562,41 @@ class Record(ObjectModificationMixin, NetBoxModel):
|
|
|
562
562
|
if self.pk is not None:
|
|
563
563
|
records = records.exclude(pk=self.pk)
|
|
564
564
|
|
|
565
|
-
if
|
|
565
|
+
if records.exists():
|
|
566
|
+
if self.ipam_ip_address is not None:
|
|
567
|
+
if not records.filter(
|
|
568
|
+
ipam_ip_address__isnull=True
|
|
569
|
+
).exists() or get_plugin_config(
|
|
570
|
+
"netbox_dns", "autodns_conflict_deactivate", False
|
|
571
|
+
):
|
|
572
|
+
return
|
|
573
|
+
|
|
566
574
|
raise ValidationError(
|
|
567
575
|
{
|
|
568
576
|
"value": f"There is already an active {self.type} record for name {self.name} in zone {self.zone} with value {self.value}."
|
|
569
577
|
}
|
|
570
578
|
) from None
|
|
571
579
|
|
|
580
|
+
def handle_conflicting_address_records(self):
|
|
581
|
+
if self.ipam_ip_address is None or not self.is_active:
|
|
582
|
+
return
|
|
583
|
+
|
|
584
|
+
if not get_plugin_config("netbox_dns", "autodns_conflict_deactivate", False):
|
|
585
|
+
return
|
|
586
|
+
|
|
587
|
+
records = Record.objects.filter(
|
|
588
|
+
zone=self.zone,
|
|
589
|
+
name=self.name,
|
|
590
|
+
type=self.type,
|
|
591
|
+
value=self.value,
|
|
592
|
+
status__in=Record.ACTIVE_STATUS_LIST,
|
|
593
|
+
ipam_ip_address__isnull=True,
|
|
594
|
+
)
|
|
595
|
+
|
|
596
|
+
for record in records:
|
|
597
|
+
record.status = RecordStatusChoices.STATUS_INACTIVE
|
|
598
|
+
record.save(update_fields=["status"])
|
|
599
|
+
|
|
572
600
|
def check_unique_rrset_ttl(self):
|
|
573
601
|
if self.pk is not None:
|
|
574
602
|
return
|
|
@@ -587,8 +615,12 @@ class Record(ObjectModificationMixin, NetBoxModel):
|
|
|
587
615
|
)
|
|
588
616
|
.exclude(ttl=self.ttl)
|
|
589
617
|
.exclude(type=RecordTypeChoices.PTR, managed=True)
|
|
618
|
+
.exclude(status=RecordStatusChoices.STATUS_INACTIVE)
|
|
590
619
|
)
|
|
591
620
|
|
|
621
|
+
if self.ipam_ip_address is not None:
|
|
622
|
+
records = records.exclude(ipam_ip_address__isnull=False)
|
|
623
|
+
|
|
592
624
|
if not records.exists():
|
|
593
625
|
return
|
|
594
626
|
|
|
@@ -621,6 +653,7 @@ class Record(ObjectModificationMixin, NetBoxModel):
|
|
|
621
653
|
.exclude(pk=self.pk)
|
|
622
654
|
.exclude(ttl=ttl)
|
|
623
655
|
.exclude(type=RecordTypeChoices.PTR, managed=True)
|
|
656
|
+
.exclude(status=RecordStatusChoices.STATUS_INACTIVE)
|
|
624
657
|
)
|
|
625
658
|
|
|
626
659
|
for record in records:
|
|
@@ -740,6 +773,7 @@ class Record(ObjectModificationMixin, NetBoxModel):
|
|
|
740
773
|
self.ip_address = None
|
|
741
774
|
|
|
742
775
|
if self.is_address_record:
|
|
776
|
+
self.handle_conflicting_address_records()
|
|
743
777
|
self.update_ptr_record(
|
|
744
778
|
update_rfc2317_cname=update_rfc2317_cname,
|
|
745
779
|
save_zone_serial=save_zone_serial,
|
netbox_dns/models/zone.py
CHANGED
|
@@ -28,6 +28,7 @@ from netbox_dns.choices import RecordClassChoices, RecordTypeChoices, ZoneStatus
|
|
|
28
28
|
from netbox_dns.fields import NetworkField, RFC2317NetworkField
|
|
29
29
|
from netbox_dns.utilities import (
|
|
30
30
|
update_dns_records,
|
|
31
|
+
check_dns_records,
|
|
31
32
|
get_ip_addresses_by_zone,
|
|
32
33
|
arpa_to_prefix,
|
|
33
34
|
name_to_unicode,
|
|
@@ -652,6 +653,19 @@ class Zone(ObjectModificationMixin, NetBoxModel):
|
|
|
652
653
|
}
|
|
653
654
|
)
|
|
654
655
|
|
|
656
|
+
if old_zone.name != self.name or old_zone.view != self.view:
|
|
657
|
+
update_ip_addresses = IPAddress.objects.filter(
|
|
658
|
+
pk__in=self.record_set.filter(
|
|
659
|
+
ipam_ip_address__isnull=False
|
|
660
|
+
).values_list("ipam_ip_address", flat=True)
|
|
661
|
+
)
|
|
662
|
+
update_ip_addresses |= get_ip_addresses_by_zone(self)
|
|
663
|
+
for ip_address in update_ip_addresses:
|
|
664
|
+
try:
|
|
665
|
+
check_dns_records(ip_address, zone=self)
|
|
666
|
+
except ValidationError as exc:
|
|
667
|
+
raise ValidationError(exc.messages)
|
|
668
|
+
|
|
655
669
|
if self.is_reverse_zone:
|
|
656
670
|
self.arpa_network = self.network_from_name
|
|
657
671
|
|
|
@@ -11,6 +11,8 @@ from utilities.exceptions import AbortRequest
|
|
|
11
11
|
|
|
12
12
|
from netbox_dns.models import view as _view
|
|
13
13
|
from netbox_dns.utilities import (
|
|
14
|
+
check_dns_records,
|
|
15
|
+
check_record_permission,
|
|
14
16
|
update_dns_records,
|
|
15
17
|
delete_dns_records,
|
|
16
18
|
get_views_by_prefix,
|
|
@@ -18,22 +20,52 @@ from netbox_dns.utilities import (
|
|
|
18
20
|
get_ip_addresses_by_view,
|
|
19
21
|
)
|
|
20
22
|
|
|
23
|
+
AUTODNS_CUSTOM_FIELDS = {
|
|
24
|
+
"ipaddress_dns_disabled": False,
|
|
25
|
+
"ipaddress_dns_record_ttl": None,
|
|
26
|
+
"ipaddress_dns_record_disable_ptr": False,
|
|
27
|
+
}
|
|
28
|
+
|
|
21
29
|
|
|
22
30
|
@receiver(post_clean, sender=IPAddress)
|
|
23
31
|
def ipam_autodns_ipaddress_post_clean(instance, **kwargs):
|
|
24
32
|
if not isinstance(instance.address, IPNetwork):
|
|
25
33
|
return
|
|
26
34
|
|
|
35
|
+
# +
|
|
36
|
+
# Check NetBox DNS record permission for changes to IPAddress custom fields
|
|
37
|
+
#
|
|
38
|
+
# Normally, as the modfication of DNS fields
|
|
39
|
+
if (request := current_request.get()) is not None:
|
|
40
|
+
cf_data = instance.custom_field_data
|
|
41
|
+
if (
|
|
42
|
+
instance.pk is not None
|
|
43
|
+
and any(
|
|
44
|
+
(
|
|
45
|
+
cf_data.get(cf)
|
|
46
|
+
!= IPAddress.objects.get(pk=instance.pk).custom_field_data.get(cf)
|
|
47
|
+
for cf in AUTODNS_CUSTOM_FIELDS.keys()
|
|
48
|
+
)
|
|
49
|
+
)
|
|
50
|
+
and not check_record_permission(request)
|
|
51
|
+
) or (
|
|
52
|
+
instance.pk is None
|
|
53
|
+
and any(
|
|
54
|
+
(
|
|
55
|
+
cf_data.get(cf) != cf_default
|
|
56
|
+
for cf, cf_default in AUTODNS_CUSTOM_FIELDS.items()
|
|
57
|
+
)
|
|
58
|
+
)
|
|
59
|
+
and not check_record_permission(request, change=False, delete=False)
|
|
60
|
+
):
|
|
61
|
+
raise ValidationError(
|
|
62
|
+
f"User '{request.user}' is not allowed to alter AutoDNS custom fields"
|
|
63
|
+
)
|
|
64
|
+
|
|
27
65
|
try:
|
|
28
|
-
|
|
66
|
+
check_dns_records(instance)
|
|
29
67
|
except ValidationError as exc:
|
|
30
|
-
|
|
31
|
-
for field in ("name", "ttl", "value", "type"):
|
|
32
|
-
value = exc.error_dict.pop(field, None)
|
|
33
|
-
if value is not None:
|
|
34
|
-
raise ValidationError({"dns_name": value})
|
|
35
|
-
|
|
36
|
-
raise exc
|
|
68
|
+
raise ValidationError({"dns_name": exc.messages})
|
|
37
69
|
|
|
38
70
|
|
|
39
71
|
@receiver(pre_delete, sender=IPAddress)
|
|
@@ -42,8 +74,8 @@ def ipam_autodns_ipaddress_pre_delete(instance, **kwargs):
|
|
|
42
74
|
|
|
43
75
|
|
|
44
76
|
@receiver(pre_save, sender=IPAddress)
|
|
45
|
-
def
|
|
46
|
-
|
|
77
|
+
def ipam_autodns_ipaddress_pre_save(instance, **kwargs):
|
|
78
|
+
check_dns_records(instance)
|
|
47
79
|
|
|
48
80
|
|
|
49
81
|
@receiver(post_save, sender=IPAddress)
|
|
@@ -80,7 +112,7 @@ def ipam_autodns_prefix_pre_delete(instance, **kwargs):
|
|
|
80
112
|
_depth=instance.depth + 1, netbox_dns_views__isnull=True
|
|
81
113
|
):
|
|
82
114
|
for ip_address in get_ip_addresses_by_prefix(prefix):
|
|
83
|
-
|
|
115
|
+
check_dns_records(ip_address)
|
|
84
116
|
except ValidationError as exc:
|
|
85
117
|
if request is not None:
|
|
86
118
|
raise AbortRequest(
|
|
@@ -45,15 +45,11 @@
|
|
|
45
45
|
{% for prefix in object.prefixes.all %}
|
|
46
46
|
<tr>
|
|
47
47
|
<td>
|
|
48
|
-
|
|
49
|
-
{{ prefix }}
|
|
50
|
-
</a>
|
|
48
|
+
{{ prefix|linkify }}
|
|
51
49
|
</td>
|
|
52
50
|
{% if prefix.vrf %}
|
|
53
51
|
<td>
|
|
54
|
-
|
|
55
|
-
{{ prefix.vrf }}
|
|
56
|
-
</a>
|
|
52
|
+
{{ prefix.vrf|linkify }}
|
|
57
53
|
</td>
|
|
58
54
|
{% else %}
|
|
59
55
|
<td>Global</td>
|
|
@@ -7,6 +7,7 @@ from dns import name as dns_name
|
|
|
7
7
|
from django.conf import settings
|
|
8
8
|
from django.db.models import Q
|
|
9
9
|
|
|
10
|
+
from netbox.context import current_request
|
|
10
11
|
from ipam.models import IPAddress, Prefix
|
|
11
12
|
|
|
12
13
|
from netbox_dns.models import zone as _zone
|
|
@@ -16,12 +17,14 @@ from netbox_dns.models import view as _view
|
|
|
16
17
|
|
|
17
18
|
__all__ = (
|
|
18
19
|
"get_zones",
|
|
20
|
+
"check_dns_records",
|
|
19
21
|
"update_dns_records",
|
|
20
22
|
"delete_dns_records",
|
|
21
23
|
"get_views_by_prefix",
|
|
22
24
|
"get_ip_addresses_by_prefix",
|
|
23
25
|
"get_ip_addresses_by_view",
|
|
24
26
|
"get_ip_addresses_by_zone",
|
|
27
|
+
"check_record_permission",
|
|
25
28
|
)
|
|
26
29
|
|
|
27
30
|
|
|
@@ -82,19 +85,54 @@ def get_zones(ip_address, view=None):
|
|
|
82
85
|
]
|
|
83
86
|
|
|
84
87
|
|
|
85
|
-
def
|
|
88
|
+
def check_dns_records(ip_address, zone=None, view=None):
|
|
86
89
|
if ip_address.dns_name == "":
|
|
87
|
-
if commit:
|
|
88
|
-
delete_dns_records(ip_address)
|
|
89
90
|
return
|
|
90
91
|
|
|
91
|
-
|
|
92
|
+
if zone is None:
|
|
93
|
+
zones = get_zones(ip_address, view=view)
|
|
94
|
+
else:
|
|
95
|
+
zones = [zone]
|
|
96
|
+
|
|
97
|
+
if ip_address.pk is not None:
|
|
98
|
+
for record in ip_address.netbox_dns_records.filter(zone__in=zones):
|
|
99
|
+
if (
|
|
100
|
+
record.fqdn != ip_address.dns_name
|
|
101
|
+
or record.value != ip_address.address.ip
|
|
102
|
+
or record.status != _get_record_status(ip_address)
|
|
103
|
+
):
|
|
104
|
+
record.update_from_ip_address(ip_address)
|
|
105
|
+
|
|
106
|
+
if record is not None:
|
|
107
|
+
record.clean()
|
|
108
|
+
|
|
109
|
+
zones = _zone.Zone.objects.filter(pk__in=[zone.pk for zone in zones]).exclude(
|
|
110
|
+
pk__in=set(
|
|
111
|
+
ip_address.netbox_dns_records.all().values_list("zone", flat=True)
|
|
112
|
+
)
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
for zone in zones:
|
|
116
|
+
record = _record.Record.create_from_ip_address(
|
|
117
|
+
ip_address,
|
|
118
|
+
zone,
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
if record is not None:
|
|
122
|
+
record.clean()
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def update_dns_records(ip_address):
|
|
126
|
+
if ip_address.dns_name == "":
|
|
127
|
+
delete_dns_records(ip_address)
|
|
128
|
+
return
|
|
129
|
+
|
|
130
|
+
zones = get_zones(ip_address)
|
|
92
131
|
|
|
93
132
|
if ip_address.pk is not None:
|
|
94
133
|
for record in ip_address.netbox_dns_records.all():
|
|
95
134
|
if record.zone not in zones:
|
|
96
|
-
|
|
97
|
-
record.delete()
|
|
135
|
+
record.delete()
|
|
98
136
|
continue
|
|
99
137
|
|
|
100
138
|
if (
|
|
@@ -105,13 +143,12 @@ def update_dns_records(ip_address, commit=True, view=None):
|
|
|
105
143
|
record.update_from_ip_address(ip_address)
|
|
106
144
|
|
|
107
145
|
if record is not None:
|
|
108
|
-
|
|
109
|
-
record.save()
|
|
110
|
-
else:
|
|
111
|
-
record.clean()
|
|
146
|
+
record.save()
|
|
112
147
|
|
|
113
|
-
zones =
|
|
114
|
-
|
|
148
|
+
zones = _zone.Zone.objects.filter(pk__in=[zone.pk for zone in zones]).exclude(
|
|
149
|
+
pk__in=set(
|
|
150
|
+
ip_address.netbox_dns_records.all().values_list("zone", flat=True)
|
|
151
|
+
)
|
|
115
152
|
)
|
|
116
153
|
|
|
117
154
|
for zone in zones:
|
|
@@ -121,10 +158,7 @@ def update_dns_records(ip_address, commit=True, view=None):
|
|
|
121
158
|
)
|
|
122
159
|
|
|
123
160
|
if record is not None:
|
|
124
|
-
|
|
125
|
-
record.save()
|
|
126
|
-
else:
|
|
127
|
-
record.clean()
|
|
161
|
+
record.save()
|
|
128
162
|
|
|
129
163
|
|
|
130
164
|
def delete_dns_records(ip_address):
|
|
@@ -203,3 +237,20 @@ def get_ip_addresses_by_zone(zone):
|
|
|
203
237
|
queryset = get_ip_addresses_by_view(zone.view)
|
|
204
238
|
|
|
205
239
|
return queryset.filter(dns_name__regex=rf"\.{re.escape(zone.name)}\.?$")
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
def check_record_permission(add=True, change=True, delete=True):
|
|
243
|
+
checks = locals()
|
|
244
|
+
|
|
245
|
+
request = current_request.get()
|
|
246
|
+
|
|
247
|
+
if request is None:
|
|
248
|
+
return True
|
|
249
|
+
|
|
250
|
+
return all(
|
|
251
|
+
(
|
|
252
|
+
request.user.has_perm(f"nebox_dns.{perm}_record")
|
|
253
|
+
for perm, check in locals().items()
|
|
254
|
+
if check
|
|
255
|
+
)
|
|
256
|
+
)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: netbox-plugin-dns
|
|
3
|
-
Version: 1.1.
|
|
3
|
+
Version: 1.1.0b2
|
|
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
|
|
@@ -8,7 +8,7 @@ Keywords: netbox,netbox-plugin,dns
|
|
|
8
8
|
Author: Peter Eckel
|
|
9
9
|
Author-email: pete@netbox-dns.org
|
|
10
10
|
Requires-Python: >=3.10,<4.0
|
|
11
|
-
Classifier: Development Status ::
|
|
11
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
12
12
|
Classifier: License :: OSI Approved :: MIT License
|
|
13
13
|
Classifier: Programming Language :: Python :: 3
|
|
14
14
|
Classifier: Programming Language :: Python :: 3.10
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
netbox_dns/__init__.py,sha256=
|
|
1
|
+
netbox_dns/__init__.py,sha256=Jdvrhj7X8a6ZTLJf0EYzWJyhawP_uJc3GSdg5USr3nw,1835
|
|
2
2
|
netbox_dns/api/nested_serializers.py,sha256=-ZhAiyf-8UHlkcBomBp1J7ci1dSwrxWRbbfskD-D_yQ,3172
|
|
3
3
|
netbox_dns/api/serializers.py,sha256=u-kQurUftGkUGAMh-VkMgXPebLYeZq9WDz9uKzkk2No,370
|
|
4
4
|
netbox_dns/api/serializers_/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -37,7 +37,7 @@ netbox_dns/forms/nameserver.py,sha256=LHomCHmFcASobaD3Z7yhAyA24h-LrYImVMz-EUXbwK
|
|
|
37
37
|
netbox_dns/forms/record.py,sha256=svBVAFy-egDEPLcRWkxNi_1bkabKmWgJ87pmdNt6dh4,7155
|
|
38
38
|
netbox_dns/forms/record_template.py,sha256=Q77p9sExJ8Xbl-Co2Px2R0At5O3naQJwx4pnino6i2o,5573
|
|
39
39
|
netbox_dns/forms/registrar.py,sha256=FMnvrcq62R3wNp_2ZUEk3v_PIav0KrWPATaJ7_9KFAo,3758
|
|
40
|
-
netbox_dns/forms/view.py,sha256=
|
|
40
|
+
netbox_dns/forms/view.py,sha256=CSMpWmjKQdfBMILdLLyOjY6o27W3mZgAVIBGjCiPS78,6144
|
|
41
41
|
netbox_dns/forms/zone.py,sha256=ZbsYcWX-t1luqBsLj4vec0IZG0lmCwGW5nzVh77qJrw,23164
|
|
42
42
|
netbox_dns/forms/zone_template.py,sha256=UNykid5pRB_ydy40j2DzRlBXp3_QAOqdqxdUojKYTd4,8161
|
|
43
43
|
netbox_dns/graphql/__init__.py,sha256=ZZSsx-VM108tB_FrcVy3uGGhtmePpkXnY5U1ytnoTvE,490
|
|
@@ -46,7 +46,7 @@ netbox_dns/graphql/schema.py,sha256=P-oQ8ei3sC6XLhgCa_riRbRTrMkPCVTJXkGv0U2rPYw,
|
|
|
46
46
|
netbox_dns/graphql/types.py,sha256=4ewWOqEbWtCBiU9bdIm_6CIm6MKAM6szCAXSvokpqWg,6108
|
|
47
47
|
netbox_dns/management/commands/cleanup_database.py,sha256=kfnyybudwKGigjJmrOwafPWSUasZr9jQsxN4eWAgMvY,5969
|
|
48
48
|
netbox_dns/management/commands/cleanup_rrset_ttl.py,sha256=UFRURLBcFeGHUS2lrYFv7UWIebjI72aG1EUQJt0XsXw,2046
|
|
49
|
-
netbox_dns/management/commands/setup_autodns.py,sha256=
|
|
49
|
+
netbox_dns/management/commands/setup_autodns.py,sha256=kX1T7VjMZ0BPuT_zte6VO6xqOSpYJXaYNfu5dxlrZLc,5507
|
|
50
50
|
netbox_dns/management/commands/update_soa.py,sha256=Rj_Xk-qpwkAVRubVnM5OqSTwgzi93E0PqjwGb3rYjf0,660
|
|
51
51
|
netbox_dns/migrations/0001_squashed_netbox_dns_0_15.py,sha256=3U0810NWSHPu2dTSHpfzlleDgwMS04FhJ_CkO76SDaw,10283
|
|
52
52
|
netbox_dns/migrations/0001_squashed_netbox_dns_0_22.py,sha256=ML6Hp17lrXiaG0eUlBjKMm6HUNhw0AHPnKrb9AN-F6E,20279
|
|
@@ -72,15 +72,15 @@ netbox_dns/mixins/object_modification.py,sha256=JbGi8a52wkZ3fFBlfat590CfqRJcEWxB
|
|
|
72
72
|
netbox_dns/models/__init__.py,sha256=wjwNsRttUVYQHZODZi806a_iUDoq_o7mdKObqh1N7N4,300
|
|
73
73
|
netbox_dns/models/contact.py,sha256=oNLyD_6TOTNQQTcCvv6TAC7OkzPTMIRy2NP5nwNKaNg,3009
|
|
74
74
|
netbox_dns/models/nameserver.py,sha256=yKo4Fwqnv5VtTndU2px7tRS3voF3Cal7OWQ6AImLwl0,3208
|
|
75
|
-
netbox_dns/models/record.py,sha256=
|
|
75
|
+
netbox_dns/models/record.py,sha256=99Ys3daxvTJuUP6NeTJrEx8Du5C8c70zk8R7S_8YWAs,25703
|
|
76
76
|
netbox_dns/models/record_template.py,sha256=3t9VceviX3kNIo5o0VPVFupLFDqPxpHIVLp5U3pBKB4,4661
|
|
77
77
|
netbox_dns/models/registrar.py,sha256=T_oMUlTWTDixOVlIbEZGvOBdvUrKxRkkS41xgM2Oee8,1557
|
|
78
78
|
netbox_dns/models/view.py,sha256=SYmhNYyRCv0rSCK5jrHtug4QgfWCBbjsAjZEEHk02QU,2873
|
|
79
|
-
netbox_dns/models/zone.py,sha256=
|
|
79
|
+
netbox_dns/models/zone.py,sha256=clKeoQ7ECYMKwIbqXnszOkuCRGC1_Q6N3q5xTUg8yoY,28905
|
|
80
80
|
netbox_dns/models/zone_template.py,sha256=lkiSIfx8KM0Cs3Mb3dLBxKbSpcssVUzQiSmD5W46was,3753
|
|
81
81
|
netbox_dns/navigation.py,sha256=EITDZkbpu4KCC9u4Noj7OORWnkL3EYT2RIRvYlTw34Q,5961
|
|
82
82
|
netbox_dns/signals/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
83
|
-
netbox_dns/signals/ipam_autodns.py,sha256=
|
|
83
|
+
netbox_dns/signals/ipam_autodns.py,sha256=HJkDU7BZHGFb02YlZHtCTRyKQiR3ZxSwempo-NdQ3o4,5779
|
|
84
84
|
netbox_dns/tables/__init__.py,sha256=s41w4o77tIwmhnLjsOsg08R9m3wrlomkkfCLTVQuPzc,196
|
|
85
85
|
netbox_dns/tables/contact.py,sha256=sPs7d1ZhVC5dOS37dPYFqebNd7WGvsV_eYzX_TMcbzY,804
|
|
86
86
|
netbox_dns/tables/nameserver.py,sha256=fFiE-yH-_GyRDaV4SVw094r6uH58Kx56NSWDGaMR58g,764
|
|
@@ -99,7 +99,7 @@ netbox_dns/templates/netbox_dns/record.html,sha256=o3z_D6Fqqn7nx1IwPXKQ75ZaPhU6k
|
|
|
99
99
|
netbox_dns/templates/netbox_dns/recordtemplate.html,sha256=9tkXtKqa5p3LdOU9REm99WSFwGJaH8OczpIqXZuXMcg,3099
|
|
100
100
|
netbox_dns/templates/netbox_dns/registrar.html,sha256=O5veGmW59Pf5yN25ihPLvRIkA2P7xmSGv0G3NrRG8vI,2152
|
|
101
101
|
netbox_dns/templates/netbox_dns/view/related.html,sha256=W9Ie2aOsFkWyYtBnZn38seQDBmyJkV9dqFDG-Dq3yMk,736
|
|
102
|
-
netbox_dns/templates/netbox_dns/view.html,sha256=
|
|
102
|
+
netbox_dns/templates/netbox_dns/view.html,sha256=NSEfPSHPLw5yjUSat9N_KYKF5FezmTlCXqPC6FYiK9E,2479
|
|
103
103
|
netbox_dns/templates/netbox_dns/zone/base.html,sha256=n_E4aVYdGeZZl-ARE8sb4DgAAgPs92X1UEFepX3xIlM,495
|
|
104
104
|
netbox_dns/templates/netbox_dns/zone/child.html,sha256=kH56PJFBGCjiRdIh7zCtClnZdfOChqN_sYslsyoz5gU,2147
|
|
105
105
|
netbox_dns/templates/netbox_dns/zone/child_zone.html,sha256=b9CSGWEfWT7hLQ80gApMnu7mXM8w2LT-3UaOYe6HIRQ,510
|
|
@@ -120,7 +120,7 @@ netbox_dns/urls/zone.py,sha256=rmB1BkzmWNG06ILUf-39Aj6-SBFkwQouyixMQiamqPc,2005
|
|
|
120
120
|
netbox_dns/urls/zone_template.py,sha256=w3Gu8qfLCWyHofeLkGZd1HpYSlcslomVlBQJZyqh8kk,1690
|
|
121
121
|
netbox_dns/utilities/__init__.py,sha256=M9T8PUFlGddtENzEznHAPbEsz1VFrPcmbD-BGLCsvB4,55
|
|
122
122
|
netbox_dns/utilities/conversions.py,sha256=NS37SoMqXc13wNWRkKnLfyQbVi6QKD33fu5ovTKRo74,1979
|
|
123
|
-
netbox_dns/utilities/ipam_autodns.py,sha256=
|
|
123
|
+
netbox_dns/utilities/ipam_autodns.py,sha256=Wit1MoJbPlYIUMfft13u7LY_Lr_zOb13DGkxIS-n-98,7338
|
|
124
124
|
netbox_dns/validators/__init__.py,sha256=Mr8TvmcJTa8Pubj8TzbFBKfbHhEmGcr5JdQvczEJ39A,72
|
|
125
125
|
netbox_dns/validators/dns_name.py,sha256=B4A0BOW5pKDjjukvksriRtnLzkYTx_pFjh7eqKo6PBE,3069
|
|
126
126
|
netbox_dns/validators/dns_value.py,sha256=y2Zga4hmywqDrTBXcMC-sWaFbw4eoY8pySq7cWnMP8Y,2822
|
|
@@ -134,7 +134,7 @@ netbox_dns/views/registrar.py,sha256=yRQgFm3vgBD21ZQex9asjs0QWegvSHlcyHXLnjvc5xs
|
|
|
134
134
|
netbox_dns/views/view.py,sha256=I_hVZYFJF8GTnlUKPrTgBk_x9UDCbZXM8R7U5Bhizjs,2107
|
|
135
135
|
netbox_dns/views/zone.py,sha256=SKhf_WHcFVpKqFTuUMf-Dmxu1AwFHBeo_DtD8UGFrJ8,5483
|
|
136
136
|
netbox_dns/views/zone_template.py,sha256=qvXl-bpc1fMc1WFngynj4-Q3-JJDgKdT-r54s4M1D0s,2118
|
|
137
|
-
netbox_plugin_dns-1.1.
|
|
138
|
-
netbox_plugin_dns-1.1.
|
|
139
|
-
netbox_plugin_dns-1.1.
|
|
140
|
-
netbox_plugin_dns-1.1.
|
|
137
|
+
netbox_plugin_dns-1.1.0b2.dist-info/LICENSE,sha256=I3tDu11bZfhFm3EkV4zOD5TmWgLjnUNLEFwrdjniZYs,1112
|
|
138
|
+
netbox_plugin_dns-1.1.0b2.dist-info/METADATA,sha256=V0TQOjdcjkw1vAf_Ih85cV2vr0xgG_10VEJkn8a2BBw,6406
|
|
139
|
+
netbox_plugin_dns-1.1.0b2.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
|
140
|
+
netbox_plugin_dns-1.1.0b2.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|