nautobot 2.4.8__py3-none-any.whl → 2.4.10__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 (387) hide show
  1. nautobot/circuits/templates/circuits/circuittype.html +1 -1
  2. nautobot/circuits/templates/circuits/circuittype_retrieve.html +1 -39
  3. nautobot/circuits/views.py +18 -23
  4. nautobot/cloud/templates/cloud/cloudresourcetype_retrieve.html +4 -111
  5. nautobot/cloud/views.py +56 -25
  6. nautobot/core/api/parsers.py +56 -2
  7. nautobot/core/celery/schedulers.py +1 -0
  8. nautobot/core/filters.py +1 -1
  9. nautobot/core/graphql/schema.py +1 -0
  10. nautobot/core/jobs/__init__.py +14 -3
  11. nautobot/core/models/__init__.py +2 -0
  12. nautobot/core/tables.py +13 -6
  13. nautobot/core/testing/views.py +27 -2
  14. nautobot/core/tests/test_csv.py +92 -1
  15. nautobot/core/tests/test_jinja_filters.py +59 -0
  16. nautobot/core/tests/test_jobs.py +113 -0
  17. nautobot/core/tests/test_ui.py +53 -1
  18. nautobot/core/tests/test_utils.py +11 -0
  19. nautobot/core/tests/test_views.py +73 -0
  20. nautobot/core/ui/object_detail.py +19 -12
  21. nautobot/core/urls.py +2 -2
  22. nautobot/core/utils/filtering.py +3 -0
  23. nautobot/core/views/__init__.py +21 -0
  24. nautobot/core/views/renderers.py +1 -1
  25. nautobot/dcim/forms.py +10 -0
  26. nautobot/dcim/models/device_component_templates.py +4 -0
  27. nautobot/dcim/models/device_components.py +12 -0
  28. nautobot/dcim/models/devices.py +6 -0
  29. nautobot/dcim/templates/dcim/devicefamily_retrieve.html +1 -43
  30. nautobot/dcim/templates/dcim/deviceredundancygroup_retrieve.html +1 -59
  31. nautobot/dcim/templates/dcim/devicetype.html +2 -217
  32. nautobot/dcim/templates/dcim/devicetype_edit.html +2 -32
  33. nautobot/dcim/templates/dcim/devicetype_retrieve.html +217 -0
  34. nautobot/dcim/templates/dcim/devicetype_update.html +32 -0
  35. nautobot/dcim/templates/dcim/inc/rack_elevation.html +1 -1
  36. nautobot/dcim/templates/dcim/modulebay_retrieve.html +1 -84
  37. nautobot/dcim/templates/dcim/rack_elevation.html +14 -0
  38. nautobot/dcim/templates/dcim/rackreservation_retrieve.html +0 -68
  39. nautobot/dcim/tests/integration/test_fileinputpicker.py +1 -1
  40. nautobot/dcim/urls.py +1 -36
  41. nautobot/dcim/views.py +133 -81
  42. nautobot/extras/api/views.py +4 -6
  43. nautobot/extras/context_managers.py +2 -2
  44. nautobot/extras/migrations/0024_job_data_migration.py +1 -1
  45. nautobot/extras/models/customfields.py +2 -0
  46. nautobot/extras/models/datasources.py +8 -0
  47. nautobot/extras/models/groups.py +18 -0
  48. nautobot/extras/models/jobs.py +92 -62
  49. nautobot/extras/models/metadata.py +2 -0
  50. nautobot/extras/models/models.py +4 -0
  51. nautobot/extras/models/secrets.py +7 -0
  52. nautobot/extras/secrets/__init__.py +14 -0
  53. nautobot/extras/tables.py +11 -1
  54. nautobot/extras/templates/extras/computedfield_retrieve.html +1 -55
  55. nautobot/extras/templates/extras/inc/job_tiles.html +1 -1
  56. nautobot/extras/templates/extras/jobresult.html +1 -1
  57. nautobot/extras/templates/extras/metadatatype_retrieve.html +1 -66
  58. nautobot/extras/templates/extras/scheduledjob.html +25 -9
  59. nautobot/extras/tests/test_api.py +1 -1
  60. nautobot/extras/tests/test_context_managers.py +20 -0
  61. nautobot/extras/tests/test_models.py +26 -0
  62. nautobot/extras/tests/test_views.py +15 -2
  63. nautobot/extras/utils.py +18 -16
  64. nautobot/extras/views.py +65 -26
  65. nautobot/ipam/models.py +32 -0
  66. nautobot/ipam/tables.py +3 -4
  67. nautobot/project-static/docs/404.html +4 -4
  68. nautobot/project-static/docs/apps/index.html +4 -4
  69. nautobot/project-static/docs/apps/nautobot-apps.html +4 -4
  70. nautobot/project-static/docs/assets/javascripts/{bundle.c8b220af.min.js → bundle.13a4f30d.min.js} +4 -4
  71. nautobot/project-static/docs/assets/javascripts/{bundle.c8b220af.min.js.map → bundle.13a4f30d.min.js.map} +2 -2
  72. nautobot/project-static/docs/assets/javascripts/workers/{search.f8cc74c7.min.js → search.d50fe291.min.js} +2 -2
  73. nautobot/project-static/docs/assets/javascripts/workers/{search.f8cc74c7.min.js.map → search.d50fe291.min.js.map} +1 -1
  74. nautobot/project-static/docs/assets/stylesheets/{main.2afb09e1.min.css → main.342714a4.min.css} +1 -1
  75. nautobot/project-static/docs/assets/stylesheets/{main.2afb09e1.min.css.map → main.342714a4.min.css.map} +1 -1
  76. nautobot/project-static/docs/code-reference/nautobot/apps/__init__.html +4 -4
  77. nautobot/project-static/docs/code-reference/nautobot/apps/admin.html +4 -4
  78. nautobot/project-static/docs/code-reference/nautobot/apps/api.html +4 -4
  79. nautobot/project-static/docs/code-reference/nautobot/apps/change_logging.html +4 -4
  80. nautobot/project-static/docs/code-reference/nautobot/apps/choices.html +4 -4
  81. nautobot/project-static/docs/code-reference/nautobot/apps/config.html +4 -4
  82. nautobot/project-static/docs/code-reference/nautobot/apps/constants.html +4 -4
  83. nautobot/project-static/docs/code-reference/nautobot/apps/datasources.html +4 -4
  84. nautobot/project-static/docs/code-reference/nautobot/apps/events.html +4 -4
  85. nautobot/project-static/docs/code-reference/nautobot/apps/exceptions.html +4 -4
  86. nautobot/project-static/docs/code-reference/nautobot/apps/factory.html +4 -4
  87. nautobot/project-static/docs/code-reference/nautobot/apps/filters.html +4 -4
  88. nautobot/project-static/docs/code-reference/nautobot/apps/forms.html +4 -4
  89. nautobot/project-static/docs/code-reference/nautobot/apps/graphql.html +4 -4
  90. nautobot/project-static/docs/code-reference/nautobot/apps/jobs.html +4 -4
  91. nautobot/project-static/docs/code-reference/nautobot/apps/models.html +4 -4
  92. nautobot/project-static/docs/code-reference/nautobot/apps/querysets.html +4 -4
  93. nautobot/project-static/docs/code-reference/nautobot/apps/secrets.html +4 -4
  94. nautobot/project-static/docs/code-reference/nautobot/apps/tables.html +4 -4
  95. nautobot/project-static/docs/code-reference/nautobot/apps/testing.html +4 -4
  96. nautobot/project-static/docs/code-reference/nautobot/apps/ui.html +6 -8
  97. nautobot/project-static/docs/code-reference/nautobot/apps/urls.html +4 -4
  98. nautobot/project-static/docs/code-reference/nautobot/apps/utils.html +36 -6
  99. nautobot/project-static/docs/code-reference/nautobot/apps/views.html +4 -4
  100. nautobot/project-static/docs/development/apps/api/configuration-view.html +4 -4
  101. nautobot/project-static/docs/development/apps/api/database-backend-config.html +4 -4
  102. nautobot/project-static/docs/development/apps/api/models/django-admin.html +4 -4
  103. nautobot/project-static/docs/development/apps/api/models/global-search.html +4 -4
  104. nautobot/project-static/docs/development/apps/api/models/graphql.html +4 -4
  105. nautobot/project-static/docs/development/apps/api/models/index.html +4 -4
  106. nautobot/project-static/docs/development/apps/api/nautobot-app-config.html +4 -4
  107. nautobot/project-static/docs/development/apps/api/platform-features/custom-validators.html +4 -4
  108. nautobot/project-static/docs/development/apps/api/platform-features/filter-extensions.html +4 -4
  109. nautobot/project-static/docs/development/apps/api/platform-features/git-repository-content.html +4 -4
  110. nautobot/project-static/docs/development/apps/api/platform-features/index.html +4 -4
  111. nautobot/project-static/docs/development/apps/api/platform-features/jinja2-filters.html +4 -4
  112. nautobot/project-static/docs/development/apps/api/platform-features/jobs.html +4 -4
  113. nautobot/project-static/docs/development/apps/api/platform-features/populating-extensibility-features.html +4 -4
  114. nautobot/project-static/docs/development/apps/api/platform-features/secrets-providers.html +43 -42
  115. nautobot/project-static/docs/development/apps/api/platform-features/table-extensions.html +4 -4
  116. nautobot/project-static/docs/development/apps/api/platform-features/uniquely-identify-objects.html +4 -4
  117. nautobot/project-static/docs/development/apps/api/prometheus.html +4 -4
  118. nautobot/project-static/docs/development/apps/api/setup.html +4 -4
  119. nautobot/project-static/docs/development/apps/api/testing.html +4 -4
  120. nautobot/project-static/docs/development/apps/api/ui-extensions/banners.html +4 -4
  121. nautobot/project-static/docs/development/apps/api/ui-extensions/home-page.html +4 -4
  122. nautobot/project-static/docs/development/apps/api/ui-extensions/index.html +4 -4
  123. nautobot/project-static/docs/development/apps/api/ui-extensions/navigation.html +4 -4
  124. nautobot/project-static/docs/development/apps/api/ui-extensions/object-views.html +4 -4
  125. nautobot/project-static/docs/development/apps/api/views/base-template.html +4 -4
  126. nautobot/project-static/docs/development/apps/api/views/core-view-overrides.html +4 -4
  127. nautobot/project-static/docs/development/apps/api/views/django-generic-views.html +4 -4
  128. nautobot/project-static/docs/development/apps/api/views/help-documentation.html +4 -4
  129. nautobot/project-static/docs/development/apps/api/views/index.html +4 -4
  130. nautobot/project-static/docs/development/apps/api/views/nautobot-generic-views.html +4 -4
  131. nautobot/project-static/docs/development/apps/api/views/nautobotuiviewset.html +4 -4
  132. nautobot/project-static/docs/development/apps/api/views/nautobotuiviewsetrouter.html +4 -4
  133. nautobot/project-static/docs/development/apps/api/views/notes.html +4 -4
  134. nautobot/project-static/docs/development/apps/api/views/rest-api.html +4 -4
  135. nautobot/project-static/docs/development/apps/api/views/urls.html +4 -4
  136. nautobot/project-static/docs/development/apps/index.html +4 -4
  137. nautobot/project-static/docs/development/apps/migration/code-updates.html +4 -4
  138. nautobot/project-static/docs/development/apps/migration/dependency-updates.html +4 -4
  139. nautobot/project-static/docs/development/apps/migration/from-v1.html +4 -4
  140. nautobot/project-static/docs/development/apps/migration/model-updates/dcim.html +4 -4
  141. nautobot/project-static/docs/development/apps/migration/model-updates/extras.html +4 -4
  142. nautobot/project-static/docs/development/apps/migration/model-updates/global.html +4 -4
  143. nautobot/project-static/docs/development/apps/migration/model-updates/ipam.html +4 -4
  144. nautobot/project-static/docs/development/apps/migration/ui-component-framework/best-practices.html +4 -4
  145. nautobot/project-static/docs/development/apps/migration/ui-component-framework/custom-content.html +4 -4
  146. nautobot/project-static/docs/development/apps/migration/ui-component-framework/index.html +4 -4
  147. nautobot/project-static/docs/development/apps/migration/ui-component-framework/migration-steps.html +4 -4
  148. nautobot/project-static/docs/development/apps/porting-from-netbox.html +4 -4
  149. nautobot/project-static/docs/development/core/application-registry.html +4 -4
  150. nautobot/project-static/docs/development/core/best-practices.html +4 -4
  151. nautobot/project-static/docs/development/core/bootstrap-ui.html +4 -4
  152. nautobot/project-static/docs/development/core/caching.html +4 -4
  153. nautobot/project-static/docs/development/core/controllers.html +4 -4
  154. nautobot/project-static/docs/development/core/docker-compose-advanced-use-cases.html +41 -55
  155. nautobot/project-static/docs/development/core/generic-views.html +4 -4
  156. nautobot/project-static/docs/development/core/getting-started.html +4 -4
  157. nautobot/project-static/docs/development/core/homepage.html +4 -4
  158. nautobot/project-static/docs/development/core/index.html +4 -4
  159. nautobot/project-static/docs/development/core/minikube-dev-environment-for-k8s-jobs.html +4 -4
  160. nautobot/project-static/docs/development/core/model-checklist.html +4 -4
  161. nautobot/project-static/docs/development/core/model-features.html +4 -4
  162. nautobot/project-static/docs/development/core/natural-keys.html +4 -4
  163. nautobot/project-static/docs/development/core/navigation-menu.html +4 -4
  164. nautobot/project-static/docs/development/core/release-checklist.html +4 -4
  165. nautobot/project-static/docs/development/core/role-internals.html +4 -4
  166. nautobot/project-static/docs/development/core/settings.html +4 -4
  167. nautobot/project-static/docs/development/core/style-guide.html +4 -4
  168. nautobot/project-static/docs/development/core/templates.html +4 -4
  169. nautobot/project-static/docs/development/core/testing.html +4 -4
  170. nautobot/project-static/docs/development/core/ui-component-framework.html +4 -4
  171. nautobot/project-static/docs/development/core/user-preferences.html +4 -4
  172. nautobot/project-static/docs/development/index.html +4 -4
  173. nautobot/project-static/docs/development/jobs/getting-started.html +4 -4
  174. nautobot/project-static/docs/development/jobs/index.html +4 -4
  175. nautobot/project-static/docs/development/jobs/installation.html +4 -4
  176. nautobot/project-static/docs/development/jobs/job-extensions.html +4 -4
  177. nautobot/project-static/docs/development/jobs/job-logging.html +4 -4
  178. nautobot/project-static/docs/development/jobs/job-patterns.html +4 -4
  179. nautobot/project-static/docs/development/jobs/job-structure.html +4 -4
  180. nautobot/project-static/docs/development/jobs/migration/from-v1.html +4 -4
  181. nautobot/project-static/docs/development/jobs/testing.html +4 -4
  182. nautobot/project-static/docs/index.html +4 -4
  183. nautobot/project-static/docs/overview/application_stack.html +4 -4
  184. nautobot/project-static/docs/overview/design_philosophy.html +4 -4
  185. nautobot/project-static/docs/release-notes/index.html +4 -4
  186. nautobot/project-static/docs/release-notes/version-1.0.html +4 -4
  187. nautobot/project-static/docs/release-notes/version-1.1.html +4 -4
  188. nautobot/project-static/docs/release-notes/version-1.2.html +4 -4
  189. nautobot/project-static/docs/release-notes/version-1.3.html +4 -4
  190. nautobot/project-static/docs/release-notes/version-1.4.html +4 -4
  191. nautobot/project-static/docs/release-notes/version-1.5.html +4 -4
  192. nautobot/project-static/docs/release-notes/version-1.6.html +301 -4
  193. nautobot/project-static/docs/release-notes/version-2.0.html +4 -4
  194. nautobot/project-static/docs/release-notes/version-2.1.html +4 -4
  195. nautobot/project-static/docs/release-notes/version-2.2.html +4 -4
  196. nautobot/project-static/docs/release-notes/version-2.3.html +4 -4
  197. nautobot/project-static/docs/release-notes/version-2.4.html +291 -4
  198. nautobot/project-static/docs/requirements.txt +1 -1
  199. nautobot/project-static/docs/search/search_index.json +1 -1
  200. nautobot/project-static/docs/sitemap.xml +298 -298
  201. nautobot/project-static/docs/sitemap.xml.gz +0 -0
  202. nautobot/project-static/docs/user-guide/administration/configuration/authentication/ldap.html +4 -4
  203. nautobot/project-static/docs/user-guide/administration/configuration/authentication/remote.html +4 -4
  204. nautobot/project-static/docs/user-guide/administration/configuration/authentication/sso.html +4 -4
  205. nautobot/project-static/docs/user-guide/administration/configuration/index.html +4 -4
  206. nautobot/project-static/docs/user-guide/administration/configuration/redis.html +4 -4
  207. nautobot/project-static/docs/user-guide/administration/configuration/settings.html +4 -4
  208. nautobot/project-static/docs/user-guide/administration/configuration/time-zones.html +4 -4
  209. nautobot/project-static/docs/user-guide/administration/guides/celery-queues.html +4 -4
  210. nautobot/project-static/docs/user-guide/administration/guides/docker.html +4 -4
  211. nautobot/project-static/docs/user-guide/administration/guides/health-checks.html +4 -4
  212. nautobot/project-static/docs/user-guide/administration/guides/permissions.html +4 -4
  213. nautobot/project-static/docs/user-guide/administration/guides/prometheus-metrics.html +4 -4
  214. nautobot/project-static/docs/user-guide/administration/guides/replicating-nautobot.html +4 -4
  215. nautobot/project-static/docs/user-guide/administration/guides/request-profiling.html +4 -4
  216. nautobot/project-static/docs/user-guide/administration/guides/s3-django-storage.html +4 -4
  217. nautobot/project-static/docs/user-guide/administration/guides/selinux-troubleshooting.html +4 -4
  218. nautobot/project-static/docs/user-guide/administration/installation/app-install.html +4 -4
  219. nautobot/project-static/docs/user-guide/administration/installation/external-authentication.html +4 -4
  220. nautobot/project-static/docs/user-guide/administration/installation/http-server.html +4 -4
  221. nautobot/project-static/docs/user-guide/administration/installation/index.html +4 -4
  222. nautobot/project-static/docs/user-guide/administration/installation/install_system.html +4 -4
  223. nautobot/project-static/docs/user-guide/administration/installation/nautobot.html +4 -4
  224. nautobot/project-static/docs/user-guide/administration/installation/services.html +4 -4
  225. nautobot/project-static/docs/user-guide/administration/migration/migrating-from-netbox.html +4 -4
  226. nautobot/project-static/docs/user-guide/administration/migration/migrating-from-postgresql.html +4 -4
  227. nautobot/project-static/docs/user-guide/administration/security/index.html +4 -5
  228. nautobot/project-static/docs/user-guide/administration/security/notices.html +117 -5
  229. nautobot/project-static/docs/user-guide/administration/tools/nautobot-server.html +4 -4
  230. nautobot/project-static/docs/user-guide/administration/tools/nautobot-shell.html +4 -4
  231. nautobot/project-static/docs/user-guide/administration/upgrading/database-backup.html +4 -4
  232. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/after-you-upgrade.html +4 -4
  233. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/before-you-upgrade.html +4 -4
  234. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/for-developers.html +4 -4
  235. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/index.html +4 -4
  236. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/whats-changed.html +4 -4
  237. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/region-and-site-data-migration-guide.html +4 -4
  238. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/upgrading-from-nautobot-v1.html +4 -4
  239. nautobot/project-static/docs/user-guide/administration/upgrading/upgrading.html +4 -4
  240. nautobot/project-static/docs/user-guide/core-data-model/circuits/circuit.html +4 -4
  241. nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittermination.html +4 -4
  242. nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittype.html +4 -4
  243. nautobot/project-static/docs/user-guide/core-data-model/circuits/provider.html +4 -4
  244. nautobot/project-static/docs/user-guide/core-data-model/circuits/providernetwork.html +4 -4
  245. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloud.html +4 -4
  246. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudaccount.html +4 -4
  247. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudnetwork.html +4 -4
  248. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudnetworkprefixassignment.html +4 -4
  249. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudresourcetype.html +4 -4
  250. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudservice.html +4 -4
  251. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudservicenetworkassignment.html +4 -4
  252. nautobot/project-static/docs/user-guide/core-data-model/dcim/cable.html +4 -4
  253. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleport.html +4 -4
  254. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleporttemplate.html +4 -4
  255. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverport.html +4 -4
  256. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverporttemplate.html +4 -4
  257. nautobot/project-static/docs/user-guide/core-data-model/dcim/controller.html +4 -4
  258. nautobot/project-static/docs/user-guide/core-data-model/dcim/controllermanageddevicegroup.html +4 -4
  259. nautobot/project-static/docs/user-guide/core-data-model/dcim/device.html +4 -4
  260. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebay.html +4 -4
  261. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebaytemplate.html +4 -4
  262. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicefamily.html +4 -4
  263. nautobot/project-static/docs/user-guide/core-data-model/dcim/deviceredundancygroup.html +4 -4
  264. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicetype.html +4 -4
  265. nautobot/project-static/docs/user-guide/core-data-model/dcim/frontport.html +4 -4
  266. nautobot/project-static/docs/user-guide/core-data-model/dcim/frontporttemplate.html +4 -4
  267. nautobot/project-static/docs/user-guide/core-data-model/dcim/interface.html +4 -4
  268. nautobot/project-static/docs/user-guide/core-data-model/dcim/interfaceredundancygroup.html +4 -4
  269. nautobot/project-static/docs/user-guide/core-data-model/dcim/interfacetemplate.html +4 -4
  270. nautobot/project-static/docs/user-guide/core-data-model/dcim/inventoryitem.html +4 -4
  271. nautobot/project-static/docs/user-guide/core-data-model/dcim/location.html +4 -4
  272. nautobot/project-static/docs/user-guide/core-data-model/dcim/locationtype.html +4 -4
  273. nautobot/project-static/docs/user-guide/core-data-model/dcim/manufacturer.html +4 -4
  274. nautobot/project-static/docs/user-guide/core-data-model/dcim/module.html +4 -4
  275. nautobot/project-static/docs/user-guide/core-data-model/dcim/modulebay.html +4 -4
  276. nautobot/project-static/docs/user-guide/core-data-model/dcim/modulebaytemplate.html +4 -4
  277. nautobot/project-static/docs/user-guide/core-data-model/dcim/moduletype.html +4 -4
  278. nautobot/project-static/docs/user-guide/core-data-model/dcim/platform.html +4 -4
  279. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerfeed.html +4 -4
  280. nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlet.html +4 -4
  281. nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlettemplate.html +4 -4
  282. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerpanel.html +4 -4
  283. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerport.html +4 -4
  284. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerporttemplate.html +4 -4
  285. nautobot/project-static/docs/user-guide/core-data-model/dcim/rack.html +4 -4
  286. nautobot/project-static/docs/user-guide/core-data-model/dcim/rackgroup.html +4 -4
  287. nautobot/project-static/docs/user-guide/core-data-model/dcim/rackreservation.html +4 -4
  288. nautobot/project-static/docs/user-guide/core-data-model/dcim/rearport.html +4 -4
  289. nautobot/project-static/docs/user-guide/core-data-model/dcim/rearporttemplate.html +4 -4
  290. nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareimagefile.html +4 -4
  291. nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareversion.html +4 -4
  292. nautobot/project-static/docs/user-guide/core-data-model/dcim/virtualchassis.html +4 -4
  293. nautobot/project-static/docs/user-guide/core-data-model/dcim/virtualdevicecontext.html +4 -4
  294. nautobot/project-static/docs/user-guide/core-data-model/extras/configcontext.html +4 -4
  295. nautobot/project-static/docs/user-guide/core-data-model/extras/configcontextschema.html +4 -4
  296. nautobot/project-static/docs/user-guide/core-data-model/extras/contact.html +4 -4
  297. nautobot/project-static/docs/user-guide/core-data-model/extras/team.html +4 -4
  298. nautobot/project-static/docs/user-guide/core-data-model/ipam/ipaddress.html +4 -4
  299. nautobot/project-static/docs/user-guide/core-data-model/ipam/namespace.html +4 -4
  300. nautobot/project-static/docs/user-guide/core-data-model/ipam/prefix.html +4 -4
  301. nautobot/project-static/docs/user-guide/core-data-model/ipam/rir.html +4 -4
  302. nautobot/project-static/docs/user-guide/core-data-model/ipam/routetarget.html +4 -4
  303. nautobot/project-static/docs/user-guide/core-data-model/ipam/service.html +4 -4
  304. nautobot/project-static/docs/user-guide/core-data-model/ipam/vlan.html +4 -4
  305. nautobot/project-static/docs/user-guide/core-data-model/ipam/vlangroup.html +4 -4
  306. nautobot/project-static/docs/user-guide/core-data-model/ipam/vrf.html +4 -4
  307. nautobot/project-static/docs/user-guide/core-data-model/overview/introduction.html +4 -4
  308. nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenant.html +4 -4
  309. nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenantgroup.html +4 -4
  310. nautobot/project-static/docs/user-guide/core-data-model/virtualization/cluster.html +4 -4
  311. nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustergroup.html +4 -4
  312. nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustertype.html +4 -4
  313. nautobot/project-static/docs/user-guide/core-data-model/virtualization/virtualmachine.html +4 -4
  314. nautobot/project-static/docs/user-guide/core-data-model/virtualization/vminterface.html +4 -4
  315. nautobot/project-static/docs/user-guide/core-data-model/wireless/index.html +4 -4
  316. nautobot/project-static/docs/user-guide/core-data-model/wireless/radioprofile.html +4 -4
  317. nautobot/project-static/docs/user-guide/core-data-model/wireless/supporteddatarate.html +4 -4
  318. nautobot/project-static/docs/user-guide/core-data-model/wireless/wirelessnetwork.html +4 -4
  319. nautobot/project-static/docs/user-guide/feature-guides/contacts-and-teams.html +4 -4
  320. nautobot/project-static/docs/user-guide/feature-guides/custom-fields.html +4 -4
  321. nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-devices.html +4 -4
  322. nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-location-types-and-locations.html +4 -4
  323. nautobot/project-static/docs/user-guide/feature-guides/getting-started/index.html +4 -4
  324. nautobot/project-static/docs/user-guide/feature-guides/getting-started/interfaces.html +4 -4
  325. nautobot/project-static/docs/user-guide/feature-guides/getting-started/ipam.html +4 -4
  326. nautobot/project-static/docs/user-guide/feature-guides/getting-started/platforms.html +4 -4
  327. nautobot/project-static/docs/user-guide/feature-guides/getting-started/search-bar.html +4 -4
  328. nautobot/project-static/docs/user-guide/feature-guides/getting-started/tenants.html +4 -4
  329. nautobot/project-static/docs/user-guide/feature-guides/getting-started/vlans-and-vlan-groups.html +4 -4
  330. nautobot/project-static/docs/user-guide/feature-guides/git-data-source.html +4 -4
  331. nautobot/project-static/docs/user-guide/feature-guides/graphql.html +4 -4
  332. nautobot/project-static/docs/user-guide/feature-guides/ip-address-merge-tool.html +4 -4
  333. nautobot/project-static/docs/user-guide/feature-guides/relationships.html +4 -4
  334. nautobot/project-static/docs/user-guide/feature-guides/software-image-files-and-versions.html +4 -4
  335. nautobot/project-static/docs/user-guide/feature-guides/wireless-networks-and-controllers.html +4 -4
  336. nautobot/project-static/docs/user-guide/index.html +4 -4
  337. nautobot/project-static/docs/user-guide/platform-functionality/change-logging.html +4 -4
  338. nautobot/project-static/docs/user-guide/platform-functionality/computedfield.html +4 -4
  339. nautobot/project-static/docs/user-guide/platform-functionality/customfield.html +4 -4
  340. nautobot/project-static/docs/user-guide/platform-functionality/customlink.html +4 -4
  341. nautobot/project-static/docs/user-guide/platform-functionality/dynamicgroup.html +4 -4
  342. nautobot/project-static/docs/user-guide/platform-functionality/events.html +4 -4
  343. nautobot/project-static/docs/user-guide/platform-functionality/exporttemplate.html +4 -4
  344. nautobot/project-static/docs/user-guide/platform-functionality/externalintegration.html +4 -4
  345. nautobot/project-static/docs/user-guide/platform-functionality/gitrepository.html +4 -4
  346. nautobot/project-static/docs/user-guide/platform-functionality/graphql.html +4 -4
  347. nautobot/project-static/docs/user-guide/platform-functionality/graphqlquery.html +4 -4
  348. nautobot/project-static/docs/user-guide/platform-functionality/imageattachment.html +4 -4
  349. nautobot/project-static/docs/user-guide/platform-functionality/jobs/index.html +4 -4
  350. nautobot/project-static/docs/user-guide/platform-functionality/jobs/job-scheduling-and-approvals.html +4 -4
  351. nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobbutton.html +4 -4
  352. nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobhook.html +4 -4
  353. nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobqueue.html +4 -4
  354. nautobot/project-static/docs/user-guide/platform-functionality/jobs/kubernetes-job-support.html +4 -4
  355. nautobot/project-static/docs/user-guide/platform-functionality/jobs/managing-jobs.html +4 -4
  356. nautobot/project-static/docs/user-guide/platform-functionality/jobs/models.html +4 -4
  357. nautobot/project-static/docs/user-guide/platform-functionality/napalm.html +4 -4
  358. nautobot/project-static/docs/user-guide/platform-functionality/note.html +4 -4
  359. nautobot/project-static/docs/user-guide/platform-functionality/objectmetadata.html +4 -4
  360. nautobot/project-static/docs/user-guide/platform-functionality/relationship.html +4 -4
  361. nautobot/project-static/docs/user-guide/platform-functionality/rendering-jinja-templates.html +4 -4
  362. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/authentication.html +4 -4
  363. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/filtering.html +4 -4
  364. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/overview.html +4 -4
  365. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/ui-related-endpoints.html +4 -4
  366. nautobot/project-static/docs/user-guide/platform-functionality/role.html +4 -4
  367. nautobot/project-static/docs/user-guide/platform-functionality/savedview.html +4 -4
  368. nautobot/project-static/docs/user-guide/platform-functionality/secret.html +4 -4
  369. nautobot/project-static/docs/user-guide/platform-functionality/staticgroupassociation.html +4 -4
  370. nautobot/project-static/docs/user-guide/platform-functionality/status.html +4 -4
  371. nautobot/project-static/docs/user-guide/platform-functionality/tag.html +4 -4
  372. nautobot/project-static/docs/user-guide/platform-functionality/template-filters.html +4 -4
  373. nautobot/project-static/docs/user-guide/platform-functionality/users/objectpermission.html +4 -4
  374. nautobot/project-static/docs/user-guide/platform-functionality/users/token.html +4 -4
  375. nautobot/project-static/docs/user-guide/platform-functionality/webhook.html +4 -4
  376. nautobot/project-static/js/forms.js +0 -14
  377. nautobot/users/models.py +4 -0
  378. nautobot/virtualization/models.py +4 -0
  379. nautobot/wireless/tables.py +1 -0
  380. nautobot/wireless/templates/wireless/wirelessnetwork_retrieve.html +1 -55
  381. nautobot/wireless/views.py +33 -28
  382. {nautobot-2.4.8.dist-info → nautobot-2.4.10.dist-info}/METADATA +4 -4
  383. {nautobot-2.4.8.dist-info → nautobot-2.4.10.dist-info}/RECORD +387 -384
  384. {nautobot-2.4.8.dist-info → nautobot-2.4.10.dist-info}/LICENSE.txt +0 -0
  385. {nautobot-2.4.8.dist-info → nautobot-2.4.10.dist-info}/NOTICE +0 -0
  386. {nautobot-2.4.8.dist-info → nautobot-2.4.10.dist-info}/WHEEL +0 -0
  387. {nautobot-2.4.8.dist-info → nautobot-2.4.10.dist-info}/entry_points.txt +0 -0
