nautobot 2.3.16__py3-none-any.whl → 2.4.0b1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of nautobot might be problematic. Click here for more details.

Files changed (675) hide show
  1. nautobot/__init__.py +15 -0
  2. nautobot/apps/api.py +0 -2
  3. nautobot/apps/config.py +32 -3
  4. nautobot/apps/events.py +19 -0
  5. nautobot/apps/exceptions.py +0 -2
  6. nautobot/apps/ui.py +44 -9
  7. nautobot/apps/utils.py +0 -8
  8. nautobot/apps/views.py +2 -0
  9. nautobot/circuits/navigation.py +0 -57
  10. nautobot/circuits/tables.py +1 -2
  11. nautobot/circuits/templates/circuits/circuit_retrieve.html +0 -71
  12. nautobot/circuits/templates/circuits/inc/circuit_termination.html +6 -64
  13. nautobot/circuits/templates/circuits/inc/circuit_termination_cable_fragment.html +40 -0
  14. nautobot/circuits/templates/circuits/inc/circuit_termination_header_extra_content.html +26 -0
  15. nautobot/circuits/templates/circuits/provider_retrieve.html +0 -76
  16. nautobot/circuits/tests/integration/test_relationships.py +33 -24
  17. nautobot/circuits/tests/test_filters.py +4 -8
  18. nautobot/circuits/views.py +143 -26
  19. nautobot/cloud/factory.py +4 -1
  20. nautobot/cloud/models.py +1 -1
  21. nautobot/cloud/tests/test_filters.py +5 -4
  22. nautobot/core/api/fields.py +5 -5
  23. nautobot/core/api/metadata.py +28 -256
  24. nautobot/core/api/pagination.py +3 -2
  25. nautobot/core/api/renderers.py +3 -0
  26. nautobot/core/api/serializers.py +24 -244
  27. nautobot/core/api/urls.py +3 -4
  28. nautobot/core/api/utils.py +0 -62
  29. nautobot/core/api/views.py +48 -158
  30. nautobot/core/apps/__init__.py +22 -578
  31. nautobot/core/celery/__init__.py +13 -0
  32. nautobot/core/celery/log.py +4 -4
  33. nautobot/core/celery/schedulers.py +48 -3
  34. nautobot/core/cli/__init__.py +8 -0
  35. nautobot/core/constants.py +7 -0
  36. nautobot/core/events/__init__.py +116 -0
  37. nautobot/core/events/base.py +27 -0
  38. nautobot/core/events/exceptions.py +10 -0
  39. nautobot/core/events/redis_broker.py +48 -0
  40. nautobot/core/events/syslog_broker.py +19 -0
  41. nautobot/core/exceptions.py +0 -6
  42. nautobot/core/filters.py +16 -21
  43. nautobot/core/fixtures/user-data.json +59 -0
  44. nautobot/core/forms/fields.py +53 -8
  45. nautobot/core/forms/utils.py +2 -1
  46. nautobot/core/graphql/schema.py +3 -1
  47. nautobot/core/graphql/types.py +1 -1
  48. nautobot/core/jobs/__init__.py +4 -4
  49. nautobot/core/jobs/cleanup.py +13 -49
  50. nautobot/core/jobs/groups.py +1 -1
  51. nautobot/core/management/commands/generate_test_data.py +21 -0
  52. nautobot/core/management/commands/validate_models.py +1 -1
  53. nautobot/core/middleware.py +16 -0
  54. nautobot/core/models/__init__.py +1 -1
  55. nautobot/core/models/fields.py +11 -7
  56. nautobot/core/models/query_functions.py +2 -2
  57. nautobot/core/models/tree_queries.py +3 -6
  58. nautobot/core/settings.py +44 -7
  59. nautobot/core/settings.yaml +86 -8
  60. nautobot/core/tables.py +15 -65
  61. nautobot/core/tasks.py +1 -1
  62. nautobot/core/templates/components/button/default.html +7 -0
  63. nautobot/core/templates/components/button/dropdown.html +20 -0
  64. nautobot/core/templates/components/layout/one_over_two.html +19 -0
  65. nautobot/core/templates/components/layout/two_over_one.html +19 -0
  66. nautobot/core/templates/components/panel/body_content_data_table.html +27 -0
  67. nautobot/core/templates/components/panel/body_content_objects_table.html +4 -0
  68. nautobot/core/templates/components/panel/body_content_tags.html +6 -0
  69. nautobot/core/templates/components/panel/body_content_text.html +12 -0
  70. nautobot/core/templates/components/panel/body_wrapper_generic.html +3 -0
  71. nautobot/core/templates/components/panel/body_wrapper_key_value_table.html +3 -0
  72. nautobot/core/templates/components/panel/body_wrapper_table.html +3 -0
  73. nautobot/core/templates/components/panel/footer_contacts_table.html +20 -0
  74. nautobot/core/templates/components/panel/footer_content_table.html +14 -0
  75. nautobot/core/templates/components/panel/grouping_toggle.html +14 -0
  76. nautobot/core/templates/components/panel/header_extra_content_table.html +3 -0
  77. nautobot/core/templates/components/panel/panel.html +16 -0
  78. nautobot/core/templates/components/panel/stats_panel_body.html +8 -0
  79. nautobot/core/templates/components/tab/content_wrapper.html +3 -0
  80. nautobot/core/templates/components/tab/label_wrapper.html +5 -0
  81. nautobot/core/templates/components/tab/label_wrapper_distinct_view.html +3 -0
  82. nautobot/core/templates/generic/object_retrieve.html +28 -17
  83. nautobot/core/templates/inc/computed_fields/panel_data.html +4 -7
  84. nautobot/core/templates/inc/custom_fields/panel.html +2 -2
  85. nautobot/core/templates/inc/custom_fields/panel_data.html +4 -7
  86. nautobot/core/templates/inc/footer.html +1 -0
  87. nautobot/core/templates/inc/media.html +0 -3
  88. nautobot/core/templates/inc/nav_menu.html +1 -1
  89. nautobot/core/templates/inc/relationships_panel.html +1 -1
  90. nautobot/core/templates/nautobot_config.py.j2 +3 -3
  91. nautobot/core/templates/panel_table.html +12 -0
  92. nautobot/core/templates/search.html +0 -7
  93. nautobot/core/templates/utilities/render_jinja2.html +117 -0
  94. nautobot/core/templatetags/helpers.py +101 -12
  95. nautobot/core/templatetags/ui_framework.py +40 -0
  96. nautobot/core/testing/api.py +23 -128
  97. nautobot/core/testing/context.py +18 -0
  98. nautobot/core/testing/filters.py +41 -58
  99. nautobot/core/testing/mixins.py +2 -7
  100. nautobot/core/testing/views.py +25 -123
  101. nautobot/core/tests/integration/test_app_home.py +1 -0
  102. nautobot/core/tests/integration/test_app_navbar.py +1 -0
  103. nautobot/core/tests/integration/test_filters.py +2 -0
  104. nautobot/core/tests/integration/test_home.py +1 -0
  105. nautobot/core/tests/integration/test_navbar.py +1 -0
  106. nautobot/core/tests/integration/test_view_authentication.py +1 -2
  107. nautobot/core/tests/nautobot_config.py +198 -0
  108. nautobot/core/tests/runner.py +3 -3
  109. nautobot/core/tests/test_api.py +82 -201
  110. nautobot/core/tests/test_csv.py +3 -25
  111. nautobot/core/tests/test_events.py +214 -0
  112. nautobot/core/tests/test_jinja_filters.py +1 -0
  113. nautobot/core/tests/test_jobs.py +84 -13
  114. nautobot/core/tests/test_navigations.py +7 -241
  115. nautobot/core/tests/test_templatetags_helpers.py +16 -0
  116. nautobot/core/tests/test_ui.py +150 -0
  117. nautobot/core/tests/test_utils.py +0 -25
  118. nautobot/core/tests/test_views.py +123 -31
  119. nautobot/core/ui/__init__.py +0 -0
  120. nautobot/core/ui/base.py +11 -0
  121. nautobot/core/ui/choices.py +44 -0
  122. nautobot/core/ui/homepage.py +167 -0
  123. nautobot/core/ui/nav.py +279 -0
  124. nautobot/core/ui/object_detail.py +1841 -0
  125. nautobot/core/ui/utils.py +36 -0
  126. nautobot/core/urls.py +4 -9
  127. nautobot/core/utils/config.py +30 -3
  128. nautobot/core/utils/lookup.py +20 -13
  129. nautobot/core/views/__init__.py +6 -1
  130. nautobot/core/views/generic.py +47 -52
  131. nautobot/core/views/mixins.py +15 -25
  132. nautobot/core/views/paginator.py +8 -5
  133. nautobot/core/views/renderers.py +3 -3
  134. nautobot/core/views/utils.py +11 -0
  135. nautobot/core/wsgi.py +3 -3
  136. nautobot/dcim/api/serializers.py +80 -179
  137. nautobot/dcim/api/urls.py +5 -0
  138. nautobot/dcim/api/views.py +17 -4
  139. nautobot/dcim/apps.py +1 -0
  140. nautobot/dcim/choices.py +28 -0
  141. nautobot/dcim/factory.py +58 -0
  142. nautobot/dcim/filters/__init__.py +197 -24
  143. nautobot/dcim/forms.py +203 -12
  144. nautobot/dcim/graphql/types.py +2 -2
  145. nautobot/dcim/migrations/0063_interfacevdcassignment_virtualdevicecontext_and_more.py +165 -0
  146. nautobot/dcim/migrations/0064_virtualdevicecontext_status_data_migration.py +28 -0
  147. nautobot/dcim/migrations/0065_controller_capabilities_and_more.py +29 -0
  148. nautobot/dcim/migrations/0066_controllermanageddevicegroup_radio_profiles_and_more.py +33 -0
  149. nautobot/dcim/models/__init__.py +4 -0
  150. nautobot/dcim/models/device_component_templates.py +2 -2
  151. nautobot/dcim/models/device_components.py +20 -22
  152. nautobot/dcim/models/devices.py +173 -4
  153. nautobot/dcim/models/locations.py +3 -3
  154. nautobot/dcim/models/power.py +5 -6
  155. nautobot/dcim/models/racks.py +6 -6
  156. nautobot/dcim/navigation.py +25 -224
  157. nautobot/dcim/signals.py +44 -0
  158. nautobot/dcim/tables/__init__.py +5 -3
  159. nautobot/dcim/tables/devices.py +96 -2
  160. nautobot/dcim/tables/devicetypes.py +2 -2
  161. nautobot/dcim/templates/dcim/controller/base.html +10 -0
  162. nautobot/dcim/templates/dcim/controller_create.html +1 -0
  163. nautobot/dcim/templates/dcim/controller_retrieve.html +5 -1
  164. nautobot/dcim/templates/dcim/controller_wirelessnetworks.html +25 -0
  165. nautobot/dcim/templates/dcim/controllermanageddevicegroup_create.html +66 -0
  166. nautobot/dcim/templates/dcim/controllermanageddevicegroup_retrieve.html +46 -0
  167. nautobot/dcim/templates/dcim/device/base.html +6 -42
  168. nautobot/dcim/templates/dcim/device/wireless.html +73 -0
  169. nautobot/dcim/templates/dcim/device.html +3 -1
  170. nautobot/dcim/templates/dcim/interface.html +1 -0
  171. nautobot/dcim/templates/dcim/interface_edit.html +1 -0
  172. nautobot/dcim/templates/dcim/locationtype.html +0 -107
  173. nautobot/dcim/templates/dcim/locationtype_retrieve.html +8 -0
  174. nautobot/dcim/templates/dcim/virtualdevicecontext_retrieve.html +76 -0
  175. nautobot/dcim/templates/dcim/virtualdevicecontext_update.html +34 -0
  176. nautobot/dcim/tests/test_api.py +172 -61
  177. nautobot/dcim/tests/test_filters.py +171 -109
  178. nautobot/dcim/tests/test_forms.py +2 -51
  179. nautobot/dcim/tests/test_graphql.py +0 -52
  180. nautobot/dcim/tests/test_models.py +126 -4
  181. nautobot/dcim/tests/test_signals.py +1 -0
  182. nautobot/dcim/tests/test_views.py +103 -11
  183. nautobot/dcim/urls.py +72 -27
  184. nautobot/dcim/utils.py +2 -2
  185. nautobot/dcim/views.py +369 -62
  186. nautobot/extras/api/customfields.py +2 -2
  187. nautobot/extras/api/serializers.py +91 -75
  188. nautobot/extras/api/urls.py +4 -0
  189. nautobot/extras/api/views.py +78 -15
  190. nautobot/extras/choices.py +13 -0
  191. nautobot/extras/constants.py +0 -1
  192. nautobot/extras/context_managers.py +23 -6
  193. nautobot/extras/datasources/git.py +4 -1
  194. nautobot/extras/factory.py +27 -0
  195. nautobot/extras/filters/__init__.py +59 -0
  196. nautobot/extras/forms/forms.py +125 -30
  197. nautobot/extras/forms/mixins.py +3 -11
  198. nautobot/extras/graphql/types.py +25 -1
  199. nautobot/extras/group_sync.py +3 -3
  200. nautobot/extras/health_checks.py +2 -1
  201. nautobot/extras/jobs.py +62 -26
  202. nautobot/extras/management/__init__.py +1 -0
  203. nautobot/extras/management/commands/runjob.py +7 -79
  204. nautobot/extras/management/commands/runjob_with_job_result.py +46 -0
  205. nautobot/extras/management/utils.py +87 -0
  206. nautobot/extras/managers.py +1 -3
  207. nautobot/extras/migrations/0018_joblog_data_migration.py +9 -7
  208. nautobot/extras/migrations/0117_create_job_queue_model.py +129 -0
  209. nautobot/extras/migrations/0118_task_queue_to_job_queue_migration.py +78 -0
  210. nautobot/extras/migrations/0119_remove_task_queues_from_job_and_queue_from_scheduled_job.py +28 -0
  211. nautobot/extras/models/__init__.py +4 -0
  212. nautobot/extras/models/change_logging.py +7 -3
  213. nautobot/extras/models/customfields.py +11 -12
  214. nautobot/extras/models/groups.py +9 -13
  215. nautobot/extras/models/jobs.py +218 -37
  216. nautobot/extras/models/models.py +2 -2
  217. nautobot/extras/models/relationships.py +69 -1
  218. nautobot/extras/models/secrets.py +5 -0
  219. nautobot/extras/navigation.py +20 -262
  220. nautobot/extras/plugins/__init__.py +56 -32
  221. nautobot/extras/plugins/marketplace_manifest.yml +450 -0
  222. nautobot/extras/plugins/urls.py +1 -0
  223. nautobot/extras/plugins/views.py +48 -1
  224. nautobot/extras/signals.py +39 -1
  225. nautobot/extras/tables.py +40 -6
  226. nautobot/extras/templates/extras/externalintegration_retrieve.html +0 -47
  227. nautobot/extras/templates/extras/inc/tags_panel.html +1 -5
  228. nautobot/extras/templates/extras/job_bulk_edit.html +2 -1
  229. nautobot/extras/templates/extras/job_detail.html +36 -6
  230. nautobot/extras/templates/extras/job_edit.html +5 -2
  231. nautobot/extras/templates/extras/job_list.html +2 -7
  232. nautobot/extras/templates/extras/jobqueue_retrieve.html +44 -0
  233. nautobot/extras/templates/extras/marketplace.html +278 -0
  234. nautobot/extras/templates/extras/plugins_list.html +35 -1
  235. nautobot/extras/templates/extras/plugins_tiles.html +79 -0
  236. nautobot/extras/templates/extras/role_retrieve.html +16 -0
  237. nautobot/extras/templates/extras/secret.html +0 -65
  238. nautobot/extras/templates/extras/secret_check.js +16 -0
  239. nautobot/extras/templates/extras/secret_create.html +114 -0
  240. nautobot/extras/templates/extras/secret_edit.html +1 -114
  241. nautobot/extras/templates/extras/secretsgroup_edit.html +1 -1
  242. nautobot/extras/templates/extras/templatetags/plugin_object_detail_tabs.html +2 -0
  243. nautobot/extras/templatetags/job_buttons.py +5 -4
  244. nautobot/extras/templatetags/plugins.py +69 -6
  245. nautobot/extras/test_jobs/api_test_job.py +1 -1
  246. nautobot/extras/test_jobs/atomic_transaction.py +2 -2
  247. nautobot/extras/test_jobs/dry_run.py +1 -1
  248. nautobot/extras/test_jobs/fail.py +5 -5
  249. nautobot/extras/test_jobs/file_output.py +1 -1
  250. nautobot/extras/test_jobs/file_upload_fail.py +1 -1
  251. nautobot/extras/test_jobs/file_upload_pass.py +1 -1
  252. nautobot/extras/test_jobs/ipaddress_vars.py +1 -3
  253. nautobot/extras/test_jobs/jobs_module/jobs_submodule/jobs.py +1 -1
  254. nautobot/extras/test_jobs/location_with_custom_field.py +1 -1
  255. nautobot/extras/test_jobs/log_redaction.py +1 -1
  256. nautobot/extras/test_jobs/log_skip_db_logging.py +1 -1
  257. nautobot/extras/test_jobs/modify_db.py +1 -1
  258. nautobot/extras/test_jobs/object_var_optional.py +1 -1
  259. nautobot/extras/test_jobs/object_var_required.py +1 -1
  260. nautobot/extras/test_jobs/object_vars.py +1 -1
  261. nautobot/extras/test_jobs/pass.py +3 -3
  262. nautobot/extras/test_jobs/profiling.py +1 -1
  263. nautobot/extras/test_jobs/relative_import.py +3 -3
  264. nautobot/extras/test_jobs/soft_time_limit_greater_than_time_limit.py +1 -1
  265. nautobot/extras/test_jobs/task_queues.py +1 -1
  266. nautobot/extras/tests/integration/test_plugin_banner.py +2 -0
  267. nautobot/extras/tests/test_api.py +157 -55
  268. nautobot/extras/tests/test_context_managers.py +4 -1
  269. nautobot/extras/tests/test_customfields.py +1 -1
  270. nautobot/extras/tests/test_datasources.py +1 -2
  271. nautobot/extras/tests/test_dynamicgroups.py +1 -1
  272. nautobot/extras/tests/test_filters.py +219 -535
  273. nautobot/extras/tests/test_forms.py +1 -20
  274. nautobot/extras/tests/test_job_variables.py +73 -152
  275. nautobot/extras/tests/test_jobs.py +43 -54
  276. nautobot/extras/tests/test_models.py +71 -16
  277. nautobot/extras/tests/test_relationships.py +5 -2
  278. nautobot/extras/tests/test_utils.py +23 -2
  279. nautobot/extras/tests/test_views.py +183 -43
  280. nautobot/extras/tests/test_webhooks.py +2 -1
  281. nautobot/extras/urls.py +2 -20
  282. nautobot/extras/utils.py +118 -4
  283. nautobot/extras/views.py +203 -92
  284. nautobot/extras/webhooks.py +5 -2
  285. nautobot/ipam/api/fields.py +3 -3
  286. nautobot/ipam/api/serializers.py +36 -137
  287. nautobot/ipam/api/views.py +93 -62
  288. nautobot/ipam/lookups.py +62 -101
  289. nautobot/ipam/models.py +11 -63
  290. nautobot/ipam/navigation.py +0 -90
  291. nautobot/ipam/querysets.py +2 -2
  292. nautobot/ipam/tables.py +6 -20
  293. nautobot/ipam/templates/ipam/routetarget.html +0 -28
  294. nautobot/ipam/templates/ipam/vrf.html +0 -47
  295. nautobot/ipam/tests/test_api.py +8 -419
  296. nautobot/ipam/tests/test_filters.py +39 -119
  297. nautobot/ipam/tests/test_forms.py +47 -51
  298. nautobot/ipam/tests/test_migrations.py +30 -30
  299. nautobot/ipam/tests/test_models.py +0 -41
  300. nautobot/ipam/tests/test_querysets.py +1 -63
  301. nautobot/ipam/urls.py +3 -69
  302. nautobot/ipam/utils/__init__.py +0 -24
  303. nautobot/ipam/views.py +153 -198
  304. nautobot/project-static/css/base.css +38 -3
  305. nautobot/project-static/docs/404.html +421 -19
  306. nautobot/project-static/docs/apps/index.html +421 -19
  307. nautobot/project-static/docs/apps/nautobot-apps.html +421 -19
  308. nautobot/project-static/docs/assets/extra.css +5 -1
  309. nautobot/project-static/docs/assets/javascripts/{bundle.88dd0f4e.min.js → bundle.83f73b43.min.js} +2 -2
  310. nautobot/project-static/docs/assets/javascripts/{bundle.88dd0f4e.min.js.map → bundle.83f73b43.min.js.map} +2 -2
  311. nautobot/project-static/docs/code-reference/nautobot/apps/__init__.html +421 -19
  312. nautobot/project-static/docs/code-reference/nautobot/apps/admin.html +421 -19
  313. nautobot/project-static/docs/code-reference/nautobot/apps/api.html +421 -172
  314. nautobot/project-static/docs/code-reference/nautobot/apps/change_logging.html +421 -19
  315. nautobot/project-static/docs/code-reference/nautobot/apps/choices.html +421 -19
  316. nautobot/project-static/docs/code-reference/nautobot/apps/config.html +425 -21
  317. nautobot/project-static/docs/code-reference/nautobot/apps/constants.html +421 -19
  318. nautobot/project-static/docs/code-reference/nautobot/apps/datasources.html +424 -22
  319. nautobot/project-static/docs/code-reference/nautobot/apps/events.html +9809 -0
  320. nautobot/project-static/docs/code-reference/nautobot/apps/exceptions.html +424 -63
  321. nautobot/project-static/docs/code-reference/nautobot/apps/factory.html +421 -19
  322. nautobot/project-static/docs/code-reference/nautobot/apps/filters.html +421 -19
  323. nautobot/project-static/docs/code-reference/nautobot/apps/forms.html +457 -20
  324. nautobot/project-static/docs/code-reference/nautobot/apps/graphql.html +421 -19
  325. nautobot/project-static/docs/code-reference/nautobot/apps/jobs.html +425 -25
  326. nautobot/project-static/docs/code-reference/nautobot/apps/models.html +457 -19
  327. nautobot/project-static/docs/code-reference/nautobot/apps/querysets.html +421 -19
  328. nautobot/project-static/docs/code-reference/nautobot/apps/secrets.html +421 -19
  329. nautobot/project-static/docs/code-reference/nautobot/apps/tables.html +425 -215
  330. nautobot/project-static/docs/code-reference/nautobot/apps/testing.html +430 -342
  331. nautobot/project-static/docs/code-reference/nautobot/apps/ui.html +5799 -1054
  332. nautobot/project-static/docs/code-reference/nautobot/apps/urls.html +421 -19
  333. nautobot/project-static/docs/code-reference/nautobot/apps/utils.html +447 -176
  334. nautobot/project-static/docs/code-reference/nautobot/apps/views.html +460 -21
  335. nautobot/project-static/docs/development/apps/api/configuration-view.html +421 -19
  336. nautobot/project-static/docs/development/apps/api/database-backend-config.html +421 -19
  337. nautobot/project-static/docs/development/apps/api/models/django-admin.html +421 -19
  338. nautobot/project-static/docs/development/apps/api/models/global-search.html +421 -19
  339. nautobot/project-static/docs/development/apps/api/models/graphql.html +421 -19
  340. nautobot/project-static/docs/development/apps/api/models/index.html +421 -19
  341. nautobot/project-static/docs/development/apps/api/nautobot-app-config.html +421 -19
  342. nautobot/project-static/docs/development/apps/api/platform-features/custom-validators.html +421 -19
  343. nautobot/project-static/docs/development/apps/api/platform-features/filter-extensions.html +421 -19
  344. nautobot/project-static/docs/development/apps/api/platform-features/git-repository-content.html +421 -19
  345. nautobot/project-static/docs/development/apps/api/platform-features/index.html +421 -19
  346. nautobot/project-static/docs/development/apps/api/platform-features/jinja2-filters.html +421 -19
  347. nautobot/project-static/docs/development/apps/api/platform-features/jobs.html +421 -19
  348. nautobot/project-static/docs/development/apps/api/platform-features/populating-extensibility-features.html +421 -19
  349. nautobot/project-static/docs/development/apps/api/platform-features/secrets-providers.html +421 -19
  350. nautobot/project-static/docs/development/apps/api/platform-features/table-extensions.html +424 -41
  351. nautobot/project-static/docs/development/apps/api/platform-features/uniquely-identify-objects.html +421 -19
  352. nautobot/project-static/docs/development/apps/api/prometheus.html +421 -19
  353. nautobot/project-static/docs/development/apps/api/setup.html +425 -155
  354. nautobot/project-static/docs/development/apps/api/testing.html +421 -19
  355. nautobot/project-static/docs/development/apps/api/ui-extensions/banners.html +421 -19
  356. nautobot/project-static/docs/development/apps/api/ui-extensions/home-page.html +421 -19
  357. nautobot/project-static/docs/development/apps/api/ui-extensions/index.html +421 -19
  358. nautobot/project-static/docs/development/apps/api/ui-extensions/navigation.html +421 -19
  359. nautobot/project-static/docs/development/apps/api/ui-extensions/object-views.html +701 -130
  360. nautobot/project-static/docs/development/apps/api/views/base-template.html +421 -19
  361. nautobot/project-static/docs/development/apps/api/views/core-view-overrides.html +421 -19
  362. nautobot/project-static/docs/development/apps/api/views/django-generic-views.html +421 -19
  363. nautobot/project-static/docs/development/apps/api/views/help-documentation.html +421 -19
  364. nautobot/project-static/docs/development/apps/api/views/index.html +423 -20
  365. nautobot/project-static/docs/development/apps/api/views/nautobot-generic-views.html +425 -19
  366. nautobot/project-static/docs/development/apps/api/views/nautobotuiviewset.html +451 -19
  367. nautobot/project-static/docs/development/apps/api/views/nautobotuiviewsetrouter.html +421 -19
  368. nautobot/project-static/docs/development/apps/api/views/notes.html +421 -19
  369. nautobot/project-static/docs/development/apps/api/views/rest-api.html +421 -19
  370. nautobot/project-static/docs/development/apps/api/views/urls.html +421 -19
  371. nautobot/project-static/docs/development/apps/index.html +421 -19
  372. nautobot/project-static/docs/development/apps/migration/code-updates.html +422 -52
  373. nautobot/project-static/docs/development/apps/migration/dependency-updates.html +422 -20
  374. nautobot/project-static/docs/development/apps/migration/from-v1.html +421 -19
  375. nautobot/project-static/docs/development/apps/migration/model-updates/dcim.html +421 -19
  376. nautobot/project-static/docs/development/apps/migration/model-updates/extras.html +421 -19
  377. nautobot/project-static/docs/development/apps/migration/model-updates/global.html +421 -19
  378. nautobot/project-static/docs/development/apps/migration/model-updates/ipam.html +424 -22
  379. nautobot/project-static/docs/development/apps/migration/ui-component-framework/best-practices.html +9219 -0
  380. nautobot/project-static/docs/development/apps/migration/ui-component-framework/custom-content.html +9333 -0
  381. nautobot/project-static/docs/development/apps/migration/ui-component-framework/index.html +9474 -0
  382. nautobot/project-static/docs/development/apps/migration/ui-component-framework/migration-steps.html +9517 -0
  383. nautobot/project-static/docs/development/apps/porting-from-netbox.html +424 -22
  384. nautobot/project-static/docs/development/core/application-registry.html +421 -19
  385. nautobot/project-static/docs/development/core/best-practices.html +421 -19
  386. nautobot/project-static/docs/development/core/bootstrap-ui.html +421 -19
  387. nautobot/project-static/docs/development/core/caching.html +421 -19
  388. nautobot/project-static/docs/development/core/controllers.html +423 -19
  389. nautobot/project-static/docs/development/core/docker-compose-advanced-use-cases.html +490 -45
  390. nautobot/project-static/docs/development/core/generic-views.html +421 -19
  391. nautobot/project-static/docs/development/core/getting-started.html +566 -179
  392. nautobot/project-static/docs/development/core/homepage.html +432 -30
  393. nautobot/project-static/docs/development/core/index.html +421 -19
  394. nautobot/project-static/docs/development/core/local-k8s.html +9453 -0
  395. nautobot/project-static/docs/development/core/model-checklist.html +424 -22
  396. nautobot/project-static/docs/development/core/model-features.html +421 -19
  397. nautobot/project-static/docs/development/core/natural-keys.html +421 -19
  398. nautobot/project-static/docs/development/core/navigation-menu.html +438 -26
  399. nautobot/project-static/docs/development/core/release-checklist.html +435 -45
  400. nautobot/project-static/docs/development/core/role-internals.html +421 -19
  401. nautobot/project-static/docs/development/core/settings.html +421 -19
  402. nautobot/project-static/docs/development/core/style-guide.html +421 -19
  403. nautobot/project-static/docs/development/core/templates.html +431 -22
  404. nautobot/project-static/docs/development/core/testing.html +421 -19
  405. nautobot/project-static/docs/development/core/ui-component-framework.html +11020 -0
  406. nautobot/project-static/docs/development/core/user-preferences.html +424 -22
  407. nautobot/project-static/docs/development/index.html +421 -19
  408. nautobot/project-static/docs/development/jobs/index.html +546 -160
  409. nautobot/project-static/docs/development/jobs/migration/from-v1.html +421 -19
  410. nautobot/project-static/docs/index.html +421 -19
  411. nautobot/project-static/docs/media/development/core/ui-component-framework/basic-panel-layout.png +0 -0
  412. nautobot/project-static/docs/media/development/core/ui-component-framework/button-example.png +0 -0
  413. nautobot/project-static/docs/media/development/core/ui-component-framework/dropdown-button-example.png +0 -0
  414. nautobot/project-static/docs/media/development/core/ui-component-framework/grouped-key-value-table-panel-example-1.png +0 -0
  415. nautobot/project-static/docs/media/development/core/ui-component-framework/grouped-key-value-table-panel-example-2.png +0 -0
  416. nautobot/project-static/docs/media/development/core/ui-component-framework/object-fields-panel-example.png +0 -0
  417. nautobot/project-static/docs/media/development/core/ui-component-framework/stats-panel-example.png +0 -0
  418. nautobot/project-static/docs/media/development/core/ui-component-framework/table-panels-family.png +0 -0
  419. nautobot/project-static/docs/media/development/core/ui-component-framework/text-panels-family.png +0 -0
  420. nautobot/project-static/docs/media/development/core/ui-component-framework/ui-framework-example.png +0 -0
  421. nautobot/project-static/docs/media/models/virtual_device_context_overview.drawio +73 -0
  422. nautobot/project-static/docs/media/models/virtual_device_context_overview.png +0 -0
  423. nautobot/project-static/docs/models/dcim/virtualdevicecontext.html +14 -0
  424. nautobot/project-static/docs/models/extras/jobqueue.html +14 -0
  425. nautobot/project-static/docs/models/wireless/radioprofile.html +14 -0
  426. nautobot/project-static/docs/models/wireless/supporteddatarate.html +14 -0
  427. nautobot/project-static/docs/models/wireless/wirelessnetwork.html +14 -0
  428. nautobot/project-static/docs/objects.inv +0 -0
  429. nautobot/project-static/docs/overview/application_stack.html +426 -20
  430. nautobot/project-static/docs/overview/design_philosophy.html +421 -19
  431. nautobot/project-static/docs/release-notes/index.html +445 -22
  432. nautobot/project-static/docs/release-notes/version-1.0.html +421 -19
  433. nautobot/project-static/docs/release-notes/version-1.1.html +421 -19
  434. nautobot/project-static/docs/release-notes/version-1.2.html +421 -19
  435. nautobot/project-static/docs/release-notes/version-1.3.html +421 -19
  436. nautobot/project-static/docs/release-notes/version-1.4.html +421 -19
  437. nautobot/project-static/docs/release-notes/version-1.5.html +421 -19
  438. nautobot/project-static/docs/release-notes/version-1.6.html +634 -667
  439. nautobot/project-static/docs/release-notes/version-2.0.html +421 -19
  440. nautobot/project-static/docs/release-notes/version-2.1.html +421 -19
  441. nautobot/project-static/docs/release-notes/version-2.2.html +421 -19
  442. nautobot/project-static/docs/release-notes/version-2.3.html +684 -886
  443. nautobot/project-static/docs/release-notes/version-2.4.html +10007 -0
  444. nautobot/project-static/docs/requirements.txt +2 -2
  445. nautobot/project-static/docs/search/search_index.json +1 -1
  446. nautobot/project-static/docs/sitemap.xml +334 -270
  447. nautobot/project-static/docs/sitemap.xml.gz +0 -0
  448. nautobot/project-static/docs/user-guide/administration/configuration/authentication/ldap.html +421 -19
  449. nautobot/project-static/docs/user-guide/administration/configuration/authentication/remote.html +421 -19
  450. nautobot/project-static/docs/user-guide/administration/configuration/authentication/sso.html +423 -21
  451. nautobot/project-static/docs/user-guide/administration/configuration/index.html +433 -32
  452. nautobot/project-static/docs/user-guide/administration/configuration/redis.html +421 -19
  453. nautobot/project-static/docs/user-guide/administration/configuration/settings.html +765 -180
  454. nautobot/project-static/docs/user-guide/administration/configuration/time-zones.html +421 -19
  455. nautobot/project-static/docs/user-guide/administration/guides/celery-queues.html +421 -19
  456. nautobot/project-static/docs/user-guide/administration/guides/docker.html +434 -29
  457. nautobot/project-static/docs/user-guide/administration/guides/health-checks.html +421 -19
  458. nautobot/project-static/docs/user-guide/administration/guides/permissions.html +421 -19
  459. nautobot/project-static/docs/user-guide/administration/guides/prometheus-metrics.html +421 -19
  460. nautobot/project-static/docs/user-guide/administration/guides/replicating-nautobot.html +421 -19
  461. nautobot/project-static/docs/user-guide/administration/guides/request-profiling.html +421 -19
  462. nautobot/project-static/docs/user-guide/administration/guides/s3-django-storage.html +421 -19
  463. nautobot/project-static/docs/user-guide/administration/guides/selinux-troubleshooting.html +421 -19
  464. nautobot/project-static/docs/user-guide/administration/installation/app-install.html +421 -19
  465. nautobot/project-static/docs/user-guide/administration/installation/external-authentication.html +421 -19
  466. nautobot/project-static/docs/user-guide/administration/installation/http-server.html +421 -19
  467. nautobot/project-static/docs/user-guide/administration/installation/index.html +426 -20
  468. nautobot/project-static/docs/user-guide/administration/installation/install_system.html +421 -19
  469. nautobot/project-static/docs/user-guide/administration/installation/nautobot.html +421 -19
  470. nautobot/project-static/docs/user-guide/administration/installation/services.html +421 -19
  471. nautobot/project-static/docs/user-guide/administration/migration/migrating-from-netbox.html +421 -19
  472. nautobot/project-static/docs/user-guide/administration/migration/migrating-from-postgresql.html +442 -41
  473. nautobot/project-static/docs/user-guide/administration/tools/nautobot-server.html +435 -66
  474. nautobot/project-static/docs/user-guide/administration/tools/nautobot-shell.html +435 -66
  475. nautobot/project-static/docs/user-guide/administration/upgrading/database-backup.html +421 -19
  476. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/after-you-upgrade.html +421 -19
  477. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/before-you-upgrade.html +421 -19
  478. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/for-developers.html +421 -19
  479. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/index.html +421 -19
  480. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/whats-changed.html +421 -19
  481. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/region-and-site-data-migration-guide.html +421 -19
  482. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/tables/v2-code-nautobot-app-location.yaml +0 -16
  483. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/upgrading-from-nautobot-v1.html +421 -19
  484. nautobot/project-static/docs/user-guide/administration/upgrading/upgrading.html +427 -21
  485. nautobot/project-static/docs/user-guide/core-data-model/circuits/circuit.html +421 -19
  486. nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittermination.html +421 -19
  487. nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittype.html +421 -19
  488. nautobot/project-static/docs/user-guide/core-data-model/circuits/provider.html +421 -19
  489. nautobot/project-static/docs/user-guide/core-data-model/circuits/providernetwork.html +421 -19
  490. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloud.html +421 -19
  491. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudaccount.html +421 -19
  492. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudnetwork.html +421 -19
  493. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudnetworkprefixassignment.html +421 -19
  494. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudresourcetype.html +421 -19
  495. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudservice.html +421 -19
  496. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudservicenetworkassignment.html +421 -19
  497. nautobot/project-static/docs/user-guide/core-data-model/dcim/cable.html +421 -19
  498. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleport.html +421 -19
  499. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleporttemplate.html +421 -19
  500. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverport.html +421 -19
  501. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverporttemplate.html +421 -19
  502. nautobot/project-static/docs/user-guide/core-data-model/dcim/controller.html +457 -20
  503. nautobot/project-static/docs/user-guide/core-data-model/dcim/controllermanageddevicegroup.html +447 -22
  504. nautobot/project-static/docs/user-guide/core-data-model/dcim/device.html +421 -19
  505. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebay.html +421 -19
  506. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebaytemplate.html +421 -19
  507. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicefamily.html +421 -19
  508. nautobot/project-static/docs/user-guide/core-data-model/dcim/deviceredundancygroup.html +421 -19
  509. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicetype.html +421 -19
  510. nautobot/project-static/docs/user-guide/core-data-model/dcim/frontport.html +421 -19
  511. nautobot/project-static/docs/user-guide/core-data-model/dcim/frontporttemplate.html +421 -19
  512. nautobot/project-static/docs/user-guide/core-data-model/dcim/interface.html +421 -19
  513. nautobot/project-static/docs/user-guide/core-data-model/dcim/interfaceredundancygroup.html +421 -19
  514. nautobot/project-static/docs/user-guide/core-data-model/dcim/interfacetemplate.html +421 -19
  515. nautobot/project-static/docs/user-guide/core-data-model/dcim/inventoryitem.html +421 -19
  516. nautobot/project-static/docs/user-guide/core-data-model/dcim/location.html +421 -19
  517. nautobot/project-static/docs/user-guide/core-data-model/dcim/locationtype.html +421 -19
  518. nautobot/project-static/docs/user-guide/core-data-model/dcim/manufacturer.html +421 -19
  519. nautobot/project-static/docs/user-guide/core-data-model/dcim/module.html +421 -19
  520. nautobot/project-static/docs/user-guide/core-data-model/dcim/modulebay.html +421 -19
  521. nautobot/project-static/docs/user-guide/core-data-model/dcim/modulebaytemplate.html +421 -19
  522. nautobot/project-static/docs/user-guide/core-data-model/dcim/moduletype.html +421 -19
  523. nautobot/project-static/docs/user-guide/core-data-model/dcim/platform.html +421 -19
  524. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerfeed.html +421 -19
  525. nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlet.html +421 -19
  526. nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlettemplate.html +421 -19
  527. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerpanel.html +421 -19
  528. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerport.html +421 -19
  529. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerporttemplate.html +421 -19
  530. nautobot/project-static/docs/user-guide/core-data-model/dcim/rack.html +421 -19
  531. nautobot/project-static/docs/user-guide/core-data-model/dcim/rackgroup.html +421 -19
  532. nautobot/project-static/docs/user-guide/core-data-model/dcim/rackreservation.html +421 -19
  533. nautobot/project-static/docs/user-guide/core-data-model/dcim/rearport.html +421 -19
  534. nautobot/project-static/docs/user-guide/core-data-model/dcim/rearporttemplate.html +421 -19
  535. nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareimagefile.html +421 -19
  536. nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareversion.html +421 -19
  537. nautobot/project-static/docs/user-guide/core-data-model/dcim/virtualchassis.html +421 -19
  538. nautobot/project-static/docs/user-guide/core-data-model/dcim/virtualdevicecontext.html +9333 -0
  539. nautobot/project-static/docs/user-guide/core-data-model/extras/configcontext.html +424 -22
  540. nautobot/project-static/docs/user-guide/core-data-model/extras/configcontextschema.html +421 -19
  541. nautobot/project-static/docs/user-guide/core-data-model/extras/contact.html +421 -19
  542. nautobot/project-static/docs/user-guide/core-data-model/extras/team.html +421 -19
  543. nautobot/project-static/docs/user-guide/core-data-model/ipam/ipaddress.html +421 -19
  544. nautobot/project-static/docs/user-guide/core-data-model/ipam/namespace.html +421 -19
  545. nautobot/project-static/docs/user-guide/core-data-model/ipam/prefix.html +421 -19
  546. nautobot/project-static/docs/user-guide/core-data-model/ipam/rir.html +421 -19
  547. nautobot/project-static/docs/user-guide/core-data-model/ipam/routetarget.html +421 -19
  548. nautobot/project-static/docs/user-guide/core-data-model/ipam/service.html +421 -19
  549. nautobot/project-static/docs/user-guide/core-data-model/ipam/vlan.html +421 -19
  550. nautobot/project-static/docs/user-guide/core-data-model/ipam/vlangroup.html +421 -19
  551. nautobot/project-static/docs/user-guide/core-data-model/ipam/vrf.html +421 -19
  552. nautobot/project-static/docs/user-guide/core-data-model/overview/introduction.html +421 -19
  553. nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenant.html +421 -19
  554. nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenantgroup.html +421 -19
  555. nautobot/project-static/docs/user-guide/core-data-model/virtualization/cluster.html +421 -19
  556. nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustergroup.html +421 -19
  557. nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustertype.html +421 -19
  558. nautobot/project-static/docs/user-guide/core-data-model/virtualization/virtualmachine.html +421 -19
  559. nautobot/project-static/docs/user-guide/core-data-model/virtualization/vminterface.html +424 -22
  560. nautobot/project-static/docs/user-guide/core-data-model/wireless/index.html +9271 -0
  561. nautobot/project-static/docs/user-guide/core-data-model/wireless/radioprofile.html +9175 -0
  562. nautobot/project-static/docs/user-guide/core-data-model/wireless/supporteddatarate.html +9169 -0
  563. nautobot/project-static/docs/user-guide/core-data-model/wireless/wirelessnetwork.html +9235 -0
  564. nautobot/project-static/docs/user-guide/feature-guides/contacts-and-teams.html +421 -19
  565. nautobot/project-static/docs/user-guide/feature-guides/custom-fields.html +421 -19
  566. nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-devices.html +421 -19
  567. nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-location-types-and-locations.html +421 -19
  568. nautobot/project-static/docs/user-guide/feature-guides/getting-started/index.html +421 -19
  569. nautobot/project-static/docs/user-guide/feature-guides/getting-started/interfaces.html +421 -19
  570. nautobot/project-static/docs/user-guide/feature-guides/getting-started/ipam.html +421 -19
  571. nautobot/project-static/docs/user-guide/feature-guides/getting-started/platforms.html +421 -19
  572. nautobot/project-static/docs/user-guide/feature-guides/getting-started/search-bar.html +421 -19
  573. nautobot/project-static/docs/user-guide/feature-guides/getting-started/tenants.html +421 -19
  574. nautobot/project-static/docs/user-guide/feature-guides/getting-started/vlans-and-vlan-groups.html +421 -19
  575. nautobot/project-static/docs/user-guide/feature-guides/git-data-source.html +421 -19
  576. nautobot/project-static/docs/user-guide/feature-guides/graphql.html +421 -19
  577. nautobot/project-static/docs/user-guide/feature-guides/ip-address-merge-tool.html +421 -19
  578. nautobot/project-static/docs/user-guide/feature-guides/relationships.html +421 -19
  579. nautobot/project-static/docs/user-guide/feature-guides/software-image-files-and-versions.html +421 -19
  580. nautobot/project-static/docs/user-guide/index.html +421 -19
  581. nautobot/project-static/docs/user-guide/platform-functionality/change-logging.html +424 -22
  582. nautobot/project-static/docs/user-guide/platform-functionality/computedfield.html +421 -19
  583. nautobot/project-static/docs/user-guide/platform-functionality/customfield.html +421 -19
  584. nautobot/project-static/docs/user-guide/platform-functionality/customlink.html +421 -19
  585. nautobot/project-static/docs/user-guide/platform-functionality/dynamicgroup.html +421 -19
  586. nautobot/project-static/docs/user-guide/platform-functionality/events.html +9575 -0
  587. nautobot/project-static/docs/user-guide/platform-functionality/exporttemplate.html +424 -22
  588. nautobot/project-static/docs/user-guide/platform-functionality/externalintegration.html +421 -19
  589. nautobot/project-static/docs/user-guide/platform-functionality/gitrepository.html +421 -19
  590. nautobot/project-static/docs/user-guide/platform-functionality/graphql.html +421 -19
  591. nautobot/project-static/docs/user-guide/platform-functionality/graphqlquery.html +421 -19
  592. nautobot/project-static/docs/user-guide/platform-functionality/imageattachment.html +421 -19
  593. nautobot/project-static/docs/user-guide/platform-functionality/jobs/index.html +426 -20
  594. nautobot/project-static/docs/user-guide/platform-functionality/jobs/job-scheduling-and-approvals.html +424 -22
  595. nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobbutton.html +421 -19
  596. nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobhook.html +421 -19
  597. nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobqueue.html +9182 -0
  598. nautobot/project-static/docs/user-guide/platform-functionality/jobs/models.html +424 -22
  599. nautobot/project-static/docs/user-guide/platform-functionality/napalm.html +421 -19
  600. nautobot/project-static/docs/user-guide/platform-functionality/note.html +421 -19
  601. nautobot/project-static/docs/user-guide/platform-functionality/objectmetadata.html +421 -19
  602. nautobot/project-static/docs/user-guide/platform-functionality/relationship.html +424 -22
  603. nautobot/project-static/docs/user-guide/platform-functionality/rendering-jinja-templates.html +9250 -0
  604. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/authentication.html +421 -19
  605. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/filtering.html +421 -19
  606. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/overview.html +424 -22
  607. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/ui-related-endpoints.html +421 -19
  608. nautobot/project-static/docs/user-guide/platform-functionality/role.html +421 -19
  609. nautobot/project-static/docs/user-guide/platform-functionality/savedview.html +421 -19
  610. nautobot/project-static/docs/user-guide/platform-functionality/secret.html +421 -19
  611. nautobot/project-static/docs/user-guide/platform-functionality/staticgroupassociation.html +424 -22
  612. nautobot/project-static/docs/user-guide/platform-functionality/status.html +421 -19
  613. nautobot/project-static/docs/user-guide/platform-functionality/tag.html +421 -19
  614. nautobot/project-static/docs/user-guide/platform-functionality/template-filters.html +489 -56
  615. nautobot/project-static/docs/user-guide/platform-functionality/users/objectpermission.html +421 -19
  616. nautobot/project-static/docs/user-guide/platform-functionality/users/token.html +421 -19
  617. nautobot/project-static/docs/user-guide/platform-functionality/webhook.html +421 -19
  618. nautobot/project-static/img/jinja_logo.svg +97 -0
  619. nautobot/project-static/js/forms.js +5 -0
  620. nautobot/project-static/js/nav_menu.js +2 -1
  621. nautobot/tenancy/api/serializers.py +0 -2
  622. nautobot/tenancy/factory.py +1 -1
  623. nautobot/tenancy/navigation.py +0 -29
  624. nautobot/tenancy/templates/tenancy/tenant.html +4 -91
  625. nautobot/tenancy/tests/test_filters.py +29 -134
  626. nautobot/tenancy/views.py +32 -23
  627. nautobot/users/admin.py +3 -1
  628. nautobot/users/api/serializers.py +4 -5
  629. nautobot/users/api/views.py +1 -1
  630. nautobot/users/forms.py +19 -0
  631. nautobot/users/templates/users/preferences.html +22 -0
  632. nautobot/users/tests/test_filters.py +1 -19
  633. nautobot/users/tests/test_views.py +57 -0
  634. nautobot/users/utils.py +8 -0
  635. nautobot/users/views.py +48 -11
  636. nautobot/virtualization/api/serializers.py +4 -4
  637. nautobot/virtualization/filters.py +2 -20
  638. nautobot/virtualization/navigation.py +0 -48
  639. nautobot/virtualization/templates/virtualization/clustertype.html +0 -39
  640. nautobot/virtualization/tests/test_filters.py +57 -183
  641. nautobot/virtualization/views.py +18 -15
  642. nautobot/wireless/__init__.py +0 -0
  643. nautobot/wireless/api/__init__.py +0 -0
  644. nautobot/wireless/api/serializers.py +44 -0
  645. nautobot/wireless/api/urls.py +20 -0
  646. nautobot/wireless/api/views.py +34 -0
  647. nautobot/wireless/apps.py +8 -0
  648. nautobot/wireless/choices.py +345 -0
  649. nautobot/wireless/factory.py +138 -0
  650. nautobot/wireless/filters.py +167 -0
  651. nautobot/wireless/forms.py +283 -0
  652. nautobot/wireless/homepage.py +19 -0
  653. nautobot/wireless/migrations/0001_initial.py +223 -0
  654. nautobot/wireless/migrations/__init__.py +0 -0
  655. nautobot/wireless/models.py +207 -0
  656. nautobot/wireless/navigation.py +105 -0
  657. nautobot/wireless/tables.py +244 -0
  658. nautobot/wireless/templates/wireless/radioprofile_retrieve.html +81 -0
  659. nautobot/wireless/templates/wireless/supporteddatarate_retrieve.html +26 -0
  660. nautobot/wireless/templates/wireless/wirelessnetwork_create.html +88 -0
  661. nautobot/wireless/templates/wireless/wirelessnetwork_retrieve.html +64 -0
  662. nautobot/wireless/tests/__init__.py +0 -0
  663. nautobot/wireless/tests/test_api.py +247 -0
  664. nautobot/wireless/tests/test_filters.py +54 -0
  665. nautobot/wireless/tests/test_models.py +22 -0
  666. nautobot/wireless/tests/test_views.py +378 -0
  667. nautobot/wireless/urls.py +13 -0
  668. nautobot/wireless/views.py +129 -0
  669. {nautobot-2.3.16.dist-info → nautobot-2.4.0b1.dist-info}/METADATA +11 -14
  670. {nautobot-2.3.16.dist-info → nautobot-2.4.0b1.dist-info}/RECORD +674 -551
  671. {nautobot-2.3.16.dist-info → nautobot-2.4.0b1.dist-info}/WHEEL +1 -1
  672. nautobot/core/utils/navigation.py +0 -54
  673. {nautobot-2.3.16.dist-info → nautobot-2.4.0b1.dist-info}/LICENSE.txt +0 -0
  674. {nautobot-2.3.16.dist-info → nautobot-2.4.0b1.dist-info}/NOTICE +0 -0
  675. {nautobot-2.3.16.dist-info → nautobot-2.4.0b1.dist-info}/entry_points.txt +0 -0
