nautobot 2.3.16__py3-none-any.whl → 2.4.0b1__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 (675) hide show
  1. nautobot/__init__.py +15 -0
  2. nautobot/apps/api.py +0 -2
  3. nautobot/apps/config.py +32 -3
  4. nautobot/apps/events.py +19 -0
  5. nautobot/apps/exceptions.py +0 -2
  6. nautobot/apps/ui.py +44 -9
  7. nautobot/apps/utils.py +0 -8
  8. nautobot/apps/views.py +2 -0
  9. nautobot/circuits/navigation.py +0 -57
  10. nautobot/circuits/tables.py +1 -2
  11. nautobot/circuits/templates/circuits/circuit_retrieve.html +0 -71
  12. nautobot/circuits/templates/circuits/inc/circuit_termination.html +6 -64
  13. nautobot/circuits/templates/circuits/inc/circuit_termination_cable_fragment.html +40 -0
  14. nautobot/circuits/templates/circuits/inc/circuit_termination_header_extra_content.html +26 -0
  15. nautobot/circuits/templates/circuits/provider_retrieve.html +0 -76
  16. nautobot/circuits/tests/integration/test_relationships.py +33 -24
  17. nautobot/circuits/tests/test_filters.py +4 -8
  18. nautobot/circuits/views.py +143 -26
  19. nautobot/cloud/factory.py +4 -1
  20. nautobot/cloud/models.py +1 -1
  21. nautobot/cloud/tests/test_filters.py +5 -4
  22. nautobot/core/api/fields.py +5 -5
  23. nautobot/core/api/metadata.py +28 -256
  24. nautobot/core/api/pagination.py +3 -2
  25. nautobot/core/api/renderers.py +3 -0
  26. nautobot/core/api/serializers.py +24 -244
  27. nautobot/core/api/urls.py +3 -4
  28. nautobot/core/api/utils.py +0 -62
  29. nautobot/core/api/views.py +48 -158
  30. nautobot/core/apps/__init__.py +22 -578
  31. nautobot/core/celery/__init__.py +13 -0
  32. nautobot/core/celery/log.py +4 -4
  33. nautobot/core/celery/schedulers.py +48 -3
  34. nautobot/core/cli/__init__.py +8 -0
  35. nautobot/core/constants.py +7 -0
  36. nautobot/core/events/__init__.py +116 -0
  37. nautobot/core/events/base.py +27 -0
  38. nautobot/core/events/exceptions.py +10 -0
  39. nautobot/core/events/redis_broker.py +48 -0
  40. nautobot/core/events/syslog_broker.py +19 -0
  41. nautobot/core/exceptions.py +0 -6
  42. nautobot/core/filters.py +16 -21
  43. nautobot/core/fixtures/user-data.json +59 -0
  44. nautobot/core/forms/fields.py +53 -8
  45. nautobot/core/forms/utils.py +2 -1
  46. nautobot/core/graphql/schema.py +3 -1
  47. nautobot/core/graphql/types.py +1 -1
  48. nautobot/core/jobs/__init__.py +4 -4
  49. nautobot/core/jobs/cleanup.py +13 -49
  50. nautobot/core/jobs/groups.py +1 -1
  51. nautobot/core/management/commands/generate_test_data.py +21 -0
  52. nautobot/core/management/commands/validate_models.py +1 -1
  53. nautobot/core/middleware.py +16 -0
  54. nautobot/core/models/__init__.py +1 -1
  55. nautobot/core/models/fields.py +11 -7
  56. nautobot/core/models/query_functions.py +2 -2
  57. nautobot/core/models/tree_queries.py +3 -6
  58. nautobot/core/settings.py +44 -7
  59. nautobot/core/settings.yaml +86 -8
  60. nautobot/core/tables.py +15 -65
  61. nautobot/core/tasks.py +1 -1
  62. nautobot/core/templates/components/button/default.html +7 -0
  63. nautobot/core/templates/components/button/dropdown.html +20 -0
  64. nautobot/core/templates/components/layout/one_over_two.html +19 -0
  65. nautobot/core/templates/components/layout/two_over_one.html +19 -0
  66. nautobot/core/templates/components/panel/body_content_data_table.html +27 -0
  67. nautobot/core/templates/components/panel/body_content_objects_table.html +4 -0
  68. nautobot/core/templates/components/panel/body_content_tags.html +6 -0
  69. nautobot/core/templates/components/panel/body_content_text.html +12 -0
  70. nautobot/core/templates/components/panel/body_wrapper_generic.html +3 -0
  71. nautobot/core/templates/components/panel/body_wrapper_key_value_table.html +3 -0
  72. nautobot/core/templates/components/panel/body_wrapper_table.html +3 -0
  73. nautobot/core/templates/components/panel/footer_contacts_table.html +20 -0
  74. nautobot/core/templates/components/panel/footer_content_table.html +14 -0
  75. nautobot/core/templates/components/panel/grouping_toggle.html +14 -0
  76. nautobot/core/templates/components/panel/header_extra_content_table.html +3 -0
  77. nautobot/core/templates/components/panel/panel.html +16 -0
  78. nautobot/core/templates/components/panel/stats_panel_body.html +8 -0
  79. nautobot/core/templates/components/tab/content_wrapper.html +3 -0
  80. nautobot/core/templates/components/tab/label_wrapper.html +5 -0
  81. nautobot/core/templates/components/tab/label_wrapper_distinct_view.html +3 -0
  82. nautobot/core/templates/generic/object_retrieve.html +28 -17
  83. nautobot/core/templates/inc/computed_fields/panel_data.html +4 -7
  84. nautobot/core/templates/inc/custom_fields/panel.html +2 -2
  85. nautobot/core/templates/inc/custom_fields/panel_data.html +4 -7
  86. nautobot/core/templates/inc/footer.html +1 -0
  87. nautobot/core/templates/inc/media.html +0 -3
  88. nautobot/core/templates/inc/nav_menu.html +1 -1
  89. nautobot/core/templates/inc/relationships_panel.html +1 -1
  90. nautobot/core/templates/nautobot_config.py.j2 +3 -3
  91. nautobot/core/templates/panel_table.html +12 -0
  92. nautobot/core/templates/search.html +0 -7
  93. nautobot/core/templates/utilities/render_jinja2.html +117 -0
  94. nautobot/core/templatetags/helpers.py +101 -12
  95. nautobot/core/templatetags/ui_framework.py +40 -0
  96. nautobot/core/testing/api.py +23 -128
  97. nautobot/core/testing/context.py +18 -0
  98. nautobot/core/testing/filters.py +41 -58
  99. nautobot/core/testing/mixins.py +2 -7
  100. nautobot/core/testing/views.py +25 -123
  101. nautobot/core/tests/integration/test_app_home.py +1 -0
  102. nautobot/core/tests/integration/test_app_navbar.py +1 -0
  103. nautobot/core/tests/integration/test_filters.py +2 -0
  104. nautobot/core/tests/integration/test_home.py +1 -0
  105. nautobot/core/tests/integration/test_navbar.py +1 -0
  106. nautobot/core/tests/integration/test_view_authentication.py +1 -2
  107. nautobot/core/tests/nautobot_config.py +198 -0
  108. nautobot/core/tests/runner.py +3 -3
  109. nautobot/core/tests/test_api.py +82 -201
  110. nautobot/core/tests/test_csv.py +3 -25
  111. nautobot/core/tests/test_events.py +214 -0
  112. nautobot/core/tests/test_jinja_filters.py +1 -0
  113. nautobot/core/tests/test_jobs.py +84 -13
  114. nautobot/core/tests/test_navigations.py +7 -241
  115. nautobot/core/tests/test_templatetags_helpers.py +16 -0
  116. nautobot/core/tests/test_ui.py +150 -0
  117. nautobot/core/tests/test_utils.py +0 -25
  118. nautobot/core/tests/test_views.py +123 -31
  119. nautobot/core/ui/__init__.py +0 -0
  120. nautobot/core/ui/base.py +11 -0
  121. nautobot/core/ui/choices.py +44 -0
  122. nautobot/core/ui/homepage.py +167 -0
  123. nautobot/core/ui/nav.py +279 -0
  124. nautobot/core/ui/object_detail.py +1841 -0
  125. nautobot/core/ui/utils.py +36 -0
  126. nautobot/core/urls.py +4 -9
  127. nautobot/core/utils/config.py +30 -3
  128. nautobot/core/utils/lookup.py +20 -13
  129. nautobot/core/views/__init__.py +6 -1
  130. nautobot/core/views/generic.py +47 -52
  131. nautobot/core/views/mixins.py +15 -25
  132. nautobot/core/views/paginator.py +8 -5
  133. nautobot/core/views/renderers.py +3 -3
  134. nautobot/core/views/utils.py +11 -0
  135. nautobot/core/wsgi.py +3 -3
  136. nautobot/dcim/api/serializers.py +80 -179
  137. nautobot/dcim/api/urls.py +5 -0
  138. nautobot/dcim/api/views.py +17 -4
  139. nautobot/dcim/apps.py +1 -0
  140. nautobot/dcim/choices.py +28 -0
  141. nautobot/dcim/factory.py +58 -0
  142. nautobot/dcim/filters/__init__.py +197 -24
  143. nautobot/dcim/forms.py +203 -12
  144. nautobot/dcim/graphql/types.py +2 -2
  145. nautobot/dcim/migrations/0063_interfacevdcassignment_virtualdevicecontext_and_more.py +165 -0
  146. nautobot/dcim/migrations/0064_virtualdevicecontext_status_data_migration.py +28 -0
  147. nautobot/dcim/migrations/0065_controller_capabilities_and_more.py +29 -0
  148. nautobot/dcim/migrations/0066_controllermanageddevicegroup_radio_profiles_and_more.py +33 -0
  149. nautobot/dcim/models/__init__.py +4 -0
  150. nautobot/dcim/models/device_component_templates.py +2 -2
  151. nautobot/dcim/models/device_components.py +20 -22
  152. nautobot/dcim/models/devices.py +173 -4
  153. nautobot/dcim/models/locations.py +3 -3
  154. nautobot/dcim/models/power.py +5 -6
  155. nautobot/dcim/models/racks.py +6 -6
  156. nautobot/dcim/navigation.py +25 -224
  157. nautobot/dcim/signals.py +44 -0
  158. nautobot/dcim/tables/__init__.py +5 -3
  159. nautobot/dcim/tables/devices.py +96 -2
  160. nautobot/dcim/tables/devicetypes.py +2 -2
  161. nautobot/dcim/templates/dcim/controller/base.html +10 -0
  162. nautobot/dcim/templates/dcim/controller_create.html +1 -0
  163. nautobot/dcim/templates/dcim/controller_retrieve.html +5 -1
  164. nautobot/dcim/templates/dcim/controller_wirelessnetworks.html +25 -0
  165. nautobot/dcim/templates/dcim/controllermanageddevicegroup_create.html +66 -0
  166. nautobot/dcim/templates/dcim/controllermanageddevicegroup_retrieve.html +46 -0
  167. nautobot/dcim/templates/dcim/device/base.html +6 -42
  168. nautobot/dcim/templates/dcim/device/wireless.html +73 -0
  169. nautobot/dcim/templates/dcim/device.html +3 -1
  170. nautobot/dcim/templates/dcim/interface.html +1 -0
  171. nautobot/dcim/templates/dcim/interface_edit.html +1 -0
  172. nautobot/dcim/templates/dcim/locationtype.html +0 -107
  173. nautobot/dcim/templates/dcim/locationtype_retrieve.html +8 -0
  174. nautobot/dcim/templates/dcim/virtualdevicecontext_retrieve.html +76 -0
  175. nautobot/dcim/templates/dcim/virtualdevicecontext_update.html +34 -0
  176. nautobot/dcim/tests/test_api.py +172 -61
  177. nautobot/dcim/tests/test_filters.py +171 -109
  178. nautobot/dcim/tests/test_forms.py +2 -51
  179. nautobot/dcim/tests/test_graphql.py +0 -52
  180. nautobot/dcim/tests/test_models.py +126 -4
  181. nautobot/dcim/tests/test_signals.py +1 -0
  182. nautobot/dcim/tests/test_views.py +103 -11
  183. nautobot/dcim/urls.py +72 -27
  184. nautobot/dcim/utils.py +2 -2
  185. nautobot/dcim/views.py +369 -62
  186. nautobot/extras/api/customfields.py +2 -2
  187. nautobot/extras/api/serializers.py +91 -75
  188. nautobot/extras/api/urls.py +4 -0
  189. nautobot/extras/api/views.py +78 -15
  190. nautobot/extras/choices.py +13 -0
  191. nautobot/extras/constants.py +0 -1
  192. nautobot/extras/context_managers.py +23 -6
  193. nautobot/extras/datasources/git.py +4 -1
  194. nautobot/extras/factory.py +27 -0
  195. nautobot/extras/filters/__init__.py +59 -0
  196. nautobot/extras/forms/forms.py +125 -30
  197. nautobot/extras/forms/mixins.py +3 -11
  198. nautobot/extras/graphql/types.py +25 -1
  199. nautobot/extras/group_sync.py +3 -3
  200. nautobot/extras/health_checks.py +2 -1
  201. nautobot/extras/jobs.py +62 -26
  202. nautobot/extras/management/__init__.py +1 -0
  203. nautobot/extras/management/commands/runjob.py +7 -79
  204. nautobot/extras/management/commands/runjob_with_job_result.py +46 -0
  205. nautobot/extras/management/utils.py +87 -0
  206. nautobot/extras/managers.py +1 -3
  207. nautobot/extras/migrations/0018_joblog_data_migration.py +9 -7
  208. nautobot/extras/migrations/0117_create_job_queue_model.py +129 -0
  209. nautobot/extras/migrations/0118_task_queue_to_job_queue_migration.py +78 -0
  210. nautobot/extras/migrations/0119_remove_task_queues_from_job_and_queue_from_scheduled_job.py +28 -0
  211. nautobot/extras/models/__init__.py +4 -0
  212. nautobot/extras/models/change_logging.py +7 -3
  213. nautobot/extras/models/customfields.py +11 -12
  214. nautobot/extras/models/groups.py +9 -13
  215. nautobot/extras/models/jobs.py +218 -37
  216. nautobot/extras/models/models.py +2 -2
  217. nautobot/extras/models/relationships.py +69 -1
  218. nautobot/extras/models/secrets.py +5 -0
  219. nautobot/extras/navigation.py +20 -262
  220. nautobot/extras/plugins/__init__.py +56 -32
  221. nautobot/extras/plugins/marketplace_manifest.yml +450 -0
  222. nautobot/extras/plugins/urls.py +1 -0
  223. nautobot/extras/plugins/views.py +48 -1
  224. nautobot/extras/signals.py +39 -1
  225. nautobot/extras/tables.py +40 -6
  226. nautobot/extras/templates/extras/externalintegration_retrieve.html +0 -47
  227. nautobot/extras/templates/extras/inc/tags_panel.html +1 -5
  228. nautobot/extras/templates/extras/job_bulk_edit.html +2 -1
  229. nautobot/extras/templates/extras/job_detail.html +36 -6
  230. nautobot/extras/templates/extras/job_edit.html +5 -2
  231. nautobot/extras/templates/extras/job_list.html +2 -7
  232. nautobot/extras/templates/extras/jobqueue_retrieve.html +44 -0
  233. nautobot/extras/templates/extras/marketplace.html +278 -0
  234. nautobot/extras/templates/extras/plugins_list.html +35 -1
  235. nautobot/extras/templates/extras/plugins_tiles.html +79 -0
  236. nautobot/extras/templates/extras/role_retrieve.html +16 -0
  237. nautobot/extras/templates/extras/secret.html +0 -65
  238. nautobot/extras/templates/extras/secret_check.js +16 -0
  239. nautobot/extras/templates/extras/secret_create.html +114 -0
  240. nautobot/extras/templates/extras/secret_edit.html +1 -114
  241. nautobot/extras/templates/extras/secretsgroup_edit.html +1 -1
  242. nautobot/extras/templates/extras/templatetags/plugin_object_detail_tabs.html +2 -0
  243. nautobot/extras/templatetags/job_buttons.py +5 -4
  244. nautobot/extras/templatetags/plugins.py +69 -6
  245. nautobot/extras/test_jobs/api_test_job.py +1 -1
  246. nautobot/extras/test_jobs/atomic_transaction.py +2 -2
  247. nautobot/extras/test_jobs/dry_run.py +1 -1
  248. nautobot/extras/test_jobs/fail.py +5 -5
  249. nautobot/extras/test_jobs/file_output.py +1 -1
  250. nautobot/extras/test_jobs/file_upload_fail.py +1 -1
  251. nautobot/extras/test_jobs/file_upload_pass.py +1 -1
  252. nautobot/extras/test_jobs/ipaddress_vars.py +1 -3
  253. nautobot/extras/test_jobs/jobs_module/jobs_submodule/jobs.py +1 -1
  254. nautobot/extras/test_jobs/location_with_custom_field.py +1 -1
  255. nautobot/extras/test_jobs/log_redaction.py +1 -1
  256. nautobot/extras/test_jobs/log_skip_db_logging.py +1 -1
  257. nautobot/extras/test_jobs/modify_db.py +1 -1
  258. nautobot/extras/test_jobs/object_var_optional.py +1 -1
  259. nautobot/extras/test_jobs/object_var_required.py +1 -1
  260. nautobot/extras/test_jobs/object_vars.py +1 -1
  261. nautobot/extras/test_jobs/pass.py +3 -3
  262. nautobot/extras/test_jobs/profiling.py +1 -1
  263. nautobot/extras/test_jobs/relative_import.py +3 -3
  264. nautobot/extras/test_jobs/soft_time_limit_greater_than_time_limit.py +1 -1
  265. nautobot/extras/test_jobs/task_queues.py +1 -1
  266. nautobot/extras/tests/integration/test_plugin_banner.py +2 -0
  267. nautobot/extras/tests/test_api.py +157 -55
  268. nautobot/extras/tests/test_context_managers.py +4 -1
  269. nautobot/extras/tests/test_customfields.py +1 -1
  270. nautobot/extras/tests/test_datasources.py +1 -2
  271. nautobot/extras/tests/test_dynamicgroups.py +1 -1
  272. nautobot/extras/tests/test_filters.py +219 -535
  273. nautobot/extras/tests/test_forms.py +1 -20
  274. nautobot/extras/tests/test_job_variables.py +73 -152
  275. nautobot/extras/tests/test_jobs.py +43 -54
  276. nautobot/extras/tests/test_models.py +71 -16
  277. nautobot/extras/tests/test_relationships.py +5 -2
  278. nautobot/extras/tests/test_utils.py +23 -2
  279. nautobot/extras/tests/test_views.py +183 -43
  280. nautobot/extras/tests/test_webhooks.py +2 -1
  281. nautobot/extras/urls.py +2 -20
  282. nautobot/extras/utils.py +118 -4
  283. nautobot/extras/views.py +203 -92
  284. nautobot/extras/webhooks.py +5 -2
  285. nautobot/ipam/api/fields.py +3 -3
  286. nautobot/ipam/api/serializers.py +36 -137
  287. nautobot/ipam/api/views.py +93 -62
  288. nautobot/ipam/lookups.py +62 -101
  289. nautobot/ipam/models.py +11 -63
  290. nautobot/ipam/navigation.py +0 -90
  291. nautobot/ipam/querysets.py +2 -2
  292. nautobot/ipam/tables.py +6 -20
  293. nautobot/ipam/templates/ipam/routetarget.html +0 -28
  294. nautobot/ipam/templates/ipam/vrf.html +0 -47
  295. nautobot/ipam/tests/test_api.py +8 -419
  296. nautobot/ipam/tests/test_filters.py +39 -119
  297. nautobot/ipam/tests/test_forms.py +47 -51
  298. nautobot/ipam/tests/test_migrations.py +30 -30
  299. nautobot/ipam/tests/test_models.py +0 -41
  300. nautobot/ipam/tests/test_querysets.py +1 -63
  301. nautobot/ipam/urls.py +3 -69
  302. nautobot/ipam/utils/__init__.py +0 -24
  303. nautobot/ipam/views.py +153 -198
  304. nautobot/project-static/css/base.css +38 -3
  305. nautobot/project-static/docs/404.html +421 -19
  306. nautobot/project-static/docs/apps/index.html +421 -19
  307. nautobot/project-static/docs/apps/nautobot-apps.html +421 -19
  308. nautobot/project-static/docs/assets/extra.css +5 -1
  309. nautobot/project-static/docs/assets/javascripts/{bundle.88dd0f4e.min.js → bundle.83f73b43.min.js} +2 -2
  310. nautobot/project-static/docs/assets/javascripts/{bundle.88dd0f4e.min.js.map → bundle.83f73b43.min.js.map} +2 -2
  311. nautobot/project-static/docs/code-reference/nautobot/apps/__init__.html +421 -19
  312. nautobot/project-static/docs/code-reference/nautobot/apps/admin.html +421 -19
  313. nautobot/project-static/docs/code-reference/nautobot/apps/api.html +421 -172
  314. nautobot/project-static/docs/code-reference/nautobot/apps/change_logging.html +421 -19
  315. nautobot/project-static/docs/code-reference/nautobot/apps/choices.html +421 -19
  316. nautobot/project-static/docs/code-reference/nautobot/apps/config.html +425 -21
  317. nautobot/project-static/docs/code-reference/nautobot/apps/constants.html +421 -19
  318. nautobot/project-static/docs/code-reference/nautobot/apps/datasources.html +424 -22
  319. nautobot/project-static/docs/code-reference/nautobot/apps/events.html +9809 -0
  320. nautobot/project-static/docs/code-reference/nautobot/apps/exceptions.html +424 -63
  321. nautobot/project-static/docs/code-reference/nautobot/apps/factory.html +421 -19
  322. nautobot/project-static/docs/code-reference/nautobot/apps/filters.html +421 -19
  323. nautobot/project-static/docs/code-reference/nautobot/apps/forms.html +457 -20
  324. nautobot/project-static/docs/code-reference/nautobot/apps/graphql.html +421 -19
  325. nautobot/project-static/docs/code-reference/nautobot/apps/jobs.html +425 -25
  326. nautobot/project-static/docs/code-reference/nautobot/apps/models.html +457 -19
  327. nautobot/project-static/docs/code-reference/nautobot/apps/querysets.html +421 -19
  328. nautobot/project-static/docs/code-reference/nautobot/apps/secrets.html +421 -19
  329. nautobot/project-static/docs/code-reference/nautobot/apps/tables.html +425 -215
  330. nautobot/project-static/docs/code-reference/nautobot/apps/testing.html +430 -342
  331. nautobot/project-static/docs/code-reference/nautobot/apps/ui.html +5799 -1054
  332. nautobot/project-static/docs/code-reference/nautobot/apps/urls.html +421 -19
  333. nautobot/project-static/docs/code-reference/nautobot/apps/utils.html +447 -176
  334. nautobot/project-static/docs/code-reference/nautobot/apps/views.html +460 -21
  335. nautobot/project-static/docs/development/apps/api/configuration-view.html +421 -19
  336. nautobot/project-static/docs/development/apps/api/database-backend-config.html +421 -19
  337. nautobot/project-static/docs/development/apps/api/models/django-admin.html +421 -19
  338. nautobot/project-static/docs/development/apps/api/models/global-search.html +421 -19
  339. nautobot/project-static/docs/development/apps/api/models/graphql.html +421 -19
  340. nautobot/project-static/docs/development/apps/api/models/index.html +421 -19
  341. nautobot/project-static/docs/development/apps/api/nautobot-app-config.html +421 -19
  342. nautobot/project-static/docs/development/apps/api/platform-features/custom-validators.html +421 -19
  343. nautobot/project-static/docs/development/apps/api/platform-features/filter-extensions.html +421 -19
  344. nautobot/project-static/docs/development/apps/api/platform-features/git-repository-content.html +421 -19
  345. nautobot/project-static/docs/development/apps/api/platform-features/index.html +421 -19
  346. nautobot/project-static/docs/development/apps/api/platform-features/jinja2-filters.html +421 -19
  347. nautobot/project-static/docs/development/apps/api/platform-features/jobs.html +421 -19
  348. nautobot/project-static/docs/development/apps/api/platform-features/populating-extensibility-features.html +421 -19
  349. nautobot/project-static/docs/development/apps/api/platform-features/secrets-providers.html +421 -19
  350. nautobot/project-static/docs/development/apps/api/platform-features/table-extensions.html +424 -41
  351. nautobot/project-static/docs/development/apps/api/platform-features/uniquely-identify-objects.html +421 -19
  352. nautobot/project-static/docs/development/apps/api/prometheus.html +421 -19
  353. nautobot/project-static/docs/development/apps/api/setup.html +425 -155
  354. nautobot/project-static/docs/development/apps/api/testing.html +421 -19
  355. nautobot/project-static/docs/development/apps/api/ui-extensions/banners.html +421 -19
  356. nautobot/project-static/docs/development/apps/api/ui-extensions/home-page.html +421 -19
  357. nautobot/project-static/docs/development/apps/api/ui-extensions/index.html +421 -19
  358. nautobot/project-static/docs/development/apps/api/ui-extensions/navigation.html +421 -19
  359. nautobot/project-static/docs/development/apps/api/ui-extensions/object-views.html +701 -130
  360. nautobot/project-static/docs/development/apps/api/views/base-template.html +421 -19
  361. nautobot/project-static/docs/development/apps/api/views/core-view-overrides.html +421 -19
  362. nautobot/project-static/docs/development/apps/api/views/django-generic-views.html +421 -19
  363. nautobot/project-static/docs/development/apps/api/views/help-documentation.html +421 -19
  364. nautobot/project-static/docs/development/apps/api/views/index.html +423 -20
  365. nautobot/project-static/docs/development/apps/api/views/nautobot-generic-views.html +425 -19
  366. nautobot/project-static/docs/development/apps/api/views/nautobotuiviewset.html +451 -19
  367. nautobot/project-static/docs/development/apps/api/views/nautobotuiviewsetrouter.html +421 -19
  368. nautobot/project-static/docs/development/apps/api/views/notes.html +421 -19
  369. nautobot/project-static/docs/development/apps/api/views/rest-api.html +421 -19
  370. nautobot/project-static/docs/development/apps/api/views/urls.html +421 -19
  371. nautobot/project-static/docs/development/apps/index.html +421 -19
  372. nautobot/project-static/docs/development/apps/migration/code-updates.html +422 -52
  373. nautobot/project-static/docs/development/apps/migration/dependency-updates.html +422 -20
  374. nautobot/project-static/docs/development/apps/migration/from-v1.html +421 -19
  375. nautobot/project-static/docs/development/apps/migration/model-updates/dcim.html +421 -19
  376. nautobot/project-static/docs/development/apps/migration/model-updates/extras.html +421 -19
  377. nautobot/project-static/docs/development/apps/migration/model-updates/global.html +421 -19
  378. nautobot/project-static/docs/development/apps/migration/model-updates/ipam.html +424 -22
  379. nautobot/project-static/docs/development/apps/migration/ui-component-framework/best-practices.html +9219 -0
  380. nautobot/project-static/docs/development/apps/migration/ui-component-framework/custom-content.html +9333 -0
  381. nautobot/project-static/docs/development/apps/migration/ui-component-framework/index.html +9474 -0
  382. nautobot/project-static/docs/development/apps/migration/ui-component-framework/migration-steps.html +9517 -0
  383. nautobot/project-static/docs/development/apps/porting-from-netbox.html +424 -22
  384. nautobot/project-static/docs/development/core/application-registry.html +421 -19
  385. nautobot/project-static/docs/development/core/best-practices.html +421 -19
  386. nautobot/project-static/docs/development/core/bootstrap-ui.html +421 -19
  387. nautobot/project-static/docs/development/core/caching.html +421 -19
  388. nautobot/project-static/docs/development/core/controllers.html +423 -19
  389. nautobot/project-static/docs/development/core/docker-compose-advanced-use-cases.html +490 -45
  390. nautobot/project-static/docs/development/core/generic-views.html +421 -19
  391. nautobot/project-static/docs/development/core/getting-started.html +566 -179
  392. nautobot/project-static/docs/development/core/homepage.html +432 -30
  393. nautobot/project-static/docs/development/core/index.html +421 -19
  394. nautobot/project-static/docs/development/core/local-k8s.html +9453 -0
  395. nautobot/project-static/docs/development/core/model-checklist.html +424 -22
  396. nautobot/project-static/docs/development/core/model-features.html +421 -19
  397. nautobot/project-static/docs/development/core/natural-keys.html +421 -19
  398. nautobot/project-static/docs/development/core/navigation-menu.html +438 -26
  399. nautobot/project-static/docs/development/core/release-checklist.html +435 -45
  400. nautobot/project-static/docs/development/core/role-internals.html +421 -19
  401. nautobot/project-static/docs/development/core/settings.html +421 -19
  402. nautobot/project-static/docs/development/core/style-guide.html +421 -19
  403. nautobot/project-static/docs/development/core/templates.html +431 -22
  404. nautobot/project-static/docs/development/core/testing.html +421 -19
  405. nautobot/project-static/docs/development/core/ui-component-framework.html +11020 -0
  406. nautobot/project-static/docs/development/core/user-preferences.html +424 -22
  407. nautobot/project-static/docs/development/index.html +421 -19
  408. nautobot/project-static/docs/development/jobs/index.html +546 -160
  409. nautobot/project-static/docs/development/jobs/migration/from-v1.html +421 -19
  410. nautobot/project-static/docs/index.html +421 -19
  411. nautobot/project-static/docs/media/development/core/ui-component-framework/basic-panel-layout.png +0 -0
  412. nautobot/project-static/docs/media/development/core/ui-component-framework/button-example.png +0 -0
  413. nautobot/project-static/docs/media/development/core/ui-component-framework/dropdown-button-example.png +0 -0
  414. nautobot/project-static/docs/media/development/core/ui-component-framework/grouped-key-value-table-panel-example-1.png +0 -0
  415. nautobot/project-static/docs/media/development/core/ui-component-framework/grouped-key-value-table-panel-example-2.png +0 -0
  416. nautobot/project-static/docs/media/development/core/ui-component-framework/object-fields-panel-example.png +0 -0
  417. nautobot/project-static/docs/media/development/core/ui-component-framework/stats-panel-example.png +0 -0
  418. nautobot/project-static/docs/media/development/core/ui-component-framework/table-panels-family.png +0 -0
  419. nautobot/project-static/docs/media/development/core/ui-component-framework/text-panels-family.png +0 -0
  420. nautobot/project-static/docs/media/development/core/ui-component-framework/ui-framework-example.png +0 -0
  421. nautobot/project-static/docs/media/models/virtual_device_context_overview.drawio +73 -0
  422. nautobot/project-static/docs/media/models/virtual_device_context_overview.png +0 -0
  423. nautobot/project-static/docs/models/dcim/virtualdevicecontext.html +14 -0
  424. nautobot/project-static/docs/models/extras/jobqueue.html +14 -0
  425. nautobot/project-static/docs/models/wireless/radioprofile.html +14 -0
  426. nautobot/project-static/docs/models/wireless/supporteddatarate.html +14 -0
  427. nautobot/project-static/docs/models/wireless/wirelessnetwork.html +14 -0
  428. nautobot/project-static/docs/objects.inv +0 -0
  429. nautobot/project-static/docs/overview/application_stack.html +426 -20
  430. nautobot/project-static/docs/overview/design_philosophy.html +421 -19
  431. nautobot/project-static/docs/release-notes/index.html +445 -22
  432. nautobot/project-static/docs/release-notes/version-1.0.html +421 -19
  433. nautobot/project-static/docs/release-notes/version-1.1.html +421 -19
  434. nautobot/project-static/docs/release-notes/version-1.2.html +421 -19
  435. nautobot/project-static/docs/release-notes/version-1.3.html +421 -19
  436. nautobot/project-static/docs/release-notes/version-1.4.html +421 -19
  437. nautobot/project-static/docs/release-notes/version-1.5.html +421 -19
  438. nautobot/project-static/docs/release-notes/version-1.6.html +634 -667
  439. nautobot/project-static/docs/release-notes/version-2.0.html +421 -19
  440. nautobot/project-static/docs/release-notes/version-2.1.html +421 -19
  441. nautobot/project-static/docs/release-notes/version-2.2.html +421 -19
  442. nautobot/project-static/docs/release-notes/version-2.3.html +684 -886
  443. nautobot/project-static/docs/release-notes/version-2.4.html +10007 -0
  444. nautobot/project-static/docs/requirements.txt +2 -2
  445. nautobot/project-static/docs/search/search_index.json +1 -1
  446. nautobot/project-static/docs/sitemap.xml +334 -270
  447. nautobot/project-static/docs/sitemap.xml.gz +0 -0
  448. nautobot/project-static/docs/user-guide/administration/configuration/authentication/ldap.html +421 -19
  449. nautobot/project-static/docs/user-guide/administration/configuration/authentication/remote.html +421 -19
  450. nautobot/project-static/docs/user-guide/administration/configuration/authentication/sso.html +423 -21
  451. nautobot/project-static/docs/user-guide/administration/configuration/index.html +433 -32
  452. nautobot/project-static/docs/user-guide/administration/configuration/redis.html +421 -19
  453. nautobot/project-static/docs/user-guide/administration/configuration/settings.html +765 -180
  454. nautobot/project-static/docs/user-guide/administration/configuration/time-zones.html +421 -19
  455. nautobot/project-static/docs/user-guide/administration/guides/celery-queues.html +421 -19
  456. nautobot/project-static/docs/user-guide/administration/guides/docker.html +434 -29
  457. nautobot/project-static/docs/user-guide/administration/guides/health-checks.html +421 -19
  458. nautobot/project-static/docs/user-guide/administration/guides/permissions.html +421 -19
  459. nautobot/project-static/docs/user-guide/administration/guides/prometheus-metrics.html +421 -19
  460. nautobot/project-static/docs/user-guide/administration/guides/replicating-nautobot.html +421 -19
  461. nautobot/project-static/docs/user-guide/administration/guides/request-profiling.html +421 -19
  462. nautobot/project-static/docs/user-guide/administration/guides/s3-django-storage.html +421 -19
  463. nautobot/project-static/docs/user-guide/administration/guides/selinux-troubleshooting.html +421 -19
  464. nautobot/project-static/docs/user-guide/administration/installation/app-install.html +421 -19
  465. nautobot/project-static/docs/user-guide/administration/installation/external-authentication.html +421 -19
  466. nautobot/project-static/docs/user-guide/administration/installation/http-server.html +421 -19
  467. nautobot/project-static/docs/user-guide/administration/installation/index.html +426 -20
  468. nautobot/project-static/docs/user-guide/administration/installation/install_system.html +421 -19
  469. nautobot/project-static/docs/user-guide/administration/installation/nautobot.html +421 -19
  470. nautobot/project-static/docs/user-guide/administration/installation/services.html +421 -19
  471. nautobot/project-static/docs/user-guide/administration/migration/migrating-from-netbox.html +421 -19
  472. nautobot/project-static/docs/user-guide/administration/migration/migrating-from-postgresql.html +442 -41
  473. nautobot/project-static/docs/user-guide/administration/tools/nautobot-server.html +435 -66
  474. nautobot/project-static/docs/user-guide/administration/tools/nautobot-shell.html +435 -66
  475. nautobot/project-static/docs/user-guide/administration/upgrading/database-backup.html +421 -19
  476. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/after-you-upgrade.html +421 -19
  477. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/before-you-upgrade.html +421 -19
  478. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/for-developers.html +421 -19
  479. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/index.html +421 -19
  480. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/whats-changed.html +421 -19
  481. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/region-and-site-data-migration-guide.html +421 -19
  482. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/tables/v2-code-nautobot-app-location.yaml +0 -16
  483. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/upgrading-from-nautobot-v1.html +421 -19
  484. nautobot/project-static/docs/user-guide/administration/upgrading/upgrading.html +427 -21
  485. nautobot/project-static/docs/user-guide/core-data-model/circuits/circuit.html +421 -19
  486. nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittermination.html +421 -19
  487. nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittype.html +421 -19
  488. nautobot/project-static/docs/user-guide/core-data-model/circuits/provider.html +421 -19
  489. nautobot/project-static/docs/user-guide/core-data-model/circuits/providernetwork.html +421 -19
  490. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloud.html +421 -19
  491. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudaccount.html +421 -19
  492. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudnetwork.html +421 -19
  493. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudnetworkprefixassignment.html +421 -19
  494. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudresourcetype.html +421 -19
  495. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudservice.html +421 -19
  496. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudservicenetworkassignment.html +421 -19
  497. nautobot/project-static/docs/user-guide/core-data-model/dcim/cable.html +421 -19
  498. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleport.html +421 -19
  499. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleporttemplate.html +421 -19
  500. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverport.html +421 -19
  501. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverporttemplate.html +421 -19
  502. nautobot/project-static/docs/user-guide/core-data-model/dcim/controller.html +457 -20
  503. nautobot/project-static/docs/user-guide/core-data-model/dcim/controllermanageddevicegroup.html +447 -22
  504. nautobot/project-static/docs/user-guide/core-data-model/dcim/device.html +421 -19
  505. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebay.html +421 -19
  506. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebaytemplate.html +421 -19
  507. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicefamily.html +421 -19
  508. nautobot/project-static/docs/user-guide/core-data-model/dcim/deviceredundancygroup.html +421 -19
  509. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicetype.html +421 -19
  510. nautobot/project-static/docs/user-guide/core-data-model/dcim/frontport.html +421 -19
  511. nautobot/project-static/docs/user-guide/core-data-model/dcim/frontporttemplate.html +421 -19
  512. nautobot/project-static/docs/user-guide/core-data-model/dcim/interface.html +421 -19
  513. nautobot/project-static/docs/user-guide/core-data-model/dcim/interfaceredundancygroup.html +421 -19
  514. nautobot/project-static/docs/user-guide/core-data-model/dcim/interfacetemplate.html +421 -19
  515. nautobot/project-static/docs/user-guide/core-data-model/dcim/inventoryitem.html +421 -19
  516. nautobot/project-static/docs/user-guide/core-data-model/dcim/location.html +421 -19
  517. nautobot/project-static/docs/user-guide/core-data-model/dcim/locationtype.html +421 -19
  518. nautobot/project-static/docs/user-guide/core-data-model/dcim/manufacturer.html +421 -19
  519. nautobot/project-static/docs/user-guide/core-data-model/dcim/module.html +421 -19
  520. nautobot/project-static/docs/user-guide/core-data-model/dcim/modulebay.html +421 -19
  521. nautobot/project-static/docs/user-guide/core-data-model/dcim/modulebaytemplate.html +421 -19
  522. nautobot/project-static/docs/user-guide/core-data-model/dcim/moduletype.html +421 -19
  523. nautobot/project-static/docs/user-guide/core-data-model/dcim/platform.html +421 -19
  524. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerfeed.html +421 -19
  525. nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlet.html +421 -19
  526. nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlettemplate.html +421 -19
  527. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerpanel.html +421 -19
  528. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerport.html +421 -19
  529. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerporttemplate.html +421 -19
  530. nautobot/project-static/docs/user-guide/core-data-model/dcim/rack.html +421 -19
  531. nautobot/project-static/docs/user-guide/core-data-model/dcim/rackgroup.html +421 -19
  532. nautobot/project-static/docs/user-guide/core-data-model/dcim/rackreservation.html +421 -19
  533. nautobot/project-static/docs/user-guide/core-data-model/dcim/rearport.html +421 -19
  534. nautobot/project-static/docs/user-guide/core-data-model/dcim/rearporttemplate.html +421 -19
  535. nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareimagefile.html +421 -19
  536. nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareversion.html +421 -19
  537. nautobot/project-static/docs/user-guide/core-data-model/dcim/virtualchassis.html +421 -19
  538. nautobot/project-static/docs/user-guide/core-data-model/dcim/virtualdevicecontext.html +9333 -0
  539. nautobot/project-static/docs/user-guide/core-data-model/extras/configcontext.html +424 -22
  540. nautobot/project-static/docs/user-guide/core-data-model/extras/configcontextschema.html +421 -19
  541. nautobot/project-static/docs/user-guide/core-data-model/extras/contact.html +421 -19
  542. nautobot/project-static/docs/user-guide/core-data-model/extras/team.html +421 -19
  543. nautobot/project-static/docs/user-guide/core-data-model/ipam/ipaddress.html +421 -19
  544. nautobot/project-static/docs/user-guide/core-data-model/ipam/namespace.html +421 -19
  545. nautobot/project-static/docs/user-guide/core-data-model/ipam/prefix.html +421 -19
  546. nautobot/project-static/docs/user-guide/core-data-model/ipam/rir.html +421 -19
  547. nautobot/project-static/docs/user-guide/core-data-model/ipam/routetarget.html +421 -19
  548. nautobot/project-static/docs/user-guide/core-data-model/ipam/service.html +421 -19
  549. nautobot/project-static/docs/user-guide/core-data-model/ipam/vlan.html +421 -19
  550. nautobot/project-static/docs/user-guide/core-data-model/ipam/vlangroup.html +421 -19
  551. nautobot/project-static/docs/user-guide/core-data-model/ipam/vrf.html +421 -19
  552. nautobot/project-static/docs/user-guide/core-data-model/overview/introduction.html +421 -19
  553. nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenant.html +421 -19
  554. nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenantgroup.html +421 -19
  555. nautobot/project-static/docs/user-guide/core-data-model/virtualization/cluster.html +421 -19
  556. nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustergroup.html +421 -19
  557. nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustertype.html +421 -19
  558. nautobot/project-static/docs/user-guide/core-data-model/virtualization/virtualmachine.html +421 -19
  559. nautobot/project-static/docs/user-guide/core-data-model/virtualization/vminterface.html +424 -22
  560. nautobot/project-static/docs/user-guide/core-data-model/wireless/index.html +9271 -0
  561. nautobot/project-static/docs/user-guide/core-data-model/wireless/radioprofile.html +9175 -0
  562. nautobot/project-static/docs/user-guide/core-data-model/wireless/supporteddatarate.html +9169 -0
  563. nautobot/project-static/docs/user-guide/core-data-model/wireless/wirelessnetwork.html +9235 -0
  564. nautobot/project-static/docs/user-guide/feature-guides/contacts-and-teams.html +421 -19
  565. nautobot/project-static/docs/user-guide/feature-guides/custom-fields.html +421 -19
  566. nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-devices.html +421 -19
  567. nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-location-types-and-locations.html +421 -19
  568. nautobot/project-static/docs/user-guide/feature-guides/getting-started/index.html +421 -19
  569. nautobot/project-static/docs/user-guide/feature-guides/getting-started/interfaces.html +421 -19
  570. nautobot/project-static/docs/user-guide/feature-guides/getting-started/ipam.html +421 -19
  571. nautobot/project-static/docs/user-guide/feature-guides/getting-started/platforms.html +421 -19
  572. nautobot/project-static/docs/user-guide/feature-guides/getting-started/search-bar.html +421 -19
  573. nautobot/project-static/docs/user-guide/feature-guides/getting-started/tenants.html +421 -19
  574. nautobot/project-static/docs/user-guide/feature-guides/getting-started/vlans-and-vlan-groups.html +421 -19
  575. nautobot/project-static/docs/user-guide/feature-guides/git-data-source.html +421 -19
  576. nautobot/project-static/docs/user-guide/feature-guides/graphql.html +421 -19
  577. nautobot/project-static/docs/user-guide/feature-guides/ip-address-merge-tool.html +421 -19
  578. nautobot/project-static/docs/user-guide/feature-guides/relationships.html +421 -19
  579. nautobot/project-static/docs/user-guide/feature-guides/software-image-files-and-versions.html +421 -19
  580. nautobot/project-static/docs/user-guide/index.html +421 -19
  581. nautobot/project-static/docs/user-guide/platform-functionality/change-logging.html +424 -22
  582. nautobot/project-static/docs/user-guide/platform-functionality/computedfield.html +421 -19
  583. nautobot/project-static/docs/user-guide/platform-functionality/customfield.html +421 -19
  584. nautobot/project-static/docs/user-guide/platform-functionality/customlink.html +421 -19
  585. nautobot/project-static/docs/user-guide/platform-functionality/dynamicgroup.html +421 -19
  586. nautobot/project-static/docs/user-guide/platform-functionality/events.html +9575 -0
  587. nautobot/project-static/docs/user-guide/platform-functionality/exporttemplate.html +424 -22
  588. nautobot/project-static/docs/user-guide/platform-functionality/externalintegration.html +421 -19
  589. nautobot/project-static/docs/user-guide/platform-functionality/gitrepository.html +421 -19
  590. nautobot/project-static/docs/user-guide/platform-functionality/graphql.html +421 -19
  591. nautobot/project-static/docs/user-guide/platform-functionality/graphqlquery.html +421 -19
  592. nautobot/project-static/docs/user-guide/platform-functionality/imageattachment.html +421 -19
  593. nautobot/project-static/docs/user-guide/platform-functionality/jobs/index.html +426 -20
  594. nautobot/project-static/docs/user-guide/platform-functionality/jobs/job-scheduling-and-approvals.html +424 -22
  595. nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobbutton.html +421 -19
  596. nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobhook.html +421 -19
  597. nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobqueue.html +9182 -0
  598. nautobot/project-static/docs/user-guide/platform-functionality/jobs/models.html +424 -22
  599. nautobot/project-static/docs/user-guide/platform-functionality/napalm.html +421 -19
  600. nautobot/project-static/docs/user-guide/platform-functionality/note.html +421 -19
  601. nautobot/project-static/docs/user-guide/platform-functionality/objectmetadata.html +421 -19
  602. nautobot/project-static/docs/user-guide/platform-functionality/relationship.html +424 -22
  603. nautobot/project-static/docs/user-guide/platform-functionality/rendering-jinja-templates.html +9250 -0
  604. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/authentication.html +421 -19
  605. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/filtering.html +421 -19
  606. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/overview.html +424 -22
  607. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/ui-related-endpoints.html +421 -19
  608. nautobot/project-static/docs/user-guide/platform-functionality/role.html +421 -19
  609. nautobot/project-static/docs/user-guide/platform-functionality/savedview.html +421 -19
  610. nautobot/project-static/docs/user-guide/platform-functionality/secret.html +421 -19
  611. nautobot/project-static/docs/user-guide/platform-functionality/staticgroupassociation.html +424 -22
  612. nautobot/project-static/docs/user-guide/platform-functionality/status.html +421 -19
  613. nautobot/project-static/docs/user-guide/platform-functionality/tag.html +421 -19
  614. nautobot/project-static/docs/user-guide/platform-functionality/template-filters.html +489 -56
  615. nautobot/project-static/docs/user-guide/platform-functionality/users/objectpermission.html +421 -19
  616. nautobot/project-static/docs/user-guide/platform-functionality/users/token.html +421 -19
  617. nautobot/project-static/docs/user-guide/platform-functionality/webhook.html +421 -19
  618. nautobot/project-static/img/jinja_logo.svg +97 -0
  619. nautobot/project-static/js/forms.js +5 -0
  620. nautobot/project-static/js/nav_menu.js +2 -1
  621. nautobot/tenancy/api/serializers.py +0 -2
  622. nautobot/tenancy/factory.py +1 -1
  623. nautobot/tenancy/navigation.py +0 -29
  624. nautobot/tenancy/templates/tenancy/tenant.html +4 -91
  625. nautobot/tenancy/tests/test_filters.py +29 -134
  626. nautobot/tenancy/views.py +32 -23
  627. nautobot/users/admin.py +3 -1
  628. nautobot/users/api/serializers.py +4 -5
  629. nautobot/users/api/views.py +1 -1
  630. nautobot/users/forms.py +19 -0
  631. nautobot/users/templates/users/preferences.html +22 -0
  632. nautobot/users/tests/test_filters.py +1 -19
  633. nautobot/users/tests/test_views.py +57 -0
  634. nautobot/users/utils.py +8 -0
  635. nautobot/users/views.py +48 -11
  636. nautobot/virtualization/api/serializers.py +4 -4
  637. nautobot/virtualization/filters.py +2 -20
  638. nautobot/virtualization/navigation.py +0 -48
  639. nautobot/virtualization/templates/virtualization/clustertype.html +0 -39
  640. nautobot/virtualization/tests/test_filters.py +57 -183
  641. nautobot/virtualization/views.py +18 -15
  642. nautobot/wireless/__init__.py +0 -0
  643. nautobot/wireless/api/__init__.py +0 -0
  644. nautobot/wireless/api/serializers.py +44 -0
  645. nautobot/wireless/api/urls.py +20 -0
  646. nautobot/wireless/api/views.py +34 -0
  647. nautobot/wireless/apps.py +8 -0
  648. nautobot/wireless/choices.py +345 -0
  649. nautobot/wireless/factory.py +138 -0
  650. nautobot/wireless/filters.py +167 -0
  651. nautobot/wireless/forms.py +283 -0
  652. nautobot/wireless/homepage.py +19 -0
  653. nautobot/wireless/migrations/0001_initial.py +223 -0
  654. nautobot/wireless/migrations/__init__.py +0 -0
  655. nautobot/wireless/models.py +207 -0
  656. nautobot/wireless/navigation.py +105 -0
  657. nautobot/wireless/tables.py +244 -0
  658. nautobot/wireless/templates/wireless/radioprofile_retrieve.html +81 -0
  659. nautobot/wireless/templates/wireless/supporteddatarate_retrieve.html +26 -0
  660. nautobot/wireless/templates/wireless/wirelessnetwork_create.html +88 -0
  661. nautobot/wireless/templates/wireless/wirelessnetwork_retrieve.html +64 -0
  662. nautobot/wireless/tests/__init__.py +0 -0
  663. nautobot/wireless/tests/test_api.py +247 -0
  664. nautobot/wireless/tests/test_filters.py +54 -0
  665. nautobot/wireless/tests/test_models.py +22 -0
  666. nautobot/wireless/tests/test_views.py +378 -0
  667. nautobot/wireless/urls.py +13 -0
  668. nautobot/wireless/views.py +129 -0
  669. {nautobot-2.3.16.dist-info → nautobot-2.4.0b1.dist-info}/METADATA +11 -14
  670. {nautobot-2.3.16.dist-info → nautobot-2.4.0b1.dist-info}/RECORD +674 -551
  671. {nautobot-2.3.16.dist-info → nautobot-2.4.0b1.dist-info}/WHEEL +1 -1
  672. nautobot/core/utils/navigation.py +0 -54
  673. {nautobot-2.3.16.dist-info → nautobot-2.4.0b1.dist-info}/LICENSE.txt +0 -0
  674. {nautobot-2.3.16.dist-info → nautobot-2.4.0b1.dist-info}/NOTICE +0 -0
  675. {nautobot-2.3.16.dist-info → nautobot-2.4.0b1.dist-info}/entry_points.txt +0 -0