@@ -1739,7 +1739,7 @@ class JobTest(
1739
1739
  # Ensure the enqueue_job args deserialize to the same as originally inputted
1740
1740
  expected_enqueue_job_args = (self.job_model, self.user)
1741
1741
  expected_enqueue_job_kwargs = {
1742
- "task_queue": self.job_model.default_job_queue.name,
1742
+ "job_queue": self.job_model.default_job_queue,
1743
1743
  **self.job_class.serialize_data(deserialized_data),
1744
1744
  }
1745
1745
  mock_enqueue_job.assert_called_with(*expected_enqueue_job_args, **expected_enqueue_job_kwargs)
@@ -2,6 +2,7 @@ from unittest import mock
2
2
 
3
3
  from django.contrib.auth import get_user_model
4
4
  from django.contrib.contenttypes.models import ContentType
5
+ from django.core.exceptions import ValidationError
5
6
  from django.test import TestCase
6
7
 
7
8
  from nautobot.core.celery import app
@@ -220,6 +221,25 @@ class WebRequestContextTestCase(TestCase):
220
221
  self.assertEqual(call_args[6], oc_list[0].request_id)
221
222
  self.assertEqual(call_args[7], oc_list[0].get_snapshots())
222
223
 
224
+ def test_web_request_context_raises_exception_correctly(self):
225
+ """
226
+ Test implemented to ensure the fix for https://github.com/nautobot/nautobot/issues/7358 is working as intended.
227
+ The operation should raise and allow an exception to be passed through instead of raising an
228
+ AttributeError: 'NoneType' object has no attribute 'get'"
229
+ """
230
+ valid_location_type = LocationType.objects.get(name="Campus")
231
+ location_status = Status.objects.get_for_model(Location).first()
232
+ invalid_location_type = LocationType(name="rackgroup")
233
+ with self.assertRaises(ValidationError):
234
+ with web_request_context(self.user, context_detail="test_web_request_context_raises_exception_correctly"):
235
+ # These operations should generate some ObjectChange records to test the code path that was causing the reported issue.
236
+ location = Location(name="Test Location 1", location_type=valid_location_type, status=location_status)
237
+ location.save()
238
+ location.description = "changed"
239
+ location.save()
240
+ # Location type name is not allowed to be "rackgroup" (reserved name), so this should raise an exception.
241
+ invalid_location_type.validated_save()
242
+
223
243
 
224
244
  class WebRequestContextTransactionTestCase(TransactionTestCase):
225
245
  def test_change_log_thread_safe(self):
@@ -125,6 +125,13 @@ class ComputedFieldTest(ModelTestCases.BaseModelTestCase):
125
125
  fallback_value="An error occurred while rendering this template.",
126
126
  weight=50,
127
127
  )
