nautobot 3.0.0a3__py3-none-any.whl → 3.0.0rc1__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.
Files changed (388) hide show
  1. nautobot/apps/choices.py +4 -0
  2. nautobot/apps/ui.py +4 -0
  3. nautobot/apps/utils.py +8 -0
  4. nautobot/circuits/tests/integration/test_circuits_bulk_operations.py +0 -3
  5. nautobot/circuits/views.py +6 -2
  6. nautobot/core/api/serializers.py +1 -1
  7. nautobot/core/api/urls.py +1 -0
  8. nautobot/core/api/views.py +4 -0
  9. nautobot/core/choices.py +1 -1
  10. nautobot/core/cli/bootstrap_v3_to_v5.py +36 -13
  11. nautobot/core/cli/migrate_deprecated_templates.py +36 -9
  12. nautobot/core/filters.py +4 -0
  13. nautobot/core/forms/__init__.py +2 -0
  14. nautobot/core/forms/widgets.py +21 -2
  15. nautobot/core/jobs/__init__.py +56 -0
  16. nautobot/core/management/commands/generate_test_data.py +3 -3
  17. nautobot/core/models/__init__.py +11 -0
  18. nautobot/core/models/utils.py +1 -1
  19. nautobot/core/settings.py +17 -7
  20. nautobot/core/settings.yaml +4 -26
  21. nautobot/core/templates/admin/base.html +1 -2
  22. nautobot/core/templates/admin/change_list.html +9 -12
  23. nautobot/core/templates/base_django.html +1 -2
  24. nautobot/core/templates/components/panel/header_extra_content_table.html +1 -1
  25. nautobot/core/templates/components/tab/content_wrapper.html +4 -4
  26. nautobot/core/templates/echarts/echarts.html +21 -8
  27. nautobot/core/templates/generic/object_bulk_create.html +2 -2
  28. nautobot/core/templates/generic/object_bulk_delete.html +1 -1
  29. nautobot/core/templates/generic/object_bulk_edit.html +1 -1
  30. nautobot/core/templates/generic/object_bulk_import.html +1 -1
  31. nautobot/core/templates/generic/object_delete.html +1 -1
  32. nautobot/core/templates/generic/object_detail.html +1 -1
  33. nautobot/core/templates/generic/object_edit.html +1 -1
  34. nautobot/core/templates/generic/object_retrieve.html +2 -2
  35. nautobot/core/templates/graphene/graphiql.html +0 -1
  36. nautobot/core/templates/inc/footer.html +3 -1
  37. nautobot/core/templates/inc/header.html +10 -0
  38. nautobot/core/templates/inc/media.html +14 -0
  39. nautobot/core/templates/inc/nav_menu.html +1 -8
  40. nautobot/core/templates/inc/object_details_advanced_panel.html +2 -2
  41. nautobot/core/templates/nautobot_config.py.j2 +0 -6
  42. nautobot/core/templates/rest_framework/api.html +103 -2
  43. nautobot/core/templates/utilities/templatetags/filter_form_drawer.html +33 -0
  44. nautobot/core/templates/utilities/theme_preview.html +3 -0
  45. nautobot/core/templates/widgets/number_input_with_choices.html +44 -0
  46. nautobot/core/templatetags/helpers.py +24 -12
  47. nautobot/core/testing/integration.py +24 -13
  48. nautobot/core/testing/utils.py +18 -4
  49. nautobot/core/testing/views.py +104 -17
  50. nautobot/core/tests/integration/test_filters.py +48 -11
  51. nautobot/core/tests/integration/test_theme.py +22 -21
  52. nautobot/core/tests/nautobot_config.py +3 -0
  53. nautobot/core/tests/runner.py +1 -2
  54. nautobot/core/tests/test_breadcrumbs.py +21 -21
  55. nautobot/core/tests/test_jobs.py +73 -6
  56. nautobot/core/tests/test_renderers.py +59 -0
  57. nautobot/core/tests/test_settings_schema.py +1 -0
  58. nautobot/core/tests/test_templatetags_helpers.py +9 -0
  59. nautobot/core/tests/test_titles.py +0 -16
  60. nautobot/core/tests/test_ui.py +122 -3
  61. nautobot/core/tests/test_utils.py +41 -1
  62. nautobot/core/ui/breadcrumbs.py +68 -17
  63. nautobot/core/ui/bulk_buttons.py +1 -1
  64. nautobot/core/ui/choices.py +49 -65
  65. nautobot/core/ui/echarts.py +15 -20
  66. nautobot/core/ui/object_detail.py +54 -46
  67. nautobot/core/ui/titles.py +3 -6
  68. nautobot/core/urls.py +8 -8
  69. nautobot/core/utils/filtering.py +11 -1
  70. nautobot/core/utils/lookup.py +46 -0
  71. nautobot/core/views/mixins.py +31 -20
  72. nautobot/core/views/renderers.py +2 -3
  73. nautobot/data_validation/migrations/0002_data_migration_from_app.py +3 -2
  74. nautobot/dcim/api/serializers.py +3 -0
  75. nautobot/dcim/choices.py +49 -0
  76. nautobot/dcim/constants.py +7 -0
  77. nautobot/dcim/factory.py +1 -1
  78. nautobot/dcim/filters.py +13 -1
  79. nautobot/dcim/forms.py +89 -3
  80. nautobot/dcim/migrations/0075_interface_duplex_interface_speed_and_more.py +32 -0
  81. nautobot/dcim/migrations/{0075_add_deviceclusterassignment.py → 0076_add_deviceclusterassignment.py} +1 -1
  82. nautobot/dcim/migrations/{0076_device_cluster_to_clusters_data_migration.py → 0077_device_cluster_to_clusters_data_migration.py} +1 -1
  83. nautobot/dcim/migrations/{0077_remove_device_cluster.py → 0078_remove_device_cluster.py} +1 -1
  84. nautobot/dcim/migrations/{0078_remove_device_location_tenant_name_uniqueness.py → 0079_remove_device_location_tenant_name_uniqueness.py} +1 -1
  85. nautobot/dcim/migrations/{0079_device_name_data_migration.py → 0080_device_name_data_migration.py} +1 -1
  86. nautobot/dcim/migrations/0081_alter_device_device_redundancy_group_priority_and_more.py +25 -0
  87. nautobot/dcim/models/device_component_templates.py +33 -1
  88. nautobot/dcim/models/device_components.py +22 -1
  89. nautobot/dcim/models/devices.py +17 -4
  90. nautobot/dcim/tables/devices.py +15 -0
  91. nautobot/dcim/tables/devicetypes.py +8 -1
  92. nautobot/dcim/tables/racks.py +0 -2
  93. nautobot/dcim/tables/template_code.py +1 -1
  94. nautobot/dcim/templates/dcim/cable_trace.html +0 -2
  95. nautobot/dcim/templates/dcim/consoleport.html +1 -1
  96. nautobot/dcim/templates/dcim/consoleserverport.html +1 -1
  97. nautobot/dcim/templates/dcim/devicebay.html +1 -1
  98. nautobot/dcim/templates/dcim/frontport.html +1 -1
  99. nautobot/dcim/templates/dcim/inc/devicetype_component_table.html +1 -1
  100. nautobot/dcim/templates/dcim/inc/moduletype_component_table.html +1 -1
  101. nautobot/dcim/templates/dcim/inc/rack_elevation.html +1 -1
  102. nautobot/dcim/templates/dcim/interface.html +9 -1
  103. nautobot/dcim/templates/dcim/interface_edit.html +2 -0
  104. nautobot/dcim/templates/dcim/inventoryitem.html +1 -1
  105. nautobot/dcim/templates/dcim/module_consoleports.html +1 -1
  106. nautobot/dcim/templates/dcim/module_consoleserverports.html +1 -1
  107. nautobot/dcim/templates/dcim/module_frontports.html +1 -1
  108. nautobot/dcim/templates/dcim/module_interfaces.html +1 -1
  109. nautobot/dcim/templates/dcim/module_modulebays.html +1 -1
  110. nautobot/dcim/templates/dcim/module_poweroutlets.html +1 -1
  111. nautobot/dcim/templates/dcim/module_powerports.html +1 -1
  112. nautobot/dcim/templates/dcim/module_rearports.html +1 -1
  113. nautobot/dcim/templates/dcim/moduletype_list.html +2 -2
  114. nautobot/dcim/templates/dcim/poweroutlet.html +1 -1
  115. nautobot/dcim/templates/dcim/powerport.html +1 -1
  116. nautobot/dcim/templates/dcim/rack_elevation_list.html +1 -1
  117. nautobot/dcim/templates/dcim/rack_retrieve.html +0 -11
  118. nautobot/dcim/templates/dcim/rearport.html +1 -1
  119. nautobot/dcim/templates/dcim/trace/cable.html +1 -1
  120. nautobot/dcim/templates/dcim/virtualchassis_update.html +1 -1
  121. nautobot/dcim/tests/integration/test_controller.py +3 -6
  122. nautobot/dcim/tests/integration/test_controller_managed_device_group.py +1 -5
  123. nautobot/dcim/tests/integration/test_create_device.py +0 -2
  124. nautobot/dcim/tests/integration/test_device_bulk_operations.py +1 -3
  125. nautobot/dcim/tests/integration/test_fileinputpicker.py +6 -10
  126. nautobot/dcim/tests/integration/test_location_bulk_operations.py +0 -2
  127. nautobot/dcim/tests/integration/test_module_bay_position.py +3 -4
  128. nautobot/dcim/tests/test_api.py +186 -6
  129. nautobot/dcim/tests/test_filters.py +43 -1
  130. nautobot/dcim/tests/test_forms.py +110 -8
  131. nautobot/dcim/tests/test_graphql.py +44 -1
  132. nautobot/dcim/tests/test_models.py +265 -0
  133. nautobot/dcim/tests/test_tables.py +160 -0
  134. nautobot/dcim/tests/test_views.py +69 -7
  135. nautobot/dcim/views.py +232 -126
  136. nautobot/extras/api/views.py +51 -44
  137. nautobot/extras/datasources/git.py +3 -1
  138. nautobot/extras/filters.py +19 -2
  139. nautobot/extras/forms/forms.py +9 -2
  140. nautobot/extras/jobs.py +2 -0
  141. nautobot/extras/jobs_ui.py +4 -3
  142. nautobot/extras/management/__init__.py +2 -0
  143. nautobot/extras/management/commands/refresh_dynamic_group_member_caches.py +4 -1
  144. nautobot/extras/migrations/0131_configcontext_device_families.py +18 -0
  145. nautobot/extras/models/approvals.py +11 -1
  146. nautobot/extras/models/change_logging.py +4 -0
  147. nautobot/extras/models/jobs.py +1 -3
  148. nautobot/extras/models/models.py +10 -2
  149. nautobot/extras/plugins/marketplace_manifest.yml +49 -1
  150. nautobot/extras/plugins/views.py +0 -5
  151. nautobot/extras/querysets.py +8 -0
  152. nautobot/extras/tables.py +12 -0
  153. nautobot/extras/templates/django_ajax_tables/ajax_wrapper.html +2 -0
  154. nautobot/extras/templates/extras/configcontext_update.html +1 -0
  155. nautobot/extras/templates/extras/dynamicgroup_update.html +1 -1
  156. nautobot/extras/templates/extras/objectchange_retrieve.html +0 -2
  157. nautobot/extras/templates/extras/plugin_detail.html +3 -3
  158. nautobot/extras/templates/extras/secret_create.html +1 -1
  159. nautobot/extras/tests/integration/test_computedfields.py +8 -9
  160. nautobot/extras/tests/integration/test_customfields.py +1 -3
  161. nautobot/extras/tests/integration/test_dynamicgroups.py +7 -8
  162. nautobot/extras/tests/integration/test_relationships.py +0 -2
  163. nautobot/extras/tests/test_api.py +63 -0
  164. nautobot/extras/tests/test_changelog.py +24 -2
  165. nautobot/extras/tests/test_filters.py +36 -3
  166. nautobot/extras/tests/test_models.py +38 -2
  167. nautobot/extras/tests/test_utils.py +3 -4
  168. nautobot/extras/tests/test_views.py +22 -83
  169. nautobot/extras/urls.py +0 -14
  170. nautobot/extras/views.py +83 -52
  171. nautobot/ipam/filters.py +26 -0
  172. nautobot/ipam/tables.py +6 -0
  173. nautobot/ipam/templates/ipam/namespace_ip_addresses.html +1 -1
  174. nautobot/ipam/templates/ipam/namespace_prefixes.html +1 -1
  175. nautobot/ipam/templates/ipam/namespace_vrfs.html +1 -1
  176. nautobot/ipam/tests/test_filters.py +26 -1
  177. nautobot/ipam/tests/test_models.py +1 -1
  178. nautobot/ipam/views.py +9 -7
  179. nautobot/load_balancers/__init__.py +0 -0
  180. nautobot/load_balancers/api/__init__.py +1 -0
  181. nautobot/load_balancers/api/serializers.py +75 -0
  182. nautobot/load_balancers/api/urls.py +23 -0
  183. nautobot/load_balancers/api/views.py +61 -0
  184. nautobot/load_balancers/apps.py +17 -0
  185. nautobot/load_balancers/choices.py +167 -0
  186. nautobot/load_balancers/filters.py +225 -0
  187. nautobot/load_balancers/forms.py +532 -0
  188. nautobot/load_balancers/management/commands/__init__.py +0 -0
  189. nautobot/load_balancers/management/commands/generate_load_balancer_models_test_data.py +38 -0
  190. nautobot/load_balancers/migrations/0001_initial.py +465 -0
  191. nautobot/load_balancers/migrations/0002_create_default_statuses_pool_members.py +31 -0
  192. nautobot/load_balancers/migrations/__init__.py +0 -0
  193. nautobot/load_balancers/models.py +423 -0
  194. nautobot/load_balancers/navigation.py +80 -0
  195. nautobot/load_balancers/tables.py +255 -0
  196. nautobot/load_balancers/tests/__init__.py +474 -0
  197. nautobot/load_balancers/tests/test_api.py +353 -0
  198. nautobot/load_balancers/tests/test_filters.py +134 -0
  199. nautobot/load_balancers/tests/test_forms.py +266 -0
  200. nautobot/load_balancers/tests/test_models.py +195 -0
  201. nautobot/load_balancers/tests/test_views.py +229 -0
  202. nautobot/load_balancers/urls.py +17 -0
  203. nautobot/load_balancers/views.py +248 -0
  204. nautobot/project-static/dist/css/github-dark.min.css +10 -0
  205. nautobot/project-static/dist/css/github.min.css +10 -0
  206. nautobot/project-static/dist/css/nautobot.css +1 -11
  207. nautobot/project-static/dist/css/nautobot.css.map +1 -1
  208. nautobot/project-static/dist/js/libraries.js +1 -1
  209. nautobot/project-static/dist/js/libraries.js.map +1 -1
  210. nautobot/project-static/dist/js/nautobot.js +1 -1
  211. nautobot/project-static/dist/js/nautobot.js.map +1 -1
  212. nautobot/project-static/js/forms.js +13 -0
  213. nautobot/project-static/nautobot-icons/bus-globe.svg +3 -0
  214. nautobot/project-static/nautobot-icons/bus-shield-check.svg +3 -0
  215. nautobot/project-static/nautobot-icons/bus-shield.svg +3 -0
  216. nautobot/ui/package-lock.json +87 -4
  217. nautobot/ui/package.json +2 -1
  218. nautobot/ui/src/js/nautobot.js +0 -1
  219. nautobot/ui/src/js/select2.js +53 -2
  220. nautobot/ui/src/scss/nautobot.scss +51 -2
  221. nautobot/ui/webpack.config.js +13 -0
  222. nautobot/users/templates/users/preferences.html +11 -2
  223. nautobot/virtualization/filters.py +6 -1
  224. nautobot/virtualization/tests/test_filters.py +10 -1
  225. nautobot/virtualization/tests/test_models.py +1 -0
  226. nautobot/virtualization/views.py +4 -1
  227. nautobot/vpn/factory.py +25 -15
  228. nautobot/vpn/filters.py +1 -0
  229. nautobot/vpn/forms.py +1 -0
  230. nautobot/vpn/migrations/0001_initial.py +1 -1
  231. nautobot/vpn/models.py +16 -8
  232. nautobot/vpn/tables.py +5 -2
  233. nautobot/vpn/tests/test_api.py +0 -5
  234. nautobot/vpn/tests/test_forms.py +1 -2
  235. nautobot/vpn/tests/test_models.py +57 -7
  236. nautobot/vpn/tests/test_views.py +22 -3
  237. nautobot/vpn/views.py +78 -20
  238. {nautobot-3.0.0a3.dist-info → nautobot-3.0.0rc1.dist-info}/METADATA +4 -4
  239. {nautobot-3.0.0a3.dist-info → nautobot-3.0.0rc1.dist-info}/RECORD +243 -352
  240. nautobot/circuits/templates/circuits/circuit.html +0 -2
  241. nautobot/circuits/templates/circuits/circuit_edit.html +0 -2
  242. nautobot/circuits/templates/circuits/circuit_retrieve.html +0 -2
  243. nautobot/circuits/templates/circuits/circuit_update.html +0 -1
  244. nautobot/circuits/templates/circuits/circuittermination.html +0 -2
  245. nautobot/circuits/templates/circuits/circuittermination_edit.html +0 -2
  246. nautobot/circuits/templates/circuits/circuittermination_retrieve.html +0 -2
  247. nautobot/circuits/templates/circuits/circuittermination_update.html +0 -1
  248. nautobot/circuits/templates/circuits/circuittype.html +0 -2
  249. nautobot/circuits/templates/circuits/circuittype_retrieve.html +0 -2
  250. nautobot/circuits/templates/circuits/inc/circuit_termination.html +0 -85
  251. nautobot/circuits/templates/circuits/provider.html +0 -2
  252. nautobot/circuits/templates/circuits/provider_edit.html +0 -2
  253. nautobot/circuits/templates/circuits/provider_retrieve.html +0 -1
  254. nautobot/circuits/templates/circuits/provider_update.html +0 -1
  255. nautobot/circuits/templates/circuits/providernetwork.html +0 -2
  256. nautobot/circuits/templates/circuits/providernetwork_retrieve.html +0 -2
  257. nautobot/cloud/templates/cloud/cloudaccount_retrieve.html +0 -2
  258. nautobot/cloud/templates/cloud/cloudnetwork_retrieve.html +0 -2
  259. nautobot/cloud/templates/cloud/cloudresourcetype_retrieve.html +0 -2
  260. nautobot/cloud/templates/cloud/cloudservice_retrieve.html +0 -2
  261. nautobot/core/templates/buttons/import.html +0 -9
  262. nautobot/data_validation/templates/data_validation/datacompliance_retrieve.html +0 -1
  263. nautobot/dcim/templates/dcim/cable.html +0 -2
  264. nautobot/dcim/templates/dcim/cable_edit.html +0 -2
  265. nautobot/dcim/templates/dcim/controller/base.html +0 -2
  266. nautobot/dcim/templates/dcim/controller_retrieve.html +0 -2
  267. nautobot/dcim/templates/dcim/controller_wirelessnetworks.html +0 -2
  268. nautobot/dcim/templates/dcim/controllermanageddevicegroup_retrieve.html +0 -2
  269. nautobot/dcim/templates/dcim/device/base.html +0 -2
  270. nautobot/dcim/templates/dcim/device/consoleports.html +0 -2
  271. nautobot/dcim/templates/dcim/device/consoleserverports.html +0 -2
  272. nautobot/dcim/templates/dcim/device/devicebays.html +0 -2
  273. nautobot/dcim/templates/dcim/device/frontports.html +0 -2
  274. nautobot/dcim/templates/dcim/device/interfaces.html +0 -2
  275. nautobot/dcim/templates/dcim/device/inventory.html +0 -2
  276. nautobot/dcim/templates/dcim/device/modulebays.html +0 -2
  277. nautobot/dcim/templates/dcim/device/poweroutlets.html +0 -2
  278. nautobot/dcim/templates/dcim/device/powerports.html +0 -2
  279. nautobot/dcim/templates/dcim/device/rearports.html +0 -2
  280. nautobot/dcim/templates/dcim/device/wireless.html +0 -2
  281. nautobot/dcim/templates/dcim/device_component.html +0 -2
  282. nautobot/dcim/templates/dcim/device_edit.html +0 -2
  283. nautobot/dcim/templates/dcim/devicefamily_retrieve.html +0 -2
  284. nautobot/dcim/templates/dcim/deviceredundancygroup_retrieve.html +0 -2
  285. nautobot/dcim/templates/dcim/devicetype.html +0 -2
  286. nautobot/dcim/templates/dcim/devicetype_edit.html +0 -2
  287. nautobot/dcim/templates/dcim/devicetype_retrieve.html +0 -2
  288. nautobot/dcim/templates/dcim/inc/device_napalm_tabs.html +0 -1
  289. nautobot/dcim/templates/dcim/interfaceredundancygroup_retrieve.html +0 -2
  290. nautobot/dcim/templates/dcim/location.html +0 -2
  291. nautobot/dcim/templates/dcim/location_edit.html +0 -2
  292. nautobot/dcim/templates/dcim/location_retrieve.html +0 -2
  293. nautobot/dcim/templates/dcim/locationtype.html +0 -2
  294. nautobot/dcim/templates/dcim/locationtype_retrieve.html +0 -2
  295. nautobot/dcim/templates/dcim/manufacturer.html +0 -2
  296. nautobot/dcim/templates/dcim/modulebay_retrieve.html +0 -1
  297. nautobot/dcim/templates/dcim/platform.html +0 -2
  298. nautobot/dcim/templates/dcim/powerfeed.html +0 -2
  299. nautobot/dcim/templates/dcim/powerfeed_retrieve.html +0 -2
  300. nautobot/dcim/templates/dcim/powerpanel.html +0 -2
  301. nautobot/dcim/templates/dcim/powerpanel_edit.html +0 -2
  302. nautobot/dcim/templates/dcim/powerpanel_retrieve.html +0 -2
  303. nautobot/dcim/templates/dcim/rack.html +0 -2
  304. nautobot/dcim/templates/dcim/rack_edit.html +0 -2
  305. nautobot/dcim/templates/dcim/rackgroup.html +0 -2
  306. nautobot/dcim/templates/dcim/rackreservation.html +0 -2
  307. nautobot/dcim/templates/dcim/softwareimagefile_retrieve.html +0 -2
  308. nautobot/dcim/templates/dcim/softwareversion_retrieve.html +0 -2
  309. nautobot/dcim/templates/dcim/virtualchassis.html +0 -2
  310. nautobot/dcim/templates/dcim/virtualchassis_add.html +0 -2
  311. nautobot/dcim/templates/dcim/virtualchassis_edit.html +0 -2
  312. nautobot/dcim/templates/dcim/virtualchassis_retrieve.html +0 -2
  313. nautobot/dcim/templates/dcim/virtualdevicecontext_retrieve.html +0 -2
  314. nautobot/dcim/ui.py +0 -29
  315. nautobot/extras/templates/extras/computedfield.html +0 -2
  316. nautobot/extras/templates/extras/computedfield_retrieve.html +0 -2
  317. nautobot/extras/templates/extras/configcontext.html +0 -2
  318. nautobot/extras/templates/extras/configcontext_edit.html +0 -2
  319. nautobot/extras/templates/extras/configcontext_retrieve.html +0 -2
  320. nautobot/extras/templates/extras/configcontextschema.html +0 -2
  321. nautobot/extras/templates/extras/configcontextschema_edit.html +0 -2
  322. nautobot/extras/templates/extras/contact_retrieve.html +0 -2
  323. nautobot/extras/templates/extras/customfield.html +0 -2
  324. nautobot/extras/templates/extras/customfield_edit.html +0 -2
  325. nautobot/extras/templates/extras/customfield_retrieve.html +0 -2
  326. nautobot/extras/templates/extras/customlink.html +0 -2
  327. nautobot/extras/templates/extras/dynamicgroup.html +0 -2
  328. nautobot/extras/templates/extras/dynamicgroup_edit.html +0 -2
  329. nautobot/extras/templates/extras/exporttemplate.html +0 -2
  330. nautobot/extras/templates/extras/gitrepository.html +0 -2
  331. nautobot/extras/templates/extras/gitrepository_object_edit.html +0 -2
  332. nautobot/extras/templates/extras/graphqlquery.html +0 -2
  333. nautobot/extras/templates/extras/graphqlquery_list.html +0 -1
  334. nautobot/extras/templates/extras/graphqlquery_retrieve.html +0 -2
  335. nautobot/extras/templates/extras/job_detail.html +0 -2
  336. nautobot/extras/templates/extras/jobbutton_retrieve.html +0 -2
  337. nautobot/extras/templates/extras/jobhook.html +0 -2
  338. nautobot/extras/templates/extras/jobqueue_retrieve.html +0 -2
  339. nautobot/extras/templates/extras/jobresult.html +0 -2
  340. nautobot/extras/templates/extras/metadatatype_retrieve.html +0 -2
  341. nautobot/extras/templates/extras/note.html +0 -2
  342. nautobot/extras/templates/extras/note_retrieve.html +0 -1
  343. nautobot/extras/templates/extras/object_changelog.html +0 -2
  344. nautobot/extras/templates/extras/object_notes.html +0 -2
  345. nautobot/extras/templates/extras/objectchange.html +0 -2
  346. nautobot/extras/templates/extras/objectchange_list.html +0 -3
  347. nautobot/extras/templates/extras/relationship.html +0 -1
  348. nautobot/extras/templates/extras/secret.html +0 -1
  349. nautobot/extras/templates/extras/secret_edit.html +0 -1
  350. nautobot/extras/templates/extras/secretsgroup.html +0 -2
  351. nautobot/extras/templates/extras/secretsgroup_edit.html +0 -2
  352. nautobot/extras/templates/extras/secretsgroup_retrieve.html +0 -2
  353. nautobot/extras/templates/extras/status.html +0 -2
  354. nautobot/extras/templates/extras/tag.html +0 -2
  355. nautobot/extras/templates/extras/tag_edit.html +0 -2
  356. nautobot/extras/templates/extras/tag_retrieve.html +0 -2
  357. nautobot/extras/templates/extras/team_retrieve.html +0 -2
  358. nautobot/ipam/templates/ipam/namespace_retrieve.html +0 -1
  359. nautobot/ipam/templates/ipam/prefix.html +0 -2
  360. nautobot/ipam/templates/ipam/prefix_edit.html +0 -1
  361. nautobot/ipam/templates/ipam/prefix_retrieve.html +0 -2
  362. nautobot/ipam/templates/ipam/rir.html +0 -2
  363. nautobot/ipam/templates/ipam/routetarget.html +0 -1
  364. nautobot/ipam/templates/ipam/service.html +0 -2
  365. nautobot/ipam/templates/ipam/service_edit.html +0 -2
  366. nautobot/ipam/templates/ipam/service_retrieve.html +0 -2
  367. nautobot/ipam/templates/ipam/vlan.html +0 -2
  368. nautobot/ipam/templates/ipam/vlan_edit.html +0 -2
  369. nautobot/ipam/templates/ipam/vlan_retrieve.html +0 -2
  370. nautobot/ipam/templates/ipam/vlangroup.html +0 -2
  371. nautobot/ipam/templates/ipam/vrf.html +0 -1
  372. nautobot/tenancy/templates/tenancy/tenant.html +0 -2
  373. nautobot/tenancy/templates/tenancy/tenant_edit.html +0 -2
  374. nautobot/tenancy/templates/tenancy/tenantgroup.html +0 -2
  375. nautobot/tenancy/templates/tenancy/tenantgroup_retrieve.html +0 -1
  376. nautobot/virtualization/templates/virtualization/clustergroup.html +0 -2
  377. nautobot/virtualization/templates/virtualization/clustertype.html +0 -2
  378. nautobot/virtualization/templates/virtualization/virtualmachine.html +0 -2
  379. nautobot/virtualization/templates/virtualization/virtualmachine_edit.html +0 -2
  380. nautobot/virtualization/templates/virtualization/virtualmachine_retrieve.html +0 -2
  381. nautobot/vpn/templates/vpn/vpnprofile.html +0 -2
  382. nautobot/wireless/templates/wireless/radioprofile_retrieve.html +0 -2
  383. nautobot/wireless/templates/wireless/supporteddatarate_retrieve.html +0 -2
  384. nautobot/wireless/templates/wireless/wirelessnetwork_retrieve.html +0 -2
  385. {nautobot-3.0.0a3.dist-info → nautobot-3.0.0rc1.dist-info}/LICENSE.txt +0 -0
  386. {nautobot-3.0.0a3.dist-info → nautobot-3.0.0rc1.dist-info}/NOTICE +0 -0
  387. {nautobot-3.0.0a3.dist-info → nautobot-3.0.0rc1.dist-info}/WHEEL +0 -0
  388. {nautobot-3.0.0a3.dist-info → nautobot-3.0.0rc1.dist-info}/entry_points.txt +0 -0
