nautobot 3.0.0a2__py3-none-any.whl → 3.0.0a3__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 (420) hide show
  1. nautobot/apps/choices.py +0 -2
  2. nautobot/apps/filters.py +7 -9
  3. nautobot/apps/models.py +2 -2
  4. nautobot/apps/ui.py +9 -1
  5. nautobot/circuits/filters.py +3 -2
  6. nautobot/circuits/navigation.py +3 -2
  7. nautobot/circuits/templates/circuits/circuit.html +1 -1
  8. nautobot/circuits/templates/circuits/circuit_create.html +3 -3
  9. nautobot/circuits/templates/circuits/circuittermination.html +1 -1
  10. nautobot/circuits/templates/circuits/circuittermination_create.html +9 -24
  11. nautobot/circuits/templates/circuits/circuittype.html +1 -1
  12. nautobot/circuits/templates/circuits/inc/circuit_termination_cable_fragment.html +6 -6
  13. nautobot/circuits/templates/circuits/inc/speed_widget.html +12 -12
  14. nautobot/circuits/templates/circuits/providernetwork.html +1 -1
  15. nautobot/circuits/tests/integration/test_circuit.py +10 -13
  16. nautobot/cloud/filters.py +1 -1
  17. nautobot/cloud/navigation.py +3 -2
  18. nautobot/core/api/schema.py +1 -1
  19. nautobot/core/api/serializers.py +6 -1
  20. nautobot/core/api/urls.py +1 -0
  21. nautobot/core/api/views.py +8 -0
  22. nautobot/core/apps/__init__.py +11 -10
  23. nautobot/core/celery/__init__.py +3 -5
  24. nautobot/core/checks.py +46 -0
  25. nautobot/core/cli/bootstrap_v3_to_v5.py +70 -1
  26. nautobot/core/cli/migrate_deprecated_templates.py +200 -0
  27. nautobot/core/constants.py +3 -0
  28. nautobot/core/context_processors.py +9 -1
  29. nautobot/core/forms/forms.py +1 -1
  30. nautobot/core/jobs/__init__.py +6 -3
  31. nautobot/core/jobs/groups.py +31 -1
  32. nautobot/core/management/commands/generate_test_data.py +28 -9
  33. nautobot/core/models/generics.py +9 -1
  34. nautobot/core/models/tree_queries.py +10 -5
  35. nautobot/core/settings.py +18 -12
  36. nautobot/core/settings.yaml +13 -7
  37. nautobot/core/signals.py +12 -1
  38. nautobot/core/tables.py +13 -6
  39. nautobot/core/templates/40x.html +1 -1
  40. nautobot/core/templates/500.html +2 -2
  41. nautobot/core/templates/admin/config/config.html +12 -12
  42. nautobot/core/templates/admin/index.html +3 -3
  43. nautobot/core/templates/buttons/export.html +1 -1
  44. nautobot/core/templates/components/button/dropdown.html +5 -3
  45. nautobot/core/templates/components/panel/body_wrapper_generic_table.html +1 -1
  46. nautobot/core/templates/components/panel/panel.html +3 -3
  47. nautobot/core/templates/components/tab/content_wrapper.html +2 -3
  48. nautobot/core/templates/components/tab/label_wrapper_distinct_view.html +1 -1
  49. nautobot/core/templates/echarts/echarts.html +1 -1
  50. nautobot/core/templates/generic/object_bulk_add_component.html +2 -1
  51. nautobot/core/templates/generic/object_bulk_create.html +4 -3
  52. nautobot/core/templates/generic/object_bulk_destroy.html +3 -3
  53. nautobot/core/templates/generic/object_bulk_remove.html +2 -2
  54. nautobot/core/templates/generic/object_bulk_update.html +5 -4
  55. nautobot/core/templates/generic/object_create.html +5 -4
  56. nautobot/core/templates/generic/object_import.html +2 -1
  57. nautobot/core/templates/generic/object_list.html +12 -4
  58. nautobot/core/templates/generic/object_notes.html +5 -3
  59. nautobot/core/templates/generic/object_retrieve.html +2 -3
  60. nautobot/core/templates/graphene/graphiql.html +7 -7
  61. nautobot/core/templates/home.html +1 -1
  62. nautobot/core/templates/import_success.html +2 -1
  63. nautobot/core/templates/inc/computed_fields/panel_data.html +1 -1
  64. nautobot/core/templates/inc/created_updated.html +7 -3
  65. nautobot/core/templates/inc/custom_fields/panel_data.html +1 -1
  66. nautobot/core/templates/inc/form_static_field.html +6 -0
  67. nautobot/core/templates/inc/header.html +1 -1
  68. nautobot/core/templates/inc/image_attachments.html +2 -1
  69. nautobot/core/templates/inc/nav_menu.html +2 -1
  70. nautobot/core/templates/inc/search_panel.html +4 -4
  71. nautobot/core/templates/login.html +4 -2
  72. nautobot/core/templates/nautobot_config.py.j2 +6 -5
  73. nautobot/core/templates/redoc_ui.html +7 -0
  74. nautobot/core/templates/search.html +1 -1
  75. nautobot/core/templates/swagger_ui.html +17 -3
  76. nautobot/core/templates/system_jobs/import_objects.html +1 -2
  77. nautobot/core/templates/utilities/confirmation_form.html +2 -2
  78. nautobot/core/templates/utilities/obj_table.html +10 -2
  79. nautobot/core/templates/utilities/render_field.html +7 -7
  80. nautobot/core/templates/utilities/render_jinja2.html +2 -2
  81. nautobot/core/templates/utilities/templatetags/filter_form_drawer.html +4 -4
  82. nautobot/core/templates/utilities/theme_preview.html +16 -3
  83. nautobot/core/templates/widgets/selectwithdisabled_option.html +3 -1
  84. nautobot/core/templatetags/helpers.py +52 -6
  85. nautobot/core/testing/api.py +68 -9
  86. nautobot/core/testing/filters.py +0 -23
  87. nautobot/core/testing/integration.py +23 -10
  88. nautobot/core/testing/mixins.py +2 -0
  89. nautobot/core/testing/views.py +4 -0
  90. nautobot/core/tests/integration/test_app_home.py +34 -30
  91. nautobot/core/tests/integration/test_app_navbar.py +3 -0
  92. nautobot/core/tests/nautobot_config_without_example_apps.py +4 -0
  93. nautobot/core/tests/runner.py +9 -1
  94. nautobot/core/tests/test_api.py +5 -3
  95. nautobot/core/tests/test_breadcrumbs.py +6 -7
  96. nautobot/core/tests/test_checks.py +28 -0
  97. nautobot/core/tests/test_cli.py +40 -0
  98. nautobot/core/tests/test_config.py +2 -1
  99. nautobot/core/tests/test_forms.py +55 -13
  100. nautobot/core/tests/test_jobs.py +75 -1
  101. nautobot/core/tests/test_nautobot_server.py +2 -0
  102. nautobot/core/tests/test_navigations.py +76 -1
  103. nautobot/core/tests/test_patch_social_django.py +42 -0
  104. nautobot/core/tests/test_tables.py +3 -1
  105. nautobot/core/tests/test_templatetags_helpers.py +53 -13
  106. nautobot/core/tests/test_templatetags_ui_framework.py +4 -4
  107. nautobot/core/tests/test_tree_queries.py +14 -1
  108. nautobot/core/tests/test_ui.py +1 -1
  109. nautobot/core/tests/test_utils.py +31 -4
  110. nautobot/core/tests/test_views.py +159 -31
  111. nautobot/core/ui/breadcrumbs.py +2 -12
  112. nautobot/core/ui/choices.py +142 -10
  113. nautobot/core/ui/constants.py +76 -12
  114. nautobot/core/ui/object_detail.py +92 -12
  115. nautobot/core/urls.py +12 -1
  116. nautobot/core/utils/cache.py +2 -1
  117. nautobot/core/utils/filtering.py +17 -17
  118. nautobot/core/utils/lookup.py +3 -8
  119. nautobot/core/utils/module_loading.py +21 -0
  120. nautobot/core/utils/patch_social_django.py +128 -0
  121. nautobot/core/views/__init__.py +38 -1
  122. nautobot/core/views/generic.py +3 -3
  123. nautobot/core/views/mixins.py +15 -3
  124. nautobot/core/views/renderers.py +2 -0
  125. nautobot/core/views/viewsets.py +2 -1
  126. nautobot/data_validation/apps.py +1 -5
  127. nautobot/data_validation/custom_validators.py +4 -4
  128. nautobot/data_validation/filters.py +1 -1
  129. nautobot/data_validation/forms.py +40 -0
  130. nautobot/data_validation/migrations/0001_initial.py +0 -7
  131. nautobot/data_validation/migrations/0002_data_migration_from_app.py +0 -12
  132. nautobot/data_validation/models.py +16 -7
  133. nautobot/data_validation/navigation.py +8 -1
  134. nautobot/data_validation/tables.py +12 -5
  135. nautobot/data_validation/templates/data_validation/datacompliance_tab.html +1 -0
  136. nautobot/data_validation/templates/data_validation/device_constraints.html +61 -0
  137. nautobot/data_validation/tests/__init__.py +2 -2
  138. nautobot/data_validation/tests/migrations/test_migrations.py +83 -3
  139. nautobot/data_validation/tests/test_data_compliance_rules.py +12 -7
  140. nautobot/data_validation/tests/test_filters.py +8 -6
  141. nautobot/data_validation/tests/test_models.py +15 -0
  142. nautobot/data_validation/tests/test_views.py +190 -32
  143. nautobot/data_validation/urls.py +2 -5
  144. nautobot/data_validation/views.py +73 -40
  145. nautobot/dcim/api/serializers.py +0 -13
  146. nautobot/dcim/apps.py +4 -0
  147. nautobot/dcim/choices.py +16 -0
  148. nautobot/dcim/custom_validators.py +84 -0
  149. nautobot/dcim/filter_mixins.py +353 -4
  150. nautobot/dcim/{filters/__init__.py → filters.py} +2 -35
  151. nautobot/dcim/forms.py +1 -1
  152. nautobot/dcim/migrations/0078_remove_device_location_tenant_name_uniqueness.py +16 -0
  153. nautobot/dcim/migrations/0079_device_name_data_migration.py +59 -0
  154. nautobot/dcim/models/device_components.py +81 -68
  155. nautobot/dcim/models/devices.py +13 -16
  156. nautobot/dcim/navigation.py +7 -6
  157. nautobot/dcim/tables/devices.py +3 -0
  158. nautobot/dcim/tables/template_code.py +14 -14
  159. nautobot/dcim/templates/dcim/cable.html +2 -61
  160. nautobot/dcim/templates/dcim/cable_connect.html +28 -112
  161. nautobot/dcim/templates/dcim/cable_edit.html +2 -5
  162. nautobot/dcim/templates/dcim/cable_retrieve.html +61 -0
  163. nautobot/dcim/templates/dcim/cable_trace.html +1 -3
  164. nautobot/dcim/templates/dcim/cable_update.html +5 -0
  165. nautobot/dcim/templates/dcim/consoleport.html +6 -5
  166. nautobot/dcim/templates/dcim/consoleserverport.html +6 -5
  167. nautobot/dcim/templates/dcim/device/config.html +2 -2
  168. nautobot/dcim/templates/dcim/device/consoleports.html +1 -1
  169. nautobot/dcim/templates/dcim/device/consoleserverports.html +1 -1
  170. nautobot/dcim/templates/dcim/device/devicebays.html +1 -1
  171. nautobot/dcim/templates/dcim/device/frontports.html +1 -1
  172. nautobot/dcim/templates/dcim/device/interfaces.html +1 -1
  173. nautobot/dcim/templates/dcim/device/inventory.html +1 -1
  174. nautobot/dcim/templates/dcim/device/lldp_neighbors.html +1 -1
  175. nautobot/dcim/templates/dcim/device/modulebays.html +1 -1
  176. nautobot/dcim/templates/dcim/device/poweroutlets.html +1 -1
  177. nautobot/dcim/templates/dcim/device/powerports.html +1 -1
  178. nautobot/dcim/templates/dcim/device/rearports.html +1 -1
  179. nautobot/dcim/templates/dcim/device/status.html +8 -8
  180. nautobot/dcim/templates/dcim/device/wireless.html +1 -1
  181. nautobot/dcim/templates/dcim/device.html +1 -1
  182. nautobot/dcim/templates/dcim/device_component_add.html +2 -2
  183. nautobot/dcim/templates/dcim/device_create.html +5 -3
  184. nautobot/dcim/templates/dcim/device_interface_delete.html +1 -1
  185. nautobot/dcim/templates/dcim/device_list.html +73 -10
  186. nautobot/dcim/templates/dcim/devicebay_populate.html +2 -2
  187. nautobot/dcim/templates/dcim/devicetype.html +1 -1
  188. nautobot/dcim/templates/dcim/devicetype_component_add.html +2 -2
  189. nautobot/dcim/templates/dcim/footer_convert_to_contact_or_team_record.html +14 -0
  190. nautobot/dcim/templates/dcim/frontport.html +9 -8
  191. nautobot/dcim/templates/dcim/inc/edit_form_softwareversion_js.html +2 -2
  192. nautobot/dcim/templates/dcim/interface.html +26 -6
  193. nautobot/dcim/templates/dcim/interface_bulk_delete.html +1 -1
  194. nautobot/dcim/templates/dcim/inventoryitem_add.html +3 -1
  195. nautobot/dcim/templates/dcim/inventoryitem_bulk_delete.html +1 -1
  196. nautobot/dcim/templates/dcim/inventoryitem_edit.html +3 -1
  197. nautobot/dcim/templates/dcim/location_retrieve.html +1 -242
  198. nautobot/dcim/templates/dcim/module/base.html +49 -9
  199. nautobot/dcim/templates/dcim/module_list.html +57 -8
  200. nautobot/dcim/templates/dcim/modulefamily_retrieve.html +1 -1
  201. nautobot/dcim/templates/dcim/moduletype_retrieve.html +49 -9
  202. nautobot/dcim/templates/dcim/platform_create.html +1 -1
  203. nautobot/dcim/templates/dcim/powerfeed.html +1 -1
  204. nautobot/dcim/templates/dcim/powerpanel.html +1 -1
  205. nautobot/dcim/templates/dcim/powerport.html +5 -4
  206. nautobot/dcim/templates/dcim/rack_elevation_list.html +16 -4
  207. nautobot/dcim/templates/dcim/rack_retrieve.html +33 -15
  208. nautobot/dcim/templates/dcim/rearport.html +7 -6
  209. nautobot/dcim/templates/dcim/virtualchassis.html +1 -1
  210. nautobot/dcim/templates/dcim/virtualchassis_add_member.html +16 -14
  211. nautobot/dcim/templates/dcim/virtualchassis_update.html +14 -6
  212. nautobot/dcim/tests/integration/test_controller.py +1 -0
  213. nautobot/dcim/tests/test_api.py +8 -0
  214. nautobot/dcim/tests/test_custom_validators.py +229 -0
  215. nautobot/dcim/tests/test_filters.py +12 -6
  216. nautobot/dcim/tests/test_models.py +63 -4
  217. nautobot/dcim/tests/test_views.py +63 -22
  218. nautobot/dcim/urls.py +64 -21
  219. nautobot/dcim/utils.py +3 -3
  220. nautobot/dcim/views.py +547 -273
  221. nautobot/extras/api/views.py +9 -1
  222. nautobot/extras/choices.py +2 -13
  223. nautobot/extras/{filters/mixins.py → filter_mixins.py} +1 -1
  224. nautobot/extras/{filters/customfields.py → filter_mixins_customfields.py} +42 -6
  225. nautobot/extras/{filters/__init__.py → filters.py} +14 -46
  226. nautobot/extras/forms/forms.py +5 -13
  227. nautobot/extras/forms/mixins.py +0 -41
  228. nautobot/extras/management/__init__.py +9 -0
  229. nautobot/extras/migrations/0127_approval_workflow_models.py +6 -6
  230. nautobot/extras/migrations/0129_jobresult_debug_log_count_jobresult_error_log_count_and_more.py +37 -0
  231. nautobot/extras/migrations/0130_jobresult_generate_log_entry_counts.py +42 -0
  232. nautobot/extras/models/__init__.py +1 -2
  233. nautobot/extras/models/approvals.py +22 -13
  234. nautobot/extras/models/contacts.py +2 -0
  235. nautobot/extras/models/groups.py +44 -5
  236. nautobot/extras/models/jobs.py +59 -1
  237. nautobot/extras/models/mixins.py +28 -0
  238. nautobot/extras/models/models.py +13 -0
  239. nautobot/extras/models/secrets.py +1 -0
  240. nautobot/extras/models/statuses.py +0 -15
  241. nautobot/extras/navigation.py +13 -9
  242. nautobot/extras/plugins/__init__.py +33 -55
  243. nautobot/extras/plugins/tables.py +3 -3
  244. nautobot/extras/plugins/urls.py +2 -21
  245. nautobot/extras/plugins/utils.py +1 -33
  246. nautobot/extras/plugins/views.py +0 -4
  247. nautobot/extras/signals.py +20 -19
  248. nautobot/extras/tables.py +52 -68
  249. nautobot/extras/templates/extras/approval_dashboard.html +7 -5
  250. nautobot/extras/templates/extras/approvalworkflowdefinition_update.html +4 -2
  251. nautobot/extras/templates/extras/approvalworkflowstage_retrieve.html +20 -12
  252. nautobot/extras/templates/extras/computedfield.html +1 -1
  253. nautobot/extras/templates/extras/configcontext.html +1 -1
  254. nautobot/extras/templates/extras/configcontextschema_validation.html +2 -2
  255. nautobot/extras/templates/extras/customfield.html +1 -1
  256. nautobot/extras/templates/extras/dynamicgroup_retrieve.html +11 -5
  257. nautobot/extras/templates/extras/dynamicgroup_update.html +1 -1
  258. nautobot/extras/templates/extras/gitrepository_result.html +0 -2
  259. nautobot/extras/templates/extras/graphqlquery_retrieve.html +1 -96
  260. nautobot/extras/templates/extras/inc/approval_buttons_column.html +20 -6
  261. nautobot/extras/templates/extras/inc/bulk_edit_overridable_field.html +8 -7
  262. nautobot/extras/templates/extras/inc/configcontext_format.html +10 -3
  263. nautobot/extras/templates/extras/inc/graphqlquery_execute.html +71 -0
  264. nautobot/extras/templates/extras/inc/job_tiles.html +15 -3
  265. nautobot/extras/templates/extras/inc/json_format.html +10 -3
  266. nautobot/extras/templates/extras/inc/overridable_field.html +13 -12
  267. nautobot/extras/templates/extras/job.html +29 -12
  268. nautobot/extras/templates/extras/job_bulk_edit.html +18 -0
  269. nautobot/extras/templates/extras/job_edit.html +52 -46
  270. nautobot/extras/templates/extras/job_list.html +29 -25
  271. nautobot/extras/templates/extras/marketplace.html +5 -9
  272. nautobot/extras/templates/extras/object_configcontext.html +1 -1
  273. nautobot/extras/templates/extras/object_dynamicgroups.html +2 -2
  274. nautobot/extras/templates/extras/objectchange_retrieve.html +19 -37
  275. nautobot/extras/templates/extras/plugin_detail.html +26 -21
  276. nautobot/extras/templates/extras/plugins_list.html +16 -26
  277. nautobot/extras/templates/extras/role_retrieve.html +64 -0
  278. nautobot/extras/templates/extras/scheduledjob.html +4 -2
  279. nautobot/extras/templates/extras/secretsgroup.html +1 -1
  280. nautobot/extras/templates/extras/tag.html +1 -1
  281. nautobot/extras/templatetags/custom_links.py +12 -12
  282. nautobot/extras/templatetags/job_buttons.py +14 -12
  283. nautobot/extras/test_jobs/invalid_import.py +9 -0
  284. nautobot/extras/test_jobs/log_counts_by_level.py +23 -0
  285. nautobot/extras/test_jobs/missing_import.py +11 -0
  286. nautobot/extras/tests/integration/test_configcontextschema.py +27 -26
  287. nautobot/extras/tests/integration/test_customfields.py +8 -7
  288. nautobot/extras/tests/integration/test_dynamicgroups.py +5 -1
  289. nautobot/extras/tests/integration/test_plugin_banner.py +3 -0
  290. nautobot/extras/tests/integration/test_plugins.py +18 -6
  291. nautobot/extras/tests/test_api.py +27 -18
  292. nautobot/extras/tests/test_approvals.py +38 -38
  293. nautobot/extras/tests/test_changelog.py +35 -3
  294. nautobot/extras/tests/test_customfields.py +22 -13
  295. nautobot/extras/tests/test_customfields_filters.py +479 -0
  296. nautobot/extras/tests/test_dynamicgroups.py +39 -1
  297. nautobot/extras/tests/test_filters.py +21 -19
  298. nautobot/extras/tests/test_forms.py +18 -21
  299. nautobot/extras/tests/test_jobs.py +25 -4
  300. nautobot/extras/tests/test_migrations.py +1 -0
  301. nautobot/extras/tests/test_models.py +13 -31
  302. nautobot/extras/tests/test_plugins.py +36 -10
  303. nautobot/extras/tests/test_views.py +31 -30
  304. nautobot/extras/views.py +81 -19
  305. nautobot/ipam/factory.py +7 -0
  306. nautobot/ipam/filter_mixins.py +38 -0
  307. nautobot/ipam/filters.py +27 -38
  308. nautobot/ipam/formfields.py +1 -1
  309. nautobot/ipam/forms.py +6 -3
  310. nautobot/ipam/migrations/0030_ipam__namespaces.py +13 -0
  311. nautobot/ipam/migrations/0031_ipam___data_migrations.py +4 -1
  312. nautobot/ipam/migrations/0054_namespace_tenant.py +25 -0
  313. nautobot/ipam/models.py +29 -2
  314. nautobot/ipam/navigation.py +3 -2
  315. nautobot/ipam/signals.py +71 -0
  316. nautobot/ipam/tables.py +13 -6
  317. nautobot/ipam/templates/ipam/inc/toggle_available.html +10 -10
  318. nautobot/ipam/templates/ipam/inc/vlangroup_header.html +1 -0
  319. nautobot/ipam/templates/ipam/ipaddress.html +14 -0
  320. nautobot/ipam/templates/ipam/ipaddress_merge.html +3 -3
  321. nautobot/ipam/templates/ipam/ipaddresstointerface_retrieve.html +1 -0
  322. nautobot/ipam/templates/ipam/namespace_update.html +15 -0
  323. nautobot/ipam/templates/ipam/prefix_delete.html +1 -1
  324. nautobot/ipam/templates/ipam/prefix_list.html +14 -13
  325. nautobot/ipam/templates/ipam/service.html +1 -1
  326. nautobot/ipam/templates/ipam/vlan.html +1 -1
  327. nautobot/ipam/templates/ipam/vlan_interfaces.html +1 -1
  328. nautobot/ipam/templates/ipam/vlan_vminterfaces.html +1 -1
  329. nautobot/ipam/tests/migration/test_migrations.py +89 -0
  330. nautobot/ipam/tests/test_api.py +13 -6
  331. nautobot/ipam/tests/test_filters.py +10 -0
  332. nautobot/ipam/tests/test_forms.py +1 -1
  333. nautobot/ipam/tests/test_models.py +43 -1
  334. nautobot/ipam/tests/test_tables.py +1 -2
  335. nautobot/ipam/tests/test_utils.py +1 -1
  336. nautobot/ipam/tests/test_views.py +13 -14
  337. nautobot/ipam/ui.py +0 -17
  338. nautobot/ipam/utils/migrations.py +16 -2
  339. nautobot/ipam/utils/testing.py +9 -3
  340. nautobot/ipam/views.py +46 -6
  341. nautobot/project-static/dist/css/nautobot.css +1 -1
  342. nautobot/project-static/dist/css/nautobot.css.map +1 -1
  343. nautobot/project-static/dist/js/nautobot.js +1 -1
  344. nautobot/project-static/dist/js/nautobot.js.map +1 -1
  345. nautobot/project-static/js/cabletrace.js +1 -1
  346. nautobot/project-static/js/interface_filtering.js +20 -16
  347. nautobot/project-static/nautobot-icons/battery-3.svg +3 -0
  348. nautobot/project-static/nautobot-icons/cloud.svg +1 -1
  349. nautobot/project-static/nautobot-icons/control-panel.svg +1 -1
  350. nautobot/project-static/nautobot-icons/device-lifecycle.svg +1 -1
  351. nautobot/project-static/nautobot-icons/elements.svg +1 -1
  352. nautobot/project-static/nautobot-icons/extensibility.svg +3 -0
  353. nautobot/project-static/nautobot-icons/hammer.svg +1 -1
  354. nautobot/project-static/nautobot-icons/organization.svg +3 -0
  355. nautobot/project-static/nautobot-icons/secrets.svg +1 -1
  356. nautobot/project-static/nautobot-icons/security.svg +3 -0
  357. nautobot/project-static/nautobot-icons/server.svg +1 -1
  358. nautobot/project-static/nautobot-icons/star-filled.svg +1 -1
  359. nautobot/project-static/nautobot-icons/star.svg +1 -1
  360. nautobot/tenancy/api/serializers.py +1 -0
  361. nautobot/tenancy/api/views.py +2 -1
  362. nautobot/tenancy/{filters/__init__.py → filters.py} +2 -10
  363. nautobot/tenancy/navigation.py +3 -1
  364. nautobot/tenancy/tests/test_filters.py +0 -2
  365. nautobot/tenancy/views.py +2 -1
  366. nautobot/ui/src/js/collapse.js +3 -3
  367. nautobot/ui/src/js/nautobot.js +16 -0
  368. nautobot/ui/src/scss/colors.scss +1 -1
  369. nautobot/ui/src/scss/nautobot.scss +61 -28
  370. nautobot/users/templates/users/profile.html +45 -12
  371. nautobot/users/templates/users/sessionkey_delete.html +1 -1
  372. nautobot/users/tests/test_api.py +4 -0
  373. nautobot/users/views.py +4 -2
  374. nautobot/virtualization/models.py +1 -68
  375. nautobot/virtualization/navigation.py +3 -2
  376. nautobot/virtualization/templates/virtualization/virtual_machine_vminterface_delete.html +1 -1
  377. nautobot/virtualization/templates/virtualization/virtualmachine.html +1 -1
  378. nautobot/virtualization/templates/virtualization/virtualmachine_list.html +2 -2
  379. nautobot/virtualization/templates/virtualization/virtualmachine_update.html +3 -1
  380. nautobot/virtualization/tests/test_api.py +3 -0
  381. nautobot/virtualization/tests/test_models.py +44 -4
  382. nautobot/vpn/__init__.py +0 -0
  383. nautobot/vpn/api/serializers.py +113 -0
  384. nautobot/vpn/api/urls.py +19 -0
  385. nautobot/vpn/api/views.py +70 -0
  386. nautobot/vpn/apps.py +8 -0
  387. nautobot/vpn/choices.py +171 -0
  388. nautobot/vpn/factory.py +209 -0
  389. nautobot/vpn/filters.py +233 -0
  390. nautobot/vpn/forms.py +486 -0
  391. nautobot/vpn/homepage.py +19 -0
  392. nautobot/vpn/migrations/0001_initial.py +541 -0
  393. nautobot/vpn/migrations/0002_populate_defaults.py +199 -0
  394. nautobot/vpn/migrations/__init__.py +0 -0
  395. nautobot/vpn/models.py +527 -0
  396. nautobot/vpn/navigation.py +98 -0
  397. nautobot/vpn/tables.py +380 -0
  398. nautobot/vpn/templates/vpn/vpnprofile.html +2 -0
  399. nautobot/vpn/templates/vpn/vpnprofile_create.html +150 -0
  400. nautobot/vpn/tests/__init__.py +0 -0
  401. nautobot/vpn/tests/test_api.py +341 -0
  402. nautobot/vpn/tests/test_filters.py +139 -0
  403. nautobot/vpn/tests/test_forms.py +294 -0
  404. nautobot/vpn/tests/test_models.py +97 -0
  405. nautobot/vpn/tests/test_views.py +281 -0
  406. nautobot/vpn/urls.py +16 -0
  407. nautobot/vpn/views.py +437 -0
  408. nautobot/wireless/navigation.py +3 -2
  409. nautobot/wireless/tests/integration/test_radio_profile.py +1 -5
  410. nautobot/wireless/tests/test_api.py +1 -1
  411. {nautobot-3.0.0a2.dist-info → nautobot-3.0.0a3.dist-info}/METADATA +14 -14
  412. {nautobot-3.0.0a2.dist-info → nautobot-3.0.0a3.dist-info}/RECORD +417 -366
  413. {nautobot-3.0.0a2.dist-info → nautobot-3.0.0a3.dist-info}/entry_points.txt +1 -0
  414. nautobot/data_validation/template_content.py +0 -42
  415. nautobot/dcim/filters/mixins.py +0 -354
  416. nautobot/ipam/templates/ipam/inc/prefix_header_extra_content_table.html +0 -4
  417. /nautobot/tenancy/{filters/mixins.py → filter_mixins.py} +0 -0
  418. {nautobot-3.0.0a2.dist-info → nautobot-3.0.0a3.dist-info}/LICENSE.txt +0 -0
  419. {nautobot-3.0.0a2.dist-info → nautobot-3.0.0a3.dist-info}/NOTICE +0 -0
  420. {nautobot-3.0.0a2.dist-info → nautobot-3.0.0a3.dist-info}/WHEEL +0 -0