@@ -66,6 +66,8 @@ from nautobot.extras.models import (
66
66
  JobButton,
67
67
  JobHook,
68
68
  JobLogEntry,
69
+ JobQueue,
70
+ JobQueueAssignment,
69
71
  JobResult,
70
72
  MetadataChoice,
71
73
  MetadataType,
@@ -212,13 +214,13 @@ class ContactSerializer(NautobotModelSerializer):
212
214
  "phone": {"default": ""},
213
215
  }
214
216
 
215
- def validate(self, attrs):
216
- local_attrs = attrs.copy()
217
- local_attrs.pop("teams", None)
217
+ def validate(self, data):
218
+ attrs = data.copy()
219
+ attrs.pop("teams", None)
218
220
  validator = UniqueTogetherValidator(queryset=Contact.objects.all(), fields=("name", "phone", "email"))
219
- validator(local_attrs, self)
220
- super().validate(local_attrs)
221
- return attrs
221
+ validator(attrs, self)
222
+ super().validate(attrs)
223
+ return data
222
224
 
223
225
 
224
226
  class ContactAssociationSerializer(NautobotModelSerializer):
@@ -233,18 +235,18 @@ class ContactAssociationSerializer(NautobotModelSerializer):
233
235
  "team": {"required": False},
234
236
  }