@@ -318,24 +318,19 @@ class VPNTunnelEndpointAPITest(APIViewTestCases.APIViewTestCase):
318
318
 
319
319
  cls.create_data = [
320
320
  {
321
- "device": interfaces[0].device.pk,
322
321
  "source_interface": interfaces[0].pk,
323
322
  "vpn_profile": models.VPNProfile.objects.first().pk,
324
323
  },
325
324
  {
326
- "device": interfaces[1].device.pk,
327
325
  "source_interface": interfaces[1].pk,
328
326
  "vpn_profile": models.VPNProfile.objects.first().pk,
329
327
  },
330
328
  {
331
- "device": interfaces[2].device.pk,
332
329
  "source_interface": interfaces[2].pk,
333
330
  "vpn_profile": models.VPNProfile.objects.first().pk,
334
331
  },
335
332
  ]
336
333
 
337
334
  cls.update_data = {
338
- "device": interfaces[2].device.pk,
339
- "source_interface": interfaces[2].pk,
340
335
  "vpn_profile": models.VPNProfile.objects.last().pk,
341
336
  }
@@ -275,7 +275,6 @@ class VPNTunnelEndpointFormTest(FormTestCases.BaseFormTestCase):
275
275
  """Test specifying all fields."""
276
276
  interfaces = Interface.objects.filter(device__isnull=False, vpn_tunnel_endpoints_src_int__isnull=True)
