nautobot 2.3.15b1__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 (785) 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 +143 -26
  32. nautobot/cloud/api/views.py +6 -10
  33. nautobot/cloud/factory.py +4 -1
  34. nautobot/cloud/models.py +1 -1
  35. nautobot/cloud/tests/test_filters.py +5 -4
  36. nautobot/cloud/views.py +0 -16
  37. nautobot/core/api/constants.py +11 -0
  38. nautobot/core/api/fields.py +5 -5
  39. nautobot/core/api/filter_backends.py +3 -9
  40. nautobot/core/api/metadata.py +28 -256
  41. nautobot/core/api/pagination.py +3 -2
  42. nautobot/core/api/renderers.py +3 -0
  43. nautobot/core/api/schema.py +13 -2
  44. nautobot/core/api/serializers.py +54 -268
  45. nautobot/core/api/urls.py +3 -4
  46. nautobot/core/api/utils.py +0 -62
  47. nautobot/core/api/views.py +102 -159
  48. nautobot/core/apps/__init__.py +22 -575
  49. nautobot/core/celery/__init__.py +13 -0
  50. nautobot/core/celery/schedulers.py +48 -3
  51. nautobot/core/choices.py +2 -2
  52. nautobot/core/cli/__init__.py +8 -0
  53. nautobot/core/constants.py +7 -0
  54. nautobot/core/events/__init__.py +116 -0
  55. nautobot/core/events/base.py +27 -0
  56. nautobot/core/events/exceptions.py +10 -0
  57. nautobot/core/events/redis_broker.py +48 -0
  58. nautobot/core/events/syslog_broker.py +19 -0
  59. nautobot/core/exceptions.py +0 -6
  60. nautobot/core/filters.py +19 -16
  61. nautobot/core/forms/__init__.py +19 -19
  62. nautobot/core/forms/fields.py +62 -14
  63. nautobot/core/forms/forms.py +33 -2
  64. nautobot/core/forms/utils.py +2 -1
  65. nautobot/core/graphql/schema.py +3 -1
  66. nautobot/core/graphql/types.py +1 -1
  67. nautobot/core/jobs/__init__.py +28 -7
  68. nautobot/core/jobs/bulk_actions.py +248 -0
  69. nautobot/core/jobs/cleanup.py +2 -2
  70. nautobot/core/jobs/groups.py +1 -1
  71. nautobot/core/management/commands/generate_test_data.py +21 -0
  72. nautobot/core/management/commands/validate_models.py +1 -1
  73. nautobot/core/middleware.py +16 -0
  74. nautobot/core/models/__init__.py +1 -1
  75. nautobot/core/models/fields.py +11 -7
  76. nautobot/core/models/query_functions.py +2 -2
  77. nautobot/core/models/tree_queries.py +2 -2
  78. nautobot/core/settings.py +71 -4
  79. nautobot/core/settings.yaml +107 -0
  80. nautobot/core/tables.py +15 -51
  81. nautobot/core/tasks.py +1 -1
  82. nautobot/core/templates/about.html +67 -0
  83. nautobot/core/templates/components/button/default.html +7 -0
  84. nautobot/core/templates/components/button/dropdown.html +20 -0
  85. nautobot/core/templates/components/layout/one_over_two.html +19 -0
  86. nautobot/core/templates/components/layout/two_over_one.html +19 -0
  87. nautobot/core/templates/components/panel/body_content_data_table.html +27 -0
  88. nautobot/core/templates/components/panel/body_content_objects_table.html +4 -0
  89. nautobot/core/templates/components/panel/body_content_tags.html +6 -0
  90. nautobot/core/templates/components/panel/body_content_text.html +12 -0
  91. nautobot/core/templates/components/panel/body_wrapper_generic.html +3 -0
  92. nautobot/core/templates/components/panel/body_wrapper_key_value_table.html +3 -0
  93. nautobot/core/templates/components/panel/body_wrapper_table.html +3 -0
  94. nautobot/core/templates/components/panel/footer_contacts_table.html +20 -0
  95. nautobot/core/templates/components/panel/footer_content_table.html +14 -0
  96. nautobot/core/templates/components/panel/grouping_toggle.html +14 -0
  97. nautobot/core/templates/components/panel/header_extra_content_table.html +3 -0
  98. nautobot/core/templates/components/panel/panel.html +16 -0
  99. nautobot/core/templates/components/panel/stats_panel_body.html +8 -0
  100. nautobot/core/templates/components/tab/content_wrapper.html +3 -0
  101. nautobot/core/templates/components/tab/label_wrapper.html +5 -0
  102. nautobot/core/templates/components/tab/label_wrapper_distinct_view.html +3 -0
  103. nautobot/core/templates/generic/object_retrieve.html +28 -17
  104. nautobot/core/templates/inc/computed_fields/panel_data.html +4 -7
  105. nautobot/core/templates/inc/custom_fields/panel.html +2 -2
  106. nautobot/core/templates/inc/custom_fields/panel_data.html +4 -7
  107. nautobot/core/templates/inc/footer.html +1 -0
  108. nautobot/core/templates/inc/media.html +3 -0
  109. nautobot/core/templates/inc/nav_menu.html +2 -1
  110. nautobot/core/templates/inc/relationships_panel.html +1 -1
  111. nautobot/core/templates/inc/tenancy_form_panel.html +9 -0
  112. nautobot/core/templates/inc/tenant_table_row.html +11 -0
  113. nautobot/core/templates/nautobot_config.py.j2 +16 -0
  114. nautobot/core/templates/panel_table.html +12 -0
  115. nautobot/core/templates/utilities/render_jinja2.html +117 -0
  116. nautobot/core/templates/utilities/templatetags/tag.html +1 -1
  117. nautobot/core/templates/utilities/theme_preview.html +7 -0
  118. nautobot/core/templatetags/helpers.py +104 -6
  119. nautobot/core/templatetags/ui_framework.py +40 -0
  120. nautobot/core/testing/__init__.py +8 -8
  121. nautobot/core/testing/api.py +187 -137
  122. nautobot/core/testing/context.py +18 -0
  123. nautobot/core/testing/filters.py +44 -34
  124. nautobot/core/testing/forms.py +2 -0
  125. nautobot/core/testing/views.py +68 -146
  126. nautobot/core/tests/integration/test_app_home.py +0 -1
  127. nautobot/core/tests/integration/test_app_navbar.py +0 -1
  128. nautobot/core/tests/integration/test_filters.py +0 -2
  129. nautobot/core/tests/integration/test_home.py +0 -1
  130. nautobot/core/tests/integration/test_navbar.py +0 -1
  131. nautobot/core/tests/integration/test_view_authentication.py +2 -1
  132. nautobot/core/tests/nautobot_config.py +198 -0
  133. nautobot/core/tests/runner.py +3 -3
  134. nautobot/core/tests/test_api.py +154 -176
  135. nautobot/core/tests/test_events.py +214 -0
  136. nautobot/core/tests/test_forms.py +1 -0
  137. nautobot/core/tests/test_jinja_filters.py +1 -0
  138. nautobot/core/tests/test_jobs.py +387 -14
  139. nautobot/core/tests/test_navigations.py +7 -241
  140. nautobot/core/tests/test_settings_schema.py +7 -0
  141. nautobot/core/tests/test_tables.py +100 -0
  142. nautobot/core/tests/test_templatetags_helpers.py +16 -0
  143. nautobot/core/tests/test_ui.py +150 -0
  144. nautobot/core/tests/test_utils.py +55 -18
  145. nautobot/core/tests/test_views.py +153 -5
  146. nautobot/core/ui/__init__.py +0 -0
  147. nautobot/core/ui/base.py +11 -0
  148. nautobot/core/ui/choices.py +44 -0
  149. nautobot/core/ui/homepage.py +167 -0
  150. nautobot/core/ui/nav.py +280 -0
  151. nautobot/core/ui/object_detail.py +1855 -0
  152. nautobot/core/ui/utils.py +36 -0
  153. nautobot/core/urls.py +15 -0
  154. nautobot/core/utils/config.py +30 -3
  155. nautobot/core/utils/lookup.py +12 -2
  156. nautobot/core/utils/querysets.py +64 -0
  157. nautobot/core/utils/requests.py +24 -9
  158. nautobot/core/views/__init__.py +48 -1
  159. nautobot/core/views/generic.py +82 -177
  160. nautobot/core/views/mixins.py +98 -38
  161. nautobot/core/views/paginator.py +8 -5
  162. nautobot/core/views/renderers.py +9 -9
  163. nautobot/core/views/utils.py +11 -0
  164. nautobot/core/wsgi.py +3 -3
  165. nautobot/dcim/api/serializers.py +82 -189
  166. nautobot/dcim/api/urls.py +5 -0
  167. nautobot/dcim/api/views.py +57 -110
  168. nautobot/dcim/apps.py +1 -0
  169. nautobot/dcim/choices.py +28 -0
  170. nautobot/dcim/factory.py +58 -0
  171. nautobot/dcim/filters/__init__.py +204 -2
  172. nautobot/dcim/forms.py +221 -9
  173. nautobot/dcim/graphql/types.py +2 -2
  174. nautobot/dcim/migrations/0063_interfacevdcassignment_virtualdevicecontext_and_more.py +165 -0
  175. nautobot/dcim/migrations/0064_virtualdevicecontext_status_data_migration.py +28 -0
  176. nautobot/dcim/migrations/0065_controller_capabilities_and_more.py +29 -0
  177. nautobot/dcim/migrations/0066_controllermanageddevicegroup_radio_profiles_and_more.py +33 -0
  178. nautobot/dcim/migrations/0067_controllermanageddevicegroup_tenant.py +25 -0
  179. nautobot/dcim/models/__init__.py +5 -1
  180. nautobot/dcim/models/device_component_templates.py +2 -2
  181. nautobot/dcim/models/device_components.py +22 -20
  182. nautobot/dcim/models/devices.py +181 -3
  183. nautobot/dcim/models/locations.py +3 -3
  184. nautobot/dcim/models/power.py +6 -5
  185. nautobot/dcim/models/racks.py +6 -6
  186. nautobot/dcim/navigation.py +25 -224
  187. nautobot/dcim/signals.py +44 -0
  188. nautobot/dcim/tables/__init__.py +5 -3
  189. nautobot/dcim/tables/devices.py +103 -7
  190. nautobot/dcim/tables/devicetypes.py +2 -2
  191. nautobot/dcim/tables/racks.py +1 -1
  192. nautobot/dcim/templates/dcim/controller/base.html +10 -0
  193. nautobot/dcim/templates/dcim/controller_create.html +2 -7
  194. nautobot/dcim/templates/dcim/controller_retrieve.html +6 -10
  195. nautobot/dcim/templates/dcim/controller_wirelessnetworks.html +25 -0
  196. nautobot/dcim/templates/dcim/controllermanageddevicegroup_create.html +68 -0
  197. nautobot/dcim/templates/dcim/controllermanageddevicegroup_retrieve.html +51 -0
  198. nautobot/dcim/templates/dcim/device/base.html +6 -42
  199. nautobot/dcim/templates/dcim/device/wireless.html +73 -0
  200. nautobot/dcim/templates/dcim/device.html +4 -10
  201. nautobot/dcim/templates/dcim/device_edit.html +36 -37
  202. nautobot/dcim/templates/dcim/interface.html +1 -0
  203. nautobot/dcim/templates/dcim/interface_edit.html +1 -0
  204. nautobot/dcim/templates/dcim/location.html +1 -9
  205. nautobot/dcim/templates/dcim/location_edit.html +1 -7
  206. nautobot/dcim/templates/dcim/locationtype.html +0 -107
  207. nautobot/dcim/templates/dcim/locationtype_retrieve.html +8 -0
  208. nautobot/dcim/templates/dcim/rack.html +1 -9
  209. nautobot/dcim/templates/dcim/rack_edit.html +1 -7
  210. nautobot/dcim/templates/dcim/rackreservation.html +1 -9
  211. nautobot/dcim/templates/dcim/virtualdevicecontext_retrieve.html +68 -0
  212. nautobot/dcim/templates/dcim/virtualdevicecontext_update.html +28 -0
  213. nautobot/dcim/tests/integration/test_controller.py +62 -0
  214. nautobot/dcim/tests/integration/test_controller_managed_device_group.py +71 -0
  215. nautobot/dcim/tests/test_api.py +188 -64
  216. nautobot/dcim/tests/test_filters.py +172 -76
  217. nautobot/dcim/tests/test_graphql.py +52 -0
  218. nautobot/dcim/tests/test_jobs.py +118 -0
  219. nautobot/dcim/tests/test_models.py +159 -5
  220. nautobot/dcim/tests/test_signals.py +1 -0
  221. nautobot/dcim/tests/test_views.py +118 -88
  222. nautobot/dcim/urls.py +72 -27
  223. nautobot/dcim/utils.py +2 -2
  224. nautobot/dcim/views.py +357 -62
  225. nautobot/extras/api/customfields.py +2 -2
  226. nautobot/extras/api/serializers.py +111 -87
  227. nautobot/extras/api/urls.py +4 -0
  228. nautobot/extras/api/views.py +93 -35
  229. nautobot/extras/choices.py +13 -0
  230. nautobot/extras/constants.py +2 -1
  231. nautobot/extras/context_managers.py +23 -6
  232. nautobot/extras/datasources/git.py +4 -1
  233. nautobot/extras/factory.py +27 -0
  234. nautobot/extras/filters/__init__.py +66 -5
  235. nautobot/extras/forms/base.py +2 -2
  236. nautobot/extras/forms/forms.py +262 -59
  237. nautobot/extras/forms/mixins.py +3 -3
  238. nautobot/extras/graphql/types.py +25 -1
  239. nautobot/extras/health_checks.py +1 -2
  240. nautobot/extras/jobs.py +114 -20
  241. nautobot/extras/management/__init__.py +1 -0
  242. nautobot/extras/management/commands/runjob.py +7 -79
  243. nautobot/extras/management/commands/runjob_with_job_result.py +46 -0
  244. nautobot/extras/management/utils.py +87 -0
  245. nautobot/extras/managers.py +3 -1
  246. nautobot/extras/migrations/0018_joblog_data_migration.py +7 -9
  247. nautobot/extras/migrations/0117_create_job_queue_model.py +129 -0
  248. nautobot/extras/migrations/0118_task_queue_to_job_queue_migration.py +78 -0
  249. nautobot/extras/migrations/0119_remove_task_queues_from_job_and_queue_from_scheduled_job.py +28 -0
  250. nautobot/extras/migrations/0120_job_is_singleton_job_is_singleton_override.py +22 -0
  251. nautobot/extras/migrations/0121_alter_team_contacts.py +17 -0
  252. nautobot/extras/models/__init__.py +5 -1
  253. nautobot/extras/models/change_logging.py +7 -3
  254. nautobot/extras/models/contacts.py +1 -1
  255. nautobot/extras/models/customfields.py +12 -11
  256. nautobot/extras/models/groups.py +11 -9
  257. nautobot/extras/models/jobs.py +237 -37
  258. nautobot/extras/models/models.py +2 -2
  259. nautobot/extras/models/relationships.py +69 -1
  260. nautobot/extras/models/secrets.py +5 -0
  261. nautobot/extras/navigation.py +20 -262
  262. nautobot/extras/plugins/__init__.py +54 -19
  263. nautobot/extras/plugins/marketplace_manifest.yml +455 -0
  264. nautobot/extras/plugins/tables.py +16 -14
  265. nautobot/extras/plugins/urls.py +1 -0
  266. nautobot/extras/plugins/views.py +104 -61
  267. nautobot/extras/registry.py +1 -1
  268. nautobot/extras/secrets/__init__.py +2 -2
  269. nautobot/extras/signals.py +39 -1
  270. nautobot/extras/tables.py +42 -6
  271. nautobot/extras/templates/extras/dynamicgroup.html +1 -9
  272. nautobot/extras/templates/extras/externalintegration_retrieve.html +0 -47
  273. nautobot/extras/templates/extras/inc/tags_panel.html +1 -5
  274. nautobot/extras/templates/extras/job_bulk_edit.html +2 -1
  275. nautobot/extras/templates/extras/job_detail.html +52 -6
  276. nautobot/extras/templates/extras/job_edit.html +6 -2
  277. nautobot/extras/templates/extras/job_list.html +2 -7
  278. nautobot/extras/templates/extras/jobqueue_retrieve.html +36 -0
  279. nautobot/extras/templates/extras/marketplace.html +296 -0
  280. nautobot/extras/templates/extras/plugin_detail.html +32 -15
  281. nautobot/extras/templates/extras/plugins_list.html +35 -1
  282. nautobot/extras/templates/extras/plugins_tiles.html +90 -0
  283. nautobot/extras/templates/extras/role_retrieve.html +16 -0
  284. nautobot/extras/templates/extras/secret.html +0 -65
  285. nautobot/extras/templates/extras/secret_check.js +16 -0
  286. nautobot/extras/templates/extras/secret_create.html +114 -0
  287. nautobot/extras/templates/extras/secret_edit.html +1 -114
  288. nautobot/extras/templates/extras/secretsgroup_edit.html +1 -1
  289. nautobot/extras/templates/extras/templatetags/plugin_object_detail_tabs.html +2 -0
  290. nautobot/extras/templatetags/job_buttons.py +5 -4
  291. nautobot/extras/templatetags/plugins.py +69 -6
  292. nautobot/extras/test_jobs/api_test_job.py +1 -1
  293. nautobot/extras/test_jobs/atomic_transaction.py +2 -2
  294. nautobot/extras/test_jobs/dry_run.py +1 -1
  295. nautobot/extras/test_jobs/fail.py +5 -5
  296. nautobot/extras/test_jobs/file_output.py +1 -1
  297. nautobot/extras/test_jobs/file_upload_fail.py +1 -1
  298. nautobot/extras/test_jobs/file_upload_pass.py +1 -1
  299. nautobot/extras/test_jobs/ipaddress_vars.py +3 -1
  300. nautobot/extras/test_jobs/jobs_module/jobs_submodule/jobs.py +1 -1
  301. nautobot/extras/test_jobs/location_with_custom_field.py +1 -1
  302. nautobot/extras/test_jobs/log_redaction.py +1 -1
  303. nautobot/extras/test_jobs/log_skip_db_logging.py +1 -1
  304. nautobot/extras/test_jobs/modify_db.py +1 -1
  305. nautobot/extras/test_jobs/object_var_optional.py +1 -1
  306. nautobot/extras/test_jobs/object_var_required.py +1 -1
  307. nautobot/extras/test_jobs/object_vars.py +1 -1
  308. nautobot/extras/test_jobs/pass.py +3 -3
  309. nautobot/extras/test_jobs/profiling.py +1 -1
  310. nautobot/extras/test_jobs/relative_import.py +3 -3
  311. nautobot/extras/test_jobs/singleton.py +16 -0
  312. nautobot/extras/test_jobs/soft_time_limit_greater_than_time_limit.py +1 -1
  313. nautobot/extras/test_jobs/task_queues.py +1 -1
  314. nautobot/extras/tests/integration/test_plugin_banner.py +0 -2
  315. nautobot/extras/tests/test_api.py +157 -55
  316. nautobot/extras/tests/test_context_managers.py +4 -1
  317. nautobot/extras/tests/test_customfields.py +1 -1
  318. nautobot/extras/tests/test_datasources.py +2 -1
  319. nautobot/extras/tests/test_dynamicgroups.py +1 -1
  320. nautobot/extras/tests/test_filters.py +219 -535
  321. nautobot/extras/tests/test_forms.py +20 -1
  322. nautobot/extras/tests/test_job_variables.py +73 -152
  323. nautobot/extras/tests/test_jobs.py +192 -62
  324. nautobot/extras/tests/test_models.py +71 -16
  325. nautobot/extras/tests/test_plugins.py +62 -9
  326. nautobot/extras/tests/test_relationships.py +124 -10
  327. nautobot/extras/tests/test_utils.py +23 -2
  328. nautobot/extras/tests/test_views.py +162 -161
  329. nautobot/extras/tests/test_webhooks.py +2 -1
  330. nautobot/extras/urls.py +2 -20
  331. nautobot/extras/utils.py +119 -4
  332. nautobot/extras/views.py +188 -141
  333. nautobot/extras/webhooks.py +5 -2
  334. nautobot/ipam/api/fields.py +3 -3
  335. nautobot/ipam/api/serializers.py +44 -137
  336. nautobot/ipam/api/views.py +68 -110
  337. nautobot/ipam/factory.py +1 -1
  338. nautobot/ipam/filters.py +3 -2
  339. nautobot/ipam/models.py +10 -12
  340. nautobot/ipam/navigation.py +0 -90
  341. nautobot/ipam/querysets.py +2 -2
  342. nautobot/ipam/tables.py +3 -1
  343. nautobot/ipam/templates/ipam/ipaddress.html +1 -9
  344. nautobot/ipam/templates/ipam/ipaddress_bulk_add.html +1 -7
  345. nautobot/ipam/templates/ipam/ipaddress_edit.html +1 -7
  346. nautobot/ipam/templates/ipam/prefix.html +1 -9
  347. nautobot/ipam/templates/ipam/prefix_edit.html +1 -7
  348. nautobot/ipam/templates/ipam/routetarget.html +0 -28
  349. nautobot/ipam/templates/ipam/vlan.html +1 -9
  350. nautobot/ipam/templates/ipam/vlan_edit.html +1 -7
  351. nautobot/ipam/templates/ipam/vrf.html +0 -47
  352. nautobot/ipam/templates/ipam/vrf_edit.html +1 -7
  353. nautobot/ipam/tests/test_api.py +19 -6
  354. nautobot/ipam/tests/test_filters.py +39 -119
  355. nautobot/ipam/tests/test_forms.py +49 -47
  356. nautobot/ipam/tests/test_migrations.py +30 -30
  357. nautobot/ipam/tests/test_models.py +56 -36
  358. nautobot/ipam/tests/test_querysets.py +14 -0
  359. nautobot/ipam/tests/test_views.py +3 -0
  360. nautobot/ipam/urls.py +3 -69
  361. nautobot/ipam/utils/__init__.py +16 -10
  362. nautobot/ipam/views.py +91 -162
  363. nautobot/project-static/bootstrap-3.4.1-dist/css/bootstrap-theme.css.map +1 -1
  364. nautobot/project-static/bootstrap-3.4.1-dist/css/bootstrap-theme.min.css.map +1 -1
  365. nautobot/project-static/bootstrap-3.4.1-dist/css/bootstrap.css +40 -2
  366. nautobot/project-static/bootstrap-3.4.1-dist/css/bootstrap.css.map +1 -1
  367. nautobot/project-static/bootstrap-3.4.1-dist/css/bootstrap.min.css +1 -1
  368. nautobot/project-static/bootstrap-3.4.1-dist/css/bootstrap.min.css.map +1 -1
  369. nautobot/project-static/css/base.css +38 -3
  370. nautobot/project-static/docs/404.html +463 -19
  371. nautobot/project-static/docs/apps/index.html +463 -19
  372. nautobot/project-static/docs/apps/nautobot-apps.html +464 -21
  373. nautobot/project-static/docs/assets/_mkdocstrings.css +25 -1
  374. nautobot/project-static/docs/assets/extra.css +5 -1
  375. nautobot/project-static/docs/assets/javascripts/{bundle.83f73b43.min.js → bundle.88dd0f4e.min.js} +2 -2
  376. nautobot/project-static/docs/assets/javascripts/{bundle.83f73b43.min.js.map → bundle.88dd0f4e.min.js.map} +2 -2
  377. nautobot/project-static/docs/code-reference/nautobot/apps/__init__.html +479 -25
  378. nautobot/project-static/docs/code-reference/nautobot/apps/admin.html +476 -22
  379. nautobot/project-static/docs/code-reference/nautobot/apps/api.html +792 -291
  380. nautobot/project-static/docs/code-reference/nautobot/apps/change_logging.html +507 -33
  381. nautobot/project-static/docs/code-reference/nautobot/apps/choices.html +512 -36
  382. nautobot/project-static/docs/code-reference/nautobot/apps/config.html +473 -22
  383. nautobot/project-static/docs/code-reference/nautobot/apps/constants.html +469 -20
  384. nautobot/project-static/docs/code-reference/nautobot/apps/datasources.html +499 -35
  385. nautobot/project-static/docs/code-reference/nautobot/apps/events.html +9883 -0
  386. nautobot/project-static/docs/code-reference/nautobot/apps/exceptions.html +525 -77
  387. nautobot/project-static/docs/code-reference/nautobot/apps/factory.html +548 -53
  388. nautobot/project-static/docs/code-reference/nautobot/apps/filters.html +672 -96
  389. nautobot/project-static/docs/code-reference/nautobot/apps/forms.html +1033 -180
  390. nautobot/project-static/docs/code-reference/nautobot/apps/graphql.html +526 -51
  391. nautobot/project-static/docs/code-reference/nautobot/apps/jobs.html +876 -190
  392. nautobot/project-static/docs/code-reference/nautobot/apps/models.html +957 -237
  393. nautobot/project-static/docs/code-reference/nautobot/apps/querysets.html +477 -23
  394. nautobot/project-static/docs/code-reference/nautobot/apps/secrets.html +488 -30
  395. nautobot/project-static/docs/code-reference/nautobot/apps/tables.html +663 -101
  396. nautobot/project-static/docs/code-reference/nautobot/apps/testing.html +949 -481
  397. nautobot/project-static/docs/code-reference/nautobot/apps/ui.html +6427 -1236
  398. nautobot/project-static/docs/code-reference/nautobot/apps/urls.html +476 -22
  399. nautobot/project-static/docs/code-reference/nautobot/apps/utils.html +879 -346
  400. nautobot/project-static/docs/code-reference/nautobot/apps/views.html +830 -173
  401. nautobot/project-static/docs/development/apps/api/configuration-view.html +463 -19
  402. nautobot/project-static/docs/development/apps/api/database-backend-config.html +463 -19
  403. nautobot/project-static/docs/development/apps/api/models/django-admin.html +463 -19
  404. nautobot/project-static/docs/development/apps/api/models/global-search.html +463 -19
  405. nautobot/project-static/docs/development/apps/api/models/graphql.html +463 -19
  406. nautobot/project-static/docs/development/apps/api/models/index.html +463 -19
  407. nautobot/project-static/docs/development/apps/api/nautobot-app-config.html +463 -19
  408. nautobot/project-static/docs/development/apps/api/platform-features/custom-validators.html +463 -19
  409. nautobot/project-static/docs/development/apps/api/platform-features/filter-extensions.html +463 -19
  410. nautobot/project-static/docs/development/apps/api/platform-features/git-repository-content.html +463 -19
  411. nautobot/project-static/docs/development/apps/api/platform-features/index.html +463 -19
  412. nautobot/project-static/docs/development/apps/api/platform-features/jinja2-filters.html +463 -19
  413. nautobot/project-static/docs/development/apps/api/platform-features/jobs.html +463 -19
  414. nautobot/project-static/docs/development/apps/api/platform-features/populating-extensibility-features.html +463 -19
  415. nautobot/project-static/docs/development/apps/api/platform-features/secrets-providers.html +463 -19
  416. nautobot/project-static/docs/development/apps/api/platform-features/table-extensions.html +463 -19
  417. nautobot/project-static/docs/development/apps/api/platform-features/uniquely-identify-objects.html +463 -19
  418. nautobot/project-static/docs/development/apps/api/prometheus.html +463 -19
  419. nautobot/project-static/docs/development/apps/api/setup.html +467 -155
  420. nautobot/project-static/docs/development/apps/api/testing.html +463 -19
  421. nautobot/project-static/docs/development/apps/api/ui-extensions/banners.html +463 -19
  422. nautobot/project-static/docs/development/apps/api/ui-extensions/home-page.html +463 -19
  423. nautobot/project-static/docs/development/apps/api/ui-extensions/index.html +463 -19
  424. nautobot/project-static/docs/development/apps/api/ui-extensions/navigation.html +463 -19
  425. nautobot/project-static/docs/development/apps/api/ui-extensions/object-views.html +743 -130
  426. nautobot/project-static/docs/development/apps/api/views/base-template.html +463 -19
  427. nautobot/project-static/docs/development/apps/api/views/core-view-overrides.html +463 -19
  428. nautobot/project-static/docs/development/apps/api/views/django-generic-views.html +463 -19
  429. nautobot/project-static/docs/development/apps/api/views/help-documentation.html +463 -19
  430. nautobot/project-static/docs/development/apps/api/views/index.html +465 -20
  431. nautobot/project-static/docs/development/apps/api/views/nautobot-generic-views.html +467 -19
  432. nautobot/project-static/docs/development/apps/api/views/nautobotuiviewset.html +493 -19
  433. nautobot/project-static/docs/development/apps/api/views/nautobotuiviewsetrouter.html +463 -19
  434. nautobot/project-static/docs/development/apps/api/views/notes.html +463 -19
  435. nautobot/project-static/docs/development/apps/api/views/rest-api.html +469 -21
  436. nautobot/project-static/docs/development/apps/api/views/urls.html +463 -19
  437. nautobot/project-static/docs/development/apps/index.html +463 -19
  438. nautobot/project-static/docs/development/apps/migration/code-updates.html +464 -52
  439. nautobot/project-static/docs/development/apps/migration/dependency-updates.html +464 -20
  440. nautobot/project-static/docs/development/apps/migration/from-v1.html +463 -19
  441. nautobot/project-static/docs/development/apps/migration/model-updates/dcim.html +463 -19
  442. nautobot/project-static/docs/development/apps/migration/model-updates/extras.html +463 -19
  443. nautobot/project-static/docs/development/apps/migration/model-updates/global.html +463 -19
  444. nautobot/project-static/docs/development/apps/migration/model-updates/ipam.html +466 -22
  445. nautobot/project-static/docs/development/apps/migration/ui-component-framework/best-practices.html +9261 -0
  446. nautobot/project-static/docs/development/apps/migration/ui-component-framework/custom-content.html +9375 -0
  447. nautobot/project-static/docs/development/apps/migration/ui-component-framework/index.html +9671 -0
  448. nautobot/project-static/docs/development/apps/migration/ui-component-framework/migration-steps.html +9559 -0
  449. nautobot/project-static/docs/development/apps/porting-from-netbox.html +466 -22
  450. nautobot/project-static/docs/development/core/application-registry.html +463 -19
  451. nautobot/project-static/docs/development/core/best-practices.html +463 -19
  452. nautobot/project-static/docs/development/core/bootstrap-ui.html +463 -19
  453. nautobot/project-static/docs/development/core/caching.html +463 -19
  454. nautobot/project-static/docs/development/core/controllers.html +465 -19
  455. nautobot/project-static/docs/development/core/docker-compose-advanced-use-cases.html +491 -90
  456. nautobot/project-static/docs/development/core/generic-views.html +463 -19
  457. nautobot/project-static/docs/development/core/getting-started.html +541 -129
  458. nautobot/project-static/docs/development/core/homepage.html +474 -30
  459. nautobot/project-static/docs/development/core/index.html +463 -19
  460. nautobot/project-static/docs/development/core/minikube-dev-environment-for-k8s-jobs.html +9754 -0
  461. nautobot/project-static/docs/development/core/model-checklist.html +473 -27
  462. nautobot/project-static/docs/development/core/model-features.html +463 -19
  463. nautobot/project-static/docs/development/core/natural-keys.html +463 -19
  464. nautobot/project-static/docs/development/core/navigation-menu.html +480 -26
  465. nautobot/project-static/docs/development/core/release-checklist.html +480 -48
  466. nautobot/project-static/docs/development/core/role-internals.html +463 -19
  467. nautobot/project-static/docs/development/core/settings.html +463 -19
  468. nautobot/project-static/docs/development/core/style-guide.html +466 -22
  469. nautobot/project-static/docs/development/core/templates.html +473 -22
  470. nautobot/project-static/docs/development/core/testing.html +463 -19
  471. nautobot/project-static/docs/development/core/ui-component-framework.html +11116 -0
  472. nautobot/project-static/docs/development/core/user-preferences.html +466 -22
  473. nautobot/project-static/docs/development/index.html +463 -19
  474. nautobot/project-static/docs/development/jobs/index.html +501 -21
  475. nautobot/project-static/docs/development/jobs/migration/from-v1.html +463 -19
  476. nautobot/project-static/docs/index.html +471 -38
  477. nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_edit.png +0 -0
  478. nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_edit_button.png +0 -0
  479. nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_list_nav.png +0 -0
  480. nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_list_view.png +0 -0
  481. nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_queue.png +0 -0
  482. nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_queue_add.png +0 -0
  483. nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_queue_config.png +0 -0
  484. nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_result_completed.png +0 -0
  485. nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_result_nav.png +0 -0
  486. nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_result_pending.png +0 -0
  487. nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_run_form.png +0 -0
  488. nautobot/project-static/docs/media/development/core/kubernetes/k8s_nautobot_login.png +0 -0
  489. nautobot/project-static/docs/media/development/core/kubernetes/k8s_run_job.png +0 -0
  490. nautobot/project-static/docs/media/development/core/kubernetes/k8s_run_scheduled_job_form.png +0 -0
  491. nautobot/project-static/docs/media/development/core/kubernetes/k8s_scheduled_job_result.png +0 -0
  492. nautobot/project-static/docs/media/development/core/ui-component-framework/basic-panel-layout.png +0 -0
  493. nautobot/project-static/docs/media/development/core/ui-component-framework/button-example.png +0 -0
  494. nautobot/project-static/docs/media/development/core/ui-component-framework/buttons-example.png +0 -0
  495. nautobot/project-static/docs/media/development/core/ui-component-framework/cluster-type-before-after-example.png +0 -0
  496. nautobot/project-static/docs/media/development/core/ui-component-framework/dropdown-button-example.png +0 -0
  497. nautobot/project-static/docs/media/development/core/ui-component-framework/grouped-key-value-table-panel-example-1.png +0 -0
  498. nautobot/project-static/docs/media/development/core/ui-component-framework/grouped-key-value-table-panel-example-2.png +0 -0
  499. nautobot/project-static/docs/media/development/core/ui-component-framework/object-fields-panel-example.png +0 -0
  500. nautobot/project-static/docs/media/development/core/ui-component-framework/object-fields-panel-example_2.png +0 -0
  501. nautobot/project-static/docs/media/development/core/ui-component-framework/stats-panel-example-code.png +0 -0
  502. nautobot/project-static/docs/media/development/core/ui-component-framework/stats-panel-example.png +0 -0
  503. nautobot/project-static/docs/media/development/core/ui-component-framework/table-panels-family.png +0 -0
  504. nautobot/project-static/docs/media/development/core/ui-component-framework/text-panels-family.png +0 -0
  505. nautobot/project-static/docs/media/development/core/ui-component-framework/ui-framework-example.png +0 -0
  506. nautobot/project-static/docs/media/models/virtual_device_context_overview.drawio +73 -0
  507. nautobot/project-static/docs/media/models/virtual_device_context_overview.png +0 -0
  508. nautobot/project-static/docs/models/dcim/virtualdevicecontext.html +14 -0
  509. nautobot/project-static/docs/models/extras/jobqueue.html +14 -0
  510. nautobot/project-static/docs/models/wireless/radioprofile.html +14 -0
  511. nautobot/project-static/docs/models/wireless/supporteddatarate.html +14 -0
  512. nautobot/project-static/docs/models/wireless/wirelessnetwork.html +14 -0
  513. nautobot/project-static/docs/objects.inv +0 -0
  514. nautobot/project-static/docs/overview/application_stack.html +469 -23
  515. nautobot/project-static/docs/overview/design_philosophy.html +463 -19
  516. nautobot/project-static/docs/release-notes/index.html +485 -22
  517. nautobot/project-static/docs/release-notes/version-1.0.html +651 -208
  518. nautobot/project-static/docs/release-notes/version-1.1.html +648 -205
  519. nautobot/project-static/docs/release-notes/version-1.2.html +723 -280
  520. nautobot/project-static/docs/release-notes/version-1.3.html +749 -306
  521. nautobot/project-static/docs/release-notes/version-1.4.html +834 -392
  522. nautobot/project-static/docs/release-notes/version-1.5.html +1022 -581
  523. nautobot/project-static/docs/release-notes/version-1.6.html +942 -518
  524. nautobot/project-static/docs/release-notes/version-2.0.html +945 -504
  525. nautobot/project-static/docs/release-notes/version-2.1.html +780 -339
  526. nautobot/project-static/docs/release-notes/version-2.2.html +773 -332
  527. nautobot/project-static/docs/release-notes/version-2.3.html +1142 -448
  528. nautobot/project-static/docs/release-notes/version-2.4.html +10323 -0
  529. nautobot/project-static/docs/requirements.txt +2 -2
  530. nautobot/project-static/docs/search/search_index.json +1 -1
  531. nautobot/project-static/docs/sitemap.xml +342 -270
  532. nautobot/project-static/docs/sitemap.xml.gz +0 -0
  533. nautobot/project-static/docs/user-guide/administration/configuration/authentication/ldap.html +463 -19
  534. nautobot/project-static/docs/user-guide/administration/configuration/authentication/remote.html +463 -19
  535. nautobot/project-static/docs/user-guide/administration/configuration/authentication/sso.html +463 -19
  536. nautobot/project-static/docs/user-guide/administration/configuration/index.html +475 -32
  537. nautobot/project-static/docs/user-guide/administration/configuration/redis.html +463 -19
  538. nautobot/project-static/docs/user-guide/administration/configuration/settings.html +894 -180
  539. nautobot/project-static/docs/user-guide/administration/configuration/time-zones.html +463 -19
  540. nautobot/project-static/docs/user-guide/administration/guides/celery-queues.html +463 -19
  541. nautobot/project-static/docs/user-guide/administration/guides/docker.html +476 -29
  542. nautobot/project-static/docs/user-guide/administration/guides/health-checks.html +463 -19
  543. nautobot/project-static/docs/user-guide/administration/guides/permissions.html +463 -19
  544. nautobot/project-static/docs/user-guide/administration/guides/prometheus-metrics.html +463 -19
  545. nautobot/project-static/docs/user-guide/administration/guides/replicating-nautobot.html +463 -19
  546. nautobot/project-static/docs/user-guide/administration/guides/request-profiling.html +463 -19
  547. nautobot/project-static/docs/user-guide/administration/guides/s3-django-storage.html +465 -21
  548. nautobot/project-static/docs/user-guide/administration/guides/selinux-troubleshooting.html +463 -19
  549. nautobot/project-static/docs/user-guide/administration/installation/app-install.html +463 -19
  550. nautobot/project-static/docs/user-guide/administration/installation/external-authentication.html +463 -19
  551. nautobot/project-static/docs/user-guide/administration/installation/http-server.html +483 -23
  552. nautobot/project-static/docs/user-guide/administration/installation/index.html +468 -20
  553. nautobot/project-static/docs/user-guide/administration/installation/install_system.html +464 -20
  554. nautobot/project-static/docs/user-guide/administration/installation/nautobot.html +463 -19
  555. nautobot/project-static/docs/user-guide/administration/installation/services.html +463 -19
  556. nautobot/project-static/docs/user-guide/administration/migration/migrating-from-netbox.html +463 -19
  557. nautobot/project-static/docs/user-guide/administration/migration/migrating-from-postgresql.html +484 -41
  558. nautobot/project-static/docs/user-guide/administration/tools/nautobot-server.html +477 -66
  559. nautobot/project-static/docs/user-guide/administration/tools/nautobot-shell.html +477 -66
  560. nautobot/project-static/docs/user-guide/administration/upgrading/database-backup.html +463 -19
  561. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/after-you-upgrade.html +463 -19
  562. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/before-you-upgrade.html +463 -19
  563. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/for-developers.html +463 -19
  564. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/index.html +463 -19
  565. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/whats-changed.html +466 -23
  566. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/region-and-site-data-migration-guide.html +463 -19
  567. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/tables/v2-code-nautobot-app-location.yaml +0 -16
  568. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/upgrading-from-nautobot-v1.html +463 -19
  569. nautobot/project-static/docs/user-guide/administration/upgrading/upgrading.html +469 -21
  570. nautobot/project-static/docs/user-guide/core-data-model/circuits/circuit.html +463 -19
  571. nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittermination.html +463 -19
  572. nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittype.html +463 -19
  573. nautobot/project-static/docs/user-guide/core-data-model/circuits/provider.html +463 -19
  574. nautobot/project-static/docs/user-guide/core-data-model/circuits/providernetwork.html +463 -19
  575. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloud.html +463 -19
  576. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudaccount.html +463 -19
  577. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudnetwork.html +463 -19
  578. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudnetworkprefixassignment.html +463 -19
  579. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudresourcetype.html +463 -19
  580. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudservice.html +463 -19
  581. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudservicenetworkassignment.html +463 -19
  582. nautobot/project-static/docs/user-guide/core-data-model/dcim/cable.html +463 -19
  583. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleport.html +463 -19
  584. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleporttemplate.html +463 -19
  585. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverport.html +463 -19
  586. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverporttemplate.html +463 -19
  587. nautobot/project-static/docs/user-guide/core-data-model/dcim/controller.html +499 -20
  588. nautobot/project-static/docs/user-guide/core-data-model/dcim/controllermanageddevicegroup.html +489 -22
  589. nautobot/project-static/docs/user-guide/core-data-model/dcim/device.html +463 -19
  590. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebay.html +463 -19
  591. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebaytemplate.html +463 -19
  592. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicefamily.html +463 -19
  593. nautobot/project-static/docs/user-guide/core-data-model/dcim/deviceredundancygroup.html +463 -19
  594. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicetype.html +463 -19
  595. nautobot/project-static/docs/user-guide/core-data-model/dcim/frontport.html +463 -19
  596. nautobot/project-static/docs/user-guide/core-data-model/dcim/frontporttemplate.html +463 -19
  597. nautobot/project-static/docs/user-guide/core-data-model/dcim/interface.html +463 -19
  598. nautobot/project-static/docs/user-guide/core-data-model/dcim/interfaceredundancygroup.html +463 -19
  599. nautobot/project-static/docs/user-guide/core-data-model/dcim/interfacetemplate.html +463 -19
  600. nautobot/project-static/docs/user-guide/core-data-model/dcim/inventoryitem.html +463 -19
  601. nautobot/project-static/docs/user-guide/core-data-model/dcim/location.html +463 -19
  602. nautobot/project-static/docs/user-guide/core-data-model/dcim/locationtype.html +463 -19
  603. nautobot/project-static/docs/user-guide/core-data-model/dcim/manufacturer.html +463 -19
  604. nautobot/project-static/docs/user-guide/core-data-model/dcim/module.html +463 -19
  605. nautobot/project-static/docs/user-guide/core-data-model/dcim/modulebay.html +463 -19
  606. nautobot/project-static/docs/user-guide/core-data-model/dcim/modulebaytemplate.html +463 -19
  607. nautobot/project-static/docs/user-guide/core-data-model/dcim/moduletype.html +463 -19
  608. nautobot/project-static/docs/user-guide/core-data-model/dcim/platform.html +463 -19
  609. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerfeed.html +463 -19
  610. nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlet.html +463 -19
  611. nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlettemplate.html +463 -19
  612. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerpanel.html +463 -19
  613. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerport.html +463 -19
  614. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerporttemplate.html +463 -19
  615. nautobot/project-static/docs/user-guide/core-data-model/dcim/rack.html +463 -19
  616. nautobot/project-static/docs/user-guide/core-data-model/dcim/rackgroup.html +463 -19
  617. nautobot/project-static/docs/user-guide/core-data-model/dcim/rackreservation.html +463 -19
  618. nautobot/project-static/docs/user-guide/core-data-model/dcim/rearport.html +463 -19
  619. nautobot/project-static/docs/user-guide/core-data-model/dcim/rearporttemplate.html +463 -19
  620. nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareimagefile.html +463 -19
  621. nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareversion.html +463 -19
  622. nautobot/project-static/docs/user-guide/core-data-model/dcim/virtualchassis.html +463 -19
  623. nautobot/project-static/docs/user-guide/core-data-model/dcim/virtualdevicecontext.html +9375 -0
  624. nautobot/project-static/docs/user-guide/core-data-model/extras/configcontext.html +470 -30
  625. nautobot/project-static/docs/user-guide/core-data-model/extras/configcontextschema.html +463 -19
  626. nautobot/project-static/docs/user-guide/core-data-model/extras/contact.html +463 -19
  627. nautobot/project-static/docs/user-guide/core-data-model/extras/team.html +463 -19
  628. nautobot/project-static/docs/user-guide/core-data-model/ipam/ipaddress.html +463 -19
  629. nautobot/project-static/docs/user-guide/core-data-model/ipam/namespace.html +463 -19
  630. nautobot/project-static/docs/user-guide/core-data-model/ipam/prefix.html +463 -19
  631. nautobot/project-static/docs/user-guide/core-data-model/ipam/rir.html +463 -19
  632. nautobot/project-static/docs/user-guide/core-data-model/ipam/routetarget.html +463 -19
  633. nautobot/project-static/docs/user-guide/core-data-model/ipam/service.html +463 -19
  634. nautobot/project-static/docs/user-guide/core-data-model/ipam/vlan.html +463 -19
  635. nautobot/project-static/docs/user-guide/core-data-model/ipam/vlangroup.html +463 -19
  636. nautobot/project-static/docs/user-guide/core-data-model/ipam/vrf.html +463 -19
  637. nautobot/project-static/docs/user-guide/core-data-model/overview/introduction.html +466 -22
  638. nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenant.html +463 -19
  639. nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenantgroup.html +463 -19
  640. nautobot/project-static/docs/user-guide/core-data-model/virtualization/cluster.html +463 -19
  641. nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustergroup.html +463 -19
  642. nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustertype.html +463 -19
  643. nautobot/project-static/docs/user-guide/core-data-model/virtualization/virtualmachine.html +463 -19
  644. nautobot/project-static/docs/user-guide/core-data-model/virtualization/vminterface.html +466 -22
  645. nautobot/project-static/docs/user-guide/core-data-model/wireless/index.html +9313 -0
  646. nautobot/project-static/docs/user-guide/core-data-model/wireless/radioprofile.html +9217 -0
  647. nautobot/project-static/docs/user-guide/core-data-model/wireless/supporteddatarate.html +9211 -0
  648. nautobot/project-static/docs/user-guide/core-data-model/wireless/wirelessnetwork.html +9277 -0
  649. nautobot/project-static/docs/user-guide/feature-guides/contacts-and-teams.html +463 -19
  650. nautobot/project-static/docs/user-guide/feature-guides/custom-fields.html +463 -19
  651. nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-devices.html +463 -19
  652. nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-location-types-and-locations.html +463 -19
  653. nautobot/project-static/docs/user-guide/feature-guides/getting-started/index.html +463 -19
  654. nautobot/project-static/docs/user-guide/feature-guides/getting-started/interfaces.html +463 -19
  655. nautobot/project-static/docs/user-guide/feature-guides/getting-started/ipam.html +463 -19
  656. nautobot/project-static/docs/user-guide/feature-guides/getting-started/platforms.html +463 -19
  657. nautobot/project-static/docs/user-guide/feature-guides/getting-started/search-bar.html +463 -19
  658. nautobot/project-static/docs/user-guide/feature-guides/getting-started/tenants.html +463 -19
  659. nautobot/project-static/docs/user-guide/feature-guides/getting-started/vlans-and-vlan-groups.html +463 -19
  660. nautobot/project-static/docs/user-guide/feature-guides/git-data-source.html +468 -22
  661. nautobot/project-static/docs/user-guide/feature-guides/graphql.html +463 -19
  662. nautobot/project-static/docs/user-guide/feature-guides/images/wireless/central-mode.png +0 -0
  663. nautobot/project-static/docs/user-guide/feature-guides/images/wireless/device-group-add.png +0 -0
  664. nautobot/project-static/docs/user-guide/feature-guides/images/wireless/device-group-create-1.png +0 -0
  665. nautobot/project-static/docs/user-guide/feature-guides/images/wireless/device-group-create-2.png +0 -0
  666. nautobot/project-static/docs/user-guide/feature-guides/images/wireless/radio-profile-add.png +0 -0
  667. nautobot/project-static/docs/user-guide/feature-guides/images/wireless/radio-profile-create.png +0 -0
  668. nautobot/project-static/docs/user-guide/feature-guides/images/wireless/supported-data-rate-add.png +0 -0
  669. nautobot/project-static/docs/user-guide/feature-guides/images/wireless/supported-data-rate-create.png +0 -0
  670. nautobot/project-static/docs/user-guide/feature-guides/images/wireless/wireless-controller-add.png +0 -0
  671. nautobot/project-static/docs/user-guide/feature-guides/images/wireless/wireless-controller-create-1.png +0 -0
  672. nautobot/project-static/docs/user-guide/feature-guides/images/wireless/wireless-controller-create-2.png +0 -0
  673. nautobot/project-static/docs/user-guide/feature-guides/images/wireless/wireless-network-add.png +0 -0
  674. nautobot/project-static/docs/user-guide/feature-guides/images/wireless/wireless-network-create.png +0 -0
  675. nautobot/project-static/docs/user-guide/feature-guides/ip-address-merge-tool.html +463 -19
  676. nautobot/project-static/docs/user-guide/feature-guides/relationships.html +463 -19
  677. nautobot/project-static/docs/user-guide/feature-guides/software-image-files-and-versions.html +466 -22
  678. nautobot/project-static/docs/user-guide/feature-guides/wireless-networks-and-controllers.html +9444 -0
  679. nautobot/project-static/docs/user-guide/index.html +463 -19
  680. nautobot/project-static/docs/user-guide/platform-functionality/change-logging.html +466 -22
  681. nautobot/project-static/docs/user-guide/platform-functionality/computedfield.html +467 -23
  682. nautobot/project-static/docs/user-guide/platform-functionality/customfield.html +463 -19
  683. nautobot/project-static/docs/user-guide/platform-functionality/customlink.html +463 -19
  684. nautobot/project-static/docs/user-guide/platform-functionality/dynamicgroup.html +463 -19
  685. nautobot/project-static/docs/user-guide/platform-functionality/events.html +9617 -0
  686. nautobot/project-static/docs/user-guide/platform-functionality/exporttemplate.html +466 -22
  687. nautobot/project-static/docs/user-guide/platform-functionality/externalintegration.html +463 -19
  688. nautobot/project-static/docs/user-guide/platform-functionality/gitrepository.html +463 -19
  689. nautobot/project-static/docs/user-guide/platform-functionality/graphql.html +463 -19
  690. nautobot/project-static/docs/user-guide/platform-functionality/graphqlquery.html +463 -19
  691. nautobot/project-static/docs/user-guide/platform-functionality/imageattachment.html +463 -19
  692. nautobot/project-static/docs/user-guide/platform-functionality/jobs/index.html +472 -23
  693. nautobot/project-static/docs/user-guide/platform-functionality/jobs/job-scheduling-and-approvals.html +466 -22
  694. nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobbutton.html +466 -22
  695. nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobhook.html +463 -19
  696. nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobqueue.html +9224 -0
  697. nautobot/project-static/docs/user-guide/platform-functionality/jobs/kubernetes-job-support.html +9722 -0
  698. nautobot/project-static/docs/user-guide/platform-functionality/jobs/models.html +466 -22
  699. nautobot/project-static/docs/user-guide/platform-functionality/napalm.html +463 -19
  700. nautobot/project-static/docs/user-guide/platform-functionality/note.html +463 -19
  701. nautobot/project-static/docs/user-guide/platform-functionality/objectmetadata.html +463 -19
  702. nautobot/project-static/docs/user-guide/platform-functionality/relationship.html +467 -23
  703. nautobot/project-static/docs/user-guide/platform-functionality/rendering-jinja-templates.html +9292 -0
  704. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/authentication.html +463 -19
  705. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/filtering.html +511 -40
  706. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/overview.html +494 -23
  707. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/ui-related-endpoints.html +463 -19
  708. nautobot/project-static/docs/user-guide/platform-functionality/role.html +463 -19
  709. nautobot/project-static/docs/user-guide/platform-functionality/savedview.html +463 -19
  710. nautobot/project-static/docs/user-guide/platform-functionality/secret.html +463 -19
  711. nautobot/project-static/docs/user-guide/platform-functionality/staticgroupassociation.html +466 -22
  712. nautobot/project-static/docs/user-guide/platform-functionality/status.html +463 -19
  713. nautobot/project-static/docs/user-guide/platform-functionality/tag.html +463 -19
  714. nautobot/project-static/docs/user-guide/platform-functionality/template-filters.html +531 -56
  715. nautobot/project-static/docs/user-guide/platform-functionality/users/objectpermission.html +463 -19
  716. nautobot/project-static/docs/user-guide/platform-functionality/users/token.html +463 -19
  717. nautobot/project-static/docs/user-guide/platform-functionality/webhook.html +463 -19
  718. nautobot/project-static/img/jinja_logo.svg +97 -0
  719. nautobot/project-static/js/forms.js +6 -1
  720. nautobot/project-static/js/nav_menu.js +2 -1
  721. nautobot/tenancy/api/serializers.py +0 -2
  722. nautobot/tenancy/api/views.py +9 -13
  723. nautobot/tenancy/factory.py +1 -1
  724. nautobot/tenancy/navigation.py +0 -29
  725. nautobot/tenancy/templates/tenancy/tenant.html +4 -91
  726. nautobot/tenancy/tests/test_filters.py +29 -134
  727. nautobot/tenancy/views.py +35 -24
  728. nautobot/users/admin.py +3 -1
  729. nautobot/users/api/serializers.py +4 -4
  730. nautobot/users/api/views.py +3 -3
  731. nautobot/users/forms.py +19 -0
  732. nautobot/users/templates/users/preferences.html +22 -0
  733. nautobot/users/tests/test_filters.py +1 -19
  734. nautobot/users/tests/test_views.py +57 -0
  735. nautobot/users/utils.py +8 -0
  736. nautobot/users/views.py +48 -11
  737. nautobot/virtualization/api/serializers.py +4 -4
  738. nautobot/virtualization/api/views.py +5 -24
  739. nautobot/virtualization/filters.py +1 -2
  740. nautobot/virtualization/models.py +1 -1
  741. nautobot/virtualization/navigation.py +0 -48
  742. nautobot/virtualization/tables.py +2 -2
  743. nautobot/virtualization/templates/virtualization/cluster_edit.html +1 -7
  744. nautobot/virtualization/templates/virtualization/clustertype.html +0 -39
  745. nautobot/virtualization/templates/virtualization/virtualmachine.html +1 -9
  746. nautobot/virtualization/templates/virtualization/virtualmachine_edit.html +2 -8
  747. nautobot/virtualization/tests/test_filters.py +57 -166
  748. nautobot/virtualization/views.py +18 -15
  749. nautobot/wireless/__init__.py +0 -0
  750. nautobot/wireless/api/__init__.py +0 -0
  751. nautobot/wireless/api/serializers.py +44 -0
  752. nautobot/wireless/api/urls.py +20 -0
  753. nautobot/wireless/api/views.py +34 -0
  754. nautobot/wireless/apps.py +8 -0
  755. nautobot/wireless/choices.py +345 -0
  756. nautobot/wireless/factory.py +138 -0
  757. nautobot/wireless/filters.py +167 -0
  758. nautobot/wireless/forms.py +283 -0
  759. nautobot/wireless/homepage.py +19 -0
  760. nautobot/wireless/migrations/0001_initial.py +223 -0
  761. nautobot/wireless/migrations/__init__.py +0 -0
  762. nautobot/wireless/models.py +207 -0
  763. nautobot/wireless/navigation.py +105 -0
  764. nautobot/wireless/tables.py +244 -0
  765. nautobot/wireless/templates/wireless/radioprofile_retrieve.html +81 -0
  766. nautobot/wireless/templates/wireless/supporteddatarate_retrieve.html +26 -0
  767. nautobot/wireless/templates/wireless/wirelessnetwork_create.html +88 -0
  768. nautobot/wireless/templates/wireless/wirelessnetwork_retrieve.html +56 -0
  769. nautobot/wireless/tests/__init__.py +0 -0
  770. nautobot/wireless/tests/integration/__init__.py +0 -0
  771. nautobot/wireless/tests/integration/test_radio_profile.py +42 -0
  772. nautobot/wireless/tests/test_api.py +247 -0
  773. nautobot/wireless/tests/test_filters.py +82 -0
  774. nautobot/wireless/tests/test_models.py +22 -0
  775. nautobot/wireless/tests/test_views.py +378 -0
  776. nautobot/wireless/urls.py +13 -0
  777. nautobot/wireless/views.py +119 -0
  778. {nautobot-2.3.15b1.dist-info → nautobot-2.4.0.dist-info}/METADATA +11 -13
  779. {nautobot-2.3.15b1.dist-info → nautobot-2.4.0.dist-info}/RECORD +783 -613
  780. {nautobot-2.3.15b1.dist-info → nautobot-2.4.0.dist-info}/WHEEL +1 -1
  781. nautobot/core/fixtures/user-data.json +0 -59
  782. nautobot/core/utils/navigation.py +0 -54
  783. {nautobot-2.3.15b1.dist-info → nautobot-2.4.0.dist-info}/LICENSE.txt +0 -0
  784. {nautobot-2.3.15b1.dist-info → nautobot-2.4.0.dist-info}/NOTICE +0 -0
  785. {nautobot-2.3.15b1.dist-info → nautobot-2.4.0.dist-info}/entry_points.txt +0 -0
