nautobot 2.3.16__py3-none-any.whl → 2.4.0__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 (721) hide show
  1. nautobot/__init__.py +15 -0
  2. nautobot/apps/__init__.py +1 -1
  3. nautobot/apps/api.py +8 -10
  4. nautobot/apps/change_logging.py +2 -2
  5. nautobot/apps/choices.py +4 -4
  6. nautobot/apps/config.py +32 -3
  7. nautobot/apps/events.py +19 -0
  8. nautobot/apps/exceptions.py +0 -2
  9. nautobot/apps/factory.py +2 -2
  10. nautobot/apps/filters.py +1 -1
  11. nautobot/apps/forms.py +20 -20
  12. nautobot/apps/graphql.py +2 -2
  13. nautobot/apps/jobs.py +8 -8
  14. nautobot/apps/models.py +19 -19
  15. nautobot/apps/tables.py +1 -1
  16. nautobot/apps/testing.py +10 -10
  17. nautobot/apps/ui.py +44 -9
  18. nautobot/apps/utils.py +7 -15
  19. nautobot/apps/views.py +8 -6
  20. nautobot/circuits/api/serializers.py +1 -0
  21. nautobot/circuits/api/views.py +4 -8
  22. nautobot/circuits/navigation.py +0 -57
  23. nautobot/circuits/templates/circuits/circuit_create.html +1 -7
  24. nautobot/circuits/templates/circuits/circuit_retrieve.html +0 -71
  25. nautobot/circuits/templates/circuits/inc/circuit_termination.html +6 -64
  26. nautobot/circuits/templates/circuits/inc/circuit_termination_cable_fragment.html +40 -0
  27. nautobot/circuits/templates/circuits/inc/circuit_termination_header_extra_content.html +26 -0
  28. nautobot/circuits/templates/circuits/provider_retrieve.html +0 -76
  29. nautobot/circuits/tests/integration/test_relationships.py +33 -24
  30. nautobot/circuits/tests/test_filters.py +4 -8
  31. nautobot/circuits/views.py +140 -23
  32. nautobot/cloud/api/views.py +6 -10
  33. nautobot/cloud/factory.py +4 -1
  34. nautobot/cloud/tests/test_filters.py +5 -4
  35. nautobot/cloud/views.py +0 -16
  36. nautobot/core/api/constants.py +11 -0
  37. nautobot/core/api/filter_backends.py +3 -9
  38. nautobot/core/api/metadata.py +28 -256
  39. nautobot/core/api/pagination.py +3 -2
  40. nautobot/core/api/renderers.py +3 -0
  41. nautobot/core/api/schema.py +13 -2
  42. nautobot/core/api/serializers.py +45 -259
  43. nautobot/core/api/urls.py +3 -4
  44. nautobot/core/api/utils.py +0 -62
  45. nautobot/core/api/views.py +99 -157
  46. nautobot/core/apps/__init__.py +22 -578
  47. nautobot/core/celery/__init__.py +13 -0
  48. nautobot/core/celery/schedulers.py +47 -2
  49. nautobot/core/choices.py +2 -2
  50. nautobot/core/cli/__init__.py +8 -0
  51. nautobot/core/constants.py +7 -0
  52. nautobot/core/events/__init__.py +116 -0
  53. nautobot/core/events/base.py +27 -0
  54. nautobot/core/events/exceptions.py +10 -0
  55. nautobot/core/events/redis_broker.py +48 -0
  56. nautobot/core/events/syslog_broker.py +19 -0
  57. nautobot/core/exceptions.py +0 -6
  58. nautobot/core/forms/__init__.py +19 -19
  59. nautobot/core/forms/fields.py +57 -9
  60. nautobot/core/forms/forms.py +33 -2
  61. nautobot/core/forms/utils.py +2 -1
  62. nautobot/core/graphql/schema.py +3 -1
  63. nautobot/core/jobs/__init__.py +24 -3
  64. nautobot/core/jobs/bulk_actions.py +248 -0
  65. nautobot/core/jobs/cleanup.py +1 -1
  66. nautobot/core/management/commands/generate_test_data.py +21 -0
  67. nautobot/core/middleware.py +16 -0
  68. nautobot/core/models/fields.py +11 -7
  69. nautobot/core/settings.py +68 -4
  70. nautobot/core/settings.yaml +99 -0
  71. nautobot/core/tables.py +10 -46
  72. nautobot/core/tasks.py +1 -1
  73. nautobot/core/templates/about.html +67 -0
  74. nautobot/core/templates/components/button/default.html +7 -0
  75. nautobot/core/templates/components/button/dropdown.html +20 -0
  76. nautobot/core/templates/components/layout/one_over_two.html +19 -0
  77. nautobot/core/templates/components/layout/two_over_one.html +19 -0
  78. nautobot/core/templates/components/panel/body_content_data_table.html +27 -0
  79. nautobot/core/templates/components/panel/body_content_objects_table.html +4 -0
  80. nautobot/core/templates/components/panel/body_content_tags.html +6 -0
  81. nautobot/core/templates/components/panel/body_content_text.html +12 -0
  82. nautobot/core/templates/components/panel/body_wrapper_generic.html +3 -0
  83. nautobot/core/templates/components/panel/body_wrapper_key_value_table.html +3 -0
  84. nautobot/core/templates/components/panel/body_wrapper_table.html +3 -0
  85. nautobot/core/templates/components/panel/footer_contacts_table.html +20 -0
  86. nautobot/core/templates/components/panel/footer_content_table.html +14 -0
  87. nautobot/core/templates/components/panel/grouping_toggle.html +14 -0
  88. nautobot/core/templates/components/panel/header_extra_content_table.html +3 -0
  89. nautobot/core/templates/components/panel/panel.html +16 -0
  90. nautobot/core/templates/components/panel/stats_panel_body.html +8 -0
  91. nautobot/core/templates/components/tab/content_wrapper.html +3 -0
  92. nautobot/core/templates/components/tab/label_wrapper.html +5 -0
  93. nautobot/core/templates/components/tab/label_wrapper_distinct_view.html +3 -0
  94. nautobot/core/templates/generic/object_retrieve.html +28 -17
  95. nautobot/core/templates/inc/computed_fields/panel_data.html +4 -7
  96. nautobot/core/templates/inc/custom_fields/panel.html +2 -2
  97. nautobot/core/templates/inc/custom_fields/panel_data.html +4 -7
  98. nautobot/core/templates/inc/footer.html +1 -0
  99. nautobot/core/templates/inc/nav_menu.html +2 -1
  100. nautobot/core/templates/inc/relationships_panel.html +1 -1
  101. nautobot/core/templates/inc/tenancy_form_panel.html +9 -0
  102. nautobot/core/templates/inc/tenant_table_row.html +11 -0
  103. nautobot/core/templates/nautobot_config.py.j2 +13 -0
  104. nautobot/core/templates/panel_table.html +12 -0
  105. nautobot/core/templates/utilities/render_jinja2.html +117 -0
  106. nautobot/core/templates/utilities/templatetags/tag.html +1 -1
  107. nautobot/core/templates/utilities/theme_preview.html +7 -0
  108. nautobot/core/templatetags/helpers.py +104 -6
  109. nautobot/core/templatetags/ui_framework.py +40 -0
  110. nautobot/core/testing/__init__.py +8 -8
  111. nautobot/core/testing/api.py +187 -137
  112. nautobot/core/testing/context.py +18 -0
  113. nautobot/core/testing/filters.py +41 -35
  114. nautobot/core/testing/forms.py +2 -0
  115. nautobot/core/testing/views.py +65 -148
  116. nautobot/core/tests/integration/test_view_authentication.py +1 -1
  117. nautobot/core/tests/nautobot_config.py +198 -0
  118. nautobot/core/tests/runner.py +2 -2
  119. nautobot/core/tests/test_api.py +154 -176
  120. nautobot/core/tests/test_events.py +214 -0
  121. nautobot/core/tests/test_forms.py +1 -0
  122. nautobot/core/tests/test_jinja_filters.py +1 -0
  123. nautobot/core/tests/test_jobs.py +387 -14
  124. nautobot/core/tests/test_navigations.py +7 -241
  125. nautobot/core/tests/test_settings_schema.py +7 -0
  126. nautobot/core/tests/test_tables.py +100 -0
  127. nautobot/core/tests/test_templatetags_helpers.py +16 -0
  128. nautobot/core/tests/test_ui.py +150 -0
  129. nautobot/core/tests/test_utils.py +55 -18
  130. nautobot/core/tests/test_views.py +124 -5
  131. nautobot/core/ui/__init__.py +0 -0
  132. nautobot/core/ui/base.py +11 -0
  133. nautobot/core/ui/choices.py +44 -0
  134. nautobot/core/ui/homepage.py +167 -0
  135. nautobot/core/ui/nav.py +280 -0
  136. nautobot/core/ui/object_detail.py +1855 -0
  137. nautobot/core/ui/utils.py +36 -0
  138. nautobot/core/urls.py +6 -0
  139. nautobot/core/utils/config.py +30 -3
  140. nautobot/core/utils/lookup.py +12 -2
  141. nautobot/core/utils/querysets.py +64 -0
  142. nautobot/core/utils/requests.py +24 -9
  143. nautobot/core/views/__init__.py +48 -1
  144. nautobot/core/views/generic.py +37 -140
  145. nautobot/core/views/mixins.py +82 -32
  146. nautobot/core/views/paginator.py +8 -5
  147. nautobot/core/views/renderers.py +9 -9
  148. nautobot/core/views/utils.py +11 -0
  149. nautobot/core/wsgi.py +3 -3
  150. nautobot/dcim/api/serializers.py +34 -141
  151. nautobot/dcim/api/urls.py +5 -0
  152. nautobot/dcim/api/views.py +57 -110
  153. nautobot/dcim/apps.py +1 -0
  154. nautobot/dcim/choices.py +28 -0
  155. nautobot/dcim/factory.py +58 -0
  156. nautobot/dcim/filters/__init__.py +204 -2
  157. nautobot/dcim/forms.py +219 -9
  158. nautobot/dcim/migrations/0063_interfacevdcassignment_virtualdevicecontext_and_more.py +165 -0
  159. nautobot/dcim/migrations/0064_virtualdevicecontext_status_data_migration.py +28 -0
  160. nautobot/dcim/migrations/0065_controller_capabilities_and_more.py +29 -0
  161. nautobot/dcim/migrations/0066_controllermanageddevicegroup_radio_profiles_and_more.py +33 -0
  162. nautobot/dcim/migrations/0067_controllermanageddevicegroup_tenant.py +25 -0
  163. nautobot/dcim/models/__init__.py +5 -1
  164. nautobot/dcim/models/devices.py +180 -2
  165. nautobot/dcim/models/racks.py +2 -2
  166. nautobot/dcim/navigation.py +25 -224
  167. nautobot/dcim/signals.py +44 -0
  168. nautobot/dcim/tables/__init__.py +2 -0
  169. nautobot/dcim/tables/devices.py +103 -7
  170. nautobot/dcim/tables/racks.py +1 -1
  171. nautobot/dcim/templates/dcim/controller/base.html +10 -0
  172. nautobot/dcim/templates/dcim/controller_create.html +2 -7
  173. nautobot/dcim/templates/dcim/controller_retrieve.html +6 -10
  174. nautobot/dcim/templates/dcim/controller_wirelessnetworks.html +25 -0
  175. nautobot/dcim/templates/dcim/controllermanageddevicegroup_create.html +68 -0
  176. nautobot/dcim/templates/dcim/controllermanageddevicegroup_retrieve.html +51 -0
  177. nautobot/dcim/templates/dcim/device/base.html +6 -42
  178. nautobot/dcim/templates/dcim/device/wireless.html +73 -0
  179. nautobot/dcim/templates/dcim/device.html +4 -10
  180. nautobot/dcim/templates/dcim/device_edit.html +36 -37
  181. nautobot/dcim/templates/dcim/interface.html +1 -0
  182. nautobot/dcim/templates/dcim/interface_edit.html +1 -0
  183. nautobot/dcim/templates/dcim/location.html +1 -9
  184. nautobot/dcim/templates/dcim/location_edit.html +1 -7
  185. nautobot/dcim/templates/dcim/locationtype.html +0 -107
  186. nautobot/dcim/templates/dcim/locationtype_retrieve.html +8 -0
  187. nautobot/dcim/templates/dcim/rack.html +1 -9
  188. nautobot/dcim/templates/dcim/rack_edit.html +1 -7
  189. nautobot/dcim/templates/dcim/rackreservation.html +1 -9
  190. nautobot/dcim/templates/dcim/virtualdevicecontext_retrieve.html +68 -0
  191. nautobot/dcim/templates/dcim/virtualdevicecontext_update.html +28 -0
  192. nautobot/dcim/tests/integration/test_controller.py +62 -0
  193. nautobot/dcim/tests/integration/test_controller_managed_device_group.py +71 -0
  194. nautobot/dcim/tests/test_api.py +188 -64
  195. nautobot/dcim/tests/test_filters.py +171 -76
  196. nautobot/dcim/tests/test_jobs.py +118 -0
  197. nautobot/dcim/tests/test_models.py +157 -6
  198. nautobot/dcim/tests/test_signals.py +1 -0
  199. nautobot/dcim/tests/test_views.py +118 -88
  200. nautobot/dcim/urls.py +72 -27
  201. nautobot/dcim/utils.py +2 -2
  202. nautobot/dcim/views.py +356 -61
  203. nautobot/extras/api/serializers.py +39 -18
  204. nautobot/extras/api/urls.py +4 -0
  205. nautobot/extras/api/views.py +89 -31
  206. nautobot/extras/choices.py +13 -0
  207. nautobot/extras/constants.py +2 -1
  208. nautobot/extras/context_managers.py +23 -6
  209. nautobot/extras/datasources/git.py +4 -1
  210. nautobot/extras/factory.py +27 -0
  211. nautobot/extras/filters/__init__.py +66 -5
  212. nautobot/extras/forms/base.py +2 -2
  213. nautobot/extras/forms/forms.py +262 -59
  214. nautobot/extras/forms/mixins.py +2 -2
  215. nautobot/extras/graphql/types.py +25 -1
  216. nautobot/extras/jobs.py +109 -15
  217. nautobot/extras/management/__init__.py +1 -0
  218. nautobot/extras/management/commands/runjob.py +7 -79
  219. nautobot/extras/management/commands/runjob_with_job_result.py +46 -0
  220. nautobot/extras/management/utils.py +87 -0
  221. nautobot/extras/migrations/0117_create_job_queue_model.py +129 -0
  222. nautobot/extras/migrations/0118_task_queue_to_job_queue_migration.py +78 -0
  223. nautobot/extras/migrations/0119_remove_task_queues_from_job_and_queue_from_scheduled_job.py +28 -0
  224. nautobot/extras/migrations/0120_job_is_singleton_job_is_singleton_override.py +22 -0
  225. nautobot/extras/migrations/0121_alter_team_contacts.py +17 -0
  226. nautobot/extras/models/__init__.py +5 -1
  227. nautobot/extras/models/change_logging.py +7 -3
  228. nautobot/extras/models/contacts.py +1 -1
  229. nautobot/extras/models/groups.py +0 -2
  230. nautobot/extras/models/jobs.py +233 -33
  231. nautobot/extras/models/relationships.py +69 -1
  232. nautobot/extras/models/secrets.py +5 -0
  233. nautobot/extras/navigation.py +20 -262
  234. nautobot/extras/plugins/__init__.py +54 -19
  235. nautobot/extras/plugins/marketplace_manifest.yml +455 -0
  236. nautobot/extras/plugins/tables.py +16 -14
  237. nautobot/extras/plugins/urls.py +1 -0
  238. nautobot/extras/plugins/views.py +103 -60
  239. nautobot/extras/registry.py +1 -1
  240. nautobot/extras/secrets/__init__.py +2 -2
  241. nautobot/extras/signals.py +39 -1
  242. nautobot/extras/tables.py +37 -1
  243. nautobot/extras/templates/extras/dynamicgroup.html +1 -9
  244. nautobot/extras/templates/extras/externalintegration_retrieve.html +0 -47
  245. nautobot/extras/templates/extras/inc/tags_panel.html +1 -5
  246. nautobot/extras/templates/extras/job_bulk_edit.html +2 -1
  247. nautobot/extras/templates/extras/job_detail.html +52 -6
  248. nautobot/extras/templates/extras/job_edit.html +6 -2
  249. nautobot/extras/templates/extras/job_list.html +2 -7
  250. nautobot/extras/templates/extras/jobqueue_retrieve.html +36 -0
  251. nautobot/extras/templates/extras/marketplace.html +296 -0
  252. nautobot/extras/templates/extras/plugin_detail.html +32 -15
  253. nautobot/extras/templates/extras/plugins_list.html +35 -1
  254. nautobot/extras/templates/extras/plugins_tiles.html +90 -0
  255. nautobot/extras/templates/extras/role_retrieve.html +16 -0
  256. nautobot/extras/templates/extras/secret.html +0 -65
  257. nautobot/extras/templates/extras/secret_check.js +16 -0
  258. nautobot/extras/templates/extras/secret_create.html +114 -0
  259. nautobot/extras/templates/extras/secret_edit.html +1 -114
  260. nautobot/extras/templates/extras/secretsgroup_edit.html +1 -1
  261. nautobot/extras/templates/extras/templatetags/plugin_object_detail_tabs.html +2 -0
  262. nautobot/extras/templatetags/job_buttons.py +5 -4
  263. nautobot/extras/templatetags/plugins.py +69 -6
  264. nautobot/extras/test_jobs/singleton.py +16 -0
  265. nautobot/extras/tests/test_api.py +145 -43
  266. nautobot/extras/tests/test_context_managers.py +4 -1
  267. nautobot/extras/tests/test_filters.py +213 -529
  268. nautobot/extras/tests/test_job_variables.py +73 -152
  269. nautobot/extras/tests/test_jobs.py +181 -51
  270. nautobot/extras/tests/test_models.py +61 -6
  271. nautobot/extras/tests/test_plugins.py +62 -9
  272. nautobot/extras/tests/test_relationships.py +123 -9
  273. nautobot/extras/tests/test_utils.py +23 -2
  274. nautobot/extras/tests/test_views.py +146 -145
  275. nautobot/extras/tests/test_webhooks.py +2 -1
  276. nautobot/extras/urls.py +2 -20
  277. nautobot/extras/utils.py +119 -4
  278. nautobot/extras/views.py +168 -125
  279. nautobot/extras/webhooks.py +5 -2
  280. nautobot/ipam/api/serializers.py +10 -103
  281. nautobot/ipam/api/views.py +31 -49
  282. nautobot/ipam/factory.py +1 -1
  283. nautobot/ipam/filters.py +3 -2
  284. nautobot/ipam/models.py +10 -12
  285. nautobot/ipam/navigation.py +0 -90
  286. nautobot/ipam/tables.py +3 -1
  287. nautobot/ipam/templates/ipam/ipaddress.html +1 -9
  288. nautobot/ipam/templates/ipam/ipaddress_bulk_add.html +1 -7
  289. nautobot/ipam/templates/ipam/ipaddress_edit.html +1 -7
  290. nautobot/ipam/templates/ipam/prefix.html +1 -9
  291. nautobot/ipam/templates/ipam/prefix_edit.html +1 -7
  292. nautobot/ipam/templates/ipam/routetarget.html +0 -28
  293. nautobot/ipam/templates/ipam/vlan.html +1 -9
  294. nautobot/ipam/templates/ipam/vlan_edit.html +1 -7
  295. nautobot/ipam/templates/ipam/vrf.html +0 -47
  296. nautobot/ipam/templates/ipam/vrf_edit.html +1 -7
  297. nautobot/ipam/tests/test_api.py +7 -5
  298. nautobot/ipam/tests/test_filters.py +39 -119
  299. nautobot/ipam/tests/test_forms.py +0 -2
  300. nautobot/ipam/tests/test_models.py +56 -36
  301. nautobot/ipam/tests/test_views.py +3 -0
  302. nautobot/ipam/urls.py +3 -69
  303. nautobot/ipam/utils/__init__.py +16 -10
  304. nautobot/ipam/views.py +91 -162
  305. nautobot/project-static/bootstrap-3.4.1-dist/css/bootstrap-theme.css.map +1 -1
  306. nautobot/project-static/bootstrap-3.4.1-dist/css/bootstrap-theme.min.css.map +1 -1
  307. nautobot/project-static/bootstrap-3.4.1-dist/css/bootstrap.css +40 -2
  308. nautobot/project-static/bootstrap-3.4.1-dist/css/bootstrap.css.map +1 -1
  309. nautobot/project-static/bootstrap-3.4.1-dist/css/bootstrap.min.css +1 -1
  310. nautobot/project-static/bootstrap-3.4.1-dist/css/bootstrap.min.css.map +1 -1
  311. nautobot/project-static/css/base.css +38 -3
  312. nautobot/project-static/docs/404.html +461 -17
  313. nautobot/project-static/docs/apps/index.html +461 -17
  314. nautobot/project-static/docs/apps/nautobot-apps.html +462 -19
  315. nautobot/project-static/docs/assets/_mkdocstrings.css +25 -1
  316. nautobot/project-static/docs/assets/extra.css +5 -1
  317. nautobot/project-static/docs/code-reference/nautobot/apps/__init__.html +477 -23
  318. nautobot/project-static/docs/code-reference/nautobot/apps/admin.html +474 -20
  319. nautobot/project-static/docs/code-reference/nautobot/apps/api.html +790 -289
  320. nautobot/project-static/docs/code-reference/nautobot/apps/change_logging.html +505 -31
  321. nautobot/project-static/docs/code-reference/nautobot/apps/choices.html +510 -34
  322. nautobot/project-static/docs/code-reference/nautobot/apps/config.html +471 -20
  323. nautobot/project-static/docs/code-reference/nautobot/apps/constants.html +467 -18
  324. nautobot/project-static/docs/code-reference/nautobot/apps/datasources.html +497 -33
  325. nautobot/project-static/docs/code-reference/nautobot/apps/events.html +9883 -0
  326. nautobot/project-static/docs/code-reference/nautobot/apps/exceptions.html +523 -75
  327. nautobot/project-static/docs/code-reference/nautobot/apps/factory.html +546 -51
  328. nautobot/project-static/docs/code-reference/nautobot/apps/filters.html +670 -94
  329. nautobot/project-static/docs/code-reference/nautobot/apps/forms.html +1030 -177
  330. nautobot/project-static/docs/code-reference/nautobot/apps/graphql.html +524 -49
  331. nautobot/project-static/docs/code-reference/nautobot/apps/jobs.html +874 -188
  332. nautobot/project-static/docs/code-reference/nautobot/apps/models.html +955 -235
  333. nautobot/project-static/docs/code-reference/nautobot/apps/querysets.html +475 -21
  334. nautobot/project-static/docs/code-reference/nautobot/apps/secrets.html +486 -28
  335. nautobot/project-static/docs/code-reference/nautobot/apps/tables.html +661 -99
  336. nautobot/project-static/docs/code-reference/nautobot/apps/testing.html +947 -479
  337. nautobot/project-static/docs/code-reference/nautobot/apps/ui.html +6425 -1234
  338. nautobot/project-static/docs/code-reference/nautobot/apps/urls.html +474 -20
  339. nautobot/project-static/docs/code-reference/nautobot/apps/utils.html +877 -344
  340. nautobot/project-static/docs/code-reference/nautobot/apps/views.html +828 -171
  341. nautobot/project-static/docs/development/apps/api/configuration-view.html +461 -17
  342. nautobot/project-static/docs/development/apps/api/database-backend-config.html +461 -17
  343. nautobot/project-static/docs/development/apps/api/models/django-admin.html +461 -17
  344. nautobot/project-static/docs/development/apps/api/models/global-search.html +461 -17
  345. nautobot/project-static/docs/development/apps/api/models/graphql.html +461 -17
  346. nautobot/project-static/docs/development/apps/api/models/index.html +461 -17
  347. nautobot/project-static/docs/development/apps/api/nautobot-app-config.html +461 -17
  348. nautobot/project-static/docs/development/apps/api/platform-features/custom-validators.html +461 -17
  349. nautobot/project-static/docs/development/apps/api/platform-features/filter-extensions.html +461 -17
  350. nautobot/project-static/docs/development/apps/api/platform-features/git-repository-content.html +461 -17
  351. nautobot/project-static/docs/development/apps/api/platform-features/index.html +461 -17
  352. nautobot/project-static/docs/development/apps/api/platform-features/jinja2-filters.html +461 -17
  353. nautobot/project-static/docs/development/apps/api/platform-features/jobs.html +461 -17
  354. nautobot/project-static/docs/development/apps/api/platform-features/populating-extensibility-features.html +461 -17
  355. nautobot/project-static/docs/development/apps/api/platform-features/secrets-providers.html +461 -17
  356. nautobot/project-static/docs/development/apps/api/platform-features/table-extensions.html +461 -17
  357. nautobot/project-static/docs/development/apps/api/platform-features/uniquely-identify-objects.html +461 -17
  358. nautobot/project-static/docs/development/apps/api/prometheus.html +461 -17
  359. nautobot/project-static/docs/development/apps/api/setup.html +465 -153
  360. nautobot/project-static/docs/development/apps/api/testing.html +461 -17
  361. nautobot/project-static/docs/development/apps/api/ui-extensions/banners.html +461 -17
  362. nautobot/project-static/docs/development/apps/api/ui-extensions/home-page.html +461 -17
  363. nautobot/project-static/docs/development/apps/api/ui-extensions/index.html +461 -17
  364. nautobot/project-static/docs/development/apps/api/ui-extensions/navigation.html +461 -17
  365. nautobot/project-static/docs/development/apps/api/ui-extensions/object-views.html +741 -128
  366. nautobot/project-static/docs/development/apps/api/views/base-template.html +461 -17
  367. nautobot/project-static/docs/development/apps/api/views/core-view-overrides.html +461 -17
  368. nautobot/project-static/docs/development/apps/api/views/django-generic-views.html +461 -17
  369. nautobot/project-static/docs/development/apps/api/views/help-documentation.html +461 -17
  370. nautobot/project-static/docs/development/apps/api/views/index.html +463 -18
  371. nautobot/project-static/docs/development/apps/api/views/nautobot-generic-views.html +465 -17
  372. nautobot/project-static/docs/development/apps/api/views/nautobotuiviewset.html +491 -17
  373. nautobot/project-static/docs/development/apps/api/views/nautobotuiviewsetrouter.html +461 -17
  374. nautobot/project-static/docs/development/apps/api/views/notes.html +461 -17
  375. nautobot/project-static/docs/development/apps/api/views/rest-api.html +467 -19
  376. nautobot/project-static/docs/development/apps/api/views/urls.html +461 -17
  377. nautobot/project-static/docs/development/apps/index.html +461 -17
  378. nautobot/project-static/docs/development/apps/migration/code-updates.html +462 -50
  379. nautobot/project-static/docs/development/apps/migration/dependency-updates.html +462 -18
  380. nautobot/project-static/docs/development/apps/migration/from-v1.html +461 -17
  381. nautobot/project-static/docs/development/apps/migration/model-updates/dcim.html +461 -17
  382. nautobot/project-static/docs/development/apps/migration/model-updates/extras.html +461 -17
  383. nautobot/project-static/docs/development/apps/migration/model-updates/global.html +461 -17
  384. nautobot/project-static/docs/development/apps/migration/model-updates/ipam.html +464 -20
  385. nautobot/project-static/docs/development/apps/migration/ui-component-framework/best-practices.html +9261 -0
  386. nautobot/project-static/docs/development/apps/migration/ui-component-framework/custom-content.html +9375 -0
  387. nautobot/project-static/docs/development/apps/migration/ui-component-framework/index.html +9671 -0
  388. nautobot/project-static/docs/development/apps/migration/ui-component-framework/migration-steps.html +9559 -0
  389. nautobot/project-static/docs/development/apps/porting-from-netbox.html +464 -20
  390. nautobot/project-static/docs/development/core/application-registry.html +461 -17
  391. nautobot/project-static/docs/development/core/best-practices.html +461 -17
  392. nautobot/project-static/docs/development/core/bootstrap-ui.html +461 -17
  393. nautobot/project-static/docs/development/core/caching.html +461 -17
  394. nautobot/project-static/docs/development/core/controllers.html +463 -17
  395. nautobot/project-static/docs/development/core/docker-compose-advanced-use-cases.html +464 -20
  396. nautobot/project-static/docs/development/core/generic-views.html +461 -17
  397. nautobot/project-static/docs/development/core/getting-started.html +539 -127
  398. nautobot/project-static/docs/development/core/homepage.html +472 -28
  399. nautobot/project-static/docs/development/core/index.html +461 -17
  400. nautobot/project-static/docs/development/core/minikube-dev-environment-for-k8s-jobs.html +9754 -0
  401. nautobot/project-static/docs/development/core/model-checklist.html +471 -25
  402. nautobot/project-static/docs/development/core/model-features.html +461 -17
  403. nautobot/project-static/docs/development/core/natural-keys.html +461 -17
  404. nautobot/project-static/docs/development/core/navigation-menu.html +478 -24
  405. nautobot/project-static/docs/development/core/release-checklist.html +478 -46
  406. nautobot/project-static/docs/development/core/role-internals.html +461 -17
  407. nautobot/project-static/docs/development/core/settings.html +461 -17
  408. nautobot/project-static/docs/development/core/style-guide.html +464 -20
  409. nautobot/project-static/docs/development/core/templates.html +471 -20
  410. nautobot/project-static/docs/development/core/testing.html +461 -17
  411. nautobot/project-static/docs/development/core/ui-component-framework.html +11116 -0
  412. nautobot/project-static/docs/development/core/user-preferences.html +464 -20
  413. nautobot/project-static/docs/development/index.html +461 -17
  414. nautobot/project-static/docs/development/jobs/index.html +499 -19
  415. nautobot/project-static/docs/development/jobs/migration/from-v1.html +461 -17
  416. nautobot/project-static/docs/index.html +469 -36
  417. nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_edit.png +0 -0
  418. nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_edit_button.png +0 -0
  419. nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_list_nav.png +0 -0
  420. nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_list_view.png +0 -0
  421. nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_queue.png +0 -0
  422. nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_queue_add.png +0 -0
  423. nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_queue_config.png +0 -0
  424. nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_result_completed.png +0 -0
  425. nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_result_nav.png +0 -0
  426. nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_result_pending.png +0 -0
  427. nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_run_form.png +0 -0
  428. nautobot/project-static/docs/media/development/core/kubernetes/k8s_nautobot_login.png +0 -0
  429. nautobot/project-static/docs/media/development/core/kubernetes/k8s_run_job.png +0 -0
  430. nautobot/project-static/docs/media/development/core/kubernetes/k8s_run_scheduled_job_form.png +0 -0
  431. nautobot/project-static/docs/media/development/core/kubernetes/k8s_scheduled_job_result.png +0 -0
  432. nautobot/project-static/docs/media/development/core/ui-component-framework/basic-panel-layout.png +0 -0
  433. nautobot/project-static/docs/media/development/core/ui-component-framework/button-example.png +0 -0
  434. nautobot/project-static/docs/media/development/core/ui-component-framework/buttons-example.png +0 -0
  435. nautobot/project-static/docs/media/development/core/ui-component-framework/cluster-type-before-after-example.png +0 -0
  436. nautobot/project-static/docs/media/development/core/ui-component-framework/dropdown-button-example.png +0 -0
  437. nautobot/project-static/docs/media/development/core/ui-component-framework/grouped-key-value-table-panel-example-1.png +0 -0
  438. nautobot/project-static/docs/media/development/core/ui-component-framework/grouped-key-value-table-panel-example-2.png +0 -0
  439. nautobot/project-static/docs/media/development/core/ui-component-framework/object-fields-panel-example.png +0 -0
  440. nautobot/project-static/docs/media/development/core/ui-component-framework/object-fields-panel-example_2.png +0 -0
  441. nautobot/project-static/docs/media/development/core/ui-component-framework/stats-panel-example-code.png +0 -0
  442. nautobot/project-static/docs/media/development/core/ui-component-framework/stats-panel-example.png +0 -0
  443. nautobot/project-static/docs/media/development/core/ui-component-framework/table-panels-family.png +0 -0
  444. nautobot/project-static/docs/media/development/core/ui-component-framework/text-panels-family.png +0 -0
  445. nautobot/project-static/docs/media/development/core/ui-component-framework/ui-framework-example.png +0 -0
  446. nautobot/project-static/docs/media/models/virtual_device_context_overview.drawio +73 -0
  447. nautobot/project-static/docs/media/models/virtual_device_context_overview.png +0 -0
  448. nautobot/project-static/docs/models/dcim/virtualdevicecontext.html +14 -0
  449. nautobot/project-static/docs/models/extras/jobqueue.html +14 -0
  450. nautobot/project-static/docs/models/wireless/radioprofile.html +14 -0
  451. nautobot/project-static/docs/models/wireless/supporteddatarate.html +14 -0
  452. nautobot/project-static/docs/models/wireless/wirelessnetwork.html +14 -0
  453. nautobot/project-static/docs/objects.inv +0 -0
  454. nautobot/project-static/docs/overview/application_stack.html +467 -21
  455. nautobot/project-static/docs/overview/design_philosophy.html +461 -17
  456. nautobot/project-static/docs/release-notes/index.html +483 -20
  457. nautobot/project-static/docs/release-notes/version-1.0.html +649 -206
  458. nautobot/project-static/docs/release-notes/version-1.1.html +646 -203
  459. nautobot/project-static/docs/release-notes/version-1.2.html +721 -278
  460. nautobot/project-static/docs/release-notes/version-1.3.html +747 -304
  461. nautobot/project-static/docs/release-notes/version-1.4.html +832 -390
  462. nautobot/project-static/docs/release-notes/version-1.5.html +1020 -579
  463. nautobot/project-static/docs/release-notes/version-1.6.html +940 -516
  464. nautobot/project-static/docs/release-notes/version-2.0.html +943 -502
  465. nautobot/project-static/docs/release-notes/version-2.1.html +778 -337
  466. nautobot/project-static/docs/release-notes/version-2.2.html +771 -330
  467. nautobot/project-static/docs/release-notes/version-2.3.html +914 -471
  468. nautobot/project-static/docs/release-notes/version-2.4.html +10323 -0
  469. nautobot/project-static/docs/search/search_index.json +1 -1
  470. nautobot/project-static/docs/sitemap.xml +342 -270
  471. nautobot/project-static/docs/sitemap.xml.gz +0 -0
  472. nautobot/project-static/docs/user-guide/administration/configuration/authentication/ldap.html +461 -17
  473. nautobot/project-static/docs/user-guide/administration/configuration/authentication/remote.html +461 -17
  474. nautobot/project-static/docs/user-guide/administration/configuration/authentication/sso.html +461 -17
  475. nautobot/project-static/docs/user-guide/administration/configuration/index.html +473 -30
  476. nautobot/project-static/docs/user-guide/administration/configuration/redis.html +461 -17
  477. nautobot/project-static/docs/user-guide/administration/configuration/settings.html +842 -155
  478. nautobot/project-static/docs/user-guide/administration/configuration/time-zones.html +461 -17
  479. nautobot/project-static/docs/user-guide/administration/guides/celery-queues.html +461 -17
  480. nautobot/project-static/docs/user-guide/administration/guides/docker.html +474 -27
  481. nautobot/project-static/docs/user-guide/administration/guides/health-checks.html +461 -17
  482. nautobot/project-static/docs/user-guide/administration/guides/permissions.html +461 -17
  483. nautobot/project-static/docs/user-guide/administration/guides/prometheus-metrics.html +461 -17
  484. nautobot/project-static/docs/user-guide/administration/guides/replicating-nautobot.html +461 -17
  485. nautobot/project-static/docs/user-guide/administration/guides/request-profiling.html +461 -17
  486. nautobot/project-static/docs/user-guide/administration/guides/s3-django-storage.html +463 -19
  487. nautobot/project-static/docs/user-guide/administration/guides/selinux-troubleshooting.html +461 -17
  488. nautobot/project-static/docs/user-guide/administration/installation/app-install.html +461 -17
  489. nautobot/project-static/docs/user-guide/administration/installation/external-authentication.html +461 -17
  490. nautobot/project-static/docs/user-guide/administration/installation/http-server.html +481 -21
  491. nautobot/project-static/docs/user-guide/administration/installation/index.html +466 -18
  492. nautobot/project-static/docs/user-guide/administration/installation/install_system.html +462 -18
  493. nautobot/project-static/docs/user-guide/administration/installation/nautobot.html +461 -17
  494. nautobot/project-static/docs/user-guide/administration/installation/services.html +461 -17
  495. nautobot/project-static/docs/user-guide/administration/migration/migrating-from-netbox.html +461 -17
  496. nautobot/project-static/docs/user-guide/administration/migration/migrating-from-postgresql.html +482 -39
  497. nautobot/project-static/docs/user-guide/administration/tools/nautobot-server.html +475 -64
  498. nautobot/project-static/docs/user-guide/administration/tools/nautobot-shell.html +475 -64
  499. nautobot/project-static/docs/user-guide/administration/upgrading/database-backup.html +461 -17
  500. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/after-you-upgrade.html +461 -17
  501. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/before-you-upgrade.html +461 -17
  502. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/for-developers.html +461 -17
  503. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/index.html +461 -17
  504. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/whats-changed.html +464 -21
  505. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/region-and-site-data-migration-guide.html +461 -17
  506. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/tables/v2-code-nautobot-app-location.yaml +0 -16
  507. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/upgrading-from-nautobot-v1.html +461 -17
  508. nautobot/project-static/docs/user-guide/administration/upgrading/upgrading.html +467 -19
  509. nautobot/project-static/docs/user-guide/core-data-model/circuits/circuit.html +461 -17
  510. nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittermination.html +461 -17
  511. nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittype.html +461 -17
  512. nautobot/project-static/docs/user-guide/core-data-model/circuits/provider.html +461 -17
  513. nautobot/project-static/docs/user-guide/core-data-model/circuits/providernetwork.html +461 -17
  514. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloud.html +461 -17
  515. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudaccount.html +461 -17
  516. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudnetwork.html +461 -17
  517. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudnetworkprefixassignment.html +461 -17
  518. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudresourcetype.html +461 -17
  519. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudservice.html +461 -17
  520. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudservicenetworkassignment.html +461 -17
  521. nautobot/project-static/docs/user-guide/core-data-model/dcim/cable.html +461 -17
  522. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleport.html +461 -17
  523. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleporttemplate.html +461 -17
  524. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverport.html +461 -17
  525. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverporttemplate.html +461 -17
  526. nautobot/project-static/docs/user-guide/core-data-model/dcim/controller.html +497 -18
  527. nautobot/project-static/docs/user-guide/core-data-model/dcim/controllermanageddevicegroup.html +487 -20
  528. nautobot/project-static/docs/user-guide/core-data-model/dcim/device.html +461 -17
  529. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebay.html +461 -17
  530. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebaytemplate.html +461 -17
  531. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicefamily.html +461 -17
  532. nautobot/project-static/docs/user-guide/core-data-model/dcim/deviceredundancygroup.html +461 -17
  533. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicetype.html +461 -17
  534. nautobot/project-static/docs/user-guide/core-data-model/dcim/frontport.html +461 -17
  535. nautobot/project-static/docs/user-guide/core-data-model/dcim/frontporttemplate.html +461 -17
  536. nautobot/project-static/docs/user-guide/core-data-model/dcim/interface.html +461 -17
  537. nautobot/project-static/docs/user-guide/core-data-model/dcim/interfaceredundancygroup.html +461 -17
  538. nautobot/project-static/docs/user-guide/core-data-model/dcim/interfacetemplate.html +461 -17
  539. nautobot/project-static/docs/user-guide/core-data-model/dcim/inventoryitem.html +461 -17
  540. nautobot/project-static/docs/user-guide/core-data-model/dcim/location.html +461 -17
  541. nautobot/project-static/docs/user-guide/core-data-model/dcim/locationtype.html +461 -17
  542. nautobot/project-static/docs/user-guide/core-data-model/dcim/manufacturer.html +461 -17
  543. nautobot/project-static/docs/user-guide/core-data-model/dcim/module.html +461 -17
  544. nautobot/project-static/docs/user-guide/core-data-model/dcim/modulebay.html +461 -17
  545. nautobot/project-static/docs/user-guide/core-data-model/dcim/modulebaytemplate.html +461 -17
  546. nautobot/project-static/docs/user-guide/core-data-model/dcim/moduletype.html +461 -17
  547. nautobot/project-static/docs/user-guide/core-data-model/dcim/platform.html +461 -17
  548. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerfeed.html +461 -17
  549. nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlet.html +461 -17
  550. nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlettemplate.html +461 -17
  551. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerpanel.html +461 -17
  552. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerport.html +461 -17
  553. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerporttemplate.html +461 -17
  554. nautobot/project-static/docs/user-guide/core-data-model/dcim/rack.html +461 -17
  555. nautobot/project-static/docs/user-guide/core-data-model/dcim/rackgroup.html +461 -17
  556. nautobot/project-static/docs/user-guide/core-data-model/dcim/rackreservation.html +461 -17
  557. nautobot/project-static/docs/user-guide/core-data-model/dcim/rearport.html +461 -17
  558. nautobot/project-static/docs/user-guide/core-data-model/dcim/rearporttemplate.html +461 -17
  559. nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareimagefile.html +461 -17
  560. nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareversion.html +461 -17
  561. nautobot/project-static/docs/user-guide/core-data-model/dcim/virtualchassis.html +461 -17
  562. nautobot/project-static/docs/user-guide/core-data-model/dcim/virtualdevicecontext.html +9375 -0
  563. nautobot/project-static/docs/user-guide/core-data-model/extras/configcontext.html +468 -28
  564. nautobot/project-static/docs/user-guide/core-data-model/extras/configcontextschema.html +461 -17
  565. nautobot/project-static/docs/user-guide/core-data-model/extras/contact.html +461 -17
  566. nautobot/project-static/docs/user-guide/core-data-model/extras/team.html +461 -17
  567. nautobot/project-static/docs/user-guide/core-data-model/ipam/ipaddress.html +461 -17
  568. nautobot/project-static/docs/user-guide/core-data-model/ipam/namespace.html +461 -17
  569. nautobot/project-static/docs/user-guide/core-data-model/ipam/prefix.html +461 -17
  570. nautobot/project-static/docs/user-guide/core-data-model/ipam/rir.html +461 -17
  571. nautobot/project-static/docs/user-guide/core-data-model/ipam/routetarget.html +461 -17
  572. nautobot/project-static/docs/user-guide/core-data-model/ipam/service.html +461 -17
  573. nautobot/project-static/docs/user-guide/core-data-model/ipam/vlan.html +461 -17
  574. nautobot/project-static/docs/user-guide/core-data-model/ipam/vlangroup.html +461 -17
  575. nautobot/project-static/docs/user-guide/core-data-model/ipam/vrf.html +461 -17
  576. nautobot/project-static/docs/user-guide/core-data-model/overview/introduction.html +464 -20
  577. nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenant.html +461 -17
  578. nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenantgroup.html +461 -17
  579. nautobot/project-static/docs/user-guide/core-data-model/virtualization/cluster.html +461 -17
  580. nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustergroup.html +461 -17
  581. nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustertype.html +461 -17
  582. nautobot/project-static/docs/user-guide/core-data-model/virtualization/virtualmachine.html +461 -17
  583. nautobot/project-static/docs/user-guide/core-data-model/virtualization/vminterface.html +464 -20
  584. nautobot/project-static/docs/user-guide/core-data-model/wireless/index.html +9313 -0
  585. nautobot/project-static/docs/user-guide/core-data-model/wireless/radioprofile.html +9217 -0
  586. nautobot/project-static/docs/user-guide/core-data-model/wireless/supporteddatarate.html +9211 -0
  587. nautobot/project-static/docs/user-guide/core-data-model/wireless/wirelessnetwork.html +9277 -0
  588. nautobot/project-static/docs/user-guide/feature-guides/contacts-and-teams.html +461 -17
  589. nautobot/project-static/docs/user-guide/feature-guides/custom-fields.html +461 -17
  590. nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-devices.html +461 -17
  591. nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-location-types-and-locations.html +461 -17
  592. nautobot/project-static/docs/user-guide/feature-guides/getting-started/index.html +461 -17
  593. nautobot/project-static/docs/user-guide/feature-guides/getting-started/interfaces.html +461 -17
  594. nautobot/project-static/docs/user-guide/feature-guides/getting-started/ipam.html +461 -17
  595. nautobot/project-static/docs/user-guide/feature-guides/getting-started/platforms.html +461 -17
  596. nautobot/project-static/docs/user-guide/feature-guides/getting-started/search-bar.html +461 -17
  597. nautobot/project-static/docs/user-guide/feature-guides/getting-started/tenants.html +461 -17
  598. nautobot/project-static/docs/user-guide/feature-guides/getting-started/vlans-and-vlan-groups.html +461 -17
  599. nautobot/project-static/docs/user-guide/feature-guides/git-data-source.html +466 -20
  600. nautobot/project-static/docs/user-guide/feature-guides/graphql.html +461 -17
  601. nautobot/project-static/docs/user-guide/feature-guides/images/wireless/central-mode.png +0 -0
  602. nautobot/project-static/docs/user-guide/feature-guides/images/wireless/device-group-add.png +0 -0
  603. nautobot/project-static/docs/user-guide/feature-guides/images/wireless/device-group-create-1.png +0 -0
  604. nautobot/project-static/docs/user-guide/feature-guides/images/wireless/device-group-create-2.png +0 -0
  605. nautobot/project-static/docs/user-guide/feature-guides/images/wireless/radio-profile-add.png +0 -0
  606. nautobot/project-static/docs/user-guide/feature-guides/images/wireless/radio-profile-create.png +0 -0
  607. nautobot/project-static/docs/user-guide/feature-guides/images/wireless/supported-data-rate-add.png +0 -0
  608. nautobot/project-static/docs/user-guide/feature-guides/images/wireless/supported-data-rate-create.png +0 -0
  609. nautobot/project-static/docs/user-guide/feature-guides/images/wireless/wireless-controller-add.png +0 -0
  610. nautobot/project-static/docs/user-guide/feature-guides/images/wireless/wireless-controller-create-1.png +0 -0
  611. nautobot/project-static/docs/user-guide/feature-guides/images/wireless/wireless-controller-create-2.png +0 -0
  612. nautobot/project-static/docs/user-guide/feature-guides/images/wireless/wireless-network-add.png +0 -0
  613. nautobot/project-static/docs/user-guide/feature-guides/images/wireless/wireless-network-create.png +0 -0
  614. nautobot/project-static/docs/user-guide/feature-guides/ip-address-merge-tool.html +461 -17
  615. nautobot/project-static/docs/user-guide/feature-guides/relationships.html +461 -17
  616. nautobot/project-static/docs/user-guide/feature-guides/software-image-files-and-versions.html +464 -20
  617. nautobot/project-static/docs/user-guide/feature-guides/wireless-networks-and-controllers.html +9444 -0
  618. nautobot/project-static/docs/user-guide/index.html +461 -17
  619. nautobot/project-static/docs/user-guide/platform-functionality/change-logging.html +464 -20
  620. nautobot/project-static/docs/user-guide/platform-functionality/computedfield.html +465 -21
  621. nautobot/project-static/docs/user-guide/platform-functionality/customfield.html +461 -17
  622. nautobot/project-static/docs/user-guide/platform-functionality/customlink.html +461 -17
  623. nautobot/project-static/docs/user-guide/platform-functionality/dynamicgroup.html +461 -17
  624. nautobot/project-static/docs/user-guide/platform-functionality/events.html +9617 -0
  625. nautobot/project-static/docs/user-guide/platform-functionality/exporttemplate.html +464 -20
  626. nautobot/project-static/docs/user-guide/platform-functionality/externalintegration.html +461 -17
  627. nautobot/project-static/docs/user-guide/platform-functionality/gitrepository.html +461 -17
  628. nautobot/project-static/docs/user-guide/platform-functionality/graphql.html +461 -17
  629. nautobot/project-static/docs/user-guide/platform-functionality/graphqlquery.html +461 -17
  630. nautobot/project-static/docs/user-guide/platform-functionality/imageattachment.html +461 -17
  631. nautobot/project-static/docs/user-guide/platform-functionality/jobs/index.html +470 -21
  632. nautobot/project-static/docs/user-guide/platform-functionality/jobs/job-scheduling-and-approvals.html +464 -20
  633. nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobbutton.html +464 -20
  634. nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobhook.html +461 -17
  635. nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobqueue.html +9224 -0
  636. nautobot/project-static/docs/user-guide/platform-functionality/jobs/kubernetes-job-support.html +9722 -0
  637. nautobot/project-static/docs/user-guide/platform-functionality/jobs/models.html +464 -20
  638. nautobot/project-static/docs/user-guide/platform-functionality/napalm.html +461 -17
  639. nautobot/project-static/docs/user-guide/platform-functionality/note.html +461 -17
  640. nautobot/project-static/docs/user-guide/platform-functionality/objectmetadata.html +461 -17
  641. nautobot/project-static/docs/user-guide/platform-functionality/relationship.html +465 -21
  642. nautobot/project-static/docs/user-guide/platform-functionality/rendering-jinja-templates.html +9292 -0
  643. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/authentication.html +461 -17
  644. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/filtering.html +509 -38
  645. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/overview.html +492 -21
  646. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/ui-related-endpoints.html +461 -17
  647. nautobot/project-static/docs/user-guide/platform-functionality/role.html +461 -17
  648. nautobot/project-static/docs/user-guide/platform-functionality/savedview.html +461 -17
  649. nautobot/project-static/docs/user-guide/platform-functionality/secret.html +461 -17
  650. nautobot/project-static/docs/user-guide/platform-functionality/staticgroupassociation.html +464 -20
  651. nautobot/project-static/docs/user-guide/platform-functionality/status.html +461 -17
  652. nautobot/project-static/docs/user-guide/platform-functionality/tag.html +461 -17
  653. nautobot/project-static/docs/user-guide/platform-functionality/template-filters.html +529 -54
  654. nautobot/project-static/docs/user-guide/platform-functionality/users/objectpermission.html +461 -17
  655. nautobot/project-static/docs/user-guide/platform-functionality/users/token.html +461 -17
  656. nautobot/project-static/docs/user-guide/platform-functionality/webhook.html +461 -17
  657. nautobot/project-static/img/jinja_logo.svg +97 -0
  658. nautobot/project-static/js/forms.js +6 -1
  659. nautobot/project-static/js/nav_menu.js +2 -1
  660. nautobot/tenancy/api/serializers.py +0 -2
  661. nautobot/tenancy/api/views.py +9 -13
  662. nautobot/tenancy/factory.py +1 -1
  663. nautobot/tenancy/navigation.py +0 -29
  664. nautobot/tenancy/templates/tenancy/tenant.html +4 -91
  665. nautobot/tenancy/tests/test_filters.py +29 -134
  666. nautobot/tenancy/views.py +35 -24
  667. nautobot/users/admin.py +2 -0
  668. nautobot/users/api/views.py +2 -2
  669. nautobot/users/forms.py +19 -0
  670. nautobot/users/templates/users/preferences.html +22 -0
  671. nautobot/users/tests/test_filters.py +1 -19
  672. nautobot/users/tests/test_views.py +57 -0
  673. nautobot/users/utils.py +8 -0
  674. nautobot/users/views.py +48 -11
  675. nautobot/virtualization/api/views.py +5 -24
  676. nautobot/virtualization/filters.py +1 -2
  677. nautobot/virtualization/models.py +1 -1
  678. nautobot/virtualization/navigation.py +0 -48
  679. nautobot/virtualization/tables.py +2 -2
  680. nautobot/virtualization/templates/virtualization/cluster_edit.html +1 -7
  681. nautobot/virtualization/templates/virtualization/clustertype.html +0 -39
  682. nautobot/virtualization/templates/virtualization/virtualmachine.html +1 -9
  683. nautobot/virtualization/templates/virtualization/virtualmachine_edit.html +2 -8
  684. nautobot/virtualization/tests/test_filters.py +57 -166
  685. nautobot/virtualization/views.py +18 -15
  686. nautobot/wireless/__init__.py +0 -0
  687. nautobot/wireless/api/__init__.py +0 -0
  688. nautobot/wireless/api/serializers.py +44 -0
  689. nautobot/wireless/api/urls.py +20 -0
  690. nautobot/wireless/api/views.py +34 -0
  691. nautobot/wireless/apps.py +8 -0
  692. nautobot/wireless/choices.py +345 -0
  693. nautobot/wireless/factory.py +138 -0
  694. nautobot/wireless/filters.py +167 -0
  695. nautobot/wireless/forms.py +283 -0
  696. nautobot/wireless/homepage.py +19 -0
  697. nautobot/wireless/migrations/0001_initial.py +223 -0
  698. nautobot/wireless/migrations/__init__.py +0 -0
  699. nautobot/wireless/models.py +207 -0
  700. nautobot/wireless/navigation.py +105 -0
  701. nautobot/wireless/tables.py +244 -0
  702. nautobot/wireless/templates/wireless/radioprofile_retrieve.html +81 -0
  703. nautobot/wireless/templates/wireless/supporteddatarate_retrieve.html +26 -0
  704. nautobot/wireless/templates/wireless/wirelessnetwork_create.html +88 -0
  705. nautobot/wireless/templates/wireless/wirelessnetwork_retrieve.html +56 -0
  706. nautobot/wireless/tests/__init__.py +0 -0
  707. nautobot/wireless/tests/integration/__init__.py +0 -0
  708. nautobot/wireless/tests/integration/test_radio_profile.py +42 -0
  709. nautobot/wireless/tests/test_api.py +247 -0
  710. nautobot/wireless/tests/test_filters.py +82 -0
  711. nautobot/wireless/tests/test_models.py +22 -0
  712. nautobot/wireless/tests/test_views.py +378 -0
  713. nautobot/wireless/urls.py +13 -0
  714. nautobot/wireless/views.py +119 -0
  715. {nautobot-2.3.16.dist-info → nautobot-2.4.0.dist-info}/METADATA +9 -12
  716. {nautobot-2.3.16.dist-info → nautobot-2.4.0.dist-info}/RECORD +720 -549
  717. nautobot/core/utils/navigation.py +0 -54
  718. {nautobot-2.3.16.dist-info → nautobot-2.4.0.dist-info}/LICENSE.txt +0 -0
  719. {nautobot-2.3.16.dist-info → nautobot-2.4.0.dist-info}/NOTICE +0 -0
  720. {nautobot-2.3.16.dist-info → nautobot-2.4.0.dist-info}/WHEEL +0 -0
  721. {nautobot-2.3.16.dist-info → nautobot-2.4.0.dist-info}/entry_points.txt +0 -0