235
237
 
236
- def validate(self, attrs):
238
+ def validate(self, data):
237
239
  # Validate uniqueness of (associated object, associated object type, contact/team, role)
238
240
  unique_together_fields = None
239
241
 
240
- if attrs.get("contact") and attrs.get("role"):
242
+ if data.get("contact") and data.get("role"):
241
243
  unique_together_fields = (
242
244
  "associated_object_type",
243
245
  "associated_object_id",
244
246
  "contact",
245
247
  "role",
246
248
  )
247
- elif attrs.get("team") and attrs.get("role"):
249
+ elif data.get("team") and data.get("role"):
248
250
  unique_together_fields = (
249
251
  "associated_object_type",
250
252
  "associated_object_id",
@@ -257,11 +259,11 @@ class ContactAssociationSerializer(NautobotModelSerializer):
257
259
  queryset=ContactAssociation.objects.all(),
258
260
  fields=unique_together_fields,
259
261
  )
260
- validator(attrs, self)
262
+ validator(data, self)
261
263
 
262
- super().validate(attrs)
264
+ super().validate(data)
263
265
 
264
- return attrs
266
+ return data
265
267
 
266
268
 
267
269
  #
@@ -270,7 +272,6 @@ class ContactAssociationSerializer(NautobotModelSerializer):
270
272
 