128
+ self.evil_computed_field = ComputedField.objects.create(
129
+ content_type=ContentType.objects.get_for_model(Secret),
130
+ key="evil_computed_field",
131
+ label="Evil Computed Field",
132
+ template="{{ obj.get_value() }}",
133
+ weight=666,
134
+ )
128
135
  self.blank_fallback_value = ComputedField.objects.create(
129
136
  content_type=ContentType.objects.get_for_model(Location),
130
137
  key="blank_fallback_value",
@@ -133,6 +140,18 @@ class ComputedFieldTest(ModelTestCases.BaseModelTestCase):
133
140
  weight=50,
134
141
  )
135
142
  self.location1 = Location.objects.filter(location_type=LocationType.objects.get(name="Campus")).first()
143
+ self.secret = Secret.objects.create(
144
+ name="Environment Variable Secret",
145
+ provider="environment-variable",
146
+ parameters={"variable": "NAUTOBOT_ROOT"},
147
+ )
148
+ self.secrets_group = SecretsGroup.objects.create(name="Group of Secrets")
149
+ SecretsGroupAssociation.objects.create(
150
+ secrets_group=self.secrets_group,
151
+ secret=self.secret,
152
+ access_type=SecretsGroupAccessTypeChoices.TYPE_GENERIC,
153
+ secret_type=SecretsGroupSecretTypeChoices.TYPE_SECRET,
154
+ )
136
155
 