@@ -1,4 +1,3 @@
1
- # pylint: disable=no-member # it doesn't recognize the class attributes assigned in common_test_data()
2
1
  import uuid
3
2
 
4
3
  from django.contrib.auth import get_user_model
@@ -45,6 +44,7 @@ from nautobot.dcim.filters import (
45
44
  InterfaceRedundancyGroupAssociationFilterSet,
46
45
  InterfaceRedundancyGroupFilterSet,
47
46
  InterfaceTemplateFilterSet,
47
+ InterfaceVDCAssignmentFilterSet,
48
48
  InventoryItemFilterSet,
49
49
  LocationFilterSet,
50
50
  LocationTypeFilterSet,
@@ -68,6 +68,7 @@ from nautobot.dcim.filters import (
68
68
  SoftwareImageFileFilterSet,
69
69
  SoftwareVersionFilterSet,
70
70
  VirtualChassisFilterSet,
71
+ VirtualDeviceContextFilterSet,
71
72
  )
72
73
  from nautobot.dcim.models import (
73
74
  Cable,
@@ -90,6 +91,7 @@ from nautobot.dcim.models import (
90
91
  InterfaceRedundancyGroup,
91
92
  InterfaceRedundancyGroupAssociation,
92
93
  InterfaceTemplate,
94
+ InterfaceVDCAssignment,
93
95
  InventoryItem,
94
96
  Location,
95
97
  LocationType,
@@ -113,11 +115,13 @@ from nautobot.dcim.models import (
113
115
  SoftwareImageFile,
114
116
  SoftwareVersion,
115
117
  VirtualChassis,
118
+ VirtualDeviceContext,
116
119
  )
117
120
  from nautobot.extras.models import ExternalIntegration, Role, SecretsGroup, Status, Tag
118
121
  from nautobot.ipam.models import IPAddress, Namespace, Prefix, Service, VLAN, VLANGroup
119
122
  from nautobot.tenancy.models import Tenant
120
123
  from nautobot.virtualization.models import Cluster, ClusterType, VirtualMachine
124
+ from nautobot.wireless.models import RadioProfile, WirelessNetwork
121
125
 
122
126
  # Use the proper swappable User model
123
127
  User = get_user_model()
@@ -594,7 +598,6 @@ def common_test_data(cls):
594
598
  )
595
599
 
596
600
  device_statuses = Status.objects.get_for_model(Device)
597
-
598
601
  cls.devices = (
599
602
  Device.objects.create(
600
603
  name="Device 1",
@@ -995,11 +998,12 @@ class PathEndpointModelTestMixin:
995
998
  )
996
999
 
997
1000
 
998
- class LocationTypeFilterSetTestCase(FilterTestCases.NameOnlyFilterTestCase):
1001
+ class LocationTypeFilterSetTestCase(FilterTestCases.FilterTestCase):
999
1002
  queryset = LocationType.objects.all()
1000
1003
  filterset = LocationTypeFilterSet
1001
1004
  generic_filter_tests = [
1002
1005
  ("description",),
1006
+ ("name",),
1003
1007
  ("parent", "parent__id"),
1004
1008
  ("parent", "parent__name"),
1005
1009
  ]
@@ -1031,7 +1035,7 @@ class LocationTypeFilterSetTestCase(FilterTestCases.NameOnlyFilterTestCase):
1031
1035
  )
1032
1036
 
1033
1037
 
1034
- class LocationFilterSetTestCase(FilterTestCases.NameOnlyFilterTestCase, FilterTestCases.TenancyFilterTestCaseMixin):
1038
+ class LocationFilterSetTestCase(FilterTestCases.FilterTestCase, FilterTestCases.TenancyFilterTestCaseMixin):
1035
1039
  queryset = Location.objects.all()
1036
1040
  filterset = LocationFilterSet
1037
1041
  tenancy_related_name = "locations"
@@ -1052,6 +1056,7 @@ class LocationFilterSetTestCase(FilterTestCases.NameOnlyFilterTestCase, FilterTe
1052
1056
  ("longitude",),
1053
1057
  ("location_type", "location_type__id"),
1054
1058
  ("location_type", "location_type__name"),
1059
+ ("name",),
1055
1060
  ("parent", "parent__id"),
1056
1061
  ("parent", "parent__name"),
1057
1062
  ("physical_address",),
@@ -1102,17 +1107,13 @@ class LocationFilterSetTestCase(FilterTestCases.NameOnlyFilterTestCase, FilterTe
1102
1107
  Location.objects.filter(location_type__content_types=ct),
1103
1108
  )
1104
1109
 
1105
- def test_search(self):
1106
- value = self.queryset.values_list("pk", flat=True)[0]
1107
- params = {"q": value}
1108
- self.assertQuerysetEqualAndNotEmpty(self.filterset(params, self.queryset).qs, self.queryset.filter(pk=value))
1109
1110
 
1110
-
1111
- class RackGroupTestCase(FilterTestCases.NameOnlyFilterTestCase):
1111
+ class RackGroupTestCase(FilterTestCases.FilterTestCase):
1112
1112
  queryset = RackGroup.objects.all()
1113
1113
  filterset = RackGroupFilterSet
1114
1114
  generic_filter_tests = [
1115
1115
  ("description",),
1116
+ ("name",),
1116
1117
  ("parent", "parent__id"),
1117
1118
  ("parent", "parent__name"),
1118
1119
  ("power_panels", "power_panels__id"),
@@ -1231,11 +1232,6 @@ class RackTestCase(FilterTestCases.FilterTestCase, FilterTestCases.TenancyFilter
1231
1232
  params = {"outer_unit": [RackDimensionUnitChoices.UNIT_MILLIMETER]}
1232
1233
  self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
1233
1234
 
1234
- def test_search(self):
1235
- value = self.queryset.values_list("pk", flat=True)[0]
1236
- params = {"q": value}
1237
- self.assertEqual(self.filterset(params, self.queryset).qs.values_list("pk", flat=True)[0], value)
1238
-
1239
1235
 
1240
1236
  class RackReservationTestCase(FilterTestCases.FilterTestCase, FilterTestCases.TenancyFilterTestCaseMixin):
1241
1237
  queryset = RackReservation.objects.all()
@@ -1255,13 +1251,8 @@ class RackReservationTestCase(FilterTestCases.FilterTestCase, FilterTestCases.Te
1255
1251
  def setUpTestData(cls):
1256
1252
  common_test_data(cls)
1257
1253
 
1258
- def test_search(self):
1259
- value = self.queryset.values_list("pk", flat=True)[0]
1260
- params = {"q": value}
1261
- self.assertEqual(self.filterset(params, self.queryset).qs.values_list("pk", flat=True)[0], value)
1262
1254
 
1263
-
1264
- class ManufacturerTestCase(FilterTestCases.NameOnlyFilterTestCase):
1255
+ class ManufacturerTestCase(FilterTestCases.FilterTestCase):
1265
1256
  queryset = Manufacturer.objects.all()
1266
1257
  filterset = ManufacturerFilterSet
1267
1258
  generic_filter_tests = [
@@ -1270,6 +1261,7 @@ class ManufacturerTestCase(FilterTestCases.NameOnlyFilterTestCase):
1270
1261
  ("device_types", "device_types__model"),
1271
1262
  ("inventory_items", "inventory_items__id"),
1272
1263
  ("inventory_items", "inventory_items__name"),
1264
+ ("name",),
1273
1265
  ("platforms", "platforms__id"),
1274
1266
  ("platforms", "platforms__name"),
1275
1267
  ]
@@ -1285,13 +1277,14 @@ class ManufacturerTestCase(FilterTestCases.NameOnlyFilterTestCase):
1285
1277
  InventoryItem.objects.create(device=devices[2], name="Inventory Item 3", manufacturer=cls.manufacturers[2])
1286
1278
 
1287
1279
 
1288
- class DeviceFamilyTestCase(FilterTestCases.NameOnlyFilterTestCase):
1280
+ class DeviceFamilyTestCase(FilterTestCases.FilterTestCase):
1289
1281
  queryset = DeviceFamily.objects.all()
1290
1282
  filterset = DeviceFamilyFilterSet
1291
1283
  generic_filter_tests = [
1292
1284
  ("description",),
1293
1285
  ("device_types", "device_types__id"),
1294
1286
  ("device_types", "device_types__model"),
1287
+ ("name",),
1295
1288
  ]
1296
1289
 
1297
1290
 
@@ -1481,11 +1474,6 @@ class DeviceTypeTestCase(FilterTestCases.FilterTestCase):
1481
1474
  self.queryset.exclude(device_bay_templates__isnull=False),
1482
1475
  )
1483
1476
 
1484
- def test_search(self):
1485
- value = self.queryset.values_list("pk", flat=True)[0]
1486
- params = {"q": value}
1487
- self.assertEqual(self.filterset(params, self.queryset).qs.values_list("pk", flat=True)[0], value)
1488
-
1489
1477
 
1490
1478
  class ConsolePortTemplateTestCase(ModularComponentTemplateTestMixin, FilterTestCases.FilterTestCase):
1491
1479
  queryset = ConsolePortTemplate.objects.all()
@@ -1633,7 +1621,7 @@ class DeviceBayTemplateTestCase(ComponentTemplateTestMixin, FilterTestCases.Filt
1633
1621
  filterset = DeviceBayTemplateFilterSet
1634
1622
 
1635
1623
 
1636
- class PlatformTestCase(FilterTestCases.NameOnlyFilterTestCase):
1624
+ class PlatformTestCase(FilterTestCases.FilterTestCase):
1637
1625
  queryset = Platform.objects.all()
1638
1626
  filterset = PlatformFilterSet
1639
1627
  generic_filter_tests = [
@@ -1641,6 +1629,7 @@ class PlatformTestCase(FilterTestCases.NameOnlyFilterTestCase):
1641
1629
  ("devices", "devices__id"),
1642
1630
  ("manufacturer", "manufacturer__id"),
1643
1631
  ("manufacturer", "manufacturer__name"),
1632
+ ("name",),
1644
1633
  ("napalm_driver",),
1645
1634
  ("virtual_machines", "virtual_machines__id"),
1646
1635
  ]
@@ -1702,7 +1691,6 @@ class DeviceTestCase(
1702
1691
  ("front_ports", "front_ports__id"),
1703
1692
  ("interfaces", "interfaces__id"),
1704
1693
  ("interfaces", "interfaces__name"),
1705
- ("ip_addresses", "interfaces__ip_addresses__id"),
1706
1694
  ("mac_address", "interfaces__mac_address"),
1707
1695
  ("manufacturer", "device_type__manufacturer__id"),
1708
1696
  ("manufacturer", "device_type__manufacturer__name"),
@@ -1717,6 +1705,8 @@ class DeviceTestCase(
1717
1705
  ("rack", "rack__name"),
1718
1706
  ("rack_group", "rack__rack_group__id"),
1719
1707
  ("rack_group", "rack__rack_group__name"),
1708
+ ("radio_profiles", "controller_managed_device_group__radio_profiles__id"),
1709
+ ("radio_profiles", "controller_managed_device_group__radio_profiles__name"),
1720
1710
  ("rear_ports", "rear_ports__id"),
1721
1711
  ("role", "role__id"),
1722
1712
  ("role", "role__name"),
@@ -1732,6 +1722,8 @@ class DeviceTestCase(
1732
1722
  ("vc_priority",),
1733
1723
  ("virtual_chassis", "virtual_chassis__id"),
1734
1724
  ("virtual_chassis", "virtual_chassis__name"),
1725
+ ("wireless_networks", "controller_managed_device_group__wireless_networks__id"),
1726
+ ("wireless_networks", "controller_managed_device_group__wireless_networks__name"),
1735
1727
  ]
1736
1728
 
1737
1729
  @classmethod
@@ -1773,6 +1765,14 @@ class DeviceTestCase(
1773
1765
  Service.objects.create(device=devices[1], name="dns", protocol="udp", ports=[53])
1774
1766
 
1775
1767
  cls.controller_managed_device_groups = list(ControllerManagedDeviceGroup.objects.all()[:2])
1768
+ cls.controller_managed_device_groups[0].radio_profiles.set(RadioProfile.objects.all()[:2])
1769
+ cls.controller_managed_device_groups[0].wireless_networks.set(
1770
+ WirelessNetwork.objects.filter(controller_managed_device_groups__isnull=True)[:2]
1771
+ )
1772
+ cls.controller_managed_device_groups[1].radio_profiles.set(RadioProfile.objects.all()[2:4])
1773
+ cls.controller_managed_device_groups[1].wireless_networks.set(
1774
+ WirelessNetwork.objects.filter(controller_managed_device_groups__isnull=True)[2:4]
1775
+ )
1776
1776
  cls.device_redundancy_groups = list(DeviceRedundancyGroup.objects.all()[:2])
1777
1777
  Device.objects.filter(pk=devices[0].pk).update(
1778
1778
  controller_managed_device_group=cls.controller_managed_device_groups[0],
@@ -1876,14 +1876,6 @@ class DeviceTestCase(
1876
1876
  Device.objects.filter(primary_ip4__isnull=True, primary_ip6__isnull=True),
1877
1877
  )
1878
1878
 
1879
- def test_ip_addresses(self):
1880
- addresses = list(IPAddress.objects.filter(interfaces__isnull=False)[:2])
1881
- params = {"ip_addresses": [addresses[0].address, addresses[1].id]}
1882
- self.assertQuerysetEqualAndNotEmpty(
1883
- self.filterset(params, self.queryset).qs,
1884
- self.queryset.filter(interfaces__ip_addresses__in=addresses).distinct(),
1885
- )
1886
-
1887
1879
  def test_virtual_chassis_member(self):
1888
1880
  # TODO: Not a generic_filter_test because this is a boolean filter but not a RelatedMembershipBooleanFilter
1889
1881
  with self.subTest():
@@ -1929,45 +1921,6 @@ class DeviceTestCase(
1929
1921
  Device.objects.filter(local_config_context_data__isnull=True),
1930
1922
  )
1931
1923
 
1932
- def test_search(self):
1933
- filter_fields = (
1934
- "name",
1935
- "serial",
1936
- "inventory_items__serial",
1937
- "asset_tag",
1938
- "device_type__manufacturer__name",
1939
- "comments",
1940
- )
1941
- for filter_field in filter_fields:
1942
- with self.subTest(f"test q filter by field {filter_field}"):
1943
- value = (
1944
- self.queryset.values_list(filter_field, flat=True)
1945
- .exclude(**{f"{filter_field}__in": ["", None]})
1946
- .first()
1947
- )
1948
- params = {"q": value}
1949
- # TODO: Remove pylint disable after issue is resolved (see: https://github.com/PyCQA/pylint/issues/7381)
1950
- # pylint: disable=unsupported-binary-operation
1951
- qs_filter = (
1952
- Q(name__icontains=value)
1953
- | Q(serial__icontains=value.strip())
1954
- | Q(inventory_items__serial__icontains=value.strip())
1955
- | Q(asset_tag__icontains=value.strip())
1956
- | Q(device_type__manufacturer__name__icontains=value.strip())
1957
- | Q(comments__icontains=value)
1958
- )
1959
- self.assertQuerysetEqualAndNotEmpty(
1960
- self.filterset(params, self.queryset).qs,
1961
- self.queryset.filter(qs_filter),
1962
- )
1963
-
1964
- with self.subTest("test q filter by field pk"):
1965
- value = self.queryset.values_list("pk", flat=True).first()
1966
- params = {"q": value}
1967
- self.assertQuerysetEqualAndNotEmpty(
1968
- self.filterset(params, self.queryset).qs, self.queryset.filter(id=value)
1969
- )
1970
-
1971
1924
 
1972
1925
  class ConsolePortTestCase(PathEndpointModelTestMixin, ModularDeviceComponentTestMixin, FilterTestCases.FilterTestCase):
1973
1926
  queryset = ConsolePort.objects.all()
@@ -2178,7 +2131,6 @@ class InterfaceTestCase(PathEndpointModelTestMixin, ModularDeviceComponentTestMi
2178
2131
  ("child_interfaces", "child_interfaces__name"),
2179
2132
  ("description",),
2180
2133
  # ("device", "device__id"), # TODO - InterfaceFilterSet overrides device as a MultiValueCharFilter on name only
2181
- ("ip_addresses", "ip_addresses__id"),
2182
2134
  ("label",),
2183
2135
  ("lag", "lag__id"),
2184
2136
  ("lag", "lag__name"),
@@ -2200,6 +2152,8 @@ class InterfaceTestCase(PathEndpointModelTestMixin, ModularDeviceComponentTestMi
2200
2152
  ("tagged_vlans", "tagged_vlans__vid"),
2201
2153
  ("untagged_vlan", "untagged_vlan__id"),
2202
2154
  ("untagged_vlan", "untagged_vlan__vid"),
2155
+ ("virtual_device_contexts", "virtual_device_contexts__id"),
2156
+ ("virtual_device_contexts", "virtual_device_contexts__name"),
2203
2157
  ]
2204
2158
 
2205
2159
  @classmethod
@@ -2424,20 +2378,17 @@ class InterfaceTestCase(PathEndpointModelTestMixin, ModularDeviceComponentTestMi
2424
2378
  status=interface_statuses[3],
2425
2379
  )
2426
2380
 
2427
- ipaddr_status = Status.objects.get_for_model(IPAddress).first()
2428
- prefix_status = Status.objects.get_for_model(Prefix).first()
2429
- namespace = Namespace.objects.first()
2430
- Prefix.objects.create(prefix="192.0.2.0/24", namespace=namespace, status=prefix_status)
2431
- Prefix.objects.create(prefix="2600::/64", namespace=namespace, status=prefix_status)
2432
- ipaddresses = (
2433
- IPAddress.objects.create(address="192.0.2.1/24", namespace=namespace, status=ipaddr_status),
2434
- IPAddress.objects.create(address="192.0.2.2/24", namespace=namespace, status=ipaddr_status),
2435
- IPAddress.objects.create(address="2600::1/120", namespace=namespace, status=ipaddr_status),
2436
- IPAddress.objects.create(address="2600::0100/120", namespace=namespace, status=ipaddr_status),
2437
- )
2438
-
2439
- cabled_interfaces[0].add_ip_addresses([ipaddresses[0], ipaddresses[2]])
2440
- cabled_interfaces[1].add_ip_addresses([ipaddresses[1], ipaddresses[3]])
2381
+ # Virtual Device Context
2382
+ vdc_status = Status.objects.get_for_model(VirtualDeviceContext).first()
2383
+ vdcs = [
2384
+ VirtualDeviceContext.objects.create(
2385
+ device=devices[2], status=vdc_status, identifier=200 + idx, name=f"Test VDC {idx}"
2386
+ )
2387
+ for idx in range(3)
2388
+ ]
2389
+ vdcs[0].interfaces.set(lag_interfaces)
2390
+ vdcs[1].interfaces.set(lag_interfaces)
2391
+ vdcs[2].interfaces.set(lag_interfaces)
2441
2392
 
2442
2393
  def test_enabled(self):
2443
2394
  # TODO: Not a generic_filter_test because this is a boolean filter but not a RelatedMembershipBooleanFilter
@@ -2672,14 +2623,6 @@ class InterfaceTestCase(PathEndpointModelTestMixin, ModularDeviceComponentTestMi
2672
2623
  with self.subTest("device (pk) filter with an invalid uuid"):
2673
2624
  self.assertFalse(self.filterset({"device": [uuid.uuid4()]}, self.queryset).is_valid())
2674
2625
 
2675
- def test_ip_addresses(self):
2676
- addresses = list(IPAddress.objects.filter(interfaces__isnull=False)[:2])
2677
- params = {"ip_addresses": [addresses[0].address, addresses[1].id]}
2678
- self.assertQuerysetEqualAndNotEmpty(
2679
- self.filterset(params, self.queryset).qs,
2680
- self.queryset.filter(ip_addresses__in=addresses).distinct(),
2681
- )
2682
-
2683
2626
  def test_kind(self):
2684
2627
  # TODO: Not a generic_filter_test because this is a single-value filter
2685
2628
  # 2.0 TODO: Support filtering for multiple values
@@ -3089,11 +3032,6 @@ class InventoryItemTestCase(DeviceComponentTestMixin, FilterTestCases.FilterTest
3089
3032
  params = {"serial": "abc"}
3090
3033
  self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1)
3091
3034
 
3092
- def test_search(self):
3093
- value = self.queryset.values_list("pk", flat=True)[0]
3094
- params = {"q": value}
3095
- self.assertEqual(self.filterset(params, self.queryset).qs.values_list("pk", flat=True)[0], value)
3096
-
3097
3035
 
3098
3036
  class VirtualChassisTestCase(FilterTestCases.FilterTestCase):
3099
3037
  queryset = VirtualChassis.objects.all()
@@ -3178,11 +3116,6 @@ class VirtualChassisTestCase(FilterTestCases.FilterTestCase):
3178
3116
  Device.objects.filter(pk=devices[3].pk).update(virtual_chassis=virtual_chassis[1])
3179
3117
  Device.objects.filter(pk=devices[5].pk).update(virtual_chassis=virtual_chassis[2])
3180
3118
 
3181
- def test_search(self):
3182
- value = self.queryset.values_list("pk", flat=True)[0]
3183
- params = {"q": value}
3184
- self.assertEqual(self.filterset(params, self.queryset).qs.values_list("pk", flat=True)[0], value)
3185
-
3186
3119
 
3187
3120
  class CableTestCase(FilterTestCases.FilterTestCase):
3188
3121
  queryset = Cable.objects.all()
@@ -3976,6 +3909,8 @@ class ControllerFilterSetTestCase(FilterTestCases.FilterTestCase):
3976
3909
  ("controller_device", "controller_device__name"),
3977
3910
  ("controller_device_redundancy_group", "controller_device_redundancy_group__id"),
3978
3911
  ("controller_device_redundancy_group", "controller_device_redundancy_group__name"),
3912
+ ("wireless_networks", "controller_managed_device_groups__wireless_networks__id"),
3913
+ ("wireless_networks", "controller_managed_device_groups__wireless_networks__name"),
3979
3914
  )
3980
3915
 
3981
3916
  @classmethod
@@ -4118,3 +4053,130 @@ class ModuleBayTestCase(FilterTestCases.FilterTestCase):
4118
4053
  module_bays = ModuleBay.objects.all()[:2]
4119
4054
  module_bays[0].tags.set(Tag.objects.get_for_model(ModuleBay))
4120
4055
  module_bays[1].tags.set(Tag.objects.get_for_model(ModuleBay)[:3])
4056
+
4057
+
4058
+ class VirtualDeviceContextTestCase(FilterTestCases.FilterTestCase, FilterTestCases):
4059
+ queryset = VirtualDeviceContext.objects.all()
4060
+ filterset = VirtualDeviceContextFilterSet
4061
+ generic_filter_tests = [
4062
+ ("description",),
4063
+ ("device", "device__name"),
4064
+ ("device", "device__id"),
4065
+ ("tenant", "tenant__name"),
4066
+ ("tenant", "tenant__id"),
4067
+ ("interfaces", "interfaces__id"),
4068
+ ("interfaces", "interfaces__name"),
4069
+ ("name",),
4070
+ ("role", "role__name"),
4071
+ ("status", "status__name"),
4072
+ ("role", "role__id"),
4073
+ ("status", "status__id"),
4074
+ ]
4075
+
4076
+ @classmethod
4077
+ def setUpTestData(cls):
4078
+ device = Device.objects.first()
4079
+ intf_status = Status.objects.get_for_model(Interface).first()
4080
+ vdc_status = Status.objects.get_for_model(VirtualDeviceContext).first()
4081
+ intf_role = Role.objects.get_for_model(Interface).first()
4082
+ interface = Interface.objects.create(
4083
+ name="Int1", device=device, status=intf_status, role=intf_role, type=InterfaceTypeChoices.TYPE_100GE_CFP
4084
+ )
4085
+ cls.ips_v4 = IPAddress.objects.filter(ip_version=4)[:3]
4086
+ cls.ips_v6 = IPAddress.objects.filter(ip_version=6)[:3]
4087
+ interface.add_ip_addresses([*cls.ips_v4, *cls.ips_v6])
4088
+ vdcs = [
4089
+ VirtualDeviceContext.objects.create(
4090
+ device=device,
4091
+ status=vdc_status,
4092
+ identifier=200 + idx,
4093
+ name=f"Test VDC {idx}",
4094
+ primary_ip4=cls.ips_v4[idx],
4095
+ primary_ip6=cls.ips_v6[idx],
4096
+ )
4097
+ for idx in range(3)
4098
+ ]
4099
+ vdcs[0].tags.set(Tag.objects.get_for_model(VirtualDeviceContext))
4100
+ vdcs[1].tags.set(Tag.objects.get_for_model(VirtualDeviceContext)[:3])
4101
+
4102
+ interfaces = [
4103
+ Interface.objects.create(
4104
+ device=device,
4105
+ type=InterfaceTypeChoices.TYPE_1GE_FIXED,
4106
+ name=f"Interface 00{idx}",
4107
+ status=intf_status,
4108
+ )
4109
+ for idx in range(3)
4110
+ ]
4111
+ InterfaceVDCAssignment.objects.create(virtual_device_context=vdcs[0], interface=interfaces[0])
4112
+ InterfaceVDCAssignment.objects.create(virtual_device_context=vdcs[1], interface=interfaces[0])
4113
+ InterfaceVDCAssignment.objects.create(virtual_device_context=vdcs[1], interface=interfaces[1])
4114
+ InterfaceVDCAssignment.objects.create(virtual_device_context=vdcs[2], interface=interfaces[2])
4115
+
4116
+ def test_has_primary_ip(self):
4117
+ # TODO: Not a generic_filter_test because this is a boolean filter but not a RelatedMembershipBooleanFilter
4118
+ with self.subTest():
4119
+ params = {"has_primary_ip": True}
4120
+ self.assertQuerysetEqualAndNotEmpty(
4121
+ self.filterset(params, self.queryset).qs,
4122
+ VirtualDeviceContext.objects.filter(Q(primary_ip4__isnull=False) | Q(primary_ip6__isnull=False)),
4123
+ )
4124
+ with self.subTest():
4125
+ params = {"has_primary_ip": False}
4126
+ self.assertQuerysetEqualAndNotEmpty(
4127
+ self.filterset(params, self.queryset).qs,
4128
+ VirtualDeviceContext.objects.filter(primary_ip4__isnull=True, primary_ip6__isnull=True),
4129
+ )
4130
+
4131
+ def test_primary_ip4(self):
4132
+ params = {"primary_ip4": ["192.0.2.1/24", self.ips_v4[0].pk]}
4133
+ self.assertQuerysetEqualAndNotEmpty(
4134
+ self.filterset(params, self.queryset).qs, VirtualDeviceContext.objects.filter(primary_ip4=self.ips_v4[0])
4135
+ )
4136
+
4137
+ def test_primary_ip6(self):
4138
+ params = {"primary_ip6": ["fe80::8ef:3eff:fe4c:3895/24", self.ips_v6[1].pk]}
4139
+ self.assertQuerysetEqualAndNotEmpty(
4140
+ self.filterset(params, self.queryset).qs, VirtualDeviceContext.objects.filter(primary_ip6=self.ips_v6[1])
4141
+ )
4142
+
4143
+
4144
+ class InterfaceVDCAssignmentTestCase(FilterTestCases.FilterTestCase):
4145
+ queryset = InterfaceVDCAssignment.objects.all()
4146
+ filterset = InterfaceVDCAssignmentFilterSet
4147
+ generic_filter_tests = [
4148
+ ("virtual_device_context", "virtual_device_context__id"),
4149
+ ("virtual_device_context", "virtual_device_context__name"),
4150
+ ("interface", "interface__id"),
4151
+ ("interface", "interface__name"),
4152
+ ("device", "interface__device__id"),
4153
+ ("device", "interface__device__name"),
4154
+ ]
4155
+
4156
+ @classmethod
4157
+ def setUpTestData(cls):
4158
+ device = Device.objects.first()
4159
+ vdc_status = Status.objects.get_for_model(VirtualDeviceContext)[0]
4160
+ interface_status = Status.objects.get_for_model(Interface)[0]
4161
+ interfaces = [
4162
+ Interface.objects.create(
4163
+ device=device,
4164
+ type=InterfaceTypeChoices.TYPE_1GE_FIXED,
4165
+ name=f"Interface 00{idx}",
4166
+ status=interface_status,
4167
+ )
4168
+ for idx in range(3)
4169
+ ]
4170
+ vdcs = [
4171
+ VirtualDeviceContext.objects.create(
4172
+ device=device,
4173
+ status=vdc_status,
4174
+ identifier=200 + idx,
4175
+ name=f"Test VDC {idx}",
4176
+ )
4177
+ for idx in range(3)
4178
+ ]
4179
+ InterfaceVDCAssignment.objects.create(virtual_device_context=vdcs[0], interface=interfaces[0])
4180
+ InterfaceVDCAssignment.objects.create(virtual_device_context=vdcs[1], interface=interfaces[0])
4181
+ InterfaceVDCAssignment.objects.create(virtual_device_context=vdcs[1], interface=interfaces[1])
4182
+ InterfaceVDCAssignment.objects.create(virtual_device_context=vdcs[2], interface=interfaces[2])
@@ -1,16 +1,8 @@
1
1
  from django.test import TestCase
2
2
 
3
3
  from nautobot.core.testing.forms import FormTestCases
4
- from nautobot.core.testing.mixins import NautobotTestCaseMixin
5
4
  from nautobot.dcim.choices import DeviceFaceChoices, InterfaceModeChoices, InterfaceTypeChoices, RackWidthChoices
6
- from nautobot.dcim.forms import (
7
- DeviceFilterForm,
8
- DeviceForm,
9
- InterfaceBulkEditForm,
10
- InterfaceCreateForm,
11
- InterfaceForm,
12
- RackForm,
13
- )
5
+ from nautobot.dcim.forms import DeviceFilterForm, DeviceForm, InterfaceCreateForm, InterfaceForm, RackForm
14
6
  from nautobot.dcim.models import (
15
7
  Device,
16
8
  DeviceType,
@@ -328,7 +320,7 @@ class RackTestCase(TestCase):
328
320
  self.assertTrue(form.is_valid())
329
321
 
330
322
 
331
- class InterfaceTestCase(NautobotTestCaseMixin, TestCase):
323
+ class InterfaceTestCase(TestCase):
332
324
  @classmethod
333
325
  def setUpTestData(cls):
334
326
  cls.device = Device.objects.first()
@@ -388,44 +380,3 @@ class InterfaceTestCase(NautobotTestCaseMixin, TestCase):
388
380
  self.vlan.locations.clear()
389
381
  form = InterfaceForm(data=self.data, instance=self.interface)
390
382
  self.assertTrue(form.is_valid())
391
-
392
- def test_untagged_vlans_dropdown_options_align_in_interface_edit_form_and_bulk_edit_form(self):
393
- """
394
- Assert that untagged_vlans field dropdown are populated correctly in InterfaceForm and InterfaceBulkEditForm,
395
- and that the queryset is the same for both forms.
396
- """
397
- status = Status.objects.get_for_model(Interface).first()
398
- location = Location.objects.filter(location_type=LocationType.objects.get(name="Campus")).first()
399
- devices = Device.objects.all()[:3]
400
- for device in devices:
401
- device.location = location
402
- device.save()
403
- interfaces = (
404
- Interface.objects.create(
405
- device=devices[0],
406
- name="Test Interface 1",
407
- type=InterfaceTypeChoices.TYPE_2GFC_SFP,
408
- status=status,
409
- ),
410
- Interface.objects.create(
411
- device=devices[1],
412
- name="Test Interface 2",
413
- type=InterfaceTypeChoices.TYPE_LAG,
414
- status=status,
415
- ),
416
- Interface.objects.create(
417
- device=devices[2],
418
- name="Test Interface 3",
419
- type=InterfaceTypeChoices.TYPE_100ME_FIXED,
420
- status=status,
421
- ),
422
- )
423
- edit_form = InterfaceForm(data=self.data, instance=interfaces[0])
424
- bulk_edit_form = InterfaceBulkEditForm(
425
- model=Interface,
426
- data={"pks": [interface.pk for interface in interfaces]},
427
- )
428
- self.assertQuerysetEqualAndNotEmpty(
429
- edit_form.fields["untagged_vlan"].queryset,
430
- bulk_edit_form.fields["untagged_vlan"].queryset,
431
- )
@@ -83,55 +83,3 @@ class GraphQLTestCase(TestCase):
83
83
  self.assertEqual(
84
84
  resp["data"]["devices"][0]["platform"]["network_driver_mappings"]["scrapli"], "cisco_iosxe"
85
85
  )
86
-
87
- with self.subTest("device serial number query"):
88
- non_empty_serial_device = Device.objects.first()
89
- non_empty_serial_device.serial = "1234567890abceFGHIJKL"
90
- non_empty_serial_device.save()
91
-
92
- # Test device serial query default behavior: serial__ie
93
- query = 'query { devices (serial: " ") { name serial } }'
94
- resp = execute_query(query, user=self.user).to_dict()
95
- self.assertFalse(resp["data"].get("error"))
96
- for device in resp["data"]["devices"]:
97
- self.assertEqual(device["serial"], "")
98
-
99
- # Test device serial default filter with non-empty serial number
100
- query = 'query { devices (serial:"' + non_empty_serial_device.serial.lower() + '") { name serial } }'
101
- resp = execute_query(query, user=self.user).to_dict()
102
- self.assertFalse(resp["data"].get("error"))
103
- self.assertEqual(resp["data"]["devices"][0]["serial"], non_empty_serial_device.serial)
104
-
105
- # Test device serial iexact filter with non-empty serial number
106
- query = 'query { devices (serial__ie:"' + non_empty_serial_device.serial.upper() + '") { name serial } }'
107
- resp = execute_query(query, user=self.user).to_dict()
108
- self.assertFalse(resp["data"].get("error"))
109
- self.assertEqual(resp["data"]["devices"][0]["serial"], non_empty_serial_device.serial)
110
-
111
- # Test device serial__nie filter with non-empty serial number
112
- query = 'query { devices (serial__nie:"' + non_empty_serial_device.serial.lower() + '") { name serial } }'
113
- resp = execute_query(query, user=self.user).to_dict()
114
- self.assertFalse(resp["data"].get("error"))
115
- for device in resp["data"]["devices"]:
116
- self.assertNotEqual(device["serial"], non_empty_serial_device.serial)
117
-
118
- # Test device serial__ie filter with empty serial number
119
- query = 'query { devices (serial__ie:" ") { name serial } }'
120
- resp = execute_query(query, user=self.user).to_dict()
121
- self.assertFalse(resp["data"].get("error"))
122
- for device in resp["data"]["devices"]:
123
- self.assertEqual(device["serial"], "")
124
-
125
- # Test device serial__nie filter with empty serial number
126
- query = 'query { devices (serial__nie:" ") { name serial } }'
127
- resp = execute_query(query, user=self.user).to_dict()
128
- self.assertFalse(resp["data"].get("error"))
129
- for device in resp["data"]["devices"]:
130
- self.assertNotEqual(device["serial"], "")
131
-
132
- # Test device serial__n filter with empty serial number
133
- query = 'query { devices (serial__n:" ") { name serial } }'
134
- resp = execute_query(query, user=self.user).to_dict()
135
- self.assertFalse(resp["data"].get("error"))
136
- for device in resp["data"]["devices"]:
137
- self.assertNotEqual(device["serial"], "")