netbox-plugin-dns 1.0b2__py3-none-any.whl → 1.0.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of netbox-plugin-dns might be problematic. Click here for more details.
- netbox_dns/__init__.py +3 -3
- netbox_dns/api/serializers_/view.py +6 -1
- netbox_dns/fields/network.py +20 -21
- netbox_dns/fields/rfc2317.py +2 -2
- netbox_dns/filtersets/view.py +1 -1
- netbox_dns/filtersets/zone.py +4 -4
- netbox_dns/forms/record.py +30 -2
- netbox_dns/forms/view.py +6 -3
- netbox_dns/forms/zone.py +71 -102
- netbox_dns/graphql/types.py +1 -4
- netbox_dns/migrations/0001_squashed_netbox_dns_0_22.py +4 -2
- netbox_dns/migrations/0003_default_view.py +15 -0
- netbox_dns/migrations/0004_create_and_assign_default_view.py +26 -0
- netbox_dns/migrations/0005_alter_zone_view_not_null.py +18 -0
- netbox_dns/mixins/__init__.py +1 -0
- netbox_dns/mixins/object_modification.py +26 -0
- netbox_dns/models/nameserver.py +7 -6
- netbox_dns/models/record.py +94 -35
- netbox_dns/models/view.py +56 -1
- netbox_dns/models/zone.py +101 -67
- netbox_dns/signals/ipam_coupling.py +1 -2
- netbox_dns/tables/view.py +12 -2
- netbox_dns/template_content.py +1 -1
- netbox_dns/templates/netbox_dns/record.html +1 -1
- netbox_dns/templates/netbox_dns/view.html +4 -0
- netbox_dns/templates/netbox_dns/zone.html +2 -4
- netbox_dns/urls/__init__.py +17 -0
- netbox_dns/urls/contact.py +51 -0
- netbox_dns/urls/nameserver.py +69 -0
- netbox_dns/urls/record.py +41 -0
- netbox_dns/urls/registrar.py +63 -0
- netbox_dns/urls/view.py +39 -0
- netbox_dns/urls/zone.py +57 -0
- netbox_dns/validators/dns_name.py +24 -11
- netbox_dns/views/record.py +10 -18
- {netbox_plugin_dns-1.0b2.dist-info → netbox_plugin_dns-1.0.2.dist-info}/LICENSE +2 -1
- {netbox_plugin_dns-1.0b2.dist-info → netbox_plugin_dns-1.0.2.dist-info}/METADATA +15 -14
- {netbox_plugin_dns-1.0b2.dist-info → netbox_plugin_dns-1.0.2.dist-info}/RECORD +39 -28
- netbox_dns/urls.py +0 -297
- {netbox_plugin_dns-1.0b2.dist-info → netbox_plugin_dns-1.0.2.dist-info}/WHEEL +0 -0
netbox_dns/__init__.py
CHANGED
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
from netbox.plugins import PluginConfig
|
|
2
2
|
|
|
3
|
-
__version__ = "1.0
|
|
3
|
+
__version__ = "1.0.2"
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
class DNSConfig(PluginConfig):
|
|
7
7
|
name = "netbox_dns"
|
|
8
8
|
verbose_name = "NetBox DNS"
|
|
9
9
|
description = "NetBox plugin for DNS data"
|
|
10
|
-
min_version = "4.0
|
|
10
|
+
min_version = "4.0.0"
|
|
11
11
|
version = __version__
|
|
12
12
|
author = "Peter Eckel"
|
|
13
13
|
author_email = "pete@netbox-dns.org"
|
|
14
14
|
required_settings = []
|
|
15
15
|
default_settings = {
|
|
16
16
|
"zone_default_ttl": 86400,
|
|
17
|
-
"
|
|
17
|
+
"zone_soa_ttl": 86400,
|
|
18
18
|
"zone_soa_serial": 1,
|
|
19
19
|
"zone_soa_refresh": 43200,
|
|
20
20
|
"zone_soa_retry": 7200,
|
|
@@ -10,6 +10,10 @@ class ViewSerializer(NetBoxModelSerializer):
|
|
|
10
10
|
url = serializers.HyperlinkedIdentityField(
|
|
11
11
|
view_name="plugins-api:netbox_dns-api:view-detail"
|
|
12
12
|
)
|
|
13
|
+
default_view = serializers.BooleanField(
|
|
14
|
+
read_only=True,
|
|
15
|
+
)
|
|
16
|
+
|
|
13
17
|
tenant = TenantSerializer(nested=True, required=False, allow_null=True)
|
|
14
18
|
|
|
15
19
|
class Meta:
|
|
@@ -19,6 +23,7 @@ class ViewSerializer(NetBoxModelSerializer):
|
|
|
19
23
|
"url",
|
|
20
24
|
"display",
|
|
21
25
|
"name",
|
|
26
|
+
"default_view",
|
|
22
27
|
"tags",
|
|
23
28
|
"description",
|
|
24
29
|
"created",
|
|
@@ -26,4 +31,4 @@ class ViewSerializer(NetBoxModelSerializer):
|
|
|
26
31
|
"custom_fields",
|
|
27
32
|
"tenant",
|
|
28
33
|
)
|
|
29
|
-
brief_fields = ("id", "url", "display", "name", "description")
|
|
34
|
+
brief_fields = ("id", "url", "display", "name", "default_view", "description")
|
netbox_dns/fields/network.py
CHANGED
|
@@ -9,51 +9,51 @@ from netaddr import AddrFormatError, IPNetwork
|
|
|
9
9
|
class NetContains(Lookup):
|
|
10
10
|
lookup_name = "net_contains"
|
|
11
11
|
|
|
12
|
-
def as_sql(self,
|
|
13
|
-
lhs, lhs_params = self.process_lhs(
|
|
14
|
-
rhs, rhs_params = self.process_rhs(
|
|
12
|
+
def as_sql(self, compiler, connection):
|
|
13
|
+
lhs, lhs_params = self.process_lhs(compiler, connection)
|
|
14
|
+
rhs, rhs_params = self.process_rhs(compiler, connection)
|
|
15
15
|
params = lhs_params + rhs_params
|
|
16
|
-
return "
|
|
16
|
+
return f"{lhs} >> {rhs}", params
|
|
17
17
|
|
|
18
18
|
|
|
19
19
|
class NetContainsOrEquals(Lookup):
|
|
20
20
|
lookup_name = "net_contains_or_equals"
|
|
21
21
|
|
|
22
|
-
def as_sql(self,
|
|
23
|
-
lhs, lhs_params = self.process_lhs(
|
|
24
|
-
rhs, rhs_params = self.process_rhs(
|
|
22
|
+
def as_sql(self, compiler, connection):
|
|
23
|
+
lhs, lhs_params = self.process_lhs(compiler, connection)
|
|
24
|
+
rhs, rhs_params = self.process_rhs(compiler, connection)
|
|
25
25
|
params = lhs_params + rhs_params
|
|
26
|
-
return "
|
|
26
|
+
return f"{lhs} >>= {rhs}", params
|
|
27
27
|
|
|
28
28
|
|
|
29
29
|
class NetContained(Lookup):
|
|
30
30
|
lookup_name = "net_contained"
|
|
31
31
|
|
|
32
|
-
def as_sql(self,
|
|
33
|
-
lhs, lhs_params = self.process_lhs(
|
|
34
|
-
rhs, rhs_params = self.process_rhs(
|
|
32
|
+
def as_sql(self, compiler, connection):
|
|
33
|
+
lhs, lhs_params = self.process_lhs(compiler, connection)
|
|
34
|
+
rhs, rhs_params = self.process_rhs(compiler, connection)
|
|
35
35
|
params = lhs_params + rhs_params
|
|
36
|
-
return "
|
|
36
|
+
return f"{lhs} << {rhs}", params
|
|
37
37
|
|
|
38
38
|
|
|
39
39
|
class NetContainedOrEqual(Lookup):
|
|
40
40
|
lookup_name = "net_contained_or_equal"
|
|
41
41
|
|
|
42
|
-
def as_sql(self,
|
|
43
|
-
lhs, lhs_params = self.process_lhs(
|
|
44
|
-
rhs, rhs_params = self.process_rhs(
|
|
42
|
+
def as_sql(self, compiler, connection):
|
|
43
|
+
lhs, lhs_params = self.process_lhs(compiler, connection)
|
|
44
|
+
rhs, rhs_params = self.process_rhs(compiler, connection)
|
|
45
45
|
params = lhs_params + rhs_params
|
|
46
|
-
return "
|
|
46
|
+
return f"{lhs} <<= {rhs}", params
|
|
47
47
|
|
|
48
48
|
|
|
49
49
|
class NetOverlap(Lookup):
|
|
50
50
|
lookup_name = "net_overlap"
|
|
51
51
|
|
|
52
|
-
def as_sql(self,
|
|
53
|
-
lhs, lhs_params = self.process_lhs(
|
|
54
|
-
rhs, rhs_params = self.process_rhs(
|
|
52
|
+
def as_sql(self, compiler, connection):
|
|
53
|
+
lhs, lhs_params = self.process_lhs(compiler, connection)
|
|
54
|
+
rhs, rhs_params = self.process_rhs(compiler, connection)
|
|
55
55
|
params = lhs_params + rhs_params
|
|
56
|
-
return "
|
|
56
|
+
return f"{lhs} && {rhs}", params
|
|
57
57
|
|
|
58
58
|
|
|
59
59
|
class NetworkFormField(forms.Field):
|
|
@@ -118,7 +118,6 @@ class NetMaskLength(Transform):
|
|
|
118
118
|
function = "MASKLEN"
|
|
119
119
|
lookup_name = "net_mask_length"
|
|
120
120
|
|
|
121
|
-
@property
|
|
122
121
|
def output_field(self):
|
|
123
122
|
return IntegerField()
|
|
124
123
|
|
netbox_dns/fields/rfc2317.py
CHANGED
|
@@ -18,8 +18,8 @@ class RFC2317NetworkFormField(forms.Field):
|
|
|
18
18
|
if isinstance(value, IPNetwork):
|
|
19
19
|
if value.version == 4 and value.prefixlen > 24:
|
|
20
20
|
return value
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
|
|
22
|
+
raise ValidationError(INVALID_RFC2317)
|
|
23
23
|
|
|
24
24
|
if len(value.split("/")) != 2:
|
|
25
25
|
raise ValidationError("Please specify the prefix length")
|
netbox_dns/filtersets/view.py
CHANGED
|
@@ -9,7 +9,7 @@ from netbox_dns.models import View
|
|
|
9
9
|
class ViewFilterSet(NetBoxModelFilterSet, TenancyFilterSet):
|
|
10
10
|
class Meta:
|
|
11
11
|
model = View
|
|
12
|
-
fields = ("id", "name", "description")
|
|
12
|
+
fields = ("id", "name", "default_view", "description")
|
|
13
13
|
|
|
14
14
|
def search(self, queryset, name, value):
|
|
15
15
|
if not value.strip():
|
netbox_dns/filtersets/zone.py
CHANGED
|
@@ -31,14 +31,14 @@ class ZoneFilterSet(TenancyFilterSet, NetBoxModelFilterSet):
|
|
|
31
31
|
to_field_name="name",
|
|
32
32
|
label="View",
|
|
33
33
|
)
|
|
34
|
-
# DEPRECATED: Remove in 1.
|
|
34
|
+
# DEPRECATED: Remove in 1.1
|
|
35
35
|
name_server_id = django_filters.ModelMultipleChoiceFilter(
|
|
36
36
|
queryset=NameServer.objects.all(),
|
|
37
37
|
field_name="nameservers",
|
|
38
38
|
to_field_name="id",
|
|
39
39
|
label="Nameserver IDs",
|
|
40
40
|
)
|
|
41
|
-
# DEPRECATED: Remove in 1.
|
|
41
|
+
# DEPRECATED: Remove in 1.1
|
|
42
42
|
name_server = django_filters.ModelMultipleChoiceFilter(
|
|
43
43
|
queryset=NameServer.objects.all(),
|
|
44
44
|
field_name="nameservers__name",
|
|
@@ -59,13 +59,13 @@ class ZoneFilterSet(TenancyFilterSet, NetBoxModelFilterSet):
|
|
|
59
59
|
)
|
|
60
60
|
soa_mname_id = django_filters.ModelMultipleChoiceFilter(
|
|
61
61
|
queryset=NameServer.objects.all(),
|
|
62
|
-
label="SOA
|
|
62
|
+
label="SOA MName ID",
|
|
63
63
|
)
|
|
64
64
|
soa_mname = django_filters.ModelMultipleChoiceFilter(
|
|
65
65
|
queryset=NameServer.objects.all(),
|
|
66
66
|
field_name="soa_mname__name",
|
|
67
67
|
to_field_name="name",
|
|
68
|
-
label="SOA
|
|
68
|
+
label="SOA MName",
|
|
69
69
|
)
|
|
70
70
|
arpa_network = MultiValueCharFilter(
|
|
71
71
|
method="filter_arpa_network",
|
netbox_dns/forms/record.py
CHANGED
|
@@ -28,10 +28,30 @@ class RecordForm(TenancyForm, NetBoxModelForm):
|
|
|
28
28
|
def __init__(self, *args, **kwargs):
|
|
29
29
|
super().__init__(*args, **kwargs)
|
|
30
30
|
|
|
31
|
+
initial_zone_id = self.initial.get("zone")
|
|
32
|
+
if initial_zone_id is not None:
|
|
33
|
+
self.initial["view"] = Zone.objects.get(pk=initial_zone_id).view
|
|
34
|
+
else:
|
|
35
|
+
self.initial["view"] = View.get_default_view()
|
|
36
|
+
|
|
31
37
|
initial_name = self.initial.get("name")
|
|
32
38
|
if initial_name:
|
|
33
39
|
self.initial["name"] = name_to_unicode(initial_name)
|
|
34
40
|
|
|
41
|
+
view = DynamicModelChoiceField(
|
|
42
|
+
queryset=View.objects.all(),
|
|
43
|
+
required=False,
|
|
44
|
+
label="View",
|
|
45
|
+
)
|
|
46
|
+
zone = DynamicModelChoiceField(
|
|
47
|
+
queryset=Zone.objects.all(),
|
|
48
|
+
required=True,
|
|
49
|
+
query_params={
|
|
50
|
+
"view_id": "$view",
|
|
51
|
+
},
|
|
52
|
+
label="Zone",
|
|
53
|
+
)
|
|
54
|
+
|
|
35
55
|
disable_ptr = forms.BooleanField(
|
|
36
56
|
label="Disable PTR",
|
|
37
57
|
required=False,
|
|
@@ -44,6 +64,7 @@ class RecordForm(TenancyForm, NetBoxModelForm):
|
|
|
44
64
|
fieldsets = (
|
|
45
65
|
FieldSet(
|
|
46
66
|
"name",
|
|
67
|
+
"view",
|
|
47
68
|
"zone",
|
|
48
69
|
"type",
|
|
49
70
|
"value",
|
|
@@ -84,6 +105,7 @@ class RecordFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
|
|
|
84
105
|
"fqdn",
|
|
85
106
|
"type",
|
|
86
107
|
"value",
|
|
108
|
+
"disable_ptr",
|
|
87
109
|
"status",
|
|
88
110
|
"description",
|
|
89
111
|
name="Attributes",
|
|
@@ -105,6 +127,10 @@ class RecordFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
|
|
|
105
127
|
value = forms.CharField(
|
|
106
128
|
required=False,
|
|
107
129
|
)
|
|
130
|
+
disable_ptr = forms.NullBooleanField(
|
|
131
|
+
required=False,
|
|
132
|
+
label="Disable PTR",
|
|
133
|
+
)
|
|
108
134
|
status = forms.MultipleChoiceField(
|
|
109
135
|
choices=RecordStatusChoices,
|
|
110
136
|
required=False,
|
|
@@ -131,10 +157,12 @@ class RecordImportForm(NetBoxModelImportForm):
|
|
|
131
157
|
except forms.ValidationError:
|
|
132
158
|
pass
|
|
133
159
|
|
|
134
|
-
if view:
|
|
160
|
+
if view is not None:
|
|
135
161
|
self.fields["zone"].queryset = Zone.objects.filter(view=view)
|
|
136
162
|
else:
|
|
137
|
-
self.fields["zone"].queryset = Zone.objects.filter(
|
|
163
|
+
self.fields["zone"].queryset = Zone.objects.filter(
|
|
164
|
+
view=View.get_default_view()
|
|
165
|
+
)
|
|
138
166
|
|
|
139
167
|
zone = CSVModelChoiceField(
|
|
140
168
|
queryset=Zone.objects.all(),
|
netbox_dns/forms/view.py
CHANGED
|
@@ -20,26 +20,29 @@ from netbox_dns.models import View
|
|
|
20
20
|
|
|
21
21
|
class ViewForm(TenancyForm, NetBoxModelForm):
|
|
22
22
|
fieldsets = (
|
|
23
|
-
FieldSet("name", "description", "tags", name="View"),
|
|
23
|
+
FieldSet("name", "default_view", "description", "tags", name="View"),
|
|
24
24
|
FieldSet("tenant_group", "tenant", name="Tenancy"),
|
|
25
25
|
)
|
|
26
26
|
|
|
27
27
|
class Meta:
|
|
28
28
|
model = View
|
|
29
|
-
fields = ("name", "description", "tags", "tenant")
|
|
29
|
+
fields = ("name", "default_view", "description", "tags", "tenant")
|
|
30
30
|
|
|
31
31
|
|
|
32
32
|
class ViewFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
|
|
33
33
|
model = View
|
|
34
34
|
fieldsets = (
|
|
35
35
|
FieldSet("q", "filter_id", "tag"),
|
|
36
|
-
FieldSet("name", "description", name="Attributes"),
|
|
36
|
+
FieldSet("name", "default_view", "description", name="Attributes"),
|
|
37
37
|
FieldSet("tenant_group_id", "tenant_id", name="Tenancy"),
|
|
38
38
|
)
|
|
39
39
|
|
|
40
40
|
name = forms.CharField(
|
|
41
41
|
required=False,
|
|
42
42
|
)
|
|
43
|
+
default_view = forms.NullBooleanField(
|
|
44
|
+
required=False,
|
|
45
|
+
)
|
|
43
46
|
description = forms.CharField(
|
|
44
47
|
required=False,
|
|
45
48
|
)
|
netbox_dns/forms/zone.py
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
from django import forms
|
|
2
2
|
from django.conf import settings
|
|
3
|
-
from django.core.exceptions import ValidationError
|
|
4
3
|
from django.core.validators import MinValueValidator, MaxValueValidator
|
|
5
4
|
from django.urls import reverse_lazy
|
|
6
5
|
|
|
@@ -56,7 +55,7 @@ class ZoneForm(TenancyForm, NetBoxModelForm):
|
|
|
56
55
|
)
|
|
57
56
|
soa_rname = forms.CharField(
|
|
58
57
|
required=True,
|
|
59
|
-
label="SOA
|
|
58
|
+
label="SOA RName",
|
|
60
59
|
help_text="Mailbox of the zone's administrator",
|
|
61
60
|
)
|
|
62
61
|
soa_serial_auto = forms.BooleanField(
|
|
@@ -143,23 +142,20 @@ class ZoneForm(TenancyForm, NetBoxModelForm):
|
|
|
143
142
|
name="Domain Registration",
|
|
144
143
|
),
|
|
145
144
|
FieldSet("tags", name="Tags"),
|
|
146
|
-
FieldSet("tenant", name="Tenancy"),
|
|
145
|
+
FieldSet("tenant_group", "tenant", name="Tenancy"),
|
|
147
146
|
)
|
|
148
147
|
|
|
149
148
|
def __init__(self, *args, **kwargs):
|
|
150
|
-
"""Override the __init__ method in order to provide the initial value for the default fields"""
|
|
151
149
|
super().__init__(*args, **kwargs)
|
|
152
150
|
|
|
153
151
|
initial_name = self.initial.get("name")
|
|
154
152
|
if initial_name:
|
|
155
153
|
self.initial["name"] = name_to_unicode(initial_name)
|
|
156
154
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
def _initialize(initial, setting):
|
|
160
|
-
if initial.get(setting, None) in (None, ""):
|
|
161
|
-
initial[setting] = defaults.get(f"zone_{setting}", None)
|
|
155
|
+
if self.initial.get("view") is None:
|
|
156
|
+
self.initial["view"] = View.get_default_view()
|
|
162
157
|
|
|
158
|
+
defaults = settings.PLUGINS_CONFIG.get("netbox_dns")
|
|
163
159
|
for setting in (
|
|
164
160
|
"default_ttl",
|
|
165
161
|
"soa_ttl",
|
|
@@ -170,16 +166,17 @@ class ZoneForm(TenancyForm, NetBoxModelForm):
|
|
|
170
166
|
"soa_expire",
|
|
171
167
|
"soa_minimum",
|
|
172
168
|
):
|
|
173
|
-
|
|
169
|
+
if self.initial.get(setting) in (None, ""):
|
|
170
|
+
self.initial[setting] = defaults.get(f"zone_{setting}")
|
|
174
171
|
|
|
175
|
-
if self.initial.get("soa_ttl"
|
|
176
|
-
self.initial["soa_ttl"] = self.initial.get("default_ttl"
|
|
172
|
+
if self.initial.get("soa_ttl") is None:
|
|
173
|
+
self.initial["soa_ttl"] = self.initial.get("default_ttl")
|
|
177
174
|
|
|
178
175
|
if self.initial.get("soa_serial_auto"):
|
|
179
176
|
self.initial["soa_serial"] = None
|
|
180
177
|
|
|
181
|
-
if self.initial.get("soa_mname"
|
|
182
|
-
default_soa_mname = defaults.get("zone_soa_mname"
|
|
178
|
+
if self.initial.get("soa_mname") is None:
|
|
179
|
+
default_soa_mname = defaults.get("zone_soa_mname")
|
|
183
180
|
if default_soa_mname is not None:
|
|
184
181
|
try:
|
|
185
182
|
self.initial["soa_mname"] = NameServer.objects.get(
|
|
@@ -245,6 +242,18 @@ class ZoneFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
|
|
|
245
242
|
FieldSet(
|
|
246
243
|
"view_id", "status", "name", "nameservers", "description", name="Attributes"
|
|
247
244
|
),
|
|
245
|
+
FieldSet(
|
|
246
|
+
"soa_mname_id",
|
|
247
|
+
"soa_rname",
|
|
248
|
+
"soa_serial_auto",
|
|
249
|
+
name="SOA",
|
|
250
|
+
),
|
|
251
|
+
FieldSet(
|
|
252
|
+
"rfc2317_prefix",
|
|
253
|
+
"rfc2317_parent_managed",
|
|
254
|
+
"rfc2317_parent_zone_id",
|
|
255
|
+
name="RFC2317",
|
|
256
|
+
),
|
|
248
257
|
FieldSet(
|
|
249
258
|
"registrar_id",
|
|
250
259
|
"registry_domain_id",
|
|
@@ -276,6 +285,32 @@ class ZoneFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
|
|
|
276
285
|
description = forms.CharField(
|
|
277
286
|
required=False,
|
|
278
287
|
)
|
|
288
|
+
soa_mname_id = DynamicModelMultipleChoiceField(
|
|
289
|
+
queryset=NameServer.objects.all(),
|
|
290
|
+
label="MName",
|
|
291
|
+
required=False,
|
|
292
|
+
)
|
|
293
|
+
soa_rname = forms.CharField(
|
|
294
|
+
required=False,
|
|
295
|
+
label="RName",
|
|
296
|
+
)
|
|
297
|
+
soa_serial_auto = forms.NullBooleanField(
|
|
298
|
+
required=False,
|
|
299
|
+
label="Generate Serial",
|
|
300
|
+
)
|
|
301
|
+
rfc2317_prefix = RFC2317NetworkFormField(
|
|
302
|
+
required=False,
|
|
303
|
+
label="Prefix",
|
|
304
|
+
)
|
|
305
|
+
rfc2317_parent_managed = forms.NullBooleanField(
|
|
306
|
+
required=False,
|
|
307
|
+
label="Parent Managed",
|
|
308
|
+
)
|
|
309
|
+
rfc2317_parent_zone_id = DynamicModelMultipleChoiceField(
|
|
310
|
+
queryset=Zone.objects.all(),
|
|
311
|
+
required=False,
|
|
312
|
+
label="Parent Zone",
|
|
313
|
+
)
|
|
279
314
|
registrar_id = DynamicModelMultipleChoiceField(
|
|
280
315
|
queryset=Registrar.objects.all(),
|
|
281
316
|
required=False,
|
|
@@ -439,87 +474,6 @@ class ZoneImportForm(NetBoxModelImportForm):
|
|
|
439
474
|
help_text="Assigned tenant",
|
|
440
475
|
)
|
|
441
476
|
|
|
442
|
-
def _get_default_value(self, field):
|
|
443
|
-
_default_values = settings.PLUGINS_CONFIG.get("netbox_dns", {})
|
|
444
|
-
if _default_values.get("zone_soa_ttl", None) is None:
|
|
445
|
-
_default_values["zone_soa_ttl"] = _default_values.get(
|
|
446
|
-
"zone_default_ttl", None
|
|
447
|
-
)
|
|
448
|
-
|
|
449
|
-
return _default_values.get(f"zone_{field}", None)
|
|
450
|
-
|
|
451
|
-
def _clean_field_with_defaults(self, field):
|
|
452
|
-
if self.cleaned_data[field]:
|
|
453
|
-
value = self.cleaned_data[field]
|
|
454
|
-
else:
|
|
455
|
-
value = self._get_default_value(field)
|
|
456
|
-
|
|
457
|
-
if value is None:
|
|
458
|
-
raise ValidationError(f"{field} not set and no default value available")
|
|
459
|
-
|
|
460
|
-
return value
|
|
461
|
-
|
|
462
|
-
def clean_default_ttl(self):
|
|
463
|
-
return self._clean_field_with_defaults("default_ttl")
|
|
464
|
-
|
|
465
|
-
def clean_soa_ttl(self):
|
|
466
|
-
return self._clean_field_with_defaults("soa_ttl")
|
|
467
|
-
|
|
468
|
-
def clean_soa_mname(self):
|
|
469
|
-
soa_mname = self._clean_field_with_defaults("soa_mname")
|
|
470
|
-
if isinstance(soa_mname, str):
|
|
471
|
-
try:
|
|
472
|
-
soa_mname = NameServer.objects.get(name=soa_mname)
|
|
473
|
-
except NameServer.DoesNotExist:
|
|
474
|
-
raise ValidationError(f"Default name server {soa_mname} does not exist")
|
|
475
|
-
|
|
476
|
-
return soa_mname
|
|
477
|
-
|
|
478
|
-
def clean_soa_rname(self):
|
|
479
|
-
return self._clean_field_with_defaults("soa_rname")
|
|
480
|
-
|
|
481
|
-
def clean_soa_refresh(self):
|
|
482
|
-
return self._clean_field_with_defaults("soa_refresh")
|
|
483
|
-
|
|
484
|
-
def clean_soa_retry(self):
|
|
485
|
-
return self._clean_field_with_defaults("soa_retry")
|
|
486
|
-
|
|
487
|
-
def clean_soa_expire(self):
|
|
488
|
-
return self._clean_field_with_defaults("soa_expire")
|
|
489
|
-
|
|
490
|
-
def clean_soa_minimum(self):
|
|
491
|
-
return self._clean_field_with_defaults("soa_minimum")
|
|
492
|
-
|
|
493
|
-
def clean(self, *args, **kwargs):
|
|
494
|
-
super().clean(*args, **kwargs)
|
|
495
|
-
|
|
496
|
-
soa_serial_auto = self.cleaned_data.get("soa_serial_auto")
|
|
497
|
-
soa_serial = self.cleaned_data.get("soa_serial")
|
|
498
|
-
|
|
499
|
-
if soa_serial is None:
|
|
500
|
-
soa_serial = self._get_default_value("soa_serial")
|
|
501
|
-
|
|
502
|
-
if soa_serial_auto is None:
|
|
503
|
-
if self._get_default_value("soa_serial_auto") is not None:
|
|
504
|
-
soa_serial_auto = self._get_default_value("soa_serial_auto")
|
|
505
|
-
|
|
506
|
-
elif soa_serial is not None:
|
|
507
|
-
soa_serial_auto = False
|
|
508
|
-
|
|
509
|
-
else:
|
|
510
|
-
raise ValidationError(
|
|
511
|
-
"SOA Serial Auto not set and no default value and SOA Serial available"
|
|
512
|
-
)
|
|
513
|
-
|
|
514
|
-
if "soa_serial_auto" in self.cleaned_data:
|
|
515
|
-
self.cleaned_data["soa_serial_auto"] = soa_serial_auto
|
|
516
|
-
|
|
517
|
-
if "soa_serial" in self.cleaned_data:
|
|
518
|
-
if soa_serial_auto:
|
|
519
|
-
self.cleaned_data["soa_serial"] = None
|
|
520
|
-
else:
|
|
521
|
-
self.cleaned_data["soa_serial"] = soa_serial
|
|
522
|
-
|
|
523
477
|
class Meta:
|
|
524
478
|
model = Zone
|
|
525
479
|
|
|
@@ -551,6 +505,27 @@ class ZoneImportForm(NetBoxModelImportForm):
|
|
|
551
505
|
"tags",
|
|
552
506
|
)
|
|
553
507
|
|
|
508
|
+
def clean_view(self):
|
|
509
|
+
view = self.cleaned_data.get("view")
|
|
510
|
+
if view is None:
|
|
511
|
+
return View.get_default_view()
|
|
512
|
+
|
|
513
|
+
return view
|
|
514
|
+
|
|
515
|
+
def clean_nameservers(self):
|
|
516
|
+
nameservers = self.cleaned_data.get("nameservers")
|
|
517
|
+
zone_defaults = settings.PLUGINS_CONFIG.get("netbox_dns")
|
|
518
|
+
|
|
519
|
+
if (
|
|
520
|
+
self.data.get("nameservers") is None
|
|
521
|
+
and zone_defaults.get("zone_nameservers") is not None
|
|
522
|
+
):
|
|
523
|
+
nameservers = NameServer.objects.filter(
|
|
524
|
+
name__in=zone_defaults.get("zone_nameservers")
|
|
525
|
+
)
|
|
526
|
+
|
|
527
|
+
return nameservers
|
|
528
|
+
|
|
554
529
|
|
|
555
530
|
class ZoneBulkEditForm(NetBoxModelBulkEditForm):
|
|
556
531
|
view = DynamicModelChoiceField(
|
|
@@ -592,7 +567,7 @@ class ZoneBulkEditForm(NetBoxModelBulkEditForm):
|
|
|
592
567
|
)
|
|
593
568
|
soa_rname = forms.CharField(
|
|
594
569
|
required=False,
|
|
595
|
-
label="SOA
|
|
570
|
+
label="SOA RName",
|
|
596
571
|
)
|
|
597
572
|
soa_serial_auto = forms.NullBooleanField(
|
|
598
573
|
required=False,
|
|
@@ -729,7 +704,6 @@ class ZoneBulkEditForm(NetBoxModelBulkEditForm):
|
|
|
729
704
|
)
|
|
730
705
|
|
|
731
706
|
nullable_fields = (
|
|
732
|
-
"view",
|
|
733
707
|
"description",
|
|
734
708
|
"rfc2317_prefix",
|
|
735
709
|
"registrar",
|
|
@@ -739,8 +713,3 @@ class ZoneBulkEditForm(NetBoxModelBulkEditForm):
|
|
|
739
713
|
"tech_c",
|
|
740
714
|
"billing_c",
|
|
741
715
|
)
|
|
742
|
-
|
|
743
|
-
def clean(self):
|
|
744
|
-
cleaned_data = super().clean()
|
|
745
|
-
if cleaned_data.get("soa_serial_auto"):
|
|
746
|
-
cleaned_data["soa_serial"] = None
|
netbox_dns/graphql/types.py
CHANGED
|
@@ -36,10 +36,7 @@ class NetBoxDNSZoneType(NetBoxObjectType):
|
|
|
36
36
|
name: str
|
|
37
37
|
status: str
|
|
38
38
|
active: bool
|
|
39
|
-
view: (
|
|
40
|
-
Annotated["NetBoxDNSViewType", strawberry.lazy("netbox_dns.graphql.types")]
|
|
41
|
-
| None
|
|
42
|
-
)
|
|
39
|
+
view: Annotated["NetBoxDNSViewType", strawberry.lazy("netbox_dns.graphql.types")]
|
|
43
40
|
nameservers: (
|
|
44
41
|
Annotated[
|
|
45
42
|
"NetBoxDNSNameServerType", strawberry.lazy("netbox_dns.graphql.types")
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# Generated by Django 5.0.1 on 2024-02-12 14:49
|
|
2
2
|
|
|
3
|
+
from dns import name as dns_name
|
|
4
|
+
|
|
3
5
|
import django.core.validators
|
|
4
6
|
import django.db.models.deletion
|
|
5
7
|
import netbox_dns.fields.address
|
|
@@ -48,9 +50,9 @@ def update_record_fqdn(apps, schema_editor):
|
|
|
48
50
|
|
|
49
51
|
for record in Record.objects.filter(fqdn__isnull=True):
|
|
50
52
|
zone = dns_name.from_text(record.zone.name, origin=dns_name.root)
|
|
51
|
-
|
|
53
|
+
_fqdn = dns_name.from_text(record.name, origin=zone)
|
|
52
54
|
|
|
53
|
-
record.fqdn =
|
|
55
|
+
record.fqdn = _fqdn.to_text()
|
|
54
56
|
|
|
55
57
|
record.save()
|
|
56
58
|
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
from django.db import migrations, models
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class Migration(migrations.Migration):
|
|
5
|
+
dependencies = [
|
|
6
|
+
("netbox_dns", "0002_contact_description_registrar_description"),
|
|
7
|
+
]
|
|
8
|
+
|
|
9
|
+
operations = [
|
|
10
|
+
migrations.AddField(
|
|
11
|
+
model_name="view",
|
|
12
|
+
name="default_view",
|
|
13
|
+
field=models.BooleanField(default=False),
|
|
14
|
+
),
|
|
15
|
+
]
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
from django.db import migrations
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def create_and_assign_default_view(apps, schema_editor):
|
|
5
|
+
View = apps.get_model("netbox_dns", "View")
|
|
6
|
+
Zone = apps.get_model("netbox_dns", "Zone")
|
|
7
|
+
|
|
8
|
+
default_view = View.objects.create(
|
|
9
|
+
name="_default_",
|
|
10
|
+
description="Default View",
|
|
11
|
+
default_view=True,
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
for zone in Zone.objects.filter(view=None):
|
|
15
|
+
zone.view = default_view
|
|
16
|
+
zone.save()
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class Migration(migrations.Migration):
|
|
20
|
+
dependencies = [
|
|
21
|
+
("netbox_dns", "0003_default_view"),
|
|
22
|
+
]
|
|
23
|
+
|
|
24
|
+
operations = [
|
|
25
|
+
migrations.RunPython(create_and_assign_default_view),
|
|
26
|
+
]
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import django.db.models.deletion
|
|
2
|
+
from django.db import migrations, models
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class Migration(migrations.Migration):
|
|
6
|
+
dependencies = [
|
|
7
|
+
("netbox_dns", "0004_create_and_assign_default_view"),
|
|
8
|
+
]
|
|
9
|
+
|
|
10
|
+
operations = [
|
|
11
|
+
migrations.AlterField(
|
|
12
|
+
model_name="zone",
|
|
13
|
+
name="view",
|
|
14
|
+
field=models.ForeignKey(
|
|
15
|
+
on_delete=django.db.models.deletion.PROTECT, to="netbox_dns.view"
|
|
16
|
+
),
|
|
17
|
+
),
|
|
18
|
+
]
|
|
@@ -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
|
+
}
|