netbox-plugin-dns 0.22.4__tar.gz → 0.22.6__tar.gz
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_plugin_dns-0.22.4 → netbox_plugin_dns-0.22.6}/PKG-INFO +11 -11
- {netbox_plugin_dns-0.22.4 → netbox_plugin_dns-0.22.6}/README.md +9 -10
- netbox_plugin_dns-0.22.6/netbox_dns/__init__.py +50 -0
- {netbox_plugin_dns-0.22.4 → netbox_plugin_dns-0.22.6}/netbox_dns/api/serializers.py +1 -0
- {netbox_plugin_dns-0.22.4 → netbox_plugin_dns-0.22.6}/netbox_dns/filters/registrar.py +1 -0
- {netbox_plugin_dns-0.22.4 → netbox_plugin_dns-0.22.6}/netbox_dns/forms/registrar.py +11 -1
- {netbox_plugin_dns-0.22.4 → netbox_plugin_dns-0.22.6}/netbox_dns/forms/zone.py +31 -21
- netbox_plugin_dns-0.22.6/netbox_dns/management/commands/cleanup_rrset_ttl.py +62 -0
- {netbox_plugin_dns-0.22.4 → netbox_plugin_dns-0.22.6}/netbox_dns/models/record.py +151 -25
- {netbox_plugin_dns-0.22.4 → netbox_plugin_dns-0.22.6}/netbox_dns/models/zone.py +82 -18
- {netbox_plugin_dns-0.22.4 → netbox_plugin_dns-0.22.6}/netbox_dns/templates/netbox_dns/record.html +6 -22
- {netbox_plugin_dns-0.22.4 → netbox_plugin_dns-0.22.6}/netbox_dns/templates/netbox_dns/registrar.html +4 -0
- {netbox_plugin_dns-0.22.4 → netbox_plugin_dns-0.22.6}/netbox_dns/templates/netbox_dns/zone.html +7 -0
- netbox_plugin_dns-0.22.6/netbox_dns/views/record.py +159 -0
- {netbox_plugin_dns-0.22.4 → netbox_plugin_dns-0.22.6}/pyproject.toml +5 -2
- netbox_plugin_dns-0.22.4/netbox_dns/__init__.py +0 -86
- netbox_plugin_dns-0.22.4/netbox_dns/views/record.py +0 -85
- {netbox_plugin_dns-0.22.4 → netbox_plugin_dns-0.22.6}/LICENSE +0 -0
- {netbox_plugin_dns-0.22.4 → netbox_plugin_dns-0.22.6}/netbox_dns/api/nested_serializers.py +0 -0
- {netbox_plugin_dns-0.22.4 → netbox_plugin_dns-0.22.6}/netbox_dns/api/urls.py +0 -0
- {netbox_plugin_dns-0.22.4 → netbox_plugin_dns-0.22.6}/netbox_dns/api/views.py +0 -0
- {netbox_plugin_dns-0.22.4 → netbox_plugin_dns-0.22.6}/netbox_dns/apps.py +0 -0
- {netbox_plugin_dns-0.22.4 → netbox_plugin_dns-0.22.6}/netbox_dns/fields/__init__.py +0 -0
- {netbox_plugin_dns-0.22.4 → netbox_plugin_dns-0.22.6}/netbox_dns/fields/address.py +0 -0
- {netbox_plugin_dns-0.22.4 → netbox_plugin_dns-0.22.6}/netbox_dns/fields/network.py +0 -0
- {netbox_plugin_dns-0.22.4 → netbox_plugin_dns-0.22.6}/netbox_dns/fields/rfc2317.py +0 -0
- {netbox_plugin_dns-0.22.4 → netbox_plugin_dns-0.22.6}/netbox_dns/filters/__init__.py +0 -0
- {netbox_plugin_dns-0.22.4 → netbox_plugin_dns-0.22.6}/netbox_dns/filters/contact.py +0 -0
- {netbox_plugin_dns-0.22.4 → netbox_plugin_dns-0.22.6}/netbox_dns/filters/nameserver.py +0 -0
- {netbox_plugin_dns-0.22.4 → netbox_plugin_dns-0.22.6}/netbox_dns/filters/record.py +0 -0
- {netbox_plugin_dns-0.22.4 → netbox_plugin_dns-0.22.6}/netbox_dns/filters/view.py +0 -0
- {netbox_plugin_dns-0.22.4 → netbox_plugin_dns-0.22.6}/netbox_dns/filters/zone.py +0 -0
- {netbox_plugin_dns-0.22.4 → netbox_plugin_dns-0.22.6}/netbox_dns/forms/__init__.py +0 -0
- {netbox_plugin_dns-0.22.4 → netbox_plugin_dns-0.22.6}/netbox_dns/forms/contact.py +0 -0
- {netbox_plugin_dns-0.22.4 → netbox_plugin_dns-0.22.6}/netbox_dns/forms/nameserver.py +0 -0
- {netbox_plugin_dns-0.22.4 → netbox_plugin_dns-0.22.6}/netbox_dns/forms/record.py +0 -0
- {netbox_plugin_dns-0.22.4 → netbox_plugin_dns-0.22.6}/netbox_dns/forms/view.py +0 -0
- {netbox_plugin_dns-0.22.4 → netbox_plugin_dns-0.22.6}/netbox_dns/graphql/__init__.py +0 -0
- {netbox_plugin_dns-0.22.4 → netbox_plugin_dns-0.22.6}/netbox_dns/graphql/contact.py +0 -0
- {netbox_plugin_dns-0.22.4 → netbox_plugin_dns-0.22.6}/netbox_dns/graphql/nameserver.py +0 -0
- {netbox_plugin_dns-0.22.4 → netbox_plugin_dns-0.22.6}/netbox_dns/graphql/record.py +0 -0
- {netbox_plugin_dns-0.22.4 → netbox_plugin_dns-0.22.6}/netbox_dns/graphql/registrar.py +0 -0
- {netbox_plugin_dns-0.22.4 → netbox_plugin_dns-0.22.6}/netbox_dns/graphql/schema.py +0 -0
- {netbox_plugin_dns-0.22.4 → netbox_plugin_dns-0.22.6}/netbox_dns/graphql/view.py +0 -0
- {netbox_plugin_dns-0.22.4 → netbox_plugin_dns-0.22.6}/netbox_dns/graphql/zone.py +0 -0
- {netbox_plugin_dns-0.22.4 → netbox_plugin_dns-0.22.6}/netbox_dns/management/commands/cleanup_database.py +0 -0
- {netbox_plugin_dns-0.22.4 → netbox_plugin_dns-0.22.6}/netbox_dns/management/commands/setup_coupling.py +0 -0
- {netbox_plugin_dns-0.22.4 → netbox_plugin_dns-0.22.6}/netbox_dns/management/commands/update_soa.py +0 -0
- {netbox_plugin_dns-0.22.4 → netbox_plugin_dns-0.22.6}/netbox_dns/migrations/0001_initial.py +0 -0
- {netbox_plugin_dns-0.22.4 → netbox_plugin_dns-0.22.6}/netbox_dns/migrations/0001_squashed_netbox_dns_0_15.py +0 -0
- {netbox_plugin_dns-0.22.4 → netbox_plugin_dns-0.22.6}/netbox_dns/migrations/0002_zone_default_ttl.py +0 -0
- {netbox_plugin_dns-0.22.4 → netbox_plugin_dns-0.22.6}/netbox_dns/migrations/0003_soa_managed_records.py +0 -0
- {netbox_plugin_dns-0.22.4 → netbox_plugin_dns-0.22.6}/netbox_dns/migrations/0004_create_ptr_for_a_aaaa_records.py +0 -0
- {netbox_plugin_dns-0.22.4 → netbox_plugin_dns-0.22.6}/netbox_dns/migrations/0005_update_ns_records.py +0 -0
- {netbox_plugin_dns-0.22.4 → netbox_plugin_dns-0.22.6}/netbox_dns/migrations/0006_zone_soa_serial_auto.py +0 -0
- {netbox_plugin_dns-0.22.4 → netbox_plugin_dns-0.22.6}/netbox_dns/migrations/0007_alter_zone_soa_serial_auto.py +0 -0
- {netbox_plugin_dns-0.22.4 → netbox_plugin_dns-0.22.6}/netbox_dns/migrations/0008_zone_status_names.py +0 -0
- {netbox_plugin_dns-0.22.4 → netbox_plugin_dns-0.22.6}/netbox_dns/migrations/0009_netbox32.py +0 -0
- {netbox_plugin_dns-0.22.4 → netbox_plugin_dns-0.22.6}/netbox_dns/migrations/0010_update_soa_records.py +0 -0
- {netbox_plugin_dns-0.22.4 → netbox_plugin_dns-0.22.6}/netbox_dns/migrations/0011_add_view_model.py +0 -0
- {netbox_plugin_dns-0.22.4 → netbox_plugin_dns-0.22.6}/netbox_dns/migrations/0012_adjust_zone_and_record.py +0 -0
- {netbox_plugin_dns-0.22.4 → netbox_plugin_dns-0.22.6}/netbox_dns/migrations/0013_add_nameserver_zone_record_description.py +0 -0
- {netbox_plugin_dns-0.22.4 → netbox_plugin_dns-0.22.6}/netbox_dns/migrations/0014_add_view_description.py +0 -0
- {netbox_plugin_dns-0.22.4 → netbox_plugin_dns-0.22.6}/netbox_dns/migrations/0015_add_record_status.py +0 -0
- {netbox_plugin_dns-0.22.4 → netbox_plugin_dns-0.22.6}/netbox_dns/migrations/0016_cleanup_ptr_records.py +0 -0
- {netbox_plugin_dns-0.22.4 → netbox_plugin_dns-0.22.6}/netbox_dns/migrations/0017_alter_record_ttl.py +0 -0
- {netbox_plugin_dns-0.22.4 → netbox_plugin_dns-0.22.6}/netbox_dns/migrations/0018_zone_arpa_network.py +0 -0
- {netbox_plugin_dns-0.22.4 → netbox_plugin_dns-0.22.6}/netbox_dns/migrations/0019_update_ns_ttl.py +0 -0
- {netbox_plugin_dns-0.22.4 → netbox_plugin_dns-0.22.6}/netbox_dns/migrations/0020_netbox_3_4.py +0 -0
- {netbox_plugin_dns-0.22.4 → netbox_plugin_dns-0.22.6}/netbox_dns/migrations/0021_record_ip_address.py +0 -0
- {netbox_plugin_dns-0.22.4 → netbox_plugin_dns-0.22.6}/netbox_dns/migrations/0022_search.py +0 -0
- {netbox_plugin_dns-0.22.4 → netbox_plugin_dns-0.22.6}/netbox_dns/migrations/0023_alter_record_value.py +0 -0
- {netbox_plugin_dns-0.22.4 → netbox_plugin_dns-0.22.6}/netbox_dns/migrations/0024_tenancy.py +0 -0
- {netbox_plugin_dns-0.22.4 → netbox_plugin_dns-0.22.6}/netbox_dns/migrations/0025_ipam_coupling_cf.py +0 -0
- {netbox_plugin_dns-0.22.4 → netbox_plugin_dns-0.22.6}/netbox_dns/migrations/0026_domain_registration.py +0 -0
- {netbox_plugin_dns-0.22.4 → netbox_plugin_dns-0.22.6}/netbox_dns/migrations/0027_alter_registrar_iana_id.py +0 -0
- {netbox_plugin_dns-0.22.4 → netbox_plugin_dns-0.22.6}/netbox_dns/migrations/0028_rfc2317_fields.py +0 -0
- {netbox_plugin_dns-0.22.4 → netbox_plugin_dns-0.22.6}/netbox_dns/migrations/__init__.py +0 -0
- {netbox_plugin_dns-0.22.4 → netbox_plugin_dns-0.22.6}/netbox_dns/models/__init__.py +0 -0
- {netbox_plugin_dns-0.22.4 → netbox_plugin_dns-0.22.6}/netbox_dns/models/contact.py +0 -0
- {netbox_plugin_dns-0.22.4 → netbox_plugin_dns-0.22.6}/netbox_dns/models/nameserver.py +0 -0
- {netbox_plugin_dns-0.22.4 → netbox_plugin_dns-0.22.6}/netbox_dns/models/registrar.py +0 -0
- {netbox_plugin_dns-0.22.4 → netbox_plugin_dns-0.22.6}/netbox_dns/models/view.py +0 -0
- {netbox_plugin_dns-0.22.4 → netbox_plugin_dns-0.22.6}/netbox_dns/navigation.py +0 -0
- {netbox_plugin_dns-0.22.4 → netbox_plugin_dns-0.22.6}/netbox_dns/signals/__init__.py +0 -0
- {netbox_plugin_dns-0.22.4 → netbox_plugin_dns-0.22.6}/netbox_dns/signals/ipam_coupling.py +0 -0
- {netbox_plugin_dns-0.22.4 → netbox_plugin_dns-0.22.6}/netbox_dns/tables/__init__.py +0 -0
- {netbox_plugin_dns-0.22.4 → netbox_plugin_dns-0.22.6}/netbox_dns/tables/contact.py +0 -0
- {netbox_plugin_dns-0.22.4 → netbox_plugin_dns-0.22.6}/netbox_dns/tables/nameserver.py +0 -0
- {netbox_plugin_dns-0.22.4 → netbox_plugin_dns-0.22.6}/netbox_dns/tables/record.py +0 -0
- {netbox_plugin_dns-0.22.4 → netbox_plugin_dns-0.22.6}/netbox_dns/tables/registrar.py +0 -0
- {netbox_plugin_dns-0.22.4 → netbox_plugin_dns-0.22.6}/netbox_dns/tables/view.py +0 -0
- {netbox_plugin_dns-0.22.4 → netbox_plugin_dns-0.22.6}/netbox_dns/tables/zone.py +0 -0
- {netbox_plugin_dns-0.22.4 → netbox_plugin_dns-0.22.6}/netbox_dns/template_content.py +0 -0
- {netbox_plugin_dns-0.22.4 → netbox_plugin_dns-0.22.6}/netbox_dns/templates/netbox_dns/contact.html +0 -0
- {netbox_plugin_dns-0.22.4 → netbox_plugin_dns-0.22.6}/netbox_dns/templates/netbox_dns/nameserver.html +0 -0
- {netbox_plugin_dns-0.22.4 → netbox_plugin_dns-0.22.6}/netbox_dns/templates/netbox_dns/record/managed.html +0 -0
- {netbox_plugin_dns-0.22.4 → netbox_plugin_dns-0.22.6}/netbox_dns/templates/netbox_dns/record/related.html +0 -0
- {netbox_plugin_dns-0.22.4 → netbox_plugin_dns-0.22.6}/netbox_dns/templates/netbox_dns/related_dns_objects.html +0 -0
- {netbox_plugin_dns-0.22.4 → netbox_plugin_dns-0.22.6}/netbox_dns/templates/netbox_dns/view.html +0 -0
- {netbox_plugin_dns-0.22.4 → netbox_plugin_dns-0.22.6}/netbox_dns/templates/netbox_dns/zone/base.html +0 -0
- {netbox_plugin_dns-0.22.4 → netbox_plugin_dns-0.22.6}/netbox_dns/templates/netbox_dns/zone/child.html +0 -0
- {netbox_plugin_dns-0.22.4 → netbox_plugin_dns-0.22.6}/netbox_dns/templates/netbox_dns/zone/managed_record.html +0 -0
- {netbox_plugin_dns-0.22.4 → netbox_plugin_dns-0.22.6}/netbox_dns/templates/netbox_dns/zone/record.html +0 -0
- {netbox_plugin_dns-0.22.4 → netbox_plugin_dns-0.22.6}/netbox_dns/templates/netbox_dns/zone/registration.html +0 -0
- {netbox_plugin_dns-0.22.4 → netbox_plugin_dns-0.22.6}/netbox_dns/templates/netbox_dns/zone/rfc2317_child_zone.html +0 -0
- {netbox_plugin_dns-0.22.4 → netbox_plugin_dns-0.22.6}/netbox_dns/urls.py +0 -0
- {netbox_plugin_dns-0.22.4 → netbox_plugin_dns-0.22.6}/netbox_dns/utilities/__init__.py +0 -0
- {netbox_plugin_dns-0.22.4 → netbox_plugin_dns-0.22.6}/netbox_dns/utilities/ipam_coupling.py +0 -0
- {netbox_plugin_dns-0.22.4 → netbox_plugin_dns-0.22.6}/netbox_dns/validators/__init__.py +0 -0
- {netbox_plugin_dns-0.22.4 → netbox_plugin_dns-0.22.6}/netbox_dns/validators/dns_name.py +0 -0
- {netbox_plugin_dns-0.22.4 → netbox_plugin_dns-0.22.6}/netbox_dns/validators/rfc2317.py +0 -0
- {netbox_plugin_dns-0.22.4 → netbox_plugin_dns-0.22.6}/netbox_dns/views/__init__.py +0 -0
- {netbox_plugin_dns-0.22.4 → netbox_plugin_dns-0.22.6}/netbox_dns/views/contact.py +0 -0
- {netbox_plugin_dns-0.22.4 → netbox_plugin_dns-0.22.6}/netbox_dns/views/nameserver.py +0 -0
- {netbox_plugin_dns-0.22.4 → netbox_plugin_dns-0.22.6}/netbox_dns/views/registrar.py +0 -0
- {netbox_plugin_dns-0.22.4 → netbox_plugin_dns-0.22.6}/netbox_dns/views/view.py +0 -0
- {netbox_plugin_dns-0.22.4 → netbox_plugin_dns-0.22.6}/netbox_dns/views/zone.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: netbox-plugin-dns
|
|
3
|
-
Version: 0.22.
|
|
3
|
+
Version: 0.22.6
|
|
4
4
|
Summary: NetBox DNS is a NetBox plugin for managing DNS data.
|
|
5
5
|
Home-page: https://github.com/peteeckel/netbox-plugin-dns
|
|
6
6
|
License: MIT
|
|
@@ -8,6 +8,7 @@ Keywords: netbox,netbox-plugin,dns
|
|
|
8
8
|
Author: Peter Eckel
|
|
9
9
|
Author-email: pete@netbox-dns.org
|
|
10
10
|
Requires-Python: >=3.8,<4.0
|
|
11
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
11
12
|
Classifier: License :: OSI Approved :: MIT License
|
|
12
13
|
Classifier: Programming Language :: Python :: 3
|
|
13
14
|
Classifier: Programming Language :: Python :: 3.8
|
|
@@ -19,16 +20,15 @@ Requires-Dist: dnspython (>=2.2.1,<3.0.0)
|
|
|
19
20
|
Project-URL: Repository, https://github.com/peteeckel/netbox-plugin-dns
|
|
20
21
|
Description-Content-Type: text/markdown
|
|
21
22
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
<p align="center"><i>NetBox DNS is a NetBox plugin for managing DNS views, zones, name servers and records.</i></p>
|
|
23
|
+
# NetBox DNS
|
|
24
|
+
The NetBox DNS plugin enables NetBox to manage operational DNS data such as name servers, zones, records and views, as well as registration data for domains. It can automate tasks like creating PTR records, generating zone serial numbers, NS and SOA records, as well as validate names and values values for resource records to ensure zone data is consistent, current and conforming to the relevant RFCs.
|
|
25
25
|
|
|
26
26
|
<div align="center">
|
|
27
27
|
<a href="https://pypi.org/project/netbox-plugin-dns/"><img src="https://img.shields.io/pypi/v/netbox-plugin-dns" alt="PyPi"/></a>
|
|
28
|
-
<a href="https://github.com/peteeckel/netbox-plugin-dns/stargazers"><img src="https://img.shields.io/github/stars/peteeckel/netbox-plugin-dns" alt="Stars Badge"/></a>
|
|
29
|
-
<a href="https://github.com/peteeckel/netbox-plugin-dns/network/members"><img src="https://img.shields.io/github/forks/peteeckel/netbox-plugin-dns" alt="Forks Badge"/></a>
|
|
30
|
-
<a href="https://github.com/peteeckel/netbox-plugin-dns/pulls"><img src="https://img.shields.io/github/issues-pr/peteeckel/netbox-plugin-dns" alt="Pull Requests Badge"/></a>
|
|
28
|
+
<a href="https://github.com/peteeckel/netbox-plugin-dns/stargazers"><img src="https://img.shields.io/github/stars/peteeckel/netbox-plugin-dns?style=flat" alt="Stars Badge"/></a>
|
|
29
|
+
<a href="https://github.com/peteeckel/netbox-plugin-dns/network/members"><img src="https://img.shields.io/github/forks/peteeckel/netbox-plugin-dns?style=flat" alt="Forks Badge"/></a>
|
|
31
30
|
<a href="https://github.com/peteeckel/netbox-plugin-dns/issues"><img src="https://img.shields.io/github/issues/peteeckel/netbox-plugin-dns" alt="Issues Badge"/></a>
|
|
31
|
+
<a href="https://github.com/peteeckel/netbox-plugin-dns/pulls"><img src="https://img.shields.io/github/issues-pr/peteeckel/netbox-plugin-dns" alt="Pull Requests Badge"/></a>
|
|
32
32
|
<a href="https://github.com/peteeckel/netbox-plugin-dns/graphs/contributors"><img alt="GitHub contributors" src="https://img.shields.io/github/contributors/peteeckel/netbox-plugin-dns?color=2b9348"></a>
|
|
33
33
|
<a href="https://github.com/peteeckel/netbox-plugin-dns/blob/master/LICENSE"><img src="https://img.shields.io/github/license/peteeckel/netbox-plugin-dns?color=2b9348" alt="License Badge"/></a>
|
|
34
34
|
<a href="https://pepy.tech/project/netbox-plugin-dns"><img alt="Downloads" src="https://static.pepy.tech/badge/netbox-plugin-dns"></a>
|
|
@@ -40,10 +40,10 @@ Description-Content-Type: text/markdown
|
|
|
40
40
|
|
|
41
41
|
* Manage name servers, zones and records
|
|
42
42
|
* Automatically generate SOA and NS records for zones
|
|
43
|
-
* Automatically create and update PTR records for IPv4 and IPv6 records
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
43
|
+
* Automatically create and update PTR records for IPv4 and IPv6 address records
|
|
44
|
+
* Organize DNS zones in views for split horizon DNS and multi-site deployments
|
|
45
|
+
* Manage domain registrar and registrant information for domains related to zones
|
|
46
|
+
* Manage RFC2317 reverse zones for IPv4 prefixes with a network mask length longer than 24 bits
|
|
47
47
|
|
|
48
48
|
NetBox DNS is using the standardized NetBox plugin interface, so it also takes advantage of the NetBox tagging and change log features.
|
|
49
49
|
|
|
@@ -1,13 +1,12 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
<p align="center"><i>NetBox DNS is a NetBox plugin for managing DNS views, zones, name servers and records.</i></p>
|
|
1
|
+
# NetBox DNS
|
|
2
|
+
The NetBox DNS plugin enables NetBox to manage operational DNS data such as name servers, zones, records and views, as well as registration data for domains. It can automate tasks like creating PTR records, generating zone serial numbers, NS and SOA records, as well as validate names and values values for resource records to ensure zone data is consistent, current and conforming to the relevant RFCs.
|
|
4
3
|
|
|
5
4
|
<div align="center">
|
|
6
5
|
<a href="https://pypi.org/project/netbox-plugin-dns/"><img src="https://img.shields.io/pypi/v/netbox-plugin-dns" alt="PyPi"/></a>
|
|
7
|
-
<a href="https://github.com/peteeckel/netbox-plugin-dns/stargazers"><img src="https://img.shields.io/github/stars/peteeckel/netbox-plugin-dns" alt="Stars Badge"/></a>
|
|
8
|
-
<a href="https://github.com/peteeckel/netbox-plugin-dns/network/members"><img src="https://img.shields.io/github/forks/peteeckel/netbox-plugin-dns" alt="Forks Badge"/></a>
|
|
9
|
-
<a href="https://github.com/peteeckel/netbox-plugin-dns/pulls"><img src="https://img.shields.io/github/issues-pr/peteeckel/netbox-plugin-dns" alt="Pull Requests Badge"/></a>
|
|
6
|
+
<a href="https://github.com/peteeckel/netbox-plugin-dns/stargazers"><img src="https://img.shields.io/github/stars/peteeckel/netbox-plugin-dns?style=flat" alt="Stars Badge"/></a>
|
|
7
|
+
<a href="https://github.com/peteeckel/netbox-plugin-dns/network/members"><img src="https://img.shields.io/github/forks/peteeckel/netbox-plugin-dns?style=flat" alt="Forks Badge"/></a>
|
|
10
8
|
<a href="https://github.com/peteeckel/netbox-plugin-dns/issues"><img src="https://img.shields.io/github/issues/peteeckel/netbox-plugin-dns" alt="Issues Badge"/></a>
|
|
9
|
+
<a href="https://github.com/peteeckel/netbox-plugin-dns/pulls"><img src="https://img.shields.io/github/issues-pr/peteeckel/netbox-plugin-dns" alt="Pull Requests Badge"/></a>
|
|
11
10
|
<a href="https://github.com/peteeckel/netbox-plugin-dns/graphs/contributors"><img alt="GitHub contributors" src="https://img.shields.io/github/contributors/peteeckel/netbox-plugin-dns?color=2b9348"></a>
|
|
12
11
|
<a href="https://github.com/peteeckel/netbox-plugin-dns/blob/master/LICENSE"><img src="https://img.shields.io/github/license/peteeckel/netbox-plugin-dns?color=2b9348" alt="License Badge"/></a>
|
|
13
12
|
<a href="https://pepy.tech/project/netbox-plugin-dns"><img alt="Downloads" src="https://static.pepy.tech/badge/netbox-plugin-dns"></a>
|
|
@@ -19,10 +18,10 @@
|
|
|
19
18
|
|
|
20
19
|
* Manage name servers, zones and records
|
|
21
20
|
* Automatically generate SOA and NS records for zones
|
|
22
|
-
* Automatically create and update PTR records for IPv4 and IPv6 records
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
21
|
+
* Automatically create and update PTR records for IPv4 and IPv6 address records
|
|
22
|
+
* Organize DNS zones in views for split horizon DNS and multi-site deployments
|
|
23
|
+
* Manage domain registrar and registrant information for domains related to zones
|
|
24
|
+
* Manage RFC2317 reverse zones for IPv4 prefixes with a network mask length longer than 24 bits
|
|
26
25
|
|
|
27
26
|
NetBox DNS is using the standardized NetBox plugin interface, so it also takes advantage of the NetBox tagging and change log features.
|
|
28
27
|
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
|
|
3
|
+
from extras.plugins import PluginConfig
|
|
4
|
+
from django.db.utils import OperationalError
|
|
5
|
+
|
|
6
|
+
try:
|
|
7
|
+
# NetBox 3.5.0 - 3.5.7, 3.5.9+
|
|
8
|
+
from extras.plugins import get_plugin_config
|
|
9
|
+
except ImportError:
|
|
10
|
+
# NetBox 3.5.8
|
|
11
|
+
from extras.plugins.utils import get_plugin_config
|
|
12
|
+
|
|
13
|
+
__version__ = "0.22.6"
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class DNSConfig(PluginConfig):
|
|
17
|
+
name = "netbox_dns"
|
|
18
|
+
verbose_name = "NetBox DNS"
|
|
19
|
+
description = "NetBox plugin for DNS data"
|
|
20
|
+
min_version = "3.5.0"
|
|
21
|
+
version = __version__
|
|
22
|
+
author = "Peter Eckel"
|
|
23
|
+
author_email = "pete@netbox-dns.org"
|
|
24
|
+
required_settings = []
|
|
25
|
+
default_settings = {
|
|
26
|
+
"zone_default_ttl": 86400,
|
|
27
|
+
"zone_soa_serial_auto": True,
|
|
28
|
+
"zone_soa_serial": 1,
|
|
29
|
+
"zone_soa_refresh": 43200,
|
|
30
|
+
"zone_soa_retry": 7200,
|
|
31
|
+
"zone_soa_expire": 2419200,
|
|
32
|
+
"zone_soa_minimum": 3600,
|
|
33
|
+
"feature_ipam_coupling": False,
|
|
34
|
+
"tolerate_underscores_in_hostnames": False,
|
|
35
|
+
"tolerate_leading_underscore_types": [
|
|
36
|
+
"TXT",
|
|
37
|
+
"SRV",
|
|
38
|
+
],
|
|
39
|
+
"tolerate_non_rfc1035_types": [],
|
|
40
|
+
"enable_root_zones": False,
|
|
41
|
+
"enforce_unique_records": True,
|
|
42
|
+
"enforce_unique_rrset_ttl": True,
|
|
43
|
+
}
|
|
44
|
+
base_url = "netbox-dns"
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
#
|
|
48
|
+
# Initialize plugin config
|
|
49
|
+
#
|
|
50
|
+
config = DNSConfig
|
|
@@ -17,6 +17,7 @@ class RegistrarForm(NetBoxModelForm):
|
|
|
17
17
|
fields = (
|
|
18
18
|
"name",
|
|
19
19
|
"iana_id",
|
|
20
|
+
"address",
|
|
20
21
|
"referral_url",
|
|
21
22
|
"whois_server",
|
|
22
23
|
"abuse_email",
|
|
@@ -29,12 +30,18 @@ class RegistrarFilterForm(NetBoxModelFilterSetForm):
|
|
|
29
30
|
model = Registrar
|
|
30
31
|
fieldsets = (
|
|
31
32
|
(None, ("q", "name", "iana_id", "tags")),
|
|
32
|
-
(
|
|
33
|
+
(
|
|
34
|
+
"Contact",
|
|
35
|
+
("address", "referral_url", "whois_server", "abuse_email", "abuse_phone"),
|
|
36
|
+
),
|
|
33
37
|
)
|
|
34
38
|
|
|
35
39
|
name = forms.CharField(
|
|
36
40
|
required=False,
|
|
37
41
|
)
|
|
42
|
+
address = forms.CharField(
|
|
43
|
+
required=False,
|
|
44
|
+
)
|
|
38
45
|
iana_id = forms.IntegerField(
|
|
39
46
|
required=False,
|
|
40
47
|
label="IANA ID",
|
|
@@ -64,6 +71,7 @@ class RegistrarImportForm(NetBoxModelImportForm):
|
|
|
64
71
|
fields = (
|
|
65
72
|
"name",
|
|
66
73
|
"iana_id",
|
|
74
|
+
"address",
|
|
67
75
|
"referral_url",
|
|
68
76
|
"whois_server",
|
|
69
77
|
"abuse_email",
|
|
@@ -96,6 +104,7 @@ class RegistrarBulkEditForm(NetBoxModelBulkEditForm):
|
|
|
96
104
|
(
|
|
97
105
|
None,
|
|
98
106
|
(
|
|
107
|
+
"address",
|
|
99
108
|
"referral_url",
|
|
100
109
|
"whois_server",
|
|
101
110
|
"abuse_email",
|
|
@@ -105,6 +114,7 @@ class RegistrarBulkEditForm(NetBoxModelBulkEditForm):
|
|
|
105
114
|
)
|
|
106
115
|
|
|
107
116
|
nullable_fields = (
|
|
117
|
+
"address",
|
|
108
118
|
"referral_url",
|
|
109
119
|
"whois_server",
|
|
110
120
|
"abuse_email",
|
|
@@ -315,7 +315,7 @@ class ZoneImportForm(NetBoxModelImportForm):
|
|
|
315
315
|
required=False,
|
|
316
316
|
help_text="Mailbox of the zone's administrator",
|
|
317
317
|
)
|
|
318
|
-
soa_serial_auto = forms.
|
|
318
|
+
soa_serial_auto = forms.NullBooleanField(
|
|
319
319
|
required=False,
|
|
320
320
|
help_text="Generate the SOA serial",
|
|
321
321
|
)
|
|
@@ -443,26 +443,6 @@ class ZoneImportForm(NetBoxModelImportForm):
|
|
|
443
443
|
def clean_soa_rname(self):
|
|
444
444
|
return self._clean_field_with_defaults("soa_rname")
|
|
445
445
|
|
|
446
|
-
def clean_soa_serial_auto(self):
|
|
447
|
-
try:
|
|
448
|
-
return self._clean_field_with_defaults("soa_serial_auto")
|
|
449
|
-
except ValidationError:
|
|
450
|
-
if self.cleaned_data["soa_serial"] or self._get_default_value("soa_serial"):
|
|
451
|
-
return None
|
|
452
|
-
|
|
453
|
-
raise
|
|
454
|
-
|
|
455
|
-
def clean_soa_serial(self):
|
|
456
|
-
try:
|
|
457
|
-
return self._clean_field_with_defaults("soa_serial")
|
|
458
|
-
except ValidationError:
|
|
459
|
-
if self.cleaned_data["soa_serial_auto"] or self._get_default_value(
|
|
460
|
-
"soa_serial_auto"
|
|
461
|
-
):
|
|
462
|
-
return None
|
|
463
|
-
|
|
464
|
-
raise
|
|
465
|
-
|
|
466
446
|
def clean_soa_refresh(self):
|
|
467
447
|
return self._clean_field_with_defaults("soa_refresh")
|
|
468
448
|
|
|
@@ -475,6 +455,36 @@ class ZoneImportForm(NetBoxModelImportForm):
|
|
|
475
455
|
def clean_soa_minimum(self):
|
|
476
456
|
return self._clean_field_with_defaults("soa_minimum")
|
|
477
457
|
|
|
458
|
+
def clean(self, *args, **kwargs):
|
|
459
|
+
super().clean(*args, **kwargs)
|
|
460
|
+
|
|
461
|
+
soa_serial_auto = self.cleaned_data.get("soa_serial_auto")
|
|
462
|
+
soa_serial = self.cleaned_data.get("soa_serial")
|
|
463
|
+
|
|
464
|
+
if soa_serial is None:
|
|
465
|
+
soa_serial = self._get_default_value("soa_serial")
|
|
466
|
+
|
|
467
|
+
if soa_serial_auto is None:
|
|
468
|
+
if self._get_default_value("soa_serial_auto") is not None:
|
|
469
|
+
soa_serial_auto = self._get_default_value("soa_serial_auto")
|
|
470
|
+
|
|
471
|
+
elif soa_serial is not None:
|
|
472
|
+
soa_serial_auto = False
|
|
473
|
+
|
|
474
|
+
else:
|
|
475
|
+
raise ValidationError(
|
|
476
|
+
"SOA Serial Auto not set and no default value and SOA Serial available"
|
|
477
|
+
)
|
|
478
|
+
|
|
479
|
+
if "soa_serial_auto" in self.cleaned_data:
|
|
480
|
+
self.cleaned_data["soa_serial_auto"] = soa_serial_auto
|
|
481
|
+
|
|
482
|
+
if "soa_serial" in self.cleaned_data:
|
|
483
|
+
if soa_serial_auto:
|
|
484
|
+
self.cleaned_data["soa_serial"] = None
|
|
485
|
+
else:
|
|
486
|
+
self.cleaned_data["soa_serial"] = soa_serial
|
|
487
|
+
|
|
478
488
|
class Meta:
|
|
479
489
|
model = Zone
|
|
480
490
|
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
from django.core.management.base import BaseCommand
|
|
2
|
+
from django.db.models import Max, Min
|
|
3
|
+
|
|
4
|
+
from netbox_dns.models import (
|
|
5
|
+
Record,
|
|
6
|
+
RecordTypeChoices,
|
|
7
|
+
)
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class Command(BaseCommand):
|
|
11
|
+
help = "Clean up the TTLs for RRSets"
|
|
12
|
+
|
|
13
|
+
def add_arguments(self, parser):
|
|
14
|
+
min_max = parser.add_mutually_exclusive_group()
|
|
15
|
+
min_max.add_argument(
|
|
16
|
+
"--min",
|
|
17
|
+
action="store_true",
|
|
18
|
+
help="Use the minimum TTL of an RRSet for all Records",
|
|
19
|
+
)
|
|
20
|
+
min_max.add_argument(
|
|
21
|
+
"--max",
|
|
22
|
+
action="store_true",
|
|
23
|
+
help="Use the maximum TTL of an RRSet for all Records",
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
def handle(self, *model_names, **options):
|
|
27
|
+
self.cleanup_rrset_ttl(**options)
|
|
28
|
+
|
|
29
|
+
self.stdout.write("RRSet cleanup completed.")
|
|
30
|
+
|
|
31
|
+
def cleanup_rrset_ttl(self, **options):
|
|
32
|
+
verbose = options.get("verbosity") > 1
|
|
33
|
+
|
|
34
|
+
ttl_records = (
|
|
35
|
+
Record.objects.filter(ttl__isnull=False)
|
|
36
|
+
.exclude(type=RecordTypeChoices.SOA)
|
|
37
|
+
.exclude(type=RecordTypeChoices.PTR, maanged=True)
|
|
38
|
+
)
|
|
39
|
+
for record in ttl_records:
|
|
40
|
+
records = Record.objects.filter(
|
|
41
|
+
name=record.name,
|
|
42
|
+
zone=record.zone,
|
|
43
|
+
type=record.type,
|
|
44
|
+
).exclude(type=RecordTypeChoices.PTR, maanged=True)
|
|
45
|
+
|
|
46
|
+
if records.count() == 1:
|
|
47
|
+
if options.get("verbosity") > 2:
|
|
48
|
+
self.stdout.write(f"Ignoring single record {record.id} ({record})")
|
|
49
|
+
continue
|
|
50
|
+
|
|
51
|
+
if options.get("max"):
|
|
52
|
+
ttl = records.aggregate(Max("ttl")).get("ttl__max")
|
|
53
|
+
else:
|
|
54
|
+
ttl = records.aggregate(Min("ttl")).get("ttl__min")
|
|
55
|
+
|
|
56
|
+
for record in records.exclude(ttl=ttl):
|
|
57
|
+
if options.get("verbosity") > 1:
|
|
58
|
+
self.stdout.write(
|
|
59
|
+
f"Updating TTL for record {record.id} ({record}) to {ttl}"
|
|
60
|
+
)
|
|
61
|
+
record.ttl = ttl
|
|
62
|
+
record.save(update_fields=["ttl"], update_rrset_ttl=False)
|
|
@@ -6,7 +6,7 @@ from dns import name as dns_name
|
|
|
6
6
|
|
|
7
7
|
from django.core.exceptions import ValidationError
|
|
8
8
|
from django.db import transaction, models
|
|
9
|
-
from django.db.models import Q, ExpressionWrapper, BooleanField
|
|
9
|
+
from django.db.models import Q, ExpressionWrapper, BooleanField, Min
|
|
10
10
|
from django.db.models.functions import Length
|
|
11
11
|
from django.urls import reverse
|
|
12
12
|
|
|
@@ -38,6 +38,10 @@ from netbox_dns.validators import (
|
|
|
38
38
|
import netbox_dns.models.zone as zone
|
|
39
39
|
|
|
40
40
|
|
|
41
|
+
def min_ttl(*ttl_list):
|
|
42
|
+
return min((ttl for ttl in ttl_list if ttl is not None), default=None)
|
|
43
|
+
|
|
44
|
+
|
|
41
45
|
class RecordManager(models.Manager.from_queryset(RestrictedQuerySet)):
|
|
42
46
|
"""Special Manager for records providing the activity status annotation"""
|
|
43
47
|
|
|
@@ -207,7 +211,8 @@ class Record(NetBoxModel):
|
|
|
207
211
|
try:
|
|
208
212
|
name = (
|
|
209
213
|
dns_name.from_text(
|
|
210
|
-
|
|
214
|
+
str(self.name),
|
|
215
|
+
origin=dns_name.from_text(self.zone.name, origin=None),
|
|
211
216
|
)
|
|
212
217
|
.relativize(dns_name.root)
|
|
213
218
|
.to_unicode()
|
|
@@ -236,6 +241,16 @@ class Record(NetBoxModel):
|
|
|
236
241
|
|
|
237
242
|
return name.to_text()
|
|
238
243
|
|
|
244
|
+
@property
|
|
245
|
+
def value_fqdn(self):
|
|
246
|
+
if self.type != RecordTypeChoices.CNAME:
|
|
247
|
+
return None
|
|
248
|
+
|
|
249
|
+
zone = dns_name.from_text(self.zone.name)
|
|
250
|
+
value_fqdn = dns_name.from_text(self.value, origin=zone)
|
|
251
|
+
|
|
252
|
+
return value_fqdn.to_text()
|
|
253
|
+
|
|
239
254
|
@property
|
|
240
255
|
def address_from_name(self):
|
|
241
256
|
prefix = arpa_to_prefix(self.fqdn)
|
|
@@ -309,7 +324,7 @@ class Record(NetBoxModel):
|
|
|
309
324
|
|
|
310
325
|
return ptr_zone
|
|
311
326
|
|
|
312
|
-
def update_ptr_record(self, update_rfc2317_cname=True):
|
|
327
|
+
def update_ptr_record(self, update_rfc2317_cname=True, save_zone_serial=True):
|
|
313
328
|
ptr_zone = self.ptr_zone
|
|
314
329
|
|
|
315
330
|
if (
|
|
@@ -339,14 +354,16 @@ class Record(NetBoxModel):
|
|
|
339
354
|
not ptr_record.zone.is_rfc2317_zone
|
|
340
355
|
and ptr_record.rfc2317_cname_record is not None
|
|
341
356
|
):
|
|
342
|
-
ptr_record.rfc2317_cname_record.delete(
|
|
357
|
+
ptr_record.rfc2317_cname_record.delete(
|
|
358
|
+
save_zone_serial=save_zone_serial
|
|
359
|
+
)
|
|
343
360
|
|
|
344
361
|
with transaction.atomic():
|
|
345
362
|
if ptr_record is not None:
|
|
346
363
|
if ptr_record.zone.pk != ptr_zone.pk:
|
|
347
364
|
if ptr_record.rfc2317_cname_record is not None:
|
|
348
365
|
ptr_record.rfc2317_cname_record.delete()
|
|
349
|
-
ptr_record.delete()
|
|
366
|
+
ptr_record.delete(save_zone_serial=save_zone_serial)
|
|
350
367
|
ptr_record = None
|
|
351
368
|
|
|
352
369
|
else:
|
|
@@ -358,7 +375,7 @@ class Record(NetBoxModel):
|
|
|
358
375
|
ptr_record.name = ptr_name
|
|
359
376
|
ptr_record.value = ptr_value
|
|
360
377
|
ptr_record.ttl = self.ttl
|
|
361
|
-
ptr_record.save()
|
|
378
|
+
ptr_record.save(save_zone_serial=save_zone_serial)
|
|
362
379
|
|
|
363
380
|
if ptr_record is None:
|
|
364
381
|
ptr_record = Record(
|
|
@@ -369,11 +386,14 @@ class Record(NetBoxModel):
|
|
|
369
386
|
value=ptr_value,
|
|
370
387
|
managed=True,
|
|
371
388
|
)
|
|
372
|
-
ptr_record.save(
|
|
389
|
+
ptr_record.save(
|
|
390
|
+
update_rfc2317_cname=update_rfc2317_cname,
|
|
391
|
+
save_zone_serial=save_zone_serial,
|
|
392
|
+
)
|
|
373
393
|
|
|
374
394
|
self.ptr_record = ptr_record
|
|
375
395
|
|
|
376
|
-
def update_rfc2317_cname_record(self):
|
|
396
|
+
def update_rfc2317_cname_record(self, save_zone_serial=True):
|
|
377
397
|
if self.zone.rfc2317_parent_managed:
|
|
378
398
|
cname_name = dns_name.from_text(
|
|
379
399
|
ipaddress.ip_address(self.ip_address).reverse_pointer
|
|
@@ -383,7 +403,13 @@ class Record(NetBoxModel):
|
|
|
383
403
|
self.rfc2317_cname_record.name = cname_name
|
|
384
404
|
self.rfc2317_cname_record.zone = self.zone.rfc2317_parent_zone
|
|
385
405
|
self.rfc2317_cname_record.value = self.fqdn
|
|
386
|
-
self.rfc2317_cname_record.
|
|
406
|
+
self.rfc2317_cname_record.ttl = min_ttl(
|
|
407
|
+
self.rfc2317_cname_record.rfc2317_ptr_records.exclude(pk=self.pk)
|
|
408
|
+
.aggregate(Min("ttl"))
|
|
409
|
+
.get("ttl__min"),
|
|
410
|
+
self.ttl,
|
|
411
|
+
)
|
|
412
|
+
self.rfc2317_cname_record.save(save_zone_serial=save_zone_serial)
|
|
387
413
|
else:
|
|
388
414
|
rfc2317_cname_record = Record.objects.filter(
|
|
389
415
|
name=cname_name,
|
|
@@ -392,20 +418,34 @@ class Record(NetBoxModel):
|
|
|
392
418
|
managed=True,
|
|
393
419
|
value=self.fqdn,
|
|
394
420
|
).first()
|
|
395
|
-
|
|
396
|
-
|
|
421
|
+
|
|
422
|
+
if rfc2317_cname_record is not None:
|
|
423
|
+
rfc2317_cname_record.ttl = min_ttl(
|
|
424
|
+
rfc2317_cname_record.rfc2317_ptr_records.exclude(pk=self.pk)
|
|
425
|
+
.aggregate(Min("ttl"))
|
|
426
|
+
.get("ttl__min"),
|
|
427
|
+
self.ttl,
|
|
428
|
+
)
|
|
429
|
+
rfc2317_cname_record.save(
|
|
430
|
+
update_fields=["ttl"], save_zone_serial=save_zone_serial
|
|
431
|
+
)
|
|
432
|
+
|
|
433
|
+
else:
|
|
434
|
+
rfc2317_cname_record = Record(
|
|
397
435
|
name=cname_name,
|
|
398
436
|
type=RecordTypeChoices.CNAME,
|
|
399
437
|
zone=self.zone.rfc2317_parent_zone,
|
|
400
438
|
managed=True,
|
|
401
439
|
value=self.fqdn,
|
|
440
|
+
ttl=self.ttl,
|
|
402
441
|
)
|
|
442
|
+
rfc2317_cname_record.save(save_zone_serial=save_zone_serial)
|
|
403
443
|
|
|
404
444
|
self.rfc2317_cname_record = rfc2317_cname_record
|
|
405
445
|
|
|
406
446
|
else:
|
|
407
447
|
if self.rfc2317_cname_record is not None:
|
|
408
|
-
self.rfc2317_cname_record.delete()
|
|
448
|
+
self.rfc2317_cname_record.delete(save_zone_serial=save_zone_serial)
|
|
409
449
|
self.rfc2317_cname_record = None
|
|
410
450
|
|
|
411
451
|
def validate_name(self):
|
|
@@ -475,7 +515,7 @@ class Record(NetBoxModel):
|
|
|
475
515
|
}
|
|
476
516
|
) from None
|
|
477
517
|
|
|
478
|
-
def
|
|
518
|
+
def check_unique_record(self):
|
|
479
519
|
if not get_plugin_config("netbox_dns", "enforce_unique_records", False):
|
|
480
520
|
return
|
|
481
521
|
|
|
@@ -489,6 +529,10 @@ class Record(NetBoxModel):
|
|
|
489
529
|
value=self.value,
|
|
490
530
|
status__in=Record.ACTIVE_STATUS_LIST,
|
|
491
531
|
)
|
|
532
|
+
|
|
533
|
+
if self.pk is not None:
|
|
534
|
+
records = records.exclude(pk=self.pk)
|
|
535
|
+
|
|
492
536
|
if len(records):
|
|
493
537
|
raise ValidationError(
|
|
494
538
|
{
|
|
@@ -496,6 +540,64 @@ class Record(NetBoxModel):
|
|
|
496
540
|
}
|
|
497
541
|
) from None
|
|
498
542
|
|
|
543
|
+
def check_unique_rrset_ttl(self):
|
|
544
|
+
if self.pk is not None:
|
|
545
|
+
return
|
|
546
|
+
|
|
547
|
+
if not get_plugin_config("netbox_dns", "enforce_unique_rrset_ttl", False):
|
|
548
|
+
return
|
|
549
|
+
|
|
550
|
+
if self.type == RecordTypeChoices.PTR and self.managed:
|
|
551
|
+
return
|
|
552
|
+
|
|
553
|
+
records = (
|
|
554
|
+
Record.objects.filter(
|
|
555
|
+
zone=self.zone,
|
|
556
|
+
name=self.name,
|
|
557
|
+
type=self.type,
|
|
558
|
+
)
|
|
559
|
+
.exclude(ttl=self.ttl)
|
|
560
|
+
.exclude(type=RecordTypeChoices.PTR, managed=True)
|
|
561
|
+
)
|
|
562
|
+
|
|
563
|
+
if not records.exists():
|
|
564
|
+
return
|
|
565
|
+
|
|
566
|
+
conflicting_ttls = ", ".join(set(str(record.ttl) for record in records))
|
|
567
|
+
raise ValidationError(
|
|
568
|
+
{
|
|
569
|
+
"ttl": f"There is at least one active {self.type} record for name {self.name} in zone {self.zone} and TTL is different ({conflicting_ttls})."
|
|
570
|
+
}
|
|
571
|
+
) from None
|
|
572
|
+
|
|
573
|
+
def update_rrset_ttl(self, ttl=None):
|
|
574
|
+
if self.pk is None:
|
|
575
|
+
return
|
|
576
|
+
|
|
577
|
+
if not get_plugin_config("netbox_dns", "enforce_unique_rrset_ttl", False):
|
|
578
|
+
return
|
|
579
|
+
|
|
580
|
+
if self.type == RecordTypeChoices.PTR and self.managed:
|
|
581
|
+
return
|
|
582
|
+
|
|
583
|
+
if ttl is None:
|
|
584
|
+
ttl = self.ttl
|
|
585
|
+
|
|
586
|
+
records = (
|
|
587
|
+
Record.objects.filter(
|
|
588
|
+
zone=self.zone,
|
|
589
|
+
name=self.name,
|
|
590
|
+
type=self.type,
|
|
591
|
+
)
|
|
592
|
+
.exclude(pk=self.pk)
|
|
593
|
+
.exclude(ttl=ttl)
|
|
594
|
+
.exclude(type=RecordTypeChoices.PTR, managed=True)
|
|
595
|
+
)
|
|
596
|
+
|
|
597
|
+
for record in records:
|
|
598
|
+
record.ttl = ttl
|
|
599
|
+
record.save(update_fields=["ttl"], update_rrset_ttl=False)
|
|
600
|
+
|
|
499
601
|
def clean_fields(self, *args, **kwargs):
|
|
500
602
|
self.type = self.type.upper()
|
|
501
603
|
super().clean_fields(*args, **kwargs)
|
|
@@ -503,7 +605,9 @@ class Record(NetBoxModel):
|
|
|
503
605
|
def clean(self, *args, **kwargs):
|
|
504
606
|
self.validate_name()
|
|
505
607
|
self.validate_value()
|
|
506
|
-
self.
|
|
608
|
+
self.check_unique_record()
|
|
609
|
+
if self.pk is None:
|
|
610
|
+
self.check_unique_rrset_ttl()
|
|
507
611
|
|
|
508
612
|
if not self.is_active:
|
|
509
613
|
return
|
|
@@ -578,14 +682,24 @@ class Record(NetBoxModel):
|
|
|
578
682
|
}
|
|
579
683
|
) from None
|
|
580
684
|
|
|
581
|
-
def save(
|
|
685
|
+
def save(
|
|
686
|
+
self,
|
|
687
|
+
*args,
|
|
688
|
+
update_rfc2317_cname=True,
|
|
689
|
+
save_zone_serial=True,
|
|
690
|
+
update_rrset_ttl=True,
|
|
691
|
+
**kwargs,
|
|
692
|
+
):
|
|
582
693
|
self.full_clean()
|
|
583
694
|
|
|
695
|
+
if self.pk is not None and update_rrset_ttl:
|
|
696
|
+
self.update_rrset_ttl()
|
|
697
|
+
|
|
584
698
|
if self.is_ptr_record:
|
|
585
699
|
if self.zone.is_rfc2317_zone:
|
|
586
700
|
self.ip_address = self.address_from_rfc2317_name
|
|
587
701
|
if update_rfc2317_cname:
|
|
588
|
-
self.update_rfc2317_cname_record()
|
|
702
|
+
self.update_rfc2317_cname_record(save_zone_serial=save_zone_serial)
|
|
589
703
|
else:
|
|
590
704
|
self.ip_address = self.address_from_name
|
|
591
705
|
|
|
@@ -595,7 +709,10 @@ class Record(NetBoxModel):
|
|
|
595
709
|
self.ip_address = None
|
|
596
710
|
|
|
597
711
|
if self.is_address_record:
|
|
598
|
-
self.update_ptr_record(
|
|
712
|
+
self.update_ptr_record(
|
|
713
|
+
update_rfc2317_cname=update_rfc2317_cname,
|
|
714
|
+
save_zone_serial=save_zone_serial,
|
|
715
|
+
)
|
|
599
716
|
elif self.ptr_record is not None:
|
|
600
717
|
self.ptr_record.delete()
|
|
601
718
|
self.ptr_record = None
|
|
@@ -604,15 +721,24 @@ class Record(NetBoxModel):
|
|
|
604
721
|
|
|
605
722
|
zone = self.zone
|
|
606
723
|
if self.type != RecordTypeChoices.SOA and zone.soa_serial_auto:
|
|
607
|
-
zone.update_serial()
|
|
724
|
+
zone.update_serial(save_zone_serial=save_zone_serial)
|
|
608
725
|
|
|
609
|
-
def delete(self, *args, **kwargs):
|
|
726
|
+
def delete(self, *args, save_zone_serial=True, **kwargs):
|
|
610
727
|
if self.rfc2317_cname_record:
|
|
611
|
-
if
|
|
612
|
-
self.rfc2317_cname_record.
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
728
|
+
if self.rfc2317_cname_record.pk:
|
|
729
|
+
if self.rfc2317_cname_record.rfc2317_ptr_records.count() == 1:
|
|
730
|
+
self.rfc2317_cname_record.delete()
|
|
731
|
+
else:
|
|
732
|
+
self.rfc2317_cname_record.ttl = (
|
|
733
|
+
self.rfc2317_cname_record.rfc2317_ptr_records.exclude(
|
|
734
|
+
pk=self.pk
|
|
735
|
+
)
|
|
736
|
+
.aggregate(Min("ttl"))
|
|
737
|
+
.get("ttl__min")
|
|
738
|
+
)
|
|
739
|
+
self.rfc2317_cname_record.save(
|
|
740
|
+
update_fields=["ttl"], save_zone_serial=save_zone_serial
|
|
741
|
+
)
|
|
616
742
|
|
|
617
743
|
if self.ptr_record:
|
|
618
744
|
self.ptr_record.delete()
|
|
@@ -621,7 +747,7 @@ class Record(NetBoxModel):
|
|
|
621
747
|
|
|
622
748
|
zone = self.zone
|
|
623
749
|
if zone.soa_serial_auto:
|
|
624
|
-
zone.update_serial()
|
|
750
|
+
zone.update_serial(save_zone_serial=save_zone_serial)
|
|
625
751
|
|
|
626
752
|
|
|
627
753
|
@register_search
|