netbox-plugin-dns 1.1.0b1__tar.gz → 1.1.0b2__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 (140) hide show
  1. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/PKG-INFO +2 -2
  2. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/__init__.py +3 -2
  3. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/forms/view.py +5 -4
  4. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/management/commands/setup_autodns.py +35 -19
  5. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/models/record.py +35 -1
  6. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/models/zone.py +14 -0
  7. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/signals/ipam_autodns.py +43 -11
  8. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/templates/netbox_dns/view.html +2 -6
  9. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/utilities/ipam_autodns.py +67 -16
  10. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/pyproject.toml +2 -2
  11. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/LICENSE +0 -0
  12. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/README.md +0 -0
  13. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/api/nested_serializers.py +0 -0
  14. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/api/serializers.py +0 -0
  15. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/api/serializers_/__init__.py +0 -0
  16. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/api/serializers_/contact.py +0 -0
  17. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/api/serializers_/nameserver.py +0 -0
  18. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/api/serializers_/prefix.py +0 -0
  19. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/api/serializers_/record.py +0 -0
  20. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/api/serializers_/record_template.py +0 -0
  21. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/api/serializers_/registrar.py +0 -0
  22. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/api/serializers_/view.py +0 -0
  23. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/api/serializers_/zone.py +0 -0
  24. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/api/serializers_/zone_template.py +0 -0
  25. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/api/urls.py +0 -0
  26. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/api/views.py +0 -0
  27. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/apps.py +0 -0
  28. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/choices/__init__.py +0 -0
  29. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/choices/record.py +0 -0
  30. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/choices/zone.py +0 -0
  31. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/fields/__init__.py +0 -0
  32. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/fields/address.py +0 -0
  33. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/fields/ipam.py +0 -0
  34. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/fields/network.py +0 -0
  35. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/fields/rfc2317.py +0 -0
  36. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/filtersets/__init__.py +0 -0
  37. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/filtersets/contact.py +0 -0
  38. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/filtersets/nameserver.py +0 -0
  39. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/filtersets/record.py +0 -0
  40. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/filtersets/record_template.py +0 -0
  41. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/filtersets/registrar.py +0 -0
  42. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/filtersets/view.py +0 -0
  43. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/filtersets/zone.py +0 -0
  44. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/filtersets/zone_template.py +0 -0
  45. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/forms/__init__.py +0 -0
  46. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/forms/contact.py +0 -0
  47. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/forms/nameserver.py +0 -0
  48. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/forms/record.py +0 -0
  49. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/forms/record_template.py +0 -0
  50. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/forms/registrar.py +0 -0
  51. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/forms/zone.py +0 -0
  52. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/forms/zone_template.py +0 -0
  53. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/graphql/__init__.py +0 -0
  54. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/graphql/filters.py +0 -0
  55. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/graphql/schema.py +0 -0
  56. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/graphql/types.py +0 -0
  57. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/management/commands/cleanup_database.py +0 -0
  58. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/management/commands/cleanup_rrset_ttl.py +0 -0
  59. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/management/commands/update_soa.py +0 -0
  60. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/migrations/0001_squashed_netbox_dns_0_15.py +0 -0
  61. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/migrations/0001_squashed_netbox_dns_0_22.py +0 -0
  62. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/migrations/0002_contact_description_registrar_description.py +0 -0
  63. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/migrations/0003_default_view.py +0 -0
  64. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/migrations/0004_create_and_assign_default_view.py +0 -0
  65. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/migrations/0005_alter_zone_view_not_null.py +0 -0
  66. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/migrations/0006_templating.py +0 -0
  67. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/migrations/0007_view_prefixes.py +0 -0
  68. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/migrations/0020_netbox_3_4.py +0 -0
  69. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/migrations/0021_record_ip_address.py +0 -0
  70. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/migrations/0022_search.py +0 -0
  71. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/migrations/0023_alter_record_value.py +0 -0
  72. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/migrations/0024_tenancy.py +0 -0
  73. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/migrations/0025_ipam_coupling_cf.py +0 -0
  74. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/migrations/0026_domain_registration.py +0 -0
  75. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/migrations/0027_alter_registrar_iana_id.py +0 -0
  76. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/migrations/0028_rfc2317_fields.py +0 -0
  77. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/migrations/0029_record_fqdn.py +0 -0
  78. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/migrations/__init__.py +0 -0
  79. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/mixins/__init__.py +0 -0
  80. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/mixins/object_modification.py +0 -0
  81. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/models/__init__.py +0 -0
  82. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/models/contact.py +0 -0
  83. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/models/nameserver.py +0 -0
  84. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/models/record_template.py +0 -0
  85. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/models/registrar.py +0 -0
  86. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/models/view.py +0 -0
  87. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/models/zone_template.py +0 -0
  88. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/navigation.py +0 -0
  89. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/signals/__init__.py +0 -0
  90. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/tables/__init__.py +0 -0
  91. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/tables/contact.py +0 -0
  92. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/tables/nameserver.py +0 -0
  93. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/tables/record.py +0 -0
  94. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/tables/record_template.py +0 -0
  95. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/tables/registrar.py +0 -0
  96. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/tables/view.py +0 -0
  97. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/tables/zone.py +0 -0
  98. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/tables/zone_template.py +0 -0
  99. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/template_content.py +0 -0
  100. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/templates/netbox_dns/contact.html +0 -0
  101. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/templates/netbox_dns/nameserver.html +0 -0
  102. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/templates/netbox_dns/record/managed.html +0 -0
  103. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/templates/netbox_dns/record/related.html +0 -0
  104. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/templates/netbox_dns/record.html +0 -0
  105. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/templates/netbox_dns/recordtemplate.html +0 -0
  106. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/templates/netbox_dns/registrar.html +0 -0
  107. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/templates/netbox_dns/view/related.html +0 -0
  108. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/templates/netbox_dns/zone/base.html +0 -0
  109. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/templates/netbox_dns/zone/child.html +0 -0
  110. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/templates/netbox_dns/zone/child_zone.html +0 -0
  111. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/templates/netbox_dns/zone/managed_record.html +0 -0
  112. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/templates/netbox_dns/zone/record.html +0 -0
  113. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/templates/netbox_dns/zone/registration.html +0 -0
  114. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/templates/netbox_dns/zone/rfc2317_child_zone.html +0 -0
  115. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/templates/netbox_dns/zone.html +0 -0
  116. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/templates/netbox_dns/zonetemplate.html +0 -0
  117. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/urls/__init__.py +0 -0
  118. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/urls/contact.py +0 -0
  119. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/urls/nameserver.py +0 -0
  120. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/urls/record.py +0 -0
  121. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/urls/record_template.py +0 -0
  122. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/urls/registrar.py +0 -0
  123. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/urls/view.py +0 -0
  124. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/urls/zone.py +0 -0
  125. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/urls/zone_template.py +0 -0
  126. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/utilities/__init__.py +0 -0
  127. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/utilities/conversions.py +0 -0
  128. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/validators/__init__.py +0 -0
  129. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/validators/dns_name.py +0 -0
  130. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/validators/dns_value.py +0 -0
  131. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/validators/rfc2317.py +0 -0
  132. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/views/__init__.py +0 -0
  133. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/views/contact.py +0 -0
  134. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/views/nameserver.py +0 -0
  135. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/views/record.py +0 -0
  136. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/views/record_template.py +0 -0
  137. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/views/registrar.py +0 -0
  138. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/views/view.py +0 -0
  139. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/views/zone.py +0 -0
  140. {netbox_plugin_dns-1.1.0b1 → netbox_plugin_dns-1.1.0b2}/netbox_dns/views/zone_template.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: netbox-plugin-dns