277
277
  data = {
278
- "device": interfaces[0].device,
279
278
  "source_interface": interfaces[0],
280
279
  "vpn_profile": models.VPNProfile.objects.first(),
281
280
  "protected_prefixes": [Prefix.objects.first()],
@@ -288,7 +287,7 @@ class VPNTunnelEndpointFormTest(FormTestCases.BaseFormTestCase):
288
287
  def test_specifying_required_fields_success(self):
289
288
  """Test specifying only required fields."""
290
289
 
291
- data = {"source_fqdn": "To Cloud"}
290
+ data = {"source_fqdn": "cloud.com"}
292
291
  form = self.form_class(data=data)
293
292
  self.assertTrue(form.is_valid())
294
293
  self.assertTrue(form.save())
@@ -3,7 +3,8 @@
3
3
  from django.core.exceptions import ValidationError
4
4
 
5
5
  from nautobot.apps.testing import ModelTestCases
6
- from nautobot.dcim.models import Interface
6
+ from nautobot.dcim.models import Device, Interface, Module
7
+ from nautobot.ipam.models import IPAddress
7
8
  from nautobot.vpn import models
8
9
 
9
10
 
@@ -64,20 +65,69 @@ class TestVPNTunnelEndpointModel(ModelTestCases.BaseModelTestCase):
64
65
 
65
66
  model = models.VPNTunnelEndpoint
66
67
 
68
+ def test_clean(self):
69
+ """Test model constraints."""
70
+ with self.subTest("Test source_ipaddress conflicts with source_fqdn"):
71
+ endpoint = models.VPNTunnelEndpoint(source_ipaddress=IPAddress.objects.first(), source_fqdn="cloud.com")
72
+ with self.assertRaises(ValidationError):
73
+ endpoint.clean()
74
+
75
+ with self.subTest("Test at least one required field is missing"):
76
+ endpoint = models.VPNTunnelEndpoint()
77
+ with self.assertRaises(ValidationError):
78
+ endpoint.clean()
79
+
80
+ with self.subTest("Test Interface without device"):
81
+ endpoint = models.VPNTunnelEndpoint(
82
+ source_interface=Interface(
83
+ name="Ethernet",
84
+ module=Module(),
85
+ ),
86
+ )
87
+ with self.assertRaises(ValidationError):
88
+ endpoint.clean()
89
+
90
+ with self.subTest("Test source_ipaddress is assigned to source_interface"):
91
+ endpoint = models.VPNTunnelEndpoint(
92
+ source_interface=Interface.objects.filter(device__isnull=False).first(),
93
+ source_ipaddress=IPAddress.objects.filter(interfaces__isnull=True).first(),
94
+ )
95
+ with self.assertRaises(ValidationError):
96
+ endpoint.clean()
97
+
98
+ with self.subTest("Test source_interface and tunnel_interface are assigned to the same device"):
99
+ source_int = Interface.objects.filter(device__isnull=False).first()
100
+ tunnel_int = Interface(
101
+ name="Tunnel0",
102
+ device=Device.objects.exclude(id=source_int.device.id).first(),
103
+ status=source_int.status,
104
+ type="tunnel",
105
+ )
106
+ endpoint = models.VPNTunnelEndpoint(
107
+ device=source_int.device, source_interface=source_int, tunnel_interface=tunnel_int
108
+ )
109
+ with self.assertRaises(ValidationError):
110
+ endpoint.clean()
111
+
67
112
  def test_name(self):
68
113
  """Test dynamic name property."""
69
- with self.subTest("Test name contains interface name and device name."):
70
- endpoint = models.VPNTunnelEndpoint.objects.filter(source_interface__isnull=False).first()
114
+ endpoint = models.VPNTunnelEndpoint.objects.filter(source_interface__isnull=False).first()
115
+ ip = IPAddress.objects.filter(interface_assignments__isnull=True).last()
116
+ ip.interfaces.add(endpoint.source_interface)
117
+ endpoint.source_ipaddress = ip
118
+ endpoint.save()
119
+
120
+ with self.subTest("Test name contains interface name, device name and IP address"):
71
121
  self.assertIn(endpoint.source_interface.name, endpoint.name)
72
122
  self.assertIn(endpoint.source_interface.device.name, endpoint.name)
123
+ self.assertIn(endpoint.source_ipaddress.host, endpoint.name)
73
124
 
74
- with self.subTest("Test name contains interface name, device name and IP address."):
125
+ with self.subTest("Test name contains interface name and device name"):
75
126
  endpoint = models.VPNTunnelEndpoint.objects.filter(
76
- source_interface__isnull=False, source_ipaddress__isnull=False
127
+ source_interface__isnull=False, source_ipaddress__isnull=True
77
128
  ).first()
78
129
  self.assertIn(endpoint.source_interface.name, endpoint.name)
79
130
  self.assertIn(endpoint.source_interface.device.name, endpoint.name)
80
- self.assertIn(endpoint.source_ipaddress.host, endpoint.name)
81
131
 
82
132
  with self.subTest("Test name is fqdn"):
83
133
  endpoint = (
@@ -87,7 +137,7 @@ class TestVPNTunnelEndpointModel(ModelTestCases.BaseModelTestCase):
87
137
 
88
138
  def test_save(self):
89
139
  """Test save adds dynamic fields."""
90
- interface = Interface.objects.filter(vpn_tunnel_endpoints_src_int__isnull=True).first()
140
+ interface = Interface.objects.filter(vpn_tunnel_endpoints_src_int__isnull=True, device__isnull=False).first()
91
141
  new_endpoint = models.VPNTunnelEndpoint.objects.create(source_interface=interface)
92
142
 
93
143
  with self.subTest("Test device field is saved"):
@@ -1,11 +1,12 @@
1
1
  """Unit tests for vpn views."""
2
2
 
3
+ from django.contrib.contenttypes.models import ContentType
3
4
  from django.test import override_settings
4
5
  from django.urls import reverse
5
6
 
6
7
  from nautobot.apps.testing import ViewTestCases
7
8
  from nautobot.dcim.models import Interface
8
- from nautobot.extras.models import Status
9
+ from nautobot.extras.models import DynamicGroup, Status
9
10
  from nautobot.ipam.models import Prefix
10
11
  from nautobot.vpn import choices, models
11
12
 
@@ -266,16 +267,34 @@ class VPNTunnelEndpointViewTestCase(ViewTestCases.PrimaryObjectViewTestCase):
266
267
  interfaces = Interface.objects.filter(device__isnull=False, vpn_tunnel_endpoints_src_int__isnull=True)
267
268
 
268
269
  cls.form_data = {
269
- "device": interfaces.first().device.pk,
270
270
  "source_interface": interfaces.first().pk,
271
271
  "vpn_profile": models.VPNProfile.objects.first().pk,
272
272
  "protected_prefixes": [Prefix.objects.first().pk],
273
273
  }
274
274
 
275
275
  cls.update_data = {
276
- "device": interfaces.last().device.pk,
277
276
  "source_interface": interfaces.last().pk,
278
277
  "protected_prefixes": [Prefix.objects.last().pk],
279
278
  }
280
279
 
281
280
  cls.bulk_edit_data = {"vpn_profile": models.VPNProfile.objects.last().pk}
281
+
282
+ @override_settings(EXEMPT_VIEW_PERMISSIONS=["*"])
283
+ def test_protected_prefixes(self):
284
+ self.add_permissions("ipam.view_prefix")
285
+ endpoint = models.VPNTunnelEndpoint.objects.filter(protected_prefixes__isnull=False).first()
286
+
287
+ url = reverse("vpn:vpntunnelendpoint_protectedprefixes", kwargs={"pk": endpoint.pk})
288
+ response = self.client.get(url)
289
+ self.assertHttpStatus(response, 200)
290
+
291
+ @override_settings(EXEMPT_VIEW_PERMISSIONS=["*"])
292
+ def test_protected_dynamic_groups(self):
293
+ self.add_permissions("extras.view_dynamicgroup")
294
+ endpoint = models.VPNTunnelEndpoint.objects.filter(protected_prefixes_dg__isnull=True).first()
295
+ dg_ct = ContentType.objects.get_for_model(DynamicGroup)
296
+ endpoint.protected_prefixes_dg.add(DynamicGroup.objects.create(name="DG for Prefixes", content_type=dg_ct))
297
+
298
+ url = reverse("vpn:vpntunnelendpoint_protecteddynamicgroups", kwargs={"pk": endpoint.pk})
299
+ response = self.client.get(url)
300
+ self.assertHttpStatus(response, 200)
nautobot/vpn/views.py CHANGED
@@ -8,6 +8,7 @@ from rest_framework.response import Response
8
8
 
9
9
  from nautobot.apps.ui import ObjectDetailContent, ObjectFieldsPanel, ObjectsTablePanel, SectionChoices
10
10
  from nautobot.apps.views import NautobotUIViewSet
11
+ from nautobot.core.templatetags import helpers
11
12
  from nautobot.core.ui import object_detail
12
13
  from nautobot.extras.tables import DynamicGroupTable
13
14
  from nautobot.ipam.tables import PrefixTable
@@ -42,10 +43,10 @@ class VPNProfileUIViewSet(NautobotUIViewSet):
42
43
  "keepalive_interval",
43
44
  "keepalive_retries",
44
45
  "nat_traversal",
45
- "extra_options",
46
46
  "secrets_group",
47
47
  "role",
48
48
  "tenant",
49
+ "extra_options",
49
50
  ],
50
51
  ),
