netbox-plugin-dns 0.21.4__py3-none-any.whl → 1.4.7__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.
- netbox_dns/__init__.py +106 -41
- netbox_dns/api/field_serializers.py +25 -0
- netbox_dns/api/nested_serializers.py +95 -52
- netbox_dns/api/serializers.py +14 -296
- netbox_dns/api/serializers_/__init__.py +0 -0
- netbox_dns/api/serializers_/dnssec_key_template.py +69 -0
- netbox_dns/api/serializers_/dnssec_policy.py +165 -0
- netbox_dns/api/serializers_/nameserver.py +56 -0
- netbox_dns/api/serializers_/prefix.py +18 -0
- netbox_dns/api/serializers_/record.py +105 -0
- netbox_dns/api/serializers_/record_template.py +71 -0
- netbox_dns/api/serializers_/registrar.py +45 -0
- netbox_dns/api/serializers_/registration_contact.py +50 -0
- netbox_dns/api/serializers_/view.py +81 -0
- netbox_dns/api/serializers_/zone.py +247 -0
- netbox_dns/api/serializers_/zone_template.py +157 -0
- netbox_dns/api/urls.py +13 -2
- netbox_dns/api/views.py +96 -58
- netbox_dns/choices/__init__.py +4 -0
- netbox_dns/choices/dnssec_key_template.py +67 -0
- netbox_dns/choices/dnssec_policy.py +40 -0
- netbox_dns/choices/record.py +104 -0
- netbox_dns/choices/utilities.py +4 -0
- netbox_dns/choices/zone.py +119 -0
- netbox_dns/fields/__init__.py +4 -0
- netbox_dns/fields/address.py +22 -16
- netbox_dns/fields/choice_array.py +33 -0
- netbox_dns/fields/ipam.py +15 -0
- netbox_dns/fields/network.py +42 -18
- netbox_dns/fields/rfc2317.py +97 -0
- netbox_dns/fields/timeperiod.py +33 -0
- netbox_dns/filters.py +7 -0
- netbox_dns/filtersets/__init__.py +12 -0
- netbox_dns/filtersets/dnssec_key_template.py +57 -0
- netbox_dns/filtersets/dnssec_policy.py +101 -0
- netbox_dns/filtersets/nameserver.py +46 -0
- netbox_dns/filtersets/record.py +135 -0
- netbox_dns/filtersets/record_template.py +59 -0
- netbox_dns/{filters → filtersets}/registrar.py +8 -1
- netbox_dns/{filters/contact.py → filtersets/registration_contact.py} +9 -3
- netbox_dns/filtersets/view.py +45 -0
- netbox_dns/filtersets/zone.py +254 -0
- netbox_dns/filtersets/zone_template.py +165 -0
- netbox_dns/forms/__init__.py +5 -1
- netbox_dns/forms/dnssec_key_template.py +250 -0
- netbox_dns/forms/dnssec_policy.py +654 -0
- netbox_dns/forms/nameserver.py +121 -27
- netbox_dns/forms/record.py +215 -104
- netbox_dns/forms/record_template.py +285 -0
- netbox_dns/forms/registrar.py +108 -31
- netbox_dns/forms/registration_contact.py +282 -0
- netbox_dns/forms/view.py +331 -20
- netbox_dns/forms/zone.py +769 -373
- netbox_dns/forms/zone_template.py +463 -0
- netbox_dns/graphql/__init__.py +25 -22
- netbox_dns/graphql/enums.py +41 -0
- netbox_dns/graphql/filter_lookups.py +13 -0
- netbox_dns/graphql/filters/__init__.py +12 -0
- netbox_dns/graphql/filters/dnssec_key_template.py +63 -0
- netbox_dns/graphql/filters/dnssec_policy.py +124 -0
- netbox_dns/graphql/filters/nameserver.py +32 -0
- netbox_dns/graphql/filters/record.py +89 -0
- netbox_dns/graphql/filters/record_template.py +55 -0
- netbox_dns/graphql/filters/registrar.py +30 -0
- netbox_dns/graphql/filters/registration_contact.py +27 -0
- netbox_dns/graphql/filters/view.py +28 -0
- netbox_dns/graphql/filters/zone.py +147 -0
- netbox_dns/graphql/filters/zone_template.py +97 -0
- netbox_dns/graphql/schema.py +89 -7
- netbox_dns/graphql/types.py +355 -0
- netbox_dns/locale/de/LC_MESSAGES/django.mo +0 -0
- netbox_dns/locale/en/LC_MESSAGES/django.mo +0 -0
- netbox_dns/locale/fr/LC_MESSAGES/django.mo +0 -0
- netbox_dns/management/commands/cleanup_database.py +175 -156
- netbox_dns/management/commands/cleanup_rrset_ttl.py +64 -0
- netbox_dns/management/commands/rebuild_dnssync.py +23 -0
- netbox_dns/management/commands/setup_dnssync.py +140 -0
- netbox_dns/migrations/0001_squashed_netbox_dns_0_15.py +0 -27
- netbox_dns/migrations/0001_squashed_netbox_dns_0_22.py +557 -0
- netbox_dns/migrations/{0013_add_nameserver_zone_record_description.py → 0002_contact_description_registrar_description.py} +4 -9
- netbox_dns/migrations/0003_default_view.py +15 -0
- netbox_dns/migrations/0004_create_and_assign_default_view.py +26 -0
- netbox_dns/migrations/0005_alter_zone_view_not_null.py +18 -0
- netbox_dns/migrations/0006_templating.py +172 -0
- netbox_dns/migrations/0007_alter_ordering_options.py +25 -0
- netbox_dns/migrations/0008_view_prefixes.py +18 -0
- netbox_dns/migrations/0009_rename_contact_registrationcontact.py +36 -0
- netbox_dns/migrations/0010_view_ip_address_filter.py +18 -0
- netbox_dns/migrations/0011_rename_related_fields.py +63 -0
- netbox_dns/migrations/0012_natural_ordering.py +88 -0
- netbox_dns/migrations/0013_zonetemplate_soa_mname_zonetemplate_soa_rname.py +30 -0
- netbox_dns/migrations/0014_alter_unique_constraints_lowercase.py +42 -0
- netbox_dns/migrations/0015_dnssec.py +168 -0
- netbox_dns/migrations/{0015_add_record_status.py → 0016_dnssec_policy_status.py} +5 -4
- netbox_dns/migrations/0017_dnssec_policy_zone_zone_template.py +41 -0
- netbox_dns/migrations/0018_zone_domain_status_zone_expiration_date.py +23 -0
- netbox_dns/migrations/0019_dnssecpolicy_parental_agents.py +25 -0
- netbox_dns/migrations/0020_netbox_3_4.py +1 -1
- netbox_dns/migrations/0020_remove_dnssecpolicy_parental_agents_and_more.py +29 -0
- netbox_dns/migrations/0021_alter_record_ptr_record.py +25 -0
- netbox_dns/migrations/0021_record_ip_address.py +1 -1
- netbox_dns/migrations/0022_alter_record_ipam_ip_address.py +26 -0
- netbox_dns/migrations/0023_disable_ptr_false.py +27 -0
- netbox_dns/migrations/0024_zonetemplate_parental_agents.py +25 -0
- netbox_dns/migrations/0025_remove_zone_inline_signing_and_more.py +22 -0
- netbox_dns/migrations/0026_alter_dnssecpolicy_nsec3_opt_out.py +18 -0
- netbox_dns/migrations/0026_domain_registration.py +1 -1
- netbox_dns/migrations/0027_zone_comments.py +18 -0
- netbox_dns/migrations/0028_alter_zone_default_ttl_alter_zone_soa_minimum_and_more.py +54 -0
- netbox_dns/migrations/0028_rfc2317_fields.py +44 -0
- netbox_dns/migrations/0029_alter_registrationcontact_street.py +18 -0
- netbox_dns/migrations/0029_record_fqdn.py +30 -0
- netbox_dns/mixins/__init__.py +1 -0
- netbox_dns/mixins/object_modification.py +57 -0
- netbox_dns/models/__init__.py +5 -1
- netbox_dns/models/dnssec_key_template.py +114 -0
- netbox_dns/models/dnssec_policy.py +203 -0
- netbox_dns/models/nameserver.py +61 -30
- netbox_dns/models/record.py +781 -234
- netbox_dns/models/record_template.py +198 -0
- netbox_dns/models/registrar.py +34 -15
- netbox_dns/models/{contact.py → registration_contact.py} +72 -43
- netbox_dns/models/view.py +129 -9
- netbox_dns/models/zone.py +806 -242
- netbox_dns/models/zone_template.py +209 -0
- netbox_dns/navigation.py +176 -76
- netbox_dns/signals/__init__.py +0 -0
- netbox_dns/signals/dnssec.py +32 -0
- netbox_dns/signals/ipam_dnssync.py +216 -0
- netbox_dns/tables/__init__.py +5 -1
- netbox_dns/tables/dnssec_key_template.py +49 -0
- netbox_dns/tables/dnssec_policy.py +140 -0
- netbox_dns/tables/ipam_dnssync.py +12 -0
- netbox_dns/tables/nameserver.py +14 -17
- netbox_dns/tables/record.py +117 -59
- netbox_dns/tables/record_template.py +91 -0
- netbox_dns/tables/registrar.py +20 -10
- netbox_dns/tables/{contact.py → registration_contact.py} +22 -11
- netbox_dns/tables/view.py +47 -3
- netbox_dns/tables/zone.py +62 -31
- netbox_dns/tables/zone_template.py +78 -0
- netbox_dns/template_content.py +124 -38
- netbox_dns/templates/netbox_dns/dnsseckeytemplate.html +70 -0
- netbox_dns/templates/netbox_dns/dnssecpolicy.html +163 -0
- netbox_dns/templates/netbox_dns/nameserver.html +31 -28
- netbox_dns/templates/netbox_dns/record/managed.html +2 -1
- netbox_dns/templates/netbox_dns/record/related.html +17 -6
- netbox_dns/templates/netbox_dns/record.html +140 -93
- netbox_dns/templates/netbox_dns/recordtemplate.html +96 -0
- netbox_dns/templates/netbox_dns/registrar.html +41 -34
- netbox_dns/templates/netbox_dns/registrationcontact.html +76 -0
- netbox_dns/templates/netbox_dns/view/button.html +10 -0
- netbox_dns/templates/netbox_dns/view/prefix.html +44 -0
- netbox_dns/templates/netbox_dns/view/related.html +33 -0
- netbox_dns/templates/netbox_dns/view.html +62 -18
- netbox_dns/templates/netbox_dns/zone/base.html +6 -3
- netbox_dns/templates/netbox_dns/zone/child.html +6 -5
- netbox_dns/templates/netbox_dns/zone/child_zone.html +18 -0
- netbox_dns/templates/netbox_dns/zone/delegation_record.html +18 -0
- netbox_dns/templates/netbox_dns/zone/managed_record.html +1 -1
- netbox_dns/templates/netbox_dns/zone/record.html +6 -5
- netbox_dns/templates/netbox_dns/zone/registration.html +43 -24
- netbox_dns/templates/netbox_dns/zone/rfc2317_child_zone.html +18 -0
- netbox_dns/templates/netbox_dns/zone.html +178 -119
- netbox_dns/templates/netbox_dns/zonetemplate/child.html +46 -0
- netbox_dns/templates/netbox_dns/zonetemplate.html +124 -0
- netbox_dns/templatetags/netbox_dns.py +10 -0
- netbox_dns/urls.py +50 -210
- netbox_dns/utilities/__init__.py +3 -0
- netbox_dns/{utilities.py → utilities/conversions.py} +55 -7
- netbox_dns/utilities/dns.py +11 -0
- netbox_dns/utilities/ipam_dnssync.py +370 -0
- netbox_dns/validators/__init__.py +4 -0
- netbox_dns/validators/dns_name.py +116 -0
- netbox_dns/validators/dns_value.py +147 -0
- netbox_dns/validators/dnssec.py +148 -0
- netbox_dns/validators/rfc2317.py +28 -0
- netbox_dns/views/__init__.py +5 -1
- netbox_dns/views/dnssec_key_template.py +78 -0
- netbox_dns/views/dnssec_policy.py +146 -0
- netbox_dns/views/nameserver.py +34 -15
- netbox_dns/views/record.py +156 -15
- netbox_dns/views/record_template.py +93 -0
- netbox_dns/views/registrar.py +32 -13
- netbox_dns/views/registration_contact.py +101 -0
- netbox_dns/views/view.py +58 -14
- netbox_dns/views/zone.py +130 -33
- netbox_dns/views/zone_template.py +82 -0
- netbox_plugin_dns-1.4.7.dist-info/METADATA +132 -0
- netbox_plugin_dns-1.4.7.dist-info/RECORD +201 -0
- {netbox_plugin_dns-0.21.4.dist-info → netbox_plugin_dns-1.4.7.dist-info}/WHEEL +2 -1
- {netbox_plugin_dns-0.21.4.dist-info → netbox_plugin_dns-1.4.7.dist-info/licenses}/LICENSE +2 -1
- netbox_plugin_dns-1.4.7.dist-info/top_level.txt +1 -0
- netbox_dns/filters/__init__.py +0 -6
- netbox_dns/filters/nameserver.py +0 -18
- netbox_dns/filters/record.py +0 -53
- netbox_dns/filters/view.py +0 -18
- netbox_dns/filters/zone.py +0 -112
- netbox_dns/forms/contact.py +0 -211
- netbox_dns/graphql/contact.py +0 -19
- netbox_dns/graphql/nameserver.py +0 -19
- netbox_dns/graphql/record.py +0 -19
- netbox_dns/graphql/registrar.py +0 -19
- netbox_dns/graphql/view.py +0 -19
- netbox_dns/graphql/zone.py +0 -19
- netbox_dns/management/commands/setup_coupling.py +0 -75
- netbox_dns/management/commands/update_soa.py +0 -22
- netbox_dns/middleware.py +0 -226
- netbox_dns/migrations/0001_initial.py +0 -115
- netbox_dns/migrations/0002_zone_default_ttl.py +0 -18
- netbox_dns/migrations/0003_soa_managed_records.py +0 -112
- netbox_dns/migrations/0004_create_ptr_for_a_aaaa_records.py +0 -80
- netbox_dns/migrations/0005_update_ns_records.py +0 -41
- netbox_dns/migrations/0006_zone_soa_serial_auto.py +0 -29
- netbox_dns/migrations/0007_alter_zone_soa_serial_auto.py +0 -17
- netbox_dns/migrations/0008_zone_status_names.py +0 -21
- netbox_dns/migrations/0009_netbox32.py +0 -71
- netbox_dns/migrations/0010_update_soa_records.py +0 -58
- netbox_dns/migrations/0011_add_view_model.py +0 -70
- netbox_dns/migrations/0012_adjust_zone_and_record.py +0 -17
- netbox_dns/migrations/0014_add_view_description.py +0 -16
- netbox_dns/migrations/0016_cleanup_ptr_records.py +0 -38
- netbox_dns/migrations/0017_alter_record_ttl.py +0 -17
- netbox_dns/migrations/0018_zone_arpa_network.py +0 -51
- netbox_dns/migrations/0019_update_ns_ttl.py +0 -19
- netbox_dns/templates/netbox_dns/contact.html +0 -71
- netbox_dns/templates/netbox_dns/related_dns_objects.html +0 -21
- netbox_dns/templatetags/view_helpers.py +0 -15
- netbox_dns/validators.py +0 -57
- netbox_dns/views/contact.py +0 -83
- netbox_plugin_dns-0.21.4.dist-info/METADATA +0 -101
- netbox_plugin_dns-0.21.4.dist-info/RECORD +0 -110
|
@@ -1,186 +1,205 @@
|
|
|
1
|
-
import
|
|
2
|
-
from dns import rdtypes, rdata, rdatatype, rdataclass
|
|
3
|
-
|
|
4
|
-
from netaddr import IPAddress, IPNetwork, AddrFormatError
|
|
1
|
+
from netaddr import IPAddress
|
|
5
2
|
|
|
6
3
|
from django.core.management.base import BaseCommand
|
|
7
4
|
|
|
8
|
-
from netbox_dns.models import
|
|
9
|
-
|
|
10
|
-
ZoneStatusChoices,
|
|
11
|
-
Record,
|
|
12
|
-
RecordTypeChoices,
|
|
13
|
-
RecordClassChoices,
|
|
14
|
-
)
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
def zone_rename_passive_status_to_parked(verbose=False):
|
|
18
|
-
passive_zones = Zone.objects.filter(status="passive")
|
|
19
|
-
if passive_zones:
|
|
20
|
-
if verbose:
|
|
21
|
-
print("Renaming 'passive' zone status to 'parked'")
|
|
22
|
-
|
|
23
|
-
for zone in passive_zones:
|
|
24
|
-
zone.status = ZoneStatusChoices.STATUS_PARKED
|
|
25
|
-
zone.save()
|
|
26
|
-
|
|
5
|
+
from netbox_dns.models import Zone, Record
|
|
6
|
+
from netbox_dns.choices import RecordTypeChoices
|
|
27
7
|
|
|
28
|
-
def zone_cleanup_ns_records(verbose=False):
|
|
29
|
-
ns_name = "@"
|
|
30
8
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
nameserver_names = [f'{ns.name.rstrip(".")}.' for ns in nameservers]
|
|
34
|
-
|
|
35
|
-
delete_ns = zone.record_set.filter(
|
|
36
|
-
name=ns_name, type=RecordTypeChoices.NS
|
|
37
|
-
).exclude(value__in=nameserver_names)
|
|
38
|
-
for record in delete_ns:
|
|
39
|
-
if verbose:
|
|
40
|
-
print(f"Deleting obsolete NS record {record}")
|
|
41
|
-
record.delete()
|
|
42
|
-
|
|
43
|
-
for ns in nameserver_names:
|
|
44
|
-
ns_records = zone.record_set.filter(
|
|
45
|
-
name=ns_name,
|
|
46
|
-
type=RecordTypeChoices.NS,
|
|
47
|
-
value=ns,
|
|
48
|
-
)
|
|
9
|
+
class Command(BaseCommand):
|
|
10
|
+
help = "Clean up NetBox DNS database"
|
|
49
11
|
|
|
50
|
-
|
|
12
|
+
def handle(self, *model_names, **options):
|
|
13
|
+
self._zone_cleanup_ns_records(**options)
|
|
14
|
+
self._zone_cleanup_soa_records(**options)
|
|
15
|
+
self._zone_update_arpa_network(**options)
|
|
16
|
+
self._record_cleanup_disable_ptr(**options)
|
|
17
|
+
self._record_update_ptr_records(**options)
|
|
18
|
+
self._record_update_ip_address(**options)
|
|
19
|
+
self._record_remove_orphaned_ptr_records(**options)
|
|
20
|
+
self._record_remove_orphaned_address_records(**options)
|
|
21
|
+
|
|
22
|
+
if options.get("verbosity"):
|
|
23
|
+
self.stdout.write("Database cleanup completed.")
|
|
24
|
+
|
|
25
|
+
def _zone_cleanup_ns_records(self, **options):
|
|
26
|
+
if options.get("verbosity"):
|
|
27
|
+
self.stdout.write("Cleaning up the NS records for all zones")
|
|
28
|
+
|
|
29
|
+
ns_name = "@"
|
|
30
|
+
|
|
31
|
+
for zone in Zone.objects.all():
|
|
32
|
+
nameservers = zone.nameservers.all()
|
|
33
|
+
nameserver_names = [f'{ns.name.rstrip(".")}.' for ns in nameservers]
|
|
34
|
+
|
|
35
|
+
delete_ns = zone.records.filter(
|
|
36
|
+
name=ns_name, type=RecordTypeChoices.NS
|
|
37
|
+
).exclude(value__in=nameserver_names)
|
|
51
38
|
for record in delete_ns:
|
|
52
|
-
if
|
|
53
|
-
|
|
39
|
+
if options.get("verbosity") > 1:
|
|
40
|
+
self.stdout.write(
|
|
41
|
+
f"Removing obsolete NS record '{record}' with value '{record.value}'"
|
|
42
|
+
)
|
|
54
43
|
record.delete()
|
|
55
44
|
|
|
56
|
-
|
|
57
|
-
|
|
45
|
+
for ns in nameserver_names:
|
|
46
|
+
ns_records = zone.records.filter(
|
|
58
47
|
name=ns_name,
|
|
59
48
|
type=RecordTypeChoices.NS,
|
|
60
49
|
value=ns,
|
|
61
50
|
)
|
|
62
51
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
ttl
|
|
79
|
-
|
|
80
|
-
|
|
52
|
+
delete_ns = ns_records[1:]
|
|
53
|
+
for record in delete_ns:
|
|
54
|
+
if options.get("verbosity") > 1:
|
|
55
|
+
self.stdout.write(
|
|
56
|
+
f"Removing duplicate NS record '{record}' with value '{record.value}'"
|
|
57
|
+
)
|
|
58
|
+
record.delete()
|
|
59
|
+
|
|
60
|
+
try:
|
|
61
|
+
ns_record = zone.records.get(
|
|
62
|
+
name=ns_name,
|
|
63
|
+
type=RecordTypeChoices.NS,
|
|
64
|
+
value=ns,
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
if ns_record.ttl is not None or not ns_record.managed:
|
|
68
|
+
if options.get("verbosity") > 1:
|
|
69
|
+
self.stdout.write(
|
|
70
|
+
f"Updating NS record '{ns_record}' with value '{record.value}'"
|
|
71
|
+
)
|
|
72
|
+
ns_record.ttl = None
|
|
73
|
+
ns_record.managed = True
|
|
74
|
+
ns_record.save()
|
|
75
|
+
|
|
76
|
+
except Record.DoesNotExist:
|
|
77
|
+
if options.get("verbosity") > 1:
|
|
78
|
+
self.stdout.write(
|
|
79
|
+
f"Creating NS record for '{ns.rstrip('.')}' in zone '{zone}'"
|
|
80
|
+
)
|
|
81
|
+
Record.objects.create(
|
|
82
|
+
name=ns_name,
|
|
83
|
+
zone=zone,
|
|
84
|
+
type=RecordTypeChoices.NS,
|
|
85
|
+
value=ns,
|
|
86
|
+
ttl=None,
|
|
87
|
+
managed=True,
|
|
88
|
+
)
|
|
81
89
|
|
|
90
|
+
def _zone_cleanup_soa_records(self, **options):
|
|
91
|
+
if options.get("verbosity"):
|
|
92
|
+
self.stdout.write("Cleaning up the SOA record for all zones")
|
|
82
93
|
|
|
83
|
-
|
|
84
|
-
soa_name = "@"
|
|
94
|
+
soa_name = "@"
|
|
85
95
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
96
|
+
for zone in Zone.objects.all():
|
|
97
|
+
delete_soa = zone.records.filter(name=soa_name, type=RecordTypeChoices.SOA)[
|
|
98
|
+
1:
|
|
99
|
+
]
|
|
100
|
+
for record in delete_soa:
|
|
101
|
+
if options.get("verbosity") > 1:
|
|
102
|
+
self.stdout.write(
|
|
103
|
+
f"Deleting duplicate SOA record '{record}' for zone '{zone}'"
|
|
104
|
+
)
|
|
105
|
+
record.delete()
|
|
94
106
|
|
|
95
|
-
|
|
107
|
+
zone.update_soa_record()
|
|
96
108
|
|
|
109
|
+
def _zone_update_arpa_network(self, **options):
|
|
110
|
+
if options.get("verbosity"):
|
|
111
|
+
self.stdout.write("Updating the ARPA network for reverse zones")
|
|
97
112
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
113
|
+
for zone in Zone.objects.filter(name__endswith=".arpa"):
|
|
114
|
+
if zone.arpa_network != (arpa_network := zone.network_from_name):
|
|
115
|
+
if options.get("verbosity") > 1:
|
|
116
|
+
self.stdout.write(
|
|
117
|
+
f"Setting the ARPA network for zone '{zone}' to '{arpa_network}'"
|
|
118
|
+
)
|
|
101
119
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
address = ".".join(reversed(name.replace(".in-addr.arpa", "").split(".")))
|
|
105
|
-
mask = len(address.split(".")) * 8
|
|
120
|
+
zone.arpa_network = arpa_network
|
|
121
|
+
zone.save()
|
|
106
122
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
prefix = None
|
|
123
|
+
def _record_cleanup_disable_ptr(self, **options):
|
|
124
|
+
if options.get("verbosity"):
|
|
125
|
+
self.stdout.write("Updating 'Disable PTR' for non-address records")
|
|
111
126
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
address = address + "0" * (32 - mask)
|
|
127
|
+
records = Record.objects.filter(
|
|
128
|
+
disable_ptr=True,
|
|
129
|
+
).exclude(type__in=(RecordTypeChoices.A, RecordTypeChoices.AAAA))
|
|
116
130
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
131
|
+
for record in records:
|
|
132
|
+
if options.get("verbosity") > 1:
|
|
133
|
+
self.stdout.write(
|
|
134
|
+
f"Setting 'Disable PTR' to False for record '{record}'"
|
|
120
135
|
)
|
|
121
|
-
except AddrFormatError:
|
|
122
|
-
prefix = None
|
|
123
|
-
# TODO: End
|
|
124
|
-
|
|
125
|
-
if zone.arpa_network != prefix:
|
|
126
|
-
if verbose:
|
|
127
|
-
print(f"Updating ARPA prefix for zone '{zone}' to '{prefix}'")
|
|
128
|
-
zone.arpa_network = prefix
|
|
129
|
-
zone.save()
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
def record_cleanup_disable_ptr(verbose=False):
|
|
133
|
-
Record.objects.filter(
|
|
134
|
-
disable_ptr=False,
|
|
135
|
-
).exclude(
|
|
136
|
-
type__in=(RecordTypeChoices.A, RecordTypeChoices.AAAA)
|
|
137
|
-
).update(disable_ptr=True)
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
def record_update_ptr_records(verbose=False):
|
|
141
|
-
for record in Record.objects.filter(
|
|
142
|
-
type__in=(RecordTypeChoices.A, RecordTypeChoices.AAAA)
|
|
143
|
-
):
|
|
144
|
-
record.update_ptr_record()
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
def record_update_ip_address(verbose=False):
|
|
148
|
-
for record in Record.objects.filter(
|
|
149
|
-
type__in=(RecordTypeChoices.A, RecordTypeChoices.AAAA, RecordTypeChoices.PTR)
|
|
150
|
-
):
|
|
151
|
-
if record.is_ptr_record:
|
|
152
|
-
if record.ip_address != record.address_from_name:
|
|
153
|
-
if verbose:
|
|
154
|
-
print(
|
|
155
|
-
f"Updating IP address of pointer record {record} to {record.address_from_name}"
|
|
156
|
-
)
|
|
157
|
-
record.ip_address = record.address_from_name
|
|
158
|
-
record.save()
|
|
159
|
-
else:
|
|
160
|
-
if record.ip_address != IPAddress(record.value):
|
|
161
|
-
if verbose:
|
|
162
|
-
print(
|
|
163
|
-
f"Updating IP address of address record {record} to {IPAddress(record.value)}"
|
|
164
|
-
)
|
|
165
|
-
record.ip_address = record.value
|
|
166
|
-
record.save()
|
|
167
136
|
|
|
137
|
+
record.disable_ptr = False
|
|
138
|
+
record.save(update_fields=["disable_ptr"])
|
|
168
139
|
|
|
169
|
-
|
|
170
|
-
|
|
140
|
+
def _record_update_ptr_records(self, **options):
|
|
141
|
+
if options.get("verbosity"):
|
|
142
|
+
self.stdout.write("Updating the PTR record for all address records")
|
|
143
|
+
|
|
144
|
+
for record in Record.objects.filter(
|
|
145
|
+
type__in=(RecordTypeChoices.A, RecordTypeChoices.AAAA)
|
|
146
|
+
):
|
|
147
|
+
record.save(update_fields=["ptr_record"])
|
|
171
148
|
|
|
172
|
-
def
|
|
173
|
-
|
|
174
|
-
"
|
|
149
|
+
def _record_update_ip_address(self, **options):
|
|
150
|
+
if options.get("verbosity"):
|
|
151
|
+
self.stdout.write("Updating the IP address for all address and PTR records")
|
|
152
|
+
|
|
153
|
+
for record in Record.objects.filter(
|
|
154
|
+
type__in=(
|
|
155
|
+
RecordTypeChoices.A,
|
|
156
|
+
RecordTypeChoices.AAAA,
|
|
157
|
+
RecordTypeChoices.PTR,
|
|
158
|
+
)
|
|
159
|
+
):
|
|
160
|
+
if record.is_ptr_record:
|
|
161
|
+
if record.ip_address != record.address_from_name:
|
|
162
|
+
if options.get("verbosity") > 1:
|
|
163
|
+
self.stdout.write(
|
|
164
|
+
f"Setting the IP Address for pointer record '{record}' to '{record.address_from_name}'"
|
|
165
|
+
)
|
|
166
|
+
record.ip_address = record.address_from_name
|
|
167
|
+
record.save()
|
|
168
|
+
else:
|
|
169
|
+
if record.ip_address != IPAddress(record.value):
|
|
170
|
+
if options.get("verbosity") > 1:
|
|
171
|
+
self.stdout.write(
|
|
172
|
+
f"Updating the IP address for address record '{record}' to '{IPAddress(record.value)}'"
|
|
173
|
+
)
|
|
174
|
+
record.ip_address = record.value
|
|
175
|
+
record.save()
|
|
176
|
+
|
|
177
|
+
def _record_remove_orphaned_ptr_records(self, **options):
|
|
178
|
+
if options.get("verbosity"):
|
|
179
|
+
self.stdout.write("Removing orphaned managed PTR records")
|
|
180
|
+
|
|
181
|
+
orphaned_ptr_records = Record.objects.filter(
|
|
182
|
+
type=RecordTypeChoices.PTR,
|
|
183
|
+
managed=True,
|
|
184
|
+
address_records__isnull=True,
|
|
175
185
|
)
|
|
176
186
|
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
+
for record in orphaned_ptr_records:
|
|
188
|
+
if options.get("verbosity") > 1:
|
|
189
|
+
self.stdout.write(f"Removing orphaned PTR record '{record}'")
|
|
190
|
+
record.delete()
|
|
191
|
+
|
|
192
|
+
def _record_remove_orphaned_address_records(self, **options):
|
|
193
|
+
if options.get("verbosity"):
|
|
194
|
+
self.stdout.write("Removing orphaned managed address records")
|
|
195
|
+
|
|
196
|
+
orphaned_address_records = Record.objects.filter(
|
|
197
|
+
type__in=(RecordTypeChoices.A, RecordTypeChoices.AAAA),
|
|
198
|
+
managed=True,
|
|
199
|
+
ipam_ip_address__isnull=True,
|
|
200
|
+
)
|
|
201
|
+
|
|
202
|
+
for record in orphaned_address_records:
|
|
203
|
+
if options.get("verbosity") > 1:
|
|
204
|
+
self.stdout.write(f"Removing orphaned address record '{record}'")
|
|
205
|
+
record.delete()
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
from django.core.management.base import BaseCommand
|
|
2
|
+
from django.db.models import Max, Min
|
|
3
|
+
|
|
4
|
+
from netbox_dns.models import Record
|
|
5
|
+
from netbox_dns.choices import RecordTypeChoices
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class Command(BaseCommand):
|
|
9
|
+
help = "Clean up the TTLs for RRSets"
|
|
10
|
+
|
|
11
|
+
def add_arguments(self, parser):
|
|
12
|
+
min_max = parser.add_mutually_exclusive_group()
|
|
13
|
+
min_max.add_argument(
|
|
14
|
+
"--min",
|
|
15
|
+
action="store_true",
|
|
16
|
+
help="Use the minimum TTL of an RRSet for all Records",
|
|
17
|
+
)
|
|
18
|
+
min_max.add_argument(
|
|
19
|
+
"--max",
|
|
20
|
+
action="store_true",
|
|
21
|
+
help="Use the maximum TTL of an RRSet for all Records",
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
def handle(self, *model_names, **options):
|
|
25
|
+
self._cleanup_rrset_ttl(**options)
|
|
26
|
+
|
|
27
|
+
def _cleanup_rrset_ttl(self, **options):
|
|
28
|
+
if options.get("verbosity"):
|
|
29
|
+
self.stdout.write("Cleaning up diverging RRset TTL values")
|
|
30
|
+
|
|
31
|
+
ttl_records = (
|
|
32
|
+
Record.objects.filter(ttl__isnull=False)
|
|
33
|
+
.exclude(type=RecordTypeChoices.SOA)
|
|
34
|
+
.exclude(type=RecordTypeChoices.PTR, managed=True)
|
|
35
|
+
)
|
|
36
|
+
for record in ttl_records:
|
|
37
|
+
records = Record.objects.filter(
|
|
38
|
+
name=record.name,
|
|
39
|
+
zone=record.zone,
|
|
40
|
+
type=record.type,
|
|
41
|
+
).exclude(type=RecordTypeChoices.PTR, managed=True)
|
|
42
|
+
|
|
43
|
+
if records.count() == 1:
|
|
44
|
+
if options.get("verbosity") > 2:
|
|
45
|
+
self.stdout.write(
|
|
46
|
+
f"Ignoring single record '{record.pk}' ('{record}')"
|
|
47
|
+
)
|
|
48
|
+
continue
|
|
49
|
+
|
|
50
|
+
if options.get("max"):
|
|
51
|
+
ttl = records.aggregate(Max("ttl")).get("ttl__max")
|
|
52
|
+
else:
|
|
53
|
+
ttl = records.aggregate(Min("ttl")).get("ttl__min")
|
|
54
|
+
|
|
55
|
+
for record in records.exclude(ttl=ttl):
|
|
56
|
+
if options.get("verbosity") > 1:
|
|
57
|
+
self.stdout.write(
|
|
58
|
+
f"Setting TTL for record '{record.pk}' ('{record}') to {ttl}"
|
|
59
|
+
)
|
|
60
|
+
record.ttl = ttl
|
|
61
|
+
record.save(update_fields=["ttl"], update_rrset_ttl=False)
|
|
62
|
+
|
|
63
|
+
if options.get("verbosity"):
|
|
64
|
+
self.stdout.write("RRSet TTL cleanup completed.")
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
from django.core.management.base import BaseCommand
|
|
2
|
+
|
|
3
|
+
from ipam.models import IPAddress
|
|
4
|
+
|
|
5
|
+
from netbox_dns.utilities import update_dns_records, get_zones
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class Command(BaseCommand):
|
|
9
|
+
help = "Rebuild DNSsync relationships between IP addresses and records"
|
|
10
|
+
|
|
11
|
+
def handle(self, *model_names, **options):
|
|
12
|
+
ip_addresses = IPAddress.objects.all()
|
|
13
|
+
for ip_address in ip_addresses:
|
|
14
|
+
if options.get("verbosity") >= 2:
|
|
15
|
+
self.stdout.write(
|
|
16
|
+
f"Updating DNS records for IP Address {ip_address}, VRF {ip_address.vrf}"
|
|
17
|
+
)
|
|
18
|
+
if options.get("verbosity") >= 3:
|
|
19
|
+
self.stdout.write(f" Zones: {get_zones(ip_address)}")
|
|
20
|
+
if update_dns_records(ip_address) and options.get("verbosity") >= 1:
|
|
21
|
+
self.stdout.write(
|
|
22
|
+
f"Updated DNS records for IP Address {ip_address}, VRF {ip_address.vrf}"
|
|
23
|
+
)
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
from django.core.management.base import BaseCommand
|
|
2
|
+
|
|
3
|
+
from core.models import ObjectType
|
|
4
|
+
from extras.models import CustomField
|
|
5
|
+
from extras.choices import CustomFieldTypeChoices
|
|
6
|
+
from ipam.models import IPAddress
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class Command(BaseCommand):
|
|
10
|
+
help = "Setup IPAddress custom fields for IPAM DNSsync"
|
|
11
|
+
|
|
12
|
+
def add_arguments(self, parser):
|
|
13
|
+
parser.add_argument(
|
|
14
|
+
"--remove", action="store_true", default=False, help="Remove custom fields"
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
def handle(self, *model_names, **options):
|
|
18
|
+
ipaddress_object_type = ObjectType.objects.get_for_model(IPAddress)
|
|
19
|
+
|
|
20
|
+
if options.get("remove"):
|
|
21
|
+
if options.get("verbosity"):
|
|
22
|
+
self.stdout.write("Trying to remove IPAM DNSsync custom fields")
|
|
23
|
+
for cf in (
|
|
24
|
+
"ipaddress_dns_disabled",
|
|
25
|
+
"ipaddress_dns_record_ttl",
|
|
26
|
+
"ipaddress_dns_record_disable_ptr",
|
|
27
|
+
):
|
|
28
|
+
try:
|
|
29
|
+
CustomField.objects.get(
|
|
30
|
+
name=cf, object_types=ipaddress_object_type
|
|
31
|
+
).delete()
|
|
32
|
+
if options.get("verbosity"):
|
|
33
|
+
self.stdout.write(f"Removed custom field '{cf}'")
|
|
34
|
+
except CustomField.DoesNotExist:
|
|
35
|
+
pass
|
|
36
|
+
return
|
|
37
|
+
|
|
38
|
+
# +
|
|
39
|
+
# Remove pre-existing IPAM Coupling custom fields
|
|
40
|
+
# -
|
|
41
|
+
if options.get("verbosity") >= 2:
|
|
42
|
+
self.stdout.write("Trying to remove obsolete IPAM Coupling custom fields")
|
|
43
|
+
for cf in (
|
|
44
|
+
"ipaddress_dns_record_name",
|
|
45
|
+
"ipaddress_dns_zone_id",
|
|
46
|
+
):
|
|
47
|
+
try:
|
|
48
|
+
CustomField.objects.get(
|
|
49
|
+
name=cf, object_types=ipaddress_object_type
|
|
50
|
+
).delete()
|
|
51
|
+
if options.get("verbosity"):
|
|
52
|
+
self.stdout.write(f"Removed custom field '{cf}'")
|
|
53
|
+
except CustomField.DoesNotExist:
|
|
54
|
+
pass
|
|
55
|
+
|
|
56
|
+
if options.get("verbosity") >= 2:
|
|
57
|
+
self.stdout.write("Creating IPAM DNSsync custom fields")
|
|
58
|
+
|
|
59
|
+
if not CustomField.objects.filter(
|
|
60
|
+
name="ipaddress_dns_disabled",
|
|
61
|
+
type=CustomFieldTypeChoices.TYPE_BOOLEAN,
|
|
62
|
+
object_types=ipaddress_object_type,
|
|
63
|
+
).exists():
|
|
64
|
+
cf_dnssync_disabled = CustomField.objects.create(
|
|
65
|
+
name="ipaddress_dns_disabled",
|
|
66
|
+
label="Disable DNSsync",
|
|
67
|
+
description="Disable DNS address and pointer record generation for this address",
|
|
68
|
+
type=CustomFieldTypeChoices.TYPE_BOOLEAN,
|
|
69
|
+
required=False,
|
|
70
|
+
default=False,
|
|
71
|
+
group_name="DNSsync",
|
|
72
|
+
is_cloneable=True,
|
|
73
|
+
weight=100,
|
|
74
|
+
)
|
|
75
|
+
cf_dnssync_disabled.object_types.set([ipaddress_object_type])
|
|
76
|
+
if options.get("verbosity"):
|
|
77
|
+
self.stdout.write("Created custom field 'ipaddress_dns_disabled'")
|
|
78
|
+
|
|
79
|
+
try:
|
|
80
|
+
cf_ttl = CustomField.objects.get(
|
|
81
|
+
name="ipaddress_dns_record_ttl",
|
|
82
|
+
type=CustomFieldTypeChoices.TYPE_INTEGER,
|
|
83
|
+
object_types=ipaddress_object_type,
|
|
84
|
+
)
|
|
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",)
|
|
88
|
+
cf_ttl.save()
|
|
89
|
+
if options.get("verbosity"):
|
|
90
|
+
self.stdout.write("Updated custom field 'ipaddress_dns_record_ttl'")
|
|
91
|
+
except CustomField.DoesNotExist:
|
|
92
|
+
cf_ttl = CustomField.objects.create(
|
|
93
|
+
name="ipaddress_dns_record_ttl",
|
|
94
|
+
description="TTL for DNS records created for this address",
|
|
95
|
+
label="TTL",
|
|
96
|
+
type=CustomFieldTypeChoices.TYPE_INTEGER,
|
|
97
|
+
validation_minimum=0,
|
|
98
|
+
validation_maximum=2147483647,
|
|
99
|
+
required=False,
|
|
100
|
+
group_name="DNSsync",
|
|
101
|
+
is_cloneable=True,
|
|
102
|
+
weight=200,
|
|
103
|
+
)
|
|
104
|
+
cf_ttl.object_types.set([ipaddress_object_type])
|
|
105
|
+
if options.get("verbosity"):
|
|
106
|
+
self.stdout.write("Created custom field 'ipaddress_dns_record_ttl'")
|
|
107
|
+
|
|
108
|
+
try:
|
|
109
|
+
cf_disable_ptr = CustomField.objects.get(
|
|
110
|
+
name="ipaddress_dns_record_disable_ptr",
|
|
111
|
+
type=CustomFieldTypeChoices.TYPE_BOOLEAN,
|
|
112
|
+
object_types=ipaddress_object_type,
|
|
113
|
+
)
|
|
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
|
+
)
|
|
119
|
+
cf_disable_ptr.save()
|
|
120
|
+
if options.get("verbosity"):
|
|
121
|
+
self.stdout.write(
|
|
122
|
+
"Updated custom field 'ipaddress_dns_record_disable_ptr'"
|
|
123
|
+
)
|
|
124
|
+
except CustomField.DoesNotExist:
|
|
125
|
+
cf_disable_ptr = CustomField.objects.create(
|
|
126
|
+
name="ipaddress_dns_record_disable_ptr",
|
|
127
|
+
description="Disable DNS PTR record generation for this address",
|
|
128
|
+
label="Disable PTR",
|
|
129
|
+
type=CustomFieldTypeChoices.TYPE_BOOLEAN,
|
|
130
|
+
required=False,
|
|
131
|
+
default=False,
|
|
132
|
+
group_name="DNSsync",
|
|
133
|
+
is_cloneable=True,
|
|
134
|
+
weight=300,
|
|
135
|
+
)
|
|
136
|
+
cf_disable_ptr.object_types.set([ipaddress_object_type])
|
|
137
|
+
if options.get("verbosity"):
|
|
138
|
+
self.stdout.write(
|
|
139
|
+
"Created custom field 'ipaddress_dns_record_disable_ptr'"
|
|
140
|
+
)
|
|
@@ -9,35 +9,8 @@ import netbox_dns.fields.network
|
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
class Migration(migrations.Migration):
|
|
12
|
-
replaces = [
|
|
13
|
-
("netbox_dns", "0001_initial"),
|
|
14
|
-
("netbox_dns", "0015_add_record_status"),
|
|
15
|
-
("netbox_dns", "0013_add_nameserver_zone_record_description"),
|
|
16
|
-
("netbox_dns", "0011_add_view_model"),
|
|
17
|
-
("netbox_dns", "0002_zone_default_ttl"),
|
|
18
|
-
("netbox_dns", "0003_soa_managed_records"),
|
|
19
|
-
("netbox_dns", "0004_create_ptr_for_a_aaaa_records"),
|
|
20
|
-
("netbox_dns", "0006_zone_soa_serial_auto"),
|
|
21
|
-
("netbox_dns", "0007_alter_zone_soa_serial_auto"),
|
|
22
|
-
("netbox_dns", "0005_update_ns_records"),
|
|
23
|
-
("netbox_dns", "0008_zone_status_names"),
|
|
24
|
-
("netbox_dns", "0009_netbox32"),
|
|
25
|
-
("netbox_dns", "0010_update_soa_records"),
|
|
26
|
-
("netbox_dns", "0012_adjust_zone_and_record"),
|
|
27
|
-
("netbox_dns", "0014_add_view_description"),
|
|
28
|
-
("netbox_dns", "0016_cleanup_ptr_records"),
|
|
29
|
-
("netbox_dns", "0017_alter_record_ttl"),
|
|
30
|
-
("netbox_dns", "0018_zone_arpa_network"),
|
|
31
|
-
("netbox_dns", "0019_update_ns_ttl"),
|
|
32
|
-
]
|
|
33
|
-
|
|
34
|
-
initial = True
|
|
35
|
-
|
|
36
12
|
dependencies = [
|
|
37
|
-
("extras", "0072_created_datetimefield"),
|
|
38
|
-
("extras", "0062_clear_secrets_changelog"),
|
|
39
13
|
("extras", "0073_journalentry_tags_custom_fields"),
|
|
40
|
-
("extras", "0059_exporttemplate_as_attachment"),
|
|
41
14
|
]
|
|
42
15
|
|
|
43
16
|
operations = [
|