3
- Version: 1.1.0b1
3
+ Version: 1.1.0b2
4
4
  Summary: NetBox DNS is a NetBox plugin for managing DNS data.
5
5
  Home-page: https://github.com/peteeckel/netbox-plugin-dns
6
6
  License: MIT
@@ -8,7 +8,7 @@ Keywords: netbox,netbox-plugin,dns
8
8
  Author: Peter Eckel
9
9
  Author-email: pete@netbox-dns.org
10
10
  Requires-Python: >=3.10,<4.0
11
- Classifier: Development Status :: 4 - Beta
11
+ Classifier: Development Status :: 5 - Production/Stable
12
12
  Classifier: License :: OSI Approved :: MIT License
13
13
  Classifier: Programming Language :: Python :: 3
14
14
  Classifier: Programming Language :: Python :: 3.10
@@ -5,14 +5,14 @@ from ipam.choices import IPAddressStatusChoices
5
5
 
6
6
  from netbox_dns.choices import RecordTypeChoices
7
7
 
8
- __version__ = "1.1.0-beta1"
8
+ __version__ = "1.1.0b2"
9
9
 
10
10
 
11
11
  class DNSConfig(PluginConfig):
12
12
  name = "netbox_dns"
13
13
  verbose_name = "NetBox DNS"