51
52
  ObjectsTablePanel(
@@ -54,6 +55,9 @@ class VPNProfileUIViewSet(NautobotUIViewSet):
54
55
  table_filter="vpn_profile",
55
56
  section=SectionChoices.RIGHT_HALF,
56
57
  exclude_columns=[],
58
+ show_table_config_button=False,
59
+ related_list_url_name="vpn:vpnphase1policy_list",
60
+ related_field_name="vpn_profiles",
57
61
  ),
58
62
  ObjectsTablePanel(
59
63
  weight=200,
@@ -61,6 +65,9 @@ class VPNProfileUIViewSet(NautobotUIViewSet):
61
65
  table_filter="vpn_profile",
62
66
  section=SectionChoices.RIGHT_HALF,
63
67
  exclude_columns=[],
68
+ show_table_config_button=False,
69
+ related_list_url_name="vpn:vpnphase2policy_list",
70
+ related_field_name="vpn_profiles",
64
71
  ),
65
72
  ],
66
73
  extra_tabs=[
@@ -155,7 +162,7 @@ class VPNProfileUIViewSet(NautobotUIViewSet):
155
162
  url_path="vpn-vpns",
156
163
  url_name="vpns",
157
164
  custom_view_base_action="view",
158
- custom_view_additional_permissions=["vpn.view_vpns"],
165
+ custom_view_additional_permissions=["vpn.view_vpn"],
159
166
  )
