netbox-plugin-dns 1.1.0b5__tar.gz → 1.1.0b7__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 (144) hide show
  1. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/PKG-INFO +2 -1
  2. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/README.md +1 -0
  3. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/__init__.py +2 -1
  4. netbox_plugin_dns-1.1.0b7/netbox_dns/management/commands/rebuild_dnssync.py +18 -0
  5. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/models/record.py +27 -16
  6. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/models/zone.py +35 -18
  7. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/signals/ipam_dnssync.py +6 -2
  8. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/tables/record.py +0 -2
  9. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/utilities/ipam_dnssync.py +34 -19
  10. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/validators/dns_name.py +9 -0
  11. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/views/record.py +0 -4
  12. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/pyproject.toml +1 -1
  13. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/LICENSE +0 -0
  14. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/api/nested_serializers.py +0 -0
  15. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/api/serializers.py +0 -0
  16. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/api/serializers_/__init__.py +0 -0
  17. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/api/serializers_/contact.py +0 -0
  18. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/api/serializers_/nameserver.py +0 -0
  19. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/api/serializers_/prefix.py +0 -0
  20. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/api/serializers_/record.py +0 -0
  21. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/api/serializers_/record_template.py +0 -0
  22. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/api/serializers_/registrar.py +0 -0
  23. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/api/serializers_/view.py +0 -0
  24. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/api/serializers_/zone.py +0 -0
  25. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/api/serializers_/zone_template.py +0 -0
  26. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/api/urls.py +0 -0
  27. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/api/views.py +0 -0
  28. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/apps.py +0 -0
  29. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/choices/__init__.py +0 -0
  30. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/choices/record.py +0 -0
  31. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/choices/zone.py +0 -0
  32. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/fields/__init__.py +0 -0
  33. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/fields/address.py +0 -0
  34. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/fields/ipam.py +0 -0
  35. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/fields/network.py +0 -0
  36. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/fields/rfc2317.py +0 -0
  37. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/filtersets/__init__.py +0 -0
  38. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/filtersets/contact.py +0 -0
  39. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/filtersets/nameserver.py +0 -0
  40. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/filtersets/record.py +0 -0
  41. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/filtersets/record_template.py +0 -0
  42. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/filtersets/registrar.py +0 -0
  43. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/filtersets/view.py +0 -0
  44. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/filtersets/zone.py +0 -0
  45. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/filtersets/zone_template.py +0 -0
  46. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/forms/__init__.py +0 -0
  47. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/forms/contact.py +0 -0
  48. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/forms/nameserver.py +0 -0
  49. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/forms/record.py +0 -0
  50. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/forms/record_template.py +0 -0
  51. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/forms/registrar.py +0 -0
  52. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/forms/view.py +0 -0
  53. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/forms/zone.py +0 -0
  54. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/forms/zone_template.py +0 -0
  55. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/graphql/__init__.py +0 -0
  56. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/graphql/filters.py +0 -0
  57. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/graphql/schema.py +0 -0
  58. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/graphql/types.py +0 -0
  59. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/management/commands/cleanup_database.py +0 -0
  60. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/management/commands/cleanup_rrset_ttl.py +0 -0
  61. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/management/commands/setup_dnssync.py +0 -0
  62. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/management/commands/update_soa.py +0 -0
  63. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/migrations/0001_squashed_netbox_dns_0_15.py +0 -0
  64. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/migrations/0001_squashed_netbox_dns_0_22.py +0 -0
  65. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/migrations/0002_contact_description_registrar_description.py +0 -0
  66. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/migrations/0003_default_view.py +0 -0
  67. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/migrations/0004_create_and_assign_default_view.py +0 -0
  68. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/migrations/0005_alter_zone_view_not_null.py +0 -0
  69. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/migrations/0006_templating.py +0 -0
  70. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/migrations/0007_view_prefixes.py +0 -0
  71. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/migrations/0020_netbox_3_4.py +0 -0
  72. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/migrations/0021_record_ip_address.py +0 -0
  73. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/migrations/0022_search.py +0 -0
  74. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/migrations/0023_alter_record_value.py +0 -0
  75. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/migrations/0024_tenancy.py +0 -0
  76. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/migrations/0025_ipam_coupling_cf.py +0 -0
  77. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/migrations/0026_domain_registration.py +0 -0
  78. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/migrations/0027_alter_registrar_iana_id.py +0 -0
  79. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/migrations/0028_rfc2317_fields.py +0 -0
  80. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/migrations/0029_record_fqdn.py +0 -0
  81. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/migrations/__init__.py +0 -0
  82. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/mixins/__init__.py +0 -0
  83. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/mixins/object_modification.py +0 -0
  84. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/models/__init__.py +0 -0
  85. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/models/contact.py +0 -0
  86. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/models/nameserver.py +0 -0
  87. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/models/record_template.py +0 -0
  88. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/models/registrar.py +0 -0
  89. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/models/view.py +0 -0
  90. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/models/zone_template.py +0 -0
  91. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/navigation.py +0 -0
  92. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/signals/__init__.py +0 -0
  93. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/tables/__init__.py +0 -0
  94. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/tables/contact.py +0 -0
  95. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/tables/ipam_dnssync.py +0 -0
  96. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/tables/nameserver.py +0 -0
  97. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/tables/record_template.py +0 -0
  98. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/tables/registrar.py +0 -0
  99. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/tables/view.py +0 -0
  100. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/tables/zone.py +0 -0
  101. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/tables/zone_template.py +0 -0
  102. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/template_content.py +0 -0
  103. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/templates/netbox_dns/contact.html +0 -0
  104. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/templates/netbox_dns/nameserver.html +0 -0
  105. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/templates/netbox_dns/record/managed.html +0 -0
  106. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/templates/netbox_dns/record/related.html +0 -0
  107. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/templates/netbox_dns/record.html +0 -0
  108. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/templates/netbox_dns/recordtemplate.html +0 -0
  109. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/templates/netbox_dns/registrar.html +0 -0
  110. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/templates/netbox_dns/view/button.html +0 -0
  111. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/templates/netbox_dns/view/prefix.html +0 -0
  112. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/templates/netbox_dns/view/related.html +0 -0
  113. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/templates/netbox_dns/view.html +0 -0
  114. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/templates/netbox_dns/zone/base.html +0 -0
  115. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/templates/netbox_dns/zone/child.html +0 -0
  116. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/templates/netbox_dns/zone/child_zone.html +0 -0
  117. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/templates/netbox_dns/zone/managed_record.html +0 -0
  118. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/templates/netbox_dns/zone/record.html +0 -0
  119. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/templates/netbox_dns/zone/registration.html +0 -0
  120. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/templates/netbox_dns/zone/rfc2317_child_zone.html +0 -0
  121. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/templates/netbox_dns/zone.html +0 -0
  122. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/templates/netbox_dns/zonetemplate.html +0 -0
  123. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/urls/__init__.py +0 -0
  124. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/urls/contact.py +0 -0
  125. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/urls/nameserver.py +0 -0
  126. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/urls/record.py +0 -0
  127. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/urls/record_template.py +0 -0
  128. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/urls/registrar.py +0 -0
  129. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/urls/view.py +0 -0
  130. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/urls/zone.py +0 -0
  131. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/urls/zone_template.py +0 -0
  132. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/utilities/__init__.py +0 -0
  133. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/utilities/conversions.py +0 -0
  134. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/validators/__init__.py +0 -0
  135. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/validators/dns_value.py +0 -0
  136. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/validators/rfc2317.py +0 -0
  137. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/views/__init__.py +0 -0
  138. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/views/contact.py +0 -0
  139. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/views/nameserver.py +0 -0
  140. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/views/record_template.py +0 -0
  141. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/views/registrar.py +0 -0
  142. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/views/view.py +0 -0
  143. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/netbox_dns/views/zone.py +0 -0
  144. {netbox_plugin_dns-1.1.0b5 → netbox_plugin_dns-1.1.0b7}/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.0b5