137
156
  def test_render_method(self):
138
157
  rendered_value = self.good_computed_field.render(context={"obj": self.location1})
@@ -146,6 +165,13 @@ class ComputedFieldTest(ModelTestCases.BaseModelTestCase):
146
165
  rendered_value = self.bad_computed_field.render(context={"obj": self.location1})
147
166
  self.assertEqual(rendered_value, self.bad_computed_field.fallback_value)
148
167
 
168
+ def test_render_method_evil_template(self):
169
+ rendered_value = self.evil_computed_field.render(context={"obj": self.secret})
170
+ self.assertEqual(rendered_value, "")
171
+ self.evil_computed_field.template = "{{ obj.secrets_groups.first().get_secret_value('Generic', 'secret') }}"
172
+ rendered_value = self.evil_computed_field.render(context={"obj": self.secret})
173
+ self.assertEqual(rendered_value, "")
174
+
149
175
  def test_check_if_key_is_graphql_safe(self):
150
176
  """
151
177
  Check the GraphQL validation method on CustomField Key Attribute.
@@ -1162,6 +1162,15 @@ class GitRepositoryTestCase(
1162
1162
  ):
1163
1163
  model = GitRepository
1164
1164
  slugify_function = staticmethod(slugify_dashes_to_underscores)
1165
+ expected_edit_form_buttons = [
1166
+ '<button type="submit" name="_dryrun_update" class="btn btn-warning">Update & Dry Run</button>',
1167
+ '<button type="submit" name="_update" class="btn btn-primary">Update & Sync</button>',
1168
+ ]
1169
+ expected_create_form_buttons = [
1170
+ '<button type="submit" name="_dryrun_create" class="btn btn-info">Create & Dry Run</button>',
1171
+ '<button type="submit" name="_create" class="btn btn-primary">Create & Sync</button>',
1172
+ '<button type="submit" name="_addanother" class="btn btn-primary">Create and Add Another</button>',
1173
+ ]
1165
1174
 
1166
1175
  @classmethod
1167
1176
  def setUpTestData(cls):
@@ -2773,10 +2782,14 @@ class JobTestCase(
2773
2782
  @mock.patch("nautobot.extras.views.get_worker_count", return_value=0)
2774
2783
  def test_run_now_no_worker(self, _):
2775
2784
  self.add_permissions("extras.run_job")
2785
+ self.add_permissions("extras.view_jobresult")
2776
2786
 
2777
2787
  for run_url in self.run_urls:
2778
- response = self.client.post(run_url, self.data_run_immediately)
2779
- self.assertBodyContains(response, "Celery worker process not running.")
2788
+ response = self.client.post(run_url, self.data_run_immediately, follow=True)
2789
+
2790
+ result = JobResult.objects.latest()
2791
+ self.assertRedirects(response, reverse("extras:jobresult", kwargs={"pk": result.pk}))
2792
+ self.assertBodyContains(response, "No celery workers found")
2780
2793
 
2781
2794
  @mock.patch("nautobot.extras.views.get_worker_count", return_value=1)
2782
2795
  def test_run_now(self, _):
nautobot/extras/utils.py CHANGED
@@ -6,7 +6,7 @@ import hmac
6
6
  import logging
7
7
  import re
8
8
  import sys
9
- from typing import Optional
9
+ from typing import Optional, TYPE_CHECKING, Union
10
10
 
11
11
  from django.apps import apps
12
12
  from django.conf import settings
@@ -37,6 +37,9 @@ from nautobot.extras.constants import (
37
37
  )
38
38
  from nautobot.extras.registry import registry
39
39
 
40
+ if TYPE_CHECKING:
41
+ from nautobot.extras.models import JobQueue
42
+
40
43
  logger = logging.getLogger(__name__)
41
44
 
42
45
 
@@ -409,10 +412,12 @@ def get_celery_queues():
409
412
  return celery_queues
410
413
 
411
414
 
412
- def get_worker_count(request=None, queue=None):
415
+ def get_worker_count(request=None, queue: Optional[Union[str, "JobQueue"]] = None) -> int:
413
416
  """