160
167
  def vpn_vpns(self, request, *args, **kwargs):
161
168
  return Response({})
@@ -165,7 +172,7 @@ class VPNProfileUIViewSet(NautobotUIViewSet):
165
172
  url_path="vpn-tunnels",
166
173
  url_name="vpntunnels",
167
174
  custom_view_base_action="view",
168
- custom_view_additional_permissions=["vpn.view_vpntunnels"],
175
+ custom_view_additional_permissions=["vpn.view_vpntunnel"],
169
176
  )
170
177
  def vpn_tunnels(self, request, *args, **kwargs):
171
178
  return Response({})
@@ -175,7 +182,7 @@ class VPNProfileUIViewSet(NautobotUIViewSet):
175
182
  url_path="vpn-endpoints",
176
183
  url_name="vpnendpoints",
177
184
  custom_view_base_action="view",
178
- custom_view_additional_permissions=["vpn.view_vpntunnelendpoints"],
185
+ custom_view_additional_permissions=["vpn.view_vpntunnelendpoint"],
179
186
  )
180
187
  def vpn_endpoints(self, request, *args, **kwargs):
181
188
  return Response({})
@@ -233,6 +240,11 @@ class VPNPhase1PolicyUIViewSet(NautobotUIViewSet):
233
240
  "authentication_method",
