nautobot 2.3.0b1__py3-none-any.whl → 2.3.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of nautobot might be problematic. Click here for more details.

Files changed (399) hide show
  1. nautobot/cloud/factory.py +2 -0
  2. nautobot/cloud/filters.py +3 -0
  3. nautobot/cloud/forms.py +8 -2
  4. nautobot/cloud/migrations/0001_initial.py +1 -1
  5. nautobot/cloud/models.py +1 -2
  6. nautobot/cloud/tables.py +1 -17
  7. nautobot/cloud/templates/cloud/cloudnetwork_retrieve.html +1 -7
  8. nautobot/cloud/templates/cloud/cloudresourcetype_retrieve.html +11 -0
  9. nautobot/cloud/templates/cloud/cloudservice_retrieve.html +4 -0
  10. nautobot/cloud/tests/test_filters.py +12 -0
  11. nautobot/cloud/tests/test_views.py +17 -0
  12. nautobot/cloud/views.py +1 -1
  13. nautobot/core/celery/__init__.py +5 -2
  14. nautobot/core/celery/schedulers.py +18 -0
  15. nautobot/core/filters.py +15 -1
  16. nautobot/core/forms/forms.py +10 -2
  17. nautobot/core/graphql/generators.py +2 -2
  18. nautobot/core/graphql/schema.py +6 -14
  19. nautobot/core/jobs/__init__.py +4 -1
  20. nautobot/core/management/commands/generate_test_data.py +2 -2
  21. nautobot/core/models/__init__.py +2 -2
  22. nautobot/core/settings.py +13 -2
  23. nautobot/core/settings.yaml +19 -5
  24. nautobot/core/tables.py +4 -1
  25. nautobot/core/templates/generic/object_retrieve.html +6 -6
  26. nautobot/core/templates/home.html +4 -3
  27. nautobot/core/templates/inc/computed_fields/panel_data.html +36 -24
  28. nautobot/core/templates/inc/object_details_advanced_panel.html +1 -1
  29. nautobot/core/templates/nautobot_config.py.j2 +15 -0
  30. nautobot/core/templatetags/buttons.py +1 -1
  31. nautobot/core/testing/filters.py +12 -1
  32. nautobot/core/tests/integration/test_general_functionality.py +1 -1
  33. nautobot/core/tests/test_jobs.py +74 -1
  34. nautobot/core/views/__init__.py +1 -1
  35. nautobot/core/views/generic.py +1 -1
  36. nautobot/core/views/mixins.py +1 -1
  37. nautobot/core/views/utils.py +11 -9
  38. nautobot/dcim/factory.py +7 -4
  39. nautobot/dcim/filters/__init__.py +4 -0
  40. nautobot/dcim/forms.py +24 -0
  41. nautobot/dcim/migrations/0061_module_models.py +1 -0
  42. nautobot/dcim/models/device_components.py +7 -0
  43. nautobot/dcim/models/devices.py +18 -19
  44. nautobot/dcim/models/racks.py +0 -1
  45. nautobot/dcim/tables/devices.py +24 -10
  46. nautobot/dcim/tables/devicetypes.py +1 -1
  47. nautobot/dcim/templates/dcim/device/base.html +1 -1
  48. nautobot/dcim/templates/dcim/device.html +15 -3
  49. nautobot/dcim/templates/dcim/deviceredundancygroup_retrieve.html +6 -0
  50. nautobot/dcim/templates/dcim/moduletype_retrieve.html +17 -0
  51. nautobot/dcim/templates/dcim/softwareimagefile_retrieve.html +15 -3
  52. nautobot/dcim/tests/test_api.py +2 -0
  53. nautobot/dcim/tests/test_filters.py +14 -7
  54. nautobot/dcim/tests/test_forms.py +54 -0
  55. nautobot/dcim/tests/test_models.py +40 -1
  56. nautobot/dcim/tests/test_views.py +45 -2
  57. nautobot/dcim/utils.py +9 -6
  58. nautobot/dcim/views.py +4 -1
  59. nautobot/extras/api/serializers.py +2 -1
  60. nautobot/extras/api/views.py +7 -59
  61. nautobot/extras/factory.py +50 -12
  62. nautobot/extras/filters/__init__.py +18 -3
  63. nautobot/extras/forms/base.py +10 -4
  64. nautobot/extras/forms/forms.py +7 -0
  65. nautobot/extras/forms/mixins.py +2 -2
  66. nautobot/extras/homepage.py +12 -2
  67. nautobot/extras/jobs.py +2 -2
  68. nautobot/extras/management/__init__.py +3 -0
  69. nautobot/extras/migrations/0111_metadata.py +4 -4
  70. nautobot/extras/migrations/0114_computedfield_grouping.py +17 -0
  71. nautobot/extras/migrations/0115_scheduledjob_time_zone.py +23 -0
  72. nautobot/extras/models/customfields.py +54 -0
  73. nautobot/extras/models/jobs.py +105 -9
  74. nautobot/extras/models/metadata.py +18 -18
  75. nautobot/extras/models/models.py +2 -0
  76. nautobot/extras/signals.py +14 -1
  77. nautobot/extras/tables.py +77 -18
  78. nautobot/extras/templates/extras/computedfield.html +4 -0
  79. nautobot/extras/templates/extras/job_detail.html +11 -0
  80. nautobot/extras/templates/extras/scheduledjob.html +13 -2
  81. nautobot/extras/tests/test_api.py +33 -27
  82. nautobot/extras/tests/test_filters.py +57 -1
  83. nautobot/extras/tests/test_jobs.py +2 -2
  84. nautobot/extras/tests/test_models.py +319 -19
  85. nautobot/extras/tests/test_views.py +26 -5
  86. nautobot/extras/utils.py +35 -6
  87. nautobot/extras/views.py +35 -51
  88. nautobot/ipam/api/views.py +9 -2
  89. nautobot/ipam/choices.py +17 -0
  90. nautobot/ipam/factory.py +6 -0
  91. nautobot/ipam/filters.py +2 -2
  92. nautobot/ipam/forms.py +6 -4
  93. nautobot/ipam/migrations/0048_vrf_status.py +23 -0
  94. nautobot/ipam/migrations/0049_vrf_data_migration.py +25 -0
  95. nautobot/ipam/models.py +11 -20
  96. nautobot/ipam/querysets.py +26 -0
  97. nautobot/ipam/tables.py +7 -2
  98. nautobot/ipam/templates/ipam/vrf.html +4 -0
  99. nautobot/ipam/templates/ipam/vrf_edit.html +1 -0
  100. nautobot/ipam/tests/test_api.py +33 -3
  101. nautobot/ipam/tests/test_models.py +89 -2
  102. nautobot/ipam/tests/test_views.py +3 -0
  103. nautobot/ipam/views.py +10 -15
  104. nautobot/project-static/css/base.css +7 -0
  105. nautobot/project-static/docs/404.html +18 -18
  106. nautobot/project-static/docs/apps/index.html +18 -18
  107. nautobot/project-static/docs/apps/nautobot-apps.html +18 -18
  108. nautobot/project-static/docs/assets/stylesheets/main.3cba04c6.min.css +1 -0
  109. nautobot/project-static/docs/assets/stylesheets/main.3cba04c6.min.css.map +1 -0
  110. nautobot/project-static/docs/code-reference/nautobot/apps/__init__.html +18 -18
  111. nautobot/project-static/docs/code-reference/nautobot/apps/admin.html +18 -18
  112. nautobot/project-static/docs/code-reference/nautobot/apps/api.html +66 -18
  113. nautobot/project-static/docs/code-reference/nautobot/apps/change_logging.html +18 -18
  114. nautobot/project-static/docs/code-reference/nautobot/apps/choices.html +18 -18
  115. nautobot/project-static/docs/code-reference/nautobot/apps/config.html +18 -18
  116. nautobot/project-static/docs/code-reference/nautobot/apps/constants.html +18 -18
  117. nautobot/project-static/docs/code-reference/nautobot/apps/datasources.html +18 -18
  118. nautobot/project-static/docs/code-reference/nautobot/apps/exceptions.html +66 -18
  119. nautobot/project-static/docs/code-reference/nautobot/apps/factory.html +34 -18
  120. nautobot/project-static/docs/code-reference/nautobot/apps/filters.html +82 -63
  121. nautobot/project-static/docs/code-reference/nautobot/apps/forms.html +75 -111
  122. nautobot/project-static/docs/code-reference/nautobot/apps/graphql.html +18 -18
  123. nautobot/project-static/docs/code-reference/nautobot/apps/jobs.html +34 -18
  124. nautobot/project-static/docs/code-reference/nautobot/apps/models.html +161 -18
  125. nautobot/project-static/docs/code-reference/nautobot/apps/querysets.html +18 -18
  126. nautobot/project-static/docs/code-reference/nautobot/apps/secrets.html +18 -18
  127. nautobot/project-static/docs/code-reference/nautobot/apps/tables.html +18 -18
  128. nautobot/project-static/docs/code-reference/nautobot/apps/testing.html +18 -18
  129. nautobot/project-static/docs/code-reference/nautobot/apps/ui.html +18 -18
  130. nautobot/project-static/docs/code-reference/nautobot/apps/urls.html +18 -18
  131. nautobot/project-static/docs/code-reference/nautobot/apps/utils.html +21 -19
  132. nautobot/project-static/docs/code-reference/nautobot/apps/views.html +34 -18
  133. nautobot/project-static/docs/development/apps/api/configuration-view.html +18 -18
  134. nautobot/project-static/docs/development/apps/api/database-backend-config.html +18 -18
  135. nautobot/project-static/docs/development/apps/api/models/django-admin.html +18 -18
  136. nautobot/project-static/docs/development/apps/api/models/global-search.html +18 -18
  137. nautobot/project-static/docs/development/apps/api/models/graphql.html +18 -18
  138. nautobot/project-static/docs/development/apps/api/models/index.html +33 -22
  139. nautobot/project-static/docs/development/apps/api/nautobot-app-config.html +18 -18
  140. nautobot/project-static/docs/development/apps/api/platform-features/custom-validators.html +18 -18
  141. nautobot/project-static/docs/development/apps/api/platform-features/filter-extensions.html +18 -18
  142. nautobot/project-static/docs/development/apps/api/platform-features/git-repository-content.html +18 -18
  143. nautobot/project-static/docs/development/apps/api/platform-features/index.html +18 -18
  144. nautobot/project-static/docs/development/apps/api/platform-features/jinja2-filters.html +18 -18
  145. nautobot/project-static/docs/development/apps/api/platform-features/jobs.html +18 -18
  146. nautobot/project-static/docs/development/apps/api/platform-features/populating-extensibility-features.html +18 -18
  147. nautobot/project-static/docs/development/apps/api/platform-features/secrets-providers.html +18 -18
  148. nautobot/project-static/docs/development/apps/api/platform-features/uniquely-identify-objects.html +18 -18
  149. nautobot/project-static/docs/development/apps/api/prometheus.html +18 -18
  150. nautobot/project-static/docs/development/apps/api/setup.html +18 -18
  151. nautobot/project-static/docs/development/apps/api/testing.html +18 -18
  152. nautobot/project-static/docs/development/apps/api/ui-extensions/banners.html +18 -18
  153. nautobot/project-static/docs/development/apps/api/ui-extensions/home-page.html +18 -18
  154. nautobot/project-static/docs/development/apps/api/ui-extensions/index.html +18 -18
  155. nautobot/project-static/docs/development/apps/api/ui-extensions/navigation.html +18 -18
  156. nautobot/project-static/docs/development/apps/api/ui-extensions/object-views.html +18 -18
  157. nautobot/project-static/docs/development/apps/api/views/base-template.html +18 -18
  158. nautobot/project-static/docs/development/apps/api/views/core-view-overrides.html +18 -18
  159. nautobot/project-static/docs/development/apps/api/views/django-generic-views.html +18 -18
  160. nautobot/project-static/docs/development/apps/api/views/help-documentation.html +18 -18
  161. nautobot/project-static/docs/development/apps/api/views/index.html +18 -18
  162. nautobot/project-static/docs/development/apps/api/views/nautobot-generic-views.html +18 -18
  163. nautobot/project-static/docs/development/apps/api/views/nautobotuiviewset.html +18 -18
  164. nautobot/project-static/docs/development/apps/api/views/nautobotuiviewsetrouter.html +18 -18
  165. nautobot/project-static/docs/development/apps/api/views/notes.html +18 -18
  166. nautobot/project-static/docs/development/apps/api/views/rest-api.html +18 -18
  167. nautobot/project-static/docs/development/apps/api/views/urls.html +18 -18
  168. nautobot/project-static/docs/development/apps/index.html +18 -18
  169. nautobot/project-static/docs/development/apps/migration/code-updates.html +18 -18
  170. nautobot/project-static/docs/development/apps/migration/dependency-updates.html +18 -18
  171. nautobot/project-static/docs/development/apps/migration/from-v1.html +18 -18
  172. nautobot/project-static/docs/development/apps/migration/model-updates/dcim.html +18 -18
  173. nautobot/project-static/docs/development/apps/migration/model-updates/extras.html +18 -18
  174. nautobot/project-static/docs/development/apps/migration/model-updates/global.html +18 -18
  175. nautobot/project-static/docs/development/apps/migration/model-updates/ipam.html +18 -18
  176. nautobot/project-static/docs/development/apps/porting-from-netbox.html +18 -18
  177. nautobot/project-static/docs/development/core/application-registry.html +18 -18
  178. nautobot/project-static/docs/development/core/best-practices.html +18 -18
  179. nautobot/project-static/docs/development/core/bootstrap-ui.html +18 -18
  180. nautobot/project-static/docs/development/core/caching.html +18 -18
  181. nautobot/project-static/docs/development/core/controllers.html +18 -18
  182. nautobot/project-static/docs/development/core/docker-compose-advanced-use-cases.html +18 -18
  183. nautobot/project-static/docs/development/core/generic-views.html +18 -18
  184. nautobot/project-static/docs/development/core/getting-started.html +18 -18
  185. nautobot/project-static/docs/development/core/homepage.html +18 -18
  186. nautobot/project-static/docs/development/core/index.html +29 -18
  187. nautobot/project-static/docs/development/core/model-checklist.html +26 -20
  188. nautobot/project-static/docs/development/core/model-features.html +18 -18
  189. nautobot/project-static/docs/development/core/natural-keys.html +18 -18
  190. nautobot/project-static/docs/development/core/navigation-menu.html +18 -18
  191. nautobot/project-static/docs/development/core/release-checklist.html +18 -18
  192. nautobot/project-static/docs/development/core/role-internals.html +18 -18
  193. nautobot/project-static/docs/development/core/settings.html +18 -18
  194. nautobot/project-static/docs/development/core/style-guide.html +19 -19
  195. nautobot/project-static/docs/development/core/templates.html +18 -18
  196. nautobot/project-static/docs/development/core/testing.html +18 -18
  197. nautobot/project-static/docs/development/core/user-preferences.html +18 -18
  198. nautobot/project-static/docs/development/index.html +18 -18
  199. nautobot/project-static/docs/development/jobs/index.html +393 -379
  200. nautobot/project-static/docs/development/jobs/migration/from-v1.html +18 -18
  201. nautobot/project-static/docs/index.html +9032 -13
  202. nautobot/project-static/docs/models/extras/metadatachoice.html +3 -3
  203. nautobot/project-static/docs/models/extras/metadatatype.html +3 -3
  204. nautobot/project-static/docs/models/extras/objectmetadata.html +3 -3
  205. nautobot/project-static/docs/objects.inv +0 -0
  206. nautobot/project-static/docs/overview/application_stack.html +18 -18
  207. nautobot/project-static/docs/overview/design_philosophy.html +20 -20
  208. nautobot/project-static/docs/overview/index.html +13 -9032
  209. nautobot/project-static/docs/release-notes/index.html +252 -19
  210. nautobot/project-static/docs/release-notes/version-1.0.html +18 -18
  211. nautobot/project-static/docs/release-notes/version-1.1.html +18 -18
  212. nautobot/project-static/docs/release-notes/version-1.2.html +18 -18
  213. nautobot/project-static/docs/release-notes/version-1.3.html +18 -18
  214. nautobot/project-static/docs/release-notes/version-1.4.html +18 -18
  215. nautobot/project-static/docs/release-notes/version-1.5.html +18 -18
  216. nautobot/project-static/docs/release-notes/version-1.6.html +18 -18
  217. nautobot/project-static/docs/release-notes/version-2.0.html +18 -18
  218. nautobot/project-static/docs/release-notes/version-2.1.html +18 -18
  219. nautobot/project-static/docs/release-notes/version-2.2.html +248 -111
  220. nautobot/project-static/docs/release-notes/version-2.3.html +775 -91
  221. nautobot/project-static/docs/requirements.txt +3 -3
  222. nautobot/project-static/docs/search/search_index.json +1 -1
  223. nautobot/project-static/docs/sitemap.xml +278 -278
  224. nautobot/project-static/docs/sitemap.xml.gz +0 -0
  225. nautobot/project-static/docs/user-guide/administration/configuration/authentication/ldap.html +18 -18
  226. nautobot/project-static/docs/user-guide/administration/configuration/authentication/remote.html +18 -18
  227. nautobot/project-static/docs/user-guide/administration/configuration/authentication/sso.html +18 -18
  228. nautobot/project-static/docs/user-guide/administration/configuration/index.html +18 -18
  229. nautobot/project-static/docs/user-guide/administration/configuration/optional-settings.html +55 -23
  230. nautobot/project-static/docs/user-guide/administration/configuration/required-settings.html +18 -18
  231. nautobot/project-static/docs/user-guide/administration/configuration/time-zones.html +18 -18
  232. nautobot/project-static/docs/user-guide/administration/guides/caching.html +18 -18
  233. nautobot/project-static/docs/user-guide/administration/guides/celery-queues.html +22 -18
  234. nautobot/project-static/docs/user-guide/administration/guides/healthcheck.html +18 -18
  235. nautobot/project-static/docs/user-guide/administration/guides/permissions.html +18 -18
  236. nautobot/project-static/docs/user-guide/administration/guides/prometheus-metrics.html +18 -18
  237. nautobot/project-static/docs/user-guide/administration/guides/replicating-nautobot.html +18 -18
  238. nautobot/project-static/docs/user-guide/administration/guides/request-profiling.html +18 -18
  239. nautobot/project-static/docs/user-guide/administration/guides/s3-django-storage.html +18 -18
  240. nautobot/project-static/docs/user-guide/administration/installation/app-install.html +18 -18
  241. nautobot/project-static/docs/user-guide/administration/installation/external-authentication.html +18 -18
  242. nautobot/project-static/docs/user-guide/administration/installation/http-server.html +69 -82
  243. nautobot/project-static/docs/user-guide/administration/installation/index.html +24 -24
  244. nautobot/project-static/docs/user-guide/administration/installation/install_system.html +60 -52
  245. nautobot/project-static/docs/user-guide/administration/installation/nautobot.html +80 -87
  246. nautobot/project-static/docs/user-guide/administration/installation/services.html +37 -44
  247. nautobot/project-static/docs/user-guide/administration/installation-extras/docker.html +18 -18
  248. nautobot/project-static/docs/user-guide/administration/installation-extras/health-checks.html +18 -18
  249. nautobot/project-static/docs/user-guide/administration/installation-extras/selinux-troubleshooting.html +18 -18
  250. nautobot/project-static/docs/user-guide/administration/migration/migrating-from-netbox.html +18 -18
  251. nautobot/project-static/docs/user-guide/administration/migration/migrating-from-postgresql.html +18 -18
  252. nautobot/project-static/docs/user-guide/administration/tools/nautobot-server.html +76 -24
  253. nautobot/project-static/docs/user-guide/administration/tools/nautobot-shell.html +18 -18
  254. nautobot/project-static/docs/user-guide/administration/upgrading/database-backup.html +18 -18
  255. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/after-you-upgrade.html +18 -18
  256. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/before-you-upgrade.html +18 -18
  257. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/for-developers.html +18 -18
  258. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/index.html +18 -18
  259. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/whats-changed.html +18 -18
  260. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/region-and-site-data-migration-guide.html +18 -18
  261. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/upgrading-from-nautobot-v1.html +18 -18
  262. nautobot/project-static/docs/user-guide/administration/upgrading/upgrading.html +18 -18
  263. nautobot/project-static/docs/user-guide/core-data-model/circuits/circuit.html +18 -18
  264. nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittermination.html +18 -18
  265. nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittype.html +18 -18
  266. nautobot/project-static/docs/user-guide/core-data-model/circuits/provider.html +18 -18
  267. nautobot/project-static/docs/user-guide/core-data-model/circuits/providernetwork.html +18 -18
  268. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloud.html +18 -18
  269. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudaccount.html +18 -18
  270. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudnetwork.html +18 -18
  271. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudnetworkprefixassignment.html +18 -18
  272. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudresourcetype.html +18 -18
  273. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudservice.html +18 -18
  274. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudservicenetworkassignment.html +18 -18
  275. nautobot/project-static/docs/user-guide/core-data-model/dcim/cable.html +18 -18
  276. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleport.html +18 -18
  277. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleporttemplate.html +18 -18
  278. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverport.html +18 -18
  279. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverporttemplate.html +18 -18
  280. nautobot/project-static/docs/user-guide/core-data-model/dcim/controller.html +18 -18
  281. nautobot/project-static/docs/user-guide/core-data-model/dcim/controllermanageddevicegroup.html +18 -18
  282. nautobot/project-static/docs/user-guide/core-data-model/dcim/device.html +19 -19
  283. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebay.html +18 -18
  284. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebaytemplate.html +18 -18
  285. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicefamily.html +18 -18
  286. nautobot/project-static/docs/user-guide/core-data-model/dcim/deviceredundancygroup.html +18 -18
  287. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicetype.html +18 -18
  288. nautobot/project-static/docs/user-guide/core-data-model/dcim/frontport.html +18 -18
  289. nautobot/project-static/docs/user-guide/core-data-model/dcim/frontporttemplate.html +18 -18
  290. nautobot/project-static/docs/user-guide/core-data-model/dcim/interface.html +18 -18
  291. nautobot/project-static/docs/user-guide/core-data-model/dcim/interfaceredundancygroup.html +18 -18
  292. nautobot/project-static/docs/user-guide/core-data-model/dcim/interfacetemplate.html +18 -18
  293. nautobot/project-static/docs/user-guide/core-data-model/dcim/inventoryitem.html +18 -18
  294. nautobot/project-static/docs/user-guide/core-data-model/dcim/location.html +18 -18
  295. nautobot/project-static/docs/user-guide/core-data-model/dcim/locationtype.html +18 -18
  296. nautobot/project-static/docs/user-guide/core-data-model/dcim/manufacturer.html +19 -19
  297. nautobot/project-static/docs/user-guide/core-data-model/dcim/module.html +18 -18
  298. nautobot/project-static/docs/user-guide/core-data-model/dcim/modulebay.html +18 -18
  299. nautobot/project-static/docs/user-guide/core-data-model/dcim/modulebaytemplate.html +18 -18
  300. nautobot/project-static/docs/user-guide/core-data-model/dcim/moduletype.html +18 -18
  301. nautobot/project-static/docs/user-guide/core-data-model/dcim/platform.html +18 -18
  302. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerfeed.html +18 -18
  303. nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlet.html +18 -18
  304. nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlettemplate.html +18 -18
  305. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerpanel.html +18 -18
  306. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerport.html +18 -18
  307. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerporttemplate.html +18 -18
  308. nautobot/project-static/docs/user-guide/core-data-model/dcim/rack.html +18 -18
  309. nautobot/project-static/docs/user-guide/core-data-model/dcim/rackgroup.html +18 -18
  310. nautobot/project-static/docs/user-guide/core-data-model/dcim/rackreservation.html +18 -18
  311. nautobot/project-static/docs/user-guide/core-data-model/dcim/rearport.html +18 -18
  312. nautobot/project-static/docs/user-guide/core-data-model/dcim/rearporttemplate.html +18 -18
  313. nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareimagefile.html +18 -18
  314. nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareversion.html +18 -18
  315. nautobot/project-static/docs/user-guide/core-data-model/dcim/virtualchassis.html +18 -18
  316. nautobot/project-static/docs/user-guide/core-data-model/extras/configcontext.html +62 -18
  317. nautobot/project-static/docs/user-guide/core-data-model/extras/configcontextschema.html +18 -18
  318. nautobot/project-static/docs/user-guide/core-data-model/extras/contact.html +18 -18
  319. nautobot/project-static/docs/user-guide/core-data-model/extras/team.html +18 -18
  320. nautobot/project-static/docs/user-guide/core-data-model/ipam/ipaddress.html +18 -18
  321. nautobot/project-static/docs/user-guide/core-data-model/ipam/namespace.html +18 -18
  322. nautobot/project-static/docs/user-guide/core-data-model/ipam/prefix.html +18 -18
  323. nautobot/project-static/docs/user-guide/core-data-model/ipam/rir.html +18 -18
  324. nautobot/project-static/docs/user-guide/core-data-model/ipam/routetarget.html +18 -18
  325. nautobot/project-static/docs/user-guide/core-data-model/ipam/service.html +18 -18
  326. nautobot/project-static/docs/user-guide/core-data-model/ipam/vlan.html +18 -18
  327. nautobot/project-static/docs/user-guide/core-data-model/ipam/vlangroup.html +18 -18
  328. nautobot/project-static/docs/user-guide/core-data-model/ipam/vrf.html +18 -18
  329. nautobot/project-static/docs/user-guide/core-data-model/overview/introduction.html +18 -18
  330. nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenant.html +18 -18
  331. nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenantgroup.html +18 -18
  332. nautobot/project-static/docs/user-guide/core-data-model/virtualization/cluster.html +18 -18
  333. nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustergroup.html +18 -18
  334. nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustertype.html +18 -18
  335. nautobot/project-static/docs/user-guide/core-data-model/virtualization/virtualmachine.html +18 -18
  336. nautobot/project-static/docs/user-guide/core-data-model/virtualization/vminterface.html +18 -18
  337. nautobot/project-static/docs/user-guide/feature-guides/contacts-and-teams.html +18 -18
  338. nautobot/project-static/docs/user-guide/feature-guides/custom-fields.html +18 -18
  339. nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-devices.html +18 -18
  340. nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-location-types-and-locations.html +18 -18
  341. nautobot/project-static/docs/user-guide/feature-guides/getting-started/index.html +18 -18
  342. nautobot/project-static/docs/user-guide/feature-guides/getting-started/interfaces.html +18 -18
  343. nautobot/project-static/docs/user-guide/feature-guides/getting-started/ipam.html +18 -18
  344. nautobot/project-static/docs/user-guide/feature-guides/getting-started/platforms.html +18 -18
  345. nautobot/project-static/docs/user-guide/feature-guides/getting-started/search-bar.html +18 -18
  346. nautobot/project-static/docs/user-guide/feature-guides/getting-started/tenants.html +18 -18
  347. nautobot/project-static/docs/user-guide/feature-guides/getting-started/vlans-and-vlan-groups.html +18 -18
  348. nautobot/project-static/docs/user-guide/feature-guides/git-data-source.html +18 -18
  349. nautobot/project-static/docs/user-guide/feature-guides/graphql.html +18 -18
  350. nautobot/project-static/docs/user-guide/feature-guides/ip-address-merge-tool.html +18 -18
  351. nautobot/project-static/docs/user-guide/feature-guides/relationships.html +18 -18
  352. nautobot/project-static/docs/user-guide/feature-guides/software-image-files-and-versions.html +18 -18
  353. nautobot/project-static/docs/user-guide/index.html +18 -18
  354. nautobot/project-static/docs/user-guide/platform-functionality/change-logging.html +18 -18
  355. nautobot/project-static/docs/user-guide/platform-functionality/computedfield.html +18 -18
  356. nautobot/project-static/docs/user-guide/platform-functionality/customfield.html +18 -18
  357. nautobot/project-static/docs/user-guide/platform-functionality/customlink.html +18 -18
  358. nautobot/project-static/docs/user-guide/platform-functionality/dynamicgroup.html +18 -18
  359. nautobot/project-static/docs/user-guide/platform-functionality/exporttemplate.html +18 -18
  360. nautobot/project-static/docs/user-guide/platform-functionality/externalintegration.html +18 -18
  361. nautobot/project-static/docs/user-guide/platform-functionality/gitrepository.html +18 -18
  362. nautobot/project-static/docs/user-guide/platform-functionality/graphql.html +18 -18
  363. nautobot/project-static/docs/user-guide/platform-functionality/graphqlquery.html +18 -18
  364. nautobot/project-static/docs/user-guide/platform-functionality/imageattachment.html +18 -18
  365. nautobot/project-static/docs/user-guide/platform-functionality/jobs/index.html +18 -18
  366. nautobot/project-static/docs/user-guide/platform-functionality/jobs/job-scheduling-and-approvals.html +21 -21
  367. nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobbutton.html +18 -18
  368. nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobhook.html +18 -18
  369. nautobot/project-static/docs/user-guide/platform-functionality/jobs/models.html +18 -18
  370. nautobot/project-static/docs/user-guide/platform-functionality/napalm.html +36 -36
  371. nautobot/project-static/docs/user-guide/platform-functionality/note.html +33 -33
  372. nautobot/project-static/docs/user-guide/platform-functionality/{metadata.html → objectmetadata.html} +197 -84
  373. nautobot/project-static/docs/user-guide/platform-functionality/relationship.html +21 -21
  374. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/authentication.html +18 -18
  375. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/filtering.html +18 -18
  376. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/overview.html +18 -18
  377. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/ui-related-endpoints.html +18 -18
  378. nautobot/project-static/docs/user-guide/platform-functionality/role.html +18 -18
  379. nautobot/project-static/docs/user-guide/platform-functionality/savedview.html +18 -18
  380. nautobot/project-static/docs/user-guide/platform-functionality/secret.html +18 -18
  381. nautobot/project-static/docs/user-guide/platform-functionality/staticgroupassociation.html +18 -18
  382. nautobot/project-static/docs/user-guide/platform-functionality/status.html +18 -18
  383. nautobot/project-static/docs/user-guide/platform-functionality/tag.html +18 -18
  384. nautobot/project-static/docs/user-guide/platform-functionality/template-filters.html +18 -18
  385. nautobot/project-static/docs/user-guide/platform-functionality/users/objectpermission.html +18 -18
  386. nautobot/project-static/docs/user-guide/platform-functionality/users/token.html +18 -18
  387. nautobot/project-static/docs/user-guide/platform-functionality/webhook.html +18 -18
  388. nautobot/project-static/js/homepage_layout.js +3 -0
  389. nautobot/tenancy/templates/tenancy/tenant.html +4 -4
  390. nautobot/virtualization/models.py +0 -2
  391. nautobot/virtualization/tables.py +2 -5
  392. {nautobot-2.3.0b1.dist-info → nautobot-2.3.2.dist-info}/METADATA +3 -3
  393. {nautobot-2.3.0b1.dist-info → nautobot-2.3.2.dist-info}/RECORD +397 -393
  394. nautobot/project-static/docs/assets/stylesheets/main.76a95c52.min.css +0 -1
  395. nautobot/project-static/docs/assets/stylesheets/main.76a95c52.min.css.map +0 -1
  396. {nautobot-2.3.0b1.dist-info → nautobot-2.3.2.dist-info}/LICENSE.txt +0 -0
  397. {nautobot-2.3.0b1.dist-info → nautobot-2.3.2.dist-info}/NOTICE +0 -0
  398. {nautobot-2.3.0b1.dist-info → nautobot-2.3.2.dist-info}/WHEEL +0 -0
  399. {nautobot-2.3.0b1.dist-info → nautobot-2.3.2.dist-info}/entry_points.txt +0 -0
