netbox-plugin-dns 1.3b2__tar.gz → 1.3.2__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.

Files changed (202) hide show
  1. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/PKG-INFO +3 -2
  2. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/README.md +1 -0
  3. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/__init__.py +2 -2
  4. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/api/serializers_/dnssec_key_template.py +1 -0
  5. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/api/serializers_/dnssec_policy.py +1 -0
  6. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/api/serializers_/nameserver.py +5 -1
  7. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/api/serializers_/record.py +5 -5
  8. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/filtersets/record.py +2 -2
  9. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/forms/zone.py +1 -1
  10. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/graphql/filters/dnssec_key_template.py +1 -1
  11. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/graphql/filters/dnssec_policy.py +1 -1
  12. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/graphql/filters/nameserver.py +1 -1
  13. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/graphql/filters/record.py +1 -1
  14. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/graphql/filters/record_template.py +1 -1
  15. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/graphql/filters/registrar.py +1 -1
  16. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/graphql/filters/registration_contact.py +1 -1
  17. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/graphql/filters/view.py +1 -1
  18. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/graphql/filters/zone.py +1 -1
  19. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/graphql/filters/zone_template.py +1 -1
  20. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/graphql/types.py +2 -3
  21. netbox_plugin_dns-1.3.2/netbox_dns/locale/de/LC_MESSAGES/django.mo +0 -0
  22. netbox_plugin_dns-1.3.2/netbox_dns/locale/fr/LC_MESSAGES/django.mo +0 -0
  23. netbox_plugin_dns-1.3.2/netbox_dns/management/commands/remove_orphaned_ptr_records.py +35 -0
  24. netbox_plugin_dns-1.3.2/netbox_dns/migrations/0021_alter_record_ptr_record.py +25 -0
  25. netbox_plugin_dns-1.3.2/netbox_dns/migrations/0022_alter_record_ipam_ip_address.py +26 -0
  26. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/models/record.py +115 -46
  27. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/models/zone.py +1 -1
  28. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/tables/record.py +26 -13
  29. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/tables/view.py +1 -0
  30. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/template_content.py +13 -2
  31. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/templates/netbox_dns/record.html +20 -11
  32. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/utilities/ipam_dnssync.py +21 -3
  33. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/validators/dns_name.py +1 -1
  34. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/views/dnssec_key_template.py +3 -3
  35. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/views/record.py +19 -3
  36. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/views/record_template.py +3 -1
  37. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/views/zone_template.py +5 -3
  38. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_plugin_dns.egg-info/PKG-INFO +3 -2
  39. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_plugin_dns.egg-info/SOURCES.txt +3 -0
  40. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/pyproject.toml +2 -2
  41. netbox_plugin_dns-1.3b2/netbox_dns/locale/de/LC_MESSAGES/django.mo +0 -0
  42. netbox_plugin_dns-1.3b2/netbox_dns/locale/fr/LC_MESSAGES/django.mo +0 -0
  43. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/LICENSE +0 -0
  44. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/api/field_serializers.py +0 -0
  45. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/api/nested_serializers.py +0 -0
  46. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/api/serializers.py +0 -0
  47. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/api/serializers_/__init__.py +0 -0
  48. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/api/serializers_/prefix.py +0 -0
  49. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/api/serializers_/record_template.py +0 -0
  50. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/api/serializers_/registrar.py +0 -0
  51. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/api/serializers_/registration_contact.py +0 -0
  52. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/api/serializers_/view.py +0 -0
  53. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/api/serializers_/zone.py +0 -0
  54. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/api/serializers_/zone_template.py +0 -0
  55. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/api/urls.py +0 -0
  56. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/api/views.py +0 -0
  57. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/apps.py +0 -0
  58. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/choices/__init__.py +0 -0
  59. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/choices/dnssec_key_template.py +0 -0
  60. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/choices/dnssec_policy.py +0 -0
  61. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/choices/record.py +0 -0
  62. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/choices/utilities.py +0 -0
  63. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/choices/zone.py +0 -0
  64. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/fields/__init__.py +0 -0
  65. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/fields/address.py +0 -0
  66. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/fields/choice_array.py +0 -0
  67. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/fields/ipam.py +0 -0
  68. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/fields/network.py +0 -0
  69. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/fields/rfc2317.py +0 -0
  70. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/fields/timeperiod.py +0 -0
  71. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/filtersets/__init__.py +0 -0
  72. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/filtersets/dnssec_key_template.py +0 -0
  73. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/filtersets/dnssec_policy.py +0 -0
  74. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/filtersets/nameserver.py +0 -0
  75. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/filtersets/record_template.py +0 -0
  76. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/filtersets/registrar.py +0 -0
  77. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/filtersets/registration_contact.py +0 -0
  78. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/filtersets/view.py +0 -0
  79. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/filtersets/zone.py +0 -0
  80. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/filtersets/zone_template.py +0 -0
  81. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/forms/__init__.py +0 -0
  82. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/forms/dnssec_key_template.py +0 -0
  83. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/forms/dnssec_policy.py +0 -0
  84. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/forms/nameserver.py +0 -0
  85. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/forms/record.py +0 -0
  86. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/forms/record_template.py +0 -0
  87. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/forms/registrar.py +0 -0
  88. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/forms/registration_contact.py +0 -0
  89. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/forms/view.py +0 -0
  90. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/forms/zone_template.py +0 -0
  91. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/graphql/__init__.py +0 -0
  92. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/graphql/enums.py +0 -0
  93. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/graphql/filter_lookups.py +0 -0
  94. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/graphql/filters/__init__.py +0 -0
  95. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/graphql/schema.py +0 -0
  96. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/locale/en/LC_MESSAGES/django.mo +0 -0
  97. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/management/commands/cleanup_database.py +0 -0
  98. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/management/commands/cleanup_rrset_ttl.py +0 -0
  99. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/management/commands/rebuild_dnssync.py +0 -0
  100. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/management/commands/setup_dnssync.py +0 -0
  101. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/management/commands/update_soa.py +0 -0
  102. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/migrations/0001_squashed_netbox_dns_0_15.py +0 -0
  103. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/migrations/0001_squashed_netbox_dns_0_22.py +0 -0
  104. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/migrations/0002_contact_description_registrar_description.py +0 -0
  105. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/migrations/0003_default_view.py +0 -0
  106. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/migrations/0004_create_and_assign_default_view.py +0 -0
  107. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/migrations/0005_alter_zone_view_not_null.py +0 -0
  108. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/migrations/0006_templating.py +0 -0
  109. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/migrations/0007_alter_ordering_options.py +0 -0
  110. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/migrations/0008_view_prefixes.py +0 -0
  111. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/migrations/0009_rename_contact_registrationcontact.py +0 -0
  112. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/migrations/0010_view_ip_address_filter.py +0 -0
  113. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/migrations/0011_rename_related_fields.py +0 -0
  114. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/migrations/0012_natural_ordering.py +0 -0
  115. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/migrations/0013_zonetemplate_soa_mname_zonetemplate_soa_rname.py +0 -0
  116. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/migrations/0014_alter_unique_constraints_lowercase.py +0 -0
  117. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/migrations/0015_dnssec.py +0 -0
  118. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/migrations/0016_dnssec_policy_status.py +0 -0
  119. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/migrations/0017_dnssec_policy_zone_zone_template.py +0 -0
  120. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/migrations/0018_zone_domain_status_zone_expiration_date.py +0 -0
  121. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/migrations/0019_dnssecpolicy_parental_agents.py +0 -0
  122. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/migrations/0020_netbox_3_4.py +0 -0
  123. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/migrations/0020_remove_dnssecpolicy_parental_agents_and_more.py +0 -0
  124. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/migrations/0021_record_ip_address.py +0 -0
  125. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/migrations/0022_search.py +0 -0
  126. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/migrations/0023_alter_record_value.py +0 -0
  127. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/migrations/0024_tenancy.py +0 -0
  128. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/migrations/0025_ipam_coupling_cf.py +0 -0
  129. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/migrations/0026_domain_registration.py +0 -0
  130. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/migrations/0027_alter_registrar_iana_id.py +0 -0
  131. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/migrations/0028_rfc2317_fields.py +0 -0
  132. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/migrations/0029_record_fqdn.py +0 -0
  133. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/migrations/__init__.py +0 -0
  134. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/mixins/__init__.py +0 -0
  135. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/mixins/object_modification.py +0 -0
  136. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/models/__init__.py +0 -0
  137. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/models/dnssec_key_template.py +0 -0
  138. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/models/dnssec_policy.py +0 -0
  139. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/models/nameserver.py +0 -0
  140. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/models/record_template.py +0 -0
  141. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/models/registrar.py +0 -0
  142. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/models/registration_contact.py +0 -0
  143. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/models/view.py +0 -0
  144. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/models/zone_template.py +0 -0
  145. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/navigation.py +0 -0
  146. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/signals/__init__.py +0 -0
  147. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/signals/dnssec.py +0 -0
  148. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/signals/ipam_dnssync.py +0 -0
  149. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/tables/__init__.py +0 -0
  150. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/tables/dnssec_key_template.py +0 -0
  151. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/tables/dnssec_policy.py +0 -0
  152. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/tables/ipam_dnssync.py +0 -0
  153. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/tables/nameserver.py +0 -0
  154. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/tables/record_template.py +0 -0
  155. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/tables/registrar.py +0 -0
  156. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/tables/registration_contact.py +0 -0
  157. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/tables/zone.py +0 -0
  158. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/tables/zone_template.py +0 -0
  159. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/templates/netbox_dns/dnsseckeytemplate.html +0 -0
  160. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/templates/netbox_dns/dnssecpolicy.html +0 -0
  161. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/templates/netbox_dns/nameserver.html +0 -0
  162. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/templates/netbox_dns/record/managed.html +0 -0
  163. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/templates/netbox_dns/record/related.html +0 -0
  164. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/templates/netbox_dns/recordtemplate.html +0 -0
  165. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/templates/netbox_dns/registrar.html +0 -0
  166. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/templates/netbox_dns/registrationcontact.html +0 -0
  167. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/templates/netbox_dns/view/button.html +0 -0
  168. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/templates/netbox_dns/view/prefix.html +0 -0
  169. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/templates/netbox_dns/view/related.html +0 -0
  170. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/templates/netbox_dns/view.html +0 -0
  171. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/templates/netbox_dns/zone/base.html +0 -0
  172. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/templates/netbox_dns/zone/child.html +0 -0
  173. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/templates/netbox_dns/zone/child_zone.html +0 -0
  174. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/templates/netbox_dns/zone/delegation_record.html +0 -0
  175. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/templates/netbox_dns/zone/managed_record.html +0 -0
  176. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/templates/netbox_dns/zone/record.html +0 -0
  177. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/templates/netbox_dns/zone/registration.html +0 -0
  178. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/templates/netbox_dns/zone/rfc2317_child_zone.html +0 -0
  179. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/templates/netbox_dns/zone.html +0 -0
  180. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/templates/netbox_dns/zonetemplate/child.html +0 -0
  181. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/templates/netbox_dns/zonetemplate.html +0 -0
  182. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/templatetags/__init__.py +0 -0
  183. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/templatetags/netbox_dns.py +0 -0
  184. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/urls.py +0 -0
  185. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/utilities/__init__.py +0 -0
  186. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/utilities/conversions.py +0 -0
  187. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/utilities/dns.py +0 -0
  188. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/validators/__init__.py +0 -0
  189. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/validators/dns_value.py +0 -0
  190. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/validators/dnssec.py +0 -0
  191. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/validators/rfc2317.py +0 -0
  192. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/views/__init__.py +0 -0
  193. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/views/dnssec_policy.py +0 -0
  194. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/views/nameserver.py +0 -0
  195. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/views/registrar.py +0 -0
  196. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/views/registration_contact.py +0 -0
  197. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/views/view.py +0 -0
  198. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_dns/views/zone.py +0 -0
  199. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_plugin_dns.egg-info/dependency_links.txt +0 -0
  200. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_plugin_dns.egg-info/requires.txt +0 -0
  201. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/netbox_plugin_dns.egg-info/top_level.txt +0 -0
  202. {netbox_plugin_dns-1.3b2 → netbox_plugin_dns-1.3.2}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: netbox-plugin-dns