@@ -19,7 +19,6 @@ from nautobot.core.api import (
19
19
  ValidatedModelSerializer,
20
20
  )
21
21
  from nautobot.core.api.exceptions import SerializerNotFound
22
- from nautobot.core.api.fields import NautobotHyperlinkedRelatedField
23
22
  from nautobot.core.api.serializers import PolymorphicProxySerializer
24
23
  from nautobot.core.api.utils import (
25
24
  get_nested_serializer_depth,
@@ -66,6 +65,8 @@ from nautobot.extras.models import (
66
65
  JobButton,
67
66
  JobHook,
68
67
  JobLogEntry,
68
+ JobQueue,
69
+ JobQueueAssignment,
69
70
  JobResult,
70
71
  MetadataChoice,
71
72
  MetadataType,
@@ -134,12 +135,12 @@ class ConfigContextSerializer(ValidatedModelSerializer, TaggedModelSerializerMix
134
135
  owner = serializers.SerializerMethodField(read_only=True)
135
136
 
136
137
  # Conditional enablement of dynamic groups filtering
137
- def __init__(self, *args, **kwargs):
138
- super().__init__(*args, **kwargs)
139
-
138
+ @property
139
+ def fields(self):
140
+ fields = super().fields
140
141
  if not settings.CONFIG_CONTEXT_DYNAMIC_GROUPS_ENABLED:
141
- # In the case of a nested serializer, we won't have a `dynamic_groups` field at all.
142
- self.fields.pop("dynamic_groups", None)
142
+ fields.pop("dynamic_groups", None)
143
+ return fields
143
144
 
144
145
  class Meta:
145
146
  model = ConfigContext
@@ -198,10 +199,7 @@ class ConfigContextSchemaSerializer(NautobotModelSerializer):
198
199
  #
199
200
 
200
201
 
201
- class ContactSerializer(NautobotModelSerializer):
202
- # needed since this is the reverse side of the M2M field.
203
- teams = NautobotHyperlinkedRelatedField(queryset=Team.objects.all(), many=True, required=False)
204
-
202
+ class ContactSerializer(TaggedModelSerializerMixin, NautobotModelSerializer):
205
203
  class Meta:
206
204
  model = Contact
207
205
  fields = "__all__"
@@ -210,8 +208,15 @@ class ContactSerializer(NautobotModelSerializer):
210
208
  extra_kwargs = {
211
209
  "email": {"default": ""},
212
210
  "phone": {"default": ""},
211
+ "teams": {"required": False},
213
212
  }
214
213
 
214
+ def get_field_names(self, declared_fields, info):
215
+ """Add reverse M2M for teams to the fields for this serializer."""
216
+ field_names = list(super().get_field_names(declared_fields, info))
217
+ self.extend_field_names(field_names, "teams")
218
+ return field_names
219
+
215
220
  def validate(self, attrs):
216
221
  local_attrs = attrs.copy()
217
222
  local_attrs.pop("teams", None)
@@ -432,7 +437,7 @@ class ExportTemplateSerializer(RelationshipModelSerializerMixin, ValidatedModelS
432
437
  #
433
438
 
434
439
 
435
- class ExternalIntegrationSerializer(NautobotModelSerializer):
440
+ class ExternalIntegrationSerializer(TaggedModelSerializerMixin, NautobotModelSerializer):
436
441
  class Meta:
437
442
  model = ExternalIntegration
438
443
  fields = "__all__"
@@ -454,7 +459,7 @@ class FileProxySerializer(BaseModelSerializer):
454
459
  #
455
460
 
456
461
 
457
- class GitRepositorySerializer(NautobotModelSerializer):
462
+ class GitRepositorySerializer(TaggedModelSerializerMixin, NautobotModelSerializer):
458
463
  """Git repositories defined as a data source."""
459
464
 
460
465
  provided_contents = MultipleChoiceJSONField(
@@ -535,6 +540,10 @@ class ImageAttachmentSerializer(ValidatedModelSerializer):
535
540
 
536
541
 
537
542
  class JobSerializer(NautobotModelSerializer, TaggedModelSerializerMixin):
543
+ # task_queues and task_queues_override are added to maintain backward compatibility with versions pre v2.4.
544
+ task_queues = serializers.JSONField(read_only=True, required=False)
545
+ task_queues_override = serializers.BooleanField(read_only=True, required=False)
546
+
538
547
  class Meta:
539
548
  model = Job
540
549
  fields = "__all__"
@@ -559,6 +568,18 @@ class JobSerializer(NautobotModelSerializer, TaggedModelSerializerMixin):
559
568
  return super().validate(attrs)
560
569
 
561
570
 
571
+ class JobQueueSerializer(NautobotModelSerializer, TaggedModelSerializerMixin):
572
+ class Meta:
573
+ model = JobQueue
574
+ fields = "__all__"
575
+
576
+
577
+ class JobQueueAssignmentSerializer(ValidatedModelSerializer):
578
+ class Meta:
579
+ model = JobQueueAssignment
580
+ fields = "__all__"
581
+
582
+
562
583
  class JobVariableSerializer(serializers.Serializer):
563
584
  """Serializer used for responses from the JobModelViewSet.variables() detail endpoint."""
564
585
 
@@ -583,6 +604,8 @@ class JobVariableSerializer(serializers.Serializer):
583
604
 
584
605
  class ScheduledJobSerializer(BaseModelSerializer):
585
606
  # start_time = serializers.DateTimeField(format=None, required=False)
607
+ # queue is added to maintain backward compatibility with versions pre v2.4.
608
+ queue = serializers.CharField(read_only=True, required=False)
586
609
  time_zone = TimeZoneSerializerField(required=False)
587
610
 
588
611
  class Meta:
@@ -733,6 +756,7 @@ class JobInputSerializer(serializers.Serializer):
733
756
  data = serializers.JSONField(required=False, default=dict)
734
757
  schedule = JobCreationSerializer(required=False)
735
758
  task_queue = serializers.CharField(required=False, allow_blank=True)
759
+ job_queue = serializers.CharField(required=False, allow_blank=True)
736
760
 
737
761
 
738
762
  class JobMultiPartInputSerializer(serializers.Serializer):
@@ -743,6 +767,7 @@ class JobMultiPartInputSerializer(serializers.Serializer):
743
767
  _schedule_interval = ChoiceField(choices=JobExecutionType, required=False)
744
768
  _schedule_crontab = serializers.CharField(required=False, allow_blank=True)
745
769
  _task_queue = serializers.CharField(required=False, allow_blank=True)
770
+ _job_queue = serializers.CharField(required=False, allow_blank=True)
746
771
 
747
772
  def validate(self, attrs):
748
773
  attrs = super().validate(attrs)
@@ -798,7 +823,7 @@ class JobButtonSerializer(ValidatedModelSerializer, NotesSerializerMixin):
798
823
  #
799
824
 
800
825
 
801
- class MetadataTypeSerializer(NautobotModelSerializer):
826
+ class MetadataTypeSerializer(TaggedModelSerializerMixin, NautobotModelSerializer):
802
827
  content_types = ContentTypeField(
803
828
  queryset=ContentType.objects.filter(FeatureQuery("metadata").get_query()),
804
829
  many=True,
@@ -862,7 +887,6 @@ class NoteSerializer(BaseModelSerializer):
862
887
  class Meta:
863
888
  model = Note
864
889
  fields = "__all__"
865
- list_display_fields = ["note", "assigned_object_type", "assigned_object_id", "user"]
866
890
 
867
891
  @extend_schema_field(
868
892
  PolymorphicProxySerializer(
@@ -902,7 +926,6 @@ class ObjectChangeSerializer(BaseModelSerializer):
902
926
  class Meta:
903
927
  model = ObjectChange
904
928
  fields = "__all__"
905
- list_display_fields = ["changed_object_id", "related_object_id", "related_object_type", "user"]
906
929
 
907
930
  @extend_schema_field(
908
931
  PolymorphicProxySerializer(
@@ -1076,9 +1099,7 @@ class TagSerializer(NautobotModelSerializer):
1076
1099
  #
1077
1100
 
1078
1101
 
1079
- class TeamSerializer(NautobotModelSerializer):
1080
- contacts = NautobotHyperlinkedRelatedField(queryset=Contact.objects.all(), many=True, required=False)
1081
-
1102
+ class TeamSerializer(TaggedModelSerializerMixin, NautobotModelSerializer):
1082
1103
  class Meta:
1083
1104
  model = Team
1084
1105
  fields = "__all__"
@@ -69,6 +69,10 @@ router.register("job-hooks", views.JobHooksViewSet)
69
69
  # Job Log Entries
70
70
  router.register("job-logs", views.JobLogEntryViewSet)
71
71
 
72
+ # Job Queues
73
+ router.register("job-queues", views.JobQueueViewSet)
74
+ router.register("job-queue-assignments", views.JobQueueAssignmentViewSet)
75
+
72
76
  # Job Results
73
77
  router.register("job-results", views.JobResultViewSet)
74
78
 
@@ -27,11 +27,13 @@ from nautobot.core.api.views import (
27
27
  NautobotAPIVersionMixin,
28
28
  ReadOnlyModelViewSet,
29
29
  )
30
+ from nautobot.core.events import publish_event
30
31
  from nautobot.core.exceptions import CeleryWorkerNotRunningException
31
32
  from nautobot.core.graphql import execute_saved_query
32
33
  from nautobot.core.models.querysets import count_related
34
+ from nautobot.core.models.utils import serialize_object_v2
33
35
  from nautobot.extras import filters
34
- from nautobot.extras.choices import JobExecutionType
36
+ from nautobot.extras.choices import JobExecutionType, JobQueueTypeChoices
35
37
  from nautobot.extras.filters import RoleFilterSet
36
38
  from nautobot.extras.jobs import get_job
37
39
  from nautobot.extras.models import (
@@ -55,6 +57,8 @@ from nautobot.extras.models import (
55
57
  JobButton,
56
58
  JobHook,
57
59
  JobLogEntry,
60
+ JobQueue,
61
+ JobQueueAssignment,
58
62
  JobResult,
59
63
  MetadataChoice,
60
64
  MetadataType,
@@ -78,7 +82,7 @@ from nautobot.extras.models import (
78
82
  Webhook,
79
83
  )
80
84
  from nautobot.extras.secrets.exceptions import SecretError
81
- from nautobot.extras.utils import get_worker_count
85
+ from nautobot.extras.utils import get_job_queue, get_worker_count
82
86
 
83
87
  from . import serializers
84
88
 
@@ -177,14 +181,7 @@ class ConfigContextQuerySetMixin:
177
181
 
178
182
 
179
183
  class ConfigContextViewSet(NotesViewSetMixin, ModelViewSet):
180
- queryset = ConfigContext.objects.prefetch_related(
181
- "locations",
182
- "roles",
183
- "device_types",
184
- "platforms",
185
- "tenant_groups",
186
- "tenants",
187
- )
184
+ queryset = ConfigContext.objects.all()
188
185
  serializer_class = serializers.ConfigContextSerializer
189
186
  filterset_class = filters.ConfigContextFilterSet
190
187
 
@@ -301,7 +298,7 @@ class DynamicGroupViewSet(NotesViewSetMixin, ModelViewSet):
301
298
  Manage Dynamic Groups through DELETE, GET, POST, PUT, and PATCH requests.
302
299
  """
303
300
 
304
- queryset = DynamicGroup.objects.select_related("content_type")
301
+ queryset = DynamicGroup.objects.all()
305
302
  serializer_class = serializers.DynamicGroupSerializer
306
303
  filterset_class = filters.DynamicGroupFilterSet
307
304
 
@@ -326,7 +323,7 @@ class DynamicGroupMembershipViewSet(ModelViewSet):
326
323
  Manage Dynamic Group Memberships through DELETE, GET, POST, PUT, and PATCH requests.
327
324
  """
328
325
 
329
- queryset = DynamicGroupMembership.objects.select_related("group", "parent_group")
326
+ queryset = DynamicGroupMembership.objects.all()
330
327
  serializer_class = serializers.DynamicGroupMembershipSerializer
331
328
  filterset_class = filters.DynamicGroupMembershipFilterSet
332
329
 
@@ -337,13 +334,13 @@ class DynamicGroupMembershipViewSet(ModelViewSet):
337
334
 
338
335
 
339
336
  class SavedViewViewSet(ModelViewSet):
340
- queryset = SavedView.objects.select_related("owner")
337
+ queryset = SavedView.objects.all()
341
338
  serializer_class = serializers.SavedViewSerializer
342
339
  filterset_class = filters.SavedViewFilterSet
343
340
 
344
341
 
345
342
  class UserSavedViewAssociationViewSet(ModelViewSet):
346
- queryset = UserSavedViewAssociation.objects.select_related("user", "saved_view")
343
+ queryset = UserSavedViewAssociation.objects.all()
347
344
  serializer_class = serializers.UserSavedViewAssociationSerializer
348
345
  filterset_class = filters.UserSavedViewAssociationFilterSet
349
346
 
@@ -353,7 +350,7 @@ class StaticGroupAssociationViewSet(NautobotModelViewSet):
353
350
  Manage Static Group Associations through DELETE, GET, POST, PUT, and PATCH requests.
354
351
  """
355
352
 
356
- queryset = StaticGroupAssociation.objects.select_related("associated_object_type", "dynamic_group")
353
+ queryset = StaticGroupAssociation.objects.all()
357
354
  serializer_class = serializers.StaticGroupAssociationSerializer
358
355
  filterset_class = filters.StaticGroupAssociationFilterSet
359
356
 
@@ -364,7 +361,7 @@ class StaticGroupAssociationViewSet(NautobotModelViewSet):
364
361
  and "dynamic_group" in self.request.GET
365
362
  and self.action in ["list", "retrieve"]
366
363
  ):
367
- self.queryset = StaticGroupAssociation.all_objects.select_related("associated_object_type", "dynamic_group")
364
+ self.queryset = StaticGroupAssociation.all_objects.all()
368
365
  return super().get_queryset()
369
366
 
370
367
 
@@ -385,7 +382,7 @@ class ExportTemplateViewSet(NotesViewSetMixin, ModelViewSet):
385
382
 
386
383
 
387
384
  class ExternalIntegrationViewSet(NautobotModelViewSet):
388
- queryset = ExternalIntegration.objects.select_related("secrets_group")
385
+ queryset = ExternalIntegration.objects.all()
389
386
  serializer_class = serializers.ExternalIntegrationSerializer
390
387
  filterset_class = filters.ExternalIntegrationFilterSet
391
388
 
@@ -396,7 +393,7 @@ class ExternalIntegrationViewSet(NautobotModelViewSet):
396
393
 
397
394
 
398
395
  class FileProxyViewSet(ReadOnlyModelViewSet):
399
- queryset = FileProxy.objects.select_related("job_result")
396
+ queryset = FileProxy.objects.all()
400
397
  serializer_class = serializers.FileProxySerializer
401
398
  filterset_class = filters.FileProxyFilterSet
402
399
 
@@ -601,9 +598,8 @@ class JobViewSetBase(
601
598
  )
602
599
 
603
600
  valid_queues = job_model.task_queues if job_model.task_queues else [settings.CELERY_TASK_DEFAULT_QUEUE]
604
- # Get a default queue from either the job model's specified task queue or
605
- # the system default to fall back on if request doesn't provide one
606
- default_valid_queue = valid_queues[0]
601
+ # default queue should be specified on the default_job_queue.
602
+ default_valid_queue = job_model.default_job_queue.name
607
603
 
608
604
  # We need to call request.data for both cases as this is what pulls and caches the request data
609
605
  data = request.data
@@ -624,7 +620,23 @@ class JobViewSetBase(
624
620
  input_serializer = serializers.JobMultiPartInputSerializer(data=data, context={"request": request})
625
621
  input_serializer.is_valid(raise_exception=True)
626
622
 
627
- task_queue = input_serializer.validated_data.get("_task_queue", default_valid_queue)
623
+ # TODO remove _task_queue related code in 3.0
624
+ # _task_queue and _job_queue are both valid arguments in v2.4
625
+ task_queue = input_serializer.validated_data.get(
626
+ "_task_queue", None
627
+ ) or input_serializer.validated_data.get("_job_queue", None)
628
+ if not task_queue:
629
+ task_queue = default_valid_queue
630
+
631
+ # Log a warning if _task_queue and _job_queue fields are both specified out
632
+ if input_serializer.validated_data.get("_task_queue", None) and input_serializer.validated_data.get(
633
+ "_job_queue", None
634
+ ):
635
+ raise ValidationError(
636
+ {
637
+ "_task_queue": "_task_queue and _job_queue are both specified. Please specifiy only one or another."
638
+ }
639
+ )
628
640
 
629
641
  # JobMultiPartInputSerializer only has keys for executing job (task_queue, etc),
630
642
  # everything else is a candidate for the job form's data.
@@ -652,7 +664,21 @@ class JobViewSetBase(
652
664
  input_serializer.is_valid(raise_exception=True)
653
665
 
654
666
  data = input_serializer.validated_data.get("data", {})
655
- task_queue = input_serializer.validated_data.get("task_queue", default_valid_queue)
667
+ # TODO remove _task_queue related code in 3.0
668
+ # _task_queue and _job_queue are both valid arguments in v2.4
669
+ task_queue = input_serializer.validated_data.get("task_queue", None) or input_serializer.validated_data.get(
670
+ "job_queue", None
671
+ )
672
+ if not task_queue:
673
+ task_queue = default_valid_queue
674
+
675
+ # Log a warning if _task_queue and _job_queue fields are both specified out
676
+ if input_serializer.validated_data.get("task_queue", None) and input_serializer.validated_data.get(
677
+ "job_queue", None
678
+ ):
679
+ raise ValidationError(
680
+ {"task_queue": "task_queue and job_queue are both specified. Please specifiy only one or another."}
681
+ )
656
682
  schedule_data = input_serializer.validated_data.get("schedule", None)
657
683
 
658
684
  if task_queue not in valid_queues:
@@ -669,7 +695,10 @@ class JobViewSetBase(
669
695
  # of errors under messages
670
696
  return Response({"errors": e.message_dict if hasattr(e, "error_dict") else e.messages}, status=400)
671
697
 
672
- if not get_worker_count(queue=task_queue):
698
+ queue = get_job_queue(task_queue)
699
+ if queue is None:
700
+ queue = job_model.default_job_queue
701
+ if queue.queue_type == JobQueueTypeChoices.TYPE_CELERY and not get_worker_count(queue=task_queue):
673
702
  raise CeleryWorkerNotRunningException(queue=task_queue)
674
703
 
675
704
  # Default to a null JobResult.
@@ -700,7 +729,7 @@ class JobViewSetBase(
700
729
  interval=schedule_data.get("interval"),
701
730
  crontab=schedule_data.get("crontab", ""),
702
731
  approval_required=approval_required,
703
- task_queue=input_serializer.validated_data.get("task_queue", None),
732
+ task_queue=task_queue,
704
733
  **job_class.serialize_data(cleaned_data),
705
734
  )
706
735
  else:
@@ -784,6 +813,31 @@ class JobHooksViewSet(NautobotModelViewSet):
784
813
  filterset_class = filters.JobHookFilterSet
785
814
 
786
815
 
816
+ #
817
+ # Job Queues
818
+ #
819
+
820
+
821
+ class JobQueueViewSet(NautobotModelViewSet):
822
+ """
823
+ Manage job queues through DELETE, GET, POST, PUT, and PATCH requests.
824
+ """
825
+
826
+ queryset = JobQueue.objects.all()
827
+ serializer_class = serializers.JobQueueSerializer
828
+ filterset_class = filters.JobQueueFilterSet
829
+
830
+
831
+ class JobQueueAssignmentViewSet(NautobotModelViewSet):
832
+ """
833
+ Manage job queue assignments through DELETE, GET, POST, PUT, and PATCH requests.
834
+ """
835
+
836
+ queryset = JobQueueAssignment.objects.all()
837
+ serializer_class = serializers.JobQueueAssignmentSerializer
838
+ filterset_class = filters.JobQueueAssignmentFilterSet
839
+
840
+
787
841
  #
788
842
  # Job Results
789
843
  #
@@ -794,7 +848,7 @@ class JobLogEntryViewSet(ReadOnlyModelViewSet):
794
848
  Retrieve a list of job log entries.
795
849
  """
796
850
 
797
- queryset = JobLogEntry.objects.select_related("job_result")
851
+ queryset = JobLogEntry.objects.all()
798
852
  serializer_class = serializers.JobLogEntrySerializer
799
853
  filterset_class = filters.JobLogEntryFilterSet
800
854
 
@@ -812,7 +866,7 @@ class JobResultViewSet(
812
866
  Retrieve a list of job results
813
867
  """
814
868
 
815
- queryset = JobResult.objects.select_related("job_model", "user")
869
+ queryset = JobResult.objects.all()
816
870
  serializer_class = serializers.JobResultSerializer
817
871
  filterset_class = filters.JobResultFilterSet
818
872
 
@@ -849,7 +903,7 @@ class ScheduledJobViewSet(ReadOnlyModelViewSet):
849
903
  Retrieve a list of scheduled jobs
850
904
  """
851
905
 
852
- queryset = ScheduledJob.objects.select_related("user")
906
+ queryset = ScheduledJob.objects.all()
853
907
  serializer_class = serializers.ScheduledJobSerializer
854
908
  filterset_class = filters.ScheduledJobFilterSet
855
909
 
@@ -912,6 +966,8 @@ class ScheduledJobViewSet(ReadOnlyModelViewSet):
912
966
  scheduled_job.approved_by_user = request.user
913
967
  scheduled_job.approved_at = timezone.now()
914
968
  scheduled_job.save()
969
+ publish_event_payload = {"data": serialize_object_v2(scheduled_job)}
970
+ publish_event(topic="nautobot.jobs.approval.approved", payload=publish_event_payload)
915
971
  serializer = serializers.ScheduledJobSerializer(scheduled_job, context={"request": request})
916
972
 
917
973
  return Response(serializer.data)
@@ -936,6 +992,8 @@ class ScheduledJobViewSet(ReadOnlyModelViewSet):
936
992
  if not Job.objects.check_perms(request.user, instance=scheduled_job.job_model, action="approve"):
937
993
  raise PermissionDenied("You do not have permission to deny this request.")
938
994
 
995
+ publish_event_payload = {"data": serialize_object_v2(scheduled_job)}
996
+ publish_event(topic="nautobot.jobs.approval.denied", payload=publish_event_payload)
939
997
  scheduled_job.delete()
940
998
 
941
999
  return Response(None)
@@ -998,7 +1056,7 @@ class MetadataTypeViewSet(NautobotModelViewSet):
998
1056
 
999
1057
 
1000
1058
  class MetadataChoiceViewSet(ModelViewSet):
1001
- queryset = MetadataChoice.objects.select_related("metadata_type")
1059
+ queryset = MetadataChoice.objects.all()
1002
1060
  serializer_class = serializers.MetadataChoiceSerializer
1003
1061
  filterset_class = filters.MetadataChoiceFilterSet
1004
1062
 
@@ -1015,7 +1073,7 @@ class ObjectMetadataViewSet(NautobotModelViewSet):
1015
1073
 
1016
1074
 
1017
1075
  class NoteViewSet(ModelViewSet):
1018
- queryset = Note.objects.select_related("user")
1076
+ queryset = Note.objects.all()
1019
1077
  serializer_class = serializers.NoteSerializer
1020
1078
  filterset_class = filters.NoteFilterSet
1021
1079
 
@@ -1034,7 +1092,7 @@ class ObjectChangeViewSet(ReadOnlyModelViewSet):
1034
1092
  Retrieve a list of recent changes.
1035
1093
  """
1036
1094
 
1037
- queryset = ObjectChange.objects.select_related("user")
1095
+ queryset = ObjectChange.objects.all()
1038
1096
  serializer_class = serializers.ObjectChangeSerializer
1039
1097
  filterset_class = filters.ObjectChangeFilterSet
1040
1098
 
@@ -229,6 +229,16 @@ class JobExecutionType(ChoiceSet):
229
229
  }
230
230
 
231
231
 
232
+ class JobQueueTypeChoices(ChoiceSet):
233
+ TYPE_CELERY = "celery"
234
+ TYPE_KUBERNETES = "kubernetes"
235
+
236
+ CHOICES = (
237
+ (TYPE_CELERY, "Celery"),
238
+ (TYPE_KUBERNETES, "Kubernetes"),
239
+ )
240
+
241
+
232
242
  #
233
243
  # Job results
234
244
  #
@@ -295,6 +305,7 @@ class LogLevelChoices(ChoiceSet):
295
305
  LOG_WARNING = "warning"
296
306
  LOG_ERROR = "error"
297
307
  LOG_CRITICAL = "critical"
308
+ LOG_SUCCESS = "success"
298
309
 
299
310
  CHOICES = (
300
311
  (LOG_DEBUG, "Debug"),
@@ -302,6 +313,7 @@ class LogLevelChoices(ChoiceSet):
302
313
  (LOG_WARNING, "Warning"),
303
314
  (LOG_ERROR, "Error"),
304
315
  (LOG_CRITICAL, "Critical"),
316
+ (LOG_SUCCESS, "Success"),
305
317
  )
306
318
 
307
319
  CSS_CLASSES = {
@@ -310,6 +322,7 @@ class LogLevelChoices(ChoiceSet):
310
322
  LOG_WARNING: "warning",
311
323
  LOG_ERROR: "error",
312
324
  LOG_CRITICAL: "critical",
325
+ LOG_SUCCESS: "success",
313
326
  }
314
327
 
315
328
 
@@ -30,7 +30,7 @@ JOB_OVERRIDABLE_FIELDS = (
30
30
  "soft_time_limit",
31
31
  "time_limit",
32
32
  "has_sensitive_variables",
33
- "task_queues",
33
+ "is_singleton",
34
34
  )
35
35
 
36
36
 
@@ -53,4 +53,5 @@ JOB_RESULT_CUSTOM_CELERY_KWARGS = (
53
53
  "nautobot_job_job_model_id",
54
54
  "nautobot_job_scheduled_job_id",
55
55
  "nautobot_job_user_id",
56
+ "nautobot_job_ignore_singleton_lock",
56
57
  )
@@ -6,6 +6,7 @@ from django.contrib.auth.models import AnonymousUser
6
6
  from django.db import transaction
7
7
  from django.test.client import RequestFactory
8
8
 
9
+ from nautobot.core.events import publish_event
9
10
  from nautobot.extras.choices import ObjectChangeEventContextChoices
10
11
  from nautobot.extras.constants import CHANGELOG_MAX_CHANGE_CONTEXT_DETAIL
11
12
  from nautobot.extras.models import ObjectChange
@@ -211,27 +212,43 @@ def web_request_context(
211
212
  last_action = None
212
213
  last_content_type = None
213
214
  # enqueue jobhooks and webhooks, use change_context.change_id in case change_id was not supplied
214
- for object_change in (
215
+ for oc in (
215
216
  ObjectChange.objects.select_related("changed_object_type", "user")
216
217
  .filter(request_id=change_context.change_id)
217
218
  .order_by("time") # default ordering is -time but we want oldest first not newest first
218
219
  .iterator()
219
220
  ):
220
- if object_change.action != last_action or object_change.changed_object_type != last_content_type:
221
+ if oc.action != last_action or oc.changed_object_type != last_content_type:
221
222
  jobhook_queryset = None
222
223
  webhook_queryset = None
223
224
 
224
225
  if context != ObjectChangeEventContextChoices.CONTEXT_JOB_HOOK:
225
226
  # Make sure JobHooks are up to date (only once) before calling them
226
227
  did_reload_jobs, jobhook_queryset = enqueue_job_hooks(
227
- object_change, may_reload_jobs=(not jobs_reloaded), jobhook_queryset=jobhook_queryset
228
+ oc, may_reload_jobs=(not jobs_reloaded), jobhook_queryset=jobhook_queryset
228
229
  )
229
230
  if did_reload_jobs:
230
231
  jobs_reloaded = True
231
232
 
232
- webhook_queryset = enqueue_webhooks(object_change, webhook_queryset=webhook_queryset)
233
- last_action = object_change.action
234
- last_content_type = object_change.changed_object_type
233
+ # TODO: get_snapshots() currently requires a DB query per object change processed.
234
+ # We need to develop a more efficient approach: https://github.com/nautobot/nautobot/issues/6303
235
+ snapshots = oc.get_snapshots()
236
+ webhook_queryset = enqueue_webhooks(oc, snapshots=snapshots, webhook_queryset=webhook_queryset)
237
+
238
+ # topic examples: "nautobot.change.dcim.device", "nautobot.add.ipam.ipaddress"
239
+ event_topic = f"nautobot.{oc.action}.{oc.changed_object_type.app_label}.{oc.changed_object_type.model}"
240
+ event_payload = snapshots.copy()
241
+ event_payload["context"] = {
242
+ "change_context": oc.get_change_context_display(),
243
+ "change_context_detail": oc.change_context_detail,
244
+ "request_id": str(oc.request_id),
245
+ "user_name": oc.user_name,
246
+ "timestamp": str(oc.time),
247
+ }
248
+ publish_event(topic=event_topic, payload=event_payload)
249
+
250
+ last_action = oc.action
251
+ last_content_type = oc.changed_object_type
235
252
 
236
253
 
237
254
  @contextmanager
@@ -31,6 +31,7 @@ from nautobot.extras.models import (
31
31
  ExportTemplate,
32
32
  GitRepository,
33
33
  Job,
34
+ JobQueue,
34
35
  JobResult,
35
36
  Role,
36
37
  Tag,
@@ -763,7 +764,9 @@ def refresh_git_jobs(repository_record, job_result, delete=False):
763
764
  if not job_class_path.startswith(f"{repository_record.slug}.jobs."):
764
765
  continue
765
766
  found_jobs = True
766
- job_model, created = refresh_job_model_from_job_class(Job, job_class)
767
+ job_model, created = refresh_job_model_from_job_class(
768
+ job_model_class=Job, job_class=job_class, job_queue_class=JobQueue
769
+ )
767
770
 
768
771
  if job_model is None:
769
772
  msg = "Failed to create Job record; check Nautobot logs for details"
@@ -20,6 +20,7 @@ from nautobot.core.factory import (
20
20
  from nautobot.core.templatetags.helpers import bettertitle
21
21
  from nautobot.extras.choices import (
22
22
  DynamicGroupTypeChoices,
23
+ JobQueueTypeChoices,
23
24
  JobResultStatusChoices,
24
25
  LogLevelChoices,
25
26
  MetadataTypeDataTypeChoices,
@@ -34,6 +35,7 @@ from nautobot.extras.models import (
34
35
  ExternalIntegration,
35
36
  Job,
36
37
  JobLogEntry,
38
+ JobQueue,
37
39
  JobResult,
38
40
  MetadataChoice,
39
41
  MetadataType,
@@ -140,6 +142,31 @@ class JobLogEntryFactory(BaseModelFactory):
140
142
  return faker.Faker().past_datetime(start_date=self.job_result.date_created, tzinfo=timezone.utc)
141
143
 
142
144
 
145
+ class JobQueueFactory(PrimaryModelFactory):
146
+ """JobQueue model Factory"""
147
+
148
+ class Meta:
149
+ model = JobQueue
150
+
151
+ class Params:
152
+ has_description = NautobotBoolIterator()
153
+ has_tenant = NautobotBoolIterator()
154
+
155
+ name = factory.LazyAttributeSequence(lambda o, n: f"{o.queue_type} Job Queue - {n}")
156
+ description = factory.Maybe("has_description", factory.Faker("text", max_nb_chars=CHARFIELD_MAX_LENGTH), "")
157
+ queue_type = factory.Iterator(JobQueueTypeChoices.CHOICES, getter=lambda choice: choice[0])
158
+ tenant = factory.Maybe("has_tenant", random_instance(Tenant))
159
+
160
+ @factory.post_generation
161
+ def jobs(self, create, extracted, **kwargs):
162
+ jobs = get_random_instances(Job)
163
+ self.jobs.set(jobs)
164
+ for job in jobs:
165
+ if not job.job_queues_override:
166
+ job.job_queues_override = True
167
+ job.validated_save()
168
+
169
+
143
170
  class JobResultFactory(BaseModelFactory):
144
171
  """JobResult model factory."""
145
172