nautobot/extras/views.py CHANGED
@@ -1,8 +1,8 @@
1
- from datetime import timedelta
2
1
  import logging
3
2
  from urllib.parse import parse_qs
4
3
 
5
4
  from celery import chain
5
+ from django.conf import settings
6
6
  from django.contrib import messages
7
7
  from django.contrib.auth.models import AnonymousUser
8
8
  from django.contrib.contenttypes.models import ContentType
@@ -24,6 +24,11 @@ from django_tables2 import RequestConfig
24
24
  from jsonschema.validators import Draft7Validator
25
25
  from rest_framework.decorators import action
26
26
 
27
+ try:
28
+ from zoneinfo import ZoneInfo
29
+ except ImportError: # python 3.8
30
+ from backports.zoneinfo import ZoneInfo
31
+
27
32
  from nautobot.core.forms import restrict_form_fields
28
33
  from nautobot.core.models.querysets import count_related
29
34
  from nautobot.core.models.utils import pretty_print_query
@@ -1388,55 +1393,25 @@ class JobRunView(ObjectPermissionRequiredMixin, View):
1388
1393
  schedule_type = schedule_form.cleaned_data["_schedule_type"]
1389
1394
 
1390
1395
  if (not dryrun and job_model.approval_required) or schedule_type in JobExecutionType.SCHEDULE_CHOICES:
1391
- crontab = ""
1392
-
1393
- if schedule_type == JobExecutionType.TYPE_IMMEDIATELY:
1394
- # The job must be approved.
1395
- # If the schedule_type is immediate, we still create the task, but mark it for approval
1396
- # as a once in the future task with the due date set to the current time. This means
1397
- # when approval is granted, the task is immediately due for execution.
1398
- schedule_type = JobExecutionType.TYPE_FUTURE
1399
- schedule_datetime = timezone.now()
1400
- schedule_name = f"{job_model} - {schedule_datetime}"
1401
-
1402
- else:
1403
- schedule_name = schedule_form.cleaned_data["_schedule_name"]
1404
-
1405
- if schedule_type == JobExecutionType.TYPE_CUSTOM:
1406
- crontab = schedule_form.cleaned_data["_recurrence_custom_time"]
1407
- # doing .get("key", "default") returns None instead of "default" here for some reason
1408
- schedule_datetime = schedule_form.cleaned_data.get("_schedule_start_time")
1409
- if schedule_datetime is None:
1410
- # "_schedule_start_time" is checked against ScheduledJob.earliest_possible_time()
1411
- # which returns timezone.now() + timedelta(seconds=15)
1412
- schedule_datetime = timezone.now() + timedelta(seconds=20)
1413
- else:
1414
- schedule_datetime = schedule_form.cleaned_data["_schedule_start_time"]
1415
-
1416
- celery_kwargs = {"nautobot_job_profile": profile, "queue": task_queue}
1417
- scheduled_job = ScheduledJob(
1418
- name=schedule_name,
1419
- task=job_model.class_path,
1420
- job_model=job_model,
1421
- start_time=schedule_datetime,
1422
- description=f"Nautobot job {schedule_name} scheduled by {request.user} for {schedule_datetime}",
1423
- kwargs=job_class.serialize_data(job_form.cleaned_data),
1424
- celery_kwargs=celery_kwargs,
1396
+ scheduled_job = ScheduledJob.create_schedule(
1397
+ job_model,
1398
+ request.user,
1399
+ name=schedule_form.cleaned_data.get("_schedule_name"),
1400
+ start_time=schedule_form.cleaned_data.get("_schedule_start_time"),
1425
1401
  interval=schedule_type,
1426
- one_off=schedule_type == JobExecutionType.TYPE_FUTURE,
1427
- queue=task_queue,
1428
- user=request.user,
1402
+ crontab=schedule_form.cleaned_data.get("_recurrence_custom_time"),
1429
1403
  approval_required=job_model.approval_required,
1430
- crontab=crontab,
1404
+ task_queue=task_queue,
1405
+ profile=profile,
1406
+ **job_class.serialize_data(job_form.cleaned_data),
1431
1407
  )
1432
- scheduled_job.validated_save()
1433
1408
 
1434
1409
  if job_model.approval_required:
1435
- messages.success(request, f"Job {schedule_name} successfully submitted for approval")
1436
- return redirect(return_url if return_url else "extras:scheduledjob_approval_queue_list")
1410
+ messages.success(request, f"Job {scheduled_job.name} successfully submitted for approval")
1411
+ return redirect(return_url or "extras:scheduledjob_approval_queue_list")
1437
1412
  else:
1438
- messages.success(request, f"Job {schedule_name} successfully scheduled")
1439
- return redirect(return_url if return_url else "extras:scheduledjob_list")
1413
+ messages.success(request, f"Job {scheduled_job.name} successfully scheduled")
1414
+ return redirect(return_url or "extras:scheduledjob_list")
1440
1415
 
1441
1416
  else:
1442
1417
  # Enqueue job for immediate execution
@@ -1722,7 +1697,12 @@ class SavedViewUIViewSet(
1722
1697
  view_name = new_global_default_view.view
1723
1698
  message = ""
1724
1699
  if new_global_default_view.is_global_default:
1725
- message += f"<br>The global default saved View for '{view_name}' is set to <a href='{new_global_default_view.get_absolute_url()}'>{new_global_default_view.name}</a>."
1700
+ message = format_html(
1701
+ '<br>The global default saved view for "{}" is set to <a href="{}">{}</a>',
1702
+ view_name,
1703
+ new_global_default_view.get_absolute_url(),
1704
+ new_global_default_view.name,
1705
+ )
1726
1706
  return message
1727
1707
 
1728
1708
  def list(self, request, *args, **kwargs):
@@ -1942,6 +1922,7 @@ class ScheduledJobView(generic.ObjectView):
1942
1922
  return {
1943
1923
  "labels": labels,
1944
1924
  "job_class_found": (job_class is not None),
1925
+ "default_time_zone": ZoneInfo(settings.TIME_ZONE),
1945
1926
  **super().get_extra_context(request, instance),
1946
1927
  }
1947
1928
 
@@ -2076,8 +2057,13 @@ class JobLogEntryTableView(generic.GenericView):
2076
2057
  else:
2077
2058
  queryset = instance.job_log_entries.all()
2078
2059
  log_table = tables.JobLogEntryTable(data=queryset, user=request.user)
2079
- RequestConfig(request).configure(log_table)
2080
- return HttpResponse(log_table.as_html(request))
2060
+ paginate = {
2061
+ "paginator_class": EnhancedPaginator,
2062
+ "per_page": get_paginate_count(request),
2063
+ }
2064
+ RequestConfig(request, paginate).configure(log_table)
2065
+ table = log_table.as_html(request)
2066
+ return HttpResponse(table)
2081
2067
 
2082
2068
 
2083
2069
  #
@@ -2237,15 +2223,13 @@ class MetadataTypeUIViewSet(NautobotUIViewSet):
2237
2223
 
2238
2224
 
2239
2225
  class ObjectMetadataUIViewSet(
2240
- ObjectBulkDestroyViewMixin,
2241
2226
  ObjectChangeLogViewMixin,
2242
- ObjectDestroyViewMixin,
2243
2227
  ObjectDetailViewMixin,
2244
2228
  ObjectListViewMixin,
2245
2229
  ):
2246
2230
  filterset_class = filters.ObjectMetadataFilterSet
2247
2231
  filterset_form_class = forms.ObjectMetadataFilterForm
2248
- queryset = ObjectMetadata.objects.all().order_by("assigned_object_type", "scoped_fields")
2232
+ queryset = ObjectMetadata.objects.all().order_by("assigned_object_type", "assigned_object_id", "scoped_fields")
2249
2233
  serializer_class = serializers.ObjectMetadataSerializer
2250
2234
  table_class = tables.ObjectMetadataTable
2251
2235
  action_buttons = ("export",)
@@ -2444,7 +2428,7 @@ class RoleUIViewSet(viewsets.NautobotUIViewSet):
2444
2428
 
2445
2429
  if ContentType.objects.get_for_model(Prefix) in context["content_types"]:
2446
2430
  prefixes = instance.prefixes.restrict(request.user, "view")
2447
- prefix_table = PrefixTable(prefixes)
2431
+ prefix_table = PrefixTable(prefixes, hide_hierarchy_ui=True)
2448
2432
  prefix_table.columns.hide("role")
2449
2433
  RequestConfig(request, paginate).configure(prefix_table)
2450
2434
  context["prefix_table"] = prefix_table
@@ -202,7 +202,7 @@ class PrefixViewSet(NautobotModelViewSet):
202
202
  if requested_prefix["prefix_length"] >= available_prefix.prefixlen:
203
203
  allocated_prefix = f"{available_prefix.network}/{requested_prefix['prefix_length']}"
204
204
  requested_prefix["prefix"] = allocated_prefix
205
- requested_prefix["namespace"] = prefix.namespace.pk
205
+ requested_prefix["namespace"] = prefix.namespace
206
206
  break
207
207
  else:
208
208
  return Response(
@@ -210,6 +210,10 @@ class PrefixViewSet(NautobotModelViewSet):
210
210
  status=status.HTTP_204_NO_CONTENT,
211
211
  )
212
212
 
213
+ # The serializer usage above has mapped "custom_fields" dict to "_custom_field_data".
214
+ # We need to convert it back to "custom_fields" as we're going to deserialize it a second time below
215
+ requested_prefix["custom_fields"] = requested_prefix.pop("_custom_field_data", {})
216
+
213
217
  # Remove the allocated prefix from the list of available prefixes
214
218
  available_prefixes.remove(allocated_prefix)
215
219
 
@@ -299,7 +303,10 @@ class PrefixViewSet(NautobotModelViewSet):
299
303
  prefix_length = prefix.prefix.prefixlen
300
304
  for requested_ip in requested_ips:
301
305
  requested_ip["address"] = f"{next(available_ips)}/{prefix_length}"
302
- requested_ip["namespace"] = prefix.namespace.pk
306
+ requested_ip["namespace"] = prefix.namespace
307
+ # The serializer usage above has mapped "custom_fields" dict to "_custom_field_data".
308
+ # We need to convert it back to "custom_fields" as we're going to deserialize it a second time below
309
+ requested_ip["custom_fields"] = requested_ip.pop("_custom_field_data", {})
303
310
 
304
311
  # Initialize the serializer with a list or a single object depending on what was requested
305
312
  context = {"request": request, "depth": 0}
nautobot/ipam/choices.py CHANGED
@@ -102,6 +102,23 @@ class IPAddressTypeChoices(ChoiceSet):
102
102
  )
103
103
 
104
104
 
105
+ #
106
+ # VRFs
107
+ #
108
+
109
+
110
+ class VRFStatusChoices(ChoiceSet):
111
+ STATUS_ACTIVE = "active"
112
+ STATUS_DOWN = "down"
113
+ STATUS_DEPRECATED = "deprecated"
114
+
115
+ CHOICES = (
116
+ (STATUS_ACTIVE, "Active"),
117
+ (STATUS_DOWN, "Down"),
118
+ (STATUS_DEPRECATED, "Deprecated"),
119
+ )
120
+
121
+
105
122
  #
106
123
  # VLANs
107
124
  #
nautobot/ipam/factory.py CHANGED
@@ -84,6 +84,7 @@ class VRFFactory(PrimaryModelFactory):
84
84
  model = VRF
85
85
  exclude = (
86
86
  "has_description",
87
+ "has_status",
87
88
  "has_tenant",
88
89
  )
89
90
 
@@ -103,6 +104,11 @@ class VRFFactory(PrimaryModelFactory):
103
104
  has_description = NautobotBoolIterator()
104
105
  description = factory.Maybe("has_description", factory.Faker("text", max_nb_chars=CHARFIELD_MAX_LENGTH), "")
105
106
 
107
+ has_status = NautobotBoolIterator()
108
+ status = factory.Maybe(
109
+ "has_status", random_instance(lambda: Status.objects.get_for_model(VRF), allow_null=False), None
110
+ )
111
+
106
112
  namespace = random_instance(Namespace, allow_null=False)
107
113
 
108
114
  @factory.post_generation
nautobot/ipam/filters.py CHANGED
@@ -66,7 +66,7 @@ class NamespaceFilterSet(NautobotFilterSet):
66
66
  fields = "__all__"
67
67
 
68
68
 
69
- class VRFFilterSet(NautobotFilterSet, TenancyModelFilterSetMixin):
69
+ class VRFFilterSet(NautobotFilterSet, StatusModelFilterSetMixin, TenancyModelFilterSetMixin):
70
70
  q = SearchFilter(
71
71
  filter_predicates={
72
72
  "name": "icontains",
@@ -498,7 +498,7 @@ class IPAddressFilterSet(
498
498
  return queryset.none()
499
499
  interface_ids = []
500
500
  for device in devices:
501
- interface_ids.extend(device.all_interfaces.values_list("id", flat=True))
501
+ interface_ids.extend(device.vc_interfaces.values_list("id", flat=True))
502
502
  return queryset.filter(interfaces__in=interface_ids)
503
503
 
504
504
  def filter_virtual_machine(self, queryset, name, value):
nautobot/ipam/forms.py CHANGED
@@ -125,6 +125,7 @@ class VRFForm(NautobotModelForm, TenancyForm):
125
125
  "name",
126
126
  "rd",
127
127
  "namespace",
128
+ "status",
128
129
  "description",
129
130
  "import_targets",
130
131
  "export_targets",
@@ -140,10 +141,11 @@ class VRFForm(NautobotModelForm, TenancyForm):
140
141
  }
141
142
  help_texts = {
142
143
  "rd": "Route distinguisher unique to this Namespace (as defined in RFC 4364)",
144
+ "status": "Operational status of this VRF",
143
145
  }
144
146
 
145
147
 
146
- class VRFBulkEditForm(TagsBulkEditFormMixin, NautobotBulkEditForm):
148
+ class VRFBulkEditForm(TagsBulkEditFormMixin, StatusModelBulkEditFormMixin, NautobotBulkEditForm):
147
149
  pk = forms.ModelMultipleChoiceField(queryset=VRF.objects.all(), widget=forms.MultipleHiddenInput())
148
150
  namespace = DynamicModelChoiceField(queryset=Namespace.objects.all(), required=False)
149
151
  tenant = DynamicModelChoiceField(queryset=Tenant.objects.all(), required=False)
@@ -162,9 +164,9 @@ class VRFBulkEditForm(TagsBulkEditFormMixin, NautobotBulkEditForm):
162
164
  ]
163
165
 
164
166
 
165
- class VRFFilterForm(NautobotFilterForm, TenancyFilterForm):
167
+ class VRFFilterForm(NautobotFilterForm, StatusModelFilterFormMixin, TenancyFilterForm):
166
168
  model = VRF
167
- field_order = ["q", "import_targets", "export_targets", "tenant_group", "tenant"]
169
+ field_order = ["q", "import_targets", "export_targets", "status", "tenant_group", "tenant"]
168
170
  q = forms.CharField(required=False, label="Search")
169
171
  import_targets = DynamicModelMultipleChoiceField(
170
172
  queryset=RouteTarget.objects.all(), to_field_name="name", required=False
@@ -899,7 +901,7 @@ class ServiceForm(NautobotModelForm):
899
901
  # Limit IP address choices to those assigned to interfaces of the parent device/VM
900
902
  if self.instance.device:
901
903
  self.fields["ip_addresses"].queryset = IPAddress.objects.filter(
902
- interfaces__in=self.instance.device.all_interfaces.values_list("id", flat=True)
904
+ interfaces__in=self.instance.device.vc_interfaces.values_list("id", flat=True)
903
905
  )
904
906
  elif self.instance.virtual_machine:
905
907
  self.fields["ip_addresses"].queryset = IPAddress.objects.filter(
@@ -0,0 +1,23 @@
1
+ # Generated by Django 4.2.15 on 2024-08-26 17:20
2
+
3
+ from django.db import migrations
4
+ import django.db.models.deletion
5
+
6
+ import nautobot.extras.models.statuses
7
+
8
+
9
+ class Migration(migrations.Migration):
10
+ dependencies = [
11
+ ("extras", "0114_computedfield_grouping"),
12
+ ("ipam", "0047_alter_ipaddress_role_alter_ipaddress_status_and_more"),
13
+ ]
14
+
15
+ operations = [
16
+ migrations.AddField(
17
+ model_name="vrf",
18
+ name="status",
19
+ field=nautobot.extras.models.statuses.StatusField(
20
+ blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to="extras.status"
21
+ ),
22
+ ),
23
+ ]
@@ -0,0 +1,25 @@
1
+ # Generated by Django 4.2.15 on 2024-08-26 18:05
2
+
3
+ from django.db import migrations
4
+
5
+ from nautobot.extras.management import clear_status_choices, populate_status_choices
6
+
7
+
8
+ def populate_vrf_status_choices(apps, schema_editor):
9
+ """Create default Status records for the VRF model."""
10
+ populate_status_choices(apps, schema_editor, models=["ipam.VRF"])
11
+
12
+
13
+ def clear_vrf_status_choices(apps, schema_editor):
14
+ """Remove default Status records for the VRF model."""
15
+ clear_status_choices(apps, schema_editor, models=["ipam.VRF"])
16
+
17
+
18
+ class Migration(migrations.Migration):
19
+ dependencies = [
20
+ ("ipam", "0048_vrf_status"),
21
+ ]
22
+
23
+ operations = [
24
+ migrations.RunPython(populate_vrf_status_choices, clear_vrf_status_choices),
25
+ ]
nautobot/ipam/models.py CHANGED
@@ -49,7 +49,6 @@ logger = logging.getLogger(__name__)
49
49
  @extras_features(
50
50
  "custom_links",
51
51
  "custom_validators",
52
- "dynamic_groups",
53
52
  "export_templates",
54
53
  "graphql",
55
54
  "locations",
@@ -98,6 +97,7 @@ def get_default_namespace_pk():
98
97
  "custom_validators",
99
98
  "export_templates",
100
99
  "graphql",
100
+ "statuses",
101
101
  "webhooks",
102
102
  )
103
103
  class VRF(PrimaryModel):
@@ -115,6 +115,7 @@ class VRF(PrimaryModel):
115
115
  verbose_name="Route distinguisher",
116
116
  help_text="Unique route distinguisher (as defined in RFC 4364)",
117
117
  )
118
+ status = StatusField(blank=True, null=True)
118
119
  namespace = models.ForeignKey(
119
120
  "ipam.Namespace",
120
121
  on_delete=models.PROTECT,
@@ -399,7 +400,6 @@ class RIR(OrganizationalModel):
399
400
  @extras_features(
400
401
  "custom_links",
401
402
  "custom_validators",
402
- "dynamic_groups",
403
403
  "export_templates",
404
404
  "graphql",
405
405
  "locations",
@@ -501,11 +501,6 @@ class Prefix(PrimaryModel):
501
501
  "type",
502
502
  "vlan",
503
503
  ]
504
- """
505
- dynamic_group_filter_fields = {
506
- "vrf": "vrf_id", # Duplicate filter fields that will be collapsed in 2.0
507
- }
508
- """
509
504
 
510
505
  class Meta:
511
506
  ordering = (
@@ -986,7 +981,6 @@ class PrefixLocationAssignment(BaseModel):
986
981
  @extras_features(
987
982
  "custom_links",
988
983
  "custom_validators",
989
- "dynamic_groups",
990
984
  "export_templates",
991
985
  "graphql",
992
986
  "statuses",
@@ -1020,7 +1014,7 @@ class IPAddress(PrimaryModel):
1020
1014
  parent = models.ForeignKey(
1021
1015
  "ipam.Prefix",
1022
1016
  blank=True,
1023
- null=True,
1017
+ null=True, # TODO remove this, it shouldn't be permitted for the database!
1024
1018
  related_name="ip_addresses", # `IPAddress` to use `related_name="ip_addresses"`
1025
1019
  on_delete=models.PROTECT,
1026
1020
  help_text="The parent Prefix of this IPAddress.",
@@ -1117,7 +1111,7 @@ class IPAddress(PrimaryModel):
1117
1111
  raise ValidationError({"namespace": "No suitable parent Prefix exists in this Namespace"}) from e
1118
1112
 
1119
1113
  def clean(self):
1120
- super().clean()
1114
+ self.address = self.address # not a no-op - forces re-calling of self._deconstruct_address()
1121
1115
 
1122
1116
  # Validate that host is not being modified
1123
1117
  if self.present_in_database:
@@ -1131,8 +1125,8 @@ class IPAddress(PrimaryModel):
1131
1125
 
1132
1126
  closest_parent = self._get_closest_parent()
1133
1127
  # Validate `parent` can be used as the parent for this ipaddress
1134
- if self.parent and closest_parent:
1135
- if self.parent != closest_parent:
1128
+ if closest_parent is not None:
1129
+ if self.parent is not None and self.parent != closest_parent:
1136
1130
  raise ValidationError(
1137
1131
  {
1138
1132
  "parent": (
@@ -1144,23 +1138,20 @@ class IPAddress(PrimaryModel):
1144
1138
  self.parent = closest_parent
1145
1139
  self._namespace = None
1146
1140
 
1147
- def save(self, *args, **kwargs):
1148
1141
  # 3.0 TODO: uncomment the below to enforce this constraint
1149
1142
  # if self.parent.type != choices.PrefixTypeChoices.TYPE_NETWORK:
1150
1143
  # err_msg = f"IP addresses cannot be created in {self.parent.type} prefixes. You must create a network prefix first."
1151
1144
  # raise ValidationError({"address": err_msg})
1152
1145
 
1153
- self.address = self.address # not a no-op - forces re-calling of self._deconstruct_address()
1154
-
1155
1146
  # Force dns_name to lowercase
1156
1147
  if not self.dns_name.islower:
1157
1148
  self.dns_name = self.dns_name.lower()
1158
1149
 
1159
- # Host and mask_length are required to get closest parent
1160
- closest_parent = self._get_closest_parent()
1161
- if closest_parent is not None:
1162
- self.parent = closest_parent
1163
- self._namespace = None
1150
+ super().clean()
1151
+
1152
+ def save(self, *args, **kwargs):
1153
+ self.clean() # MUST do data fixup as above
1154
+
1164
1155
  super().save(*args, **kwargs)
1165
1156
 
1166
1157
  @property
@@ -1,6 +1,7 @@
1
1
  import re
2
2
 
3
3
  from django.core.exceptions import ValidationError
4
+ from django.core.validators import validate_ipv46_address
4
5
  from django.db.models import ProtectedError, Q
5
6
  import netaddr
6
7
 
@@ -397,6 +398,31 @@ class IPAddressQuerySet(BaseNetworkQuerySet):
397
398
  """
398
399
  return super().order_by("host")
399
400
 
401
+ def get_or_create(self, **kwargs):
402
+ from nautobot.ipam.models import get_default_namespace, Prefix
403
+
404
+ parent = kwargs.get("parent")
405
+ namespace = kwargs.pop("namespace", None)
406
+ host = kwargs.get("host")
407
+ mask_length = kwargs.get("mask_length")
408
+ # If `host` or `mask_length` is None skip; then there is no way of getting the closest parent;
409
+ if parent is None and host is not None and mask_length is not None:
410
+ if namespace is None:
411
+ namespace = get_default_namespace()
412
+ cidr = f"{host}/{mask_length}"
413
+
414
+ try:
415
+ validate_ipv46_address(host)
416
+ except ValidationError as err:
417
+ raise ValidationError({"host": err.error_list}) from err
418
+ try:
419
+ netaddr.IPNetwork(cidr)
420
+ except netaddr.AddrFormatError as err:
421
+ raise ValidationError(f"{cidr} does not appear to be an IPv4 or IPv6 network.") from err
422
+ parent = Prefix.objects.filter(namespace=namespace).get_closest_parent(cidr=cidr, include_self=True)
423
+ kwargs["parent"] = parent
424
+ return super().get_or_create(**kwargs)
425
+
400
426
  def string_search(self, search):
401
427
  """
402
428
  Interpret a search string and return useful results.
nautobot/ipam/tables.py CHANGED
@@ -217,7 +217,7 @@ class NamespaceTable(BaseTable):
217
217
  #
218
218
 
219
219
 
220
- class VRFTable(BaseTable):
220
+ class VRFTable(StatusTableMixin, BaseTable):
221
221
  pk = ToggleColumn()
222
222
  name = tables.LinkColumn()
223
223
  # rd = tables.Column(verbose_name="RD")
@@ -232,6 +232,7 @@ class VRFTable(BaseTable):
232
232
  "pk",
233
233
  "name",
234
234
  # "rd",
235
+ "status",
235
236
  "namespace",
236
237
  "tenant",
237
238
  "description",
@@ -240,7 +241,7 @@ class VRFTable(BaseTable):
240
241
  "tags",
241
242
  )
242
243
  # default_columns = ("pk", "name", "rd", "namespace", "tenant", "description")
243
- default_columns = ("pk", "name", "namespace", "tenant", "description")
244
+ default_columns = ("pk", "name", "status", "namespace", "tenant", "description")
244
245
 
245
246
 
246
247
  class VRFDeviceAssignmentTable(BaseTable):
@@ -355,6 +356,9 @@ class PrefixTable(StatusTableMixin, RoleTableMixin, BaseTable):
355
356
  location_count = LinkedCountColumn(
356
357
  viewname="dcim:location_list", url_params={"prefixes": "pk"}, verbose_name="Locations"
357
358
  )
359
+ cloud_networks_count = LinkedCountColumn(
360
+ viewname="cloud:cloudnetwork_list", url_params={"prefixes": "pk"}, verbose_name="Cloud Networks"
361
+ )
358
362
 
359
363
  class Meta(BaseTable.Meta):
360
364
  model = Prefix
@@ -368,6 +372,7 @@ class PrefixTable(StatusTableMixin, RoleTableMixin, BaseTable):
368
372
  "namespace",
369
373
  "tenant",
370
374
  "location_count",
375
+ "cloud_networks_count",
371
376
  "vlan",
372
377
  "role",
373
378
  "rir",
@@ -19,6 +19,10 @@
19
19
  <td>Tenant</td>
20
20
  <td>{{ object.tenant|hyperlinked_object }}</td>
21
21
  </tr>
22
+ <tr>
23
+ <td>Status</td>
24
+ <td>{{ object.status|hyperlinked_object_with_color }}</td>
25
+ </tr>
22
26
  <tr>
23
27
  <td>Description</td>
24
28
  <td>{{ object.description|placeholder }}</td>
@@ -8,6 +8,7 @@
8
8
  {% render_field form.name %}
9
9
  {% render_field form.namespace %}
10
10
  {% render_field form.rd %}
11
+ {% render_field form.status %}
11
12
  {% render_field form.description %}
12
13
  </div>
13
14
  </div>