14
14
  description = "NetBox plugin for DNS data"
15
- min_version = "4.1.0-beta1"
15
+ min_version = "4.0.0"
16
16
  version = __version__
17
17
  author = "Peter Eckel"
18
18
  author_email = "pete@netbox-dns.org"
@@ -31,6 +31,7 @@ class DNSConfig(PluginConfig):
31
31
  IPAddressStatusChoices.STATUS_DHCP,
32
32
  IPAddressStatusChoices.STATUS_SLAAC,
33
33
  ],
34
+ "autodns_conflict_deactivate": False,
34
35
  "tolerate_characters_in_zone_labels": "",
35
36
  "tolerate_underscores_in_labels": False,
36
37
  "tolerate_underscores_in_hostnames": False, # Deprecated, will be removed in 1.2.0
@@ -25,8 +25,9 @@ from ipam.models import Prefix
25
25
  from netbox_dns.models import View
26
26
  from netbox_dns.fields import PrefixDynamicModelMultipleChoiceField
27
27
  from netbox_dns.utilities import (
28
- get_ip_addresses_by_prefix,
28
+ check_dns_records,
29
29
  update_dns_records,
30
+ get_ip_addresses_by_prefix,
30
31
  get_views_by_prefix,
31
32
  )
32
33
 
@@ -52,7 +53,7 @@ class ViewPrefixUpdateMixin:
52
53
  for prefix in prefixes.difference(old_prefixes):
53
54
  for ip_address in get_ip_addresses_by_prefix(prefix, check_view=False):
54
55
  try:
55
- update_dns_records(ip_address, commit=False, view=self.instance)
56
+ check_dns_records(ip_address, view=self.instance)
56
57
  except ValidationError as exc:
57
58
  self.add_error("prefixes", exc.messages)
58
59
 
@@ -74,7 +75,7 @@ class ViewPrefixUpdateMixin:
74
75
  # parent. If that's the case, the IP addresses need to be checked.
75
76
  # -
76
77
  if (parent := check_prefix.get_parents().last()) is None:
77
- return
78
+ continue
78
79
 
79
80
  for view in get_views_by_prefix(parent):
80
81
  if view == self.instance:
@@ -84,7 +85,7 @@ class ViewPrefixUpdateMixin:
84
85
  check_prefix, check_view=False
85
86
  ):
86
87
  try:
87
- update_dns_records(ip_address, commit=False, view=view)
88
+ check_dns_records(ip_address, view=view)
88
89
  except ValidationError as exc:
89
90
  self.add_error("prefixes", exc.messages)
90
91
 
