netbox-plugin-dns 1.2.5__py3-none-any.whl → 1.2.7__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 +16 -8
- netbox_dns/api/field_serializers.py +25 -0
- netbox_dns/api/nested_serializers.py +19 -1
- netbox_dns/api/serializers.py +3 -0
- netbox_dns/api/serializers_/dnssec_key_template.py +59 -0
- netbox_dns/api/serializers_/dnssec_policy.py +113 -0
- netbox_dns/api/serializers_/record.py +2 -0
- netbox_dns/api/serializers_/record_template.py +2 -0
- netbox_dns/api/serializers_/zone.py +20 -1
- netbox_dns/api/serializers_/zone_template.py +13 -4
- netbox_dns/api/urls.py +4 -0
- netbox_dns/api/views.py +18 -0
- netbox_dns/choices/__init__.py +2 -0
- netbox_dns/choices/dnssec_key_template.py +63 -0
- netbox_dns/choices/dnssec_policy.py +40 -0
- netbox_dns/choices/record.py +2 -25
- netbox_dns/choices/utilities.py +26 -0
- netbox_dns/choices/zone.py +96 -1
- netbox_dns/fields/__init__.py +2 -0
- netbox_dns/fields/choice_array.py +33 -0
- netbox_dns/fields/timeperiod.py +33 -0
- netbox_dns/filtersets/__init__.py +3 -0
- netbox_dns/filtersets/dnssec_key_template.py +51 -0
- netbox_dns/filtersets/dnssec_policy.py +97 -0
- netbox_dns/filtersets/zone.py +30 -6
- netbox_dns/filtersets/zone_template.py +13 -2
- netbox_dns/forms/__init__.py +2 -0
- netbox_dns/forms/dnssec_key_template.py +189 -0
- netbox_dns/forms/dnssec_policy.py +593 -0
- netbox_dns/forms/nameserver.py +2 -0
- netbox_dns/forms/record.py +12 -6
- netbox_dns/forms/record_template.py +10 -3
- netbox_dns/forms/zone.py +142 -31
- netbox_dns/forms/zone_template.py +38 -0
- netbox_dns/graphql/__init__.py +7 -3
- netbox_dns/graphql/filters.py +16 -0
- netbox_dns/graphql/schema.py +20 -0
- netbox_dns/graphql/types.py +67 -3
- netbox_dns/locale/de/LC_MESSAGES/django.mo +0 -0
- netbox_dns/locale/fr/LC_MESSAGES/django.mo +0 -0
- netbox_dns/migrations/0015_dnssec.py +168 -0
- netbox_dns/migrations/0016_dnssec_policy_status.py +18 -0
- netbox_dns/migrations/0017_dnssec_policy_zone_zone_template.py +41 -0
- netbox_dns/migrations/0018_zone_domain_status_zone_expiration_date.py +23 -0
- netbox_dns/models/__init__.py +2 -0
- netbox_dns/models/dnssec_key_template.py +114 -0
- netbox_dns/models/dnssec_policy.py +203 -0
- netbox_dns/models/record.py +1 -1
- netbox_dns/models/zone.py +74 -19
- netbox_dns/models/zone_template.py +17 -7
- netbox_dns/navigation.py +49 -0
- netbox_dns/signals/dnssec.py +32 -0
- netbox_dns/tables/__init__.py +2 -0
- netbox_dns/tables/dnssec_key_template.py +48 -0
- netbox_dns/tables/dnssec_policy.py +131 -0
- netbox_dns/tables/zone.py +23 -2
- netbox_dns/tables/zone_template.py +4 -0
- netbox_dns/template_content.py +2 -1
- netbox_dns/templates/netbox_dns/dnsseckeytemplate.html +70 -0
- netbox_dns/templates/netbox_dns/dnssecpolicy.html +155 -0
- netbox_dns/templates/netbox_dns/zone/registration.html +19 -0
- netbox_dns/templates/netbox_dns/zone.html +16 -0
- netbox_dns/templates/netbox_dns/zonetemplate/child.html +46 -0
- netbox_dns/templates/netbox_dns/zonetemplate.html +12 -0
- netbox_dns/urls.py +23 -0
- netbox_dns/utilities/conversions.py +13 -0
- netbox_dns/validators/__init__.py +1 -0
- netbox_dns/validators/dnssec.py +148 -0
- netbox_dns/views/__init__.py +2 -0
- netbox_dns/views/dnssec_key_template.py +87 -0
- netbox_dns/views/dnssec_policy.py +155 -0
- netbox_dns/views/zone.py +11 -1
- {netbox_plugin_dns-1.2.5.dist-info → netbox_plugin_dns-1.2.7.dist-info}/METADATA +3 -2
- {netbox_plugin_dns-1.2.5.dist-info → netbox_plugin_dns-1.2.7.dist-info}/RECORD +77 -49
- {netbox_plugin_dns-1.2.5.dist-info → netbox_plugin_dns-1.2.7.dist-info}/WHEEL +1 -1
- {netbox_plugin_dns-1.2.5.dist-info → netbox_plugin_dns-1.2.7.dist-info/licenses}/LICENSE +0 -0
- {netbox_plugin_dns-1.2.5.dist-info → netbox_plugin_dns-1.2.7.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
from django.db import models
|
|
2
|
+
from django.urls import reverse
|
|
3
|
+
from django.utils.translation import gettext_lazy as _
|
|
4
|
+
|
|
5
|
+
from netbox.models import NetBoxModel
|
|
6
|
+
from netbox.search import SearchIndex, register_search
|
|
7
|
+
from netbox.models.features import ContactsMixin
|
|
8
|
+
from netbox.plugins.utils import get_plugin_config
|
|
9
|
+
|
|
10
|
+
from netbox_dns.choices import DNSSECPolicyDigestChoices, DNSSECPolicyStatusChoices
|
|
11
|
+
from netbox_dns.fields import ChoiceArrayField
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
__all__ = (
|
|
15
|
+
"DNSSECPolicy",
|
|
16
|
+
"DNSSECPolicyIndex",
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class DNSSECPolicy(ContactsMixin, NetBoxModel):
|
|
21
|
+
name = models.CharField(
|
|
22
|
+
verbose_name=_("Name"),
|
|
23
|
+
max_length=255,
|
|
24
|
+
unique=True,
|
|
25
|
+
)
|
|
26
|
+
description = models.CharField(
|
|
27
|
+
verbose_name=_("Description"),
|
|
28
|
+
max_length=200,
|
|
29
|
+
blank=True,
|
|
30
|
+
)
|
|
31
|
+
status = models.CharField(
|
|
32
|
+
verbose_name=_("Status"),
|
|
33
|
+
choices=DNSSECPolicyStatusChoices,
|
|
34
|
+
default=DNSSECPolicyStatusChoices.STATUS_ACTIVE,
|
|
35
|
+
blank=False,
|
|
36
|
+
null=False,
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
key_templates = models.ManyToManyField(
|
|
40
|
+
verbose_name=_("Key Templates"),
|
|
41
|
+
to="DNSSECKeyTemplate",
|
|
42
|
+
related_name="policies",
|
|
43
|
+
blank=True,
|
|
44
|
+
)
|
|
45
|
+
dnskey_ttl = models.PositiveIntegerField(
|
|
46
|
+
verbose_name=_("DNSKEY TTL"),
|
|
47
|
+
blank=True,
|
|
48
|
+
null=True,
|
|
49
|
+
)
|
|
50
|
+
purge_keys = models.PositiveIntegerField(
|
|
51
|
+
verbose_name=_("Purge Keys"),
|
|
52
|
+
blank=True,
|
|
53
|
+
null=True,
|
|
54
|
+
)
|
|
55
|
+
publish_safety = models.PositiveIntegerField(
|
|
56
|
+
verbose_name=_("Publish Safety"),
|
|
57
|
+
blank=True,
|
|
58
|
+
null=True,
|
|
59
|
+
)
|
|
60
|
+
retire_safety = models.PositiveIntegerField(
|
|
61
|
+
verbose_name=_("Retire Safety"),
|
|
62
|
+
blank=True,
|
|
63
|
+
null=True,
|
|
64
|
+
)
|
|
65
|
+
signatures_jitter = models.PositiveIntegerField(
|
|
66
|
+
verbose_name=_("Signatures Jitter"),
|
|
67
|
+
blank=True,
|
|
68
|
+
null=True,
|
|
69
|
+
)
|
|
70
|
+
signatures_refresh = models.PositiveIntegerField(
|
|
71
|
+
verbose_name=_("Signatures Refresh"),
|
|
72
|
+
blank=True,
|
|
73
|
+
null=True,
|
|
74
|
+
)
|
|
75
|
+
signatures_validity = models.PositiveIntegerField(
|
|
76
|
+
verbose_name=_("Signatures Validity"),
|
|
77
|
+
blank=True,
|
|
78
|
+
null=True,
|
|
79
|
+
)
|
|
80
|
+
signatures_validity_dnskey = models.PositiveIntegerField(
|
|
81
|
+
verbose_name=_("Signatures Validity for DNSKEY"),
|
|
82
|
+
blank=True,
|
|
83
|
+
null=True,
|
|
84
|
+
)
|
|
85
|
+
max_zone_ttl = models.PositiveIntegerField(
|
|
86
|
+
verbose_name=_("Max Zone TTL"),
|
|
87
|
+
blank=True,
|
|
88
|
+
null=True,
|
|
89
|
+
)
|
|
90
|
+
zone_propagation_delay = models.PositiveIntegerField(
|
|
91
|
+
verbose_name=_("Zone Propagation Delay"),
|
|
92
|
+
blank=True,
|
|
93
|
+
null=True,
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
create_cdnskey = models.BooleanField(
|
|
97
|
+
verbose_name=_("Create CDNSKEY"),
|
|
98
|
+
null=False,
|
|
99
|
+
default=True,
|
|
100
|
+
)
|
|
101
|
+
cds_digest_types = ChoiceArrayField(
|
|
102
|
+
base_field=models.CharField(
|
|
103
|
+
choices=DNSSECPolicyDigestChoices,
|
|
104
|
+
),
|
|
105
|
+
verbose_name=_("CDS Digest Types"),
|
|
106
|
+
blank=True,
|
|
107
|
+
null=True,
|
|
108
|
+
default=list,
|
|
109
|
+
)
|
|
110
|
+
parent_ds_ttl = models.PositiveIntegerField(
|
|
111
|
+
verbose_name=_("Parent DS TTL"),
|
|
112
|
+
blank=True,
|
|
113
|
+
null=True,
|
|
114
|
+
)
|
|
115
|
+
parent_propagation_delay = models.PositiveIntegerField(
|
|
116
|
+
verbose_name=_("Parent Propagation Delay"),
|
|
117
|
+
blank=True,
|
|
118
|
+
null=True,
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
use_nsec3 = models.BooleanField(
|
|
122
|
+
verbose_name=_("Use NSEC3"),
|
|
123
|
+
null=False,
|
|
124
|
+
default=True,
|
|
125
|
+
)
|
|
126
|
+
nsec3_iterations = models.PositiveIntegerField(
|
|
127
|
+
verbose_name=_("NSEC3 Iterations"),
|
|
128
|
+
blank=True,
|
|
129
|
+
null=True,
|
|
130
|
+
)
|
|
131
|
+
nsec3_opt_out = models.BooleanField(
|
|
132
|
+
verbose_name=_("NSEC3 Opt-Out"),
|
|
133
|
+
blank=False,
|
|
134
|
+
null=False,
|
|
135
|
+
default=False,
|
|
136
|
+
)
|
|
137
|
+
nsec3_salt_size = models.PositiveIntegerField(
|
|
138
|
+
verbose_name=_("NSEC3 Salt Size"),
|
|
139
|
+
blank=True,
|
|
140
|
+
null=True,
|
|
141
|
+
)
|
|
142
|
+
|
|
143
|
+
tenant = models.ForeignKey(
|
|
144
|
+
verbose_name=_("Tenant"),
|
|
145
|
+
to="tenancy.Tenant",
|
|
146
|
+
on_delete=models.PROTECT,
|
|
147
|
+
related_name="netbox_dns_dnssec_policy",
|
|
148
|
+
blank=True,
|
|
149
|
+
null=True,
|
|
150
|
+
)
|
|
151
|
+
|
|
152
|
+
clone_fields = (
|
|
153
|
+
"name",
|
|
154
|
+
"key_templates",
|
|
155
|
+
"description",
|
|
156
|
+
"tenant",
|
|
157
|
+
)
|
|
158
|
+
|
|
159
|
+
class Meta:
|
|
160
|
+
verbose_name = _("DNSSEC Policy")
|
|
161
|
+
verbose_name_plural = _("DNSSEC Policies")
|
|
162
|
+
|
|
163
|
+
ordering = ("name",)
|
|
164
|
+
|
|
165
|
+
def __str__(self):
|
|
166
|
+
return str(self.name)
|
|
167
|
+
|
|
168
|
+
def get_status_color(self):
|
|
169
|
+
return DNSSECPolicyStatusChoices.colors.get(self.status)
|
|
170
|
+
|
|
171
|
+
# TODO: Remove in version 1.3.0 (NetBox #18555)
|
|
172
|
+
def get_absolute_url(self):
|
|
173
|
+
return reverse("plugins:netbox_dns:dnssecpolicy", kwargs={"pk": self.pk})
|
|
174
|
+
|
|
175
|
+
@property
|
|
176
|
+
def purge_keys_value(self):
|
|
177
|
+
return self.purge_keys if self.purge_keys is not None else 776000
|
|
178
|
+
|
|
179
|
+
@property
|
|
180
|
+
def publish_safety_value(self):
|
|
181
|
+
return self.publish_safety if self.publish_safety is not None else 3600
|
|
182
|
+
|
|
183
|
+
def get_effective_value(self, attribute):
|
|
184
|
+
if not hasattr(self, attribute):
|
|
185
|
+
raise AttributeError(f"DNSSECPolicy does not have attribute {attribute}")
|
|
186
|
+
|
|
187
|
+
if (value := getattr(self, attribute)) is None:
|
|
188
|
+
return self.get_fallback_setting(attribute)
|
|
189
|
+
|
|
190
|
+
return value
|
|
191
|
+
|
|
192
|
+
@classmethod
|
|
193
|
+
def get_fallback_setting(cls, attribute):
|
|
194
|
+
return get_plugin_config("netbox_dns", f"dnssec_{attribute}")
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
@register_search
|
|
198
|
+
class DNSSECPolicyIndex(SearchIndex):
|
|
199
|
+
model = DNSSECPolicy
|
|
200
|
+
fields = (
|
|
201
|
+
("name", 100),
|
|
202
|
+
("description", 500),
|
|
203
|
+
)
|
netbox_dns/models/record.py
CHANGED
|
@@ -167,7 +167,7 @@ class Record(ObjectModificationMixin, ContactsMixin, NetBoxModel):
|
|
|
167
167
|
default=False,
|
|
168
168
|
)
|
|
169
169
|
ptr_record = models.OneToOneField(
|
|
170
|
-
verbose_name="PTR Record",
|
|
170
|
+
verbose_name=_("PTR Record"),
|
|
171
171
|
to="self",
|
|
172
172
|
on_delete=models.SET_NULL,
|
|
173
173
|
related_name="address_record",
|
netbox_dns/models/zone.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import re
|
|
2
2
|
from math import ceil
|
|
3
|
-
from datetime import datetime
|
|
3
|
+
from datetime import datetime, date
|
|
4
4
|
|
|
5
5
|
from dns import name as dns_name
|
|
6
6
|
from dns.exception import DNSException
|
|
@@ -26,7 +26,12 @@ from netbox.plugins.utils import get_plugin_config
|
|
|
26
26
|
from utilities.querysets import RestrictedQuerySet
|
|
27
27
|
from ipam.models import IPAddress
|
|
28
28
|
|
|
29
|
-
from netbox_dns.choices import
|
|
29
|
+
from netbox_dns.choices import (
|
|
30
|
+
RecordClassChoices,
|
|
31
|
+
RecordTypeChoices,
|
|
32
|
+
ZoneStatusChoices,
|
|
33
|
+
ZoneEPPStatusChoices,
|
|
34
|
+
)
|
|
30
35
|
from netbox_dns.fields import NetworkField, RFC2317NetworkField
|
|
31
36
|
from netbox_dns.utilities import (
|
|
32
37
|
update_dns_records,
|
|
@@ -97,6 +102,11 @@ class Zone(ObjectModificationMixin, ContactsMixin, NetBoxModel):
|
|
|
97
102
|
max_length=255,
|
|
98
103
|
db_collation="natural_sort",
|
|
99
104
|
)
|
|
105
|
+
description = models.CharField(
|
|
106
|
+
verbose_name=_("Description"),
|
|
107
|
+
max_length=200,
|
|
108
|
+
blank=True,
|
|
109
|
+
)
|
|
100
110
|
status = models.CharField(
|
|
101
111
|
verbose_name=_("Status"),
|
|
102
112
|
max_length=50,
|
|
@@ -170,25 +180,19 @@ class Zone(ObjectModificationMixin, ContactsMixin, NetBoxModel):
|
|
|
170
180
|
help_text=_("Automatically generate the SOA serial number"),
|
|
171
181
|
default=True,
|
|
172
182
|
)
|
|
173
|
-
|
|
174
|
-
verbose_name=_("
|
|
175
|
-
|
|
176
|
-
blank=True,
|
|
177
|
-
)
|
|
178
|
-
arpa_network = NetworkField(
|
|
179
|
-
verbose_name=_("ARPA Network"),
|
|
180
|
-
help_text=_("Network related to a reverse lookup zone (.arpa)"),
|
|
181
|
-
blank=True,
|
|
182
|
-
null=True,
|
|
183
|
-
)
|
|
184
|
-
tenant = models.ForeignKey(
|
|
185
|
-
verbose_name=_("Tenant"),
|
|
186
|
-
to="tenancy.Tenant",
|
|
183
|
+
dnssec_policy = models.ForeignKey(
|
|
184
|
+
verbose_name=_("DNSSEC Policy"),
|
|
185
|
+
to="DNSSECPolicy",
|
|
187
186
|
on_delete=models.PROTECT,
|
|
188
|
-
related_name="
|
|
187
|
+
related_name="zones",
|
|
189
188
|
blank=True,
|
|
190
189
|
null=True,
|
|
191
190
|
)
|
|
191
|
+
inline_signing = models.BooleanField(
|
|
192
|
+
verbose_name=_("Inline Signing"),
|
|
193
|
+
help_text=_("Use inline signing for DNSSEC"),
|
|
194
|
+
default=True,
|
|
195
|
+
)
|
|
192
196
|
registrar = models.ForeignKey(
|
|
193
197
|
verbose_name=_("Registrar"),
|
|
194
198
|
to="Registrar",
|
|
@@ -203,6 +207,18 @@ class Zone(ObjectModificationMixin, ContactsMixin, NetBoxModel):
|
|
|
203
207
|
blank=True,
|
|
204
208
|
null=True,
|
|
205
209
|
)
|
|
210
|
+
expiration_date = models.DateField(
|
|
211
|
+
verbose_name=_("Expiration Date"),
|
|
212
|
+
blank=True,
|
|
213
|
+
null=True,
|
|
214
|
+
)
|
|
215
|
+
domain_status = models.CharField(
|
|
216
|
+
verbose_name=_("Domain Status"),
|
|
217
|
+
max_length=50,
|
|
218
|
+
choices=ZoneEPPStatusChoices,
|
|
219
|
+
blank=True,
|
|
220
|
+
null=True,
|
|
221
|
+
)
|
|
206
222
|
registrant = models.ForeignKey(
|
|
207
223
|
verbose_name=_("Registrant"),
|
|
208
224
|
to="RegistrationContact",
|
|
@@ -212,7 +228,7 @@ class Zone(ObjectModificationMixin, ContactsMixin, NetBoxModel):
|
|
|
212
228
|
null=True,
|
|
213
229
|
)
|
|
214
230
|
admin_c = models.ForeignKey(
|
|
215
|
-
verbose_name="Administrative Contact",
|
|
231
|
+
verbose_name=_("Administrative Contact"),
|
|
216
232
|
to="RegistrationContact",
|
|
217
233
|
on_delete=models.SET_NULL,
|
|
218
234
|
related_name="admin_c_zones",
|
|
@@ -255,12 +271,27 @@ class Zone(ObjectModificationMixin, ContactsMixin, NetBoxModel):
|
|
|
255
271
|
blank=True,
|
|
256
272
|
null=True,
|
|
257
273
|
)
|
|
274
|
+
arpa_network = NetworkField(
|
|
275
|
+
verbose_name=_("ARPA Network"),
|
|
276
|
+
help_text=_("Network related to a reverse lookup zone (.arpa)"),
|
|
277
|
+
blank=True,
|
|
278
|
+
null=True,
|
|
279
|
+
)
|
|
280
|
+
tenant = models.ForeignKey(
|
|
281
|
+
verbose_name=_("Tenant"),
|
|
282
|
+
to="tenancy.Tenant",
|
|
283
|
+
on_delete=models.PROTECT,
|
|
284
|
+
related_name="netbox_dns_zones",
|
|
285
|
+
blank=True,
|
|
286
|
+
null=True,
|
|
287
|
+
)
|
|
258
288
|
|
|
259
289
|
objects = ZoneManager()
|
|
260
290
|
|
|
261
291
|
clone_fields = (
|
|
262
292
|
"view",
|
|
263
293
|
"name",
|
|
294
|
+
"description",
|
|
264
295
|
"status",
|
|
265
296
|
"nameservers",
|
|
266
297
|
"default_ttl",
|
|
@@ -271,7 +302,6 @@ class Zone(ObjectModificationMixin, ContactsMixin, NetBoxModel):
|
|
|
271
302
|
"soa_retry",
|
|
272
303
|
"soa_expire",
|
|
273
304
|
"soa_minimum",
|
|
274
|
-
"description",
|
|
275
305
|
"tenant",
|
|
276
306
|
)
|
|
277
307
|
|
|
@@ -357,6 +387,9 @@ class Zone(ObjectModificationMixin, ContactsMixin, NetBoxModel):
|
|
|
357
387
|
def get_status_color(self):
|
|
358
388
|
return ZoneStatusChoices.colors.get(self.status)
|
|
359
389
|
|
|
390
|
+
def get_domain_status_color(self):
|
|
391
|
+
return ZoneEPPStatusChoices.colors.get(self.domain_status)
|
|
392
|
+
|
|
360
393
|
# TODO: Remove in version 1.3.0 (NetBox #18555)
|
|
361
394
|
def get_absolute_url(self):
|
|
362
395
|
return reverse("plugins:netbox_dns:zone", kwargs={"pk": self.pk})
|
|
@@ -397,6 +430,8 @@ class Zone(ObjectModificationMixin, ContactsMixin, NetBoxModel):
|
|
|
397
430
|
self.admin_c,
|
|
398
431
|
self.tech_c,
|
|
399
432
|
self.billing_c,
|
|
433
|
+
self.expiration_date,
|
|
434
|
+
self.domain_status,
|
|
400
435
|
)
|
|
401
436
|
)
|
|
402
437
|
|
|
@@ -566,6 +601,26 @@ class Zone(ObjectModificationMixin, ContactsMixin, NetBoxModel):
|
|
|
566
601
|
|
|
567
602
|
return ns_warnings, ns_errors
|
|
568
603
|
|
|
604
|
+
def check_expiration(self):
|
|
605
|
+
if self.expiration_date is None:
|
|
606
|
+
return None, None
|
|
607
|
+
|
|
608
|
+
expiration_warning = None
|
|
609
|
+
expiration_error = None
|
|
610
|
+
|
|
611
|
+
expiration_warning_days = get_plugin_config(
|
|
612
|
+
"netbox_dns", "zone_expiration_warning_days"
|
|
613
|
+
)
|
|
614
|
+
|
|
615
|
+
if self.expiration_date < date.today():
|
|
616
|
+
expiration_error = _("The registration for this domain has expired.")
|
|
617
|
+
elif (self.expiration_date - date.today()).days < expiration_warning_days:
|
|
618
|
+
expiration_warning = _(
|
|
619
|
+
f"The registration for his domain will expire less than {expiration_warning_days} days."
|
|
620
|
+
)
|
|
621
|
+
|
|
622
|
+
return expiration_warning, expiration_error
|
|
623
|
+
|
|
569
624
|
def check_soa_serial_increment(self, old_serial, new_serial):
|
|
570
625
|
MAX_SOA_SERIAL_INCREMENT = 2**31 - 1
|
|
571
626
|
SOA_SERIAL_WRAP = 2**32
|
|
@@ -55,11 +55,11 @@ class ZoneTemplate(NetBoxModel):
|
|
|
55
55
|
related_name="zone_templates",
|
|
56
56
|
blank=True,
|
|
57
57
|
)
|
|
58
|
-
|
|
59
|
-
verbose_name=_("
|
|
60
|
-
to="
|
|
58
|
+
dnssec_policy = models.ForeignKey(
|
|
59
|
+
verbose_name=_("DNSSEC Policy"),
|
|
60
|
+
to="DNSSECPolicy",
|
|
61
61
|
on_delete=models.SET_NULL,
|
|
62
|
-
related_name="
|
|
62
|
+
related_name="zone_templates",
|
|
63
63
|
blank=True,
|
|
64
64
|
null=True,
|
|
65
65
|
)
|
|
@@ -103,33 +103,43 @@ class ZoneTemplate(NetBoxModel):
|
|
|
103
103
|
blank=True,
|
|
104
104
|
null=True,
|
|
105
105
|
)
|
|
106
|
+
tenant = models.ForeignKey(
|
|
107
|
+
verbose_name=_("Tenant"),
|
|
108
|
+
to="tenancy.Tenant",
|
|
109
|
+
on_delete=models.SET_NULL,
|
|
110
|
+
related_name="+",
|
|
111
|
+
blank=True,
|
|
112
|
+
null=True,
|
|
113
|
+
)
|
|
106
114
|
|
|
107
115
|
clone_fields = (
|
|
108
116
|
"description",
|
|
109
117
|
"nameservers",
|
|
110
118
|
"record_templates",
|
|
111
|
-
"
|
|
119
|
+
"dnssec_policy",
|
|
112
120
|
"registrar",
|
|
113
121
|
"registrant",
|
|
114
122
|
"admin_c",
|
|
115
123
|
"tech_c",
|
|
116
124
|
"billing_c",
|
|
125
|
+
"tenant",
|
|
117
126
|
)
|
|
118
127
|
|
|
119
128
|
template_fields = (
|
|
120
129
|
"soa_mname",
|
|
121
130
|
"soa_rname",
|
|
122
|
-
"
|
|
131
|
+
"dnssec_policy",
|
|
123
132
|
"registrar",
|
|
124
133
|
"registrant",
|
|
125
134
|
"admin_c",
|
|
126
135
|
"tech_c",
|
|
127
136
|
"billing_c",
|
|
137
|
+
"tenant",
|
|
128
138
|
)
|
|
129
139
|
|
|
130
140
|
class Meta:
|
|
131
141
|
verbose_name = _("Zone Template")
|
|
132
|
-
verbose_name_plural = "Zone Templates"
|
|
142
|
+
verbose_name_plural = _("Zone Templates")
|
|
133
143
|
|
|
134
144
|
ordering = ("name",)
|
|
135
145
|
|
netbox_dns/navigation.py
CHANGED
|
@@ -92,6 +92,46 @@ managed_record_menu_item = PluginMenuItem(
|
|
|
92
92
|
permissions=["netbox_dns.view_record"],
|
|
93
93
|
)
|
|
94
94
|
|
|
95
|
+
dnsseckeytemplate_menu_item = PluginMenuItem(
|
|
96
|
+
link="plugins:netbox_dns:dnsseckeytemplate_list",
|
|
97
|
+
link_text=_("DNSSEC Key Templates"),
|
|
98
|
+
permissions=["netbox_dns.view_dnsseckeytemplate"],
|
|
99
|
+
buttons=(
|
|
100
|
+
PluginMenuButton(
|
|
101
|
+
"plugins:netbox_dns:dnsseckeytemplate_add",
|
|
102
|
+
_("Add"),
|
|
103
|
+
"mdi mdi-plus-thick",
|
|
104
|
+
permissions=["netbox_dns.add_dnsseckeytemplate"],
|
|
105
|
+
),
|
|
106
|
+
PluginMenuButton(
|
|
107
|
+
"plugins:netbox_dns:dnsseckeytemplate_bulk_import",
|
|
108
|
+
_("Import"),
|
|
109
|
+
"mdi mdi-upload",
|
|
110
|
+
permissions=["netbox_dns.add_dnsseckeytemplate"],
|
|
111
|
+
),
|
|
112
|
+
),
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
dnssecpolicy_menu_item = PluginMenuItem(
|
|
116
|
+
link="plugins:netbox_dns:dnssecpolicy_list",
|
|
117
|
+
link_text=_("DNSSEC Policies"),
|
|
118
|
+
permissions=["netbox_dns.view_dnssecpolicy"],
|
|
119
|
+
buttons=(
|
|
120
|
+
PluginMenuButton(
|
|
121
|
+
"plugins:netbox_dns:dnssecpolicy_add",
|
|
122
|
+
_("Add"),
|
|
123
|
+
"mdi mdi-plus-thick",
|
|
124
|
+
permissions=["netbox_dns.add_dnssecpolicy"],
|
|
125
|
+
),
|
|
126
|
+
PluginMenuButton(
|
|
127
|
+
"plugins:netbox_dns:dnssecpolicy_bulk_import",
|
|
128
|
+
_("Import"),
|
|
129
|
+
"mdi mdi-upload",
|
|
130
|
+
permissions=["netbox_dns.add_dnssecpolicy"],
|
|
131
|
+
),
|
|
132
|
+
),
|
|
133
|
+
)
|
|
134
|
+
|
|
95
135
|
zonetemplate_menu_item = PluginMenuItem(
|
|
96
136
|
link="plugins:netbox_dns:zonetemplate_list",
|
|
97
137
|
link_text=_("Zone Templates"),
|
|
@@ -187,6 +227,13 @@ if top_level_menu:
|
|
|
187
227
|
managed_record_menu_item,
|
|
188
228
|
),
|
|
189
229
|
),
|
|
230
|
+
(
|
|
231
|
+
_("DNSSEC"),
|
|
232
|
+
(
|
|
233
|
+
dnsseckeytemplate_menu_item,
|
|
234
|
+
dnssecpolicy_menu_item,
|
|
235
|
+
),
|
|
236
|
+
),
|
|
190
237
|
(
|
|
191
238
|
_("Templates"),
|
|
192
239
|
(
|
|
@@ -211,6 +258,8 @@ else:
|
|
|
211
258
|
nameserver_menu_item,
|
|
212
259
|
record_menu_item,
|
|
213
260
|
managed_record_menu_item,
|
|
261
|
+
dnsseckeytemplate_menu_item,
|
|
262
|
+
dnssecpolicy_menu_item,
|
|
214
263
|
registrar_menu_item,
|
|
215
264
|
contact_menu_item,
|
|
216
265
|
)
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
from django.dispatch import receiver
|
|
2
|
+
from django.db.models.signals import m2m_changed
|
|
3
|
+
from django.core.exceptions import ValidationError
|
|
4
|
+
|
|
5
|
+
from netbox.context import current_request
|
|
6
|
+
from utilities.exceptions import AbortRequest
|
|
7
|
+
|
|
8
|
+
from netbox_dns.validators import validate_key_template_assignment
|
|
9
|
+
|
|
10
|
+
from netbox_dns.models import DNSSECPolicy, DNSSECKeyTemplate
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@receiver(m2m_changed, sender=DNSSECPolicy.key_templates.through)
|
|
14
|
+
def dnssec_policy_key_templates_changed(action, instance, pk_set, **kwargs):
|
|
15
|
+
request = current_request.get()
|
|
16
|
+
|
|
17
|
+
key_templates = instance.key_templates.all()
|
|
18
|
+
match action:
|
|
19
|
+
case "pre_remove":
|
|
20
|
+
key_templates = key_templates.exclude(pk__in=pk_set)
|
|
21
|
+
case "pre_add":
|
|
22
|
+
key_templates |= DNSSECKeyTemplate.objects.filter(pk__in=pk_set)
|
|
23
|
+
case _:
|
|
24
|
+
return
|
|
25
|
+
|
|
26
|
+
try:
|
|
27
|
+
validate_key_template_assignment(key_templates)
|
|
28
|
+
except ValidationError as exc:
|
|
29
|
+
if request is not None:
|
|
30
|
+
raise AbortRequest(exc)
|
|
31
|
+
else:
|
|
32
|
+
raise exc
|
netbox_dns/tables/__init__.py
CHANGED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import django_tables2 as tables
|
|
2
|
+
from django.utils.translation import gettext_lazy as _
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
from netbox.tables import (
|
|
6
|
+
NetBoxTable,
|
|
7
|
+
ChoiceFieldColumn,
|
|
8
|
+
TagColumn,
|
|
9
|
+
)
|
|
10
|
+
from tenancy.tables import TenancyColumnsMixin
|
|
11
|
+
|
|
12
|
+
from netbox_dns.models import DNSSECKeyTemplate
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
__all__ = ("DNSSECKeyTemplateTable",)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class DNSSECKeyTemplateTable(TenancyColumnsMixin, NetBoxTable):
|
|
19
|
+
name = tables.Column(
|
|
20
|
+
verbose_name=_("Name"),
|
|
21
|
+
linkify=True,
|
|
22
|
+
)
|
|
23
|
+
type = ChoiceFieldColumn(
|
|
24
|
+
verbose_name=_("Key Type"),
|
|
25
|
+
)
|
|
26
|
+
lifetime = tables.Column(
|
|
27
|
+
verbose_name=_("Lifetime"),
|
|
28
|
+
)
|
|
29
|
+
algorithm = ChoiceFieldColumn(
|
|
30
|
+
verbose_name=_("Algorithm"),
|
|
31
|
+
)
|
|
32
|
+
key_size = ChoiceFieldColumn(
|
|
33
|
+
verbose_name=_("Key Size"),
|
|
34
|
+
)
|
|
35
|
+
tags = TagColumn(
|
|
36
|
+
url_name="plugins:netbox_dns:dnsseckeytemplate_list",
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
class Meta(NetBoxTable.Meta):
|
|
40
|
+
model = DNSSECKeyTemplate
|
|
41
|
+
fields = ("description",)
|
|
42
|
+
default_columns = (
|
|
43
|
+
"name",
|
|
44
|
+
"type",
|
|
45
|
+
"algorithm",
|
|
46
|
+
"key_size",
|
|
47
|
+
"tags",
|
|
48
|
+
)
|