271
273
 
272
274
  class ContentTypeSerializer(BaseModelSerializer):
273
- id = serializers.IntegerField(read_only=True)
274
275
  url = serializers.HyperlinkedIdentityField(view_name="extras-api:contenttype-detail")
275
276
  display = serializers.SerializerMethodField()
276
277
 
@@ -279,8 +280,8 @@ class ContentTypeSerializer(BaseModelSerializer):
279
280
  fields = "__all__"
280
281
 
281
282
  @extend_schema_field(serializers.CharField)
282
- def get_display(self, instance):
283
- return instance.app_labeled_name
283
+ def get_display(self, obj):
284
+ return obj.app_labeled_name
284
285
 
285
286
 
286
287
  #
@@ -501,17 +502,17 @@ class ImageAttachmentSerializer(ValidatedModelSerializer):
501
502
  model = ImageAttachment
502
503
  fields = "__all__"
503
504
 
504
- def validate(self, attrs):
505
+ def validate(self, data):
505
506
  # Validate that the parent object exists
506
507
  try:
507
- attrs["content_type"].get_object_for_this_type(id=attrs["object_id"])
508
+ data["content_type"].get_object_for_this_type(id=data["object_id"])
508
509
  except ObjectDoesNotExist:
509
- raise serializers.ValidationError(f"Invalid parent object: {attrs['content_type']} ID {attrs['object_id']}")
510
+ raise serializers.ValidationError(f"Invalid parent object: {data['content_type']} ID {data['object_id']}")
510
511
 