234
241
  "tenant",
235
242
  ],
243
+ value_transforms={
244
+ "encryption_algorithm": [helpers.label_list],
245
+ "integrity_algorithm": [helpers.label_list],
246
+ "dh_group": [helpers.label_list],
247
+ },
236
248
  ),
237
249
  ],
238
250
  )
@@ -264,6 +276,11 @@ class VPNPhase2PolicyUIViewSet(NautobotUIViewSet):
264
276
  "lifetime",
265
277
  "tenant",
266
278
  ],
279
+ value_transforms={
280
+ "encryption_algorithm": [helpers.label_list],
281
+ "integrity_algorithm": [helpers.label_list],
282
+ "pfs_group": [helpers.label_list],
283
+ },
267
284
  ),
268
285
  ],
269
286
  )
@@ -415,23 +432,64 @@ class VPNTunnelEndpointUIViewSet(NautobotUIViewSet):
415
432
  ],
416
433
  add_button_route=None,
417
434
  ),
418
- ObjectsTablePanel(
419
- weight=100,
420
- table_title="Protected Prefixes",
421
- table_class=PrefixTable,
422
- table_filter="vpn_tunnel_endpoints",
423
- section=SectionChoices.FULL_WIDTH,
424
- exclude_columns=[],
425
- add_button_route=None,
435
+ ],
436
+ extra_tabs=[
437
+ object_detail.DistinctViewTab(
438
+ weight=object_detail.Tab.WEIGHT_CHANGELOG_TAB + 100,
439
+ tab_id="protected_prefixes",
440
+ label="Protected Prefixes",
441
+ url_name="vpn:vpntunnelendpoint_protectedprefixes",
442
+ related_object_attribute="protected_prefixes",
443
+ hide_if_empty=True,
444
+ panels=(
445
+ object_detail.ObjectsTablePanel(
446
+ section=SectionChoices.FULL_WIDTH,
447
+ weight=100,
448
+ table_class=PrefixTable,
449
+ table_filter="vpn_tunnel_endpoints",
450
+ tab_id="protected_prefixes",
451
+ include_paginator=True,
452
+ ),
453
+ ),
426
454
  ),
427
- ObjectsTablePanel(
428
- weight=200,
429
- table_title="Protected Prefixes from Dynamic Group",
430
- table_class=DynamicGroupTable,
431
- table_filter="vpn_tunnel_endpoints",
432
- section=SectionChoices.FULL_WIDTH,
433
- exclude_columns=[],
434
- add_button_route=None,
455
+ object_detail.DistinctViewTab(
456
+ weight=object_detail.Tab.WEIGHT_CHANGELOG_TAB + 200,
457
+ tab_id="protected_dynamic_groups",
458
+ label="Protected Prefixes from Dynamic Group",
459
+ url_name="vpn:vpntunnelendpoint_protecteddynamicgroups",
460
+ related_object_attribute="protected_prefixes_dg",
461
+ hide_if_empty=True,
462
+ panels=(
463
+ object_detail.ObjectsTablePanel(
464
+ section=SectionChoices.FULL_WIDTH,
465
+ weight=100,
466
+ table_class=DynamicGroupTable,
467
+ table_filter="vpn_tunnel_endpoints",
468
+ tab_id="protected_dynamic_groups",
469
+ include_paginator=True,
470
+ enable_related_link=False,
471
+ ),
472
+ ),
435
473
  ),
436
474
  ],
437
475
  )