3
+ Version: 1.1.0b7
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
@@ -48,6 +48,7 @@ The main focus of the plugin is to ensure the quality of the data stored in it.
48
48
  * Validation of record types such as CNAME and singletons, to ensure DNS zone validity
49
49
  * Support for [RFC 2317](https://datatracker.ietf.org/doc/html/rfc2317) delegation of PTR zones for IPv4 subnets longer than 24 bits
50
50
  * 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
51
+ * 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
51
52
 
52
53
  Other main features include:
53
54
 
@@ -28,6 +28,7 @@ The main focus of the plugin is to ensure the quality of the data stored in it.
28
28
  * Validation of record types such as CNAME and singletons, to ensure DNS zone validity
29
29
  * Support for [RFC 2317](https://datatracker.ietf.org/doc/html/rfc2317) delegation of PTR zones for IPv4 subnets longer than 24 bits
30
30
  * 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
31
+ * 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
31
32
 
32
33
  Other main features include:
33
34
 
@@ -5,7 +5,7 @@ from ipam.choices import IPAddressStatusChoices
5
5
 
6
6
  from netbox_dns.choices import RecordTypeChoices
7
7
 
8
- __version__ = "1.1.0b5"
8
+ __version__ = "1.1.0b7"
9
9
 
10
10
 
11
11
  class DNSConfig(PluginConfig):
@@ -32,6 +32,7 @@ class DNSConfig(PluginConfig):
32
32
  IPAddressStatusChoices.STATUS_SLAAC,
33
33
  ],
34
34
  "dnssync_conflict_deactivate": False,
35
+ "dnssync_minimum_zone_labels": 2,
35
36
  "tolerate_characters_in_zone_labels": "",
36
37
  "tolerate_underscores_in_labels": False,
37
38
  "tolerate_underscores_in_hostnames": False, # Deprecated, will be removed in 1.2.0
@@ -0,0 +1,18 @@
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
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
+ update_dns_records(ip_address)
@@ -493,20 +493,33 @@ class Record(ObjectModificationMixin, NetBoxModel):
493
493
  **data,
494
494
  )