414
- Return a count of the active Celery workers in a specified queue (Could be a JobQueue instance, instance pk or instance name).
415
- Defaults to the `CELERY_TASK_DEFAULT_QUEUE` setting.
417
+ Return a count of the active Celery workers in a specified queue.
418
+
419
+ Args:
420
+ queue (str, JobQueue, None): queue name or JobQueue to check; if unset, defaults to CELERY_TASK_DEFAULT_QUEUE.
416
421
  """
417
422
  from nautobot.extras.models import JobQueue
418
423
 
@@ -434,7 +439,7 @@ def get_worker_count(request=None, queue=None):
434
439
  return celery_queues.get(queue, 0)
435
440
 
436
441
 
437
- def get_job_queue_worker_count(request=None, job_queue=None):
442
+ def get_job_queue_worker_count(request=None, job_queue: Optional["JobQueue"] = None) -> int:
438
443
  """
439
444
  Return a count of the active Celery workers in a specified queue. Defaults to the `CELERY_TASK_DEFAULT_QUEUE` setting.
440
445
  Same as get_worker_count() method above, but job_queue is an actual JobQueue model instance.
@@ -449,27 +454,24 @@ def get_job_queue_worker_count(request=None, job_queue=None):
449
454
  return celery_queues.get(queue, 0)
450
455
 
451
456
 
452
- def get_job_queue(job_queue):
457
+ def get_job_queue(job_queue: str) -> Optional["JobQueue"]:
453
458
  """
454
459
  Search for a JobQueue instance based on the str job_queue.
455
460
  If no existing Job Queue not found, return None
456
461
  """
457
462
  from nautobot.extras.models import JobQueue
458
463
 
459
- queue = None
460
464
  if is_uuid(job_queue):
461
465
  try:
462
466
  # check if the string passed in is a valid UUID
463
- queue = JobQueue.objects.get(pk=job_queue)
467
+ return JobQueue.objects.get(pk=job_queue)
464
468
  except JobQueue.DoesNotExist:
465
- queue = None
466
- else:
467
- try:
468
- # check if the string passed in is a valid name
469
- queue = JobQueue.objects.get(name=job_queue)
470
- except JobQueue.DoesNotExist:
471
- queue = None
472
- return queue
469
+ return None
470
+ try:
471
+ # check if the string passed in is a valid name
472
+ return JobQueue.objects.get(name=job_queue)
473
+ except JobQueue.DoesNotExist:
474
+ return None
473
475
 
