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
@@ -7,7 +7,7 @@ from nautobot.extras.jobs import get_task_logger, Job, RunJobTaskFailed
7
7
  logger = get_task_logger(__name__)
8
8
 
9
9
 
10
- class TestFail(Job):
10
+ class TestFailJob(Job):
11
11
  """
12
12
  Job with fail result.
13
13
  """
@@ -15,7 +15,7 @@ class TestFail(Job):
15
15
  description = "Validate job import"
16
16
 
17
17
  def before_start(self, task_id, args, kwargs):
18
- if task_id != self.request.id:
18
+ if task_id != self.request.id: # pylint: disable=no-member
19
19
  raise RuntimeError(f"Expected task_id {task_id} to equal self.request.id {self.request.id}")
20
20
  if args:
21
21
  raise RuntimeError(f"Expected args to be empty, but it was {args!r}")
@@ -23,7 +23,7 @@ class TestFail(Job):
23
23
  raise RuntimeError(f"Expected kwargs to be empty, but it was {kwargs!r}")
24
24
  logger.info("before_start() was called as expected")
25
25
 
26
- def run(self):
26
+ def run(self): # pylint:disable=arguments-differ
27
27
  """
28
28
  Job function.
29
29
  """
@@ -71,7 +71,7 @@ class TestFailWithSanitization(Job):
71
71
 
72
72
  description = "Validate job failure sanitization"
73
73
 
74
- def run(self):
74
+ def run(self): # pylint:disable=arguments-differ
75
75
  logger.info("I'm a test job that fails and sanitizes the exception!")
76
76
  exc = RunJobTaskFailed(
77
77
  "fatal: could not read Password for 'https://abc123@github.com': terminal prompts disabled"
@@ -91,4 +91,4 @@ class TestFailWithSanitization(Job):
91
91
  raise exc
92
92
 
93
93
 
94
- register_jobs(TestFail, TestFailWithSanitization)
94
+ register_jobs(TestFailJob, TestFailWithSanitization)
@@ -9,7 +9,7 @@ class FileOutputJob(Job):
9
9
  name = "File Output job"
10
10
  description = "Creates a text file as output."
11
11
 
12
- def run(self, lines):
12
+ def run(self, lines): # pylint:disable=arguments-differ
13
13
  self.create_file("output.txt", "Hello World!\n" * lines)
14
14
 
15
15
 
@@ -21,7 +21,7 @@ class TestFileUploadFail(Job):
21
21
  description="File to upload",
22
22
  )
23
23
 
24
- def run(self, file):
24
+ def run(self, file): # pylint:disable=arguments-differ
25
25
  contents = str(file.read())
26
26
  logger.warning("File contents: %s", contents)
27
27
 
@@ -13,7 +13,7 @@ class TestFileUploadPass(Job):
13
13
  description="File to upload",
14
14
  )
15
15
 
16
- def run(self, file):
16
+ def run(self, file): # pylint:disable=arguments-differ
17
17
  contents = str(file.read())
18
18
  logger.warning("File contents: %s", contents)
19
19
  logger.info("Job didn't crash!")
@@ -39,7 +39,9 @@ class TestIPAddresses(Job):
39
39
  if kwargs[expected_kwarg] is None:
40
40
  raise RuntimeError(f"kwargs[{expected_kwarg}] is unexpectedly None!")
41
41
 
42
- def run(self, *, ipv4_address, ipv4_with_mask, ipv4_network, ipv6_address, ipv6_with_mask, ipv6_network):
42
+ def run( # pylint:disable=arguments-differ
43
+ self, *, ipv4_address, ipv4_with_mask, ipv4_network, ipv6_address, ipv6_with_mask, ipv6_network
44
+ ):
43
45
  if not isinstance(ipv4_address, netaddr.IPAddress):
44
46
  raise RuntimeError(f"Expected ipv4_address to be a netaddr.IPAddress, but it was {ipv4_address!r}")
45
47
  if not isinstance(ipv4_with_mask, netaddr.IPNetwork):