@@ -29,7 +29,7 @@ class Command(BaseCommand):
29
29
  CustomField.objects.get(
30
30
  name=cf, object_types=ipaddress_object_type
31
31
  ).delete()
32
- if options.get("verbosity") >= 2:
32
+ if options.get("verbosity"):
33
33
  self.stdout.write(f"Custom field '{cf}' removed")
34
34
  except CustomField.DoesNotExist:
35
35
  pass
@@ -38,7 +38,7 @@ class Command(BaseCommand):
38
38
  # +
39
39
  # Remove pre-existing IPAM Coupling custom fields
40
40
  # -
41
- if options.get("verbosity"):
41
+ if options.get("verbosity") >= 2:
42
42
  self.stdout.write(f"Trying to remove obsolete IPAM Coupling custom fields")
43
43
  for cf in (
44
44
  "ipaddress_dns_record_name",
@@ -48,12 +48,12 @@ class Command(BaseCommand):
48
48
  CustomField.objects.get(
49
49
  name=cf, object_types=ipaddress_object_type
50
50
  ).delete()
51
- if options.get("verbosity") >= 2:
51
+ if options.get("verbosity"):
52
52
  self.stdout.write(f"Removed custom field '{cf}'")
53
53
  except CustomField.DoesNotExist:
54
54
  pass
55
55
 
56
- if options.get("verbosity"):
56
+ if options.get("verbosity") >= 2:
57
57
  self.stdout.write(f"Creating IPAM AutoDNS custom fields")
58
58
 
59
59
  if not CustomField.objects.filter(
@@ -61,7 +61,7 @@ class Command(BaseCommand):
61
61
  type=CustomFieldTypeChoices.TYPE_BOOLEAN,
62
62
  object_types=ipaddress_object_type,
63
63
  ).exists():
64
- cf_disable_ptr = CustomField.objects.create(
64
+ cf_autodns_disabled = CustomField.objects.create(
65
65
  name="ipaddress_dns_disabled",
66
66
  label="Disable AutoDNS",
67
67
  description="Disable DNS address and pointer record generation for this address",
@@ -72,15 +72,22 @@ class Command(BaseCommand):
72
72
  is_cloneable=True,
73
73
  weight=100,
74
74
  )
75
- cf_disable_ptr.object_types.set([ipaddress_object_type])
76
- if options.get("verbosity") >= 2:
75
+ cf_autodns_disabled.object_types.set([ipaddress_object_type])
76
+ if options.get("verbosity"):
77
77
  self.stdout.write("Created custom field 'ipaddress_dns_disabled'")
78
78
 
79
- if not CustomField.objects.filter(
80
- name="ipaddress_dns_record_ttl",
81
- type=CustomFieldTypeChoices.TYPE_INTEGER,
82
- object_types=ipaddress_object_type,
83
- ).exists():
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 != "AutoDNS":
86
+ cf_ttl.group_name = "AutoDNS"
87
+ cf_ttl.save()
88
+ if options.get("verbosity"):
89
+ self.stdout.write("Updated custom field 'ipaddress_dns_record_ttl'")
90
+ except CustomField.DoesNotExist:
84
91
  cf_ttl = CustomField.objects.create(
85
92
  name="ipaddress_dns_record_ttl",
86
93
  description="TTL for DNS records created for this address",
@@ -94,14 +101,23 @@ class Command(BaseCommand):
94
101
  weight=200,
95
102
  )
96
103
  cf_ttl.object_types.set([ipaddress_object_type])
97
- if options.get("verbosity") >= 2:
104
+ if options.get("verbosity"):
98
105
  self.stdout.write("Created custom field 'ipaddress_dns_record_ttl'")
99
106
 
100
- if not CustomField.objects.filter(
101
- name="ipaddress_dns_record_disable_ptr",
102
- type=CustomFieldTypeChoices.TYPE_BOOLEAN,
103
- object_types=ipaddress_object_type,
104
- ).exists():
107
+ try:
108
+ cf_disable_ptr = CustomField.objects.get(
109
+ name="ipaddress_dns_record_disable_ptr",
110
+ type=CustomFieldTypeChoices.TYPE_BOOLEAN,
111
+ object_types=ipaddress_object_type,
112
+ )
113
+ if cf_disable_ptr.group_name != "AutoDNS":
114
+ cf_disable_ptr.group_name = "AutoDNS"
115
+ cf_disable_ptr.save()
116
+ if options.get("verbosity"):
117
+ self.stdout.write(
118
+ "Updated custom field 'ipaddress_dns_record_disable_ptr'"
119
+ )
120
+ except CustomField.DoesNotExist:
105
121
  cf_disable_ptr = CustomField.objects.create(
106
122
  name="ipaddress_dns_record_disable_ptr",
107
123
  description="Disable DNS PTR record generation for this address",
@@ -114,7 +130,7 @@ class Command(BaseCommand):
114
130
  weight=300,
115
131
  )
116
132
  cf_disable_ptr.object_types.set([ipaddress_object_type])
117
- if options.get("verbosity") >= 2:
133
+ if options.get("verbosity"):
118
134
  self.stdout.write(
119
135
  "Created custom field 'ipaddress_dns_record_disable_ptr'"
120
136
  )
@@ -562,13 +562,41 @@ class Record(ObjectModificationMixin, NetBoxModel):
562
562
  if self.pk is not None:
563
563
  records = records.exclude(pk=self.pk)
564
564
 
565
- if len(records):
565
+ if records.exists():
566
+ if self.ipam_ip_address is not None:
567
+ if not records.filter(
568
+ ipam_ip_address__isnull=True
569
+ ).exists() or get_plugin_config(
570
+ "netbox_dns", "autodns_conflict_deactivate", False
571
+ ):
572
+ return
573
+
566
574
  raise ValidationError(
567
575
  {
568
576
  "value": f"There is already an active {self.type} record for name {self.name} in zone {self.zone} with value {self.value}."
569
577
  }
570
578
  ) from None
571
579
 
580
+ def handle_conflicting_address_records(self):
581
+ if self.ipam_ip_address is None or not self.is_active:
582
+ return
583
+
584
+ if not get_plugin_config("netbox_dns", "autodns_conflict_deactivate", False):
585
+ return
586
+
587
+ records = Record.objects.filter(
588
+ zone=self.zone,
589
+ name=self.name,
590
+ type=self.type,
591
+ value=self.value,
592
+ status__in=Record.ACTIVE_STATUS_LIST,
593
+ ipam_ip_address__isnull=True,
594
+ )
595
+
596
+ for record in records:
597
+ record.status = RecordStatusChoices.STATUS_INACTIVE
598
+ record.save(update_fields=["status"])
599
+
572
600
  def check_unique_rrset_ttl(self):
573
601
  if self.pk is not None:
574
602
  return
@@ -587,8 +615,12 @@ class Record(ObjectModificationMixin, NetBoxModel):
587
615
  )
588
616
  .exclude(ttl=self.ttl)
589
617
  .exclude(type=RecordTypeChoices.PTR, managed=True)
618
+ .exclude(status=RecordStatusChoices.STATUS_INACTIVE)
590
619
  )
