netbox-plugin-dns 1.1.0b2__tar.gz → 1.1.0b4__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-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/PKG-INFO +1 -1
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/netbox_dns/__init__.py +7 -6
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/netbox_dns/filtersets/record.py +1 -1
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/netbox_dns/forms/view.py +91 -4
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/netbox_dns/forms/zone.py +9 -4
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/netbox_dns/graphql/types.py +2 -0
- netbox_plugin_dns-1.1.0b2/netbox_dns/management/commands/setup_autodns.py → netbox_plugin_dns-1.1.0b4/netbox_dns/management/commands/setup_dnssync.py +19 -15
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/netbox_dns/models/record.py +23 -14
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/netbox_dns/models/zone.py +10 -5
- netbox_plugin_dns-1.1.0b2/netbox_dns/signals/ipam_autodns.py → netbox_plugin_dns-1.1.0b4/netbox_dns/signals/ipam_dnssync.py +72 -22
- netbox_plugin_dns-1.1.0b4/netbox_dns/tables/ipam_dnssync.py +11 -0
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/netbox_dns/template_content.py +14 -2
- netbox_plugin_dns-1.1.0b4/netbox_dns/templates/netbox_dns/view/button.html +9 -0
- netbox_plugin_dns-1.1.0b4/netbox_dns/templates/netbox_dns/view/prefix.html +41 -0
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/netbox_dns/templates/netbox_dns/view.html +1 -1
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/netbox_dns/urls/view.py +6 -0
- netbox_plugin_dns-1.1.0b4/netbox_dns/utilities/__init__.py +2 -0
- netbox_plugin_dns-1.1.0b2/netbox_dns/utilities/ipam_autodns.py → netbox_plugin_dns-1.1.0b4/netbox_dns/utilities/ipam_dnssync.py +55 -31
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/netbox_dns/views/record.py +2 -2
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/netbox_dns/views/view.py +26 -1
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/pyproject.toml +1 -1
- netbox_plugin_dns-1.1.0b2/netbox_dns/utilities/__init__.py +0 -2
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/LICENSE +0 -0
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/README.md +0 -0
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/netbox_dns/api/nested_serializers.py +0 -0
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/netbox_dns/api/serializers.py +0 -0
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/netbox_dns/api/serializers_/__init__.py +0 -0
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/netbox_dns/api/serializers_/contact.py +0 -0
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/netbox_dns/api/serializers_/nameserver.py +0 -0
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/netbox_dns/api/serializers_/prefix.py +0 -0
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/netbox_dns/api/serializers_/record.py +0 -0
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/netbox_dns/api/serializers_/record_template.py +0 -0
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/netbox_dns/api/serializers_/registrar.py +0 -0
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/netbox_dns/api/serializers_/view.py +0 -0
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/netbox_dns/api/serializers_/zone.py +0 -0
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/netbox_dns/api/serializers_/zone_template.py +0 -0
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/netbox_dns/api/urls.py +0 -0
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/netbox_dns/api/views.py +0 -0
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/netbox_dns/apps.py +0 -0
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/netbox_dns/choices/__init__.py +0 -0
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/netbox_dns/choices/record.py +0 -0
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/netbox_dns/choices/zone.py +0 -0
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/netbox_dns/fields/__init__.py +0 -0
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/netbox_dns/fields/address.py +0 -0
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/netbox_dns/fields/ipam.py +0 -0
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/netbox_dns/fields/network.py +0 -0
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/netbox_dns/fields/rfc2317.py +0 -0
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/netbox_dns/filtersets/__init__.py +0 -0
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/netbox_dns/filtersets/contact.py +0 -0
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/netbox_dns/filtersets/nameserver.py +0 -0
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/netbox_dns/filtersets/record_template.py +0 -0
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/netbox_dns/filtersets/registrar.py +0 -0
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/netbox_dns/filtersets/view.py +0 -0
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/netbox_dns/filtersets/zone.py +0 -0
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/netbox_dns/filtersets/zone_template.py +0 -0
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/netbox_dns/forms/__init__.py +0 -0
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/netbox_dns/forms/contact.py +0 -0
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/netbox_dns/forms/nameserver.py +0 -0
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/netbox_dns/forms/record.py +0 -0
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/netbox_dns/forms/record_template.py +0 -0
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/netbox_dns/forms/registrar.py +0 -0
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/netbox_dns/forms/zone_template.py +0 -0
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/netbox_dns/graphql/__init__.py +0 -0
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/netbox_dns/graphql/filters.py +0 -0
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/netbox_dns/graphql/schema.py +0 -0
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/netbox_dns/management/commands/cleanup_database.py +0 -0
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/netbox_dns/management/commands/cleanup_rrset_ttl.py +0 -0
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/netbox_dns/management/commands/update_soa.py +0 -0
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/netbox_dns/migrations/0001_squashed_netbox_dns_0_15.py +0 -0
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/netbox_dns/migrations/0001_squashed_netbox_dns_0_22.py +0 -0
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/netbox_dns/migrations/0002_contact_description_registrar_description.py +0 -0
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/netbox_dns/migrations/0003_default_view.py +0 -0
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/netbox_dns/migrations/0004_create_and_assign_default_view.py +0 -0
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/netbox_dns/migrations/0005_alter_zone_view_not_null.py +0 -0
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/netbox_dns/migrations/0006_templating.py +0 -0
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/netbox_dns/migrations/0007_view_prefixes.py +0 -0
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/netbox_dns/migrations/0020_netbox_3_4.py +0 -0
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/netbox_dns/migrations/0021_record_ip_address.py +0 -0
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/netbox_dns/migrations/0022_search.py +0 -0
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/netbox_dns/migrations/0023_alter_record_value.py +0 -0
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/netbox_dns/migrations/0024_tenancy.py +0 -0
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/netbox_dns/migrations/0025_ipam_coupling_cf.py +0 -0
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/netbox_dns/migrations/0026_domain_registration.py +0 -0
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/netbox_dns/migrations/0027_alter_registrar_iana_id.py +0 -0
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/netbox_dns/migrations/0028_rfc2317_fields.py +0 -0
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/netbox_dns/migrations/0029_record_fqdn.py +0 -0
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/netbox_dns/migrations/__init__.py +0 -0
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/netbox_dns/mixins/__init__.py +0 -0
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/netbox_dns/mixins/object_modification.py +0 -0
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/netbox_dns/models/__init__.py +0 -0
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/netbox_dns/models/contact.py +0 -0
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/netbox_dns/models/nameserver.py +0 -0
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/netbox_dns/models/record_template.py +0 -0
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/netbox_dns/models/registrar.py +0 -0
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/netbox_dns/models/view.py +0 -0
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/netbox_dns/models/zone_template.py +0 -0
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/netbox_dns/navigation.py +0 -0
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/netbox_dns/signals/__init__.py +0 -0
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/netbox_dns/tables/__init__.py +0 -0
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/netbox_dns/tables/contact.py +0 -0
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/netbox_dns/tables/nameserver.py +0 -0
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/netbox_dns/tables/record.py +0 -0
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/netbox_dns/tables/record_template.py +0 -0
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/netbox_dns/tables/registrar.py +0 -0
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/netbox_dns/tables/view.py +0 -0
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/netbox_dns/tables/zone.py +0 -0
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/netbox_dns/tables/zone_template.py +0 -0
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/netbox_dns/templates/netbox_dns/contact.html +0 -0
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/netbox_dns/templates/netbox_dns/nameserver.html +0 -0
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/netbox_dns/templates/netbox_dns/record/managed.html +0 -0
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/netbox_dns/templates/netbox_dns/record/related.html +0 -0
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/netbox_dns/templates/netbox_dns/record.html +0 -0
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/netbox_dns/templates/netbox_dns/recordtemplate.html +0 -0
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/netbox_dns/templates/netbox_dns/registrar.html +0 -0
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/netbox_dns/templates/netbox_dns/view/related.html +0 -0
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/netbox_dns/templates/netbox_dns/zone/base.html +0 -0
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/netbox_dns/templates/netbox_dns/zone/child.html +0 -0
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/netbox_dns/templates/netbox_dns/zone/child_zone.html +0 -0
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/netbox_dns/templates/netbox_dns/zone/managed_record.html +0 -0
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/netbox_dns/templates/netbox_dns/zone/record.html +0 -0
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/netbox_dns/templates/netbox_dns/zone/registration.html +0 -0
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/netbox_dns/templates/netbox_dns/zone/rfc2317_child_zone.html +0 -0
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/netbox_dns/templates/netbox_dns/zone.html +0 -0
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/netbox_dns/templates/netbox_dns/zonetemplate.html +0 -0
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/netbox_dns/urls/__init__.py +0 -0
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/netbox_dns/urls/contact.py +0 -0
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/netbox_dns/urls/nameserver.py +0 -0
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/netbox_dns/urls/record.py +0 -0
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/netbox_dns/urls/record_template.py +0 -0
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/netbox_dns/urls/registrar.py +0 -0
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/netbox_dns/urls/zone.py +0 -0
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/netbox_dns/urls/zone_template.py +0 -0
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/netbox_dns/utilities/conversions.py +0 -0
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/netbox_dns/validators/__init__.py +0 -0
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/netbox_dns/validators/dns_name.py +0 -0
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/netbox_dns/validators/dns_value.py +0 -0
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/netbox_dns/validators/rfc2317.py +0 -0
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/netbox_dns/views/__init__.py +0 -0
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/netbox_dns/views/contact.py +0 -0
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/netbox_dns/views/nameserver.py +0 -0
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/netbox_dns/views/record_template.py +0 -0
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/netbox_dns/views/registrar.py +0 -0
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/netbox_dns/views/zone.py +0 -0
- {netbox_plugin_dns-1.1.0b2 → netbox_plugin_dns-1.1.0b4}/netbox_dns/views/zone_template.py +0 -0
|
@@ -5,7 +5,7 @@ from ipam.choices import IPAddressStatusChoices
|
|
|
5
5
|
|
|
6
6
|
from netbox_dns.choices import RecordTypeChoices
|
|
7
7
|
|
|
8
|
-
__version__ = "1.1.
|
|
8
|
+
__version__ = "1.1.0b4"
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
class DNSConfig(PluginConfig):
|
|
@@ -25,13 +25,13 @@ class DNSConfig(PluginConfig):
|
|
|
25
25
|
"zone_soa_retry": 7200,
|
|
26
26
|
"zone_soa_expire": 2419200,
|
|
27
27
|
"zone_soa_minimum": 3600,
|
|
28
|
-
"
|
|
29
|
-
"
|
|
28
|
+
"dnssync_disabled": False,
|
|
29
|
+
"dnssync_ipaddress_active_status": [
|
|
30
30
|
IPAddressStatusChoices.STATUS_ACTIVE,
|
|
31
31
|
IPAddressStatusChoices.STATUS_DHCP,
|
|
32
32
|
IPAddressStatusChoices.STATUS_SLAAC,
|
|
33
33
|
],
|
|
34
|
-
"
|
|
34
|
+
"dnssync_conflict_deactivate": False,
|
|
35
35
|
"tolerate_characters_in_zone_labels": "",
|
|
36
36
|
"tolerate_underscores_in_labels": False,
|
|
37
37
|
"tolerate_underscores_in_hostnames": False, # Deprecated, will be removed in 1.2.0
|
|
@@ -51,8 +51,9 @@ class DNSConfig(PluginConfig):
|
|
|
51
51
|
def ready(self):
|
|
52
52
|
super().ready()
|
|
53
53
|
|
|
54
|
-
if not settings.PLUGINS_CONFIG["netbox_dns"].get("
|
|
55
|
-
|
|
54
|
+
if not settings.PLUGINS_CONFIG["netbox_dns"].get("dnssync_disabled"):
|
|
55
|
+
import netbox_dns.signals.ipam_dnssync
|
|
56
|
+
import netbox_dns.tables.ipam_dnssync
|
|
56
57
|
|
|
57
58
|
|
|
58
59
|
#
|
|
@@ -121,7 +121,7 @@ class RecordFilterSet(TenancyFilterSet, NetBoxModelFilterSet):
|
|
|
121
121
|
if not value.strip():
|
|
122
122
|
return queryset
|
|
123
123
|
qs_filter = (
|
|
124
|
-
Q(
|
|
124
|
+
Q(fqdn__icontains=value)
|
|
125
125
|
| Q(value__icontains=value)
|
|
126
126
|
| Q(zone__name__icontains=value)
|
|
127
127
|
)
|
|
@@ -21,12 +21,12 @@ from utilities.forms.rendering import FieldSet
|
|
|
21
21
|
from tenancy.models import Tenant
|
|
22
22
|
from tenancy.forms import TenancyForm, TenancyFilterForm
|
|
23
23
|
from ipam.models import Prefix
|
|
24
|
+
from netbox.context import current_request
|
|
24
25
|
|
|
25
26
|
from netbox_dns.models import View
|
|
26
27
|
from netbox_dns.fields import PrefixDynamicModelMultipleChoiceField
|
|
27
28
|
from netbox_dns.utilities import (
|
|
28
29
|
check_dns_records,
|
|
29
|
-
update_dns_records,
|
|
30
30
|
get_ip_addresses_by_prefix,
|
|
31
31
|
get_views_by_prefix,
|
|
32
32
|
)
|
|
@@ -37,6 +37,7 @@ __all__ = (
|
|
|
37
37
|
"ViewFilterForm",
|
|
38
38
|
"ViewImportForm",
|
|
39
39
|
"ViewBulkEditForm",
|
|
40
|
+
"ViewPrefixEditForm",
|
|
40
41
|
)
|
|
41
42
|
|
|
42
43
|
|
|
@@ -94,9 +95,24 @@ class ViewForm(ViewPrefixUpdateMixin, TenancyForm, NetBoxModelForm):
|
|
|
94
95
|
def __init__(self, *args, **kwargs):
|
|
95
96
|
super().__init__(*args, **kwargs)
|
|
96
97
|
|
|
97
|
-
if settings.PLUGINS_CONFIG["netbox_dns"].get("
|
|
98
|
+
if settings.PLUGINS_CONFIG["netbox_dns"].get("dnssync_disabled"):
|
|
98
99
|
del self.fields["prefixes"]
|
|
99
100
|
|
|
101
|
+
if request := current_request.get():
|
|
102
|
+
if not request.user.has_perm("ipam.view_prefix"):
|
|
103
|
+
self._saved_prefixes = self.initial["prefixes"]
|
|
104
|
+
self.initial["prefixes"] = []
|
|
105
|
+
self.fields["prefixes"].disabled = True
|
|
106
|
+
self.fields["prefixes"].widget.attrs[
|
|
107
|
+
"placeholder"
|
|
108
|
+
] = "You do not have permission to modify assigned prefixes"
|
|
109
|
+
|
|
110
|
+
def clean_prefixes(self):
|
|
111
|
+
if hasattr(self, "_saved_prefixes"):
|
|
112
|
+
return self._saved_prefixes
|
|
113
|
+
|
|
114
|
+
return self.cleaned_data["prefixes"]
|
|
115
|
+
|
|
100
116
|
prefixes = PrefixDynamicModelMultipleChoiceField(
|
|
101
117
|
queryset=Prefix.objects.all(),
|
|
102
118
|
required=False,
|
|
@@ -128,7 +144,7 @@ class ViewFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
|
|
|
128
144
|
def __init__(self, *args, **kwargs):
|
|
129
145
|
super().__init__(*args, **kwargs)
|
|
130
146
|
|
|
131
|
-
if settings.PLUGINS_CONFIG["netbox_dns"].get("
|
|
147
|
+
if settings.PLUGINS_CONFIG["netbox_dns"].get("dnssync_disabled"):
|
|
132
148
|
del self.fields["prefix_id"]
|
|
133
149
|
|
|
134
150
|
model = View
|
|
@@ -164,7 +180,7 @@ class ViewImportForm(ViewPrefixUpdateMixin, NetBoxModelImportForm):
|
|
|
164
180
|
def __init__(self, *args, **kwargs):
|
|
165
181
|
super().__init__(*args, **kwargs)
|
|
166
182
|
|
|
167
|
-
if settings.PLUGINS_CONFIG["netbox_dns"].get("
|
|
183
|
+
if settings.PLUGINS_CONFIG["netbox_dns"].get("dnssync_disabled"):
|
|
168
184
|
del self.fields["prefixes"]
|
|
169
185
|
|
|
170
186
|
prefixes = CSVModelMultipleChoiceField(
|
|
@@ -201,3 +217,74 @@ class ViewBulkEditForm(NetBoxModelBulkEditForm):
|
|
|
201
217
|
)
|
|
202
218
|
|
|
203
219
|
nullable_fields = ("description", "tenant")
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
class ViewPrefixEditForm(forms.ModelForm):
|
|
223
|
+
views = DynamicModelMultipleChoiceField(
|
|
224
|
+
queryset=View.objects.all(),
|
|
225
|
+
required=False,
|
|
226
|
+
label="Assigned DNS Views",
|
|
227
|
+
help_text="Explicitly assigning DNS views overrides all inherited views for this prefix",
|
|
228
|
+
)
|
|
229
|
+
|
|
230
|
+
class Meta:
|
|
231
|
+
model = Prefix
|
|
232
|
+
fields = ("views",)
|
|
233
|
+
|
|
234
|
+
def __init__(self, *args, **kwargs):
|
|
235
|
+
super().__init__(*args, **kwargs)
|
|
236
|
+
|
|
237
|
+
self.initial["views"] = self.instance.netbox_dns_views.all()
|
|
238
|
+
self._permission_denied = False
|
|
239
|
+
|
|
240
|
+
if request := current_request.get():
|
|
241
|
+
if not request.user.has_perm("netbox_dns.change_view"):
|
|
242
|
+
self._permission_denied = True
|
|
243
|
+
self.initial["views"] = []
|
|
244
|
+
self.fields["views"].disabled = True
|
|
245
|
+
self.fields["views"].widget.attrs[
|
|
246
|
+
"placeholder"
|
|
247
|
+
] = "You do not have permission to modify assigned views"
|
|
248
|
+
|
|
249
|
+
def clean(self, *args, **kwargs):
|
|
250
|
+
if self._permission_denied:
|
|
251
|
+
return
|
|
252
|
+
|
|
253
|
+
prefix = self.instance
|
|
254
|
+
|
|
255
|
+
super().clean(*args, **kwargs)
|
|
256
|
+
|
|
257
|
+
views = self.cleaned_data.get("views")
|
|
258
|
+
old_views = prefix.netbox_dns_views.all()
|
|
259
|
+
|
|
260
|
+
check_views = View.objects.none()
|
|
261
|
+
|
|
262
|
+
if not views.exists():
|
|
263
|
+
if (parent := prefix.get_parents().last()) is not None:
|
|
264
|
+
check_views = parent.netbox_dns_views.all().difference(old_views)
|
|
265
|
+
|
|
266
|
+
else:
|
|
267
|
+
check_views = views.difference(old_views)
|
|
268
|
+
|
|
269
|
+
for view in check_views:
|
|
270
|
+
try:
|
|
271
|
+
for ip_address in get_ip_addresses_by_prefix(prefix, check_view=False):
|
|
272
|
+
check_dns_records(ip_address, view=view)
|
|
273
|
+
except ValidationError as exc:
|
|
274
|
+
self.add_error("views", exc.messages)
|
|
275
|
+
|
|
276
|
+
def save(self, *args, **kwargs):
|
|
277
|
+
prefix = self.instance
|
|
278
|
+
|
|
279
|
+
if self._permission_denied:
|
|
280
|
+
return prefix
|
|
281
|
+
|
|
282
|
+
old_views = prefix.netbox_dns_views.all()
|
|
283
|
+
views = self.cleaned_data.get("views")
|
|
284
|
+
|
|
285
|
+
for view in views.difference(old_views):
|
|
286
|
+
view.prefixes.add(prefix)
|
|
287
|
+
for view in old_views.difference(views):
|
|
288
|
+
view.prefixes.remove(prefix)
|
|
289
|
+
|
|
290
|
+
return prefix
|
|
@@ -81,6 +81,14 @@ class ZoneTemplateUpdateMixin:
|
|
|
81
81
|
else:
|
|
82
82
|
zone_data = self.cleaned_data.copy()
|
|
83
83
|
|
|
84
|
+
custom_fields = {}
|
|
85
|
+
for key, value in zone_data.copy().items():
|
|
86
|
+
if key.startswith("cf_"):
|
|
87
|
+
custom_fields[key[3:]] = value
|
|
88
|
+
zone_data.pop(key)
|
|
89
|
+
if custom_fields:
|
|
90
|
+
zone_data["custom_field_data"] = custom_fields
|
|
91
|
+
|
|
84
92
|
zone_data.pop("template", None)
|
|
85
93
|
zone_data.pop("tenant_group", None)
|
|
86
94
|
zone_data.pop("_init_time", None)
|
|
@@ -97,10 +105,7 @@ class ZoneTemplateUpdateMixin:
|
|
|
97
105
|
raise RollbackTransaction
|
|
98
106
|
|
|
99
107
|
except ValidationError as exc:
|
|
100
|
-
|
|
101
|
-
template_error = item.value()
|
|
102
|
-
else:
|
|
103
|
-
template_error = [exc]
|
|
108
|
+
self.add_error("template", exc.messages)
|
|
104
109
|
except RollbackTransaction:
|
|
105
110
|
pass
|
|
106
111
|
|
|
@@ -4,6 +4,8 @@ import strawberry
|
|
|
4
4
|
import strawberry_django
|
|
5
5
|
|
|
6
6
|
from netbox.graphql.types import NetBoxObjectType
|
|
7
|
+
from tenancy.graphql.types import TenantType
|
|
8
|
+
from ipam.graphql.types import IPAddressType, PrefixType
|
|
7
9
|
from netbox.graphql.scalars import BigInt
|
|
8
10
|
|
|
9
11
|
from netbox_dns.models import (
|
|
@@ -7,7 +7,7 @@ from ipam.models import IPAddress
|
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
class Command(BaseCommand):
|
|
10
|
-
help = "Setup IPAddress custom fields for IPAM
|
|
10
|
+
help = "Setup IPAddress custom fields for IPAM DNSsync"
|
|
11
11
|
|
|
12
12
|
def add_arguments(self, parser):
|
|
13
13
|
parser.add_argument(
|
|
@@ -19,7 +19,7 @@ class Command(BaseCommand):
|
|
|
19
19
|
|
|
20
20
|
if options.get("remove"):
|
|
21
21
|
if options.get("verbosity"):
|
|
22
|
-
self.stdout.write(
|
|
22
|
+
self.stdout.write("Trying to remove IPAM DNSsync custom fields")
|
|
23
23
|
for cf in (
|
|
24
24
|
"ipaddress_dns_disabled",
|
|
25
25
|
"ipaddress_dns_record_ttl",
|
|
@@ -30,7 +30,7 @@ class Command(BaseCommand):
|
|
|
30
30
|
name=cf, object_types=ipaddress_object_type
|
|
31
31
|
).delete()
|
|
32
32
|
if options.get("verbosity"):
|
|
33
|
-
self.stdout.write(f"
|
|
33
|
+
self.stdout.write(f"Removed custom field '{cf}'")
|
|
34
34
|
except CustomField.DoesNotExist:
|
|
35
35
|
pass
|
|
36
36
|
return
|
|
@@ -39,7 +39,7 @@ class Command(BaseCommand):
|
|
|
39
39
|
# Remove pre-existing IPAM Coupling custom fields
|
|
40
40
|
# -
|
|
41
41
|
if options.get("verbosity") >= 2:
|
|
42
|
-
self.stdout.write(
|
|
42
|
+
self.stdout.write("Trying to remove obsolete IPAM Coupling custom fields")
|
|
43
43
|
for cf in (
|
|
44
44
|
"ipaddress_dns_record_name",
|
|
45
45
|
"ipaddress_dns_zone_id",
|
|
@@ -54,25 +54,25 @@ class Command(BaseCommand):
|
|
|
54
54
|
pass
|
|
55
55
|
|
|
56
56
|
if options.get("verbosity") >= 2:
|
|
57
|
-
self.stdout.write(
|
|
57
|
+
self.stdout.write("Creating IPAM DNSsync custom fields")
|
|
58
58
|
|
|
59
59
|
if not CustomField.objects.filter(
|
|
60
60
|
name="ipaddress_dns_disabled",
|
|
61
61
|
type=CustomFieldTypeChoices.TYPE_BOOLEAN,
|
|
62
62
|
object_types=ipaddress_object_type,
|
|
63
63
|
).exists():
|
|
64
|
-
|
|
64
|
+
cf_dnssync_disabled = CustomField.objects.create(
|
|
65
65
|
name="ipaddress_dns_disabled",
|
|
66
|
-
label="Disable
|
|
66
|
+
label="Disable DNSsync",
|
|
67
67
|
description="Disable DNS address and pointer record generation for this address",
|
|
68
68
|
type=CustomFieldTypeChoices.TYPE_BOOLEAN,
|
|
69
69
|
required=False,
|
|
70
70
|
default=False,
|
|
71
|
-
group_name="
|
|
71
|
+
group_name="DNSsync",
|
|
72
72
|
is_cloneable=True,
|
|
73
73
|
weight=100,
|
|
74
74
|
)
|
|
75
|
-
|
|
75
|
+
cf_dnssync_disabled.object_types.set([ipaddress_object_type])
|
|
76
76
|
if options.get("verbosity"):
|
|
77
77
|
self.stdout.write("Created custom field 'ipaddress_dns_disabled'")
|
|
78
78
|
|
|
@@ -82,8 +82,9 @@ class Command(BaseCommand):
|
|
|
82
82
|
type=CustomFieldTypeChoices.TYPE_INTEGER,
|
|
83
83
|
object_types=ipaddress_object_type,
|
|
84
84
|
)
|
|
85
|
-
if cf_ttl.group_name != "
|
|
86
|
-
cf_ttl.group_name = "
|
|
85
|
+
if cf_ttl.group_name != "DNSsync":
|
|
86
|
+
cf_ttl.group_name = "DNSsync"
|
|
87
|
+
cf_ttl.description = ("TTL for DNS records created for this address",)
|
|
87
88
|
cf_ttl.save()
|
|
88
89
|
if options.get("verbosity"):
|
|
89
90
|
self.stdout.write("Updated custom field 'ipaddress_dns_record_ttl'")
|
|
@@ -96,7 +97,7 @@ class Command(BaseCommand):
|
|
|
96
97
|
validation_minimum=0,
|
|
97
98
|
validation_maximum=2147483647,
|
|
98
99
|
required=False,
|
|
99
|
-
group_name="
|
|
100
|
+
group_name="DNSsync",
|
|
100
101
|
is_cloneable=True,
|
|
101
102
|
weight=200,
|
|
102
103
|
)
|
|
@@ -110,8 +111,11 @@ class Command(BaseCommand):
|
|
|
110
111
|
type=CustomFieldTypeChoices.TYPE_BOOLEAN,
|
|
111
112
|
object_types=ipaddress_object_type,
|
|
112
113
|
)
|
|
113
|
-
if cf_disable_ptr.group_name != "
|
|
114
|
-
cf_disable_ptr.group_name = "
|
|
114
|
+
if cf_disable_ptr.group_name != "DNSsync":
|
|
115
|
+
cf_disable_ptr.group_name = "DNSsync"
|
|
116
|
+
cf_disable_ptr.description = (
|
|
117
|
+
"Disable DNS PTR record generation for this address",
|
|
118
|
+
)
|
|
115
119
|
cf_disable_ptr.save()
|
|
116
120
|
if options.get("verbosity"):
|
|
117
121
|
self.stdout.write(
|
|
@@ -125,7 +129,7 @@ class Command(BaseCommand):
|
|
|
125
129
|
type=CustomFieldTypeChoices.TYPE_BOOLEAN,
|
|
126
130
|
required=False,
|
|
127
131
|
default=False,
|
|
128
|
-
group_name="
|
|
132
|
+
group_name="DNSsync",
|
|
129
133
|
is_cloneable=True,
|
|
130
134
|
weight=300,
|
|
131
135
|
)
|
|
@@ -58,7 +58,7 @@ def record_data_from_ip_address(ip_address, zone):
|
|
|
58
58
|
RecordStatusChoices.STATUS_ACTIVE
|
|
59
59
|
if ip_address.status
|
|
60
60
|
in settings.PLUGINS_CONFIG["netbox_dns"].get(
|
|
61
|
-
"
|
|
61
|
+
"dnssync_ipaddress_active_status", []
|
|
62
62
|
)
|
|
63
63
|
else RecordStatusChoices.STATUS_INACTIVE
|
|
64
64
|
),
|
|
@@ -461,8 +461,11 @@ class Record(ObjectModificationMixin, NetBoxModel):
|
|
|
461
461
|
self.rfc2317_cname_record.delete(save_zone_serial=save_zone_serial)
|
|
462
462
|
self.rfc2317_cname_record = None
|
|
463
463
|
|
|
464
|
-
def update_from_ip_address(self, ip_address):
|
|
465
|
-
|
|
464
|
+
def update_from_ip_address(self, ip_address, zone=None):
|
|
465
|
+
if zone is None:
|
|
466
|
+
zone = self.zone
|
|
467
|
+
|
|
468
|
+
data = record_data_from_ip_address(ip_address, zone)
|
|
466
469
|
|
|
467
470
|
if data is None:
|
|
468
471
|
self.delete()
|
|
@@ -490,9 +493,12 @@ class Record(ObjectModificationMixin, NetBoxModel):
|
|
|
490
493
|
**data,
|
|
491
494
|
)
|
|
492
495
|
|
|
493
|
-
def validate_name(self):
|
|
496
|
+
def validate_name(self, new_zone=None):
|
|
497
|
+
if new_zone is None:
|
|
498
|
+
new_zone = self.zone
|
|
499
|
+
|
|
494
500
|
try:
|
|
495
|
-
_zone = dns_name.from_text(
|
|
501
|
+
_zone = dns_name.from_text(new_zone.name, origin=dns_name.root)
|
|
496
502
|
name = dns_name.from_text(self.name, origin=None)
|
|
497
503
|
fqdn = dns_name.from_text(self.name, origin=_zone)
|
|
498
504
|
|
|
@@ -512,7 +518,7 @@ class Record(ObjectModificationMixin, NetBoxModel):
|
|
|
512
518
|
if not fqdn.is_subdomain(_zone):
|
|
513
519
|
raise ValidationError(
|
|
514
520
|
{
|
|
515
|
-
"name": f"{self.name} is not a name in {
|
|
521
|
+
"name": f"{self.name} is not a name in {new_zone.name}",
|
|
516
522
|
}
|
|
517
523
|
)
|
|
518
524
|
|
|
@@ -544,15 +550,18 @@ class Record(ObjectModificationMixin, NetBoxModel):
|
|
|
544
550
|
except ValidationError as exc:
|
|
545
551
|
raise ValidationError({"value": exc}) from None
|
|
546
552
|
|
|
547
|
-
def check_unique_record(self):
|
|
553
|
+
def check_unique_record(self, new_zone=None):
|
|
548
554
|
if not get_plugin_config("netbox_dns", "enforce_unique_records", False):
|
|
549
555
|
return
|
|
550
556
|
|
|
551
557
|
if not self.is_active:
|
|
552
558
|
return
|
|
553
559
|
|
|
560
|
+
if new_zone is None:
|
|
561
|
+
new_zone = self.zone
|
|
562
|
+
|
|
554
563
|
records = Record.objects.filter(
|
|
555
|
-
zone=
|
|
564
|
+
zone=new_zone,
|
|
556
565
|
name=self.name,
|
|
557
566
|
type=self.type,
|
|
558
567
|
value=self.value,
|
|
@@ -567,7 +576,7 @@ class Record(ObjectModificationMixin, NetBoxModel):
|
|
|
567
576
|
if not records.filter(
|
|
568
577
|
ipam_ip_address__isnull=True
|
|
569
578
|
).exists() or get_plugin_config(
|
|
570
|
-
"netbox_dns", "
|
|
579
|
+
"netbox_dns", "dnssync_conflict_deactivate", False
|
|
571
580
|
):
|
|
572
581
|
return
|
|
573
582
|
|
|
@@ -581,7 +590,7 @@ class Record(ObjectModificationMixin, NetBoxModel):
|
|
|
581
590
|
if self.ipam_ip_address is None or not self.is_active:
|
|
582
591
|
return
|
|
583
592
|
|
|
584
|
-
if not get_plugin_config("netbox_dns", "
|
|
593
|
+
if not get_plugin_config("netbox_dns", "dnssync_conflict_deactivate", False):
|
|
585
594
|
return
|
|
586
595
|
|
|
587
596
|
records = Record.objects.filter(
|
|
@@ -624,7 +633,7 @@ class Record(ObjectModificationMixin, NetBoxModel):
|
|
|
624
633
|
if not records.exists():
|
|
625
634
|
return
|
|
626
635
|
|
|
627
|
-
conflicting_ttls = ", ".join(
|
|
636
|
+
conflicting_ttls = ", ".join({str(record.ttl) for record in records})
|
|
628
637
|
raise ValidationError(
|
|
629
638
|
{
|
|
630
639
|
"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})."
|
|
@@ -664,10 +673,10 @@ class Record(ObjectModificationMixin, NetBoxModel):
|
|
|
664
673
|
self.type = self.type.upper()
|
|
665
674
|
super().clean_fields(*args, **kwargs)
|
|
666
675
|
|
|
667
|
-
def clean(self, *args, **kwargs):
|
|
668
|
-
self.validate_name()
|
|
676
|
+
def clean(self, *args, new_zone=None, **kwargs):
|
|
677
|
+
self.validate_name(new_zone=new_zone)
|
|
669
678
|
self.validate_value()
|
|
670
|
-
self.check_unique_record()
|
|
679
|
+
self.check_unique_record(new_zone=new_zone)
|
|
671
680
|
if self.pk is None:
|
|
672
681
|
self.check_unique_rrset_ttl()
|
|
673
682
|
|
|
@@ -654,13 +654,18 @@ class Zone(ObjectModificationMixin, NetBoxModel):
|
|
|
654
654
|
)
|
|
655
655
|
|
|
656
656
|
if old_zone.name != self.name or old_zone.view != self.view:
|
|
657
|
-
|
|
658
|
-
|
|
657
|
+
for ip_address in get_ip_addresses_by_zone(self):
|
|
658
|
+
try:
|
|
659
|
+
check_dns_records(ip_address, zone=self)
|
|
660
|
+
except ValidationError as exc:
|
|
661
|
+
raise ValidationError(exc.messages)
|
|
662
|
+
|
|
663
|
+
ip_addresses = IPAddress.objects.filter(
|
|
664
|
+
netbox_dns_records__in=self.record_set.filter(
|
|
659
665
|
ipam_ip_address__isnull=False
|
|
660
|
-
)
|
|
666
|
+
)
|
|
661
667
|
)
|
|
662
|
-
|
|
663
|
-
for ip_address in update_ip_addresses:
|
|
668
|
+
for ip_address in ip_addresses:
|
|
664
669
|
try:
|
|
665
670
|
check_dns_records(ip_address, zone=self)
|
|
666
671
|
except ValidationError as exc:
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
from netaddr import IPNetwork
|
|
2
2
|
|
|
3
|
+
from django.conf import settings
|
|
3
4
|
from django.dispatch import receiver
|
|
4
5
|
from django.db.models.signals import pre_delete, pre_save, post_save, m2m_changed
|
|
5
6
|
from django.core.exceptions import ValidationError
|
|
@@ -17,21 +18,55 @@ from netbox_dns.utilities import (
|
|
|
17
18
|
delete_dns_records,
|
|
18
19
|
get_views_by_prefix,
|
|
19
20
|
get_ip_addresses_by_prefix,
|
|
20
|
-
get_ip_addresses_by_view,
|
|
21
21
|
)
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
DNSSYNC_CUSTOM_FIELDS = {
|
|
24
24
|
"ipaddress_dns_disabled": False,
|
|
25
25
|
"ipaddress_dns_record_ttl": None,
|
|
26
26
|
"ipaddress_dns_record_disable_ptr": False,
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
+
IPADDRESS_ACTIVE_STATUS = settings.PLUGINS_CONFIG["netbox_dns"][
|
|
30
|
+
"dnssync_ipaddress_active_status"
|
|
31
|
+
]
|
|
32
|
+
ENFORCE_UNIQUE_RECORDS = settings.PLUGINS_CONFIG["netbox_dns"]["enforce_unique_records"]
|
|
33
|
+
|
|
29
34
|
|
|
30
35
|
@receiver(post_clean, sender=IPAddress)
|
|
31
|
-
def
|
|
36
|
+
def ipam_dnssync_ipaddress_post_clean(instance, **kwargs):
|
|
32
37
|
if not isinstance(instance.address, IPNetwork):
|
|
33
38
|
return
|
|
34
39
|
|
|
40
|
+
if instance.custom_field_data.get("ipaddress_dns_disabled"):
|
|
41
|
+
return
|
|
42
|
+
|
|
43
|
+
# +
|
|
44
|
+
# Check for uniqueness of IP address and dns_name. If unique records are
|
|
45
|
+
# enforced, report an error when trying to create the same IP address with
|
|
46
|
+
# the same dns_name. Ignore existing IP addresses that have their CF
|
|
47
|
+
# "ipaddress_dns_disabled" set to "True".
|
|
48
|
+
# -
|
|
49
|
+
duplicate_addresses = IPAddress.objects.filter(
|
|
50
|
+
address=instance.address,
|
|
51
|
+
vrf=instance.vrf,
|
|
52
|
+
dns_name=instance.dns_name,
|
|
53
|
+
status__in=IPADDRESS_ACTIVE_STATUS,
|
|
54
|
+
)
|
|
55
|
+
if instance.pk is not None:
|
|
56
|
+
duplicate_addresses = duplicate_addresses.exclude(pk=instance.pk)
|
|
57
|
+
|
|
58
|
+
if ENFORCE_UNIQUE_RECORDS and instance.status in IPADDRESS_ACTIVE_STATUS:
|
|
59
|
+
for ip_address in duplicate_addresses.only("custom_field_data"):
|
|
60
|
+
if not ip_address.custom_field_data.get("ipaddress_dns_disabled"):
|
|
61
|
+
raise ValidationError(
|
|
62
|
+
{
|
|
63
|
+
"dns_name": "Unique DNS records are enforced and there is already "
|
|
64
|
+
f"an active IP address {instance.address} with DNS name {instance.dns_name}. "
|
|
65
|
+
"Plesase choose a different name or disable record creation for this "
|
|
66
|
+
"IP address."
|
|
67
|
+
}
|
|
68
|
+
)
|
|
69
|
+
|
|
35
70
|
# +
|
|
36
71
|
# Check NetBox DNS record permission for changes to IPAddress custom fields
|
|
37
72
|
#
|
|
@@ -42,24 +77,26 @@ def ipam_autodns_ipaddress_post_clean(instance, **kwargs):
|
|
|
42
77
|
instance.pk is not None
|
|
43
78
|
and any(
|
|
44
79
|
(
|
|
45
|
-
cf_data.get(cf)
|
|
46
|
-
!= IPAddress.objects.get(pk=instance.pk).custom_field_data.get(
|
|
47
|
-
|
|
80
|
+
cf_data.get(cf, cf_default)
|
|
81
|
+
!= IPAddress.objects.get(pk=instance.pk).custom_field_data.get(
|
|
82
|
+
cf, cf_default
|
|
83
|
+
)
|
|
84
|
+
for cf, cf_default in DNSSYNC_CUSTOM_FIELDS.items()
|
|
48
85
|
)
|
|
49
86
|
)
|
|
50
|
-
and not check_record_permission(
|
|
87
|
+
and not check_record_permission()
|
|
51
88
|
) or (
|
|
52
89
|
instance.pk is None
|
|
53
90
|
and any(
|
|
54
91
|
(
|
|
55
|
-
cf_data.get(cf) != cf_default
|
|
56
|
-
for cf, cf_default in
|
|
92
|
+
cf_data.get(cf, cf_default) != cf_default
|
|
93
|
+
for cf, cf_default in DNSSYNC_CUSTOM_FIELDS.items()
|
|
57
94
|
)
|
|
58
95
|
)
|
|
59
|
-
and not check_record_permission(
|
|
96
|
+
and not check_record_permission(change=False, delete=False)
|
|
60
97
|
):
|
|
61
98
|
raise ValidationError(
|
|
62
|
-
f"User '{request.user}' is not allowed to alter
|
|
99
|
+
f"User '{request.user}' is not allowed to alter DNSsync custom fields"
|
|
63
100
|
)
|
|
64
101
|
|
|
65
102
|
try:
|
|
@@ -69,38 +106,51 @@ def ipam_autodns_ipaddress_post_clean(instance, **kwargs):
|
|
|
69
106
|
|
|
70
107
|
|
|
71
108
|
@receiver(pre_delete, sender=IPAddress)
|
|
72
|
-
def
|
|
109
|
+
def ipam_dnssync_ipaddress_pre_delete(instance, **kwargs):
|
|
73
110
|
delete_dns_records(instance)
|
|
74
111
|
|
|
75
112
|
|
|
76
113
|
@receiver(pre_save, sender=IPAddress)
|
|
77
|
-
def
|
|
114
|
+
def ipam_dnssync_ipaddress_pre_save(instance, **kwargs):
|
|
78
115
|
check_dns_records(instance)
|
|
79
116
|
|
|
80
117
|
|
|
81
118
|
@receiver(post_save, sender=IPAddress)
|
|
82
|
-
def
|
|
119
|
+
def ipam_dnssync_ipaddress_post_save(instance, **kwargs):
|
|
83
120
|
update_dns_records(instance)
|
|
84
121
|
|
|
85
122
|
|
|
86
123
|
@receiver(pre_save, sender=Prefix)
|
|
87
|
-
def
|
|
124
|
+
def ipam_dnssync_prefix_pre_save(instance, **kwargs):
|
|
88
125
|
"""
|
|
89
126
|
Changes that modify the prefix hierarchy cannot be validated properly before
|
|
90
|
-
commiting them. So the solution in this case is to
|
|
91
|
-
|
|
127
|
+
commiting them. So the solution in this case is to ask the user to deassign
|
|
128
|
+
the prefix from any views it is assigned to and retry.
|
|
92
129
|
"""
|
|
130
|
+
request = current_request.get()
|
|
131
|
+
|
|
93
132
|
if instance.pk is None or not instance.netbox_dns_views.exists():
|
|
94
133
|
return
|
|
95
134
|
|
|
96
|
-
saved_prefix = Prefix.objects.get(
|
|
135
|
+
saved_prefix = Prefix.objects.prefetch_related("netbox_dns_views").get(
|
|
136
|
+
pk=instance.pk
|
|
137
|
+
)
|
|
97
138
|
if saved_prefix.prefix != instance.prefix or saved_prefix.vrf != instance.vrf:
|
|
98
|
-
for view in
|
|
99
|
-
|
|
139
|
+
dns_views = ", ".join([view.name for view in instance.netbox_dns_views.all()])
|
|
140
|
+
if request is not None:
|
|
141
|
+
raise AbortRequest(
|
|
142
|
+
f"This prefix is currently assigned to the following DNS views: {dns_views}"
|
|
143
|
+
f"Please deassign it from these views before making changes to the prefix "
|
|
144
|
+
f"or VRF."
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
raise ValidationError(
|
|
148
|
+
f"Prefix is assigned to DNS views {dns_views}. Prefix and VRF must not be changed"
|
|
149
|
+
)
|
|
100
150
|
|
|
101
151
|
|
|
102
152
|
@receiver(pre_delete, sender=Prefix)
|
|
103
|
-
def
|
|
153
|
+
def ipam_dnssync_prefix_pre_delete(instance, **kwargs):
|
|
104
154
|
parent = instance.get_parents().last()
|
|
105
155
|
request = current_request.get()
|
|
106
156
|
|
|
@@ -144,7 +194,7 @@ def ipam_autodns_prefix_pre_delete(instance, **kwargs):
|
|
|
144
194
|
|
|
145
195
|
|
|
146
196
|
@receiver(m2m_changed, sender=_view.View.prefixes.through)
|
|
147
|
-
def
|
|
197
|
+
def ipam_dnssync_view_prefix_changed(**kwargs):
|
|
148
198
|
action = kwargs.get("action")
|
|
149
199
|
request = current_request.get()
|
|
150
200
|
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import django_tables2 as tables
|
|
2
|
+
|
|
3
|
+
from ipam.tables import PrefixTable
|
|
4
|
+
from utilities.tables import register_table_column
|
|
5
|
+
|
|
6
|
+
views = tables.ManyToManyColumn(
|
|
7
|
+
verbose_name="DNS Views",
|
|
8
|
+
linkify_item=True,
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
register_table_column(views, "netbox_dns_views", PrefixTable)
|