474
476
 
475
477
  def task_queues_as_choices(task_queues):
nautobot/extras/views.py CHANGED
@@ -73,7 +73,7 @@ from nautobot.dcim.tables import (
73
73
  VirtualDeviceContextTable,
74
74
  )
75
75
  from nautobot.extras.context_managers import deferred_change_logging_for_bulk_operation
76
- from nautobot.extras.utils import fixup_filterset_query_params, get_base_template, get_job_queue, get_worker_count
76
+ from nautobot.extras.utils import fixup_filterset_query_params, get_base_template, get_worker_count
77
77
  from nautobot.ipam.models import IPAddress, Prefix, VLAN
78
78
  from nautobot.ipam.tables import IPAddressTable, PrefixTable, VLANTable
79
79
  from nautobot.virtualization.models import VirtualMachine, VMInterface
@@ -153,6 +153,23 @@ class ComputedFieldUIViewSet(NautobotUIViewSet):
153
153
  table_class = tables.ComputedFieldTable
154
154
  queryset = ComputedField.objects.all()
155
155
  action_buttons = ("add",)
156
+ object_detail_content = object_detail.ObjectDetailContent(
157
+ panels=(
158
+ object_detail.ObjectFieldsPanel(
159
+ section=SectionChoices.LEFT_HALF,
160
+ weight=100,
161
+ fields="__all__",
162
+ exclude_fields=["template"],
163
+ ),
164
+ ObjectTextPanel(
165
+ label="Template",
166
+ section=SectionChoices.FULL_WIDTH,
167
+ weight=100,
168
+ object_field="template",
169
+ render_as=ObjectTextPanel.RenderOptions.CODE,
170
+ ),
171
+ ),
172
+ )
156
173
 
157
174
 
158
175
  #
@@ -1359,14 +1376,16 @@ class JobRunView(ObjectPermissionRequiredMixin, View):
1359
1376
  # for example "?kwargs_from_job_result=<UUID>&integervar=22"
1360
1377
  explicit_initial = initial
1361
1378
  initial = job_result.task_kwargs.copy()
1362
- job_queue = job_result.celery_kwargs.get("queue", None)
1363
- jq = None
1364
- if job_queue is not None:
1379
+ task_queue = job_result.celery_kwargs.get("queue", None)
1380
+ job_queue = None
1381
+ if task_queue is not None:
1365
1382
  try:
1366
- jq = JobQueue.objects.get(name=job_queue, queue_type=JobQueueTypeChoices.TYPE_CELERY)
1383
+ job_queue = JobQueue.objects.get(
1384
+ name=task_queue, queue_type=JobQueueTypeChoices.TYPE_CELERY
1385
+ )
1367
1386
  except JobQueue.DoesNotExist:
1368
1387
  pass
1369
- initial["_job_queue"] = jq
1388
+ initial["_job_queue"] = job_queue
1370
1389
  initial["_profile"] = job_result.celery_kwargs.get("nautobot_job_profile", False)
1371
1390
  initial["_ignore_singleton_lock"] = job_result.celery_kwargs.get(
1372
1391
  "nautobot_job_ignore_singleton_lock", False
@@ -1410,7 +1429,6 @@ class JobRunView(ObjectPermissionRequiredMixin, View):
1410
1429
  job_class = get_job(job_model.class_path, reload=True)
1411
1430
  job_form = job_class.as_form(request.POST, request.FILES) if job_class is not None else None
1412
1431
  schedule_form = forms.JobScheduleForm(request.POST)
1413
- job_queue = request.POST.get("_job_queue")
1414
1432
 
1415
1433
  return_url = request.POST.get("_return_url")
1416
1434
  if return_url is not None and url_has_allowed_host_and_scheme(url=return_url, allowed_hosts=request.get_host()):
@@ -1418,13 +1436,8 @@ class JobRunView(ObjectPermissionRequiredMixin, View):
1418
1436
  else:
1419
1437
  return_url = None
1420
1438
 
1421
- queue = get_job_queue(job_queue)
1422
- if queue is None:
1423
- queue = job_model.default_job_queue
1424
- # Allow execution only if a worker process is running on a celery queue and the job is runnable.
1425
- if queue.queue_type == JobQueueTypeChoices.TYPE_CELERY and not get_worker_count(queue=job_queue):
1426
- messages.error(request, "Unable to run or schedule job: Celery worker process not running.")
1427
- elif not job_model.installed or job_class is None:
1439
+ # Allow execution only if the job is runnable.
1440
+ if not job_model.installed or job_class is None:
1428
1441
  messages.error(request, "Unable to run or schedule job: Job is not presently installed.")
1429
1442
  elif not job_model.enabled:
1430
1443
  messages.error(request, "Unable to run or schedule job: Job is not enabled to be run.")
@@ -1442,15 +1455,17 @@ class JobRunView(ObjectPermissionRequiredMixin, View):
1442
1455
  )
1443
1456
  elif job_form is not None and job_form.is_valid() and schedule_form.is_valid():
1444
1457
  job_queue = job_form.cleaned_data.pop("_job_queue", None)
1445
- jq = None
1446
- if job_queue is not None:
1447
- try:
1448
- jq = JobQueue.objects.get(pk=job_queue)
1449
- except (ValidationError, JobQueue.DoesNotExist):
1450
- try:
1451
- jq = JobQueue.objects.get(name=job_queue)
1452
- except JobQueue.DoesNotExist:
1453
- pass
1458
+ if job_queue is None:
1459
+ job_queue = job_model.default_job_queue
1460
+
1461
+ if job_queue.queue_type == JobQueueTypeChoices.TYPE_CELERY and not get_worker_count(queue=job_queue):
1462
+ messages.warning(
1463
+ request,
1464
+ format_html(
1465
+ "No celery workers found for queue {}, job may never run unless a worker is started.",
1466
+ job_queue,
1467
+ ),
1468
+ )
1454
1469
 
1455
1470
  dryrun = job_form.cleaned_data.get("dryrun", False)
1456
1471
  # Run the job. A new JobResult is created.
@@ -1467,7 +1482,7 @@ class JobRunView(ObjectPermissionRequiredMixin, View):
1467
1482
  interval=schedule_type,
1468
1483
  crontab=schedule_form.cleaned_data.get("_recurrence_custom_time"),
1469
1484
  approval_required=job_model.approval_required,
1470
- task_queue=jq.name if jq else None,
1485
+ job_queue=job_queue,
1471
1486
  profile=profile,
1472
1487
  ignore_singleton_lock=ignore_singleton_lock,
1473
1488
  **job_class.serialize_data(job_form.cleaned_data),
@@ -1488,7 +1503,7 @@ class JobRunView(ObjectPermissionRequiredMixin, View):
1488
1503
  request.user,
1489
1504
  profile=profile,
1490
1505
  ignore_singleton_lock=ignore_singleton_lock,
1491
- task_queue=jq.name if jq else None,
1506
+ job_queue=job_queue,
1492
1507
  **job_class.serialize_data(job_kwargs),
1493
1508
  )
1494
1509
 
@@ -1585,7 +1600,7 @@ class JobApprovalRequestView(generic.ObjectView):
1585
1600
  if job_class is not None:
1586
1601
  # Render the form with all fields disabled
1587
1602
  initial = instance.kwargs
1588
- initial["_job_queue"] = instance.queue
1603
+ initial["_job_queue"] = instance.job_queue
1589
1604
  initial["_profile"] = instance.celery_kwargs.get("profile", False)
1590
1605
  job_form = job_class().as_form(initial=initial, approval_view=True)
1591
1606
  else:
@@ -2312,6 +2327,28 @@ class MetadataTypeUIViewSet(NautobotUIViewSet):
2312
2327
  serializer_class = serializers.MetadataTypeSerializer
2313
2328
  table_class = tables.MetadataTypeTable
2314
2329
 
2330
+ object_detail_content = object_detail.ObjectDetailContent(
2331
+ panels=(
2332
+ object_detail.ObjectFieldsPanel(
2333
+ section=SectionChoices.LEFT_HALF,
2334
+ weight=100,
2335
+ exclude_fields=("content_types",),
2336
+ ),
2337
+ object_detail.ObjectsTablePanel(
2338
+ section=SectionChoices.LEFT_HALF,
2339
+ weight=200,
2340
+ context_table_key="choices",
2341
+ table_title="Choices",
2342
+ ),
2343
+ object_detail.ObjectFieldsPanel(
2344
+ section=SectionChoices.RIGHT_HALF,
2345
+ weight=100,
2346
+ fields=["content_types"],
2347
+ label="Assignment",
2348
+ ),
2349
+ ),
2350
+ )
2351
+
2315
2352
  def get_extra_context(self, request, instance):