591
620
 
621
+ if self.ipam_ip_address is not None:
622
+ records = records.exclude(ipam_ip_address__isnull=False)
623
+
592
624
  if not records.exists():
593
625
  return
594
626
 
@@ -621,6 +653,7 @@ class Record(ObjectModificationMixin, NetBoxModel):
621
653
  .exclude(pk=self.pk)
622
654
  .exclude(ttl=ttl)
623
655
  .exclude(type=RecordTypeChoices.PTR, managed=True)
656
+ .exclude(status=RecordStatusChoices.STATUS_INACTIVE)
624
657
  )
625
658
 
626
659
  for record in records:
@@ -740,6 +773,7 @@ class Record(ObjectModificationMixin, NetBoxModel):
740
773
  self.ip_address = None
741
774
 
742
775
  if self.is_address_record:
776
+ self.handle_conflicting_address_records()
743
777
  self.update_ptr_record(
744
778
  update_rfc2317_cname=update_rfc2317_cname,
745
779
  save_zone_serial=save_zone_serial,
@@ -28,6 +28,7 @@ from netbox_dns.choices import RecordClassChoices, RecordTypeChoices, ZoneStatus
28
28
  from netbox_dns.fields import NetworkField, RFC2317NetworkField
29
29
  from netbox_dns.utilities import (
30
30
  update_dns_records,
31
+ check_dns_records,
31
32
  get_ip_addresses_by_zone,
32
33
  arpa_to_prefix,
33
34
  name_to_unicode,
@@ -652,6 +653,19 @@ class Zone(ObjectModificationMixin, NetBoxModel):
652
653
  }
653
654
  )
