netbox-plugin-dns 1.1.1__py3-none-any.whl → 1.1.3__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 +8 -6
- netbox_dns/api/nested_serializers.py +3 -2
- netbox_dns/api/serializers_/nameserver.py +2 -1
- netbox_dns/api/serializers_/record.py +5 -4
- netbox_dns/api/serializers_/record_template.py +2 -1
- netbox_dns/api/serializers_/view.py +3 -1
- netbox_dns/api/serializers_/zone.py +12 -11
- netbox_dns/api/serializers_/zone_template.py +8 -7
- netbox_dns/api/views.py +9 -4
- netbox_dns/choices/record.py +4 -2
- netbox_dns/choices/zone.py +6 -4
- netbox_dns/fields/address.py +2 -1
- netbox_dns/fields/network.py +2 -1
- netbox_dns/fields/rfc2317.py +7 -3
- netbox_dns/filtersets/nameserver.py +3 -2
- netbox_dns/filtersets/record.py +10 -9
- netbox_dns/filtersets/record_template.py +3 -2
- netbox_dns/filtersets/view.py +3 -2
- netbox_dns/filtersets/zone.py +24 -22
- netbox_dns/filtersets/zone_template.py +15 -14
- netbox_dns/forms/nameserver.py +41 -17
- netbox_dns/forms/record.py +43 -26
- netbox_dns/forms/record_template.py +49 -28
- netbox_dns/forms/registrar.py +21 -17
- netbox_dns/forms/registration_contact.py +37 -25
- netbox_dns/forms/view.py +75 -34
- netbox_dns/forms/zone.py +167 -120
- netbox_dns/forms/zone_template.py +53 -43
- netbox_dns/graphql/schema.py +0 -10
- netbox_dns/graphql/types.py +1 -0
- netbox_dns/locale/de/LC_MESSAGES/django.mo +0 -0
- netbox_dns/locale/en/LC_MESSAGES/django.mo +0 -0
- netbox_dns/management/commands/rebuild_dnssync.py +14 -1
- netbox_dns/migrations/0010_view_ip_address_filter.py +18 -0
- netbox_dns/mixins/object_modification.py +30 -8
- netbox_dns/models/nameserver.py +6 -2
- netbox_dns/models/record.py +95 -40
- netbox_dns/models/record_template.py +16 -8
- netbox_dns/models/registrar.py +11 -7
- netbox_dns/models/registration_contact.py +23 -11
- netbox_dns/models/view.py +54 -5
- netbox_dns/models/zone.py +77 -50
- netbox_dns/models/zone_template.py +12 -10
- netbox_dns/navigation.py +30 -28
- netbox_dns/signals/ipam_dnssync.py +25 -18
- netbox_dns/tables/ipam_dnssync.py +2 -1
- netbox_dns/tables/nameserver.py +2 -0
- netbox_dns/tables/record.py +21 -11
- netbox_dns/tables/record_template.py +12 -5
- netbox_dns/tables/registrar.py +2 -0
- netbox_dns/tables/registration_contact.py +2 -0
- netbox_dns/tables/view.py +4 -2
- netbox_dns/tables/zone.py +15 -2
- netbox_dns/tables/zone_template.py +7 -0
- netbox_dns/templates/netbox_dns/nameserver.html +6 -5
- netbox_dns/templates/netbox_dns/record/managed.html +2 -1
- netbox_dns/templates/netbox_dns/record/related.html +26 -14
- netbox_dns/templates/netbox_dns/record.html +39 -20
- netbox_dns/templates/netbox_dns/recordtemplate.html +27 -15
- netbox_dns/templates/netbox_dns/registrar.html +11 -10
- netbox_dns/templates/netbox_dns/registrationcontact.html +16 -15
- netbox_dns/templates/netbox_dns/view/button.html +2 -1
- netbox_dns/templates/netbox_dns/view/prefix.html +7 -4
- netbox_dns/templates/netbox_dns/view/related.html +26 -10
- netbox_dns/templates/netbox_dns/view.html +22 -9
- netbox_dns/templates/netbox_dns/zone/base.html +2 -1
- netbox_dns/templates/netbox_dns/zone/child.html +3 -2
- netbox_dns/templates/netbox_dns/zone/record.html +3 -2
- netbox_dns/templates/netbox_dns/zone/registration.html +8 -7
- netbox_dns/templates/netbox_dns/zone.html +28 -30
- netbox_dns/templates/netbox_dns/zonetemplate.html +27 -17
- netbox_dns/utilities/ipam_dnssync.py +71 -28
- netbox_dns/validators/dns_name.py +11 -4
- netbox_dns/validators/dns_value.py +9 -4
- netbox_dns/validators/rfc2317.py +6 -3
- netbox_dns/views/nameserver.py +4 -2
- netbox_dns/views/record_template.py +4 -3
- netbox_dns/views/registrar.py +3 -1
- netbox_dns/views/registration_contact.py +2 -1
- netbox_dns/views/view.py +2 -1
- netbox_dns/views/zone.py +6 -4
- netbox_dns/views/zone_template.py +8 -7
- {netbox_plugin_dns-1.1.1.dist-info → netbox_plugin_dns-1.1.3.dist-info}/METADATA +1 -1
- netbox_plugin_dns-1.1.3.dist-info/RECORD +150 -0
- {netbox_plugin_dns-1.1.1.dist-info → netbox_plugin_dns-1.1.3.dist-info}/WHEEL +1 -1
- netbox_plugin_dns-1.1.1.dist-info/RECORD +0 -147
- {netbox_plugin_dns-1.1.1.dist-info → netbox_plugin_dns-1.1.3.dist-info}/LICENSE +0 -0
- {netbox_plugin_dns-1.1.1.dist-info → netbox_plugin_dns-1.1.3.dist-info}/top_level.txt +0 -0
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
{% load helpers %}
|
|
3
3
|
{% load render_table from django_tables2 %}
|
|
4
4
|
{% load perms %}
|
|
5
|
+
{% load i18n %}
|
|
5
6
|
|
|
6
7
|
{% block content %}
|
|
7
8
|
{% include 'inc/table_controls_htmx.html' with table_modal="ZoneTable_config" %}
|
|
@@ -23,12 +24,12 @@
|
|
|
23
24
|
{% block bulk_buttons %}{% endblock %}
|
|
24
25
|
{% if bulk_edit_url and perms.netbox_dns.change_zone %}
|
|
25
26
|
<button type="submit" name="_edit" formaction="{% url bulk_edit_url %}{% if request.GET %}?{{ request.GET.urlencode }}{% endif %}" class="btn btn-warning">
|
|
26
|
-
<i class="mdi mdi-pencil" aria-hidden="true"></i> Edit Selected
|
|
27
|
+
<i class="mdi mdi-pencil" aria-hidden="true"></i> {% trans "Edit Selected" %}
|
|
27
28
|
</button>
|
|
28
29
|
{% endif %}
|
|
29
30
|
{% if bulk_delete_url and perms.netbox_dns.delete_zone %}
|
|
30
31
|
<button type="submit" name="_delete" formaction="{% url bulk_delete_url %}{% if request.GET %}?{{ request.GET.urlencode }}{% endif %}" class="btn btn-danger">
|
|
31
|
-
<i class="mdi mdi-trash-can-outline" aria-hidden="true"></i> Delete Selected
|
|
32
|
+
<i class="mdi mdi-trash-can-outline" aria-hidden="true"></i> {% trans "Delete Selected" %}
|
|
32
33
|
</button>
|
|
33
34
|
{% endif %}
|
|
34
35
|
</div>
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
{% load helpers %}
|
|
3
3
|
{% load render_table from django_tables2 %}
|
|
4
4
|
{% load perms %}
|
|
5
|
+
{% load i18n %}
|
|
5
6
|
|
|
6
7
|
{% block content %}
|
|
7
8
|
{% include 'inc/table_controls_htmx.html' with table_modal="RecordTable_config" %}
|
|
@@ -23,12 +24,12 @@
|
|
|
23
24
|
{% block bulk_buttons %}{% endblock %}
|
|
24
25
|
{% if bulk_edit_url and perms.netbox_dns.change_record %}
|
|
25
26
|
<button type="submit" name="_edit" formaction="{% url bulk_edit_url %}{% if request.GET %}?{{ request.GET.urlencode }}{% endif %}" class="btn btn-warning">
|
|
26
|
-
<i class="mdi mdi-pencil" aria-hidden="true"></i> Edit Selected
|
|
27
|
+
<i class="mdi mdi-pencil" aria-hidden="true"></i> {% trans "Edit Selected" %}
|
|
27
28
|
</button>
|
|
28
29
|
{% endif %}
|
|
29
30
|
{% if bulk_delete_url and perms.netbox_dns.delete_record %}
|
|
30
31
|
<button type="submit" name="_delete" formaction="{% url bulk_delete_url %}{% if request.GET %}?{{ request.GET.urlencode }}{% endif %}" class="btn btn-danger">
|
|
31
|
-
<i class="mdi mdi-trash-can-outline" aria-hidden="true"></i> Delete Selected
|
|
32
|
+
<i class="mdi mdi-trash-can-outline" aria-hidden="true"></i> {% trans "Delete Selected" %}
|
|
32
33
|
</button>
|
|
33
34
|
{% endif %}
|
|
34
35
|
</div>
|
|
@@ -1,32 +1,33 @@
|
|
|
1
1
|
{% extends 'netbox_dns/zone/base.html' %}
|
|
2
2
|
{% load helpers %}
|
|
3
|
+
{% load i18n %}
|
|
3
4
|
|
|
4
5
|
{% block content %}
|
|
5
6
|
<div class="card">
|
|
6
|
-
<h5 class="card-header">Domain Registration</h5>
|
|
7
|
+
<h5 class="card-header">{% trans "Domain Registration" %}</h5>
|
|
7
8
|
<table class="table table-hover attr-table">
|
|
8
9
|
<tr>
|
|
9
|
-
<th scope="row">Registrar</th>
|
|
10
|
+
<th scope="row">{% trans "Registrar" %}</th>
|
|
10
11
|
<td>{{ object.registrar|linkify|placeholder }}</td>
|
|
11
12
|
</tr>
|
|
12
13
|
<tr>
|
|
13
|
-
<th scope="row">Registry Domain ID</th>
|
|
14
|
+
<th scope="row">{% trans "Registry Domain ID" %}</th>
|
|
14
15
|
<td>{{ object.registry_domain_id|placeholder }}</td>
|
|
15
16
|
</tr>
|
|
16
17
|
<tr>
|
|
17
|
-
<th scope="row">Registrant</th>
|
|
18
|
+
<th scope="row">{% trans "Registrant" %}</th>
|
|
18
19
|
<td>{{ object.registrant|linkify|placeholder }}</td>
|
|
19
20
|
</tr>
|
|
20
21
|
<tr>
|
|
21
|
-
<th scope="row">Administrative Contact</th>
|
|
22
|
+
<th scope="row">{% trans "Administrative Contact" %}</th>
|
|
22
23
|
<td>{{ object.admin_c|linkify|placeholder }}</td>
|
|
23
24
|
</tr>
|
|
24
25
|
<tr>
|
|
25
|
-
<th scope="row">Technical Contact</th>
|
|
26
|
+
<th scope="row">{% trans "Technical Contact" %}</th>
|
|
26
27
|
<td>{{ object.tech_c|linkify|placeholder }}</td>
|
|
27
28
|
</tr>
|
|
28
29
|
<tr>
|
|
29
|
-
<th scope="row">Billing Contact</th>
|
|
30
|
+
<th scope="row">{% trans "Billing Contact" %}</th>
|
|
30
31
|
<td>{{ object.billing_c|linkify|placeholder }}</td>
|
|
31
32
|
</tr>
|
|
32
33
|
</table>
|
|
@@ -1,43 +1,41 @@
|
|
|
1
1
|
{% extends 'netbox_dns/zone/base.html' %}
|
|
2
2
|
{% load helpers %}
|
|
3
|
-
{% load
|
|
3
|
+
{% load i18n %}
|
|
4
4
|
|
|
5
5
|
{% block content %}
|
|
6
6
|
<div class="row">
|
|
7
7
|
<div class="col col-md-6">
|
|
8
8
|
<div class="card">
|
|
9
|
-
<h5 class="card-header">
|
|
10
|
-
Zone
|
|
11
|
-
</h5>
|
|
9
|
+
<h5 class="card-header">{% trans "Zone" %}</h5>
|
|
12
10
|
<table class="table table-hover attr-table">
|
|
13
11
|
<tr>
|
|
14
|
-
<th scope="row">Name</th>
|
|
12
|
+
<th scope="row">{% trans "Name" %}</th>
|
|
15
13
|
<td>{{ object.name }}</td>
|
|
16
14
|
</tr>
|
|
17
15
|
{% if unicode_name %}
|
|
18
16
|
<tr>
|
|
19
|
-
<th scope="row">IDN</th>
|
|
17
|
+
<th scope="row">{% trans "IDN" %}</th>
|
|
20
18
|
<td>{{ unicode_name }}</td>
|
|
21
19
|
</tr>
|
|
22
20
|
{% endif %}
|
|
23
21
|
{% if parent_zone %}
|
|
24
22
|
<tr>
|
|
25
|
-
<th scope="row">Parent Zone</th>
|
|
23
|
+
<th scope="row">{% trans "Parent Zone" %}</th>
|
|
26
24
|
<td>{{ parent_zone|linkify }}</td>
|
|
27
25
|
</tr>
|
|
28
26
|
{% endif %}
|
|
29
27
|
<tr>
|
|
30
|
-
<th scope="row">View</th>
|
|
28
|
+
<th scope="row">{% trans "View" context "DNS" %}</th>
|
|
31
29
|
<td>{{ object.view|linkify }}</td>
|
|
32
30
|
</tr>
|
|
33
31
|
{% if object.description %}
|
|
34
32
|
<tr>
|
|
35
|
-
<th scope="row">Description</th>
|
|
33
|
+
<th scope="row">{% trans "Description" %}</th>
|
|
36
34
|
<td style="word-break:break-all;">{{ object.description }}</td>
|
|
37
35
|
</tr>
|
|
38
36
|
{% endif %}
|
|
39
37
|
<tr>
|
|
40
|
-
<th scope="row">Tenant</th>
|
|
38
|
+
<th scope="row">{% trans "Tenant" %}</th>
|
|
41
39
|
<td>
|
|
42
40
|
{% if object.tenant.group %}
|
|
43
41
|
{{ object.tenant.group|linkify }} /
|
|
@@ -46,11 +44,11 @@
|
|
|
46
44
|
</td>
|
|
47
45
|
</tr>
|
|
48
46
|
<tr>
|
|
49
|
-
<th scope="row">Status</th>
|
|
47
|
+
<th scope="row">{% trans "Status" %}</th>
|
|
50
48
|
<td>{% badge object.get_status_display bg_color=object.get_status_color %}</td>
|
|
51
49
|
</tr>
|
|
52
50
|
<tr>
|
|
53
|
-
<th scope="row">Nameservers</th>
|
|
51
|
+
<th scope="row">{% trans "Nameservers" %}</th>
|
|
54
52
|
<td>
|
|
55
53
|
<table>
|
|
56
54
|
{% for nameserver in object.nameservers.all %}
|
|
@@ -60,7 +58,7 @@
|
|
|
60
58
|
</td>
|
|
61
59
|
{% if nameserver_warnings %}
|
|
62
60
|
<tr>
|
|
63
|
-
<th class="text-warning" scope="row">Warnings</th>
|
|
61
|
+
<th class="text-warning" scope="row">{% trans "Warnings" %}</th>
|
|
64
62
|
<td>
|
|
65
63
|
<table>
|
|
66
64
|
{% for warning in nameserver_warnings %}
|
|
@@ -74,7 +72,7 @@
|
|
|
74
72
|
{% endif %}
|
|
75
73
|
{% if nameserver_errors %}
|
|
76
74
|
<tr>
|
|
77
|
-
<th class="text-danger" scope="row">Errors</th>
|
|
75
|
+
<th class="text-danger" scope="row">{% trans "Errors" %}</th>
|
|
78
76
|
<td>
|
|
79
77
|
<table>
|
|
80
78
|
{% for error in nameserver_errors %}
|
|
@@ -88,11 +86,11 @@
|
|
|
88
86
|
{% endif %}
|
|
89
87
|
</tr>
|
|
90
88
|
<tr>
|
|
91
|
-
<th scope="row">Default TTL</th>
|
|
89
|
+
<th scope="row">{% trans "Default TTL" %}</th>
|
|
92
90
|
<td>{{ object.default_ttl }}</td>
|
|
93
91
|
</tr>
|
|
94
92
|
<tr>
|
|
95
|
-
<th scope="row">Description</th>
|
|
93
|
+
<th scope="row">{% trans "Description" %}</th>
|
|
96
94
|
<td>{{ object.description }}</td>
|
|
97
95
|
</tr>
|
|
98
96
|
</table>
|
|
@@ -103,64 +101,64 @@
|
|
|
103
101
|
</div>
|
|
104
102
|
<div class="col col-md-6">
|
|
105
103
|
<div class="card">
|
|
106
|
-
<h5 class="card-header">Zone SOA</h5>
|
|
104
|
+
<h5 class="card-header">{% trans "Zone SOA" %}</h5>
|
|
107
105
|
<table class="table table-hover attr-table">
|
|
108
106
|
<tr>
|
|
109
|
-
<th scope="row">TTL</th>
|
|
107
|
+
<th scope="row">{% trans "TTL" %}</th>
|
|
110
108
|
<td>{{ object.soa_ttl }}</td>
|
|
111
109
|
</tr>
|
|
112
110
|
<tr>
|
|
113
|
-
<th scope="row">MName</th>
|
|
111
|
+
<th scope="row">{% trans "MName" %}</th>
|
|
114
112
|
<td>{{ object.soa_mname|linkify }}</td>
|
|
115
113
|
</tr>
|
|
116
114
|
<tr>
|
|
117
|
-
<th scope="row">RName</th>
|
|
115
|
+
<th scope="row">{% trans "RName" %}</th>
|
|
118
116
|
<td>{{ object.soa_rname }}</td>
|
|
119
117
|
</tr>
|
|
120
118
|
{% if object.soa_serial_auto %}
|
|
121
119
|
<tr>
|
|
122
|
-
<th scope="row">Serial (auto-generated)</th>
|
|
120
|
+
<th scope="row">{% trans "Serial (auto-generated)" %}</th>
|
|
123
121
|
<td>{{ object.soa_serial }}</td>
|
|
124
122
|
</tr>
|
|
125
123
|
{% else %}
|
|
126
124
|
<tr>
|
|
127
|
-
<th scope="row">Serial</th>
|
|
125
|
+
<th scope="row">{% trans "Serial" context "SOA" %}</th>
|
|
128
126
|
<td>{{ object.soa_serial }}</td>
|
|
129
127
|
</tr>
|
|
130
128
|
{% endif %}
|
|
131
129
|
<tr>
|
|
132
|
-
<th scope="row">Refresh</th>
|
|
130
|
+
<th scope="row">{% trans "Refresh" %}</th>
|
|
133
131
|
<td>{{ object.soa_refresh }}</td>
|
|
134
132
|
</tr>
|
|
135
133
|
<tr>
|
|
136
|
-
<th scope="row">Retry</th>
|
|
134
|
+
<th scope="row">{% trans "Retry" %}</th>
|
|
137
135
|
<td>{{ object.soa_retry }}</td>
|
|
138
136
|
</tr>
|
|
139
137
|
<tr>
|
|
140
|
-
<th scope="row">Expire</th>
|
|
138
|
+
<th scope="row">{% trans "Expire" %}</th>
|
|
141
139
|
<td>{{ object.soa_expire }}</td>
|
|
142
140
|
</tr>
|
|
143
141
|
<tr>
|
|
144
|
-
<th scope="row">Minimum TTL</th>
|
|
142
|
+
<th scope="row">{% trans "Minimum TTL" %}</th>
|
|
145
143
|
<td>{{ object.soa_minimum }}</td>
|
|
146
144
|
</tr>
|
|
147
145
|
</table>
|
|
148
146
|
</div>
|
|
149
147
|
{% if object.rfc2317_prefix %}
|
|
150
148
|
<div class="card">
|
|
151
|
-
<h5 class="card-header">RFC2317</h5>
|
|
149
|
+
<h5 class="card-header">{% trans "RFC2317" %}</h5>
|
|
152
150
|
<table class="table table-hover attr-table">
|
|
153
151
|
<tr>
|
|
154
|
-
<th scope="row">Prefix</th>
|
|
152
|
+
<th scope="row">{% trans "Prefix" %}</th>
|
|
155
153
|
<td>{{ object.rfc2317_prefix }}</td>
|
|
156
154
|
</tr>
|
|
157
155
|
<tr>
|
|
158
|
-
<th scope="row">Parent Managed</th>
|
|
156
|
+
<th scope="row">{% trans "Parent Managed" %}</th>
|
|
159
157
|
<td>{% checkmark object.rfc2317_parent_managed %}</td>
|
|
160
158
|
</tr>
|
|
161
159
|
{% if object.rfc2317_parent_managed %}
|
|
162
160
|
<tr>
|
|
163
|
-
<th scope="row">Parent Zone</th>
|
|
161
|
+
<th scope="row">{% trans "Parent Zone" %}</th>
|
|
164
162
|
<td>{{ object.rfc2317_parent_zone|linkify }}</td>
|
|
165
163
|
</tr>
|
|
166
164
|
{% endif %}
|
|
@@ -3,27 +3,26 @@
|
|
|
3
3
|
{% load plugins %}
|
|
4
4
|
{% load render_table from django_tables2 %}
|
|
5
5
|
{% load perms %}
|
|
6
|
+
{% load i18n %}
|
|
6
7
|
|
|
7
8
|
{% block content %}
|
|
8
9
|
<div class="row">
|
|
9
10
|
<div class="col col-md-6">
|
|
10
11
|
<div class="card">
|
|
11
|
-
<h5 class="card-header">
|
|
12
|
-
Zone Template
|
|
13
|
-
</h5>
|
|
12
|
+
<h5 class="card-header">{% trans "Zone Template" %}</h5>
|
|
14
13
|
<table class="table table-hover attr-table">
|
|
15
14
|
<tr>
|
|
16
|
-
<th scope="row">Name</th>
|
|
15
|
+
<th scope="row">{% trans "Name" %}</th>
|
|
17
16
|
<td>{{ object.name }}</td>
|
|
18
17
|
</tr>
|
|
19
18
|
{% if object.description %}
|
|
20
19
|
<tr>
|
|
21
|
-
<th scope="row">Description</th>
|
|
20
|
+
<th scope="row">{% trans "Description" %}</th>
|
|
22
21
|
<td style="word-break:break-all;">{{ object.description }}</td>
|
|
23
22
|
</tr>
|
|
24
23
|
{% endif %}
|
|
25
24
|
<tr>
|
|
26
|
-
<th scope="row">Tenant</th>
|
|
25
|
+
<th scope="row">{% trans "Tenant" %}</th>
|
|
27
26
|
<td>
|
|
28
27
|
{% if object.tenant.group %}
|
|
29
28
|
{{ object.tenant.group|linkify }} /
|
|
@@ -32,7 +31,7 @@
|
|
|
32
31
|
</td>
|
|
33
32
|
</tr>
|
|
34
33
|
<tr>
|
|
35
|
-
<th scope="row">Nameservers</th>
|
|
34
|
+
<th scope="row">{% trans "Nameservers" %}</th>
|
|
36
35
|
<td>
|
|
37
36
|
<table>
|
|
38
37
|
{% for nameserver in object.nameservers.all %}
|
|
@@ -42,7 +41,7 @@
|
|
|
42
41
|
</td>
|
|
43
42
|
</tr>
|
|
44
43
|
<tr>
|
|
45
|
-
<th scope="row">Description</th>
|
|
44
|
+
<th scope="row">{% trans "Description" %}</th>
|
|
46
45
|
<td>{{ object.description }}</td>
|
|
47
46
|
</tr>
|
|
48
47
|
</table>
|
|
@@ -53,34 +52,45 @@
|
|
|
53
52
|
</div>
|
|
54
53
|
<div class="col col-md-6">
|
|
55
54
|
<div class="card">
|
|
56
|
-
<h5 class="card-header">Domain Registration</h5>
|
|
55
|
+
<h5 class="card-header">{% trans "Domain Registration" %}</h5>
|
|
57
56
|
<table class="table table-hover attr-table">
|
|
58
57
|
<tr>
|
|
59
|
-
<th scope="row">Registrar</th>
|
|
58
|
+
<th scope="row">{% trans "Registrar" %}</th>
|
|
60
59
|
<td>{{ object.registrar|linkify|placeholder }}</td>
|
|
61
60
|
</tr>
|
|
62
61
|
<tr>
|
|
63
|
-
<th scope="row">Registrant</th>
|
|
62
|
+
<th scope="row">{% trans "Registrant" %}</th>
|
|
64
63
|
<td>{{ object.registrant|linkify|placeholder }}</td>
|
|
65
64
|
</tr>
|
|
66
65
|
<tr>
|
|
67
|
-
<th scope="row">Administrative Contact</th>
|
|
66
|
+
<th scope="row">{% trans "Administrative Contact" %}</th>
|
|
68
67
|
<td>{{ object.admin_c|linkify|placeholder }}</td>
|
|
69
68
|
</tr>
|
|
70
69
|
<tr>
|
|
71
|
-
<th scope="row">Technical Contact</th>
|
|
70
|
+
<th scope="row">{% trans "Technical Contact" %}</th>
|
|
72
71
|
<td>{{ object.tech_c|linkify|placeholder }}</td>
|
|
73
72
|
</tr>
|
|
74
73
|
<tr>
|
|
75
|
-
<th scope="row">Billing Contact</th>
|
|
74
|
+
<th scope="row">{% trans "Billing Contact" %}</th>
|
|
76
75
|
<td>{{ object.billing_c|linkify|placeholder }}</td>
|
|
77
76
|
</tr>
|
|
78
77
|
</table>
|
|
79
78
|
</div>
|
|
80
79
|
</div>
|
|
81
80
|
</div>
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
81
|
+
{% if record_template_table %}
|
|
82
|
+
<div class="col col-md-12">
|
|
83
|
+
<div class="card">
|
|
84
|
+
{% if record_template_table.rows|length == 1 %}
|
|
85
|
+
<h2 class="card-header">{% trans "Record Template" %}</h2>
|
|
86
|
+
{% else %}
|
|
87
|
+
<h2 class="card-header">{% trans "Record Templates" %}</h2>
|
|
88
|
+
{% endif %}
|
|
89
|
+
<div class="table-responsive">
|
|
90
|
+
{% render_table record_template_table 'inc/table.html' %}
|
|
91
|
+
</div>
|
|
92
|
+
</div>
|
|
93
|
+
</div>
|
|
94
|
+
{% endif %}
|
|
85
95
|
</div>
|
|
86
96
|
{% endblock %}
|
|
@@ -10,9 +10,6 @@ from django.db.models import Q
|
|
|
10
10
|
from netbox.context import current_request
|
|
11
11
|
from ipam.models import IPAddress, Prefix
|
|
12
12
|
|
|
13
|
-
from netbox_dns.models import zone as _zone
|
|
14
|
-
from netbox_dns.models import record as _record
|
|
15
|
-
from netbox_dns.models import view as _view
|
|
16
13
|
from netbox_dns.choices import RecordStatusChoices
|
|
17
14
|
|
|
18
15
|
|
|
@@ -26,6 +23,7 @@ __all__ = (
|
|
|
26
23
|
"get_ip_addresses_by_view",
|
|
27
24
|
"get_ip_addresses_by_zone",
|
|
28
25
|
"check_record_permission",
|
|
26
|
+
"get_query_from_filter",
|
|
29
27
|
)
|
|
30
28
|
|
|
31
29
|
|
|
@@ -74,6 +72,8 @@ def _match_data(ip_address, record):
|
|
|
74
72
|
|
|
75
73
|
|
|
76
74
|
def get_zones(ip_address, view=None, old_zone=None):
|
|
75
|
+
from netbox_dns.models import Zone
|
|
76
|
+
|
|
77
77
|
if view is None:
|
|
78
78
|
views = _get_assigned_views(ip_address)
|
|
79
79
|
if not views:
|
|
@@ -91,7 +91,7 @@ def get_zones(ip_address, view=None, old_zone=None):
|
|
|
91
91
|
for i in range(min_labels + 1, len(fqdn.labels) + 1)
|
|
92
92
|
]
|
|
93
93
|
|
|
94
|
-
zones =
|
|
94
|
+
zones = Zone.objects.filter(
|
|
95
95
|
view__in=views,
|
|
96
96
|
name__in=zone_name_candidates,
|
|
97
97
|
active=True,
|
|
@@ -114,28 +114,28 @@ def get_zones(ip_address, view=None, old_zone=None):
|
|
|
114
114
|
|
|
115
115
|
|
|
116
116
|
def check_dns_records(ip_address, zone=None, view=None):
|
|
117
|
+
from netbox_dns.models import Zone, Record
|
|
118
|
+
|
|
117
119
|
if ip_address.dns_name == "":
|
|
118
120
|
return
|
|
119
121
|
|
|
120
122
|
if zone is None:
|
|
121
123
|
zones = get_zones(ip_address, view=view)
|
|
122
124
|
|
|
123
|
-
if ip_address.
|
|
125
|
+
if not ip_address._state.adding:
|
|
124
126
|
for record in ip_address.netbox_dns_records.filter(zone__in=zones):
|
|
125
127
|
if not _match_data(ip_address, record):
|
|
126
|
-
record.update_from_ip_address(ip_address)
|
|
128
|
+
updated = record.update_from_ip_address(ip_address)
|
|
127
129
|
|
|
128
|
-
if
|
|
130
|
+
if updated:
|
|
129
131
|
record.clean()
|
|
130
132
|
|
|
131
|
-
zones =
|
|
132
|
-
pk__in=[zone.pk for zone in zones]
|
|
133
|
-
).exclude(
|
|
133
|
+
zones = Zone.objects.filter(pk__in=[zone.pk for zone in zones]).exclude(
|
|
134
134
|
pk__in=set(ip_address.netbox_dns_records.values_list("zone", flat=True))
|
|
135
135
|
)
|
|
136
136
|
|
|
137
137
|
for zone in zones:
|
|
138
|
-
record =
|
|
138
|
+
record = Record.create_from_ip_address(
|
|
139
139
|
ip_address,
|
|
140
140
|
zone,
|
|
141
141
|
)
|
|
@@ -143,7 +143,7 @@ def check_dns_records(ip_address, zone=None, view=None):
|
|
|
143
143
|
if record is not None:
|
|
144
144
|
record.clean()
|
|
145
145
|
|
|
146
|
-
if ip_address.
|
|
146
|
+
if ip_address._state.adding:
|
|
147
147
|
return
|
|
148
148
|
|
|
149
149
|
try:
|
|
@@ -152,63 +152,91 @@ def check_dns_records(ip_address, zone=None, view=None):
|
|
|
152
152
|
return
|
|
153
153
|
|
|
154
154
|
for record in ip_address.netbox_dns_records.filter(zone=zone):
|
|
155
|
-
record.update_from_ip_address(ip_address, new_zone)
|
|
155
|
+
updated = record.update_from_ip_address(ip_address, new_zone)
|
|
156
156
|
|
|
157
|
-
if
|
|
157
|
+
if updated:
|
|
158
158
|
record.clean(new_zone=new_zone)
|
|
159
159
|
|
|
160
160
|
|
|
161
|
-
def update_dns_records(ip_address):
|
|
161
|
+
def update_dns_records(ip_address, view=None, force=False):
|
|
162
|
+
from netbox_dns.models import Zone, Record
|
|
163
|
+
|
|
164
|
+
updated = False
|
|
165
|
+
|
|
162
166
|
if ip_address.dns_name == "":
|
|
163
|
-
delete_dns_records(ip_address)
|
|
164
|
-
|
|
167
|
+
return delete_dns_records(ip_address)
|
|
168
|
+
|
|
169
|
+
zones = get_zones(ip_address, view=view)
|
|
165
170
|
|
|
166
|
-
|
|
171
|
+
if not ip_address._state.adding:
|
|
172
|
+
if view is None:
|
|
173
|
+
address_records = ip_address.netbox_dns_records.all()
|
|
174
|
+
else:
|
|
175
|
+
address_records = ip_address.netbox_dns_records.filter(zone__view=view)
|
|
167
176
|
|
|
168
|
-
|
|
169
|
-
for record in ip_address.netbox_dns_records.all():
|
|
177
|
+
for record in address_records:
|
|
170
178
|
if record.zone not in zones or ip_address.custom_field_data.get(
|
|
171
179
|
"ipaddress_dns_disabled"
|
|
172
180
|
):
|
|
173
181
|
record.delete()
|
|
182
|
+
updated = True
|
|
174
183
|
continue
|
|
175
184
|
|
|
176
185
|
record.update_fqdn()
|
|
177
|
-
if not _match_data(ip_address, record):
|
|
178
|
-
record.update_from_ip_address(ip_address)
|
|
186
|
+
if not _match_data(ip_address, record) or force:
|
|
187
|
+
updated, deleted = record.update_from_ip_address(ip_address)
|
|
179
188
|
|
|
180
|
-
if
|
|
189
|
+
if deleted:
|
|
190
|
+
record.delete()
|
|
191
|
+
updated = True
|
|
192
|
+
elif updated:
|
|
181
193
|
record.save()
|
|
194
|
+
updated = True
|
|
182
195
|
|
|
183
|
-
zones =
|
|
196
|
+
zones = Zone.objects.filter(pk__in=[zone.pk for zone in zones]).exclude(
|
|
184
197
|
pk__in=set(
|
|
185
198
|
ip_address.netbox_dns_records.all().values_list("zone", flat=True)
|
|
186
199
|
)
|
|
187
200
|
)
|
|
188
201
|
|
|
189
202
|
for zone in zones:
|
|
190
|
-
record =
|
|
203
|
+
record = Record.create_from_ip_address(
|
|
191
204
|
ip_address,
|
|
192
205
|
zone,
|
|
193
206
|
)
|
|
194
207
|
|
|
195
208
|
if record is not None:
|
|
196
209
|
record.save()
|
|
210
|
+
updated = True
|
|
211
|
+
|
|
212
|
+
return updated
|
|
197
213
|
|
|
198
214
|
|
|
199
|
-
def delete_dns_records(ip_address):
|
|
200
|
-
|
|
215
|
+
def delete_dns_records(ip_address, view=None):
|
|
216
|
+
deleted = False
|
|
217
|
+
|
|
218
|
+
if view is None:
|
|
219
|
+
address_records = ip_address.netbox_dns_records.all()
|
|
220
|
+
else:
|
|
221
|
+
address_records = ip_address.netbox_dns_records.filter(zone__view=view)
|
|
222
|
+
|
|
223
|
+
for record in address_records:
|
|
201
224
|
record.delete()
|
|
225
|
+
deleted = True
|
|
226
|
+
|
|
227
|
+
return deleted
|
|
202
228
|
|
|
203
229
|
|
|
204
230
|
def get_views_by_prefix(prefix):
|
|
231
|
+
from netbox_dns.models import View
|
|
232
|
+
|
|
205
233
|
if (views := prefix.netbox_dns_views.all()).exists():
|
|
206
234
|
return views
|
|
207
235
|
|
|
208
236
|
if (parent := prefix.get_parents().filter(netbox_dns_views__isnull=False)).exists():
|
|
209
237
|
return parent.last().netbox_dns_views.all()
|
|
210
238
|
|
|
211
|
-
return
|
|
239
|
+
return View.objects.none()
|
|
212
240
|
|
|
213
241
|
|
|
214
242
|
def get_ip_addresses_by_prefix(prefix, check_view=True):
|
|
@@ -293,3 +321,18 @@ def check_record_permission(add=True, change=True, delete=True):
|
|
|
293
321
|
if check
|
|
294
322
|
)
|
|
295
323
|
)
|
|
324
|
+
|
|
325
|
+
|
|
326
|
+
def get_query_from_filter(ip_address_filter):
|
|
327
|
+
query = Q()
|
|
328
|
+
|
|
329
|
+
if not isinstance(ip_address_filter, list):
|
|
330
|
+
ip_address_filter = [ip_address_filter]
|
|
331
|
+
|
|
332
|
+
for condition in ip_address_filter:
|
|
333
|
+
if condition:
|
|
334
|
+
query |= Q(**condition)
|
|
335
|
+
else:
|
|
336
|
+
return Q()
|
|
337
|
+
|
|
338
|
+
return query
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import re
|
|
2
2
|
|
|
3
3
|
from django.core.exceptions import ValidationError
|
|
4
|
+
from django.utils.translation import gettext as _
|
|
4
5
|
|
|
5
6
|
from netbox.plugins.utils import get_plugin_config
|
|
6
7
|
|
|
@@ -55,7 +56,9 @@ def validate_fqdn(name, always_tolerant=False):
|
|
|
55
56
|
regex = rf"^(\*|{label})(\.{zone_label})+\.?$"
|
|
56
57
|
|
|
57
58
|
if not re.match(regex, name, flags=re.IGNORECASE) or _has_invalid_double_dash(name):
|
|
58
|
-
raise ValidationError(
|
|
59
|
+
raise ValidationError(
|
|
60
|
+
_("{name} is not a valid fully qualified DNS host name").format(name=name)
|
|
61
|
+
)
|
|
59
62
|
|
|
60
63
|
|
|
61
64
|
def validate_rname(name, always_tolerant=False):
|
|
@@ -63,7 +66,7 @@ def validate_rname(name, always_tolerant=False):
|
|
|
63
66
|
regex = rf"^(\*|{label})(\\\.{label})*(\.{zone_label}){{2,}}\.?$"
|
|
64
67
|
|
|
65
68
|
if not re.match(regex, name, flags=re.IGNORECASE) or _has_invalid_double_dash(name):
|
|
66
|
-
raise ValidationError(
|
|
69
|
+
raise ValidationError(_("{name} is not a valid RName").format(name=name))
|
|
67
70
|
|
|
68
71
|
|
|
69
72
|
def validate_generic_name(
|
|
@@ -76,7 +79,9 @@ def validate_generic_name(
|
|
|
76
79
|
regex = rf"^([*@]|(\*\.)?{label}(\.{zone_label})*\.?)$"
|
|
77
80
|
|
|
78
81
|
if not re.match(regex, name, flags=re.IGNORECASE) or _has_invalid_double_dash(name):
|
|
79
|
-
raise ValidationError(
|
|
82
|
+
raise ValidationError(
|
|
83
|
+
_("{name} is not a valid DNS host name").format(name=name)
|
|
84
|
+
)
|
|
80
85
|
|
|
81
86
|
|
|
82
87
|
def validate_domain_name(
|
|
@@ -97,4 +102,6 @@ def validate_domain_name(
|
|
|
97
102
|
regex = rf"^{label}(\.{zone_label})*\.?$"
|
|
98
103
|
|
|
99
104
|
if not re.match(regex, name, flags=re.IGNORECASE) or _has_invalid_double_dash(name):
|
|
100
|
-
raise ValidationError(
|
|
105
|
+
raise ValidationError(
|
|
106
|
+
_("{name} is not a valid DNS domain name").format(name=name)
|
|
107
|
+
)
|
|
@@ -2,6 +2,7 @@ import dns
|
|
|
2
2
|
from dns import rdata, name as dns_name
|
|
3
3
|
|
|
4
4
|
from django.core.exceptions import ValidationError
|
|
5
|
+
from django.utils.translation import gettext as _
|
|
5
6
|
|
|
6
7
|
from netbox_dns.choices import RecordClassChoices, RecordTypeChoices
|
|
7
8
|
from netbox_dns.validators import (
|
|
@@ -20,15 +21,19 @@ def validate_record_value(record_type, value):
|
|
|
20
21
|
name.to_unicode()
|
|
21
22
|
except dns_name.IDNAException as exc:
|
|
22
23
|
raise ValidationError(
|
|
23
|
-
|
|
24
|
-
|
|
24
|
+
"{name} is not a valid IDN: {error}.".format(
|
|
25
|
+
name=name.to_text(), error=exc
|
|
26
|
+
)
|
|
27
|
+
)
|
|
25
28
|
|
|
26
29
|
try:
|
|
27
30
|
rr = rdata.from_text(RecordClassChoices.IN, record_type, value)
|
|
28
31
|
except dns.exception.SyntaxError as exc:
|
|
29
32
|
raise ValidationError(
|
|
30
|
-
|
|
31
|
-
|
|
33
|
+
_(
|
|
34
|
+
"Record value {value} is not a valid value for a {type} record: {error}."
|
|
35
|
+
).format(value=value, type=record_type, error=exc)
|
|
36
|
+
)
|
|
32
37
|
|
|
33
38
|
match record_type:
|
|
34
39
|
case RecordTypeChoices.CNAME:
|