3
- Version: 1.3b2
3
+ Version: 1.3.2
4
4
  Summary: NetBox DNS is a NetBox plugin for managing DNS data.
5
5
  Author-email: Peter Eckel <pete@netbox-dns.org>
6
6
  Project-URL: Homepage, https://github.com/peteeckel/netbox-plugin-dns
@@ -8,7 +8,7 @@ Project-URL: Documentation, https://github.com/peteeckel/netbox-plugin-dns/blob/
8
8
  Project-URL: Repository, https://github.com/peteeckel/netbox-plugin-dns
9
9
  Project-URL: Issues, https://github.com/peteeckel/netbox-plugin-dns/issues
10
10
  Keywords: netbox,netbox-plugin,dns
11
- Classifier: Development Status :: 4 - Beta
11
+ Classifier: Development Status :: 5 - Production/Stable
12
12
  Requires-Python: >=3.10
13
13
  Description-Content-Type: text/markdown
14
14
  License-File: LICENSE
@@ -52,6 +52,7 @@ The main focus of the plugin is to ensure the quality of the data stored in it.
52
52
  * Support for [RFC 2317](https://datatracker.ietf.org/doc/html/rfc2317) delegation of PTR zones for IPv4 subnets longer than 24 bits
53
53
  * Templating for zones and records enables faster creations of zones with given boilerplate object relations, such as name servers, tags, tenants or registration information, or records like standard SPF or MX records that are the same for a subset of zones
54
54
  * IPAM DNSsync can be used to automatically create address and pointer records for IP addresses by assigning prefixes to DNS views. When an IP address has a DNS name assigned and there are zones with matching names in the DNS views linked to the IP address' prefix, a matching DNS record will be created in these zones
55
+ * DNSSEC support for storing configuration data relevant to DNSSEC operation in NetBox DNS
55
56
 
56
57
  Other main features include:
57
58
 
@@ -35,6 +35,7 @@ The main focus of the plugin is to ensure the quality of the data stored in it.
35
35
  * Support for [RFC 2317](https://datatracker.ietf.org/doc/html/rfc2317) delegation of PTR zones for IPv4 subnets longer than 24 bits
36
36
  * Templating for zones and records enables faster creations of zones with given boilerplate object relations, such as name servers, tags, tenants or registration information, or records like standard SPF or MX records that are the same for a subset of zones
37
37
  * IPAM DNSsync can be used to automatically create address and pointer records for IP addresses by assigning prefixes to DNS views. When an IP address has a DNS name assigned and there are zones with matching names in the DNS views linked to the IP address' prefix, a matching DNS record will be created in these zones
38
+ * DNSSEC support for storing configuration data relevant to DNSSEC operation in NetBox DNS
38
39
 
39
40
  Other main features include:
40
41
 
@@ -4,7 +4,7 @@ from django.core.exceptions import ImproperlyConfigured
4
4
  from netbox.plugins import PluginConfig
5
5
  from netbox.plugins.utils import get_plugin_config
6
6
 
7
- __version__ = "1.3-beta2"
7
+ __version__ = "1.3.2"
8
8
 
9
9
 
10
10
  def _check_list(setting):
@@ -16,7 +16,7 @@ class DNSConfig(PluginConfig):
16
16
  name = "netbox_dns"
17
17
  verbose_name = _("NetBox DNS")
18
18
  description = _("NetBox plugin for DNS data")
19
- min_version = "4.2.0"
19
+ min_version = "4.3.0"
20
20
  version = __version__
21
21
  author = "Peter Eckel"
22
22
  author_email = "pete@netbox-dns.org"
@@ -62,6 +62,7 @@ class DNSSECKeyTemplateSerializer(NetBoxModelSerializer):
62
62
  help_text=_("Policies using this Key Template"),
63
63
  )
64
64
  tenant = TenantSerializer(
65
+ nested=True,
65
66
  required=False,
66
67
  allow_null=True,
67
68
  )
@@ -136,6 +136,7 @@ class DNSSECPolicySerializer(NetBoxModelSerializer):
136
136
  help_text=_("Zone templates this policy is assigned to"),
137
137
  )