@@ -2,5 +2,5 @@ from nautobot.apps.jobs import Job
2
2
 
3
3
 
4
4
  class ChildJob(Job):
5
- def run(self):
5
+ def run(self): # pylint:disable=arguments-differ
6
6
  pass
@@ -15,7 +15,7 @@ class TestCreateLocationWithCustomField(Job):
15
15
  name = "Location and Custom Field Creation"
16
16
  description = "Location with a custom field"
17
17
 
18
- def run(self):
18
+ def run(self): # pylint: disable=arguments-differ
19
19
  with transaction.atomic():
20
20
  obj_type = ContentType.objects.get_for_model(Location)
21
21
  cf = CustomField(label="cf1", type=CustomFieldTypeChoices.TYPE_TEXT, default="-")
@@ -8,7 +8,7 @@ class TestLogRedaction(Job):
8
8
  class Meta:
9
9
  description = "Test redaction of logs"
10
10
 
11
- def run(self):
11
+ def run(self): # pylint: disable=arguments-differ
12
12
  logger.debug("The secret is supersecret123")
13
13
  logger.info("The secret is supersecret123")
14
14
  logger.warning("The secret is supersecret123")
@@ -8,7 +8,7 @@ class TestLogSkipDBLogging(Job):
8
8
  class Meta:
9
9
  description = "Test logs not being saved to the database"
10
10
 
11
- def run(self):
11
+ def run(self): # pylint: disable=arguments-differ
12
12
  logger.debug("I should NOT be logged to the database", extra={"skip_db_logging": True})
13
13
  logger.info("I should be logged to the database")
14
14
 
@@ -10,7 +10,7 @@ class TestModifyDB(Job):
10
10
  Job that modifies the database.
11
11
  """
12
12
 
13
- def run(self):
13
+ def run(self): # pylint: disable=arguments-differ
14
14
  """
15
15
  Job function.
16
16
  """
@@ -12,7 +12,7 @@ class TestOptionalObjectVar(Job):
12
12
  required=False,
13
13
  )
14
14
 
15
- def run(self, location=None):
15
+ def run(self, location=None): # pylint: disable=arguments-differ
16
16
  logger.info("The Location if any that the user provided.", extra={"object": location})
17
17
  return "Nice Location (or not)!"
18
18
 
@@ -12,7 +12,7 @@ class TestRequiredObjectVar(Job):
12
12
  required=True,
13
13
  )
14
14
 
15
- def run(self, location):
15
+ def run(self, location): # pylint: disable=arguments-differ
16
16
  logger.info("The Location that the user provided.", extra={"object": location})
17
17
  return "Nice Location!"
18
18
 
@@ -13,7 +13,7 @@ class TestObjectVars(Job):
13
13
  role = ObjectVar(model=Role)
14
14
  roles = MultiObjectVar(model=Role)
15
15
 
16
- def run(self, role, roles):
16
+ def run(self, role, roles): # pylint: disable=arguments-differ
17
17
  logger.info("Role: %s", role)
18
18
  logger.warning("Roles: %s", roles)
19
19
 
@@ -5,7 +5,7 @@ from nautobot.extras.jobs import get_task_logger, Job
5
5
  logger = get_task_logger(__name__)
6
6
 
7
7
 
8
- class TestPass(Job):
8
+ class TestPassJob(Job):
9
9
  """
10
10
  Job with pass result.
11
11
  """
@@ -24,7 +24,7 @@ class TestPass(Job):
24
24
  raise RuntimeError(f"Expected kwargs to be empty, but it was {kwargs!r}")
25
25
  logger.info("before_start() was called as expected")
26
26
 
27
- def run(self):
27
+ def run(self): # pylint: disable=arguments-differ
28
28
  """
29
29
  Job function.