511
512
  # Enforce model validation
512
- super().validate(attrs)
513
+ super().validate(data)
513
514
 
514
- return attrs
515
+ return data
515
516
 
516
517
  @extend_schema_field(
517
518
  PolymorphicProxySerializer(
@@ -535,28 +536,44 @@ class ImageAttachmentSerializer(ValidatedModelSerializer):
535
536
 
536
537
 
537
538
  class JobSerializer(NautobotModelSerializer, TaggedModelSerializerMixin):
539
+ # task_queues and task_queues_override are added to maintain backward compatibility with versions pre v2.4.
540
+ task_queues = serializers.JSONField(read_only=True, required=False)
541
+ task_queues_override = serializers.BooleanField(read_only=True, required=False)
542
+
538
543
  class Meta:
539
544
  model = Job
540
545
  fields = "__all__"
541
546
 
542
- def validate(self, attrs):
547
+ def validate(self, data):
543
548
  # note no validation for on creation of jobs because we do not support user creation of Job records via API
544
549
  if self.instance:
545
- has_sensitive_variables = attrs.get("has_sensitive_variables", self.instance.has_sensitive_variables)
546
- approval_required = attrs.get("approval_required", self.instance.approval_required)
550
+ has_sensitive_variables = data.get("has_sensitive_variables", self.instance.has_sensitive_variables)
551
+ approval_required = data.get("approval_required", self.instance.approval_required)
547
552
 
548
553
  if approval_required and has_sensitive_variables:
549
554
  error_message = "A job with sensitive variables cannot also be marked as requiring approval"
550
555
  errors = {}
551
556
 
552
- if "approval_required" in attrs:
557
+ if "approval_required" in data:
553
558
  errors["approval_required"] = [error_message]
554
- if "has_sensitive_variables" in attrs:
559
+ if "has_sensitive_variables" in data:
555
560
  errors["has_sensitive_variables"] = [error_message]
556
561
 
557
562
  raise serializers.ValidationError(errors)
558
563
 
559
- return super().validate(attrs)
564
+ return super().validate(data)
565
+
566
+
567
+ class JobQueueSerializer(NautobotModelSerializer, TaggedModelSerializerMixin):
568
+ class Meta:
569
+ model = JobQueue
570
+ fields = "__all__"
571
+
572
+
573
+ class JobQueueAssignmentSerializer(ValidatedModelSerializer):
574
+ class Meta:
575
+ model = JobQueueAssignment
576
+ fields = "__all__"
560
577
 
561
578
 
562
579
  class JobVariableSerializer(serializers.Serializer):
@@ -583,6 +600,8 @@ class JobVariableSerializer(serializers.Serializer):
583
600
 
584
601
  class ScheduledJobSerializer(BaseModelSerializer):
585
602
  # start_time = serializers.DateTimeField(format=None, required=False)
603
+ # queue is added to maintain backward compatibility with versions pre v2.4.
604
+ queue = serializers.CharField(read_only=True, required=False)
586
605
  time_zone = TimeZoneSerializerField(required=False)
587
606
 
588
607
  class Meta:
@@ -668,22 +687,22 @@ class JobHookSerializer(NautobotModelSerializer):
668
687
  model = JobHook
669
688
  fields = "__all__"
670
689
 
671
- def validate(self, attrs):
672
- validated_attrs = super().validate(attrs)
690
+ def validate(self, data):
691
+ validated_data = super().validate(data)
673
692
 
674
693
  conflicts = JobHook.check_for_conflicts(
675
694
  instance=self.instance,
676
- content_types=attrs.get("content_types"),
677
- job=attrs.get("job"),
678
- type_create=attrs.get("type_create"),
679
- type_update=attrs.get("type_update"),
680
- type_delete=attrs.get("type_delete"),
695
+ content_types=data.get("content_types"),
696
+ job=data.get("job"),
697
+ type_create=data.get("type_create"),
698
+ type_update=data.get("type_update"),
699
+ type_delete=data.get("type_delete"),
681
700
  )
682
701
 
683
702
  if conflicts:
684
703
  raise serializers.ValidationError(conflicts)
685
704
 
686
- return validated_attrs
705
+ return validated_data
687
706
 
688
707
 
689
708
  class JobCreationSerializer(BaseModelSerializer):
@@ -702,15 +721,15 @@ class JobCreationSerializer(BaseModelSerializer):
702
721
  model = ScheduledJob
703
722
  fields = ["url", "name", "start_time", "interval", "crontab"]
704
723
 
705
- def validate(self, attrs):
706
- attrs = super().validate(attrs)
724
+ def validate(self, data):
725
+ data = super().validate(data)
707
726
 
708
- if attrs["interval"] in choices.JobExecutionType.SCHEDULE_CHOICES:
709
- if "name" not in attrs:
727
+ if data["interval"] in choices.JobExecutionType.SCHEDULE_CHOICES:
728
+ if "name" not in data:
710
729
  raise serializers.ValidationError({"name": "Please provide a name for the job schedule."})
711
730
 
712
- if ("start_time" not in attrs and attrs["interval"] != choices.JobExecutionType.TYPE_CUSTOM) or (
713
- "start_time" in attrs and attrs["start_time"] < models.ScheduledJob.earliest_possible_time()
731
+ if ("start_time" not in data and data["interval"] != choices.JobExecutionType.TYPE_CUSTOM) or (
732
+ "start_time" in data and data["start_time"] < models.ScheduledJob.earliest_possible_time()
714
733
  ):
715
734
  raise serializers.ValidationError(
716
735
  {
@@ -718,21 +737,22 @@ class JobCreationSerializer(BaseModelSerializer):
718
737
  }
719
738
  )
720
739
 
721
- if attrs["interval"] == choices.JobExecutionType.TYPE_CUSTOM:
722
- if attrs.get("crontab") is None:
740
+ if data["interval"] == choices.JobExecutionType.TYPE_CUSTOM:
741
+ if data.get("crontab") is None:
723
742
  raise serializers.ValidationError({"crontab": "Please enter a valid crontab."})
724
743
  try:
725
- models.ScheduledJob.get_crontab(attrs["crontab"])
744
+ models.ScheduledJob.get_crontab(data["crontab"])
726
745
  except Exception as e:
727
746
  raise serializers.ValidationError({"crontab": e})
728
747
 
729
- return attrs
748
+ return data
730
749
 
731
750
 
732
751
  class JobInputSerializer(serializers.Serializer):
733
752
  data = serializers.JSONField(required=False, default=dict)
734
753
  schedule = JobCreationSerializer(required=False)
735
754
  task_queue = serializers.CharField(required=False, allow_blank=True)
755
+ job_queue = serializers.CharField(required=False, allow_blank=True)
736
756
 
737
757
 
738
758
  class JobMultiPartInputSerializer(serializers.Serializer):
@@ -743,19 +763,17 @@ class JobMultiPartInputSerializer(serializers.Serializer):
743
763
  _schedule_interval = ChoiceField(choices=JobExecutionType, required=False)
744
764
  _schedule_crontab = serializers.CharField(required=False, allow_blank=True)
745
765
  _task_queue = serializers.CharField(required=False, allow_blank=True)
766
+ _job_queue = serializers.CharField(required=False, allow_blank=True)
746
767
 
747
- def validate(self, attrs):
748
- attrs = super().validate(attrs)
768
+ def validate(self, data):
769
+ data = super().validate(data)
749
770
 
750
- if "_schedule_interval" in attrs and attrs["_schedule_interval"] != JobExecutionType.TYPE_IMMEDIATELY:
751
- if "_schedule_name" not in attrs:
771
+ if "_schedule_interval" in data and data["_schedule_interval"] != JobExecutionType.TYPE_IMMEDIATELY:
772
+ if "_schedule_name" not in data:
752
773
  raise serializers.ValidationError({"_schedule_name": "Please provide a name for the job schedule."})
753
774
 
754
- if (
755
- "_schedule_start_time" not in attrs and attrs["_schedule_interval"] != JobExecutionType.TYPE_CUSTOM
756
- ) or (
757
- "_schedule_start_time" in attrs
758
- and attrs["_schedule_start_time"] < ScheduledJob.earliest_possible_time()
775
+ if ("_schedule_start_time" not in data and data["_schedule_interval"] != JobExecutionType.TYPE_CUSTOM) or (
776
+ "_schedule_start_time" in data and data["_schedule_start_time"] < ScheduledJob.earliest_possible_time()
759
777
  ):
760
778
  raise serializers.ValidationError(
761
779
  {
@@ -763,15 +781,15 @@ class JobMultiPartInputSerializer(serializers.Serializer):
763
781
  }
764
782
  )
765
783
 
766
- if attrs["_schedule_interval"] == JobExecutionType.TYPE_CUSTOM:
767
- if attrs.get("_schedule_crontab") is None:
784
+ if data["_schedule_interval"] == JobExecutionType.TYPE_CUSTOM:
785
+ if data.get("_schedule_crontab") is None:
768
786
  raise serializers.ValidationError({"_schedule_crontab": "Please enter a valid crontab."})
769
787
  try:
770
- ScheduledJob.get_crontab(attrs["_schedule_crontab"])
788
+ ScheduledJob.get_crontab(data["_schedule_crontab"])
771
789
  except Exception as e:
772
790
  raise serializers.ValidationError({"_schedule_crontab": e})
773
791
 
774
- return attrs
792
+ return data
775
793
 
776
794
 
777
795
  class JobLogEntrySerializer(BaseModelSerializer):
@@ -862,7 +880,6 @@ class NoteSerializer(BaseModelSerializer):
862
880
  class Meta:
863
881
  model = Note
864
882
  fields = "__all__"
865
- list_display_fields = ["note", "assigned_object_type", "assigned_object_id", "user"]
866
883
 
867
884
  @extend_schema_field(
868
885
  PolymorphicProxySerializer(
@@ -902,7 +919,6 @@ class ObjectChangeSerializer(BaseModelSerializer):
902
919
  class Meta:
903
920
  model = ObjectChange
904
921
  fields = "__all__"
905
- list_display_fields = ["changed_object_id", "related_object_id", "related_object_type", "user"]
906
922
 
907
923
  @extend_schema_field(
908
924
  PolymorphicProxySerializer(
@@ -1057,18 +1073,18 @@ class TagSerializer(NautobotModelSerializer):
1057
1073
  "color": {"help_text": "RGB color in hexadecimal (e.g. 00ff00)"},
1058
1074
  }
1059
1075
 
1060
- def validate(self, attrs):
1061
- attrs = super().validate(attrs)
1076
+ def validate(self, data):
1077
+ data = super().validate(data)
1062
1078
 
1063
1079
  # check if tag is assigned to any of the removed content_types
1064
- if self.instance is not None and self.instance.present_in_database and "content_types" in attrs:
1065
- content_types_id = [content_type.id for content_type in attrs["content_types"]]
1080
+ if self.instance is not None and self.instance.present_in_database and "content_types" in data:
1081
+ content_types_id = [content_type.id for content_type in data["content_types"]]
1066
1082
  errors = self.instance.validate_content_types_removal(content_types_id)
1067
1083
 
1068
1084
  if errors:
1069
1085
  raise serializers.ValidationError(errors)
1070
1086
 
1071
- return attrs
1087
+ return data
1072
1088
 
1073
1089
 
1074
1090
  #
@@ -1090,10 +1106,10 @@ class TeamSerializer(NautobotModelSerializer):
1090
1106
  # https://www.django-rest-framework.org/api-guide/validators/#optional-fields
1091
1107
  validators = []
1092
1108
 
1093
- def validate(self, attrs):
1109
+ def validate(self, data):
1094
1110
  validator = UniqueTogetherValidator(queryset=Team.objects.all(), fields=("name", "phone", "email"))
1095
- validator(attrs, self)
1096
- return super().validate(attrs)
1111
+ validator(data, self)
1112
+ return super().validate(data)
1097
1113
 
1098
1114
 
1099
1115
  #
@@ -1111,19 +1127,19 @@ class WebhookSerializer(ValidatedModelSerializer, NotesSerializerMixin):
1111
1127
  model = Webhook
1112
1128
  fields = "__all__"
1113
1129
 
1114
- def validate(self, attrs):
1115
- validated_attrs = super().validate(attrs)
1130
+ def validate(self, data):
1131
+ validated_data = super().validate(data)
1116
1132
 
1117
1133
  conflicts = Webhook.check_for_conflicts(
1118
1134
  instance=self.instance,
1119
- content_types=attrs.get("content_types"),
1120
- payload_url=attrs.get("payload_url"),
1121
- type_create=attrs.get("type_create"),
1122
- type_update=attrs.get("type_update"),
1123
- type_delete=attrs.get("type_delete"),
1135
+ content_types=data.get("content_types"),
1136
+ payload_url=data.get("payload_url"),
1137
+ type_create=data.get("type_create"),
1138
+ type_update=data.get("type_update"),
1139
+ type_delete=data.get("type_delete"),
1124
1140
  )
1125
1141
 
1126
1142
  if conflicts:
1127
1143
  raise serializers.ValidationError(conflicts)
1128
1144
 
1129
- return validated_attrs
1145
+ return validated_data
@@ -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
 
@@ -17,7 +17,6 @@ from rest_framework.permissions import IsAuthenticated
17
17
  from rest_framework.response import Response
18
18
 
19
19
  from nautobot.core.api.authentication import TokenPermissions
20
- from nautobot.core.api.parsers import NautobotCSVParser
21
20
  from nautobot.core.api.utils import get_serializer_for_model
22
21
  from nautobot.core.api.views import (
23
22
  BulkDestroyModelMixin,
@@ -27,11 +26,13 @@ from nautobot.core.api.views import (
27
26
  NautobotAPIVersionMixin,
28
27
  ReadOnlyModelViewSet,
29
28
  )
29
+ from nautobot.core.events import publish_event
30
30
  from nautobot.core.exceptions import CeleryWorkerNotRunningException
31
31
  from nautobot.core.graphql import execute_saved_query
32
32
  from nautobot.core.models.querysets import count_related
33
+ from nautobot.core.models.utils import serialize_object_v2
33
34
  from nautobot.extras import filters
34
- from nautobot.extras.choices import JobExecutionType
35
+ from nautobot.extras.choices import JobExecutionType, JobQueueTypeChoices
35
36
  from nautobot.extras.filters import RoleFilterSet
36
37
  from nautobot.extras.jobs import get_job
37
38
  from nautobot.extras.models import (
@@ -55,6 +56,8 @@ from nautobot.extras.models import (
55
56
  JobButton,
56
57
  JobHook,
57
58
  JobLogEntry,
59
+ JobQueue,
60
+ JobQueueAssignment,
58
61
  JobResult,
59
62
  MetadataChoice,
60
63
  MetadataType,
@@ -78,7 +81,7 @@ from nautobot.extras.models import (
78
81
  Webhook,
79
82
  )
80
83
  from nautobot.extras.secrets.exceptions import SecretError
81
- from nautobot.extras.utils import get_worker_count
84
+ from nautobot.extras.utils import get_job_queue, get_worker_count
82
85
 
83
86
  from . import serializers
84
87
 
@@ -485,7 +488,6 @@ class ImageAttachmentViewSet(ModelViewSet):
485
488
  queryset = ImageAttachment.objects.all()
486
489
  serializer_class = serializers.ImageAttachmentSerializer
487
490
  filterset_class = filters.ImageAttachmentFilterSet
488
- parser_classes = [JSONParser, NautobotCSVParser, MultiPartParser]
489
491
 
490
492
 
491
493
  #
@@ -601,9 +603,8 @@ class JobViewSetBase(
601
603
  )
602
604
 
603
605
  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]
606
+ # default queue should be specified on the default_job_queue.
607
+ default_valid_queue = job_model.default_job_queue.name
607
608
 
608
609
  # We need to call request.data for both cases as this is what pulls and caches the request data
609
610
  data = request.data
@@ -624,7 +625,23 @@ class JobViewSetBase(
624
625
  input_serializer = serializers.JobMultiPartInputSerializer(data=data, context={"request": request})
625
626
  input_serializer.is_valid(raise_exception=True)
626
627
 
627
- task_queue = input_serializer.validated_data.get("_task_queue", default_valid_queue)
628
+ # TODO remove _task_queue related code in 3.0
629
+ # _task_queue and _job_queue are both valid arguments in v2.4
630
+ task_queue = input_serializer.validated_data.get(
631
+ "_task_queue", None
632
+ ) or input_serializer.validated_data.get("_job_queue", None)
633
+ if not task_queue:
634
+ task_queue = default_valid_queue
635
+
636
+ # Log a warning if _task_queue and _job_queue fields are both specified out
637
+ if input_serializer.validated_data.get("_task_queue", None) and input_serializer.validated_data.get(
638
+ "_job_queue", None
639
+ ):
640
+ raise ValidationError(
641
+ {
642
+ "_task_queue": "_task_queue and _job_queue are both specified. Please specifiy only one or another."
643
+ }
644
+ )
628
645
 
629
646
  # JobMultiPartInputSerializer only has keys for executing job (task_queue, etc),
630
647
  # everything else is a candidate for the job form's data.
@@ -652,7 +669,21 @@ class JobViewSetBase(
652
669
  input_serializer.is_valid(raise_exception=True)
653
670
 
654
671
  data = input_serializer.validated_data.get("data", {})
655
- task_queue = input_serializer.validated_data.get("task_queue", default_valid_queue)
672
+ # TODO remove _task_queue related code in 3.0
673
+ # _task_queue and _job_queue are both valid arguments in v2.4
674
+ task_queue = input_serializer.validated_data.get("task_queue", None) or input_serializer.validated_data.get(
675
+ "job_queue", None
676
+ )
677
+ if not task_queue:
678
+ task_queue = default_valid_queue
679
+
680
+ # Log a warning if _task_queue and _job_queue fields are both specified out
681
+ if input_serializer.validated_data.get("task_queue", None) and input_serializer.validated_data.get(
682
+ "job_queue", None
683
+ ):
684
+ raise ValidationError(
685
+ {"task_queue": "task_queue and job_queue are both specified. Please specifiy only one or another."}
686
+ )
656
687
  schedule_data = input_serializer.validated_data.get("schedule", None)
657
688
 
658
689
  if task_queue not in valid_queues:
@@ -669,7 +700,10 @@ class JobViewSetBase(
669
700
  # of errors under messages
670
701
  return Response({"errors": e.message_dict if hasattr(e, "error_dict") else e.messages}, status=400)
671
702
 
672
- if not get_worker_count(queue=task_queue):
703
+ queue = get_job_queue(task_queue)
704
+ if queue is None:
705
+ queue = job_model.default_job_queue
706
+ if queue.queue_type == JobQueueTypeChoices.TYPE_CELERY and not get_worker_count(queue=task_queue):
673
707
  raise CeleryWorkerNotRunningException(queue=task_queue)
674
708
 
675
709
  # Default to a null JobResult.
@@ -700,7 +734,7 @@ class JobViewSetBase(
700
734
  interval=schedule_data.get("interval"),
701
735
  crontab=schedule_data.get("crontab", ""),
702
736
  approval_required=approval_required,
703
- task_queue=input_serializer.validated_data.get("task_queue", None),
737
+ task_queue=task_queue,
704
738
  **job_class.serialize_data(cleaned_data),
705
739
  )
706
740
  else:
@@ -732,13 +766,13 @@ class JobViewSet(
732
766
  ):
733
767
  lookup_value_regex = r"[-0-9a-fA-F]+"
734
768
 
735
- def perform_destroy(self, instance):
736
- if instance.module_name.startswith("nautobot."):
769
+ def perform_destroy(self, obj):
770
+ if obj.module_name.startswith("nautobot."):
737
771
  raise ProtectedError(
738
- f"Unable to delete Job {instance}. System Job cannot be deleted",
772
+ f"Unable to delete Job {obj}. System Job cannot be deleted",
739
773
  [],
740
774
  )
741
- super().perform_destroy(instance)
775
+ super().perform_destroy(obj)
742
776
 
743
777
 
744
778
  @extend_schema_view(
@@ -784,6 +818,31 @@ class JobHooksViewSet(NautobotModelViewSet):
784
818
  filterset_class = filters.JobHookFilterSet
785
819
 
786
820
 
821
+ #
822
+ # Job Queues
823
+ #
824
+
825
+
826
+ class JobQueueViewSet(NautobotModelViewSet):
827
+ """
828
+ Manage job queues through DELETE, GET, POST, PUT, and PATCH requests.
829
+ """
830
+
831
+ queryset = JobQueue.objects.all()
832
+ serializer_class = serializers.JobQueueSerializer
833
+ filterset_class = filters.JobQueueFilterSet
834
+
835
+
836
+ class JobQueueAssignmentViewSet(NautobotModelViewSet):
837
+ """
838
+ Manage job queue assignments through DELETE, GET, POST, PUT, and PATCH requests.
839
+ """
840
+
841
+ queryset = JobQueueAssignment.objects.select_related("job", "job_queue")
842
+ serializer_class = serializers.JobQueueAssignmentSerializer
843
+ filterset_class = filters.JobQueueAssignmentFilterSet
844
+
845
+
787
846
  #
788
847
  # Job Results
789
848
  #
@@ -912,6 +971,8 @@ class ScheduledJobViewSet(ReadOnlyModelViewSet):
912
971
  scheduled_job.approved_by_user = request.user
913
972
  scheduled_job.approved_at = timezone.now()
914
973
  scheduled_job.save()
974
+ publish_event_payload = {"data": serialize_object_v2(scheduled_job)}
975
+ publish_event(topic="nautobot.jobs.approval.approved", payload=publish_event_payload)
915
976
  serializer = serializers.ScheduledJobSerializer(scheduled_job, context={"request": request})
916
977
 
917
978
  return Response(serializer.data)
@@ -936,6 +997,8 @@ class ScheduledJobViewSet(ReadOnlyModelViewSet):
936
997
  if not Job.objects.check_perms(request.user, instance=scheduled_job.job_model, action="approve"):
937
998
  raise PermissionDenied("You do not have permission to deny this request.")
938
999
 
1000
+ publish_event_payload = {"data": serialize_object_v2(scheduled_job)}
1001
+ publish_event(topic="nautobot.jobs.approval.denied", payload=publish_event_payload)
939
1002
  scheduled_job.delete()
940
1003
 
941
1004
  return Response(None)
@@ -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,6 @@ JOB_OVERRIDABLE_FIELDS = (
30
30
  "soft_time_limit",
31
31
  "time_limit",
32
32
  "has_sensitive_variables",
33
- "task_queues",
34
33
  )
35
34
 
36
35