138
138
  tenant = TenantSerializer(
139
+ nested=True,
139
140
  required=False,
140
141
  allow_null=True,
141
142
  )
@@ -48,4 +48,8 @@ class NameServerSerializer(NetBoxModelSerializer):
48
48
  default=None,
49
49
  help_text=_("Zones served by the authoritative nameserver"),
50
50
  )
51
- tenant = TenantSerializer(required=False, allow_null=True)
51
+ tenant = TenantSerializer(
52
+ nested=True,
53
+ required=False,
54
+ allow_null=True,
55
+ )
@@ -35,7 +35,7 @@ class RecordSerializer(NetBoxModelSerializer):
35
35
  "managed",
36
36
  "disable_ptr",
37
37
  "ptr_record",
38
- "address_record",
38
+ "address_records",
39
39
  "active",
40
40
  "custom_fields",
41
41
  "tenant",
@@ -71,14 +71,14 @@ class RecordSerializer(NetBoxModelSerializer):
71
71
  read_only=True,
72
72
  required=False,
73
73
  allow_null=True,
74
- help_text=_("PTR record generated from an address"),
74
+ help_text=_("PTR record related to an address"),
75
75
  )
76
- address_record = NestedRecordSerializer(
77
- many=False,
76
+ address_records = NestedRecordSerializer(
77
+ many=True,
78
78
  read_only=True,
79
79
  required=False,
80
80
  allow_null=True,
81
- help_text=_("Address record defining the PTR"),
81
+ help_text=_("Address records related to the PTR"),
82
82
  )
83
83
  zone = NestedZoneSerializer(
84
84
  many=False,
@@ -63,10 +63,10 @@ class RecordFilterSet(TenancyFilterSet, NetBoxModelFilterSet):
63
63
  label=_("View the Parent Zone belongs to"),
64
64
  )
65
65
  address_record_id = django_filters.ModelMultipleChoiceFilter(
66
- field_name="address_record",
66
+ field_name="address_records",
67
67
  queryset=Record.objects.all(),
68
68
  to_field_name="id",
69
- label=_("Address Record"),
69
+ label=_("Address Records"),
70
70
  )
71
71
  ptr_record_id = django_filters.ModelMultipleChoiceFilter(
72
72
  field_name="ptr_record",
@@ -534,7 +534,7 @@ class ZoneFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
534
534
  )
535
535
  parental_agents = forms.GenericIPAddressField(
536
536
  required=False,
537
- label=_("Parental Agent"),
537
+ label=_("Parental Agents"),
538
538
  )
539
539
  registrar_id = DynamicModelMultipleChoiceField(
540
540
  queryset=Registrar.objects.all(),
@@ -23,7 +23,7 @@ from netbox_dns.models import DNSSECKeyTemplate
23
23
  __all__ = ("NetBoxDNSDNSSECKeyTemplateFilter",)
24
24
 
25
25
 
26
- @strawberry_django.filter(DNSSECKeyTemplate, lookups=True)
26
+ @strawberry_django.filter_type(DNSSECKeyTemplate, lookups=True)
27
27
  class NetBoxDNSDNSSECKeyTemplateFilter(
28
28
  ContactFilterMixin, TenancyFilterMixin, NetBoxModelFilterMixin
29
29
  ):
@@ -21,7 +21,7 @@ from netbox_dns.graphql.filter_lookups import PolicyDigestArrayLookup
21
21
  __all__ = ("NetBoxDNSDNSSECPolicyFilter", "PolicyDigestArrayLookup")
22
22
 
23
23
 
24
- @strawberry_django.filter(DNSSECPolicy, lookups=True)
24
+ @strawberry_django.filter_type(DNSSECPolicy, lookups=True)
25
25
  class NetBoxDNSDNSSECPolicyFilter(
26
26
  ContactFilterMixin, TenancyFilterMixin, NetBoxModelFilterMixin
27
27
  ):
@@ -16,7 +16,7 @@ from netbox_dns.models import NameServer
16
16
  __all__ = ("NetBoxDNSNameServerFilter",)
17
17
 
18
18
 
19
- @strawberry_django.filter(NameServer, lookups=True)
19
+ @strawberry_django.filter_type(NameServer, lookups=True)
20
20
  class NetBoxDNSNameServerFilter(
21
21
  ContactFilterMixin, TenancyFilterMixin, NetBoxModelFilterMixin
22
22
  ):
@@ -24,7 +24,7 @@ from netbox_dns.models import Record
24
24
  __all__ = ("NetBoxDNSRecordFilter",)
25
25
 
26
26
 
27
- @strawberry_django.filter(Record, lookups=True)
27
+ @strawberry_django.filter_type(Record, lookups=True)
28
28
  class NetBoxDNSRecordFilter(
29
29
  ContactFilterMixin, TenancyFilterMixin, NetBoxModelFilterMixin
30
30
  ):
@@ -20,7 +20,7 @@ from netbox_dns.models import RecordTemplate
20
20
  __all__ = ("NetBoxDNSRecordTemplateFilter",)
21
21
 
22
22
 
23
- @strawberry_django.filter(RecordTemplate, lookups=True)
23
+ @strawberry_django.filter_type(RecordTemplate, lookups=True)
24
24
  class NetBoxDNSRecordTemplateFilter(
25
25
  ContactFilterMixin, TenancyFilterMixin, NetBoxModelFilterMixin
26
26
  ):
@@ -15,7 +15,7 @@ from netbox_dns.models import Registrar
15
15
  __all__ = ("NetBoxDNSRegistrarFilter",)
16
16
 
17
17
 
18
- @strawberry_django.filter(Registrar, lookups=True)
18
+ @strawberry_django.filter_type(Registrar, lookups=True)
19
19
  class NetBoxDNSRegistrarFilter(NetBoxModelFilterMixin):
20
20
  name: FilterLookup[str] | None = strawberry_django.filter_field()
21
21
  description: FilterLookup[str] | None = strawberry_django.filter_field()
@@ -9,7 +9,7 @@ from netbox_dns.models import RegistrationContact
9
9
  __all__ = ("NetBoxDNSRegistrationContactFilter",)
10
10
 
11
11
 
12
- @strawberry_django.filter(RegistrationContact, lookups=True)
12
+ @strawberry_django.filter_type(RegistrationContact, lookups=True)
13
13
  class NetBoxDNSRegistrationContactFilter(NetBoxModelFilterMixin):
14
14
  name: FilterLookup[str] | None = strawberry_django.filter_field()
15
15
  description: FilterLookup[str] | None = strawberry_django.filter_field()
@@ -16,7 +16,7 @@ from netbox_dns.models import View
16
16
  __all__ = ("NetBoxDNSViewFilter",)
17
17
 
18
18
 
19
- @strawberry_django.filter(View, lookups=True)
19
+ @strawberry_django.filter_type(View, lookups=True)
20
20
  class NetBoxDNSViewFilter(
21
21
  ContactFilterMixin, TenancyFilterMixin, NetBoxModelFilterMixin
22
22
  ):
@@ -23,7 +23,7 @@ from netbox_dns.models import Zone
23
23
  __all__ = ("NetBoxDNSZoneFilter",)
24
24
 
25
25
 
26
- @strawberry_django.filter(Zone, lookups=True)
26
+ @strawberry_django.filter_type(Zone, lookups=True)
27
27
  class NetBoxDNSZoneFilter(
28
28
  ContactFilterMixin, TenancyFilterMixin, NetBoxModelFilterMixin
29
29
  ):
@@ -21,7 +21,7 @@ from netbox_dns.models import ZoneTemplate
21
21
  __all__ = ("NetBoxDNSZoneTemplateFilter",)
22
22
 
23
23
 
24
- @strawberry_django.filter(ZoneTemplate, lookups=True)
24
+ @strawberry_django.filter_type(ZoneTemplate, lookups=True)
25
25
  class NetBoxDNSZoneTemplateFilter(
26
26
  ContactFilterMixin, TenancyFilterMixin, NetBoxModelFilterMixin
27
27
  ):
@@ -165,10 +165,9 @@ class NetBoxDNSRecordType(NetBoxObjectType):
165
165
  Annotated["NetBoxDNSRecordType", strawberry.lazy("netbox_dns.graphql.types")]
166
166
  | None
167
167
  )
168
- address_record: (
168
+ address_records: List[
169
169
  Annotated["NetBoxDNSRecordType", strawberry.lazy("netbox_dns.graphql.types")]
170
- | None
171
- )
170
+ ]
172
171
  rfc2317_ptr_records: List[
173
172
  Annotated["NetBoxDNSRecordType", strawberry.lazy("netbox_dns.graphql.types")]
174
173
  ]
@@ -0,0 +1,35 @@
1
+ from django.core.management.base import BaseCommand
2
+
3
+ from netbox_dns.models import Record
4
+ from netbox_dns.choices import RecordTypeChoices
5
+
6
+
7
+ class Command(BaseCommand):
8
+ help = "Remove managed PTR records without an address record"
9
+
10
+ def handle(self, *model_names, **options):
11
+ orphaned_ptr_records = Record.objects.filter(
12
+ type=RecordTypeChoices.PTR,
13
+ address_records__isnull=True,
14
+ managed=True,
15
+ )
16
+
17
+ if not orphaned_ptr_records.exists():
18
+ if options.get("verbosity") >= 1:
19
+ self.stdout.write("No orphaned PTR records found")
20
+ return
21
+
22
+ if options.get("verbosity") >= 1:
23
+ self.stdout.write(
24
+ f"Removing {orphaned_ptr_records.count()} orphaned PTR record(s) ..."
25
+ )
26
+
27
+ for record in orphaned_ptr_records:
28
+ if options.get("verbosity") >= 2:
29
+ self.stdout.write(
30
+ f"removing PTR record {record} from zone {record.zone}"
31
+ )
32
+ record.delete()
33
+
34
+ if options.get("verbosity") >= 1:
35
+ self.stdout.write("... done.")
@@ -0,0 +1,25 @@
1
+ # Generated by Django 5.2 on 2025-05-13 09:16
2
+
3
+ import django.db.models.deletion
4
+ from django.db import migrations, models
5
+
6
+
7
+ class Migration(migrations.Migration):
8
+
9
+ dependencies = [
10
+ ("netbox_dns", "0020_remove_dnssecpolicy_parental_agents_and_more"),
11
+ ]
12
+
13
+ operations = [
14
+ migrations.AlterField(
15
+ model_name="record",
16
+ name="ptr_record",
17
+ field=models.ForeignKey(
18
+ blank=True,
19
+ null=True,
20
+ on_delete=django.db.models.deletion.SET_NULL,
21
+ related_name="address_records",
22
+ to="netbox_dns.record",
23
+ ),
24
+ ),
25
+ ]
@@ -0,0 +1,26 @@
1
+ # Generated by Django 5.2.1 on 2025-05-19 19:34
2
+
3
+ import django.db.models.deletion
4
+ from django.db import migrations, models
5
+
6
+
7
+ class Migration(migrations.Migration):
8
+
9
+ dependencies = [
10
+ ("ipam", "0081_remove_service_device_virtual_machine_add_parent_gfk_index"),
11
+ ("netbox_dns", "0021_alter_record_ptr_record"),
12
+ ]
13
+
14
+ operations = [
15
+ migrations.AlterField(
16
+ model_name="record",
17
+ name="ipam_ip_address",
18
+ field=models.ForeignKey(
19
+ blank=True,
20
+ null=True,
21
+ on_delete=django.db.models.deletion.SET_NULL,
22
+ related_name="netbox_dns_records",
23
+ to="ipam.ipaddress",
24
+ ),
25
+ ),
26
+ ]
@@ -6,7 +6,7 @@ from dns import name as dns_name
6
6
  from dns import rdata
7
7
 
8
8
  from django.core.exceptions import ValidationError
9
- from django.db import transaction, models
9
+ from django.db import models
10
10
  from django.db.models import Q, ExpressionWrapper, BooleanField, Min
11
11
  from django.conf import settings
12
12
  from django.utils.translation import gettext_lazy as _
@@ -28,7 +28,6 @@ from netbox_dns.choices import (
28
28
  RecordClassChoices,
29
29
  )
30
30
 
31
-
32
31
  __all__ = (
33
32
  "Record",
34
33
  "RecordIndex",
@@ -143,6 +142,11 @@ class Record(ObjectModificationMixin, ContactsMixin, NetBoxModel):
143
142
  "tenant",
144
143
  )
145
144
 
145
+ def __init__(self, *args, **kwargs):
146
+ super().__init__(*args, **kwargs)
147
+
148
+ self._cleanup_ptr_record = None
149
+
146
150
  def __str__(self):
147
151
  try:
148
152
  fqdn = dns_name.from_text(
@@ -206,11 +210,11 @@ class Record(ObjectModificationMixin, ContactsMixin, NetBoxModel):
206
210
  null=False,
207
211
  default=False,
208
212
  )
209
- ptr_record = models.OneToOneField(
213
+ ptr_record = models.ForeignKey(
210
214
  verbose_name=_("PTR Record"),
211
215
  to="self",
212
216
  on_delete=models.SET_NULL,
213
- related_name="address_record",
217
+ related_name="address_records",
214
218
  null=True,
215
219
  blank=True,
216
220
  )
@@ -241,7 +245,7 @@ class Record(ObjectModificationMixin, ContactsMixin, NetBoxModel):
241
245
  ipam_ip_address = models.ForeignKey(
242
246
  verbose_name=_("IPAM IP Address"),
243
247
  to="ipam.IPAddress",
244
- on_delete=models.CASCADE,
248
+ on_delete=models.SET_NULL,
245
249
  related_name="netbox_dns_records",
246
250
  blank=True,
247
251
  null=True,
@@ -255,6 +259,14 @@ class Record(ObjectModificationMixin, ContactsMixin, NetBoxModel):
255
259
  blank=True,
256
260
  )
257
261
 
262
+ @property
263
+ def cleanup_ptr_record(self):
264
+ return self._cleanup_ptr_record
265
+
266
+ @cleanup_ptr_record.setter
267
+ def cleanup_ptr_record(self, ptr_record):
268
+ self._cleanup_ptr_record = ptr_record
269
+
258
270
  @property
259
271
  def display_name(self):
260
272
  return name_to_unicode(self.name)
@@ -348,21 +360,42 @@ class Record(ObjectModificationMixin, ContactsMixin, NetBoxModel):
348
360
  def is_delegation_record(self):
349
361
  return self in self.zone.delegation_records
350
362
 
363
+ def refresh_ptr_record(
364
+ self, ptr_record=None, update_rfc2317_cname=True, save_zone_serial=True
365
+ ):
366
+ if ptr_record is None:
367
+ return
368
+
369
+ if not ptr_record.address_records.exists():
370
+ if ptr_record.rfc2317_cname_record is not None:
371
+ ptr_record.remove_from_rfc2317_cname_record()
372
+
373
+ ptr_record.delete(save_zone_serial=save_zone_serial)
374
+
375
+ elif update_rfc2317_cname:
376
+ ptr_record.update_rfc2317_cname_record(save_zone_serial=save_zone_serial)
377
+
351
378
  def update_ptr_record(self, update_rfc2317_cname=True, save_zone_serial=True):
352
379
  ptr_zone = self.ptr_zone
353
380
 
381
+ # +
382
+ # Check whether a PTR record is optioned for and return if that is not the
383
+ # case.
384
+ # -
354
385
  if (
355
386
  ptr_zone is None
356
387
  or self.disable_ptr
357
388
  or not self.is_active
358
389
  or self.name.startswith("*")
359
390
  ):
360
- if self.ptr_record is not None:
361
- with transaction.atomic():
362
- self.ptr_record.delete()
363
- self.ptr_record = None
391
+ self.cleanup_ptr_record = self.ptr_record
392
+ self.ptr_record = None
364
393
  return
365
394
 
395
+ # +
396
+ # Determine the ptr_name and ptr_value related to the ptr_zone. RFC2317
397
+ # PTR names and zones need to be handled differently.
398
+ # -
366
399
  if ptr_zone.is_rfc2317_zone:
367
400
  ptr_name = self.rfc2317_ptr_name
368
401
  else:
@@ -371,51 +404,76 @@ class Record(ObjectModificationMixin, ContactsMixin, NetBoxModel):
371
404
  .relativize(dns_name.from_text(ptr_zone.name))
372
405
  .to_text()
373
406
  )
374
-
375
407
  ptr_value = self.fqdn
376
- ptr_record = self.ptr_record
377
408
 
378
- if ptr_record is not None:
409
+ # +
410
+ # If there is an existing and matching PTR record there is nothing to be done.
411
+ # -
412
+ if (ptr_record := self.ptr_record) is not None:
379
413
  if (
380
- not ptr_record.zone.is_rfc2317_zone
381
- and ptr_record.rfc2317_cname_record is not None
414
+ ptr_record.zone == ptr_zone
415
+ and ptr_record.name == ptr_name
416
+ and ptr_record.value == ptr_value
417
+ and ptr_record.ttl == self.ttl
382
418
  ):
419
+ return
420
+
421
+ # +
422
+ # If there is an RFC2317 CNAME for the PTR record and it is either
423
+ # not required or needs to be changed, remove it.
424
+ # -
425
+ if (
426
+ ptr_record.zone.pk != ptr_zone.pk or not ptr_record.zone.is_rfc2317_zone
427
+ ) and ptr_record.rfc2317_cname_record is not None:
383
428
  ptr_record.rfc2317_cname_record.delete(
384
429
  save_zone_serial=save_zone_serial
385
430
  )
386
-
387
- with transaction.atomic():
388
- if ptr_record is not None:
389
- if ptr_record.zone.pk != ptr_zone.pk:
390
- if ptr_record.rfc2317_cname_record is not None:
391
- ptr_record.rfc2317_cname_record.delete()
392
- ptr_record.delete(save_zone_serial=save_zone_serial)
393
- ptr_record = None
394
-
395
- else:
396
- if (
397
- ptr_record.name != ptr_name
398
- or ptr_record.value != ptr_value
399
- or ptr_record.ttl != self.ttl
400
- ):
401
- ptr_record.name = ptr_name
402
- ptr_record.value = ptr_value
403
- ptr_record.ttl = self.ttl
404
- ptr_record.save(save_zone_serial=save_zone_serial)
405
-
406
- if ptr_record is None:
407
- ptr_record = Record(
408
- zone_id=ptr_zone.pk,
409
- type=RecordTypeChoices.PTR,
410
- name=ptr_name,
411
- ttl=self.ttl,
412
- value=ptr_value,
413
- managed=True,
414
- )
431
+ ptr_record.rfc2317_cname_record = None
432
+
433
+ # +
434
+ # If the PTR record is used exclusively by the address record it can be
435
+ # modified to match the new name, zone, value and TTL.
436
+ # -
437
+ if ptr_record.address_records.count() == 1:
438
+ ptr_record.zone = ptr_zone
439
+ ptr_record.name = ptr_name
440
+ ptr_record.value = ptr_value
441
+ ptr_record.ttl = self.ttl
415
442
  ptr_record.save(
416
443
  update_rfc2317_cname=update_rfc2317_cname,
417
444
  save_zone_serial=save_zone_serial,
418
445
  )
446
+ return
447
+
448
+ # +
449
+ # Either there was no PTR record or the existing PTR record could not be re-used,
450
+ # so we need to either get find a matching PTR record or create a new one.
451
+ # -
452
+ try:
453
+ ptr_record = Record.objects.get(
454
+ name=ptr_name,
455
+ zone=ptr_zone,
456
+ type=RecordTypeChoices.PTR,
457
+ value=ptr_value,
458
+ )
459
+
460
+ # +
461
+ # If no existing PTR record could be found in the database, create a new
462
+ # one from scratch.
463
+ # -
464
+ except Record.DoesNotExist:
465
+ ptr_record = Record(
466
+ zone_id=ptr_zone.pk,
467
+ type=RecordTypeChoices.PTR,
468
+ name=ptr_name,
469
+ ttl=self.ttl,
470
+ value=ptr_value,
471
+ managed=True,
472
+ )
473
+ ptr_record.save(
474
+ update_rfc2317_cname=update_rfc2317_cname,
475
+ save_zone_serial=save_zone_serial,
476
+ )
419
477
 
420
478
  self.ptr_record = ptr_record
421
479
 
@@ -905,13 +963,19 @@ class Record(ObjectModificationMixin, ContactsMixin, NetBoxModel):
905
963
  save_zone_serial=save_zone_serial,
906
964
  )