30
30
  """
@@ -61,4 +61,4 @@ class TestPass(Job):
61
61
  logger.info("after_return() was called as expected")
62
62
 
63
63
 
64
- register_jobs(TestPass)
64
+ register_jobs(TestPassJob)
@@ -14,7 +14,7 @@ class TestProfilingJob(Job):
14
14
 
15
15
  description = "Test profiling"
16
16
 
17
- def run(self):
17
+ def run(self): # pylint: disable=arguments-differ
18
18
  """
19
19
  Job function.
20
20
  """
@@ -1,10 +1,10 @@
1
- from fail import TestFail # pylint: disable=import-error
1
+ from fail import TestFailJob # pylint: disable=import-error
2
2
 
3
3
  from nautobot.apps.jobs import register_jobs
4
4
 
5
5
 
6
- class TestReallyPass(TestFail):
7
- def run(self):
6
+ class TestReallyPass(TestFailJob):
7
+ def run(self): # pylint: disable=arguments-differ
8
8
  pass
9
9
 
10
10
 
@@ -0,0 +1,16 @@
1
+ import time
2
+
3
+ from nautobot.core.celery import register_jobs
4
+ from nautobot.extras.jobs import Job
5
+
6
+
7
+ class TestSingletonJob(Job):
8
+ class Meta:
9
+ name = "Example Singleton Job"
10
+ is_singleton = True
11
+
12
+ def run(self, *args, **kwargs):
13
+ time.sleep(1)
14
+
15
+
16
+ register_jobs(TestSingletonJob)
@@ -8,7 +8,7 @@ class TestSoftTimeLimitGreaterThanHardTimeLimit(Job):
8
8
  soft_time_limit = 10
9
9
  time_limit = 5
10
10
 
11
- def run(self):
11
+ def run(self): # pylint: disable=arguments-differ
12
12
  pass
13
13
 
14
14
 
@@ -16,7 +16,7 @@ class TestWorkerQueues(Job):
16
16
  "nonexistent", # This queue doesn't exist and should have zero workers
17
17
  ]
18
18
 
19
- def run(self):
19
+ def run(self): # pylint: disable=arguments-differ
20
20
  pass
21
21
 
22
22
 
@@ -4,8 +4,6 @@ from nautobot.core.testing.integration import SeleniumTestCase
4
4
  class PluginBannerTestCase(SeleniumTestCase):
5
5
  """Integration test for rendering of plugin-injected banner content."""
6
6
 
7
- fixtures = ("user-data",)
8
-
9
7
  def test_banner_not_rendered(self):
10
8
  """As implemented, plugin banner does not render if the user is not logged in.
11
9
 
@@ -2,6 +2,7 @@ from datetime import datetime, timedelta
2
2
  import tempfile
3
3
  from unittest import mock, skip
4
4
  import uuid
5
+ from zoneinfo import ZoneInfo
5
6
 
6
7
  from django.conf import settings
7
8
  from django.contrib.auth import get_user_model
@@ -12,11 +13,6 @@ from django.urls import reverse
12
13
  from django.utils.timezone import make_aware, now
13
14
  from rest_framework import status
14
15
 
15
- try:
16
- from zoneinfo import ZoneInfo
17
- except ImportError: # Python 3.8
18
- from backports.zoneinfo import ZoneInfo
19
-
20
16
  from nautobot.core.choices import ColorChoices
21
17
  from nautobot.core.models.fields import slugify_dashes_to_underscores
22
18
  from nautobot.core.testing import APITestCase, APIViewTestCases
@@ -25,6 +21,7 @@ from nautobot.core.utils.lookup import get_route_for_model
25
21
  from nautobot.core.utils.permissions import get_permission_for_model
