netbox-plugin-dns 1.2.7b2__py3-none-any.whl → 1.3b1__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 +55 -29
- netbox_dns/api/field_serializers.py +25 -0
- netbox_dns/api/nested_serializers.py +19 -1
- netbox_dns/api/serializers_/dnssec_key_template.py +13 -0
- netbox_dns/api/serializers_/dnssec_policy.py +30 -0
- netbox_dns/api/serializers_/record.py +2 -0
- netbox_dns/api/serializers_/record_template.py +2 -0
- netbox_dns/api/serializers_/zone.py +10 -1
- netbox_dns/choices/dnssec_key_template.py +4 -4
- netbox_dns/choices/dnssec_policy.py +2 -2
- netbox_dns/choices/record.py +64 -19
- netbox_dns/choices/utilities.py +4 -26
- netbox_dns/choices/zone.py +96 -1
- netbox_dns/fields/choice_array.py +13 -0
- netbox_dns/fields/timeperiod.py +15 -13
- netbox_dns/filtersets/dnssec_policy.py +25 -1
- netbox_dns/filtersets/zone.py +7 -2
- netbox_dns/filtersets/zone_template.py +2 -2
- netbox_dns/forms/dnssec_key_template.py +2 -1
- netbox_dns/forms/dnssec_policy.py +32 -2
- netbox_dns/forms/nameserver.py +2 -0
- netbox_dns/forms/record_template.py +1 -0
- netbox_dns/forms/zone.py +78 -15
- netbox_dns/forms/zone_template.py +9 -0
- netbox_dns/graphql/enums.py +41 -0
- netbox_dns/graphql/filter_lookups.py +13 -0
- netbox_dns/graphql/filters/__init__.py +12 -0
- netbox_dns/graphql/filters/dnssec_key_template.py +63 -0
- netbox_dns/graphql/filters/dnssec_policy.py +123 -0
- netbox_dns/graphql/filters/nameserver.py +32 -0
- netbox_dns/graphql/filters/record.py +89 -0
- netbox_dns/graphql/filters/record_template.py +55 -0
- netbox_dns/graphql/filters/registrar.py +30 -0
- netbox_dns/graphql/filters/registration_contact.py +27 -0
- netbox_dns/graphql/filters/view.py +28 -0
- netbox_dns/graphql/filters/zone.py +146 -0
- netbox_dns/graphql/filters/zone_template.py +97 -0
- netbox_dns/locale/de/LC_MESSAGES/django.mo +0 -0
- netbox_dns/locale/fr/LC_MESSAGES/django.mo +0 -0
- netbox_dns/migrations/0018_zone_domain_status_zone_expiration_date.py +23 -0
- netbox_dns/models/dnssec_key_template.py +0 -5
- netbox_dns/models/dnssec_policy.py +5 -8
- netbox_dns/models/nameserver.py +0 -5
- netbox_dns/models/record.py +4 -6
- netbox_dns/models/record_template.py +0 -5
- netbox_dns/models/registrar.py +0 -5
- netbox_dns/models/registration_contact.py +0 -5
- netbox_dns/models/view.py +0 -5
- netbox_dns/models/zone.py +44 -7
- netbox_dns/models/zone_template.py +1 -6
- netbox_dns/tables/zone.py +6 -1
- netbox_dns/template_content.py +2 -1
- netbox_dns/templates/netbox_dns/zone/registration.html +19 -0
- netbox_dns/urls.py +7 -0
- netbox_dns/utilities/conversions.py +13 -0
- netbox_dns/validators/dns_value.py +3 -0
- netbox_dns/validators/dnssec.py +10 -8
- netbox_dns/views/dnssec_key_template.py +0 -9
- netbox_dns/views/dnssec_policy.py +3 -10
- netbox_dns/views/nameserver.py +0 -9
- netbox_dns/views/record.py +0 -9
- netbox_dns/views/record_template.py +0 -3
- netbox_dns/views/registrar.py +0 -3
- netbox_dns/views/registration_contact.py +0 -3
- netbox_dns/views/view.py +0 -9
- netbox_dns/views/zone.py +11 -11
- netbox_dns/views/zone_template.py +0 -4
- {netbox_plugin_dns-1.2.7b2.dist-info → netbox_plugin_dns-1.3b1.dist-info}/METADATA +5 -3
- {netbox_plugin_dns-1.2.7b2.dist-info → netbox_plugin_dns-1.3b1.dist-info}/RECORD +72 -58
- {netbox_plugin_dns-1.2.7b2.dist-info → netbox_plugin_dns-1.3b1.dist-info}/WHEEL +1 -1
- netbox_dns/graphql/filters.py +0 -88
- {netbox_plugin_dns-1.2.7b2.dist-info → netbox_plugin_dns-1.3b1.dist-info/licenses}/LICENSE +0 -0
- {netbox_plugin_dns-1.2.7b2.dist-info → netbox_plugin_dns-1.3b1.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
from typing import Annotated, TYPE_CHECKING
|
|
2
|
+
|
|
3
|
+
import strawberry
|
|
4
|
+
import strawberry_django
|
|
5
|
+
from strawberry.scalars import ID
|
|
6
|
+
from strawberry_django import FilterLookup
|
|
7
|
+
|
|
8
|
+
from netbox.graphql.filter_mixins import NetBoxModelFilterMixin
|
|
9
|
+
from tenancy.graphql.filter_mixins import ContactFilterMixin, TenancyFilterMixin
|
|
10
|
+
|
|
11
|
+
if TYPE_CHECKING:
|
|
12
|
+
from .enums import NetBoxDNSZoneStatusEnum
|
|
13
|
+
from .nameserver import NetBoxDNSNameServerFilter
|
|
14
|
+
from .record_template import NetBoxDNSRecordTemplateFilter
|
|
15
|
+
from .registrar import NetBoxDNSRegistrarFilter
|
|
16
|
+
from .registration_contact import NetBoxDNSRegistrationContactFilter
|
|
17
|
+
|
|
18
|
+
from netbox_dns.models import ZoneTemplate
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
__all__ = ("NetBoxDNSZoneTemplateFilter",)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
@strawberry_django.filter(ZoneTemplate, lookups=True)
|
|
25
|
+
class NetBoxDNSZoneTemplateFilter(
|
|
26
|
+
ContactFilterMixin, TenancyFilterMixin, NetBoxModelFilterMixin
|
|
27
|
+
):
|
|
28
|
+
name: FilterLookup[str] | None = strawberry_django.filter_field()
|
|
29
|
+
description: FilterLookup[str] | None = strawberry_django.filter_field()
|
|
30
|
+
nameservers: (
|
|
31
|
+
Annotated[
|
|
32
|
+
"NetBoxDNSNameServerFilter", strawberry.lazy("netbox_dns.graphql.filters")
|
|
33
|
+
]
|
|
34
|
+
| None
|
|
35
|
+
) = strawberry_django.filter_field()
|
|
36
|
+
status: (
|
|
37
|
+
Annotated[
|
|
38
|
+
"NetBoxDNSZoneStatusEnum", strawberry.lazy("netbox_dns.graphql.enums")
|
|
39
|
+
]
|
|
40
|
+
| None
|
|
41
|
+
) = strawberry_django.filter_field()
|
|
42
|
+
|
|
43
|
+
soa_mname: (
|
|
44
|
+
Annotated[
|
|
45
|
+
"NetBoxDNSNameServerFilter", strawberry.lazy("netbox_dns.graphql.filters")
|
|
46
|
+
]
|
|
47
|
+
| None
|
|
48
|
+
) = strawberry_django.filter_field()
|
|
49
|
+
soa_mname_id: ID | None = strawberry_django.filter_field()
|
|
50
|
+
soa_rname: FilterLookup[str] | None = strawberry_django.filter_field()
|
|
51
|
+
|
|
52
|
+
registrar: (
|
|
53
|
+
Annotated[
|
|
54
|
+
"NetBoxDNSRegistrarFilter", strawberry.lazy("netbox_dns.graphql.filters")
|
|
55
|
+
]
|
|
56
|
+
| None
|
|
57
|
+
)
|
|
58
|
+
registrar_id: ID | None = strawberry_django.filter_field()
|
|
59
|
+
registrant: (
|
|
60
|
+
Annotated[
|
|
61
|
+
"NetBoxDNSRegistrationContactFilter",
|
|
62
|
+
strawberry.lazy("netbox_dns.graphql.filters"),
|
|
63
|
+
]
|
|
64
|
+
| None
|
|
65
|
+
)
|
|
66
|
+
registrant_id: ID | None = strawberry_django.filter_field()
|
|
67
|
+
admin_c: (
|
|
68
|
+
Annotated[
|
|
69
|
+
"NetBoxDNSRegistrationContactFilter",
|
|
70
|
+
strawberry.lazy("netbox_dns.graphql.filters"),
|
|
71
|
+
]
|
|
72
|
+
| None
|
|
73
|
+
)
|
|
74
|
+
admin_c_id: ID | None = strawberry_django.filter_field()
|
|
75
|
+
tech_c: (
|
|
76
|
+
Annotated[
|
|
77
|
+
"NetBoxDNSRegistrationContactFilter",
|
|
78
|
+
strawberry.lazy("netbox_dns.graphql.filters"),
|
|
79
|
+
]
|
|
80
|
+
| None
|
|
81
|
+
)
|
|
82
|
+
tech_c_id: ID | None = strawberry_django.filter_field()
|
|
83
|
+
billing_c: (
|
|
84
|
+
Annotated[
|
|
85
|
+
"NetBoxDNSRegistrationContactFilter",
|
|
86
|
+
strawberry.lazy("netbox_dns.graphql.filters"),
|
|
87
|
+
]
|
|
88
|
+
| None
|
|
89
|
+
)
|
|
90
|
+
billing_c_id: ID | None = strawberry_django.filter_field()
|
|
91
|
+
record_templates: (
|
|
92
|
+
Annotated[
|
|
93
|
+
"NetBoxDNSRecordTemplateFilter",
|
|
94
|
+
strawberry.lazy("netbox_dns.graphql.filters"),
|
|
95
|
+
]
|
|
96
|
+
| None
|
|
97
|
+
) = strawberry_django.filter_field()
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Generated by Django 5.1.7 on 2025-04-03 13:43
|
|
2
|
+
|
|
3
|
+
from django.db import migrations, models
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class Migration(migrations.Migration):
|
|
7
|
+
|
|
8
|
+
dependencies = [
|
|
9
|
+
("netbox_dns", "0017_dnssec_policy_zone_zone_template"),
|
|
10
|
+
]
|
|
11
|
+
|
|
12
|
+
operations = [
|
|
13
|
+
migrations.AddField(
|
|
14
|
+
model_name="zone",
|
|
15
|
+
name="domain_status",
|
|
16
|
+
field=models.CharField(blank=True, max_length=50, null=True),
|
|
17
|
+
),
|
|
18
|
+
migrations.AddField(
|
|
19
|
+
model_name="zone",
|
|
20
|
+
name="expiration_date",
|
|
21
|
+
field=models.DateField(blank=True, null=True),
|
|
22
|
+
),
|
|
23
|
+
]
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
from django.db import models
|
|
2
|
-
from django.urls import reverse
|
|
3
2
|
from django.utils.translation import gettext_lazy as _
|
|
4
3
|
|
|
5
4
|
from netbox.models import NetBoxModel
|
|
@@ -87,10 +86,6 @@ class DNSSECKeyTemplate(ContactsMixin, NetBoxModel):
|
|
|
87
86
|
def __str__(self):
|
|
88
87
|
return f"{str(self.name)} [{self.type}]"
|
|
89
88
|
|
|
90
|
-
# TODO: Remove in version 1.3.0 (NetBox #18555)
|
|
91
|
-
def get_absolute_url(self):
|
|
92
|
-
return reverse("plugins:netbox_dns:dnsseckeytemplate", kwargs={"pk": self.pk})
|
|
93
|
-
|
|
94
89
|
def get_type_color(self):
|
|
95
90
|
return DNSSECKeyTemplateTypeChoices.colors.get(self.type)
|
|
96
91
|
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
from django.db import models
|
|
2
|
-
from django.urls import reverse
|
|
3
2
|
from django.utils.translation import gettext_lazy as _
|
|
4
3
|
|
|
5
4
|
from netbox.models import NetBoxModel
|
|
@@ -168,10 +167,6 @@ class DNSSECPolicy(ContactsMixin, NetBoxModel):
|
|
|
168
167
|
def get_status_color(self):
|
|
169
168
|
return DNSSECPolicyStatusChoices.colors.get(self.status)
|
|
170
169
|
|
|
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
170
|
@property
|
|
176
171
|
def purge_keys_value(self):
|
|
177
172
|
return self.purge_keys if self.purge_keys is not None else 776000
|
|
@@ -181,16 +176,18 @@ class DNSSECPolicy(ContactsMixin, NetBoxModel):
|
|
|
181
176
|
return self.publish_safety if self.publish_safety is not None else 3600
|
|
182
177
|
|
|
183
178
|
def get_effective_value(self, attribute):
|
|
184
|
-
default_value = get_plugin_config("netbox_dns", f"dnssec_{attribute}", None)
|
|
185
|
-
|
|
186
179
|
if not hasattr(self, attribute):
|
|
187
180
|
raise AttributeError(f"DNSSECPolicy does not have attribute {attribute}")
|
|
188
181
|
|
|
189
182
|
if (value := getattr(self, attribute)) is None:
|
|
190
|
-
return
|
|
183
|
+
return self.get_fallback_setting(attribute)
|
|
191
184
|
|
|
192
185
|
return value
|
|
193
186
|
|
|
187
|
+
@classmethod
|
|
188
|
+
def get_fallback_setting(cls, attribute):
|
|
189
|
+
return get_plugin_config("netbox_dns", f"dnssec_{attribute}")
|
|
190
|
+
|
|
194
191
|
|
|
195
192
|
@register_search
|
|
196
193
|
class DNSSECPolicyIndex(SearchIndex):
|
netbox_dns/models/nameserver.py
CHANGED
|
@@ -4,7 +4,6 @@ from django.core.exceptions import ValidationError
|
|
|
4
4
|
from django.db import models, transaction
|
|
5
5
|
from django.db.models import Q, UniqueConstraint
|
|
6
6
|
from django.db.models.functions import Lower
|
|
7
|
-
from django.urls import reverse
|
|
8
7
|
from django.utils.translation import gettext_lazy as _
|
|
9
8
|
|
|
10
9
|
from netbox.models import NetBoxModel
|
|
@@ -80,10 +79,6 @@ class NameServer(ObjectModificationMixin, ContactsMixin, NetBoxModel):
|
|
|
80
79
|
def display_name(self):
|
|
81
80
|
return name_to_unicode(self.name)
|
|
82
81
|
|
|
83
|
-
# TODO: Remove in version 1.3.0 (NetBox #18555)
|
|
84
|
-
def get_absolute_url(self):
|
|
85
|
-
return reverse("plugins:netbox_dns:nameserver", kwargs={"pk": self.pk})
|
|
86
|
-
|
|
87
82
|
def clean_fields(self, exclude=None):
|
|
88
83
|
if get_plugin_config("netbox_dns", "convert_names_to_lowercase", False):
|
|
89
84
|
self.name = self.name.lower()
|
netbox_dns/models/record.py
CHANGED
|
@@ -8,7 +8,6 @@ from dns import rdata
|
|
|
8
8
|
from django.core.exceptions import ValidationError
|
|
9
9
|
from django.db import transaction, models
|
|
10
10
|
from django.db.models import Q, ExpressionWrapper, BooleanField, Min
|
|
11
|
-
from django.urls import reverse
|
|
12
11
|
from django.conf import settings
|
|
13
12
|
from django.utils.translation import gettext_lazy as _
|
|
14
13
|
|
|
@@ -167,7 +166,7 @@ class Record(ObjectModificationMixin, ContactsMixin, NetBoxModel):
|
|
|
167
166
|
default=False,
|
|
168
167
|
)
|
|
169
168
|
ptr_record = models.OneToOneField(
|
|
170
|
-
verbose_name="PTR Record",
|
|
169
|
+
verbose_name=_("PTR Record"),
|
|
171
170
|
to="self",
|
|
172
171
|
on_delete=models.SET_NULL,
|
|
173
172
|
related_name="address_record",
|
|
@@ -263,10 +262,6 @@ class Record(ObjectModificationMixin, ContactsMixin, NetBoxModel):
|
|
|
263
262
|
def get_status_color(self):
|
|
264
263
|
return RecordStatusChoices.colors.get(self.status)
|
|
265
264
|
|
|
266
|
-
# TODO: Remove in version 1.3.0 (NetBox #18555)
|
|
267
|
-
def get_absolute_url(self):
|
|
268
|
-
return reverse("plugins:netbox_dns:record", kwargs={"pk": self.pk})
|
|
269
|
-
|
|
270
265
|
@property
|
|
271
266
|
def value_fqdn(self):
|
|
272
267
|
if self.type not in (RecordTypeChoices.CNAME, RecordTypeChoices.NS):
|
|
@@ -649,6 +644,9 @@ class Record(ObjectModificationMixin, ContactsMixin, NetBoxModel):
|
|
|
649
644
|
|
|
650
645
|
@property
|
|
651
646
|
def absolute_value(self):
|
|
647
|
+
if self.type in RecordTypeChoices.CUSTOM_TYPES:
|
|
648
|
+
return self.value
|
|
649
|
+
|
|
652
650
|
zone = dns_name.from_text(self.zone.name)
|
|
653
651
|
rr = rdata.from_text(RecordClassChoices.IN, self.type, self.value)
|
|
654
652
|
|
|
@@ -3,7 +3,6 @@ from dns import name as dns_name
|
|
|
3
3
|
|
|
4
4
|
from django.core.exceptions import ValidationError
|
|
5
5
|
from django.db import models
|
|
6
|
-
from django.urls import reverse
|
|
7
6
|
from django.utils.translation import gettext_lazy as _
|
|
8
7
|
|
|
9
8
|
from netbox.models import NetBoxModel
|
|
@@ -104,10 +103,6 @@ class RecordTemplate(NetBoxModel):
|
|
|
104
103
|
def get_status_color(self):
|
|
105
104
|
return RecordStatusChoices.colors.get(self.status)
|
|
106
105
|
|
|
107
|
-
# TODO: Remove in version 1.3.0 (NetBox #18555)
|
|
108
|
-
def get_absolute_url(self):
|
|
109
|
-
return reverse("plugins:netbox_dns:recordtemplate", kwargs={"pk": self.pk})
|
|
110
|
-
|
|
111
106
|
def validate_name(self):
|
|
112
107
|
try:
|
|
113
108
|
name = dns_name.from_text(self.record_name, origin=None)
|
netbox_dns/models/registrar.py
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
from django.db import models
|
|
2
|
-
from django.urls import reverse
|
|
3
2
|
from django.utils.translation import gettext_lazy as _
|
|
4
3
|
|
|
5
4
|
from netbox.models import NetBoxModel
|
|
@@ -57,10 +56,6 @@ class Registrar(NetBoxModel):
|
|
|
57
56
|
blank=True,
|
|
58
57
|
)
|
|
59
58
|
|
|
60
|
-
# TODO: Remove in version 1.3.0 (NetBox #18555)
|
|
61
|
-
def get_absolute_url(self):
|
|
62
|
-
return reverse("plugins:netbox_dns:registrar", kwargs={"pk": self.pk})
|
|
63
|
-
|
|
64
59
|
def __str__(self):
|
|
65
60
|
return str(self.name)
|
|
66
61
|
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
from django.db import models
|
|
2
|
-
from django.urls import reverse
|
|
3
2
|
from django.utils.translation import gettext_lazy as _
|
|
4
3
|
|
|
5
4
|
from netbox.models import NetBoxModel
|
|
@@ -118,10 +117,6 @@ class RegistrationContact(NetBoxModel):
|
|
|
118
117
|
"tags",
|
|
119
118
|
)
|
|
120
119
|
|
|
121
|
-
# TODO: Remove in version 1.3.0 (NetBox #18555)
|
|
122
|
-
def get_absolute_url(self):
|
|
123
|
-
return reverse("plugins:netbox_dns:registrationcontact", kwargs={"pk": self.pk})
|
|
124
|
-
|
|
125
120
|
def __str__(self):
|
|
126
121
|
if self.name is not None:
|
|
127
122
|
return f"{self.contact_id} ({self.name})"
|
netbox_dns/models/view.py
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
from django.db import models
|
|
2
|
-
from django.urls import reverse
|
|
3
2
|
from django.core.exceptions import ValidationError
|
|
4
3
|
from django.utils.translation import gettext_lazy as _
|
|
5
4
|
|
|
@@ -71,10 +70,6 @@ class View(ObjectModificationMixin, ContactsMixin, NetBoxModel):
|
|
|
71
70
|
def get_default_view(cls):
|
|
72
71
|
return cls.objects.get(default_view=True)
|
|
73
72
|
|
|
74
|
-
# TODO: Remove in version 1.3.0 (NetBox #18555)
|
|
75
|
-
def get_absolute_url(self):
|
|
76
|
-
return reverse("plugins:netbox_dns:view", kwargs={"pk": self.pk})
|
|
77
|
-
|
|
78
73
|
def __str__(self):
|
|
79
74
|
return str(self.name)
|
|
80
75
|
|
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
|
|
@@ -14,7 +14,6 @@ from django.db import models, transaction
|
|
|
14
14
|
from django.db.models import Q, Max, ExpressionWrapper, BooleanField, UniqueConstraint
|
|
15
15
|
from django.db.models.functions import Length, Lower
|
|
16
16
|
from django.db.models.signals import m2m_changed
|
|
17
|
-
from django.urls import reverse
|
|
18
17
|
from django.dispatch import receiver
|
|
19
18
|
from django.conf import settings
|
|
20
19
|
from django.utils.translation import gettext_lazy as _
|
|
@@ -26,7 +25,12 @@ from netbox.plugins.utils import get_plugin_config
|
|
|
26
25
|
from utilities.querysets import RestrictedQuerySet
|
|
27
26
|
from ipam.models import IPAddress
|
|
28
27
|
|
|
29
|
-
from netbox_dns.choices import
|
|
28
|
+
from netbox_dns.choices import (
|
|
29
|
+
RecordClassChoices,
|
|
30
|
+
RecordTypeChoices,
|
|
31
|
+
ZoneStatusChoices,
|
|
32
|
+
ZoneEPPStatusChoices,
|
|
33
|
+
)
|
|
30
34
|
from netbox_dns.fields import NetworkField, RFC2317NetworkField
|
|
31
35
|
from netbox_dns.utilities import (
|
|
32
36
|
update_dns_records,
|
|
@@ -202,6 +206,18 @@ class Zone(ObjectModificationMixin, ContactsMixin, NetBoxModel):
|
|
|
202
206
|
blank=True,
|
|
203
207
|
null=True,
|
|
204
208
|
)
|
|
209
|
+
expiration_date = models.DateField(
|
|
210
|
+
verbose_name=_("Expiration Date"),
|
|
211
|
+
blank=True,
|
|
212
|
+
null=True,
|
|
213
|
+
)
|
|
214
|
+
domain_status = models.CharField(
|
|
215
|
+
verbose_name=_("Domain Status"),
|
|
216
|
+
max_length=50,
|
|
217
|
+
choices=ZoneEPPStatusChoices,
|
|
218
|
+
blank=True,
|
|
219
|
+
null=True,
|
|
220
|
+
)
|
|
205
221
|
registrant = models.ForeignKey(
|
|
206
222
|
verbose_name=_("Registrant"),
|
|
207
223
|
to="RegistrationContact",
|
|
@@ -211,7 +227,7 @@ class Zone(ObjectModificationMixin, ContactsMixin, NetBoxModel):
|
|
|
211
227
|
null=True,
|
|
212
228
|
)
|
|
213
229
|
admin_c = models.ForeignKey(
|
|
214
|
-
verbose_name="Administrative Contact",
|
|
230
|
+
verbose_name=_("Administrative Contact"),
|
|
215
231
|
to="RegistrationContact",
|
|
216
232
|
on_delete=models.SET_NULL,
|
|
217
233
|
related_name="admin_c_zones",
|
|
@@ -370,9 +386,8 @@ class Zone(ObjectModificationMixin, ContactsMixin, NetBoxModel):
|
|
|
370
386
|
def get_status_color(self):
|
|
371
387
|
return ZoneStatusChoices.colors.get(self.status)
|
|
372
388
|
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
return reverse("plugins:netbox_dns:zone", kwargs={"pk": self.pk})
|
|
389
|
+
def get_domain_status_color(self):
|
|
390
|
+
return ZoneEPPStatusChoices.colors.get(self.domain_status)
|
|
376
391
|
|
|
377
392
|
def get_status_class(self):
|
|
378
393
|
return self.CSS_CLASSES.get(self.status)
|
|
@@ -410,6 +425,8 @@ class Zone(ObjectModificationMixin, ContactsMixin, NetBoxModel):
|
|
|
410
425
|
self.admin_c,
|
|
411
426
|
self.tech_c,
|
|
412
427
|
self.billing_c,
|
|
428
|
+
self.expiration_date,
|
|
429
|
+
self.domain_status,
|
|
413
430
|
)
|
|
414
431
|
)
|
|
415
432
|
|
|
@@ -579,6 +596,26 @@ class Zone(ObjectModificationMixin, ContactsMixin, NetBoxModel):
|
|
|
579
596
|
|
|
580
597
|
return ns_warnings, ns_errors
|
|
581
598
|
|
|
599
|
+
def check_expiration(self):
|
|
600
|
+
if self.expiration_date is None:
|
|
601
|
+
return None, None
|
|
602
|
+
|
|
603
|
+
expiration_warning = None
|
|
604
|
+
expiration_error = None
|
|
605
|
+
|
|
606
|
+
expiration_warning_days = get_plugin_config(
|
|
607
|
+
"netbox_dns", "zone_expiration_warning_days"
|
|
608
|
+
)
|
|
609
|
+
|
|
610
|
+
if self.expiration_date < date.today():
|
|
611
|
+
expiration_error = _("The registration for this domain has expired.")
|
|
612
|
+
elif (self.expiration_date - date.today()).days < expiration_warning_days:
|
|
613
|
+
expiration_warning = _(
|
|
614
|
+
f"The registration for his domain will expire less than {expiration_warning_days} days."
|
|
615
|
+
)
|
|
616
|
+
|
|
617
|
+
return expiration_warning, expiration_error
|
|
618
|
+
|
|
582
619
|
def check_soa_serial_increment(self, old_serial, new_serial):
|
|
583
620
|
MAX_SOA_SERIAL_INCREMENT = 2**31 - 1
|
|
584
621
|
SOA_SERIAL_WRAP = 2**32
|
|
@@ -2,7 +2,6 @@ from dns import name as dns_name
|
|
|
2
2
|
from dns.exception import DNSException
|
|
3
3
|
|
|
4
4
|
from django.db import models
|
|
5
|
-
from django.urls import reverse
|
|
6
5
|
from django.utils.translation import gettext_lazy as _
|
|
7
6
|
from django.core.exceptions import ValidationError
|
|
8
7
|
|
|
@@ -139,17 +138,13 @@ class ZoneTemplate(NetBoxModel):
|
|
|
139
138
|
|
|
140
139
|
class Meta:
|
|
141
140
|
verbose_name = _("Zone Template")
|
|
142
|
-
verbose_name_plural = "Zone Templates"
|
|
141
|
+
verbose_name_plural = _("Zone Templates")
|
|
143
142
|
|
|
144
143
|
ordering = ("name",)
|
|
145
144
|
|
|
146
145
|
def __str__(self):
|
|
147
146
|
return str(self.name)
|
|
148
147
|
|
|
149
|
-
# TODO: Remove in version 1.3.0 (NetBox #18555)
|
|
150
|
-
def get_absolute_url(self):
|
|
151
|
-
return reverse("plugins:netbox_dns:zonetemplate", kwargs={"pk": self.pk})
|
|
152
|
-
|
|
153
148
|
def apply_to_zone_data(self, data):
|
|
154
149
|
fields_changed = False
|
|
155
150
|
for field in self.template_fields:
|
netbox_dns/tables/zone.py
CHANGED
|
@@ -38,7 +38,7 @@ class ZoneTable(TenancyColumnsMixin, NetBoxTable):
|
|
|
38
38
|
url_name="plugins:netbox_dns:zone_list",
|
|
39
39
|
)
|
|
40
40
|
default_ttl = tables.Column(
|
|
41
|
-
verbose_name="Default TTL",
|
|
41
|
+
verbose_name=_("Default TTL"),
|
|
42
42
|
)
|
|
43
43
|
dnssec_policy = tables.Column(
|
|
44
44
|
verbose_name=_("DNSSEC Policy"),
|
|
@@ -55,6 +55,9 @@ class ZoneTable(TenancyColumnsMixin, NetBoxTable):
|
|
|
55
55
|
verbose_name=_("Registrar"),
|
|
56
56
|
linkify=True,
|
|
57
57
|
)
|
|
58
|
+
domain_status = ChoiceFieldColumn(
|
|
59
|
+
verbose_name=_("Domain Status"),
|
|
60
|
+
)
|
|
58
61
|
registrant = tables.Column(
|
|
59
62
|
verbose_name=_("Registrant"),
|
|
60
63
|
linkify=True,
|
|
@@ -84,6 +87,8 @@ class ZoneTable(TenancyColumnsMixin, NetBoxTable):
|
|
|
84
87
|
"inline_signing",
|
|
85
88
|
"rfc2317_parent_managed",
|
|
86
89
|
"registry_domain_id",
|
|
90
|
+
"expiration_date",
|
|
91
|
+
"domain_status",
|
|
87
92
|
)
|
|
88
93
|
default_columns = (
|
|
89
94
|
"name",
|
netbox_dns/template_content.py
CHANGED
|
@@ -2,6 +2,7 @@ import django_tables2 as tables
|
|
|
2
2
|
|
|
3
3
|
from django.conf import settings
|
|
4
4
|
from django.urls import reverse
|
|
5
|
+
from django.utils.translation import gettext_lazy as _
|
|
5
6
|
|
|
6
7
|
from netbox.plugins.utils import get_plugin_config
|
|
7
8
|
from netbox.plugins import PluginTemplateExtension
|
|
@@ -119,7 +120,7 @@ class IPRelatedDNSRecords(PluginTemplateExtension):
|
|
|
119
120
|
|
|
120
121
|
|
|
121
122
|
address_records = tables.ManyToManyColumn(
|
|
122
|
-
verbose_name="DNS Address Records",
|
|
123
|
+
verbose_name=_("DNS Address Records"),
|
|
123
124
|
accessor="netbox_dns_records",
|
|
124
125
|
linkify_item=True,
|
|
125
126
|
transform=lambda obj: (
|
|
@@ -14,6 +14,25 @@
|
|
|
14
14
|
<th scope="row">{% trans "Registry Domain ID" %}</th>
|
|
15
15
|
<td>{{ object.registry_domain_id|placeholder }}</td>
|
|
16
16
|
</tr>
|
|
17
|
+
<tr>
|
|
18
|
+
<th scope="row">{% trans "Expiration Date" %}</th>
|
|
19
|
+
<td>{{ object.expiration_date|placeholder }}</td>
|
|
20
|
+
</tr>
|
|
21
|
+
{% if expiration_warning %}
|
|
22
|
+
<tr>
|
|
23
|
+
<th class="text-warning" scope="row">{% trans "Warning" %}</th>
|
|
24
|
+
<td class="text-warning">{{ expiration_warning }}</td>
|
|
25
|
+
</tr>
|
|
26
|
+
{% elif expiration_error %}
|
|
27
|
+
<tr>
|
|
28
|
+
<th class="text-danger" scope="row">{% trans "Error" %}</th>
|
|
29
|
+
<td class="text-danger">{{ expiration_error }}</td>
|
|
30
|
+
</tr>
|
|
31
|
+
{% endif %}
|
|
32
|
+
<tr>
|
|
33
|
+
<th scope="row">{% trans "Domain Status" %}</th>
|
|
34
|
+
<td>{% badge object.get_domain_status_display bg_color=object.get_domain_status_color %}</td>
|
|
35
|
+
</tr>
|
|
17
36
|
<tr>
|
|
18
37
|
<th scope="row">{% trans "Registrant" %}</th>
|
|
19
38
|
<td>{{ object.registrant|linkify|placeholder }}</td>
|
netbox_dns/urls.py
CHANGED
|
@@ -2,6 +2,13 @@ from django.urls import include, path
|
|
|
2
2
|
|
|
3
3
|
from utilities.urls import get_model_urls
|
|
4
4
|
|
|
5
|
+
# +
|
|
6
|
+
# Import views so the register_model_view is run. This is required for the
|
|
7
|
+
# URLs to be set up properly with get_model_urls().
|
|
8
|
+
# -
|
|
9
|
+
from .views import * # noqa: F401
|
|
10
|
+
|
|
11
|
+
|
|
5
12
|
app_name = "netbox_dns"
|
|
6
13
|
|
|
7
14
|
urlpatterns = (
|
|
@@ -4,6 +4,8 @@ from dns import name as dns_name
|
|
|
4
4
|
from dns.exception import DNSException
|
|
5
5
|
from netaddr import IPNetwork, AddrFormatError
|
|
6
6
|
|
|
7
|
+
from django.utils.dateparse import parse_duration
|
|
8
|
+
|
|
7
9
|
from netbox.plugins.utils import get_plugin_config
|
|
8
10
|
|
|
9
11
|
|
|
@@ -15,6 +17,7 @@ __all__ = (
|
|
|
15
17
|
"normalize_name",
|
|
16
18
|
"network_to_reverse",
|
|
17
19
|
"regex_from_list",
|
|
20
|
+
"iso8601_to_int",
|
|
18
21
|
)
|
|
19
22
|
|
|
20
23
|
|
|
@@ -111,3 +114,13 @@ def network_to_reverse(network):
|
|
|
111
114
|
|
|
112
115
|
def regex_from_list(names):
|
|
113
116
|
return f"^({'|'.join(re.escape(name) for name in names)})$"
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def iso8601_to_int(value):
|
|
120
|
+
try:
|
|
121
|
+
return int(value)
|
|
122
|
+
except ValueError:
|
|
123
|
+
duration = parse_duration(value)
|
|
124
|
+
if duration is None:
|
|
125
|
+
raise TypeError
|
|
126
|
+
return int(duration.total_seconds())
|
|
@@ -52,6 +52,9 @@ def validate_record_value(record):
|
|
|
52
52
|
for part in textwrap.wrap(raw_value, MAX_TXT_LENGTH, drop_whitespace=False)
|
|
53
53
|
)
|
|
54
54
|
|
|
55
|
+
if record.type in (RecordTypeChoices.CUSTOM_TYPES):
|
|
56
|
+
return
|
|
57
|
+
|
|
55
58
|
if record.type in (RecordTypeChoices.TXT, RecordTypeChoices.SPF):
|
|
56
59
|
if not (record.value.isascii() and record.value.isprintable()):
|
|
57
60
|
raise ValidationError(
|
netbox_dns/validators/dnssec.py
CHANGED
|
@@ -97,8 +97,8 @@ def validate_key_template_lifetime(key_template, policy, raise_exception=True):
|
|
|
97
97
|
):
|
|
98
98
|
validation_errors.append(
|
|
99
99
|
_(
|
|
100
|
-
"Key Lifetime is less than DNSKEY TTL + Publish Safety + Zone Propagation Delay."
|
|
101
|
-
)
|
|
100
|
+
"Key Lifetime {lifetime} is less than DNSKEY TTL + Publish Safety + Zone Propagation Delay."
|
|
101
|
+
).format(lifetime=key_lifetime)
|
|
102
102
|
)
|
|
103
103
|
|
|
104
104
|
if (
|
|
@@ -109,8 +109,8 @@ def validate_key_template_lifetime(key_template, policy, raise_exception=True):
|
|
|
109
109
|
):
|
|
110
110
|
validation_errors.append(
|
|
111
111
|
_(
|
|
112
|
-
"Key Lifetime is less than Max Zone TTL + Retire Safety + Zone Propagation Delay."
|
|
113
|
-
)
|
|
112
|
+
"Key Lifetime {lifetime} is less than Max Zone TTL + Retire Safety + Zone Propagation Delay."
|
|
113
|
+
).format(lifetime=key_lifetime)
|
|
114
114
|
)
|
|
115
115
|
|
|
116
116
|
if key_template.type == DNSSECKeyTemplateTypeChoices.TYPE_ZSK:
|
|
@@ -123,8 +123,10 @@ def validate_key_template_lifetime(key_template, policy, raise_exception=True):
|
|
|
123
123
|
and key_lifetime < signatures_validity - signatures_refresh
|
|
124
124
|
):
|
|
125
125
|
validation_errors.append(
|
|
126
|
-
_(
|
|
127
|
-
|
|
126
|
+
_(
|
|
127
|
+
"Key Lifetime {lifetime} is less than Signatures Validity - Signatures Refresh."
|
|
128
|
+
)
|
|
129
|
+
).format(lifetime=key_lifetime)
|
|
128
130
|
else:
|
|
129
131
|
parent_ds_ttl = policy.get_effective_value("parent_ds_ttl")
|
|
130
132
|
parent_propagation_delay = policy.get_effective_value(
|
|
@@ -139,8 +141,8 @@ def validate_key_template_lifetime(key_template, policy, raise_exception=True):
|
|
|
139
141
|
):
|
|
140
142
|
validation_errors.append(
|
|
141
143
|
_(
|
|
142
|
-
"Key Lifetime is less than Parent DS TTL + Retire Safety + Parent Propagation Delay."
|
|
143
|
-
)
|
|
144
|
+
"Key Lifetime {lifetime} is less than Parent DS TTL + Retire Safety + Parent Propagation Delay."
|
|
145
|
+
).format(lifetime=key_lifetime)
|
|
144
146
|
)
|
|
145
147
|
|
|
146
148
|
return validation_errors
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
from netbox.views import generic
|
|
2
2
|
from utilities.views import register_model_view
|
|
3
|
-
from tenancy.views import ObjectContactsView
|
|
4
3
|
|
|
5
4
|
from netbox_dns.filtersets import DNSSECKeyTemplateFilterSet
|
|
6
5
|
from netbox_dns.forms import (
|
|
@@ -50,13 +49,11 @@ class DNSSECKeyTemplateView(generic.ObjectView):
|
|
|
50
49
|
class DNSSECKeyTemplateEditView(generic.ObjectEditView):
|
|
51
50
|
queryset = DNSSECKeyTemplate.objects.all()
|
|
52
51
|
form = DNSSECKeyTemplateForm
|
|
53
|
-
default_return_url = "plugins:netbox_dns:dnsseckeytemplate_list"
|
|
54
52
|
|
|
55
53
|
|
|
56
54
|
@register_model_view(DNSSECKeyTemplate, "delete")
|
|
57
55
|
class DNSSECKeyTemplateDeleteView(generic.ObjectDeleteView):
|
|
58
56
|
queryset = DNSSECKeyTemplate.objects.all()
|
|
59
|
-
default_return_url = "plugins:netbox_dns:dnsseckeytemplate_list"
|
|
60
57
|
|
|
61
58
|
|
|
62
59
|
@register_model_view(DNSSECKeyTemplate, "bulk_import", detail=False)
|
|
@@ -64,7 +61,6 @@ class DNSSECKeyTemplateBulkImportView(generic.BulkImportView):
|
|
|
64
61
|
queryset = DNSSECKeyTemplate.objects.all()
|
|
65
62
|
model_form = DNSSECKeyTemplateImportForm
|
|
66
63
|
table = DNSSECKeyTemplateTable
|
|
67
|
-
default_return_url = "plugins:netbox_dns:dnsseckeytemplate_list"
|
|
68
64
|
|
|
69
65
|
|
|
70
66
|
@register_model_view(DNSSECKeyTemplate, "bulk_edit", path="edit", detail=False)
|
|
@@ -80,8 +76,3 @@ class DNSSECKeyTemplateBulkDeleteView(generic.BulkDeleteView):
|
|
|
80
76
|
queryset = DNSSECKeyTemplate.objects.all()
|
|
81
77
|
filterset = DNSSECKeyTemplateFilterSet
|
|
82
78
|
table = DNSSECKeyTemplateTable
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
@register_model_view(DNSSECKeyTemplate, "contacts")
|
|
86
|
-
class DNSSECKeyTemplateContactsView(ObjectContactsView):
|
|
87
|
-
queryset = DNSSECKeyTemplate.objects.all()
|