907
965
  elif self.ptr_record is not None:
908
- self.ptr_record.delete()
966
+ self.cleanup_ptr_record = self.ptr_record
909
967
  self.ptr_record = None
910
968
 
911
969
  changed_fields = self.changed_fields
912
970
  if changed_fields is None or changed_fields:
913
971
  super().save(*args, **kwargs)
914
972
 
973
+ self.refresh_ptr_record(
974
+ self.cleanup_ptr_record,
975
+ update_rfc2317_cname=update_rfc2317_cname,
976
+ save_zone_serial=save_zone_serial,
977
+ )
978
+
915
979
  if self.type != RecordTypeChoices.SOA and self.zone.soa_serial_auto:
916
980
  self.zone.update_serial(save_zone_serial=save_zone_serial)
917
981
 
@@ -919,11 +983,16 @@ class Record(ObjectModificationMixin, ContactsMixin, NetBoxModel):
919
983
  if self.rfc2317_cname_record:
920
984
  self.remove_from_rfc2317_cname_record(save_zone_serial=save_zone_serial)
921
985
 
922
- if self.ptr_record:
923
- self.ptr_record.delete()
986
+ ptr_record = self.ptr_record
924
987
 
925
988
  super().delete(*args, **kwargs)
926
989
 
990
+ self.refresh_ptr_record(
991
+ ptr_record,
992
+ update_rfc2317_cname=True,
993
+ save_zone_serial=save_zone_serial,
994
+ )
995
+
927
996
  _zone = self.zone
928
997
  if _zone.soa_serial_auto:
929
998
  _zone.update_serial(save_zone_serial=save_zone_serial)
@@ -1036,7 +1036,7 @@ class Zone(ObjectModificationMixin, ContactsMixin, NetBoxModel):
1036
1036
  for address_record in address_records:
1037
1037
  address_record.ptr_record.delete()
1038
1038
 
1039
- ptr_records = self.records.filter(address_record__isnull=False)
1039
+ ptr_records = self.records.filter(address_records__isnull=False)
1040
1040
  update_records = list(
1041
1041
  Record.objects.filter(ptr_record__in=ptr_records).values_list(
1042
1042
  "pk", flat=True