476
+
477
+ @action(
478
+ detail=True,
479
+ url_path="protected-prefixes",
480
+ url_name="protectedprefixes",
481
+ custom_view_base_action="view",
482
+ custom_view_additional_permissions=["ipam.view_prefix"],
483
+ )
484
+ def protected_prefixes(self, request, *args, **kwargs):
485
+ return Response({})
486
+
487
+ @action(
488
+ detail=True,
489
+ url_path="protected-dynamic-groups",
490
+ url_name="protecteddynamicgroups",
491
+ custom_view_base_action="view",
492
+ custom_view_additional_permissions=["extras.view_dynamicgroup"],
493
+ )
494
+ def protected_dynamic_groups(self, request, *args, **kwargs):
495
+ return Response({})
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: nautobot
3
- Version: 3.0.0a3
3
+ Version: 3.0.0rc1
4
4
  Summary: Source of truth and network automation platform.
5
5
  License: Apache-2.0
6
6
  Keywords: Nautobot
@@ -21,7 +21,7 @@ Provides-Extra: mysql
21
21
  Provides-Extra: napalm
22
22
  Provides-Extra: remote-storage
23
23
  Provides-Extra: sso
24
- Requires-Dist: Django (>=4.2.25,<4.3.0)
24
+ Requires-Dist: Django (>=4.2.26,<4.3.0)
25
25
  Requires-Dist: GitPython (>=3.1.45,<3.2.0)