2316
2353
  context = super().get_extra_context(request, instance)
2317
2354
 
@@ -2320,6 +2357,8 @@ class MetadataTypeUIViewSet(NautobotUIViewSet):
2320
2357
  context["choices"] = forms.MetadataChoiceFormSet(data=request.POST, instance=instance)
2321
2358
  else:
2322
2359
  context["choices"] = forms.MetadataChoiceFormSet(instance=instance)
2360
+ elif self.action == "retrieve":
2361
+ context["choices"] = tables.MetadataChoiceTable(instance.choices.all())
2323
2362
 
2324
2363
  return context
2325
2364
 
nautobot/ipam/models.py CHANGED
@@ -200,6 +200,8 @@ class VRF(PrimaryModel):
200
200
  instance.validated_save()
201
201
  return instance
202
202
 
203
+ add_device.alters_data = True
204
+
203
205
  def remove_device(self, device):
204
206
  """
205
207
  Remove a `device` from this VRF.
@@ -213,6 +215,8 @@ class VRF(PrimaryModel):
213
215
  instance = self.devices.through.objects.get(vrf=self, device=device)
214
216
  return instance.delete()
215
217
 
218
+ remove_device.alters_data = True
219
+
216
220
  def add_virtual_machine(self, virtual_machine, rd="", name=""):
217
221
  """
218
222
  Add a `virtual_machine` to this VRF, optionally overloading `rd` and `name`.
@@ -231,6 +235,8 @@ class VRF(PrimaryModel):
231
235
  instance.validated_save()
232
236
  return instance
233
237
 
238
+ add_virtual_machine.alters_data = True
239
+
234
240
  def remove_virtual_machine(self, virtual_machine):
235
241
  """
236
242
  Remove a `virtual_machine` from this VRF.
@@ -244,6 +250,8 @@ class VRF(PrimaryModel):
244
250
  instance = self.virtual_machines.through.objects.get(vrf=self, virtual_machine=virtual_machine)
245
251
  return instance.delete()
246
252
 
253
+ remove_virtual_machine.alters_data = True
254
+
247
255
  def add_virtual_device_context(self, virtual_device_context, rd="", name=""):
248
256
  """
249
257
  Add a `virtual_device_context` to this VRF, optionally overloading `rd` and `name`.
@@ -264,6 +272,8 @@ class VRF(PrimaryModel):
264
272
  instance.validated_save()
265
273
  return instance
266
274
 
275
+ add_virtual_device_context.alters_data = True
276
+
267
277
  def remove_virtual_device_context(self, virtual_device_context):
268
278
  """
269
279
  Remove a `virtual_device_context` from this VRF.
@@ -279,6 +289,8 @@ class VRF(PrimaryModel):
279
289
  )
280
290
  return instance.delete()
281
291
 
292
+ remove_virtual_device_context.alters_data = True
293
+
282
294
  def add_prefix(self, prefix):
283
295
  """
284
296
  Add a `prefix` to this VRF. Each object must be in the same Namespace.
@@ -293,6 +305,8 @@ class VRF(PrimaryModel):
293
305
  instance.validated_save()
294
306
  return instance
295
307
 
308
+ add_prefix.alters_data = True
309
+
296
310
  def remove_prefix(self, prefix):
297
311
  """
298
312
  Remove a `prefix` from this VRF.
@@ -306,6 +320,8 @@ class VRF(PrimaryModel):
306
320
  instance = self.prefixes.through.objects.get(vrf=self, prefix=prefix)
307
321
  return instance.delete()
308
322
 
323
+ remove_prefix.alters_data = True
324
+
309
325
 
310
326
  @extras_features("graphql")
311
327
  class VRFDeviceAssignment(BaseModel):
@@ -374,6 +390,8 @@ class VRFDeviceAssignment(BaseModel):
374
390
  "A VRFDeviceAssignment entry must be associated with a device, a virtual machine, or a virtual device context."
375
391
  )
376
392
 
393
+ clean.alters_data = True
394
+
377
395
 
378
396
  @extras_features("graphql")
379
397
  class VRFPrefixAssignment(BaseModel):
@@ -640,6 +658,8 @@ class Prefix(PrimaryModel):
640
658
  self.prefix_length = prefix.prefixlen
641
659
  self.ip_version = prefix.version
642
660
 
661
+ _deconstruct_prefix.alters_data = True
662
+
643
663
  def delete(self, *args, **kwargs):
644
664
  """
645
665
  A Prefix with children will be impossible to delete and raise a `ProtectedError`.
@@ -705,6 +725,8 @@ class Prefix(PrimaryModel):
705
725
  return parent
706
726
  return None
707
727
 
728
+ get_parent.alters_data = True
729
+
708
730
  def clean(self):
709
731
  if self.prefix is not None: # missing network/prefix_length will be caught by super().clean()
710
732
  # Clear host bits from prefix
@@ -716,6 +738,8 @@ class Prefix(PrimaryModel):
716
738
 
717
739
  super().clean()
718
740
 
741
+ clean.alters_data = True
742
+
719
743
  def save(self, *args, **kwargs):
720
744
  self.clean()
721
745
 
@@ -821,6 +845,8 @@ class Prefix(PrimaryModel):
821
845
 
822
846
  return query.update(parent=self)
823
847
 
848
+ reparent_subnets.alters_data = True
849
+
824
850
  def reparent_ips(self):
825
851
  """Determine the list of child IPAddresses and set the parent to self."""