654
655
 
656
+ if old_zone.name != self.name or old_zone.view != self.view:
657
+ update_ip_addresses = IPAddress.objects.filter(
658
+ pk__in=self.record_set.filter(
659
+ ipam_ip_address__isnull=False
660
+ ).values_list("ipam_ip_address", flat=True)
661
+ )
662
+ update_ip_addresses |= get_ip_addresses_by_zone(self)
663
+ for ip_address in update_ip_addresses:
664
+ try:
665
+ check_dns_records(ip_address, zone=self)
666
+ except ValidationError as exc:
667
+ raise ValidationError(exc.messages)
668
+
655
669
  if self.is_reverse_zone:
656
670
  self.arpa_network = self.network_from_name
657
671
 
@@ -11,6 +11,8 @@ from utilities.exceptions import AbortRequest
11
11
 
12
12
  from netbox_dns.models import view as _view
13
13
  from netbox_dns.utilities import (
14
+ check_dns_records,
15
+ check_record_permission,
14
16
  update_dns_records,
15
17
  delete_dns_records,
16
18
  get_views_by_prefix,
@@ -18,22 +20,52 @@ from netbox_dns.utilities import (
18
20
  get_ip_addresses_by_view,
19
21
  )
20
22
 
23
+ AUTODNS_CUSTOM_FIELDS = {
24
+ "ipaddress_dns_disabled": False,
25
+ "ipaddress_dns_record_ttl": None,
26
+ "ipaddress_dns_record_disable_ptr": False,
27
+ }
28
+
21
29
 
22
30
  @receiver(post_clean, sender=IPAddress)
23
31
  def ipam_autodns_ipaddress_post_clean(instance, **kwargs):
24
32
  if not isinstance(instance.address, IPNetwork):
25
33
  return
26
34
 
35
+ # +
36
+ # Check NetBox DNS record permission for changes to IPAddress custom fields
37
+ #
38
+ # Normally, as the modfication of DNS fields
39
+ if (request := current_request.get()) is not None:
40
+ cf_data = instance.custom_field_data
41
+ if (
42
+ instance.pk is not None
43
+ and any(
44
+ (
45
+ cf_data.get(cf)
46
+ != IPAddress.objects.get(pk=instance.pk).custom_field_data.get(cf)
47
+ for cf in AUTODNS_CUSTOM_FIELDS.keys()
48
+ )
49
+ )
50
+ and not check_record_permission(request)
51
+ ) or (
52
+ instance.pk is None
53
+ and any(
54
+ (
55
+ cf_data.get(cf) != cf_default
56
+ for cf, cf_default in AUTODNS_CUSTOM_FIELDS.items()
57
+ )
58
+ )
59
+ and not check_record_permission(request, change=False, delete=False)
60
+ ):
61
+ raise ValidationError(
62
+ f"User '{request.user}' is not allowed to alter AutoDNS custom fields"
63
+ )
64
+
27
65
  try:
28
- update_dns_records(instance, commit=False)
66
+ check_dns_records(instance)
29
67
  except ValidationError as exc:
30
- if hasattr(exc, "error_dict"):
31
- for field in ("name", "ttl", "value", "type"):
32
- value = exc.error_dict.pop(field, None)
33
- if value is not None:
34
- raise ValidationError({"dns_name": value})
35
-
36
- raise exc
68
+ raise ValidationError({"dns_name": exc.messages})
37
69
 
38
70
 
39
71
  @receiver(pre_delete, sender=IPAddress)
@@ -42,8 +74,8 @@ def ipam_autodns_ipaddress_pre_delete(instance, **kwargs):
42
74
 
43
75
 
44
76
  @receiver(pre_save, sender=IPAddress)
45
- def ipam_autodns_ipaddress_post_save(instance, **kwargs):
46
- update_dns_records(instance, commit=False)
77
+ def ipam_autodns_ipaddress_pre_save(instance, **kwargs):
78
+ check_dns_records(instance)
47
79
 
48
80
 
49
81
  @receiver(post_save, sender=IPAddress)
@@ -80,7 +112,7 @@ def ipam_autodns_prefix_pre_delete(instance, **kwargs):
80
112
  _depth=instance.depth + 1, netbox_dns_views__isnull=True
81
113
  ):