26
22
  from nautobot.dcim.models import (
27
23
  Controller,
24
+ ControllerManagedDeviceGroup,
28
25
  Device,
29
26
  DeviceType,
30
27
  Location,
@@ -39,6 +36,7 @@ from nautobot.extras.choices import (
39
36
  DynamicGroupOperatorChoices,
40
37
  DynamicGroupTypeChoices,
41
38
  JobExecutionType,
39
+ JobQueueTypeChoices,
42
40
  JobResultStatusChoices,
43
41
  MetadataTypeDataTypeChoices,
44
42
  ObjectChangeActionChoices,
@@ -67,6 +65,8 @@ from nautobot.extras.models import (
67
65
  ImageAttachment,
68
66
  Job,
69
67
  JobLogEntry,
68
+ JobQueue,
69
+ JobQueueAssignment,
70
70
  JobResult,
71
71
  MetadataChoice,
72
72
  MetadataType,
@@ -1341,37 +1341,6 @@ class JobTest(
1341
1341
 
1342
1342
  model = Job
1343
1343
  choices_fields = None
1344
- update_data = {
1345
- # source, module_name, job_class_name, installed are NOT editable
1346
- "grouping_override": True,
1347
- "grouping": "Overridden grouping",
1348
- "name_override": True,
1349
- "name": "Overridden name",
1350
- "description_override": True,
1351
- "description": "This is an overridden description.",
1352
- "enabled": True,
1353
- "approval_required_override": True,
1354
- "approval_required": True,
1355
- "dryrun_default_override": True,
1356
- "dryrun_default": True,
1357
- "hidden_override": True,
1358
- "hidden": True,
1359
- "soft_time_limit_override": True,
1360
- "soft_time_limit": 350.1,
1361
- "time_limit_override": True,
1362
- "time_limit": 650,
1363
- "has_sensitive_variables": False,
1364
- "has_sensitive_variables_override": True,
1365
- "task_queues": ["default", "priority"],
1366
- "task_queues_override": True,
1367
- }
1368
- bulk_update_data = {
1369
- "enabled": True,
1370
- "approval_required_override": True,
1371
- "approval_required": True,
1372
- "has_sensitive_variables": False,
1373
- "has_sensitive_variables_override": True,
1374
- }
1375
1344
 
1376
1345
  def setUp(self):
1377
1346
  super().setUp()
@@ -1382,6 +1351,38 @@ class JobTest(
1382
1351
  self.job_model.enabled = True
1383
1352
  self.job_model.validated_save()
1384
1353
 
1354
+ @classmethod
1355
+ def setUpTestData(cls):
1356
+ cls.update_data = {
1357
+ # source, module_name, job_class_name, installed are NOT editable
1358
+ "grouping_override": True,
1359
+ "grouping": "Overridden grouping",
1360
+ "name_override": True,
1361
+ "name": "Overridden name",
1362
+ "description_override": True,
1363
+ "description": "This is an overridden description.",
1364
+ "enabled": True,
1365
+ "approval_required_override": True,
1366
+ "approval_required": True,
1367
+ "dryrun_default_override": True,
1368
+ "dryrun_default": True,
1369
+ "hidden_override": True,
1370
+ "hidden": True,
1371
+ "soft_time_limit_override": True,
1372
+ "soft_time_limit": 350.1,
1373
+ "time_limit_override": True,
1374
+ "time_limit": 650,
1375
+ "has_sensitive_variables": False,
1376
+ "has_sensitive_variables_override": True,
1377
+ }
1378
+ cls.bulk_update_data = {
1379
+ "enabled": True,
1380
+ "approval_required_override": True,
1381
+ "approval_required": True,
1382
+ "has_sensitive_variables": False,
1383
+ "has_sensitive_variables_override": True,
1384
+ }
1385
+
1385
1386
  run_success_response_status = status.HTTP_201_CREATED
1386
1387
 
1387
1388
  def get_run_url(self, class_path="api_test_job.APITestJob"):
@@ -1535,10 +1536,10 @@ class JobTest(
1535
1536
  self.assertHttpStatus(response, status.HTTP_404_NOT_FOUND)
1536
1537
 
1537
1538
  # Try post to permitted job
1538
- job_model = Job.objects.get_for_class_path("pass.TestPass")
1539
+ job_model = Job.objects.get_for_class_path("pass.TestPassJob")
1539
1540
  job_model.enabled = True
1540
1541
  job_model.validated_save()
1541
- url = self.get_run_url("pass.TestPass")
1542
+ url = self.get_run_url("pass.TestPassJob")
1542
1543
  response = self.client.post(url, **self.header)
1543
1544
  self.assertHttpStatus(response, self.run_success_response_status)
1544
1545
 
@@ -1572,6 +1573,7 @@ class JobTest(
1572
1573
  name="No such job",
1573
1574
  installed=False,
1574
1575
  enabled=True,
1576
+ default_job_queue=JobQueue.objects.get(name="default", queue_type=JobQueueTypeChoices.TYPE_CELERY),
1575
1577
  )
1576
1578
  job_model.validated_save()
1577
1579
 
@@ -1586,6 +1588,11 @@ class JobTest(
1586
1588
  """Job run cannot be requested if Celery is not running."""
1587
1589
  mock_get_worker_count.return_value = 0
1588
1590
  self.add_permissions("extras.run_job")
1591
+ class_path = "api_test_job.APITestJob"
1592
+ job_model = Job.objects.get_for_class_path(class_path)
1593
+ # Make sure no queues are associated with it so it is using the celery default queue.
1594
+ # And the error message is deterministic on line 1573
1595
+ job_model.job_queues.set([])
1589
1596
  device_role = Role.objects.get_for_model(Device).first()
1590
1597
  job_data = {
1591
1598
  "var1": "FooBar",
@@ -1602,7 +1609,8 @@ class JobTest(
1602
1609
  response = self.client.post(url, data, format="json", **self.header)
1603
1610
  self.assertHttpStatus(response, status.HTTP_503_SERVICE_UNAVAILABLE)
1604
1611
  self.assertEqual(
1605
- response.data["detail"], "Unable to process request: No celery workers running on queue default."
1612
+ response.data["detail"],
1613
+ f"Unable to process request: No celery workers running on queue {job_model.default_job_queue.name}.",
1606
1614
  )
1607
1615
 
1608
1616
  @override_settings(EXEMPT_VIEW_PERMISSIONS=["*"])
@@ -1710,6 +1718,7 @@ class JobTest(
1710
1718
  # This handles things like ObjectVar fields looked up by non-UUID
1711
1719
  # Jobs are executed with deserialized data
1712
1720
  deserialized_data = self.job_class.deserialize_data(job_data)
1721
+ self.job_model.job_queues.set([])
1713
1722
 
1714
1723
  self.assertEqual(
1715
1724
  deserialized_data,
@@ -1723,7 +1732,7 @@ class JobTest(
1723
1732
  # Ensure the enqueue_job args deserialize to the same as originally inputted
1724
1733
  expected_enqueue_job_args = (self.job_model, self.user)
1725
1734
  expected_enqueue_job_kwargs = {
1726
- "task_queue": settings.CELERY_TASK_DEFAULT_QUEUE,
1735
+ "task_queue": self.job_model.default_job_queue.name,
1727
1736
  **self.job_class.serialize_data(deserialized_data),
1728
1737
  }
1729
1738
  mock_enqueue_job.assert_called_with(*expected_enqueue_job_args, **expected_enqueue_job_kwargs)
@@ -1746,7 +1755,7 @@ class JobTest(
1746
1755
  response = self.client.post(url, {"data": job_data}, format="json", **self.header)
1747
1756
  self.assertHttpStatus(response, self.run_success_response_status)
1748
1757
 
1749
- job_result = JobResult.objects.get(name=self.job_model.name)
1758
+ job_result = JobResult.objects.filter(name=self.job_model.name).latest()
1750
1759
 
1751
1760
  self.assertIn("scheduled_job", response.data)
1752
1761
  self.assertIn("job_result", response.data)
@@ -1755,6 +1764,36 @@ class JobTest(
1755
1764
  expected_data_job_result = JobResultSerializer(job_result, context={"request": response.wsgi_request}).data
1756
1765
  self.assertEqual(data_job_result, expected_data_job_result)
1757
1766
 
1767
+ @override_settings(EXEMPT_VIEW_PERMISSIONS=["*"])
1768
+ @mock.patch("nautobot.extras.api.views.get_worker_count")
1769
+ def test_run_job_with_both_task_queue_and_job_queue_specified(self, mock_get_worker_count):
1770
+ """Test job run response contains nested job result."""
1771
+ mock_get_worker_count.return_value = 1
1772
+ self.add_permissions("extras.run_job")
1773
+ device_role = Role.objects.get_for_model(Device).first()
1774
+ job_data = {
1775
+ "var1": "FooBar",
1776
+ "var2": 123,
1777
+ "var3": False,
1778
+ "var4": {"name": device_role.name},
1779
+ }
1780
+
1781
+ url = self.get_run_url()
1782
+ response = self.client.post(
1783
+ url,
1784
+ {
1785
+ "data": job_data,
1786
+ "task_queue": "default",
1787
+ "job_queue": "default",
1788
+ },
1789
+ format="json",
1790
+ **self.header,
1791
+ )
1792
+ self.assertHttpStatus(response, status.HTTP_400_BAD_REQUEST)
1793
+ self.assertIn(
1794
+ "task_queue and job_queue are both specified. Please specifiy only one or another.", str(response.content)
1795
+ )
1796
+
1758
1797
  @override_settings(EXEMPT_VIEW_PERMISSIONS=["*"])
1759
1798
  @mock.patch("nautobot.extras.api.views.get_worker_count")
1760
1799
  def test_run_job_file_data_commit(self, mock_get_worker_count):
@@ -2078,23 +2117,27 @@ class JobTest(
2078
2117
  "data": {"var1": "x", "var2": 1, "var3": False, "var4": d.pk},
2079
2118
  "task_queue": settings.CELERY_TASK_DEFAULT_QUEUE,
2080
2119
  }
2081
-
2120
+ jq, _ = JobQueue.objects.get_or_create(
2121
+ name=settings.CELERY_TASK_DEFAULT_QUEUE, defaults={"queue_type": JobQueueTypeChoices.TYPE_CELERY}
2122
+ )
2123
+ self.job_model.job_queues.set([jq])
2082
2124
  url = self.get_run_url()
2083
2125
  response = self.client.post(url, data, format="json", **self.header)
2084
2126
  self.assertHttpStatus(response, self.run_success_response_status)
2085
2127
 
2086
2128
  @override_settings(EXEMPT_VIEW_PERMISSIONS=[])
2087
2129
  @mock.patch("nautobot.extras.api.views.get_worker_count", return_value=1)
2088
- def test_run_job_with_default_queue_with_empty_job_model_task_queues(self, _):
2130
+ def test_run_job_with_default_queue_with_empty_job_model_job_queues(self, _):
2089
2131
  self.add_permissions("extras.run_job")
2132
+ job_model = Job.objects.get_for_class_path("pass.TestPassJob")
2090
2133
  data = {
2091
- "task_queue": settings.CELERY_TASK_DEFAULT_QUEUE,
2134
+ "task_queue": job_model.default_job_queue.name,
2092
2135
  }
2093
2136
 
2094
- job_model = Job.objects.get_for_class_path("pass.TestPass")
2137
+ job_model.job_queues.set([])
2095
2138
  job_model.enabled = True
2096
2139
  job_model.validated_save()
2097
- url = self.get_run_url("pass.TestPass")
2140
+ url = self.get_run_url("pass.TestPassJob")
2098
2141
  response = self.client.post(url, data, format="json", **self.header)
2099
2142
  self.assertHttpStatus(response, self.run_success_response_status)
2100
2143
 
@@ -2352,6 +2395,62 @@ class JobLogEntryTest(
2352
2395
  self.assertEqual(len(response.json()), JobLogEntry.objects.filter(job_result=self.job_result).count())
2353
2396
 
2354
2397
 
2398
+ class JobQueueTestCase(APIViewTestCases.APIViewTestCase):
2399
+ model = JobQueue
2400
+ choices_fields = ["queue_type"]
2401
+
2402
+ def setUp(self):
2403
+ super().setUp()
2404
+ self.create_data = [
2405
+ {
2406
+ "name": "Test API Job Queue 1",
2407
+ "queue_type": JobQueueTypeChoices.TYPE_CELERY,
2408
+ "description": "Job Queue 1 for API Testing",
2409
+ "tenant": Tenant.objects.first().pk,
2410
+ },
2411
+ {
2412
+ "name": "Test API Job Queue 2",
2413
+ "queue_type": JobQueueTypeChoices.TYPE_KUBERNETES,
2414
+ "description": "Job Queue 2 for API Testing",
2415
+ "tenant": Tenant.objects.first().pk,
2416
+ },
2417
+ {
2418
+ "name": "Test API Job Queue 3",
2419
+ "queue_type": JobQueueTypeChoices.TYPE_CELERY,
2420
+ "description": "Job Queue 3 for API Testing",
2421
+ "tenant": Tenant.objects.last().pk,
2422
+ "tags": [tag.pk for tag in Tag.objects.get_for_model(JobQueue)],
2423
+ },
2424
+ ]
2425
+
2426
+
2427
+ class JobQueueAssignmentTestCase(APIViewTestCases.APIViewTestCase):
2428
+ model = JobQueueAssignment
2429
+
2430
+ def setUp(self):
2431
+ super().setUp()
2432
+ jobs = Job.objects.all()[:3]
2433
+ job_queues = JobQueue.objects.all()[:3]
2434
+ JobQueueAssignment.objects.all().delete()
2435
+ JobQueueAssignment.objects.create(job=jobs[0], job_queue=job_queues[0])
2436
+ JobQueueAssignment.objects.create(job=jobs[1], job_queue=job_queues[1])
2437
+ JobQueueAssignment.objects.create(job=jobs[2], job_queue=job_queues[2])
2438
+ self.create_data = [
2439
+ {
2440
+ "job": jobs[0].pk,
2441
+ "job_queue": job_queues[1].pk,
2442
+ },
2443
+ {
2444
+ "job": jobs[1].pk,
2445
+ "job_queue": job_queues[2].pk,
2446
+ },
2447
+ {
2448
+ "job": jobs[0].pk,
2449
+ "job_queue": job_queues[2].pk,
2450
+ },
2451
+ ]
2452
+
2453
+
2355
2454
  class SavedViewTest(APIViewTestCases.APIViewTestCase):
2356
2455
  model = SavedView
2357
2456
 
@@ -2465,10 +2564,10 @@ class ScheduledJobTest(
2465
2564
  @classmethod
2466
2565
  def setUpTestData(cls):
2467
2566
  user = User.objects.create(username="user1", is_active=True)
2468
- job_model = Job.objects.get_for_class_path("pass.TestPass")
2567
+ job_model = Job.objects.get_for_class_path("pass.TestPassJob")
2469
2568
  ScheduledJob.objects.create(
2470
2569
  name="test1",
2471
- task="pass.TestPass",
2570
+ task="pass.TestPassJob",
2472
2571
  job_model=job_model,
2473
2572
  interval=JobExecutionType.TYPE_IMMEDIATELY,
2474
2573
  user=user,
@@ -2477,7 +2576,7 @@ class ScheduledJobTest(
2477
2576
  )
2478
2577
  ScheduledJob.objects.create(
2479
2578
  name="test2",
2480
- task="pass.TestPass",
2579
+ task="pass.TestPassJob",
2481
2580
  job_model=job_model,
2482
2581
  interval=JobExecutionType.TYPE_DAILY,
2483
2582
  user=user,
@@ -2487,7 +2586,7 @@ class ScheduledJobTest(
2487
2586
  )
2488
2587
  ScheduledJob.objects.create(
2489
2588
  name="test3",
2490
- task="pass.TestPass",
2589
+ task="pass.TestPassJob",
2491
2590
  job_model=job_model,
2492
2591
  interval=JobExecutionType.TYPE_CUSTOM,
2493
2592
  crontab="34 12 * * *",
@@ -2502,12 +2601,12 @@ class JobApprovalTest(APITestCase):
2502
2601
  @classmethod
2503
2602
  def setUpTestData(cls):
2504
2603
  cls.additional_user = User.objects.create(username="user1", is_active=True)
2505
- cls.job_model = Job.objects.get_for_class_path("pass.TestPass")
2604
+ cls.job_model = Job.objects.get_for_class_path("pass.TestPassJob")
2506
2605
  cls.job_model.enabled = True
2507
2606
  cls.job_model.save()
2508
2607
  cls.scheduled_job = ScheduledJob.objects.create(
2509
2608
  name="test pass",
2510
- task="pass.TestPass",
2609
+ task="pass.TestPassJob",
2511
2610
  job_model=cls.job_model,
2512
2611
  interval=JobExecutionType.TYPE_IMMEDIATELY,
2513
2612
  user=cls.additional_user,
@@ -2560,7 +2659,7 @@ class JobApprovalTest(APITestCase):
2560
2659
  self.add_permissions("extras.approve_job", "extras.view_scheduledjob", "extras.change_scheduledjob")
2561
2660
  scheduled_job = ScheduledJob.objects.create(
2562
2661
  name="test",
2563
- task="pass.TestPass",
2662
+ task="pass.TestPassJob",
2564
2663
  job_model=self.job_model,
2565
2664
  interval=JobExecutionType.TYPE_IMMEDIATELY,
2566
2665
  user=self.user,
@@ -2583,7 +2682,7 @@ class JobApprovalTest(APITestCase):
2583
2682
  self.add_permissions("extras.approve_job", "extras.view_scheduledjob", "extras.change_scheduledjob")
2584
2683
  scheduled_job = ScheduledJob.objects.create(
2585
2684
  name="test",
2586
- task="pass.TestPass",
2685
+ task="pass.TestPassJob",
2587
2686
  job_model=self.job_model,
2588
2687
  interval=JobExecutionType.TYPE_FUTURE,
2589
2688
  one_off=True,
@@ -2600,7 +2699,7 @@ class JobApprovalTest(APITestCase):
2600
2699
  self.add_permissions("extras.approve_job", "extras.view_scheduledjob", "extras.change_scheduledjob")
2601
2700
  scheduled_job = ScheduledJob.objects.create(
2602
2701
  name="test",
2603
- task="pass.TestPass",
2702
+ task="pass.TestPassJob",
2604
2703
  job_model=self.job_model,
2605
2704
  interval=JobExecutionType.TYPE_FUTURE,
2606
2705
  one_off=True,
@@ -2761,6 +2860,8 @@ class ObjectMetadataTest(APIViewTestCases.APIViewTestCase):
2761
2860
 
2762
2861
  @classmethod
2763
2862
  def setUpTestData(cls):
2863
+ # Delete existing metadata objects to avoid conflicts with generate_test_data randomness.
2864
+ ObjectMetadata.objects.all().delete()
2764
2865
  mdts = [
2765
2866
  MetadataType.objects.create(name="Location Metadata Type", data_type=MetadataTypeDataTypeChoices.TYPE_TEXT),
2766
2867
  MetadataType.objects.create(name="Device Metadata Type", data_type=MetadataTypeDataTypeChoices.TYPE_TEXT),
@@ -3215,6 +3316,7 @@ class RelationshipTest(APIViewTestCases.APIViewTestCase, RequiredRelationshipTes
3215
3316
  IPAddress.objects.all().delete()
3216
3317
  Prefix.objects.update(parent=None)
3217
3318
  Prefix.objects.all().delete()
3319
+ ControllerManagedDeviceGroup.objects.all().delete()
3218
3320
  VLAN.objects.all().delete()
3219
3321
 
3220
3322
  # Parameterized tests (for creating and updating single objects):