495
495
 
496
+ def update_fqdn(self, zone=None):
497
+ if zone is None:
498
+ zone = self.zone
499
+
500
+ _zone = dns_name.from_text(zone.name, origin=dns_name.root)
501
+ name = dns_name.from_text(self.name, origin=None)
502
+ fqdn = dns_name.from_text(self.name, origin=_zone)
503
+
504
+ if not fqdn.is_subdomain(_zone):
505
+ raise ValidationError(
506
+ {
507
+ "name": f"{self.name} is not a name in {zone.name}",
508
+ }
509
+ )
510
+
511
+ _zone.to_unicode()
512
+ name.to_unicode()
513
+
514
+ self.name = name.relativize(_zone).to_text()
515
+ self.fqdn = fqdn.to_text()
516
+
496
517
  def validate_name(self, new_zone=None):
497
518
  if new_zone is None:
498
519
  new_zone = self.zone
499
520
 
500
521
  try:
501
- _zone = dns_name.from_text(new_zone.name, origin=dns_name.root)
502
- name = dns_name.from_text(self.name, origin=None)
503
- fqdn = dns_name.from_text(self.name, origin=_zone)
504
-
505
- _zone.to_unicode()
506
- name.to_unicode()
507
-
508
- self.name = name.relativize(_zone).to_text()
509
- self.fqdn = fqdn.to_text()
522
+ self.update_fqdn(zone=new_zone)
510
523
 
511
524
  except dns.exception.DNSException as exc:
512
525
  raise ValidationError(
@@ -515,13 +528,6 @@ class Record(ObjectModificationMixin, NetBoxModel):
515
528
  }
516
529
  )
517
530
 
518
- if not fqdn.is_subdomain(_zone):
519
- raise ValidationError(
520
- {
521
- "name": f"{self.name} is not a name in {new_zone.name}",
522
- }
523
- )
524
-
525
531
  if self.type not in get_plugin_config(
526
532
  "netbox_dns", "tolerate_non_rfc1035_types", default=[]
527
533
  ):
@@ -613,6 +619,11 @@ class Record(ObjectModificationMixin, NetBoxModel):
613
619
  if not get_plugin_config("netbox_dns", "enforce_unique_rrset_ttl", False):
614
620
  return
615
621
 
622
+ if self.ipam_ip_address is not None and get_plugin_config(
623
+ "netbox_dns", "dnssync_conflict_deactivate", False
624
+ ):
625
+ return
626
+
616
627
  if self.type == RecordTypeChoices.PTR and self.managed:
617
628
  return
618
629
 
@@ -3,6 +3,7 @@ from math import ceil
3
3
  from datetime import datetime
4
4
 
5
5
  from dns import name as dns_name
6
+ from dns.exception import DNSException
6
7
  from dns.rdtypes.ANY import SOA
7
8
  from dns.exception import DNSException
8
9
 
@@ -37,6 +38,7 @@ from netbox_dns.utilities import (
37
38
  )
38
39
  from netbox_dns.validators import (
39
40
  validate_fqdn,
41
+ validate_rname,
40
42
  validate_domain_name,
41
43
  )
42
44
  from netbox_dns.mixins import ObjectModificationMixin
@@ -78,6 +80,7 @@ class Zone(ObjectModificationMixin, NetBoxModel):
78
80
  super().__init__(*args, **kwargs)
79
81
 
80
82
  self._soa_serial_dirty = False
83
+ self._ip_addresses_checked = False
81
84
 