@@ -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:
@@ -732,13 +761,13 @@ class JobViewSet(
732
761
  ):
733
762
  lookup_value_regex = r"[-0-9a-fA-F]+"
734
763
 
735
- def perform_destroy(self, obj):
736
- if obj.module_name.startswith("nautobot."):
764
+ def perform_destroy(self, instance):
765
+ if instance.module_name.startswith("nautobot."):
737
766
  raise ProtectedError(
738
- f"Unable to delete Job {obj}. System Job cannot be deleted",
767
+ f"Unable to delete Job {instance}. System Job cannot be deleted",
739
768
  [],
740
769
  )
741
- super().perform_destroy(obj)
770
+ super().perform_destroy(instance)
742
771
 
743
772
 
744
773
  @extend_schema_view(
@@ -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
 
@@ -23,6 +23,7 @@ from nautobot.core.filters import (
23
23
  from nautobot.core.utils.deprecation import class_deprecated_in_favor_of
24
24
  from nautobot.dcim.models import DeviceRedundancyGroup, DeviceType, Location, Platform
25
25
  from nautobot.extras.choices import (
26
+ JobQueueTypeChoices,
26
27
  JobResultStatusChoices,
27
28
  MetadataTypeDataTypeChoices,
28
29
  RelationshipTypeChoices,
@@ -73,6 +74,8 @@ from nautobot.extras.models import (
73
74
  JobButton,
74
75
  JobHook,
75
76
  JobLogEntry,
77
+ JobQueue,
78
+ JobQueueAssignment,
76
79
  JobResult,
77
80
  MetadataChoice,
78
81
  MetadataType,
@@ -116,13 +119,13 @@ __all__ = (
116
119
  "CustomFieldDateFilter",
117
120
  "CustomFieldFilterMixin",
118
121
  "CustomFieldJSONFilter",
122
+ "CustomFieldModelFilterSet",
123
+ "CustomFieldModelFilterSetMixin",
119
124
  "CustomFieldMultiSelectFilter",
120
125
  "CustomFieldMultiValueCharFilter",
121
126
  "CustomFieldMultiValueDateFilter",
122
127
  "CustomFieldMultiValueNumberFilter",
123
128
  "CustomFieldNumberFilter",
124
- "CustomFieldModelFilterSet",
125
- "CustomFieldModelFilterSetMixin",
126
129
  "CustomLinkFilterSet",
127
130
  "DynamicGroupFilterSet",
128
131
  "DynamicGroupMembershipFilterSet",
@@ -133,23 +136,25 @@ __all__ = (
133
136
  "ImageAttachmentFilterSet",
134
137
  "JobFilterSet",
135
138
  "JobLogEntryFilterSet",
139
+ "JobQueueAssignmentFilterSet",
140
+ "JobQueueFilterSet",
136
141
  "JobResultFilterSet",
137
142
  "LocalContextFilterSet",
138
143
  "LocalContextModelFilterSetMixin",
139
- "MetadataTypeFilterSet",
140
144
  "MetadataChoiceFilterSet",
145
+ "MetadataTypeFilterSet",
141
146
  "NautobotFilterSet",
142
147
  "NoteFilterSet",
143
148
  "ObjectChangeFilterSet",
149
+ "RelationshipAssociationFilterSet",
144
150
  "RelationshipFilter",
145
151
  "RelationshipFilterSet",
146
- "RelationshipAssociationFilterSet",
147
152
  "RoleFilterSet",
148
153
  "RoleModelFilterSetMixin",
149
154
  "ScheduledJobFilterSet",
150
155
  "SecretFilterSet",
151
- "SecretsGroupFilterSet",
152
156
  "SecretsGroupAssociationFilterSet",
157
+ "SecretsGroupFilterSet",
153
158
  "StatusFilter",
154
159
  "StatusFilterSet",
155
160
  "StatusModelFilterSetMixin",
@@ -869,6 +874,7 @@ class JobFilterSet(BaseFilterSet, CustomFieldModelFilterSetMixin):
869
874
  "is_job_button_receiver",
870
875
  "soft_time_limit",
871
876
  "time_limit",
877
+ "is_singleton",
872
878
  "grouping_override",
873
879
  "name_override",
874
880
  "approval_required_override",
@@ -878,6 +884,7 @@ class JobFilterSet(BaseFilterSet, CustomFieldModelFilterSetMixin):
878
884
  "soft_time_limit_override",
879
885
  "time_limit_override",
880
886
  "has_sensitive_variables_override",
887
+ "is_singleton_override",
881
888
  "tags",
882
889
  ]
883
890
 
@@ -906,6 +913,60 @@ class JobHookFilterSet(BaseFilterSet):
906
913
  ]
907
914
 
908
915
 
916
+ class JobQueueFilterSet(NautobotFilterSet, TenancyModelFilterSetMixin):
917
+ q = SearchFilter(
918
+ filter_predicates={
919
+ "name": "icontains",
920
+ "queue_type": "icontains",
921
+ "description": "icontains",
922
+ "tenant__name": "icontains",
923
+ },
924
+ )
925
+ queue_type = django_filters.MultipleChoiceFilter(choices=JobQueueTypeChoices, null_value=None)
926
+ jobs = NaturalKeyOrPKMultipleChoiceFilter(
927
+ queryset=Job.objects.all(),
928
+ label="Job (name or ID)",
929
+ )
930
+ has_jobs = RelatedMembershipBooleanFilter(
931
+ field_name="jobs",
932
+ label="Has jobs",
933
+ )
934
+
935
+ class Meta:
936
+ model = JobQueue
937
+ fields = [
938
+ "id",
939
+ "name",
940
+ "description",
941
+ "tags",
942
+ ]
943
+
944
+
945
+ class JobQueueAssignmentFilterSet(BaseFilterSet):
946
+ q = SearchFilter(
947
+ filter_predicates={
948
+ "job__name": "icontains",
949
+ "job__grouping": "icontains",
950
+ "job__description": "icontains",
951
+ "job_queue__name": "icontains",
952
+ "job_queue__description": "icontains",
953
+ "job_queue__queue_type": "icontains",
954
+ }
955
+ )
956
+ job = NaturalKeyOrPKMultipleChoiceFilter(
957
+ queryset=Job.objects.all(),
958
+ label="Job (name or ID)",
959
+ )
960
+ job_queue = NaturalKeyOrPKMultipleChoiceFilter(
961
+ queryset=JobQueue.objects.all(),
962
+ label="Job Queue (name or ID)",
963
+ )
964
+
965
+ class Meta:
966
+ model = JobQueueAssignment
967
+ fields = ["id"]
968
+
969
+
909
970
  class JobResultFilterSet(BaseFilterSet, CustomFieldModelFilterSetMixin):
910
971
  q = SearchFilter(
911
972
  filter_predicates={
@@ -14,9 +14,9 @@ from .mixins import (
14
14
  )
15
15
 
16
16
  __all__ = (
17
- "NautobotModelForm",
18
- "NautobotFilterForm",
19
17
  "NautobotBulkEditForm",
18
+ "NautobotFilterForm",
19
+ "NautobotModelForm",
20
20
  )
21
21
 
22
22