26
26
  Requires-Dist: Jinja2 (>=3.1.6,<3.2.0)
27
27
  Requires-Dist: Markdown (>=3.8.2,<3.9.0)
@@ -33,7 +33,7 @@ Requires-Dist: django-ajax-tables (>=1.1.1,<1.2.0)
33
33
  Requires-Dist: django-auth-ldap (>=5.2.0,<5.3.0) ; extra == "all" or extra == "ldap"
34
34
  Requires-Dist: django-celery-beat (>=2.7.0,<2.8.0)
35
35
  Requires-Dist: django-celery-results (>=2.6.0,<2.7.0)
36
- Requires-Dist: django-constance (>=4.3.2,<4.4.0)
36
+ Requires-Dist: django-constance (>=4.3.3,<4.4.0)
37
37
  Requires-Dist: django-cors-headers (>=4.9.0,<4.10.0)
38
38
  Requires-Dist: django-db-file-storage (>=0.5.6.1,<0.6.0.0)
39
39
  Requires-Dist: django-extensions (>=4.1,<4.2)
@@ -61,7 +61,7 @@ Requires-Dist: mysqlclient (>=2.2.7,<2.3.0) ; extra == "all" or extra == "mysql"
61
61
  Requires-Dist: napalm (>=4.1.0,<6.0.0) ; extra == "all" or extra == "napalm"
62
62
  Requires-Dist: netaddr (>=1.3.0,<1.4.0)
63
63
  Requires-Dist: netutils (>=1.14.0,<2.0.0)
64
- Requires-Dist: nh3 (>=0.3.1,<0.4.0)
64
+ Requires-Dist: nh3 (>=0.3.2,<0.4.0)
65
65
  Requires-Dist: packaging (>=23.1)
66
66
  Requires-Dist: prometheus-client (>=0.23.1,<0.24.0)
67
67
  Requires-Dist: psycopg2-binary (>=2.9.11,<2.10.0)