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
@@ -0,0 +1,266 @@
1
+ """Test virtualserver forms."""
2
+
3
+ from nautobot.core.testing.forms import FormTestCases
4
+ from nautobot.load_balancers import choices, forms
5
+ from nautobot.load_balancers.tests import LoadBalancerModelsTestCaseMixin
6
+
7
+
8
+ # pylint: disable=no-member
9
+ class VirtualServerFormTest(LoadBalancerModelsTestCaseMixin, FormTestCases.BaseFormTestCase):
10
+ """Test VirtualServer forms."""
11
+
12
+ form_class = forms.VirtualServerForm
13
+
14
+ def test_specifying_all_fields_success(self):
15
+ form = forms.VirtualServerForm(
16
+ data={
17
+ "name": "Virtual Server 1",
18
+ "vip": self.ip_address.pk,
19
+ "enabled": True,
20
+ "port": 80,
21
+ "protocol": choices.ProtocolChoices.PROTOCOL_TCP,
22
+ "load_balancer_pool": self.load_balancer_pools[0].pk,
23
+ "load_balancer_type": choices.LoadBalancerTypeChoices.TYPE_LAYER4,
24
+ "tenant": self.tenant1.pk,
25
+ "source_nat_pool": self.source_nat_pool1.pk,
26
+ "source_nat_type": choices.SourceNATTypeChoices.TYPE_STATIC,
27
+ "device": self.device1.pk,
28
+ "health_check_monitor": self.health_check_monitors[1].pk,
29
+ "ssl_offload": True,
30
+ "certificate_profiles": [self.certificate_profiles[0]],
31
+ }
32
+ )
33
+ self.assertTrue(form.is_valid())
34
+ self.assertTrue(form.save())
35
+
36
+ def test_specifying_only_required_success(self):
37
+ form = forms.VirtualServerForm(
38
+ data={
39
+ "name": "Virtual Server 1",
40
+ "vip": self.ip_address.pk,
41
+ }
42
+ )
43
+ self.assertTrue(form.is_valid())
44
+ self.assertTrue(form.save())
45
+
46
+ def test_validate_name_is_required(self):
47
+ form = forms.VirtualServerForm(data={"vip": self.ip_address.pk})
48
+ self.assertFalse(form.is_valid())
49
+ self.assertIn("This field is required.", form.errors["name"])
50
+
51
+
52
+ # pylint: disable=no-member
53
+ class LoadBalancerPoolFormTest(LoadBalancerModelsTestCaseMixin, FormTestCases.BaseFormTestCase):
54
+ """Test the LoadBalancerPool form."""
55
+
56
+ form_class = forms.LoadBalancerPoolForm
57
+
58
+ def test_specifying_all_fields_success(self):
59
+ """Test specifying all fields."""
60
+
61
+ data = {
62
+ "name": "Load Balance Pool 1",
63
+ "load_balancing_algorithm": choices.LoadBalancingAlgorithmChoices.ROUND_ROBIN,
64
+ "health_check_monitor": self.health_check_monitors[0].pk,
65
+ "tenant": self.tenant1.pk,
66
+ }
67
+ form = self.form_class(data=data)
68
+ self.assertTrue(form.is_valid())
69
+ self.assertTrue(form.save())
70
+
71
+ def test_specifying_required_fields_success(self):
72
+ """Test specifying only required fields."""
73
+
74
+ data = {
75
+ "name": "Load Balance Pool 2",
76
+ "load_balancing_algorithm": choices.LoadBalancingAlgorithmChoices.ROUND_ROBIN,
77
+ }
78
+ form = self.form_class(data=data)
79
+ self.assertTrue(form.is_valid())
80
+ self.assertTrue(form.save())
81
+
82
+ def test_validate_name_is_required(self):
83
+ """Test that the name field is required."""
84
+
85
+ data = {
86
+ "load_balancing_algorithm": choices.LoadBalancingAlgorithmChoices.ROUND_ROBIN,
87
+ "virtual_server": self.virtual_servers[0].pk,
88
+ }
89
+ form = self.form_class(data=data)
90
+ self.assertFalse(form.is_valid())
91
+ self.assertIn("This field is required.", form.errors["name"])
92
+
93
+ def test_validate_load_balancing_algorithm_is_required(self):
94
+ """Test that the load_balancing_algorithm field is required."""
95
+
96
+ data = {
97
+ "name": "Load Balance Pool 4",
98
+ "virtual_server": self.virtual_servers[0].pk,
99
+ }
100
+ form = self.form_class(data=data)
101
+ self.assertFalse(form.is_valid())
102
+ self.assertIn("This field is required.", form.errors["load_balancing_algorithm"])
103
+
104
+
105
+ # pylint: disable=no-member
106
+ class LoadBalancerPoolMemberFormTest(LoadBalancerModelsTestCaseMixin, FormTestCases.BaseFormTestCase):
107
+ """Test the LoadBalancerPoolMember form."""
108
+
109
+ form_class = forms.LoadBalancerPoolMemberForm
110
+
111
+ def test_specifying_all_fields_success(self):
112
+ """Test specifying all fields."""
113
+
114
+ data = {
115
+ "ip_address": self.ip1.pk,
116
+ "load_balancer_pool": self.load_balancer_pools[0].pk,
117
+ "certificate_profiles": [self.certificate_profiles[0]],
118
+ "port": 123,
119
+ "ssl_offload": True,
120
+ "health_check_monitor": self.health_check_monitors[1].pk,
121
+ "tenant": self.tenant1.pk,
122
+ "status": self.status.pk,
123
+ }
124
+ form = self.form_class(data=data)
125
+ self.assertTrue(form.is_valid())
126
+ self.assertTrue(form.save())
127
+
128
+ def test_specifying_required_fields_success(self):
129
+ """Test specifying only required fields."""
130
+
131
+ data = {
132
+ "ip_address": self.ip2.pk,
133
+ "load_balancer_pool": self.load_balancer_pools[0].pk,
134
+ "port": 123,
135
+ "ssl_offload": False,
136
+ "status": self.status.pk,
137
+ }
138
+ form = self.form_class(data=data)
139
+ self.assertTrue(form.is_valid())
140
+ self.assertTrue(form.save())
141
+
142
+ def test_validate_ip_address_is_required(self):
143
+ """Test that the ip_address field is required."""
144
+
145
+ data = {
146
+ "load_balancer_pool": self.load_balancer_pools[0].pk,
147
+ "certificate_profiles": [self.certificate_profiles[0]],
148
+ "port": 123,
149
+ "ssl_offload": True,
150
+ "health_check_monitor": self.health_check_monitors[0].pk,
151
+ "tenant": self.tenant1.pk,
152
+ "status": self.status.pk,
153
+ }
154
+ form = self.form_class(data=data)
155
+ self.assertFalse(form.is_valid())
156
+ self.assertIn("This field is required.", form.errors["ip_address"])
157
+
158
+ def test_validate_load_balancer_pool_is_required(self):
159
+ """Test that the load_balancer_pool field is required."""
160
+
161
+ data = {
162
+ "ip_address": self.ip1.pk,
163
+ "certificate_profiles": [self.certificate_profiles[0]],
164
+ "port": 123,
165
+ "ssl_offload": True,
166
+ "health_check_monitor": self.health_check_monitors[0].pk,
167
+ "tenant": self.tenant1.pk,
168
+ "status": self.status.pk,
169
+ }
170
+ form = self.form_class(data=data)
171
+ self.assertFalse(form.is_valid())
172
+ self.assertIn("This field is required.", form.errors["load_balancer_pool"])
173
+
174
+ def test_validate_port_is_required(self):
175
+ """Test that the port field is required."""
176
+
177
+ data = {
178
+ "ip_address": self.ip1.pk,
179
+ "load_balancer_pool": self.load_balancer_pools[0].pk,
180
+ "port": None,
181
+ "certificate_profiles": [self.certificate_profiles[0]],
182
+ "ssl_offload": True,
183
+ "health_check_monitor": self.health_check_monitors[1].pk,
184
+ "tenant": self.tenant1.pk,
185
+ "status": self.status.pk,
186
+ }
187
+ form = self.form_class(data=data)
188
+ self.assertFalse(form.is_valid())
189
+ self.assertIn("This field is required.", form.errors["port"])
190
+
191
+ def test_validate_status_is_required(self):
192
+ """Test that the status field is required."""
193
+
194
+ data = {
195
+ "ip_address": self.ip1.pk,
196
+ "load_balancer_pool": self.load_balancer_pools[0].pk,
197
+ "certificate_profiles": [self.certificate_profiles[0]],
198
+ "port": 123,
199
+ "ssl_offload": True,
200
+ "health_check_monitor": self.health_check_monitors[0].pk,
201
+ "tenant": self.tenant1.pk,
202
+ }
203
+ form = self.form_class(data=data)
204
+ self.assertFalse(form.is_valid())
205
+ self.assertIn("This field is required.", form.errors["status"])
206
+
207
+
208
+ class HealthCheckMonitorFormTest(LoadBalancerModelsTestCaseMixin, FormTestCases.BaseFormTestCase):
209
+ """Test the HealthCheckMonitor form."""
210
+
211
+ form_class = forms.HealthCheckMonitorForm
212
+
213
+ def test_specifying_all_fields_success(self):
214
+ """Test specifying all fields."""
215
+
216
+ data = {
217
+ "name": "HTTPS Monitor 4",
218
+ "interval": 4,
219
+ "retry": 5,
220
+ "timeout": 6,
221
+ "port": 443,
222
+ "health_check_type": choices.HealthCheckTypeChoices.HTTPS,
223
+ "tenant": self.tenant2.pk,
224
+ }
225
+ form = self.form_class(data=data)
226
+ self.assertTrue(form.is_valid())
227
+ self.assertTrue(form.save())
228
+
229
+ def test_specifying_required_fields_success(self):
230
+ """Test specifying only required fields."""
231
+
232
+ data = {"name": "DNS Monitor 4"}
233
+ form = self.form_class(data=data)
234
+ self.assertTrue(form.is_valid())
235
+ self.assertTrue(form.save())
236
+
237
+
238
+ class CertificateProfileFormTest(LoadBalancerModelsTestCaseMixin, FormTestCases):
239
+ """Test the CertificateProfile form."""
240
+
241
+ form_class = forms.CertificateProfileForm
242
+
243
+ def test_specifying_all_fields_success(self):
244
+ """Test specifying all fields."""
245
+
246
+ data = {
247
+ "name": "Certificate Profile 4",
248
+ "certificate_type": choices.CertificateTypeChoices.TYPE_CLIENT,
249
+ "certificate_file_path": "test_certificate.crt",
250
+ "chain_file_path": "chain.pem",
251
+ "key_file_path": "id_rsa.key",
252
+ "expiration_date": "2022-01-01",
253
+ "cipher": "RSA-AES256-GCM-SHA384",
254
+ "tenant": self.tenant2.pk,
255
+ }
256
+ form = self.form_class(data=data)
257
+ self.assertTrue(form.is_valid())
258
+ self.assertTrue(form.save())
259
+
260
+ def test_specifying_required_fields_success(self):
261
+ """Test specifying only required fields."""
262
+
263
+ data = {"name": "Certificate Profile 5"}
264
+ form = self.form_class(data=data)
265
+ self.assertTrue(form.is_valid())
266
+ self.assertTrue(form.save())
@@ -0,0 +1,195 @@
1
+ """Test VirtualServer."""
2
+
3
+ from django.db.utils import IntegrityError
4
+
5
+ from nautobot.core.testing.models import ModelTestCases
6
+ from nautobot.ipam.models import IPAddress
7
+ from nautobot.load_balancers import choices, models
8
+ from nautobot.load_balancers.tests import LoadBalancerModelsTestCaseMixin
9
+
10
+
11
+ # pylint: disable=no-member
12
+ class TestVirtualServer(LoadBalancerModelsTestCaseMixin, ModelTestCases.BaseModelTestCase):
13
+ """Test VirtualServer."""
14
+
15
+ model = models.VirtualServer
16
+
17
+ @classmethod
18
+ def setUpTestData(cls):
19
+ """Setup test data."""
20
+ super().setUpTestData()
21
+
22
+ # Create a Virtual Server for the generic tests to use
23
+ vip = IPAddress.objects.create(address="10.0.0.50/32", namespace=cls.namespace, status=cls.status)
24
+ cls.virtual_server = models.VirtualServer.objects.create(name="VS0", vip=vip)
25
+ cls.lb_pool = models.LoadBalancerPool.objects.first()
26
+
27
+ def test_create_virtualserver_only_required(self):
28
+ """Create VirtualServer with only required fields, and validate __str__."""
29
+ virtual_server = models.VirtualServer.objects.create(name="VS1", vip=self.ip_address)
30
+ self.assertEqual(virtual_server.name, "VS1")
31
+ self.assertEqual(str(virtual_server), "VS1")
32
+
33
+ def test_create_virtualserver_vip_required(self):
34
+ """Create VirtualServer without vip."""
35
+ with self.assertRaises(IntegrityError):
36
+ models.VirtualServer.objects.create(name="VS1")
37
+
38
+ def test_create_virtualserver_all_fields_success(self):
39
+ """Create VirtualServer with all fields."""
40
+ # Assign to a device
41
+ virtual_server = models.VirtualServer.objects.create(
42
+ name="VS1",
43
+ vip=self.ip_address,
44
+ port=80,
45
+ protocol=choices.ProtocolChoices.PROTOCOL_TCP,
46
+ source_nat_pool=self.source_nat_pool1,
47
+ source_nat_type=choices.SourceNATTypeChoices.TYPE_POOL,
48
+ load_balancer_pool=self.lb_pool,
49
+ load_balancer_type=choices.LoadBalancerTypeChoices.TYPE_LAYER4,
50
+ enabled=False,
51
+ ssl_offload=True,
52
+ tenant=self.tenant1,
53
+ device=self.device1,
54
+ )
55
+ self.assertEqual(virtual_server.name, "VS1")
56
+
57
+ # Assign to a device redundancy group
58
+ virtual_server.device = None
59
+ virtual_server.device_redundancy_group = self.device_redundancy_group1
60
+ virtual_server.save()
61
+ virtual_server.refresh_from_db()
62
+ self.assertIsNone(virtual_server.device)
63
+ self.assertEqual(virtual_server.device_redundancy_group, self.device_redundancy_group1)
64
+
65
+ # Assign to a cloud service
66
+ virtual_server.device_redundancy_group = None
67
+ virtual_server.cloud_service = self.cloud_service1
68
+ virtual_server.save()
69
+ virtual_server.refresh_from_db()
70
+ self.assertIsNone(virtual_server.device_redundancy_group)
71
+ self.assertEqual(virtual_server.cloud_service, self.cloud_service1)
72
+
73
+ # Assign to a virtual chassis
74
+ virtual_server.cloud_service = None
75
+ virtual_server.virtual_chassis = self.virtual_chassis1
76
+ virtual_server.save()
77
+ virtual_server.refresh_from_db()
78
+ self.assertIsNone(virtual_server.cloud_service)
79
+ self.assertEqual(virtual_server.virtual_chassis, self.virtual_chassis1)
80
+
81
+
82
+ class TestLoadBalancerPool(LoadBalancerModelsTestCaseMixin, ModelTestCases.BaseModelTestCase):
83
+ """Test LoadBalancerPool."""
84
+
85
+ model = models.LoadBalancerPool
86
+
87
+ @classmethod
88
+ def setUpTestData(cls):
89
+ """Setup test data."""
90
+ super().setUpTestData()
91
+
92
+ # Create a LoadBalancerPool for the generic tests to use
93
+ cls.lb_pool = models.LoadBalancerPool.objects.create(name="Pool0", load_balancing_algorithm="round_robin")
94
+
95
+ def test_create_load_balancer_pool_only_required(self):
96
+ """Create LoadBalancerPool with only required fields, and validate __str__."""
97
+ lb_pool = models.LoadBalancerPool.objects.create(
98
+ name="Pool1",
99
+ load_balancing_algorithm="url_hash",
100
+ )
101
+ self.assertEqual(lb_pool.name, "Pool1")
102
+ self.assertEqual(str(lb_pool), "Pool1")
103
+
104
+ def test_create_load_balancer_pool_load_balancing_algorithm_required(self):
105
+ """Create LoadBalancerPool without load_balancing_algorithm."""
106
+ with self.assertRaises(IntegrityError):
107
+ models.LoadBalancerPool.objects.create(name="Pool2", load_balancing_algorithm=None)
108
+
109
+ def test_create_load_balancer_pool_name_required(self):
110
+ """Create LoadBalancerPool without name."""
111
+ with self.assertRaises(IntegrityError):
112
+ models.LoadBalancerPool.objects.create(load_balancing_algorithm="url_hash", name=None)
113
+
114
+
115
+ # pylint: disable=no-member
116
+ class TestLoadBalancerPoolMemberModel(LoadBalancerModelsTestCaseMixin, ModelTestCases.BaseModelTestCase):
117
+ """Test LoadBalancerPoolMember model."""
118
+
119
+ model = models.LoadBalancerPoolMember
120
+
121
+ @classmethod
122
+ def setUpTestData(cls):
123
+ """Set up test data."""
124
+ super().setUpTestData()
125
+
126
+ # Create a LoadBalancerPool for the generic tests to use
127
+ cls.lb_pool = models.LoadBalancerPool.objects.create(name="Pool0", load_balancing_algorithm="round_robin")
128
+
129
+ # Create a LoadBalancerPoolMember for the generic tests to use
130
+ cls.load_balancer_pool_member = models.LoadBalancerPoolMember.objects.create(
131
+ ip_address=cls.ip_address,
132
+ port=80,
133
+ tenant=cls.tenant1,
134
+ ssl_offload=True,
135
+ load_balancer_pool=cls.lb_pool,
136
+ status=cls.status,
137
+ )
138
+
139
+ def test_create_load_balancer_pool_member_only_required(self):
140
+ """Create LoadBalancerPoolMember with only required fields, and validate __str__."""
141
+ ip_address = IPAddress.objects.create(address="10.0.0.50/32", namespace=self.namespace, status=self.status)
142
+ load_balancer_pool_member = models.LoadBalancerPoolMember.objects.create(
143
+ ip_address=ip_address, port=80, load_balancer_pool=self.lb_pool, status=self.status
144
+ )
145
+ self.assertEqual(load_balancer_pool_member.port, 80)
146
+ self.assertEqual(str(load_balancer_pool_member), f"{ip_address.host}:80")
147
+
148
+ def test_create_load_balancer_pool_member_ipaddress_required(self):
149
+ """Create LoadBalancerPoolMember without ipaddress."""
150
+ with self.assertRaises(IntegrityError):
151
+ models.LoadBalancerPoolMember.objects.create(port=80, load_balancer_pool=self.lb_pool, status=self.status)
152
+
153
+ def test_create_load_balancer_pool_member_port_required(self):
154
+ """Create LoadBalancerPoolMember without port."""
155
+ ip_address = IPAddress.objects.create(address="10.0.0.50/32", namespace=self.namespace, status=self.status)
156
+ with self.assertRaises(IntegrityError):
157
+ models.LoadBalancerPoolMember.objects.create(
158
+ ip_address=ip_address, port=None, load_balancer_pool=self.lb_pool, status=self.status
159
+ )
160
+
161
+ def test_create_load_balancer_pool_member_load_balancer_pool_required(self):
162
+ """Create LoadBalancerPoolMember without load_balancer_pool."""
163
+ ip_address = IPAddress.objects.create(address="10.0.0.50/32", namespace=self.namespace, status=self.status)
164
+ with self.assertRaises(IntegrityError):
165
+ models.LoadBalancerPoolMember.objects.create(ip_address=ip_address, port=80, status=self.status)
166
+
167
+ def test_create_load_balancer_pool_member_status_required(self):
168
+ """Create LoadBalancerPoolMember without status."""
169
+ ip_address = IPAddress.objects.create(address="10.0.0.50/32", namespace=self.namespace, status=self.status)
170
+ with self.assertRaises(IntegrityError):
171
+ models.LoadBalancerPoolMember.objects.create(
172
+ ip_address=ip_address, port=80, load_balancer_pool=self.lb_pool
173
+ )
174
+
175
+
176
+ class TestHealthCheckMonitorModel(LoadBalancerModelsTestCaseMixin, ModelTestCases.BaseModelTestCase):
177
+ """Test HealthCheckMonitor model."""
178
+
179
+ model = models.HealthCheckMonitor
180
+
181
+ @classmethod
182
+ def setUpTestData(cls):
183
+ """Set up test data."""
184
+ super().setUpTestData()
185
+
186
+
187
+ class TestCertificateProfileModel(LoadBalancerModelsTestCaseMixin, ModelTestCases.BaseModelTestCase):
188
+ """Test CertificateProfile model."""
189
+
190
+ model = models.CertificateProfile
191
+
192
+ @classmethod
193
+ def setUpTestData(cls):
194
+ """Set up test data."""
195
+ super().setUpTestData()
@@ -0,0 +1,229 @@
1
+ """Unit tests for views."""
2
+
3
+ import datetime
4
+
5
+ from django.utils.timezone import make_aware
6
+
7
+ from nautobot.core.testing.views import ViewTestCases
8
+ from nautobot.load_balancers import choices, models
9
+ from nautobot.load_balancers.tests import LoadBalancerModelsTestCaseMixin
10
+
11
+
12
+ # pylint: disable=too-many-ancestors, no-member
13
+ class VirtualServerViewTest(LoadBalancerModelsTestCaseMixin, ViewTestCases.PrimaryObjectViewTestCase):
14
+ """Test the VirtualServer views."""
15
+
16
+ model = models.VirtualServer
17
+
18
+ @classmethod
19
+ def setUpTestData(cls):
20
+ """Setup test data."""
21
+ super().setUpTestData()
22
+
23
+ cls.form_data = {
24
+ "name": "VS4",
25
+ "vip": cls.vips[-4].pk,
26
+ "port": 4444,
27
+ "load_balancer_pool": cls.load_balancer_pools[0].pk,
28
+ "protocol": choices.ProtocolChoices.PROTOCOL_TCP,
29
+ "source_nat_pool": None,
30
+ "source_nat_type": "",
31
+ "load_balancer_type": choices.LoadBalancerTypeChoices.TYPE_LAYER4,
32
+ "enabled": True,
33
+ "ssl_offload": False,
34
+ "device": cls.device1.pk,
35
+ "device_redundancy_group": None,
36
+ "cloud_service": None,
37
+ "virtual_chassis": None,
38
+ "tenant": None,
39
+ "health_check_monitor": None,
40
+ }
41
+
42
+ cls.update_data = {
43
+ "name": "VS5",
44
+ "vip": cls.vips[-5].pk,
45
+ "port": 5555,
46
+ "protocol": choices.ProtocolChoices.PROTOCOL_DNS,
47
+ "load_balancer_pool": cls.load_balancer_pools[1].pk,
48
+ "source_nat_pool": None,
49
+ "source_nat_type": "",
50
+ "load_balancer_type": choices.LoadBalancerTypeChoices.TYPE_DNS,
51
+ "enabled": False,
52
+ "ssl_offload": True,
53
+ "device": None,
54
+ "device_redundancy_group": cls.device_redundancy_group1.pk,
55
+ "cloud_service": None,
56
+ "virtual_chassis": None,
57
+ "tenant": None,
58
+ "health_check_monitor": cls.health_check_monitors[0].pk,
59
+ }
60
+
61
+ cls.bulk_edit_data = {
62
+ "port": 7777,
63
+ "protocol": choices.ProtocolChoices.PROTOCOL_ANY,
64
+ "source_nat_pool": None,
65
+ "source_nat_type": "",
66
+ "load_balancer_pool": cls.load_balancer_pools[0].pk,
67
+ "load_balancer_type": choices.LoadBalancerTypeChoices.TYPE_LAYER2,
68
+ "enabled": False,
69
+ "ssl_offload": True,
70
+ "device": None,
71
+ "device_redundancy_group": None,
72
+ "cloud_service": None,
73
+ "virtual_chassis": cls.virtual_chassis1.pk,
74
+ "tenant": None,
75
+ "health_check_monitor": cls.health_check_monitors[1].pk,
76
+ "add_certificate_profiles": [cls.certificate_profiles[1].pk],
77
+ "remove_certificate_profiles": [cls.certificate_profiles[0].pk],
78
+ }
79
+
80
+
81
+ # pylint: disable=too-many-ancestors, no-member
82
+ class LoadBalancerPoolViewTestCase(LoadBalancerModelsTestCaseMixin, ViewTestCases.PrimaryObjectViewTestCase):
83
+ """Test the LoadBalancerPool views."""
84
+
85
+ model = models.LoadBalancerPool
86
+
87
+ @classmethod
88
+ def setUpTestData(cls):
89
+ """Set up test data."""
90
+ super().setUpTestData()
91
+
92
+ cls.form_data = {
93
+ "name": "Load Balancer Pool 1",
94
+ "load_balancing_algorithm": choices.LoadBalancingAlgorithmChoices.ROUND_ROBIN,
95
+ "health_check_monitor": None,
96
+ "tenant": cls.tenant1.pk,
97
+ }
98
+
99
+ cls.update_data = {
100
+ "name": "Load Balancer Pool 2",
101
+ "load_balancing_algorithm": choices.LoadBalancingAlgorithmChoices.LEAST_CONNECTIONS,
102
+ "health_check_monitor": cls.health_check_monitors[0].pk,
103
+ "tenant": None,
104
+ }
105
+
106
+ cls.bulk_edit_data = {
107
+ "name": "Load Balancer Pool 2",
108
+ "load_balancing_algorithm": choices.LoadBalancingAlgorithmChoices.URL_HASH,
109
+ "health_check_monitor": cls.health_check_monitors[1].pk,
110
+ "tenant": None,
111
+ }
112
+
113
+
114
+ # pylint: disable=too-many-ancestors, no-member
115
+ class LoadBalancerPoolMemberViewTestCase(LoadBalancerModelsTestCaseMixin, ViewTestCases.PrimaryObjectViewTestCase):
116
+ """Test the LoadBalancerPoolMember views."""
117
+
118
+ model = models.LoadBalancerPoolMember
119
+
120
+ @classmethod
121
+ def setUpTestData(cls):
122
+ """Set up test data."""
123
+ super().setUpTestData()
124
+
125
+ cls.form_data = {
126
+ "ip_address": cls.ip2.pk,
127
+ "load_balancer_pool": cls.load_balancer_pools[1].pk,
128
+ "port": 161,
129
+ "ssl_offload": True,
130
+ "tenant": cls.tenant1.pk,
131
+ "status": cls.status.pk,
132
+ "health_check_monitor": cls.health_check_monitors[0].pk,
133
+ }
134
+
135
+ cls.bulk_edit_data = {
136
+ "load_balancer_pool": cls.load_balancer_pools[0].pk,
137
+ "ssl_offload": False,
138
+ "tenant": None,
139
+ "status": cls.status.pk,
140
+ "health_check_monitor": cls.health_check_monitors[1].pk,
141
+ "add_certificate_profiles": [cls.certificate_profiles[1].pk],
142
+ "remove_certificate_profiles": [cls.certificate_profiles[0].pk],
143
+ }
144
+
145
+
146
+ # pylint: disable=too-many-ancestors, no-member
147
+ class HealthCheckMonitorViewTestCase(LoadBalancerModelsTestCaseMixin, ViewTestCases.PrimaryObjectViewTestCase):
148
+ """Test the HealthCheckMonitor views."""
149
+
150
+ model = models.HealthCheckMonitor
151
+
152
+ @classmethod
153
+ def setUpTestData(cls):
154
+ """Set up test data."""
155
+ super().setUpTestData()
156
+
157
+ cls.form_data = {
158
+ "name": "HTTP Monitor 4",
159
+ "interval": 35,
160
+ "retry": 3,
161
+ "timeout": 30,
162
+ "port": 8008,
163
+ "health_check_type": choices.HealthCheckTypeChoices.HTTP,
164
+ "tenant": cls.tenant1.pk,
165
+ }
166
+
167
+ cls.update_data = {
168
+ "name": "DNS Monitor 3",
169
+ "interval": 4,
170
+ "retry": 5,
171
+ "timeout": 6,
172
+ "port": 0,
173
+ "health_check_type": choices.HealthCheckTypeChoices.DNS,
174
+ "tenant": cls.tenant2.pk,
175
+ }
176
+
177
+ cls.bulk_edit_data = {
178
+ "interval": 8,
179
+ "retry": 9,
180
+ "timeout": 10,
181
+ "port": 11,
182
+ "health_check_type": choices.HealthCheckTypeChoices.TCP,
183
+ "tenant": None,
184
+ }
185
+
186
+
187
+ # pylint: disable=too-many-ancestors, no-member
188
+ class CertificateProfileViewTestCase(LoadBalancerModelsTestCaseMixin, ViewTestCases.PrimaryObjectViewTestCase):
189
+ """Test the CertificateProfile views."""
190
+
191
+ model = models.CertificateProfile
192
+
193
+ @classmethod
194
+ def setUpTestData(cls):
195
+ """Set up test data."""
196
+ super().setUpTestData()
197
+
198
+ cls.form_data = {
199
+ "name": "Test Certificate Profile 1",
200
+ "certificate_type": choices.CertificateTypeChoices.TYPE_CLIENT,
201
+ "certificate_file_path": "/this/is/a/path.crt",
202
+ "chain_file_path": "/chain/certificate/path.pem",
203
+ "key_file_path": "test_key.key",
204
+ "expiration_date": make_aware(datetime.datetime(2023, 11, 1, 0, 0)),
205
+ "cipher": "TLS_AES_256_GCM_SHA384",
206
+ "tenant": cls.tenant1.pk,
207
+ }
208
+
209
+ cls.update_data = {
210
+ "name": "Test Certificate Profile 2",
211
+ "certificate_type": choices.CertificateTypeChoices.TYPE_SERVER,
212
+ "certificate_file_path": "/test_cert.pem",
213
+ "chain_file_path": "/test_chain.pem",
214
+ "key_file_path": "/test_key",
215
+ "expiration_date": make_aware(datetime.datetime(2030, 12, 1, 0, 0)),
216
+ "cipher": "ECDHE_RSA",
217
+ "tenant": cls.tenant2.pk,
218
+ }
219
+
220
+ cls.bulk_edit_data = {
221
+ "name": "Test Certificate Profile 3",
222
+ "tenant": None,
223
+ "certificate_type": choices.CertificateTypeChoices.TYPE_MTLS,
224
+ "certificate_file_path": "/etc/certificate.pem",
225
+ "chain_file_path": "/bin/chain.pem",
226
+ "key_file_path": "/home/key",
227
+ "expiration_date": make_aware(datetime.datetime(2020, 1, 1, 0, 0, 0, 0)),
228
+ "cipher": "CHACHA20_POLY1305",
229
+ }