@@ -0,0 +1,341 @@
1
+ """Unit tests for vpn."""
2
+
3
+ from nautobot.apps.testing import APIViewTestCases
4
+ from nautobot.dcim.models import Interface
5
+ from nautobot.extras.models import Status
6
+ from nautobot.vpn import choices, models
7
+
8
+
9
+ class VPNProfileAPITest(APIViewTestCases.APIViewTestCase):
10
+ """VPNProfile API tests."""
11
+
12
+ # Removes 'crypt' because of encryption_algorithm field.
13
+ VERBOTEN_STRINGS = (
14
+ "password",
15
+ "argon2",
16
+ "bcrypt",
17
+ "md5",
18
+ "pbkdf2",
19
+ "scrypt",
20
+ "sha1",
21
+ "sha256",
22
+ "sha512",
23
+ )
24
+ model = models.VPNProfile
25
+ choices_fields = ()
26
+
27
+ @classmethod
28
+ def setUpTestData(cls):
29
+ super().setUpTestData()
30
+
31
+ cls.create_data = [
32
+ {
33
+ "name": "test 1",
34
+ "description": "test value",
35
+ "keepalive_enabled": True,
36
+ "keepalive_interval": 3,
37
+ "keepalive_retries": 5,
38
+ "nat_traversal": False,
39
+ "extra_options": None,
40
+ },
41
+ {
42
+ "name": "test 2",
43
+ "description": "test value",
44
+ "keepalive_enabled": True,
45
+ "keepalive_interval": 15,
46
+ "keepalive_retries": 3,
47
+ "nat_traversal": False,
48
+ "extra_options": None,
49
+ },
50
+ {
51
+ "name": "test 3",
52
+ "description": "test value",
53
+ "keepalive_enabled": True,
54
+ "keepalive_interval": 30,
55
+ "keepalive_retries": 3,
56
+ "nat_traversal": True,
57
+ "extra_options": None,
58
+ },
59
+ ]
60
+
61
+ cls.update_data = {
62
+ "name": "test 1",
63
+ "description": "updated value",
64
+ "keepalive_enabled": True,
65
+ "keepalive_interval": 60,
66
+ "keepalive_retries": 3,
67
+ "nat_traversal": False,
68
+ "extra_options": None,
69
+ }
70
+
71
+
72
+ class VPNPhase1PolicyAPITest(APIViewTestCases.APIViewTestCase):
73
+ """VPNPhase1Policy API tests."""
74
+
75
+ # Removes 'crypt' because of encryption_algorithm field.
76
+ VERBOTEN_STRINGS = (
77
+ "password",
78
+ "argon2",
79
+ "bcrypt",
80
+ "md5",
81
+ "pbkdf2",
82
+ "scrypt",
83
+ "sha1",
84
+ "sha256",
85
+ "sha512",
86
+ )
87
+ model = models.VPNPhase1Policy
88
+ choices_fields = (
89
+ "ike_version",
90
+ "encryption_algorithm",
91
+ "integrity_algorithm",
92
+ "dh_group",
93
+ "authentication_method",
94
+ )
95
+
96
+ @classmethod
97
+ def setUpTestData(cls):
98
+ super().setUpTestData()
99
+
100
+ cls.create_data = [
101
+ {
102
+ "name": "test 1",
103
+ "description": "test value",
104
+ "ike_version": choices.IkeVersionChoices.ike_v2,
105
+ "aggressive_mode": False,
106
+ "encryption_algorithm": [choices.EncryptionAlgorithmChoices.aes_128_cbc],
107
+ "integrity_algorithm": [choices.IntegrityAlgorithmChoices.sha1],
108
+ "dh_group": [choices.DhGroupChoices.group5],
109
+ "lifetime_seconds": 10,
110
+ "lifetime_kb": None,
111
+ "authentication_method": choices.AuthenticationMethodChoices.rsa,
112
+ },
113
+ {
114
+ "name": "test 2",
115
+ "description": "test value",
116
+ "ike_version": choices.IkeVersionChoices.ike_v2,
117
+ "aggressive_mode": False,
118
+ "encryption_algorithm": [choices.EncryptionAlgorithmChoices.aes_256_gcm],
119
+ "integrity_algorithm": [choices.IntegrityAlgorithmChoices.sha256],
120
+ "dh_group": [choices.DhGroupChoices.group14],
121
+ "lifetime_seconds": 10,
122
+ "lifetime_kb": None,
123
+ "authentication_method": choices.AuthenticationMethodChoices.ecdsa,
124
+ },
125
+ {
126
+ "name": "test 3",
127
+ "description": "test value",
128
+ "ike_version": choices.IkeVersionChoices.ike_v2,
129
+ "aggressive_mode": False,
130
+ "encryption_algorithm": [choices.EncryptionAlgorithmChoices.aes_192_cbc],
131
+ "integrity_algorithm": [choices.IntegrityAlgorithmChoices.sha512],
132
+ "dh_group": [choices.DhGroupChoices.group21],
133
+ "lifetime_seconds": 10,
134
+ "lifetime_kb": None,
135
+ "authentication_method": choices.AuthenticationMethodChoices.certificate,
136
+ },
137
+ ]
138
+
139
+ cls.update_data = {
140
+ "name": "test 1",
141
+ "description": "updated value",
142
+ "ike_version": choices.IkeVersionChoices.ike_v1,
143
+ "lifetime_seconds": 5,
144
+ "authentication_method": choices.AuthenticationMethodChoices.ecdsa,
145
+ }
146
+
147
+
148
+ class VPNPhase2PolicyAPITest(APIViewTestCases.APIViewTestCase):
149
+ """VPNPhase2Policy API tests."""
150
+
151
+ # Removes 'crypt' because of encryption_algorithm field.
152
+ VERBOTEN_STRINGS = (
153
+ "password",
154
+ "argon2",
155
+ "bcrypt",
156
+ "md5",
157
+ "pbkdf2",
158
+ "scrypt",
159
+ "sha1",
160
+ "sha256",
161
+ "sha512",
162
+ )
163
+ model = models.VPNPhase2Policy
164
+ choices_fields = (
165
+ "encryption_algorithm",
166
+ "integrity_algorithm",
167
+ "pfs_group",
168
+ )
169
+
170
+ @classmethod
171
+ def setUpTestData(cls):
172
+ super().setUpTestData()
173
+
174
+ cls.create_data = [
175
+ {
176
+ "name": "test 1",
177
+ "description": "test value",
178
+ "encryption_algorithm": [choices.EncryptionAlgorithmChoices.aes_128_cbc],
179
+ "integrity_algorithm": [choices.IntegrityAlgorithmChoices.sha1],
180
+ "pfs_group": [choices.DhGroupChoices.group5],
181
+ "lifetime": 10,
182
+ },
183
+ {
184
+ "name": "test 2",
185
+ "description": "test value",
186
+ "encryption_algorithm": [choices.EncryptionAlgorithmChoices.aes_256_gcm],
187
+ "integrity_algorithm": [choices.IntegrityAlgorithmChoices.sha256],
188
+ "pfs_group": [choices.DhGroupChoices.group14],
189
+ "lifetime": 10,
190
+ },
191
+ {
192
+ "name": "test 3",
193
+ "description": "test value",
194
+ "encryption_algorithm": [choices.EncryptionAlgorithmChoices.aes_192_cbc],
195
+ "integrity_algorithm": [choices.IntegrityAlgorithmChoices.sha512],
196
+ "pfs_group": [choices.DhGroupChoices.group21],
197
+ "lifetime": 10,
198
+ },
199
+ ]
200
+
201
+ cls.update_data = {
202
+ "name": "test 1",
203
+ "description": "updated value",
204
+ "lifetime_seconds": 5,
205
+ }
206
+
207
+
208
+ class VPNAPITest(APIViewTestCases.APIViewTestCase):
209
+ """VPN API tests."""
210
+
211
+ model = models.VPN
212
+ choices_fields = ()
213
+
214
+ @classmethod
215
+ def setUpTestData(cls):
216
+ super().setUpTestData()
217
+
218
+ profiles = models.VPNProfile.objects.all()
219
+
220
+ cls.create_data = [
221
+ {
222
+ "name": "test 1",
223
+ "description": "test value",
224
+ "vpn_id": "test value",
225
+ "vpn_profile": profiles[1].pk,
226
+ },
227
+ {
228
+ "name": "test 2",
229
+ "description": "test value",
230
+ "vpn_id": "test value",
231
+ "vpn_profile": profiles[2].pk,
232
+ },
233
+ {
234
+ "name": "test 3",
235
+ "description": "test value",
236
+ "vpn_id": "test value",
237
+ "vpn_profile": profiles[3].pk,
238
+ },
239
+ ]
240
+
241
+ cls.update_data = {
242
+ "name": "test 3",
243
+ "vpn_profile": profiles[4].pk,
244
+ }
245
+
246
+
247
+ class VPNTunnelAPITest(APIViewTestCases.APIViewTestCase):
248
+ """VPNTunnel API tests."""
249
+
250
+ model = models.VPNTunnel
251
+ choices_fields = ("encapsulation",)
252
+
253
+ @classmethod
254
+ def setUpTestData(cls):
255
+ super().setUpTestData()
256
+
257
+ endpoints = models.VPNTunnelEndpoint.objects.all()
258
+
259
+ cls.create_data = [
260
+ {
261
+ "name": "test 1",
262
+ "description": "test value",
263
+ "vpn_profile": models.VPNProfile.objects.first().pk,
264
+ "vpn": models.VPN.objects.first().pk,
265
+ "tunnel_id": "test value",
266
+ "status": Status.objects.get(name="Active").pk,
267
+ "encapsulation": choices.EncapsulationChoices.ipsec_tunnel,
268
+ "endpoint_a": endpoints[1].pk,
269
+ "endpoint_z": endpoints[2].pk,
270
+ },
271
+ {
272
+ "name": "test 2",
273
+ "description": "test value",
274
+ "vpn_profile": models.VPNProfile.objects.first().pk,
275
+ "vpn": models.VPN.objects.first().pk,
276
+ "tunnel_id": "test value",
277
+ "status": Status.objects.get(name="Active").pk,
278
+ "encapsulation": choices.EncapsulationChoices.l2tp,
279
+ "endpoint_a": endpoints[3].pk,
280
+ "endpoint_z": endpoints[4].pk,
281
+ },
282
+ {
283
+ "name": "test 3",
284
+ "description": "test value",
285
+ "vpn_profile": models.VPNProfile.objects.first().pk,
286
+ "vpn": models.VPN.objects.first().pk,
287
+ "tunnel_id": "test value",
288
+ "status": Status.objects.get(name="Active").pk,
289
+ "encapsulation": choices.EncapsulationChoices.ipsec_transport,
290
+ "endpoint_a": endpoints[5].pk,
291
+ "endpoint_z": endpoints[6].pk,
292
+ },
293
+ ]
294
+
295
+ cls.update_data = {
296
+ "name": "test 4",
297
+ "encapsulation": choices.EncapsulationChoices.ipsec_transport,
298
+ "endpoint_a": endpoints[7].pk,
299
+ "endpoint_z": endpoints[8].pk,
300
+ }
301
+
302
+ def get_deletable_object(self):
303
+ """Return VPNTunnel where both endpoints are attached to a device."""
304
+ return models.VPNTunnel.objects.create(name="Deletable VPN Tunnel", status=Status.objects.get(name="Active"))
305
+
306
+
307
+ class VPNTunnelEndpointAPITest(APIViewTestCases.APIViewTestCase):
308
+ """VPNTunnelEndpoint API tests."""
309
+
310
+ model = models.VPNTunnelEndpoint
311
+ choices_fields = ()
312
+
313
+ @classmethod
314
+ def setUpTestData(cls):
315
+ super().setUpTestData()
316
+
317
+ interfaces = Interface.objects.filter(device__isnull=False, vpn_tunnel_endpoints_src_int__isnull=True)
318
+
319
+ cls.create_data = [
320
+ {
321
+ "device": interfaces[0].device.pk,
322
+ "source_interface": interfaces[0].pk,
323
+ "vpn_profile": models.VPNProfile.objects.first().pk,
324
+ },
325
+ {
326
+ "device": interfaces[1].device.pk,
327
+ "source_interface": interfaces[1].pk,
328
+ "vpn_profile": models.VPNProfile.objects.first().pk,
329
+ },
330
+ {
331
+ "device": interfaces[2].device.pk,
332
+ "source_interface": interfaces[2].pk,
333
+ "vpn_profile": models.VPNProfile.objects.first().pk,
334
+ },
335
+ ]
336
+
337
+ cls.update_data = {
338
+ "device": interfaces[2].device.pk,
339
+ "source_interface": interfaces[2].pk,
340
+ "vpn_profile": models.VPNProfile.objects.last().pk,
341
+ }
@@ -0,0 +1,139 @@
1
+ """Test vpn Filters."""
2
+
3
+ from nautobot.apps.testing import FilterTestCases
4
+ from nautobot.vpn import filters, models
5
+
6
+
7
+ class VPNProfileFilterTestCase(FilterTestCases.FilterTestCase):
8
+ """VPNProfileFilterSet Test Case."""
9
+
10
+ queryset = models.VPNProfile.objects.all()
11
+ filterset = filters.VPNProfileFilterSet
12
+ generic_filter_tests = (
13
+ ("name",),
14
+ ("description",),
15
+ ("vpn_phase1_policies", "vpn_phase1_policies__id"),
16
+ ("vpn_phase1_policies", "vpn_phase1_policies__name"),
17
+ ("vpn_phase2_policies", "vpn_phase2_policies__id"),
18
+ ("vpn_phase2_policies", "vpn_phase2_policies__name"),
19
+ ("keepalive_interval",),
20
+ ("keepalive_retries",),
21
+ )
22
+
23
+
24
+ class VPNPhase1PolicyFilterTestCase(FilterTestCases.FilterTestCase):
25
+ """VPNPhase1PolicyFilterSet Test Case."""
26
+
27
+ queryset = models.VPNPhase1Policy.objects.all()
28
+ filterset = filters.VPNPhase1PolicyFilterSet
29
+ generic_filter_tests = (
30
+ ("name",),
31
+ ("description",),
32
+ ("lifetime_seconds",),
33
+ ("lifetime_kb",),
34
+ ("authentication_method",),
35
+ )
36
+
37
+ def test_encryption_algorithm(self):
38
+ self.assertQuerysetEqualAndNotEmpty(
39
+ self.filterset({"encryption_algorithm": "AES-128-CBC"}, self.queryset).qs,
40
+ self.queryset.filter(encryption_algorithm__contains=["AES-128-CBC"]),
41
+ ordered=False,
42
+ )
43
+
44
+ def test_integrity_algorithm(self):
45
+ self.assertQuerysetEqualAndNotEmpty(
46
+ self.filterset({"integrity_algorithm": "SHA256"}, self.queryset).qs,
47
+ self.queryset.filter(integrity_algorithm__contains=["SHA256"]),
48
+ ordered=False,
49
+ )
50
+
51
+ def test_dh_group(self):
52
+ self.assertQuerysetEqualAndNotEmpty(
53
+ self.filterset({"dh_group": "14"}, self.queryset).qs,
54
+ self.queryset.filter(dh_group__contains=["14"]),
55
+ ordered=False,
56
+ )
57
+
58
+
59
+ class VPNPhase2PolicyFilterTestCase(FilterTestCases.FilterTestCase):
60
+ """VPNPhase2PolicyFilterSet Test Case."""
61
+
62
+ queryset = models.VPNPhase2Policy.objects.all()
63
+ filterset = filters.VPNPhase2PolicyFilterSet
64
+ generic_filter_tests = (
65
+ ("name",),
66
+ ("description",),
67
+ ("lifetime",),
68
+ )
69
+
70
+ def test_encryption_algorithm(self):
71
+ self.assertQuerysetEqualAndNotEmpty(
72
+ self.filterset({"encryption_algorithm": "AES-128-CBC"}, self.queryset).qs,
73
+ self.queryset.filter(encryption_algorithm__contains=["AES-128-CBC"]),
74
+ ordered=False,
75
+ )
76
+
77
+ def test_integrity_algorithm(self):
78
+ self.assertQuerysetEqualAndNotEmpty(
79
+ self.filterset({"integrity_algorithm": "SHA256"}, self.queryset).qs,
80
+ self.queryset.filter(integrity_algorithm__contains=["SHA256"]),
81
+ ordered=False,
82
+ )
83
+
84
+ def test_pfs_group(self):
85
+ self.assertQuerysetEqualAndNotEmpty(
86
+ self.filterset({"pfs_group": "14"}, self.queryset).qs,
87
+ self.queryset.filter(pfs_group__contains=["14"]),
88
+ ordered=False,
89
+ )
90
+
91
+
92
+ class VPNFilterTestCase(FilterTestCases.FilterTestCase):
93
+ """VPNFilterSet Test Case."""
94
+
95
+ queryset = models.VPN.objects.all()
96
+ filterset = filters.VPNFilterSet
97
+ generic_filter_tests = (
98
+ ("vpn_profile", "vpn_profile__id"),
99
+ ("vpn_profile", "vpn_profile__name"),
100
+ ("name",),
101
+ ("description",),
102
+ ("vpn_id",),
103
+ )
104
+
105
+
106
+ class VPNTunnelFilterTestCase(FilterTestCases.FilterTestCase):
107
+ """VPNTunnelFilterSet Test Case."""
108
+
109
+ queryset = models.VPNTunnel.objects.all()
110
+ filterset = filters.VPNTunnelFilterSet
111
+ generic_filter_tests = (
112
+ ("id",),
113
+ ("vpn_profile", "vpn_profile__id"),
114
+ ("vpn_profile", "vpn_profile__name"),
115
+ ("vpn", "vpn__id"),
116
+ ("vpn", "vpn__name"),
117
+ ("name",),
118
+ ("description",),
119
+ ("tunnel_id",),
120
+ ("encapsulation",),
121
+ )
122
+
123
+
124
+ class VPNTunnelEndpointFilterTestCase(FilterTestCases.FilterTestCase):
125
+ """VPNTunnelEndpointFilterSet Test Case."""
126
+
127
+ queryset = models.VPNTunnelEndpoint.objects.all()
128
+ filterset = filters.VPNTunnelEndpointFilterSet
129
+ generic_filter_tests = (
130
+ ("device", "device__id"),
131
+ ("device", "device__name"),
132
+ ("source_interface", "source_interface__id"),
133
+ ("source_interface", "source_interface__name"),
134
+ ("source_fqdn",),
135
+ ("endpoint_a_vpn_tunnels", "endpoint_a_vpn_tunnels__id"),
136
+ ("endpoint_a_vpn_tunnels", "endpoint_a_vpn_tunnels__name"),
137
+ ("endpoint_z_vpn_tunnels", "endpoint_z_vpn_tunnels__id"),
138
+ ("endpoint_z_vpn_tunnels", "endpoint_z_vpn_tunnels__name"),
139
+ )