82
85
  view = models.ForeignKey(
83
86
  to="View",
@@ -280,7 +283,7 @@ class Zone(ObjectModificationMixin, NetBoxModel):
280
283
  else:
281
284
  try:
282
285
  name = dns_name.from_text(self.name, origin=None).to_unicode()
283
- except dns_name.IDNAException:
286
+ except DNSException:
284
287
  name = self.name
285
288
 
286
289
  try:
@@ -308,6 +311,14 @@ class Zone(ObjectModificationMixin, NetBoxModel):
308
311
  def soa_serial_dirty(self, soa_serial_dirty):
309
312
  self._soa_serial_dirty = soa_serial_dirty
310
313
 
314
+ @property
315
+ def ip_addresses_checked(self):
316
+ return self._ip_addresses_checked
317
+
318
+ @ip_addresses_checked.setter
319
+ def ip_addresses_checked(self, ip_addresses_checked):
320
+ self._ip_addresses_checked = ip_addresses_checked
321
+
311
322
  @property
312
323
  def display_name(self):
313
324
  return name_to_unicode(self.name)
@@ -621,7 +632,7 @@ class Zone(ObjectModificationMixin, NetBoxModel):
621
632
  raise ValidationError("soa_rname not set and no default value defined")
622
633
  try:
623
634
  dns_name.from_text(self.soa_rname, origin=dns_name.root)
624
- validate_fqdn(self.soa_rname)
635
+ validate_rname(self.soa_rname)
625
636
  except (DNSException, ValidationError) as exc:
626
637
  raise ValidationError(
627
638
  {
@@ -653,24 +664,26 @@ class Zone(ObjectModificationMixin, NetBoxModel):
653
664
  }
654
665
  )
655
666
 
656
- if old_zone.name != self.name or old_zone.view != self.view:
657
- for ip_address in get_ip_addresses_by_zone(self):
658
- try:
659
- check_dns_records(ip_address, zone=self)
660
- except ValidationError as exc:
661
- raise ValidationError(exc.messages)
662
-
667
+ if (
668
+ not self.ip_addresses_checked
669
+ and old_zone.name != self.name
670
+ or old_zone.view != self.view
671
+ ):
663
672
  ip_addresses = IPAddress.objects.filter(
664
673
  netbox_dns_records__in=self.record_set.filter(
665
674
  ipam_ip_address__isnull=False
666
675
  )
667
676
  )
668
- for ip_address in ip_addresses:
677
+ ip_addresses |= get_ip_addresses_by_zone(self)
678
+
679
+ for ip_address in ip_addresses.distinct():
669
680
  try:
670
681
  check_dns_records(ip_address, zone=self)
671
682
  except ValidationError as exc:
672
683
  raise ValidationError(exc.messages)
673
684
 
685
+ self.ip_addresses_checked = True
686
+
674
687
  if self.is_reverse_zone:
675
688
  self.arpa_network = self.network_from_name
676
689
 
@@ -785,12 +798,13 @@ class Zone(ObjectModificationMixin, NetBoxModel):
785
798
 
786
799
  elif changed_fields is not None and {"name", "view", "status"} & changed_fields:
787
800
  for address_record in self.record_set.filter(
788
- type__in=(RecordTypeChoices.A, RecordTypeChoices.AAAA)
801
+ type__in=(RecordTypeChoices.A, RecordTypeChoices.AAAA),
802
+ ipam_ip_address__isnull=True,
789
803
  ):
790
804
  address_record.save(update_fields=["ptr_record"])
791
805
 
792
806
  if changed_fields is not None and "name" in changed_fields:
793
- for _record in self.record_set.all():
807
+ for _record in self.record_set.filter(ipam_ip_address__isnull=True):
794
808
  _record.save(
795
809
  update_fields=["fqdn"],
796
810
  save_zone_serial=False,
@@ -799,13 +813,14 @@ class Zone(ObjectModificationMixin, NetBoxModel):
799
813
  )
800
814
 
801
815
  if changed_fields is None or {"name", "view"} & changed_fields:
802
- update_ip_addresses = IPAddress.objects.filter(
803
- pk__in=self.record_set.filter(
816
+ ip_addresses = IPAddress.objects.filter(
817
+ netbox_dns_records__in=self.record_set.filter(
804
818
  ipam_ip_address__isnull=False
805
- ).values_list("ipam_ip_address", flat=True)
819
+ )
806
820
  )
807
- update_ip_addresses |= get_ip_addresses_by_zone(self)
808
- for ip_address in update_ip_addresses:
821
+ ip_addresses |= get_ip_addresses_by_zone(self)
822
+
823
+ for ip_address in ip_addresses.distinct():
809
824
  update_dns_records(ip_address)
810
825
 
811
826
  self.save_soa_serial()
@@ -848,7 +863,9 @@ class Zone(ObjectModificationMixin, NetBoxModel):
848
863
  netbox_dns_records__in=self.record_set.filter(
849
864
  ipam_ip_address__isnull=False
850
865
  )
851
- ).values_list("pk", flat=True)
866
+ )
867
+ .distinct()
868
+ .values_list("pk", flat=True)
852
869
  )
853
870
 
854
871
  super().delete(*args, **kwargs)
@@ -215,6 +215,10 @@ def ipam_dnssync_view_prefix_changed(**kwargs):
215
215
  return
216
216
 
217
217
  check_view = action != "post_remove"
218
+
219
+ ip_addresses = IPAddress.objects.none()
218
220
  for prefix in Prefix.objects.filter(pk__in=kwargs.get("pk_set")):
219
- for ip_address in get_ip_addresses_by_prefix(prefix, check_view=check_view):
220
- update_dns_records(ip_address)
221
+ ip_addresses |= get_ip_addresses_by_prefix(prefix, check_view=check_view)
222
+
223
+ for ip_address in ip_addresses.distinct():
224
+ update_dns_records(ip_address)
@@ -1,5 +1,4 @@
1
1
  import django_tables2 as tables