826
852
  query = IPAddress.objects.select_for_update().filter(
@@ -832,6 +858,8 @@ class Prefix(PrimaryModel):
832
858
 
833
859
  return query.update(parent=self)
834
860
 
861
+ reparent_ips.alters_data = True
862
+
835
863
  def supernets(self, direct=False, include_self=False, for_update=False):
836
864
  """
837
865
  Return supernets of this Prefix.
@@ -1228,6 +1256,8 @@ class IPAddress(PrimaryModel):
1228
1256
  self.mask_length = address.prefixlen
1229
1257
  self.ip_version = address.version
1230
1258
 
1259
+ _deconstruct_address.alters_data = True
1260
+
1231
1261
  natural_key_field_names = ["parent__namespace", "host"]
1232
1262
 
1233
1263
  def _get_closest_parent(self):
@@ -1289,6 +1319,8 @@ class IPAddress(PrimaryModel):
1289
1319
 
1290
1320
  super().clean()
1291
1321
 
1322
+ clean.alters_data = True
1323
+
1292
1324
  def save(self, *args, **kwargs):
1293
1325
  self.clean() # MUST do data fixup as above
1294
1326
 
nautobot/ipam/tables.py CHANGED
@@ -214,7 +214,7 @@ class NamespaceTable(BaseTable):
214
214
  class VRFTable(StatusTableMixin, BaseTable):
215
215
  pk = ToggleColumn()
216
216
  name = tables.LinkColumn()
217
- # rd = tables.Column(verbose_name="RD")
217
+ rd = tables.Column(verbose_name="RD")
218
218
  tenant = TenantColumn()
219
219
  import_targets = tables.TemplateColumn(template_code=VRF_TARGETS, orderable=False)
220
220
  export_targets = tables.TemplateColumn(template_code=VRF_TARGETS, orderable=False)
@@ -225,7 +225,7 @@ class VRFTable(StatusTableMixin, BaseTable):
225
225
  fields = (
226
226
  "pk",
227
227
  "name",
228
- # "rd",
228
+ "rd",
229
229
  "status",
230
230
  "namespace",
231
231
  "tenant",
@@ -234,8 +234,7 @@ class VRFTable(StatusTableMixin, BaseTable):
234
234
  "export_targets",
235
235
  "tags",
236
236
  )
237
- # default_columns = ("pk", "name", "rd", "namespace", "tenant", "description")
238
- default_columns = ("pk", "name", "status", "namespace", "tenant", "description")
237
+ default_columns = ("pk", "name", "rd", "status", "namespace", "tenant", "description")
239
238
 
240
239
 
241
240
  class VRFDeviceAssignmentTable(BaseTable):
@@ -12,7 +12,7 @@
12
12
 
13
13
 
14
14
  <link rel="icon" href="/projects/core/en/stable/assets/favicon.ico">
15
- <meta name="generator" content="mkdocs-1.6.1, mkdocs-material-9.6.12">
15
+ <meta name="generator" content="mkdocs-1.6.1, mkdocs-material-9.6.14">
16
16
 
17
17
 
18
18
 
@@ -20,7 +20,7 @@
20
20
 
21
21
 
22
22
 
23
- <link rel="stylesheet" href="/projects/core/en/stable/assets/stylesheets/main.2afb09e1.min.css">
23
+ <link rel="stylesheet" href="/projects/core/en/stable/assets/stylesheets/main.342714a4.min.css">
24
24
 
25
25
 
26
26
  <link rel="stylesheet" href="/projects/core/en/stable/assets/stylesheets/palette.06af60db.min.css">
@@ -10122,10 +10122,10 @@
10122
10122
 
10123
10123
 
10124
10124
 
10125
- <script id="__config" type="application/json">{"base": "/projects/core/en/stable/", "features": ["content.code.annotate", "content.code.copy", "content.tabs.link", "navigation.footer", "navigation.tabs", "navigation.tabs.sticky", "navigation.tracking", "search.highlight", "search.share", "search.suggest"], "search": "/projects/core/en/stable/assets/javascripts/workers/search.f8cc74c7.min.js", "tags": null, "translations": {"clipboard.copied": "Copied to clipboard", "clipboard.copy": "Copy to clipboard", "search.result.more.one": "1 more on this page", "search.result.more.other": "# more on this page", "search.result.none": "No matching documents", "search.result.one": "1 matching document", "search.result.other": "# matching documents", "search.result.placeholder": "Type to start searching", "search.result.term.missing": "Missing", "select.version": "Select version"}, "version": null}</script>
10125
+ <script id="__config" type="application/json">{"base": "/projects/core/en/stable/", "features": ["content.code.annotate", "content.code.copy", "content.tabs.link", "navigation.footer", "navigation.tabs", "navigation.tabs.sticky", "navigation.tracking", "search.highlight", "search.share", "search.suggest"], "search": "/projects/core/en/stable/assets/javascripts/workers/search.d50fe291.min.js", "tags": null, "translations": {"clipboard.copied": "Copied to clipboard", "clipboard.copy": "Copy to clipboard", "search.result.more.one": "1 more on this page", "search.result.more.other": "# more on this page", "search.result.none": "No matching documents", "search.result.one": "1 matching document", "search.result.other": "# matching documents", "search.result.placeholder": "Type to start searching", "search.result.term.missing": "Missing", "select.version": "Select version"}, "version": null}</script>
10126
10126
 
10127
10127
 
10128
- <script src="/projects/core/en/stable/assets/javascripts/bundle.c8b220af.min.js"></script>
10128
+ <script src="/projects/core/en/stable/assets/javascripts/bundle.13a4f30d.min.js"></script>
10129
10129
 
10130
10130
 
10131
10131
  </body>
@@ -18,7 +18,7 @@
18
18
 
19
19
 
20
20
  <link rel="icon" href="../assets/favicon.ico">
21
- <meta name="generator" content="mkdocs-1.6.1, mkdocs-material-9.6.12">
21
+ <meta name="generator" content="mkdocs-1.6.1, mkdocs-material-9.6.14">
22
22
 
23
23
 
24
24
 
@@ -26,7 +26,7 @@
26
26
 
27
27
 
28
28
 
29
- <link rel="stylesheet" href="../assets/stylesheets/main.2afb09e1.min.css">
29
+ <link rel="stylesheet" href="../assets/stylesheets/main.342714a4.min.css">
30
30
 
31
31
 
32
32
  <link rel="stylesheet" href="../assets/stylesheets/palette.06af60db.min.css">
@@ -10290,10 +10290,10 @@
10290
10290
 
10291
10291
 
10292
10292
 
10293
- <script id="__config" type="application/json">{"base": "..", "features": ["content.code.annotate", "content.code.copy", "content.tabs.link", "navigation.footer", "navigation.tabs", "navigation.tabs.sticky", "navigation.tracking", "search.highlight", "search.share", "search.suggest"], "search": "../assets/javascripts/workers/search.f8cc74c7.min.js", "tags": null, "translations": {"clipboard.copied": "Copied to clipboard", "clipboard.copy": "Copy to clipboard", "search.result.more.one": "1 more on this page", "search.result.more.other": "# more on this page", "search.result.none": "No matching documents", "search.result.one": "1 matching document", "search.result.other": "# matching documents", "search.result.placeholder": "Type to start searching", "search.result.term.missing": "Missing", "select.version": "Select version"}, "version": null}</script>
10293
+ <script id="__config" type="application/json">{"base": "..", "features": ["content.code.annotate", "content.code.copy", "content.tabs.link", "navigation.footer", "navigation.tabs", "navigation.tabs.sticky", "navigation.tracking", "search.highlight", "search.share", "search.suggest"], "search": "../assets/javascripts/workers/search.d50fe291.min.js", "tags": null, "translations": {"clipboard.copied": "Copied to clipboard", "clipboard.copy": "Copy to clipboard", "search.result.more.one": "1 more on this page", "search.result.more.other": "# more on this page", "search.result.none": "No matching documents", "search.result.one": "1 matching document", "search.result.other": "# matching documents", "search.result.placeholder": "Type to start searching", "search.result.term.missing": "Missing", "select.version": "Select version"}, "version": null}</script>
10294
10294
 
10295
10295
 
10296
- <script src="../assets/javascripts/bundle.c8b220af.min.js"></script>
10296
+ <script src="../assets/javascripts/bundle.13a4f30d.min.js"></script>
10297
10297
 
10298
10298
 
10299
10299
  <script id="init-glightbox">const lightbox = GLightbox({"touchNavigation": true, "loop": false, "zoomable": true, "draggable": true, "openEffect": "zoom", "closeEffect": "zoom", "slideEffect": "slide"});
@@ -16,7 +16,7 @@
16
16
 
17
17
 
18
18
  <link rel="icon" href="../assets/favicon.ico">
19
- <meta name="generator" content="mkdocs-1.6.1, mkdocs-material-9.6.12">
19
+ <meta name="generator" content="mkdocs-1.6.1, mkdocs-material-9.6.14">
20
20
 
21
21
 
22
22
 
@@ -24,7 +24,7 @@
24
24
 
25
25
 
26
26
 
27
- <link rel="stylesheet" href="../assets/stylesheets/main.2afb09e1.min.css">
27
+ <link rel="stylesheet" href="../assets/stylesheets/main.342714a4.min.css">
28
28
 
29
29
 
30
30
  <link rel="stylesheet" href="../assets/stylesheets/palette.06af60db.min.css">
@@ -10223,10 +10223,10 @@
10223
10223
 
10224
10224
 
10225
10225
 
10226
- <script id="__config" type="application/json">{"base": "..", "features": ["content.code.annotate", "content.code.copy", "content.tabs.link", "navigation.footer", "navigation.tabs", "navigation.tabs.sticky", "navigation.tracking", "search.highlight", "search.share", "search.suggest"], "search": "../assets/javascripts/workers/search.f8cc74c7.min.js", "tags": null, "translations": {"clipboard.copied": "Copied to clipboard", "clipboard.copy": "Copy to clipboard", "search.result.more.one": "1 more on this page", "search.result.more.other": "# more on this page", "search.result.none": "No matching documents", "search.result.one": "1 matching document", "search.result.other": "# matching documents", "search.result.placeholder": "Type to start searching", "search.result.term.missing": "Missing", "select.version": "Select version"}, "version": null}</script>
10226
+ <script id="__config" type="application/json">{"base": "..", "features": ["content.code.annotate", "content.code.copy", "content.tabs.link", "navigation.footer", "navigation.tabs", "navigation.tabs.sticky", "navigation.tracking", "search.highlight", "search.share", "search.suggest"], "search": "../assets/javascripts/workers/search.d50fe291.min.js", "tags": null, "translations": {"clipboard.copied": "Copied to clipboard", "clipboard.copy": "Copy to clipboard", "search.result.more.one": "1 more on this page", "search.result.more.other": "# more on this page", "search.result.none": "No matching documents", "search.result.one": "1 matching document", "search.result.other": "# matching documents", "search.result.placeholder": "Type to start searching", "search.result.term.missing": "Missing", "select.version": "Select version"}, "version": null}</script>
10227
10227
 
10228
10228
 
10229
- <script src="../assets/javascripts/bundle.c8b220af.min.js"></script>
10229
+ <script src="../assets/javascripts/bundle.13a4f30d.min.js"></script>
10230
10230
 
10231
10231
 
10232
10232
  <script id="init-glightbox">const lightbox = GLightbox({"touchNavigation": true, "loop": false, "zoomable": true, "draggable": true, "openEffect": "zoom", "closeEffect": "zoom", "slideEffect": "slide"});