82
114
  for ip_address in get_ip_addresses_by_prefix(prefix):
83
- update_dns_records(ip_address, commit=False)
115
+ check_dns_records(ip_address)
84
116
  except ValidationError as exc:
85
117
  if request is not None:
86
118
  raise AbortRequest(
@@ -45,15 +45,11 @@
45
45
  {% for prefix in object.prefixes.all %}
46
46
  <tr>
47
47
  <td>
48
- <a href="{% url 'ipam:prefix' pk=prefix.pk %}">
49
- {{ prefix }}
50
- </a>
48
+ {{ prefix|linkify }}
51
49
  </td>
52
50
  {% if prefix.vrf %}
53
51
  <td>
54
- <a href="{% url 'ipam:vrf' pk=prefix.vrf.pk %}">
55
- {{ prefix.vrf }}
56
- </a>
52
+ {{ prefix.vrf|linkify }}
57
53
  </td>
58
54
  {% else %}
59
55
  <td>Global</td>
@@ -7,6 +7,7 @@ from dns import name as dns_name
7
7
  from django.conf import settings
8
8
  from django.db.models import Q
9
9
 
10
+ from netbox.context import current_request
10
11
  from ipam.models import IPAddress, Prefix
11
12
 
12
13
  from netbox_dns.models import zone as _zone
@@ -16,12 +17,14 @@ from netbox_dns.models import view as _view
16
17
 
17
18
  __all__ = (
18
19
  "get_zones",
20
+ "check_dns_records",
19
21
  "update_dns_records",
20
22
  "delete_dns_records",
21
23
  "get_views_by_prefix",
22
24
  "get_ip_addresses_by_prefix",
23
25
  "get_ip_addresses_by_view",
24
26
  "get_ip_addresses_by_zone",
27
+ "check_record_permission",
25
28
  )
26
29
 
27
30
 
@@ -82,19 +85,54 @@ def get_zones(ip_address, view=None):
82
85
  ]
83
86
 
84
87
 
85
- def update_dns_records(ip_address, commit=True, view=None):
88
+ def check_dns_records(ip_address, zone=None, view=None):
86
89
  if ip_address.dns_name == "":
87
- if commit:
88
- delete_dns_records(ip_address)
89
90
  return
90
91
 