2
- from django_tables2.utils import Accessor
3
2
  from django.utils.html import format_html
4
3
 
5
4
 
@@ -9,7 +8,6 @@ from netbox.tables import (
9
8
  TagColumn,
10
9
  ActionsColumn,
11
10
  )
12
- from ipam.lookups import Host, Inet
13
11
  from tenancy.tables import TenancyColumnsMixin
14
12
 
15
13
  from netbox_dns.models import Record
@@ -44,7 +44,7 @@ def _get_assigned_views(ip_address):
44
44
 
45
45
  def _get_record_status(ip_address):
46
46
  return (
47
- RecordStatusChoices.STATE_ACTIVE
47
+ RecordStatusChoices.STATUS_ACTIVE
48
48
  if ip_address.status
49
49
  in settings.PLUGINS_CONFIG["netbox_dns"].get(
50
50
  "dnssync_ipaddress_active_status", []
@@ -59,6 +59,20 @@ def _valid_entry(ip_address, zone):
59
59
  ).is_subdomain(dns_name.from_text(zone.name))
60
60
 
61
61
 
62
+ def _match_data(ip_address, record):
63
+ cf_disable_ptr = ip_address.custom_field_data.get(
64
+ "ipaddress_dns_record_disable_ptr"
65
+ )
66
+
67
+ return (
68
+ record.fqdn.rstrip(".") == ip_address.dns_name.rstrip(".")
69
+ and record.value == str(ip_address.address.ip)
70
+ and record.status == _get_record_status(ip_address)
71
+ and record.ttl == ip_address.custom_field_data.get("ipaddress_dns_record_ttl")
72
+ and (cf_disable_ptr is None or record.disable_ptr == cf_disable_ptr)
73
+ )
74
+
75
+
62
76
  def get_zones(ip_address, view=None, old_zone=None):
63
77
  if view is None:
64
78
  views = _get_assigned_views(ip_address)
@@ -68,9 +82,13 @@ def get_zones(ip_address, view=None, old_zone=None):
68
82
  else:
69
83
  views = [view]
70
84
 
85
+ min_labels = settings.PLUGINS_CONFIG["netbox_dns"].get(
86
+ "dnssync_minimum_zone_labels", 2
87
+ )
71
88
  fqdn = dns_name.from_text(ip_address.dns_name)
72
89
  zone_name_candidates = [
73
- fqdn.split(i)[1].to_text().rstrip(".") for i in range(3, len(fqdn.labels))
90
+ fqdn.split(i)[1].to_text().rstrip(".")
91
+ for i in range(min_labels + 1, len(fqdn.labels))
74
92
  ]
75
93
 
76
94
  zones = _zone.Zone.objects.filter(
@@ -104,11 +122,7 @@ def check_dns_records(ip_address, zone=None, view=None):
104
122
 
105
123
  if ip_address.pk is not None:
106
124
  for record in ip_address.netbox_dns_records.filter(zone__in=zones):
107
- if (
108
- record.fqdn != ip_address.dns_name
109
- or record.value != ip_address.address.ip
110
- or record.status != _get_record_status(ip_address)
111
- ):
125
+ if not _match_data(ip_address, record):
112
126
  record.update_from_ip_address(ip_address)
113
127
 
114
128
  if record is not None:
@@ -117,9 +131,7 @@ def check_dns_records(ip_address, zone=None, view=None):
117
131
  zones = _zone.Zone.objects.filter(
118
132
  pk__in=[zone.pk for zone in zones]
119
133
  ).exclude(
120
- pk__in=set(
121
- ip_address.netbox_dns_records.all().values_list("zone", flat=True)
122
- )
134
+ pk__in=set(ip_address.netbox_dns_records.values_list("zone", flat=True))
123
135
  )
124
136
 
125
137
  for zone in zones:
@@ -155,15 +167,14 @@ def update_dns_records(ip_address):
155
167
 
156
168
  if ip_address.pk is not None:
157
169
  for record in ip_address.netbox_dns_records.all():
158
- if record.zone not in zones:
170
+ if record.zone not in zones or ip_address.custom_field_data.get(
171
+ "ipaddress_dns_disabled"
172
+ ):
159
173
  record.delete()
160
174
  continue
161
175
 
162
- if (
163
- record.fqdn != ip_address.dns_name
164
- or record.value != ip_address.address.ip
165
- or record.status != _get_record_status(ip_address)
166
- ):
176
+ record.update_fqdn()
177
+ if not _match_data(ip_address, record):
167
178
  record.update_from_ip_address(ip_address)
168
179
 
169
180
  if record is not None:
@@ -217,7 +228,9 @@ def get_ip_addresses_by_prefix(prefix, check_view=True):
217
228
  vrf=prefix.vrf, address__net_host_contained=prefix.prefix
218
229
  )
219
230
 
220
- for exclude_child in prefix.get_children().filter(netbox_dns_views__isnull=False):
231
+ for exclude_child in (
232
+ prefix.get_children().filter(netbox_dns_views__isnull=False).distinct()
233
+ ):
221
234
  queryset = queryset.exclude(
222
235
  vrf=exclude_child.vrf,
223
236
  address__net_host_contained=exclude_child.prefix,
@@ -258,9 +271,11 @@ def get_ip_addresses_by_zone(zone):
258
271
  are the IPAddress objects in prefixes assigned to the same view, if the
259
272
  'dns_name' attribute of the IPAddress object ends in the zone's name.
260
273
  """
261
- queryset = get_ip_addresses_by_view(zone.view)
274
+ queryset = get_ip_addresses_by_view(zone.view).filter(
275
+ dns_name__regex=rf"\.{re.escape(zone.name)}\.?$"
276
+ )
262
277
 
263
- return queryset.filter(dns_name__regex=rf"\.{re.escape(zone.name)}\.?$")
278
+ return queryset
264
279
 
265
280
 
266
281
  def check_record_permission(add=True, change=True, delete=True):
@@ -7,6 +7,7 @@ from netbox.plugins.utils import get_plugin_config
7
7
 
8
8
  __all__ = (
9
9
  "validate_fqdn",
10
+ "validate_rname",
10
11
  "validate_generic_name",
11
12
  "validate_domain_name",
12
13
  )
@@ -57,6 +58,14 @@ def validate_fqdn(name, always_tolerant=False):
57
58
  raise ValidationError(f"{name} is not a valid fully qualified DNS host name")
58
59
 
59
60
 
61
+ def validate_rname(name, always_tolerant=False):
62
+ label, zone_label = _get_label(always_tolerant=always_tolerant)
63
+ regex = rf"^(\*|{label})(\\\.{label})*(\.{zone_label}){{2,}}\.?$"
64
+
65
+ if not re.match(regex, name, flags=re.IGNORECASE) or _has_invalid_double_dash(name):
66
+ raise ValidationError(f"{name} is not a valid RNAME")
67
+
68
+
60
69
  def validate_generic_name(
61
70
  name, tolerate_leading_underscores=False, always_tolerant=False
62
71
  ):
@@ -1,10 +1,6 @@
1
1
  from dns import name as dns_name
2
2
 
3
- from django.db.models import F, Q, Case, When, OuterRef, Subquery
4
-
5
3
  from netbox.views import generic
6
- from ipam.fields import IPAddressField
7
- from ipam.models import IPAddress
8
4
 
9
5
  from netbox_dns.filtersets import RecordFilterSet
10
6
  from netbox_dns.forms import (
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "netbox-plugin-dns"
3
- version = "1.1.0b5"
3
+ version = "1.1.0b7"
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"