netbox-plugin-dns 1.0.4__py3-none-any.whl → 1.0.6__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 +1 -1
- netbox_dns/api/nested_serializers.py +46 -1
- netbox_dns/api/serializers.py +2 -0
- netbox_dns/api/serializers_/contact.py +3 -0
- netbox_dns/api/serializers_/nameserver.py +4 -1
- netbox_dns/api/serializers_/record.py +5 -4
- netbox_dns/api/serializers_/record_template.py +58 -0
- netbox_dns/api/serializers_/registrar.py +3 -0
- netbox_dns/api/serializers_/view.py +3 -0
- netbox_dns/api/serializers_/zone.py +31 -6
- netbox_dns/api/serializers_/zone_template.py +130 -0
- netbox_dns/api/urls.py +4 -0
- netbox_dns/api/views.py +41 -1
- netbox_dns/choices/__init__.py +2 -0
- netbox_dns/choices/record.py +49 -0
- netbox_dns/choices/zone.py +20 -0
- netbox_dns/fields/address.py +6 -0
- netbox_dns/fields/network.py +3 -0
- netbox_dns/fields/rfc2317.py +6 -0
- netbox_dns/filtersets/__init__.py +3 -0
- netbox_dns/filtersets/contact.py +3 -0
- netbox_dns/filtersets/nameserver.py +3 -0
- netbox_dns/filtersets/record.py +5 -1
- netbox_dns/filtersets/record_template.py +54 -0
- netbox_dns/filtersets/registrar.py +3 -0
- netbox_dns/filtersets/view.py +3 -0
- netbox_dns/filtersets/zone.py +5 -8
- netbox_dns/filtersets/zone_template.py +116 -0
- netbox_dns/forms/__init__.py +2 -0
- netbox_dns/forms/contact.py +8 -0
- netbox_dns/forms/nameserver.py +21 -2
- netbox_dns/forms/record.py +24 -10
- netbox_dns/forms/record_template.py +220 -0
- netbox_dns/forms/registrar.py +8 -0
- netbox_dns/forms/view.py +10 -0
- netbox_dns/forms/zone.py +125 -41
- netbox_dns/forms/zone_template.py +298 -0
- netbox_dns/graphql/__init__.py +4 -0
- netbox_dns/graphql/filters.py +24 -1
- netbox_dns/graphql/schema.py +34 -1
- netbox_dns/graphql/types.py +70 -1
- netbox_dns/management/commands/cleanup_database.py +2 -6
- netbox_dns/management/commands/cleanup_rrset_ttl.py +2 -4
- netbox_dns/migrations/0001_squashed_netbox_dns_0_22.py +1 -2
- netbox_dns/migrations/0006_templating.py +172 -0
- netbox_dns/migrations/0021_record_ip_address.py +1 -1
- netbox_dns/mixins/object_modification.py +5 -0
- netbox_dns/models/__init__.py +7 -0
- netbox_dns/models/contact.py +6 -0
- netbox_dns/models/nameserver.py +8 -1
- netbox_dns/models/record.py +13 -122
- netbox_dns/models/record_template.py +180 -0
- netbox_dns/models/registrar.py +6 -0
- netbox_dns/models/view.py +7 -1
- netbox_dns/models/zone.py +63 -71
- netbox_dns/models/zone_template.py +150 -0
- netbox_dns/navigation.py +47 -0
- netbox_dns/tables/__init__.py +2 -0
- netbox_dns/tables/contact.py +3 -0
- netbox_dns/tables/nameserver.py +3 -2
- netbox_dns/tables/record.py +7 -3
- netbox_dns/tables/record_template.py +91 -0
- netbox_dns/tables/registrar.py +3 -0
- netbox_dns/tables/view.py +3 -0
- netbox_dns/tables/zone.py +3 -2
- netbox_dns/tables/zone_template.py +70 -0
- netbox_dns/template_content.py +2 -8
- netbox_dns/templates/netbox_dns/recordtemplate.html +84 -0
- netbox_dns/templates/netbox_dns/zonetemplate.html +86 -0
- netbox_dns/urls/__init__.py +4 -0
- netbox_dns/urls/record_template.py +65 -0
- netbox_dns/urls/zone_template.py +57 -0
- netbox_dns/utilities/ipam_coupling.py +2 -1
- netbox_dns/validators/__init__.py +1 -0
- netbox_dns/validators/dns_name.py +14 -9
- netbox_dns/validators/dns_value.py +83 -0
- netbox_dns/validators/rfc2317.py +7 -0
- netbox_dns/views/__init__.py +2 -0
- netbox_dns/views/contact.py +12 -0
- netbox_dns/views/nameserver.py +13 -0
- netbox_dns/views/record.py +14 -1
- netbox_dns/views/record_template.py +83 -0
- netbox_dns/views/registrar.py +12 -0
- netbox_dns/views/view.py +12 -0
- netbox_dns/views/zone.py +16 -0
- netbox_dns/views/zone_template.py +73 -0
- {netbox_plugin_dns-1.0.4.dist-info → netbox_plugin_dns-1.0.6.dist-info}/METADATA +2 -1
- netbox_plugin_dns-1.0.6.dist-info/RECORD +136 -0
- netbox_plugin_dns-1.0.4.dist-info/RECORD +0 -115
- {netbox_plugin_dns-1.0.4.dist-info → netbox_plugin_dns-1.0.6.dist-info}/LICENSE +0 -0
- {netbox_plugin_dns-1.0.4.dist-info → netbox_plugin_dns-1.0.6.dist-info}/WHEEL +0 -0
netbox_dns/graphql/schema.py
CHANGED
|
@@ -3,7 +3,16 @@ from typing import List
|
|
|
3
3
|
import strawberry
|
|
4
4
|
import strawberry_django
|
|
5
5
|
|
|
6
|
-
from netbox_dns.models import
|
|
6
|
+
from netbox_dns.models import (
|
|
7
|
+
NameServer,
|
|
8
|
+
View,
|
|
9
|
+
Zone,
|
|
10
|
+
Record,
|
|
11
|
+
Contact,
|
|
12
|
+
Registrar,
|
|
13
|
+
ZoneTemplate,
|
|
14
|
+
RecordTemplate,
|
|
15
|
+
)
|
|
7
16
|
from .types import (
|
|
8
17
|
NetBoxDNSNameServerType,
|
|
9
18
|
NetBoxDNSViewType,
|
|
@@ -11,6 +20,8 @@ from .types import (
|
|
|
11
20
|
NetBoxDNSRecordType,
|
|
12
21
|
NetBoxDNSContactType,
|
|
13
22
|
NetBoxDNSRegistrarType,
|
|
23
|
+
NetBoxDNSZoneTemplateType,
|
|
24
|
+
NetBoxDNSRecordTemplateType,
|
|
14
25
|
)
|
|
15
26
|
|
|
16
27
|
|
|
@@ -68,3 +79,25 @@ class NetBoxDNSRegistrarQuery:
|
|
|
68
79
|
return Registrar.objects.get(pk=id)
|
|
69
80
|
|
|
70
81
|
netbox_dns_registrar_list: List[NetBoxDNSRegistrarType] = strawberry_django.field()
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
@strawberry.type
|
|
85
|
+
class NetBoxDNSZoneTemplateQuery:
|
|
86
|
+
@strawberry.field
|
|
87
|
+
def netbox_dns_zone_template(self, id: int) -> NetBoxDNSZoneTemplateType:
|
|
88
|
+
return ZoneTemplate.objects.get(pk=id)
|
|
89
|
+
|
|
90
|
+
netbox_dns_zone_template_list: List[NetBoxDNSZoneTemplateType] = (
|
|
91
|
+
strawberry_django.field()
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
@strawberry.type
|
|
96
|
+
class NetBoxDNSRecordTemplateQuery:
|
|
97
|
+
@strawberry.field
|
|
98
|
+
def netbox_dns_record_template(self, id: int) -> NetBoxDNSRecordTemplateType:
|
|
99
|
+
return RecordTemplate.objects.get(pk=id)
|
|
100
|
+
|
|
101
|
+
netbox_dns_record_template_list: List[NetBoxDNSRecordTemplateType] = (
|
|
102
|
+
strawberry_django.field()
|
|
103
|
+
)
|
netbox_dns/graphql/types.py
CHANGED
|
@@ -6,7 +6,16 @@ import strawberry_django
|
|
|
6
6
|
from netbox.graphql.types import NetBoxObjectType
|
|
7
7
|
from netbox.graphql.scalars import BigInt
|
|
8
8
|
|
|
9
|
-
from netbox_dns.models import
|
|
9
|
+
from netbox_dns.models import (
|
|
10
|
+
NameServer,
|
|
11
|
+
View,
|
|
12
|
+
Zone,
|
|
13
|
+
Record,
|
|
14
|
+
Contact,
|
|
15
|
+
Registrar,
|
|
16
|
+
ZoneTemplate,
|
|
17
|
+
RecordTemplate,
|
|
18
|
+
)
|
|
10
19
|
from .filters import (
|
|
11
20
|
NetBoxDNSNameServerFilter,
|
|
12
21
|
NetBoxDNSViewFilter,
|
|
@@ -14,6 +23,8 @@ from .filters import (
|
|
|
14
23
|
NetBoxDNSRecordFilter,
|
|
15
24
|
NetBoxDNSContactFilter,
|
|
16
25
|
NetBoxDNSRegistrarFilter,
|
|
26
|
+
NetBoxDNSZoneTemplateFilter,
|
|
27
|
+
NetBoxDNSRecordTemplateFilter,
|
|
17
28
|
)
|
|
18
29
|
|
|
19
30
|
|
|
@@ -140,3 +151,61 @@ class NetBoxDNSRegistrarType(NetBoxObjectType):
|
|
|
140
151
|
address: str
|
|
141
152
|
abuse_email: str
|
|
142
153
|
abuse_phone: str
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
@strawberry_django.type(
|
|
157
|
+
ZoneTemplate, fields="__all__", filters=NetBoxDNSZoneTemplateFilter
|
|
158
|
+
)
|
|
159
|
+
class NetBoxDNSZoneTemplateType(NetBoxObjectType):
|
|
160
|
+
name: str
|
|
161
|
+
nameservers: List[
|
|
162
|
+
Annotated[
|
|
163
|
+
"NetBoxDNSNameServerType", strawberry.lazy("netbox_dns.graphql.types")
|
|
164
|
+
]
|
|
165
|
+
]
|
|
166
|
+
record_templates: List[
|
|
167
|
+
Annotated[
|
|
168
|
+
"NetBoxDNSRecordTemplateType", strawberry.lazy("netbox_dns.graphql.types")
|
|
169
|
+
]
|
|
170
|
+
]
|
|
171
|
+
description: str | None
|
|
172
|
+
tenant: Annotated["TenantType", strawberry.lazy("tenancy.graphql.types")] | None
|
|
173
|
+
registrar: (
|
|
174
|
+
Annotated["NetBoxDNSRegistrarType", strawberry.lazy("netbox_dns.graphql.types")]
|
|
175
|
+
| None
|
|
176
|
+
)
|
|
177
|
+
registrant: (
|
|
178
|
+
Annotated["NetBoxDNSContactType", strawberry.lazy("netbox_dns.graphql.types")]
|
|
179
|
+
| None
|
|
180
|
+
)
|
|
181
|
+
admin_c: (
|
|
182
|
+
Annotated["NetBoxDNSContactType", strawberry.lazy("netbox_dns.graphql.types")]
|
|
183
|
+
| None
|
|
184
|
+
)
|
|
185
|
+
tech_c: (
|
|
186
|
+
Annotated["NetBoxDNSContactType", strawberry.lazy("netbox_dns.graphql.types")]
|
|
187
|
+
| None
|
|
188
|
+
)
|
|
189
|
+
billing_c: (
|
|
190
|
+
Annotated["NetBoxDNSContactType", strawberry.lazy("netbox_dns.graphql.types")]
|
|
191
|
+
| None
|
|
192
|
+
)
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
@strawberry_django.type(
|
|
196
|
+
RecordTemplate, fields="__all__", filters=NetBoxDNSRecordTemplateFilter
|
|
197
|
+
)
|
|
198
|
+
class NetBoxDNSRecordTemplateType(NetBoxObjectType):
|
|
199
|
+
name: str
|
|
200
|
+
record_name: str
|
|
201
|
+
type: str
|
|
202
|
+
value: str
|
|
203
|
+
ttl: BigInt | None
|
|
204
|
+
disable_ptr: bool
|
|
205
|
+
description: str | None
|
|
206
|
+
tenant: Annotated["TenantType", strawberry.lazy("tenancy.graphql.types")] | None
|
|
207
|
+
zone_templates: List[
|
|
208
|
+
Annotated[
|
|
209
|
+
"NetBoxDNSZoneTemplateType", strawberry.lazy("netbox_dns.graphql.types")
|
|
210
|
+
]
|
|
211
|
+
]
|
|
@@ -2,12 +2,8 @@ from netaddr import IPAddress, IPNetwork, AddrFormatError
|
|
|
2
2
|
|
|
3
3
|
from django.core.management.base import BaseCommand
|
|
4
4
|
|
|
5
|
-
from netbox_dns.models import
|
|
6
|
-
|
|
7
|
-
ZoneStatusChoices,
|
|
8
|
-
Record,
|
|
9
|
-
RecordTypeChoices,
|
|
10
|
-
)
|
|
5
|
+
from netbox_dns.models import Zone, Record
|
|
6
|
+
from netbox_dns.choices import ZoneStatusChoices, RecordTypeChoices
|
|
11
7
|
|
|
12
8
|
|
|
13
9
|
def zone_rename_passive_status_to_parked(verbose=False):
|
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
from django.core.management.base import BaseCommand
|
|
2
2
|
from django.db.models import Max, Min
|
|
3
3
|
|
|
4
|
-
from netbox_dns.models import
|
|
5
|
-
|
|
6
|
-
RecordTypeChoices,
|
|
7
|
-
)
|
|
4
|
+
from netbox_dns.models import Record
|
|
5
|
+
from netbox_dns.choices import RecordTypeChoices
|
|
8
6
|
|
|
9
7
|
|
|
10
8
|
class Command(BaseCommand):
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
# Generated by Django 5.0.7 on 2024-07-12 11:38
|
|
2
|
+
|
|
3
|
+
import django.db.models.deletion
|
|
4
|
+
import taggit.managers
|
|
5
|
+
import utilities.json
|
|
6
|
+
from django.db import migrations, models
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class Migration(migrations.Migration):
|
|
10
|
+
|
|
11
|
+
dependencies = [
|
|
12
|
+
("extras", "0115_convert_dashboard_widgets"),
|
|
13
|
+
("netbox_dns", "0005_alter_zone_view_not_null"),
|
|
14
|
+
("tenancy", "0015_contactassignment_rename_content_type"),
|
|
15
|
+
]
|
|
16
|
+
|
|
17
|
+
operations = [
|
|
18
|
+
migrations.CreateModel(
|
|
19
|
+
name="RecordTemplate",
|
|
20
|
+
fields=[
|
|
21
|
+
(
|
|
22
|
+
"id",
|
|
23
|
+
models.BigAutoField(
|
|
24
|
+
auto_created=True, primary_key=True, serialize=False
|
|
25
|
+
),
|
|
26
|
+
),
|
|
27
|
+
("created", models.DateTimeField(auto_now_add=True, null=True)),
|
|
28
|
+
("last_updated", models.DateTimeField(auto_now=True, null=True)),
|
|
29
|
+
(
|
|
30
|
+
"custom_field_data",
|
|
31
|
+
models.JSONField(
|
|
32
|
+
blank=True,
|
|
33
|
+
default=dict,
|
|
34
|
+
encoder=utilities.json.CustomFieldJSONEncoder,
|
|
35
|
+
),
|
|
36
|
+
),
|
|
37
|
+
("name", models.CharField(max_length=200, unique=True)),
|
|
38
|
+
("record_name", models.CharField(max_length=255)),
|
|
39
|
+
("description", models.CharField(blank=True, max_length=200)),
|
|
40
|
+
("type", models.CharField()),
|
|
41
|
+
("value", models.CharField(max_length=65535)),
|
|
42
|
+
("status", models.CharField(default="active")),
|
|
43
|
+
("ttl", models.PositiveIntegerField(blank=True, null=True)),
|
|
44
|
+
("disable_ptr", models.BooleanField(default=False)),
|
|
45
|
+
(
|
|
46
|
+
"tags",
|
|
47
|
+
taggit.managers.TaggableManager(
|
|
48
|
+
through="extras.TaggedItem", to="extras.Tag"
|
|
49
|
+
),
|
|
50
|
+
),
|
|
51
|
+
(
|
|
52
|
+
"tenant",
|
|
53
|
+
models.ForeignKey(
|
|
54
|
+
blank=True,
|
|
55
|
+
null=True,
|
|
56
|
+
on_delete=django.db.models.deletion.PROTECT,
|
|
57
|
+
related_name="+",
|
|
58
|
+
to="tenancy.tenant",
|
|
59
|
+
),
|
|
60
|
+
),
|
|
61
|
+
],
|
|
62
|
+
options={
|
|
63
|
+
"ordering": ["name"],
|
|
64
|
+
},
|
|
65
|
+
),
|
|
66
|
+
migrations.CreateModel(
|
|
67
|
+
name="ZoneTemplate",
|
|
68
|
+
fields=[
|
|
69
|
+
(
|
|
70
|
+
"id",
|
|
71
|
+
models.BigAutoField(
|
|
72
|
+
auto_created=True, primary_key=True, serialize=False
|
|
73
|
+
),
|
|
74
|
+
),
|
|
75
|
+
("created", models.DateTimeField(auto_now_add=True, null=True)),
|
|
76
|
+
("last_updated", models.DateTimeField(auto_now=True, null=True)),
|
|
77
|
+
(
|
|
78
|
+
"custom_field_data",
|
|
79
|
+
models.JSONField(
|
|
80
|
+
blank=True,
|
|
81
|
+
default=dict,
|
|
82
|
+
encoder=utilities.json.CustomFieldJSONEncoder,
|
|
83
|
+
),
|
|
84
|
+
),
|
|
85
|
+
("name", models.CharField(max_length=200, unique=True)),
|
|
86
|
+
("description", models.CharField(blank=True, max_length=200)),
|
|
87
|
+
(
|
|
88
|
+
"admin_c",
|
|
89
|
+
models.ForeignKey(
|
|
90
|
+
blank=True,
|
|
91
|
+
null=True,
|
|
92
|
+
on_delete=django.db.models.deletion.SET_NULL,
|
|
93
|
+
related_name="+",
|
|
94
|
+
to="netbox_dns.contact",
|
|
95
|
+
),
|
|
96
|
+
),
|
|
97
|
+
(
|
|
98
|
+
"billing_c",
|
|
99
|
+
models.ForeignKey(
|
|
100
|
+
blank=True,
|
|
101
|
+
null=True,
|
|
102
|
+
on_delete=django.db.models.deletion.SET_NULL,
|
|
103
|
+
related_name="+",
|
|
104
|
+
to="netbox_dns.contact",
|
|
105
|
+
),
|
|
106
|
+
),
|
|
107
|
+
(
|
|
108
|
+
"nameservers",
|
|
109
|
+
models.ManyToManyField(
|
|
110
|
+
blank=True, related_name="+", to="netbox_dns.nameserver"
|
|
111
|
+
),
|
|
112
|
+
),
|
|
113
|
+
(
|
|
114
|
+
"record_templates",
|
|
115
|
+
models.ManyToManyField(
|
|
116
|
+
blank=True,
|
|
117
|
+
related_name="zone_templates",
|
|
118
|
+
to="netbox_dns.recordtemplate",
|
|
119
|
+
),
|
|
120
|
+
),
|
|
121
|
+
(
|
|
122
|
+
"registrant",
|
|
123
|
+
models.ForeignKey(
|
|
124
|
+
blank=True,
|
|
125
|
+
null=True,
|
|
126
|
+
on_delete=django.db.models.deletion.SET_NULL,
|
|
127
|
+
related_name="+",
|
|
128
|
+
to="netbox_dns.contact",
|
|
129
|
+
),
|
|
130
|
+
),
|
|
131
|
+
(
|
|
132
|
+
"registrar",
|
|
133
|
+
models.ForeignKey(
|
|
134
|
+
blank=True,
|
|
135
|
+
null=True,
|
|
136
|
+
on_delete=django.db.models.deletion.SET_NULL,
|
|
137
|
+
related_name="+",
|
|
138
|
+
to="netbox_dns.registrar",
|
|
139
|
+
),
|
|
140
|
+
),
|
|
141
|
+
(
|
|
142
|
+
"tags",
|
|
143
|
+
taggit.managers.TaggableManager(
|
|
144
|
+
through="extras.TaggedItem", to="extras.Tag"
|
|
145
|
+
),
|
|
146
|
+
),
|
|
147
|
+
(
|
|
148
|
+
"tech_c",
|
|
149
|
+
models.ForeignKey(
|
|
150
|
+
blank=True,
|
|
151
|
+
null=True,
|
|
152
|
+
on_delete=django.db.models.deletion.SET_NULL,
|
|
153
|
+
related_name="+",
|
|
154
|
+
to="netbox_dns.contact",
|
|
155
|
+
),
|
|
156
|
+
),
|
|
157
|
+
(
|
|
158
|
+
"tenant",
|
|
159
|
+
models.ForeignKey(
|
|
160
|
+
blank=True,
|
|
161
|
+
null=True,
|
|
162
|
+
on_delete=django.db.models.deletion.SET_NULL,
|
|
163
|
+
related_name="+",
|
|
164
|
+
to="tenancy.tenant",
|
|
165
|
+
),
|
|
166
|
+
),
|
|
167
|
+
],
|
|
168
|
+
options={
|
|
169
|
+
"ordering": ["name"],
|
|
170
|
+
},
|
|
171
|
+
),
|
|
172
|
+
]
|
|
@@ -5,7 +5,7 @@ import django.db.models.deletion
|
|
|
5
5
|
from django.db import migrations, models
|
|
6
6
|
|
|
7
7
|
import netbox_dns.fields.address
|
|
8
|
-
from netbox_dns.
|
|
8
|
+
from netbox_dns.choices import RecordTypeChoices
|
|
9
9
|
from netbox_dns.utilities import arpa_to_prefix
|
|
10
10
|
|
|
11
11
|
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
from netbox.models import NetBoxModel
|
|
2
2
|
|
|
3
3
|
|
|
4
|
+
__all__ = ("ObjectModificationMixin",)
|
|
5
|
+
|
|
6
|
+
|
|
4
7
|
class ObjectModificationMixin:
|
|
5
8
|
def __init__(self, *args, **kwargs):
|
|
6
9
|
super().__init__(*args, **kwargs)
|
|
@@ -12,6 +15,8 @@ class ObjectModificationMixin:
|
|
|
12
15
|
- {"id"}
|
|
13
16
|
)
|
|
14
17
|
|
|
18
|
+
self.__class__.check_fields.add("custom_field_data")
|
|
19
|
+
|
|
15
20
|
@property
|
|
16
21
|
def changed_fields(self):
|
|
17
22
|
if self.pk is None:
|
netbox_dns/models/__init__.py
CHANGED
|
@@ -4,5 +4,12 @@ from .record import *
|
|
|
4
4
|
from .view import *
|
|
5
5
|
from .contact import *
|
|
6
6
|
from .registrar import *
|
|
7
|
+
from .zone_template import *
|
|
8
|
+
from .record_template import *
|
|
9
|
+
|
|
10
|
+
# +
|
|
11
|
+
# Backwards compatibility fix, will be removed in version 1.1
|
|
12
|
+
# -
|
|
13
|
+
from netbox_dns.choices import *
|
|
7
14
|
|
|
8
15
|
from netbox_dns.signals import ipam_coupling
|
netbox_dns/models/contact.py
CHANGED
|
@@ -7,6 +7,12 @@ from netbox.search import SearchIndex, register_search
|
|
|
7
7
|
from taggit.managers import TaggableManager
|
|
8
8
|
|
|
9
9
|
|
|
10
|
+
__all__ = (
|
|
11
|
+
"Contact",
|
|
12
|
+
"ContactIndex",
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
|
|
10
16
|
class Contact(NetBoxModel):
|
|
11
17
|
# +
|
|
12
18
|
# Data fields according to https://www.icann.org/resources/pages/rdds-labeling-policy-2017-02-01-en
|
netbox_dns/models/nameserver.py
CHANGED
|
@@ -13,10 +13,17 @@ from netbox_dns.utilities import (
|
|
|
13
13
|
normalize_name,
|
|
14
14
|
NameFormatError,
|
|
15
15
|
)
|
|
16
|
+
from netbox_dns.choices import RecordTypeChoices
|
|
16
17
|
from netbox_dns.validators import validate_fqdn
|
|
17
18
|
from netbox_dns.mixins import ObjectModificationMixin
|
|
18
19
|
|
|
19
|
-
from .record import Record
|
|
20
|
+
from .record import Record
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
__all__ = (
|
|
24
|
+
"NameServer",
|
|
25
|
+
"NameServerIndex",
|
|
26
|
+
)
|
|
20
27
|
|
|
21
28
|
|
|
22
29
|
class NameServer(ObjectModificationMixin, NetBoxModel):
|
netbox_dns/models/record.py
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import ipaddress
|
|
2
2
|
|
|
3
3
|
import dns
|
|
4
|
-
from dns import rdata, rdatatype, rdataclass
|
|
5
4
|
from dns import name as dns_name
|
|
6
5
|
|
|
7
6
|
from django.core.exceptions import ValidationError
|
|
@@ -13,24 +12,23 @@ from netbox.models import NetBoxModel
|
|
|
13
12
|
from netbox.search import SearchIndex, register_search
|
|
14
13
|
from netbox.plugins.utils import get_plugin_config
|
|
15
14
|
from utilities.querysets import RestrictedQuerySet
|
|
16
|
-
from utilities.choices import ChoiceSet
|
|
17
15
|
|
|
18
16
|
from netbox_dns.fields import AddressField
|
|
19
|
-
from netbox_dns.utilities import
|
|
20
|
-
|
|
21
|
-
name_to_unicode,
|
|
22
|
-
)
|
|
23
|
-
from netbox_dns.validators import (
|
|
24
|
-
validate_fqdn,
|
|
25
|
-
validate_generic_name,
|
|
26
|
-
validate_domain_name,
|
|
27
|
-
)
|
|
17
|
+
from netbox_dns.utilities import arpa_to_prefix, name_to_unicode
|
|
18
|
+
from netbox_dns.validators import validate_generic_name, validate_record_value
|
|
28
19
|
from netbox_dns.mixins import ObjectModificationMixin
|
|
20
|
+
from netbox_dns.choices import RecordTypeChoices, RecordStatusChoices
|
|
29
21
|
|
|
30
22
|
# +
|
|
31
23
|
# This is a hack designed to break cyclic imports between Record and Zone
|
|
32
24
|
# -
|
|
33
|
-
|
|
25
|
+
from netbox_dns.models import zone
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
__all__ = (
|
|
29
|
+
"Record",
|
|
30
|
+
"RecordIndex",
|
|
31
|
+
)
|
|
34
32
|
|
|
35
33
|
|
|
36
34
|
def min_ttl(*ttl_list):
|
|
@@ -64,45 +62,6 @@ class RecordManager(models.Manager.from_queryset(RestrictedQuerySet)):
|
|
|
64
62
|
)
|
|
65
63
|
|
|
66
64
|
|
|
67
|
-
def initialize_choice_names(cls):
|
|
68
|
-
for choice in cls.CHOICES:
|
|
69
|
-
setattr(cls, choice[0], choice[0])
|
|
70
|
-
return cls
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
@initialize_choice_names
|
|
74
|
-
class RecordTypeChoices(ChoiceSet):
|
|
75
|
-
CHOICES = [
|
|
76
|
-
(rdtype.name, rdtype.name)
|
|
77
|
-
for rdtype in sorted(rdatatype.RdataType, key=lambda a: a.name)
|
|
78
|
-
if not rdatatype.is_metatype(rdtype)
|
|
79
|
-
]
|
|
80
|
-
SINGLETONS = [
|
|
81
|
-
rdtype.name for rdtype in rdatatype.RdataType if rdatatype.is_singleton(rdtype)
|
|
82
|
-
]
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
@initialize_choice_names
|
|
86
|
-
class RecordClassChoices(ChoiceSet):
|
|
87
|
-
CHOICES = [
|
|
88
|
-
(rdclass.name, rdclass.name)
|
|
89
|
-
for rdclass in sorted(rdataclass.RdataClass)
|
|
90
|
-
if not rdataclass.is_metaclass(rdclass)
|
|
91
|
-
]
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
class RecordStatusChoices(ChoiceSet):
|
|
95
|
-
key = "Record.status"
|
|
96
|
-
|
|
97
|
-
STATUS_ACTIVE = "active"
|
|
98
|
-
STATUS_INACTIVE = "inactive"
|
|
99
|
-
|
|
100
|
-
CHOICES = [
|
|
101
|
-
(STATUS_ACTIVE, "Active", "blue"),
|
|
102
|
-
(STATUS_INACTIVE, "Inactive", "red"),
|
|
103
|
-
]
|
|
104
|
-
|
|
105
|
-
|
|
106
65
|
class Record(ObjectModificationMixin, NetBoxModel):
|
|
107
66
|
ACTIVE_STATUS_LIST = (RecordStatusChoices.STATUS_ACTIVE,)
|
|
108
67
|
|
|
@@ -513,78 +472,8 @@ class Record(ObjectModificationMixin, NetBoxModel):
|
|
|
513
472
|
) from None
|
|
514
473
|
|
|
515
474
|
def validate_value(self):
|
|
516
|
-
def _validate_idn(name):
|
|
517
|
-
try:
|
|
518
|
-
name.to_unicode()
|
|
519
|
-
except dns_name.IDNAException as exc:
|
|
520
|
-
raise ValidationError(
|
|
521
|
-
f"{name.to_text()} is not a valid IDN: {exc}."
|
|
522
|
-
) from None
|
|
523
|
-
|
|
524
475
|
try:
|
|
525
|
-
|
|
526
|
-
except dns.exception.SyntaxError as exc:
|
|
527
|
-
raise ValidationError(
|
|
528
|
-
{
|
|
529
|
-
"value": f"Record value {self.value} is not a valid value for a {self.type} record: {exc}."
|
|
530
|
-
}
|
|
531
|
-
) from None
|
|
532
|
-
|
|
533
|
-
try:
|
|
534
|
-
match self.type:
|
|
535
|
-
case RecordTypeChoices.CNAME:
|
|
536
|
-
_validate_idn(rr.target)
|
|
537
|
-
validate_domain_name(
|
|
538
|
-
rr.target.to_text(),
|
|
539
|
-
always_tolerant=True,
|
|
540
|
-
allow_empty_label=True,
|
|
541
|
-
)
|
|
542
|
-
|
|
543
|
-
case (
|
|
544
|
-
RecordTypeChoices.NS
|
|
545
|
-
| RecordTypeChoices.HTTPS
|
|
546
|
-
| RecordTypeChoices.SRV
|
|
547
|
-
| RecordTypeChoices.SVCB
|
|
548
|
-
):
|
|
549
|
-
_validate_idn(rr.target)
|
|
550
|
-
validate_domain_name(rr.target.to_text(), always_tolerant=True)
|
|
551
|
-
|
|
552
|
-
case RecordTypeChoices.DNAME:
|
|
553
|
-
_validate_idn(rr.target)
|
|
554
|
-
validate_domain_name(
|
|
555
|
-
rr.target.to_text(), always_tolerant=True, zone_name=True
|
|
556
|
-
)
|
|
557
|
-
|
|
558
|
-
case RecordTypeChoices.PTR | RecordTypeChoices.NSAP_PTR:
|
|
559
|
-
_validate_idn(rr.target)
|
|
560
|
-
validate_fqdn(rr.target.to_text(), always_tolerant=True)
|
|
561
|
-
|
|
562
|
-
case RecordTypeChoices.MX | RecordTypeChoices.RT | RecordTypeChoices.KX:
|
|
563
|
-
_validate_idn(rr.exchange)
|
|
564
|
-
validate_domain_name(rr.exchange.to_text(), always_tolerant=True)
|
|
565
|
-
|
|
566
|
-
case RecordTypeChoices.NSEC:
|
|
567
|
-
_validate_idn(rr.next)
|
|
568
|
-
validate_domain_name(rr.next.to_text(), always_tolerant=True)
|
|
569
|
-
|
|
570
|
-
case RecordTypeChoices.RP:
|
|
571
|
-
_validate_idn(rr.mbox)
|
|
572
|
-
validate_domain_name(rr.mbox.to_text(), always_tolerant=True)
|
|
573
|
-
_validate_idn(rr.txt)
|
|
574
|
-
validate_domain_name(rr.txt.to_text(), always_tolerant=True)
|
|
575
|
-
|
|
576
|
-
case RecordTypeChoices.NAPTR:
|
|
577
|
-
_validate_idn(rr.replacement)
|
|
578
|
-
validate_generic_name(
|
|
579
|
-
rr.replacement.to_text(), always_tolerant=True
|
|
580
|
-
)
|
|
581
|
-
|
|
582
|
-
case RecordTypeChoices.PX:
|
|
583
|
-
_validate_idn(rr.map822)
|
|
584
|
-
validate_domain_name(rr.map822.to_text(), always_tolerant=True)
|
|
585
|
-
_validate_idn(rr.mapx400)
|
|
586
|
-
validate_domain_name(rr.mapx400.to_text(), always_tolerant=True)
|
|
587
|
-
|
|
476
|
+
validate_record_value(self.type, self.value)
|
|
588
477
|
except ValidationError as exc:
|
|
589
478
|
raise ValidationError({"value": exc}) from None
|
|
590
479
|
|
|
@@ -631,6 +520,7 @@ class Record(ObjectModificationMixin, NetBoxModel):
|
|
|
631
520
|
)
|
|
632
521
|
.exclude(ttl=self.ttl)
|
|
633
522
|
.exclude(type=RecordTypeChoices.PTR, managed=True)
|
|
523
|
+
.exclude(status=RecordStatusChoices.STATUS_INACTIVE)
|
|
634
524
|
)
|
|
635
525
|
|
|
636
526
|
if not records.exists():
|
|
@@ -665,6 +555,7 @@ class Record(ObjectModificationMixin, NetBoxModel):
|
|
|
665
555
|
.exclude(pk=self.pk)
|
|
666
556
|
.exclude(ttl=ttl)
|
|
667
557
|
.exclude(type=RecordTypeChoices.PTR, managed=True)
|
|
558
|
+
.exclude(status=RecordStatusChoices.STATUS_INACTIVE)
|
|
668
559
|
)
|
|
669
560
|
|
|
670
561
|
for record in records:
|