91
- zones = get_zones(ip_address, view=view)
92
+ if zone is None:
93
+ zones = get_zones(ip_address, view=view)
94
+ else:
95
+ zones = [zone]
96
+
97
+ if ip_address.pk is not None:
98
+ for record in ip_address.netbox_dns_records.filter(zone__in=zones):
99
+ if (
100
+ record.fqdn != ip_address.dns_name
101
+ or record.value != ip_address.address.ip
102
+ or record.status != _get_record_status(ip_address)
103
+ ):
104
+ record.update_from_ip_address(ip_address)
105
+
106
+ if record is not None:
107
+ record.clean()
108
+
109
+ zones = _zone.Zone.objects.filter(pk__in=[zone.pk for zone in zones]).exclude(
110
+ pk__in=set(
111
+ ip_address.netbox_dns_records.all().values_list("zone", flat=True)
112
+ )
113
+ )
114
+
115
+ for zone in zones:
116
+ record = _record.Record.create_from_ip_address(
117
+ ip_address,
118
+ zone,
119
+ )
120
+
121
+ if record is not None:
122
+ record.clean()
123
+
124
+
125
+ def update_dns_records(ip_address):
126
+ if ip_address.dns_name == "":
127
+ delete_dns_records(ip_address)
128
+ return
129
+
130
+ zones = get_zones(ip_address)
92
131
 
93
132
  if ip_address.pk is not None:
94
133
  for record in ip_address.netbox_dns_records.all():
95
134
  if record.zone not in zones:
96
- if commit:
97
- record.delete()
135
+ record.delete()
98
136
  continue
99
137
 
100
138
  if (
@@ -105,13 +143,12 @@ def update_dns_records(ip_address, commit=True, view=None):
105
143
  record.update_from_ip_address(ip_address)
106
144
 
107
145
  if record is not None:
108
- if commit:
109
- record.save()
110
- else:
111
- record.clean()
146
+ record.save()
112
147
 
113
- zones = set(zones).difference(
114
- {record.zone for record in ip_address.netbox_dns_records.all()}
148
+ zones = _zone.Zone.objects.filter(pk__in=[zone.pk for zone in zones]).exclude(
149
+ pk__in=set(
150
+ ip_address.netbox_dns_records.all().values_list("zone", flat=True)
151
+ )
115
152
  )
116
153
 
117
154
  for zone in zones:
@@ -121,10 +158,7 @@ def update_dns_records(ip_address, commit=True, view=None):
121
158
  )
122
159
 
123
160
  if record is not None:
124
- if commit:
125
- record.save()
126
- else:
127
- record.clean()
161
+ record.save()
128
162
 
129
163
 
130
164
  def delete_dns_records(ip_address):
@@ -203,3 +237,20 @@ def get_ip_addresses_by_zone(zone):
203
237
  queryset = get_ip_addresses_by_view(zone.view)
204
238
 
205
239
  return queryset.filter(dns_name__regex=rf"\.{re.escape(zone.name)}\.?$")
240
+
241
+
242
+ def check_record_permission(add=True, change=True, delete=True):
243
+ checks = locals()
244
+
245
+ request = current_request.get()
246
+
247
+ if request is None:
248
+ return True
249
+
250
+ return all(
251
+ (
252
+ request.user.has_perm(f"nebox_dns.{perm}_record")
253
+ for perm, check in locals().items()
254
+ if check
255
+ )
256
+ )
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "netbox-plugin-dns"
3
- version = "1.1.0-beta1"
3
+ version = "1.1.0b2"
4
4
  description = "NetBox DNS is a NetBox plugin for managing DNS data."
5
5
  authors = ["Peter Eckel <pete@netbox-dns.org>"]
6
6
  homepage = "https://github.com/peteeckel/netbox-plugin-dns"
@@ -11,7 +11,7 @@ packages = [{include = "netbox_dns"}]
11
11
  exclude = ["netbox_dns/tests/*"]
12
12
  keywords = ["netbox", "netbox-plugin", "dns"]
13
13
  classifiers = [
14
- "Development Status :: 4 - Beta"
14
+ "Development Status :: 5 - Production/Stable"
15
15
  ]
16
16
 
17
17
  [tool.poetry.dependencies]