nautobot 2.0.0a2__py3-none-any.whl → 2.0.0b1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (1029) hide show
  1. nautobot/__init__.py +1 -5
  2. nautobot/apps/api.py +6 -8
  3. nautobot/apps/forms.py +0 -2
  4. nautobot/apps/ui.py +0 -8
  5. nautobot/circuits/api/serializers.py +9 -119
  6. nautobot/circuits/api/urls.py +1 -1
  7. nautobot/circuits/api/views.py +0 -1
  8. nautobot/circuits/choices.py +0 -2
  9. nautobot/circuits/filters.py +7 -6
  10. nautobot/circuits/forms.py +3 -73
  11. nautobot/circuits/migrations/0001_initial_part_1.py +0 -1
  12. nautobot/circuits/migrations/0002_initial_part_2.py +0 -1
  13. nautobot/circuits/migrations/0003_auto_slug.py +0 -1
  14. nautobot/circuits/migrations/0004_increase_provider_account_length.py +0 -1
  15. nautobot/circuits/migrations/0005_providernetwork.py +0 -1
  16. nautobot/circuits/migrations/0006_cache_circuit_terminations.py +0 -1
  17. nautobot/circuits/migrations/0007_circuitterminations_primary_model.py +0 -1
  18. nautobot/circuits/migrations/0008_add_natural_indexing.py +0 -1
  19. nautobot/circuits/migrations/0009_circuittermination_location.py +0 -1
  20. nautobot/circuits/migrations/0010_rename_foreign_keys_and_related_names.py +0 -1
  21. nautobot/circuits/migrations/0011_remove_site_foreign_key_from_circuit_termination_class.py +0 -1
  22. nautobot/circuits/migrations/0012_created_datetime.py +0 -1
  23. nautobot/circuits/migrations/0013_alter_circuittermination__path.py +0 -1
  24. nautobot/circuits/migrations/0014_related_name_changes.py +1 -2
  25. nautobot/circuits/migrations/0015_remove_circuittype_provider_slug.py +20 -0
  26. nautobot/circuits/migrations/0016_tagsfield.py +34 -0
  27. nautobot/circuits/migrations/0017_fixup_null_statuses.py +22 -0
  28. nautobot/circuits/migrations/0018_status_nonnullable.py +22 -0
  29. nautobot/circuits/models.py +3 -93
  30. nautobot/circuits/navigation.py +14 -69
  31. nautobot/circuits/signals.py +0 -2
  32. nautobot/circuits/tables.py +42 -5
  33. nautobot/circuits/templates/circuits/circuit_retrieve.html +1 -1
  34. nautobot/circuits/templates/circuits/circuittermination_retrieve.html +1 -1
  35. nautobot/circuits/templates/circuits/circuittype_retrieve.html +1 -1
  36. nautobot/circuits/templates/circuits/provider_create.html +0 -1
  37. nautobot/circuits/templates/circuits/provider_retrieve.html +1 -1
  38. nautobot/circuits/tests/integration/test_relationships.py +13 -16
  39. nautobot/circuits/tests/test_api.py +13 -43
  40. nautobot/circuits/tests/test_filters.py +20 -15
  41. nautobot/circuits/tests/test_models.py +7 -3
  42. nautobot/circuits/tests/test_views.py +57 -67
  43. nautobot/circuits/views.py +18 -9
  44. nautobot/core/api/__init__.py +8 -2
  45. nautobot/core/api/authentication.py +0 -3
  46. nautobot/core/api/fields.py +15 -6
  47. nautobot/core/api/filter_backends.py +3 -2
  48. nautobot/core/api/metadata.py +237 -30
  49. nautobot/core/api/mixins.py +94 -0
  50. nautobot/core/api/pagination.py +3 -3
  51. nautobot/core/api/parsers.py +154 -0
  52. nautobot/core/api/renderers.py +153 -2
  53. nautobot/core/api/schema.py +47 -3
  54. nautobot/core/api/serializers.py +377 -37
  55. nautobot/core/api/urls.py +11 -3
  56. nautobot/core/api/utils.py +174 -2
  57. nautobot/core/api/versioning.py +32 -10
  58. nautobot/core/api/views.py +266 -75
  59. nautobot/core/apps/__init__.py +138 -221
  60. nautobot/core/celery/__init__.py +112 -41
  61. nautobot/core/celery/backends.py +19 -13
  62. nautobot/core/celery/control.py +46 -0
  63. nautobot/core/celery/encoders.py +53 -0
  64. nautobot/core/celery/log.py +38 -0
  65. nautobot/core/celery/schedulers.py +23 -4
  66. nautobot/core/celery/task.py +1 -16
  67. nautobot/core/checks.py +0 -27
  68. nautobot/core/choices.py +21 -113
  69. nautobot/core/{cli.py → cli/__init__.py} +1 -2
  70. nautobot/core/cli/__main__.py +3 -0
  71. nautobot/core/constants.py +25 -43
  72. nautobot/core/context_processors.py +12 -0
  73. nautobot/core/filters.py +2 -2
  74. nautobot/core/forms/__init__.py +0 -4
  75. nautobot/core/forms/fields.py +39 -68
  76. nautobot/core/forms/forms.py +27 -27
  77. nautobot/core/forms/utils.py +7 -59
  78. nautobot/core/forms/widgets.py +0 -1
  79. nautobot/core/graphql/__init__.py +2 -2
  80. nautobot/core/graphql/schema.py +4 -27
  81. nautobot/core/jobs/__init__.py +75 -0
  82. nautobot/core/management/commands/build_ui.py +255 -0
  83. nautobot/core/management/commands/celery.py +0 -1
  84. nautobot/core/management/commands/generate_test_data.py +18 -13
  85. nautobot/core/management/commands/post_upgrade.py +24 -24
  86. nautobot/core/management/commands/validate_models.py +0 -1
  87. nautobot/core/middleware.py +0 -1
  88. nautobot/core/models/__init__.py +26 -1
  89. nautobot/core/models/fields.py +24 -5
  90. nautobot/core/models/generics.py +2 -46
  91. nautobot/core/models/managers.py +5 -0
  92. nautobot/core/models/name_color_content_types.py +1 -19
  93. nautobot/core/models/tree_queries.py +14 -4
  94. nautobot/core/models/utils.py +9 -10
  95. nautobot/core/models/validators.py +17 -8
  96. nautobot/core/releases.py +8 -10
  97. nautobot/core/settings.py +81 -53
  98. nautobot/core/tables.py +5 -5
  99. nautobot/core/tasks.py +4 -7
  100. nautobot/core/templates/base.html +1 -49
  101. nautobot/core/templates/base_django.html +49 -0
  102. nautobot/core/templates/base_react.html +55 -0
  103. nautobot/core/templates/buttons/export.html +6 -4
  104. nautobot/core/templates/generic/object_bulk_create.html +10 -21
  105. nautobot/core/templates/generic/object_list.html +4 -1
  106. nautobot/core/templates/generic/object_retrieve_plugin_full_width.html +3 -0
  107. nautobot/core/templates/inc/footer.html +1 -0
  108. nautobot/core/templates/inc/javascript.html +0 -14
  109. nautobot/core/templates/inc/nav_menu.html +28 -33
  110. nautobot/core/templates/inc/object_details_advanced_panel.html +13 -0
  111. nautobot/core/templates/inc/relationships_table_rows.html +2 -2
  112. nautobot/core/templates/nautobot_config.py.j2 +8 -25
  113. nautobot/core/templates/plugin_template/__init__.py-tpl +1 -2
  114. nautobot/core/templates/rest_framework/api.html +8 -0
  115. nautobot/core/templatetags/buttons.py +32 -29
  116. nautobot/core/templatetags/helpers.py +1 -1
  117. nautobot/core/testing/__init__.py +47 -44
  118. nautobot/core/testing/api.py +365 -47
  119. nautobot/core/testing/filters.py +12 -7
  120. nautobot/core/testing/integration.py +1 -1
  121. nautobot/core/testing/migrations.py +2 -0
  122. nautobot/core/testing/mixins.py +22 -12
  123. nautobot/core/testing/schema.py +2 -1
  124. nautobot/core/testing/views.py +28 -51
  125. nautobot/core/tests/integration/test_filters.py +17 -8
  126. nautobot/core/tests/integration/test_navbar.py +11 -34
  127. nautobot/core/tests/integration/test_plugin_navbar.py +9 -103
  128. nautobot/core/tests/nautobot_config.py +2 -3
  129. nautobot/core/tests/runner.py +0 -1
  130. nautobot/core/tests/test_api.py +290 -24
  131. nautobot/core/tests/test_authentication.py +57 -14
  132. nautobot/core/tests/test_checks.py +0 -7
  133. nautobot/core/tests/test_choices.py +0 -1
  134. nautobot/core/tests/test_filters.py +117 -110
  135. nautobot/core/tests/test_forms.py +47 -110
  136. nautobot/core/tests/test_graphql.py +158 -135
  137. nautobot/core/tests/test_logging.py +4 -1
  138. nautobot/core/tests/test_managers.py +3 -5
  139. nautobot/core/tests/test_models.py +2 -0
  140. nautobot/core/tests/test_ordering.py +0 -2
  141. nautobot/core/tests/test_paginator.py +3 -1
  142. nautobot/core/tests/test_releases.py +12 -12
  143. nautobot/core/tests/test_templatetags_helpers.py +7 -4
  144. nautobot/core/tests/test_utils.py +112 -78
  145. nautobot/core/tests/test_views.py +12 -17
  146. nautobot/core/tests/test_views_utils.py +6 -9
  147. nautobot/core/utils/data.py +17 -0
  148. nautobot/core/utils/deprecation.py +13 -20
  149. nautobot/core/utils/filtering.py +53 -9
  150. nautobot/core/utils/git.py +12 -4
  151. nautobot/core/utils/lookup.py +3 -1
  152. nautobot/core/utils/requests.py +23 -116
  153. nautobot/core/views/__init__.py +1 -2
  154. nautobot/core/views/generic.py +131 -119
  155. nautobot/core/views/mixins.py +53 -62
  156. nautobot/core/views/paginator.py +0 -1
  157. nautobot/core/views/renderers.py +14 -12
  158. nautobot/core/views/utils.py +87 -4
  159. nautobot/dcim/api/serializers.py +160 -672
  160. nautobot/dcim/api/urls.py +1 -1
  161. nautobot/dcim/api/views.py +7 -46
  162. nautobot/dcim/choices.py +2 -25
  163. nautobot/dcim/elevations.py +0 -1
  164. nautobot/dcim/factory.py +15 -4
  165. nautobot/dcim/filters/__init__.py +42 -13
  166. nautobot/dcim/form_mixins.py +1 -27
  167. nautobot/dcim/forms.py +58 -797
  168. nautobot/dcim/management/commands/trace_paths.py +0 -1
  169. nautobot/dcim/migrations/0001_initial_part_1.py +0 -1
  170. nautobot/dcim/migrations/0002_initial_part_2.py +0 -1
  171. nautobot/dcim/migrations/0003_initial_part_3.py +0 -1
  172. nautobot/dcim/migrations/0004_initial_part_4.py +0 -1
  173. nautobot/dcim/migrations/0005_device_local_context_schema.py +0 -1
  174. nautobot/dcim/migrations/0006_auto_slug.py +0 -1
  175. nautobot/dcim/migrations/0007_device_secrets_group.py +0 -1
  176. nautobot/dcim/migrations/0008_increase_all_serial_lengths.py +0 -1
  177. nautobot/dcim/migrations/0009_add_natural_indexing.py +0 -1
  178. nautobot/dcim/migrations/0010_interface_status.py +0 -1
  179. nautobot/dcim/migrations/0011_interface_status_data_migration.py +0 -1
  180. nautobot/dcim/migrations/0012_interface_parent_bridge.py +0 -1
  181. nautobot/dcim/migrations/0013_location_location_type.py +0 -1
  182. nautobot/dcim/migrations/0014_location_status_data_migration.py +0 -1
  183. nautobot/dcim/migrations/0015_device_components__changeloggedmodel.py +0 -1
  184. nautobot/dcim/migrations/0016_device_components__timestamp_data_migration.py +0 -1
  185. nautobot/dcim/migrations/0017_locationtype_nestable.py +0 -1
  186. nautobot/dcim/migrations/0018_device_redundancy_group.py +0 -1
  187. nautobot/dcim/migrations/0019_device_redundancy_group_data_migration.py +0 -1
  188. nautobot/dcim/migrations/0020_move_site_fields_to_location_model.py +0 -1
  189. nautobot/dcim/migrations/0021_mptt_to_tree_queries.py +0 -1
  190. nautobot/dcim/migrations/0022_interface_mac_address_data_migration.py +0 -1
  191. nautobot/dcim/migrations/0023_alter_interface_mac_address.py +0 -1
  192. nautobot/dcim/migrations/0024_alter_device_and_rack_role_add_new_role.py +2 -2
  193. nautobot/dcim/migrations/0025_device_and_rack_roles_data_migrations.py +19 -14
  194. nautobot/dcim/migrations/0026_rename_device_and_rack_role.py +0 -1
  195. nautobot/dcim/migrations/0027_remove_device_role_and_rack_role.py +1 -2
  196. nautobot/dcim/migrations/0028_rename_foreignkey_fields.py +1 -2
  197. nautobot/dcim/migrations/0029_add_tree_managers_and_foreign_keys_pre_data_migration.py +0 -1
  198. nautobot/dcim/migrations/0030_migrate_region_and_site_data_to_locations.py +2 -2
  199. nautobot/dcim/migrations/0031_rename_path_end_point_related_name.py +0 -1
  200. nautobot/dcim/migrations/0032_remove_site_foreign_key_from_dcim_models.py +0 -1
  201. nautobot/dcim/migrations/0033_created_datetime.py +0 -1
  202. nautobot/dcim/migrations/0034_fixup_fks_and_related_names.py +0 -1
  203. nautobot/dcim/migrations/0035_related_name_changes.py +1 -2
  204. nautobot/dcim/migrations/0036_remove_region_and_site.py +1 -2
  205. nautobot/dcim/migrations/0037_interface_ip_addresses_m2m.py +0 -1
  206. nautobot/dcim/migrations/0038_alter_location_managers.py +0 -1
  207. nautobot/dcim/migrations/0039_remove_slug.py +24 -0
  208. nautobot/dcim/migrations/0040_tagsfield.py +109 -0
  209. nautobot/dcim/migrations/0041_ipam__namespaces.py +25 -0
  210. nautobot/dcim/migrations/0042_fixup_null_statuses.py +51 -0
  211. nautobot/dcim/migrations/0043_status_nonnullable.py +72 -0
  212. nautobot/dcim/models/cables.py +4 -35
  213. nautobot/dcim/models/device_component_templates.py +7 -2
  214. nautobot/dcim/models/device_components.py +26 -203
  215. nautobot/dcim/models/devices.py +30 -152
  216. nautobot/dcim/models/locations.py +3 -64
  217. nautobot/dcim/models/power.py +3 -51
  218. nautobot/dcim/models/racks.py +7 -86
  219. nautobot/dcim/navigation.py +141 -467
  220. nautobot/dcim/signals.py +0 -2
  221. nautobot/dcim/tables/devices.py +8 -5
  222. nautobot/dcim/tables/devicetypes.py +1 -1
  223. nautobot/dcim/tables/locations.py +2 -2
  224. nautobot/dcim/tables/power.py +2 -2
  225. nautobot/dcim/templates/dcim/console_port_connection_list.html +7 -0
  226. nautobot/dcim/templates/dcim/device.html +15 -4
  227. nautobot/dcim/templates/dcim/device_edit.html +6 -0
  228. nautobot/dcim/templates/dcim/deviceredundancygroup_create.html +0 -1
  229. nautobot/dcim/templates/dcim/devicetype.html +2 -2
  230. nautobot/dcim/templates/dcim/interface.html +4 -0
  231. nautobot/dcim/templates/dcim/interface_connection_list.html +7 -0
  232. nautobot/dcim/templates/dcim/interface_edit.html +1 -0
  233. nautobot/dcim/templates/dcim/location.html +16 -1
  234. nautobot/dcim/templates/dcim/locationtype.html +15 -0
  235. nautobot/dcim/templates/dcim/power_port_connection_list.html +7 -0
  236. nautobot/dcim/templates/dcim/rackgroup.html +0 -12
  237. nautobot/dcim/tests/integration/test_cable_connect_form.py +4 -4
  238. nautobot/dcim/tests/test_api.py +202 -130
  239. nautobot/dcim/tests/test_cablepaths.py +47 -42
  240. nautobot/dcim/tests/test_filters.py +156 -134
  241. nautobot/dcim/tests/test_forms.py +12 -213
  242. nautobot/dcim/tests/test_graphql.py +8 -3
  243. nautobot/dcim/tests/test_migrations.py +6 -11
  244. nautobot/dcim/tests/test_models.py +208 -158
  245. nautobot/dcim/tests/test_natural_ordering.py +12 -14
  246. nautobot/dcim/tests/test_signals.py +7 -4
  247. nautobot/dcim/tests/test_views.py +270 -264
  248. nautobot/dcim/urls.py +21 -26
  249. nautobot/dcim/views.py +14 -156
  250. nautobot/docs/additional-features/caching.md +6 -87
  251. nautobot/docs/additional-features/job-scheduling-and-approvals.md +3 -0
  252. nautobot/docs/additional-features/jobs.md +179 -197
  253. nautobot/docs/administration/nautobot-server.md +9 -24
  254. nautobot/docs/administration/nautobot-shell.md +6 -6
  255. nautobot/docs/administration/replicating-nautobot.md +0 -10
  256. nautobot/docs/configuration/index.md +9 -9
  257. nautobot/docs/configuration/optional-settings.md +32 -61
  258. nautobot/docs/configuration/required-settings.md +11 -52
  259. nautobot/docs/development/application-registry.md +2 -13
  260. nautobot/docs/development/best-practices.md +2 -1
  261. nautobot/docs/development/docker-compose-advanced-use-cases.md +1 -1
  262. nautobot/docs/development/extending-models.md +15 -17
  263. nautobot/docs/development/generic-views.md +0 -2
  264. nautobot/docs/development/getting-started.md +56 -6
  265. nautobot/docs/development/navigation-menu.md +22 -93
  266. nautobot/docs/development/react-ui.md +105 -0
  267. nautobot/docs/development/release-checklist.md +3 -3
  268. nautobot/docs/development/role-internals.md +1 -3
  269. nautobot/docs/development/style-guide.md +6 -4
  270. nautobot/docs/development/templates.md +2 -1
  271. nautobot/docs/docker/index.md +16 -14
  272. nautobot/docs/index.md +7 -3
  273. nautobot/docs/installation/index.md +4 -1
  274. nautobot/docs/installation/migrating-from-netbox.md +12 -43
  275. nautobot/docs/installation/migrating-from-postgresql.md +1 -1
  276. nautobot/docs/installation/nautobot.md +1 -1
  277. nautobot/docs/installation/tables/v2-api-behavior-changes.yaml +70 -0
  278. nautobot/docs/installation/tables/v2-api-removed-fields.yaml +142 -0
  279. nautobot/docs/installation/tables/v2-api-renamed-fields.yaml +124 -0
  280. nautobot/docs/installation/tables/v2-code-location-changes.yaml +241 -0
  281. nautobot/docs/installation/tables/v2-code-removals.yaml +67 -0
  282. nautobot/docs/installation/tables/v2-database-behavior-changes.yaml +37 -0
  283. nautobot/docs/installation/tables/v2-database-removed-fields.yaml +166 -0
  284. nautobot/docs/installation/tables/v2-database-renamed-fields.yaml +340 -0
  285. nautobot/docs/installation/tables/v2-filters-corrected-fields.yaml +28 -0
  286. nautobot/docs/installation/tables/v2-filters-enhanced-fields.yaml +241 -0
  287. nautobot/docs/installation/tables/v2-filters-removed-fields.yaml +553 -0
  288. nautobot/docs/installation/tables/v2-filters-renamed-fields.yaml +223 -0
  289. nautobot/docs/installation/tables/v2-logging-renamed-loggers.yaml +23 -0
  290. nautobot/docs/installation/upgrading-from-nautobot-v1.md +190 -636
  291. nautobot/docs/installation/upgrading.md +5 -2
  292. nautobot/docs/models/dcim/device.md +3 -0
  293. nautobot/docs/models/dcim/deviceredundancygroup.md +3 -3
  294. nautobot/docs/models/extras/computedfield.md +4 -4
  295. nautobot/docs/models/extras/dynamicgroup.md +9 -9
  296. nautobot/docs/models/extras/gitrepository.md +3 -0
  297. nautobot/docs/models/extras/job.md +1 -0
  298. nautobot/docs/models/extras/jobbutton.md +18 -13
  299. nautobot/docs/models/extras/jobhook.md +7 -4
  300. nautobot/docs/models/extras/jobresult.md +6 -2
  301. nautobot/docs/models/extras/relationship.md +2 -2
  302. nautobot/docs/models/extras/status.md +6 -19
  303. nautobot/docs/models/ipam/ipaddress.md +3 -0
  304. nautobot/docs/models/ipam/vrf.md +0 -3
  305. nautobot/docs/models/virtualization/virtualmachine.md +3 -0
  306. nautobot/docs/plugins/development.md +92 -24
  307. nautobot/docs/release-notes/version-1.5.md +96 -0
  308. nautobot/docs/release-notes/version-2.0.md +216 -0
  309. nautobot/docs/requirements.txt +5 -4
  310. nautobot/docs/rest-api/overview.md +384 -215
  311. nautobot/docs/rest-api/ui-related-endpoints.md +9 -0
  312. nautobot/extras/admin.py +3 -5
  313. nautobot/extras/api/customfields.py +15 -39
  314. nautobot/extras/api/fields.py +0 -11
  315. nautobot/extras/api/mixins.py +45 -0
  316. nautobot/extras/api/relationships.py +63 -159
  317. nautobot/extras/api/serializers.py +165 -706
  318. nautobot/extras/api/urls.py +1 -1
  319. nautobot/extras/api/views.py +295 -282
  320. nautobot/extras/apps.py +4 -7
  321. nautobot/extras/choices.py +11 -22
  322. nautobot/extras/constants.py +9 -3
  323. nautobot/extras/datasources/__init__.py +2 -0
  324. nautobot/extras/datasources/git.py +135 -186
  325. nautobot/extras/datasources/registry.py +25 -35
  326. nautobot/extras/factory.py +1 -3
  327. nautobot/extras/filters/__init__.py +49 -47
  328. nautobot/extras/filters/mixins.py +10 -8
  329. nautobot/extras/forms/forms.py +72 -148
  330. nautobot/extras/forms/mixins.py +34 -57
  331. nautobot/extras/health_checks.py +0 -33
  332. nautobot/extras/jobs.py +387 -566
  333. nautobot/extras/management/__init__.py +55 -48
  334. nautobot/extras/management/commands/renaturalize.py +0 -1
  335. nautobot/extras/management/commands/runjob.py +24 -62
  336. nautobot/extras/management/commands/webhook_receiver.py +0 -1
  337. nautobot/extras/managers.py +30 -7
  338. nautobot/extras/migrations/0001_initial_part_1.py +0 -1
  339. nautobot/extras/migrations/0002_initial_part_2.py +0 -1
  340. nautobot/extras/migrations/0003_initial_part_3.py +0 -1
  341. nautobot/extras/migrations/0004_populate_default_status_records.py +0 -1
  342. nautobot/extras/migrations/0005_configcontext_device_types.py +0 -1
  343. nautobot/extras/migrations/0006_graphqlquery.py +0 -1
  344. nautobot/extras/migrations/0007_configcontextschema.py +0 -1
  345. nautobot/extras/migrations/0008_jobresult__custom_field_data.py +0 -1
  346. nautobot/extras/migrations/0009_computedfield.py +0 -1
  347. nautobot/extras/migrations/0010_change_cf_validation_max_min_field_to_bigint.py +0 -1
  348. nautobot/extras/migrations/0011_fileattachment_fileproxy.py +0 -1
  349. nautobot/extras/migrations/0012_healthchecktestmodel.py +0 -1
  350. nautobot/extras/migrations/0013_default_fallback_value_computedfield.py +0 -1
  351. nautobot/extras/migrations/0014_auto_slug.py +0 -1
  352. nautobot/extras/migrations/0015_scheduled_job.py +0 -1
  353. nautobot/extras/migrations/0016_secret.py +0 -1
  354. nautobot/extras/migrations/0017_joblogentry.py +0 -1
  355. nautobot/extras/migrations/0018_joblog_data_migration.py +0 -2
  356. nautobot/extras/migrations/0019_joblogentry__meta_options__related_name.py +0 -1
  357. nautobot/extras/migrations/0020_customfield_changelog.py +0 -1
  358. nautobot/extras/migrations/0021_customfield_changelog_data.py +0 -1
  359. nautobot/extras/migrations/0022_objectchange_object_datav2.py +0 -1
  360. nautobot/extras/migrations/0023_job_model.py +0 -1
  361. nautobot/extras/migrations/0024_job_data_migration.py +0 -1
  362. nautobot/extras/migrations/0025_add_advanced_ui_boolean_to_customfield_conputedfield_and_relationship.py +0 -1
  363. nautobot/extras/migrations/0026_job_add_gitrepository_fk.py +0 -1
  364. nautobot/extras/migrations/0027_job_gitrepository_data_migration.py +0 -1
  365. nautobot/extras/migrations/0028_job_reduce_source.py +0 -1
  366. nautobot/extras/migrations/0029_dynamicgroup.py +0 -1
  367. nautobot/extras/migrations/0030_webhook_alter_unique_together.py +0 -1
  368. nautobot/extras/migrations/0031_tag_content_types.py +0 -1
  369. nautobot/extras/migrations/0032_tag_content_types_data_migration.py +0 -1
  370. nautobot/extras/migrations/0033_add__optimized_indexing.py +0 -1
  371. nautobot/extras/migrations/0034_alter_fileattachment_mimetype.py +0 -1
  372. nautobot/extras/migrations/0035_scheduledjob_crontab.py +0 -1
  373. nautobot/extras/migrations/0036_job_add_has_sensitive_variables.py +0 -1
  374. nautobot/extras/migrations/0037_configcontextschema__remove_name_unique__create_constraint_unique_name_owner.py +0 -1
  375. nautobot/extras/migrations/0038_configcontext_locations.py +0 -1
  376. nautobot/extras/migrations/0039_objectchange__add_change_context.py +0 -1
  377. nautobot/extras/migrations/0040_dynamicgroup__dynamicgroupmembership.py +0 -1
  378. nautobot/extras/migrations/0041_jobresult_job_kwargs.py +0 -1
  379. nautobot/extras/migrations/0042_job__add_is_job_hook_receiver.py +0 -1
  380. nautobot/extras/migrations/0043_note.py +0 -1
  381. nautobot/extras/migrations/0044_add_job_hook.py +0 -1
  382. nautobot/extras/migrations/0045_add_custom_field_slug.py +0 -1
  383. nautobot/extras/migrations/0046_populate_custom_field_slug_label.py +0 -1
  384. nautobot/extras/migrations/0047_enforce_custom_field_slug.py +0 -1
  385. nautobot/extras/migrations/0048_alter_objectchange_change_context_detail.py +0 -1
  386. nautobot/extras/migrations/0049_alter_tag_slug.py +0 -1
  387. nautobot/extras/migrations/0050_customfield_grouping.py +0 -1
  388. nautobot/extras/migrations/0051_add_job_task_queues.py +0 -1
  389. nautobot/extras/migrations/0052_configcontext_device_redundancy_groups.py +0 -1
  390. nautobot/extras/migrations/0053_relationship_required_on.py +0 -1
  391. nautobot/extras/migrations/0054_scheduledjob_kwargs_request_user_change.py +0 -1
  392. nautobot/extras/migrations/0055_configcontext_dynamic_groups.py +0 -1
  393. nautobot/extras/migrations/0056_objectchange_add_reverse_time_idx.py +0 -1
  394. nautobot/extras/migrations/0057_jobbutton.py +0 -1
  395. nautobot/extras/migrations/0058_jobresult_add_time_status_idxs.py +38 -0
  396. nautobot/extras/migrations/{0058_joblogentry_scheduledjob_webhook_data_migration.py → 0059_joblogentry_scheduledjob_webhook_data_migration.py} +1 -2
  397. nautobot/extras/migrations/{0059_alter_joblogentry_scheduledjob_webhook_fields.py → 0060_alter_joblogentry_scheduledjob_webhook_fields.py} +1 -2
  398. nautobot/extras/migrations/{0060_role_and_alter_status.py → 0061_role_and_alter_status.py} +1 -8
  399. nautobot/extras/migrations/{0061_collect_roles_from_related_apps_roles.py → 0062_collect_roles_from_related_apps_roles.py} +33 -33
  400. nautobot/extras/migrations/{0062_alter_role_options.py → 0063_alter_role_options.py} +1 -2
  401. nautobot/extras/migrations/{0063_alter_configcontext_and_add_new_role.py → 0064_alter_configcontext_and_add_new_role.py} +1 -2
  402. nautobot/extras/migrations/0065_configcontext_data_migrations.py +44 -0
  403. nautobot/extras/migrations/{0065_rename_configcontext_role.py → 0066_rename_configcontext_role.py} +1 -2
  404. nautobot/extras/migrations/{0066_jobresult__add_celery_fields.py → 0067_jobresult__add_celery_fields.py} +36 -3
  405. nautobot/extras/migrations/{0067_created_datetime.py → 0068_created_datetime.py} +1 -2
  406. nautobot/extras/migrations/{0068_remove_site_and_region_attributes_from_config_context.py → 0069_remove_site_and_region_attributes_from_config_context.py} +1 -2
  407. nautobot/extras/migrations/{0069_replace_related_names.py → 0070_replace_related_names.py} +1 -1
  408. nautobot/extras/migrations/{0070_rename_model_fields.py → 0071_rename_model_fields.py} +1 -2
  409. nautobot/extras/migrations/0072_job__unique_name_data_migration.py +86 -0
  410. nautobot/extras/migrations/{0072_job__unique_name.py → 0073_job__unique_name.py} +13 -10
  411. nautobot/extras/migrations/{0073_remove_gitrepository_fields.py → 0074_remove_gitrepository_fields.py} +1 -2
  412. nautobot/extras/migrations/{0074_rename_slug_to_key_for_custom_field.py → 0075_rename_slug_to_key_for_custom_field.py} +1 -1
  413. nautobot/extras/migrations/{0075_migrate_custom_field_data.py → 0076_migrate_custom_field_data.py} +1 -1
  414. nautobot/extras/migrations/{0076_remove_name_field_and_make_label_field_non_nullable.py → 0077_remove_name_field_and_make_label_field_non_nullable.py} +1 -1
  415. nautobot/extras/migrations/0078_remove_slug.py +45 -0
  416. nautobot/extras/migrations/0079_tagsfield.py +28 -0
  417. nautobot/extras/migrations/0080_rename_relationship_slug_to_key.py +17 -0
  418. nautobot/extras/migrations/0081_rename_relationship_name_to_label.py +29 -0
  419. nautobot/extras/migrations/0082_ensure_relationship_keys_are_unique.py +43 -0
  420. nautobot/extras/migrations/0083_rename_computed_field_slug_to_key.py +21 -0
  421. nautobot/extras/migrations/0084_taggeditem_cleanup.py +43 -0
  422. nautobot/extras/migrations/0085_taggeditem_uniqueness.py +22 -0
  423. nautobot/extras/migrations/0086_job__celery_task_fields__dryrun_support.py +81 -0
  424. nautobot/extras/migrations/0087_job__commit_default_data_migration.py +26 -0
  425. nautobot/extras/migrations/0088_joblogentry__log_level_default.py +17 -0
  426. nautobot/extras/migrations/0089_joblogentry__log_level_data_migration.py +34 -0
  427. nautobot/extras/migrations/0090_scheduledjob__data_migration.py +57 -0
  428. nautobot/extras/models/__init__.py +2 -3
  429. nautobot/extras/models/change_logging.py +0 -36
  430. nautobot/extras/models/customfields.py +39 -33
  431. nautobot/extras/models/datasources.py +48 -50
  432. nautobot/extras/models/groups.py +5 -12
  433. nautobot/extras/models/jobs.py +190 -323
  434. nautobot/extras/models/mixins.py +0 -71
  435. nautobot/extras/models/models.py +1 -22
  436. nautobot/extras/models/relationships.py +20 -21
  437. nautobot/extras/models/roles.py +0 -23
  438. nautobot/extras/models/secrets.py +2 -31
  439. nautobot/extras/models/statuses.py +6 -5
  440. nautobot/extras/models/tags.py +2 -17
  441. nautobot/extras/navigation.py +89 -307
  442. nautobot/extras/plugins/__init__.py +3 -121
  443. nautobot/extras/plugins/utils.py +0 -3
  444. nautobot/extras/plugins/validators.py +5 -4
  445. nautobot/extras/plugins/views.py +16 -4
  446. nautobot/extras/querysets.py +1 -7
  447. nautobot/extras/registry.py +3 -0
  448. nautobot/extras/signals.py +26 -60
  449. nautobot/extras/tables.py +42 -49
  450. nautobot/extras/tasks.py +0 -12
  451. nautobot/extras/templates/extras/configcontext.html +1 -1
  452. nautobot/extras/templates/extras/configcontextschema.html +16 -1
  453. nautobot/extras/templates/extras/customfield.html +0 -13
  454. nautobot/extras/templates/extras/dynamicgroup_edit.html +0 -1
  455. nautobot/extras/templates/extras/gitrepository.html +3 -3
  456. nautobot/extras/templates/extras/inc/jobresult.html +10 -0
  457. nautobot/extras/templates/extras/inc/panel_jobhistory.html +1 -1
  458. nautobot/extras/templates/extras/job.html +35 -25
  459. nautobot/extras/templates/extras/job_approval_request.html +15 -30
  460. nautobot/extras/templates/extras/job_detail.html +13 -31
  461. nautobot/extras/templates/extras/job_edit.html +14 -17
  462. nautobot/extras/templates/extras/jobresult.html +24 -6
  463. nautobot/extras/templates/extras/objectchange_list.html +1 -1
  464. nautobot/extras/templates/extras/scheduledjob.html +2 -2
  465. nautobot/extras/templates/extras/secret.html +28 -0
  466. nautobot/extras/templates/extras/secret_edit.html +0 -1
  467. nautobot/extras/templates/extras/secretsgroup_edit.html +0 -1
  468. nautobot/extras/templatetags/custom_links.py +0 -2
  469. nautobot/extras/templatetags/job_buttons.py +1 -0
  470. nautobot/extras/templatetags/plugins.py +0 -1
  471. nautobot/extras/{tests/example_jobs → test_jobs}/api_test_job.py +13 -6
  472. nautobot/extras/test_jobs/atomic_transaction.py +53 -0
  473. nautobot/extras/test_jobs/dry_run.py +29 -0
  474. nautobot/extras/{tests/example_jobs/test_duplicate_name.py → test_jobs/duplicate_name.py} +4 -0
  475. nautobot/extras/test_jobs/duplicate_name2.py +9 -0
  476. nautobot/extras/test_jobs/fail.py +23 -0
  477. nautobot/extras/{tests/example_jobs/test_field_default.py → test_jobs/field_default.py} +4 -0
  478. nautobot/extras/{tests/example_jobs/test_field_order.py → test_jobs/field_order.py} +4 -0
  479. nautobot/extras/{tests/example_jobs/test_file_upload_fail.py → test_jobs/file_upload_fail.py} +11 -6
  480. nautobot/extras/test_jobs/file_upload_pass.py +25 -0
  481. nautobot/extras/test_jobs/has_sensitive_variables.py +25 -0
  482. nautobot/extras/test_jobs/ipaddress_vars.py +66 -0
  483. nautobot/extras/test_jobs/job_button_receiver.py +28 -0
  484. nautobot/extras/test_jobs/job_hook_receiver.py +29 -0
  485. nautobot/extras/test_jobs/job_variables.py +88 -0
  486. nautobot/extras/test_jobs/location_with_custom_field.py +45 -0
  487. nautobot/extras/test_jobs/log_redaction.py +20 -0
  488. nautobot/extras/test_jobs/log_skip_db_logging.py +17 -0
  489. nautobot/extras/test_jobs/modify_db.py +25 -0
  490. nautobot/extras/{tests/example_jobs/test_no_field_order.py → test_jobs/no_field_order.py} +4 -0
  491. nautobot/extras/test_jobs/object_var_optional.py +21 -0
  492. nautobot/extras/test_jobs/object_var_required.py +21 -0
  493. nautobot/extras/test_jobs/object_vars.py +26 -0
  494. nautobot/extras/test_jobs/pass.py +25 -0
  495. nautobot/extras/test_jobs/profiling.py +32 -0
  496. nautobot/extras/test_jobs/read_only_job.py +15 -0
  497. nautobot/extras/{tests/example_jobs/test_required_args.py → test_jobs/required_args.py} +4 -0
  498. nautobot/extras/{tests/example_jobs/test_soft_time_limit_greater_than_time_limit.py → test_jobs/soft_time_limit_greater_than_time_limit.py} +5 -1
  499. nautobot/extras/{tests/example_jobs/test_task_queues.py → test_jobs/task_queues.py} +5 -1
  500. nautobot/extras/tests/integration/__init__.py +3 -3
  501. nautobot/extras/tests/integration/test_computedfields.py +1 -1
  502. nautobot/extras/tests/integration/test_configcontextschema.py +7 -5
  503. nautobot/extras/tests/integration/test_customfields.py +4 -2
  504. nautobot/extras/tests/integration/test_dynamicgroups.py +2 -2
  505. nautobot/extras/tests/integration/test_jobs.py +25 -27
  506. nautobot/extras/tests/integration/test_notes.py +8 -4
  507. nautobot/extras/tests/integration/test_plugins.py +4 -4
  508. nautobot/extras/tests/integration/test_relationships.py +2 -2
  509. nautobot/extras/tests/test_api.py +371 -381
  510. nautobot/extras/tests/test_changelog.py +17 -16
  511. nautobot/extras/tests/test_context_managers.py +5 -6
  512. nautobot/extras/tests/test_customfields.py +112 -73
  513. nautobot/extras/tests/test_datasources.py +191 -117
  514. nautobot/extras/tests/test_dynamicgroups.py +45 -68
  515. nautobot/extras/tests/test_filters.py +170 -130
  516. nautobot/extras/tests/test_forms.py +107 -109
  517. nautobot/extras/tests/{test_scripts.py → test_job_variables.py} +43 -49
  518. nautobot/extras/tests/test_jobs.py +271 -273
  519. nautobot/extras/tests/test_management.py +3 -6
  520. nautobot/extras/tests/test_migrations.py +5 -3
  521. nautobot/extras/tests/test_models.py +121 -173
  522. nautobot/extras/tests/test_notes.py +0 -1
  523. nautobot/extras/tests/test_plugins.py +55 -89
  524. nautobot/extras/tests/test_relationships.py +174 -130
  525. nautobot/extras/tests/test_tags.py +6 -12
  526. nautobot/extras/tests/test_utils.py +31 -1
  527. nautobot/extras/tests/test_views.py +223 -184
  528. nautobot/extras/tests/test_webhooks.py +16 -15
  529. nautobot/extras/urls.py +69 -69
  530. nautobot/extras/utils.py +137 -163
  531. nautobot/extras/views.py +81 -153
  532. nautobot/ipam/api/fields.py +17 -0
  533. nautobot/ipam/api/serializers.py +77 -164
  534. nautobot/ipam/api/urls.py +4 -1
  535. nautobot/ipam/api/views.py +28 -19
  536. nautobot/ipam/apps.py +1 -0
  537. nautobot/ipam/choices.py +5 -12
  538. nautobot/ipam/constants.py +1 -0
  539. nautobot/ipam/factory.py +41 -30
  540. nautobot/ipam/filters.py +58 -25
  541. nautobot/ipam/forms.py +82 -211
  542. nautobot/ipam/graphql/types.py +0 -9
  543. nautobot/ipam/lookups.py +13 -8
  544. nautobot/ipam/management/commands/__init__.py +0 -0
  545. nautobot/ipam/management/commands/fix_prefix_broadcast.py +17 -0
  546. nautobot/ipam/migrations/0001_initial_part_1.py +0 -1
  547. nautobot/ipam/migrations/0002_initial_part_2.py +0 -1
  548. nautobot/ipam/migrations/0003_remove_max_length.py +0 -1
  549. nautobot/ipam/migrations/0004_fixup_p2p_broadcast.py +0 -1
  550. nautobot/ipam/migrations/0005_auto_slug.py +0 -1
  551. nautobot/ipam/migrations/0006_ipaddress_nat_outside_list.py +0 -1
  552. nautobot/ipam/migrations/0007_add_natural_indexing.py +0 -1
  553. nautobot/ipam/migrations/0008_prefix_vlan_vlangroup_location.py +0 -1
  554. nautobot/ipam/migrations/0009_alter_vlan_name.py +0 -1
  555. nautobot/ipam/migrations/0010_alter_ipam_role_add_new_role.py +1 -2
  556. nautobot/ipam/migrations/0011_migrate_ipam_role_data.py +32 -39
  557. nautobot/ipam/migrations/0012_rename_ipam_roles.py +0 -1
  558. nautobot/ipam/migrations/0013_delete_role.py +0 -1
  559. nautobot/ipam/migrations/0014_rename_foreign_keys_and_related_names.py +0 -1
  560. nautobot/ipam/migrations/0015_prefix_add_type.py +0 -1
  561. nautobot/ipam/migrations/0016_prefix_type_data_migration.py +0 -3
  562. nautobot/ipam/migrations/0017_prefix_remove_is_pool.py +0 -1
  563. nautobot/ipam/migrations/0018_remove_site_foreign_key_from_ipam_models.py +0 -1
  564. nautobot/ipam/migrations/0019_created_datetime.py +0 -1
  565. nautobot/ipam/migrations/0020_related_name_changes.py +1 -2
  566. nautobot/ipam/migrations/0021_prefix_add_rir_and_date_allocated.py +0 -1
  567. nautobot/ipam/migrations/0022_aggregate_to_prefix_data_migration.py +3 -5
  568. nautobot/ipam/migrations/0023_delete_aggregate.py +0 -1
  569. nautobot/ipam/migrations/0024_interface_to_ipaddress_m2m.py +0 -1
  570. nautobot/ipam/migrations/0025_interface_ipaddress_m2m_data_migration.py +0 -1
  571. nautobot/ipam/migrations/0026_ipaddress_remove_assigned_object.py +0 -1
  572. nautobot/ipam/migrations/0027_remove_rir_slug.py +16 -0
  573. nautobot/ipam/migrations/0028_tagsfield.py +44 -0
  574. nautobot/ipam/migrations/0029_ip_address_to_interface_uniqueness_constraints.py +18 -0
  575. nautobot/ipam/migrations/0030_ipam__namespaces.py +231 -0
  576. nautobot/ipam/migrations/0031_ipam__prefix__add_parent.py +58 -0
  577. nautobot/ipam/migrations/0032_ipam__namespaces_finish.py +63 -0
  578. nautobot/ipam/migrations/0033_fixup_null_statuses.py +26 -0
  579. nautobot/ipam/migrations/0034_status_nonnullable.py +36 -0
  580. nautobot/ipam/models.py +579 -368
  581. nautobot/ipam/navigation.py +36 -159
  582. nautobot/ipam/querysets.py +117 -90
  583. nautobot/ipam/signals.py +89 -0
  584. nautobot/ipam/tables.py +86 -28
  585. nautobot/ipam/templates/ipam/ipaddress.html +14 -30
  586. nautobot/ipam/templates/ipam/ipaddress_edit.html +1 -0
  587. nautobot/ipam/templates/ipam/namespace_ipaddresses.html +11 -0
  588. nautobot/ipam/templates/ipam/namespace_prefixes.html +11 -0
  589. nautobot/ipam/templates/ipam/namespace_retrieve.html +42 -0
  590. nautobot/ipam/templates/ipam/namespace_vrfs.html +11 -0
  591. nautobot/ipam/templates/ipam/prefix.html +27 -33
  592. nautobot/ipam/templates/ipam/prefix_edit.html +7 -1
  593. nautobot/ipam/templates/ipam/vlangroup.html +0 -13
  594. nautobot/ipam/templates/ipam/vrf.html +6 -4
  595. nautobot/ipam/templates/ipam/vrf_edit.html +20 -2
  596. nautobot/ipam/tests/integration/test_prefixes.py +4 -27
  597. nautobot/ipam/tests/test_api.py +60 -61
  598. nautobot/ipam/tests/test_filters.py +187 -126
  599. nautobot/ipam/tests/test_forms.py +12 -6
  600. nautobot/ipam/tests/test_graphql.py +8 -6
  601. nautobot/ipam/tests/test_migrations.py +8 -13
  602. nautobot/ipam/tests/test_models.py +426 -274
  603. nautobot/ipam/tests/test_ordering.py +6 -3
  604. nautobot/ipam/tests/test_querysets.py +340 -96
  605. nautobot/ipam/tests/test_views.py +100 -55
  606. nautobot/ipam/urls.py +28 -5
  607. nautobot/ipam/{utils.py → utils/__init__.py} +2 -2
  608. nautobot/ipam/utils/migrations.py +713 -0
  609. nautobot/ipam/views.py +237 -122
  610. nautobot/project-static/docs/404.html +1399 -166
  611. nautobot/project-static/docs/additional-features/caching.html +1416 -320
  612. nautobot/project-static/docs/additional-features/change-logging.html +1389 -190
  613. nautobot/project-static/docs/additional-features/config-contexts.html +1389 -190
  614. nautobot/project-static/docs/additional-features/graphql.html +1389 -190
  615. nautobot/project-static/docs/additional-features/healthcheck.html +1389 -190
  616. nautobot/project-static/docs/additional-features/job-scheduling-and-approvals.html +1393 -190
  617. nautobot/project-static/docs/additional-features/jobs.html +1677 -460
  618. nautobot/project-static/docs/additional-features/napalm.html +1389 -190
  619. nautobot/project-static/docs/additional-features/prometheus-metrics.html +1389 -190
  620. nautobot/project-static/docs/additional-features/template-filters.html +1389 -190
  621. nautobot/project-static/docs/administration/celery-queues.html +1389 -190
  622. nautobot/project-static/docs/administration/nautobot-server.html +1553 -375
  623. nautobot/project-static/docs/administration/nautobot-shell.html +1395 -196
  624. nautobot/project-static/docs/administration/permissions.html +1389 -190
  625. nautobot/project-static/docs/administration/replicating-nautobot.html +1387 -207
  626. nautobot/project-static/docs/apps/index.html +1389 -190
  627. nautobot/project-static/docs/apps/nautobot-apps.html +1387 -175
  628. nautobot/project-static/docs/assets/javascripts/bundle.51198bba.min.js +29 -0
  629. nautobot/project-static/docs/assets/javascripts/bundle.51198bba.min.js.map +8 -0
  630. nautobot/project-static/docs/assets/javascripts/workers/{search.16e2a7d4.min.js → search.208ed371.min.js} +9 -15
  631. nautobot/project-static/docs/assets/javascripts/workers/{search.16e2a7d4.min.js.map → search.208ed371.min.js.map} +4 -4
  632. nautobot/project-static/docs/assets/stylesheets/main.ded33207.min.css +1 -0
  633. nautobot/project-static/docs/assets/stylesheets/main.ded33207.min.css.map +1 -0
  634. nautobot/project-static/docs/assets/stylesheets/palette.a0c5b2b5.min.css +1 -0
  635. nautobot/project-static/docs/assets/stylesheets/palette.a0c5b2b5.min.css.map +1 -0
  636. nautobot/project-static/docs/code-reference/nautobot/apps/__init__.html +1775 -590
  637. nautobot/project-static/docs/code-reference/nautobot/apps/admin.html +1389 -190
  638. nautobot/project-static/docs/code-reference/nautobot/apps/api.html +3588 -1922
  639. nautobot/project-static/docs/code-reference/nautobot/apps/choices.html +1461 -262
  640. nautobot/project-static/docs/code-reference/nautobot/apps/config.html +1401 -170
  641. nautobot/project-static/docs/code-reference/nautobot/apps/datasources.html +1396 -191
  642. nautobot/project-static/docs/code-reference/nautobot/apps/filters.html +2095 -894
  643. nautobot/project-static/docs/code-reference/nautobot/apps/forms.html +2357 -1194
  644. nautobot/project-static/docs/code-reference/nautobot/apps/models.html +2258 -940
  645. nautobot/project-static/docs/code-reference/nautobot/apps/secrets.html +1389 -190
  646. nautobot/project-static/docs/code-reference/nautobot/apps/tables.html +1400 -201
  647. nautobot/project-static/docs/code-reference/nautobot/apps/testing.html +11068 -7861
  648. nautobot/project-static/docs/code-reference/nautobot/apps/ui.html +2867 -2224
  649. nautobot/project-static/docs/code-reference/nautobot/apps/urls.html +1389 -190
  650. nautobot/project-static/docs/code-reference/nautobot/apps/views.html +2641 -1573
  651. nautobot/project-static/docs/configuration/authentication/ldap.html +1389 -190
  652. nautobot/project-static/docs/configuration/authentication/remote.html +1389 -190
  653. nautobot/project-static/docs/configuration/authentication/sso.html +1389 -190
  654. nautobot/project-static/docs/configuration/index.html +1398 -199
  655. nautobot/project-static/docs/configuration/optional-settings.html +1418 -274
  656. nautobot/project-static/docs/configuration/required-settings.html +1419 -287
  657. nautobot/project-static/docs/core-functionality/circuits.html +1446 -247
  658. nautobot/project-static/docs/core-functionality/device-types.html +1448 -249
  659. nautobot/project-static/docs/core-functionality/devices.html +1452 -249
  660. nautobot/project-static/docs/core-functionality/ipam.html +1452 -253
  661. nautobot/project-static/docs/core-functionality/power.html +1448 -249
  662. nautobot/project-static/docs/core-functionality/secrets.html +1448 -249
  663. nautobot/project-static/docs/core-functionality/services.html +1448 -249
  664. nautobot/project-static/docs/core-functionality/sites-and-racks.html +1448 -249
  665. nautobot/project-static/docs/core-functionality/tenancy.html +1448 -249
  666. nautobot/project-static/docs/core-functionality/virtualization.html +1452 -249
  667. nautobot/project-static/docs/core-functionality/vlans.html +1448 -249
  668. nautobot/project-static/docs/development/application-registry.html +1393 -214
  669. nautobot/project-static/docs/development/best-practices.html +1392 -192
  670. nautobot/project-static/docs/development/docker-compose-advanced-use-cases.html +1390 -191
  671. nautobot/project-static/docs/development/extending-models.html +1443 -257
  672. nautobot/project-static/docs/development/generic-views.html +1403 -174
  673. nautobot/project-static/docs/development/getting-started.html +1568 -262
  674. nautobot/project-static/docs/development/homepage.html +1389 -190
  675. nautobot/project-static/docs/development/index.html +1389 -190
  676. nautobot/project-static/docs/development/model-features.html +1389 -190
  677. nautobot/project-static/docs/development/natural-keys.html +1389 -190
  678. nautobot/project-static/docs/development/navigation-menu.html +1451 -330
  679. nautobot/project-static/docs/development/react-ui.html +4199 -0
  680. nautobot/project-static/docs/development/release-checklist.html +1392 -193
  681. nautobot/project-static/docs/development/role-internals.html +1402 -172
  682. nautobot/project-static/docs/development/style-guide.html +1399 -199
  683. nautobot/project-static/docs/development/templates.html +1391 -191
  684. nautobot/project-static/docs/development/testing.html +1389 -190
  685. nautobot/project-static/docs/development/user-preferences.html +1389 -190
  686. nautobot/project-static/docs/docker/index.html +1408 -206
  687. nautobot/project-static/docs/index.html +1397 -180
  688. nautobot/project-static/docs/installation/centos.html +1401 -170
  689. nautobot/project-static/docs/installation/external-authentication.html +1389 -190
  690. nautobot/project-static/docs/installation/http-server.html +1389 -190
  691. nautobot/project-static/docs/installation/index.html +1394 -191
  692. nautobot/project-static/docs/installation/migrating-from-netbox.html +1452 -305
  693. nautobot/project-static/docs/installation/migrating-from-postgresql.html +1390 -191
  694. nautobot/project-static/docs/installation/nautobot.html +1390 -191
  695. nautobot/project-static/docs/installation/region-and-site-data-migration-guide.html +1389 -190
  696. nautobot/project-static/docs/installation/selinux-troubleshooting.html +1401 -170
  697. nautobot/project-static/docs/installation/services.html +1389 -190
  698. nautobot/project-static/docs/installation/tables/v2-api-behavior-changes.yaml +70 -0
  699. nautobot/project-static/docs/installation/tables/v2-api-removed-fields.yaml +142 -0
  700. nautobot/project-static/docs/installation/tables/v2-api-renamed-fields.yaml +124 -0
  701. nautobot/project-static/docs/installation/tables/v2-code-location-changes.yaml +241 -0
  702. nautobot/project-static/docs/installation/tables/v2-code-removals.yaml +67 -0
  703. nautobot/project-static/docs/installation/tables/v2-database-behavior-changes.yaml +37 -0
  704. nautobot/project-static/docs/installation/tables/v2-database-removed-fields.yaml +166 -0
  705. nautobot/project-static/docs/installation/tables/v2-database-renamed-fields.yaml +340 -0
  706. nautobot/project-static/docs/installation/tables/v2-filters-corrected-fields.yaml +28 -0
  707. nautobot/project-static/docs/installation/tables/v2-filters-enhanced-fields.yaml +241 -0
  708. nautobot/project-static/docs/installation/tables/v2-filters-removed-fields.yaml +553 -0
  709. nautobot/project-static/docs/installation/tables/v2-filters-renamed-fields.yaml +223 -0
  710. nautobot/project-static/docs/installation/tables/v2-logging-renamed-loggers.yaml +23 -0
  711. nautobot/project-static/docs/installation/ubuntu.html +1401 -170
  712. nautobot/project-static/docs/installation/upgrading-from-nautobot-v1.html +4254 -1923
  713. nautobot/project-static/docs/installation/upgrading.html +1395 -192
  714. nautobot/project-static/docs/models/circuits/circuit.html +1427 -174
  715. nautobot/project-static/docs/models/circuits/circuittermination.html +1427 -174
  716. nautobot/project-static/docs/models/circuits/circuittype.html +1427 -174
  717. nautobot/project-static/docs/models/circuits/provider.html +1427 -174
  718. nautobot/project-static/docs/models/circuits/providernetwork.html +1427 -174
  719. nautobot/project-static/docs/models/dcim/cable.html +1458 -174
  720. nautobot/project-static/docs/models/dcim/consoleport.html +1427 -174
  721. nautobot/project-static/docs/models/dcim/consoleporttemplate.html +1427 -174
  722. nautobot/project-static/docs/models/dcim/consoleserverport.html +1427 -174
  723. nautobot/project-static/docs/models/dcim/consoleserverporttemplate.html +1427 -174
  724. nautobot/project-static/docs/models/dcim/device.html +1431 -174
  725. nautobot/project-static/docs/models/dcim/devicebay.html +1427 -174
  726. nautobot/project-static/docs/models/dcim/devicebaytemplate.html +1427 -174
  727. nautobot/project-static/docs/models/dcim/deviceredundancygroup.html +1522 -177
  728. nautobot/project-static/docs/models/dcim/devicetype.html +1427 -174
  729. nautobot/project-static/docs/models/dcim/frontport.html +1427 -174
  730. nautobot/project-static/docs/models/dcim/frontporttemplate.html +1427 -174
  731. nautobot/project-static/docs/models/dcim/interface.html +1427 -174
  732. nautobot/project-static/docs/models/dcim/interfacetemplate.html +1427 -174
  733. nautobot/project-static/docs/models/dcim/inventoryitem.html +1427 -174
  734. nautobot/project-static/docs/models/dcim/location.html +1427 -174
  735. nautobot/project-static/docs/models/dcim/locationtype.html +1427 -174
  736. nautobot/project-static/docs/models/dcim/manufacturer.html +1427 -174
  737. nautobot/project-static/docs/models/dcim/platform.html +1427 -174
  738. nautobot/project-static/docs/models/dcim/powerfeed.html +1425 -172
  739. nautobot/project-static/docs/models/dcim/poweroutlet.html +1427 -174
  740. nautobot/project-static/docs/models/dcim/poweroutlettemplate.html +1427 -174
  741. nautobot/project-static/docs/models/dcim/powerpanel.html +1425 -172
  742. nautobot/project-static/docs/models/dcim/powerport.html +1427 -174
  743. nautobot/project-static/docs/models/dcim/powerporttemplate.html +1427 -174
  744. nautobot/project-static/docs/models/dcim/rack.html +1427 -174
  745. nautobot/project-static/docs/models/dcim/rackgroup.html +1427 -174
  746. nautobot/project-static/docs/models/dcim/rackreservation.html +1427 -174
  747. nautobot/project-static/docs/models/dcim/rearport.html +1427 -174
  748. nautobot/project-static/docs/models/dcim/rearporttemplate.html +1427 -174
  749. nautobot/project-static/docs/models/dcim/region.html +1401 -170
  750. nautobot/project-static/docs/models/dcim/site.html +1401 -170
  751. nautobot/project-static/docs/models/dcim/virtualchassis.html +1425 -172
  752. nautobot/project-static/docs/models/extras/computedfield.html +1393 -194
  753. nautobot/project-static/docs/models/extras/configcontext.html +1465 -174
  754. nautobot/project-static/docs/models/extras/configcontextschema.html +1421 -168
  755. nautobot/project-static/docs/models/extras/customfield.html +1389 -190
  756. nautobot/project-static/docs/models/extras/customlink.html +1389 -190
  757. nautobot/project-static/docs/models/extras/dynamicgroup.html +1398 -199
  758. nautobot/project-static/docs/models/extras/exporttemplate.html +1389 -190
  759. nautobot/project-static/docs/models/extras/gitrepository.html +1393 -190
  760. nautobot/project-static/docs/models/extras/graphqlquery.html +1469 -171
  761. nautobot/project-static/docs/models/extras/imageattachment.html +1434 -181
  762. nautobot/project-static/docs/models/extras/job.html +1411 -157
  763. nautobot/project-static/docs/models/extras/jobbutton.html +1410 -207
  764. nautobot/project-static/docs/models/extras/jobhook.html +1397 -194
  765. nautobot/project-static/docs/models/extras/joblogentry.html +1408 -155
  766. nautobot/project-static/docs/models/extras/jobresult.html +1417 -159
  767. nautobot/project-static/docs/models/extras/note.html +1389 -190
  768. nautobot/project-static/docs/models/extras/relationship.html +1391 -192
  769. nautobot/project-static/docs/models/extras/role.html +1495 -198
  770. nautobot/project-static/docs/models/extras/secret.html +1492 -201
  771. nautobot/project-static/docs/models/extras/secretsgroup.html +1410 -157
  772. nautobot/project-static/docs/models/extras/status.html +1381 -221
  773. nautobot/project-static/docs/models/extras/tag.html +1389 -190
  774. nautobot/project-static/docs/models/extras/webhook.html +1389 -190
  775. nautobot/project-static/docs/models/ipam/ipaddress.html +1488 -200
  776. nautobot/project-static/docs/models/ipam/prefix.html +1410 -157
  777. nautobot/project-static/docs/models/ipam/rir.html +1410 -157
  778. nautobot/project-static/docs/models/ipam/routetarget.html +1410 -157
  779. nautobot/project-static/docs/models/ipam/service.html +1410 -157
  780. nautobot/project-static/docs/models/ipam/vlan.html +1410 -157
  781. nautobot/project-static/docs/models/ipam/vlangroup.html +1410 -157
  782. nautobot/project-static/docs/models/ipam/vrf.html +1410 -161
  783. nautobot/project-static/docs/models/tenancy/tenant.html +1412 -159
  784. nautobot/project-static/docs/models/tenancy/tenantgroup.html +1412 -159
  785. nautobot/project-static/docs/models/users/objectpermission.html +1462 -171
  786. nautobot/project-static/docs/models/users/token.html +1410 -157
  787. nautobot/project-static/docs/models/virtualization/cluster.html +1410 -157
  788. nautobot/project-static/docs/models/virtualization/clustergroup.html +1410 -157
  789. nautobot/project-static/docs/models/virtualization/clustertype.html +1410 -157
  790. nautobot/project-static/docs/models/virtualization/virtualmachine.html +1414 -157
  791. nautobot/project-static/docs/models/virtualization/vminterface.html +1410 -157
  792. nautobot/project-static/docs/objects.inv +0 -0
  793. nautobot/project-static/docs/plugins/development.html +1916 -646
  794. nautobot/project-static/docs/plugins/index.html +1389 -190
  795. nautobot/project-static/docs/plugins/porting-from-netbox.html +1389 -190
  796. nautobot/project-static/docs/release-notes/index.html +1389 -190
  797. nautobot/project-static/docs/release-notes/version-1.0.html +1389 -190
  798. nautobot/project-static/docs/release-notes/version-1.1.html +1389 -190
  799. nautobot/project-static/docs/release-notes/version-1.2.html +1389 -190
  800. nautobot/project-static/docs/release-notes/version-1.3.html +1389 -190
  801. nautobot/project-static/docs/release-notes/version-1.4.html +1389 -190
  802. nautobot/project-static/docs/release-notes/version-1.5.html +2016 -397
  803. nautobot/project-static/docs/release-notes/version-2.0.html +1935 -287
  804. nautobot/project-static/docs/requirements.txt +5 -4
  805. nautobot/project-static/docs/rest-api/authentication.html +1389 -190
  806. nautobot/project-static/docs/rest-api/filtering.html +1389 -190
  807. nautobot/project-static/docs/rest-api/overview.html +2002 -576
  808. nautobot/project-static/docs/rest-api/ui-related-endpoints.html +4057 -0
  809. nautobot/project-static/docs/search/search_index.json +1 -1
  810. nautobot/project-static/docs/sitemap.xml +197 -187
  811. nautobot/project-static/docs/sitemap.xml.gz +0 -0
  812. nautobot/project-static/docs/user-guides/custom-fields.html +1390 -191
  813. nautobot/project-static/docs/user-guides/getting-started/creating-devices.html +1392 -193
  814. nautobot/project-static/docs/user-guides/getting-started/index.html +1388 -189
  815. nautobot/project-static/docs/user-guides/getting-started/interfaces.html +1388 -189
  816. nautobot/project-static/docs/user-guides/getting-started/ipam.html +1386 -187
  817. nautobot/project-static/docs/user-guides/getting-started/platforms.html +1448 -249
  818. nautobot/project-static/docs/user-guides/getting-started/regions.html +1411 -212
  819. nautobot/project-static/docs/user-guides/getting-started/search-bar.html +1395 -196
  820. nautobot/project-static/docs/user-guides/getting-started/tenants.html +1448 -249
  821. nautobot/project-static/docs/user-guides/getting-started/vlans-and-vlan-groups.html +1448 -249
  822. nautobot/project-static/docs/user-guides/git-data-source.html +1405 -206
  823. nautobot/project-static/docs/user-guides/graphql.html +1402 -203
  824. nautobot/project-static/docs/user-guides/relationships.html +1448 -249
  825. nautobot/project-static/docs/user-guides/s3-django-storage.html +1448 -249
  826. nautobot/project-static/js/forms.js +16 -9
  827. nautobot/project-static/js/theme.js +5 -0
  828. nautobot/tenancy/api/serializers.py +4 -34
  829. nautobot/tenancy/api/urls.py +1 -1
  830. nautobot/tenancy/filters/__init__.py +9 -7
  831. nautobot/tenancy/filters/mixins.py +3 -2
  832. nautobot/tenancy/forms.py +3 -36
  833. nautobot/tenancy/migrations/0001_initial.py +0 -1
  834. nautobot/tenancy/migrations/0002_auto_slug.py +0 -1
  835. nautobot/tenancy/migrations/0003_mptt_to_tree_queries.py +0 -1
  836. nautobot/tenancy/migrations/0004_change_tree_manager_on_tree_models.py +0 -1
  837. nautobot/tenancy/migrations/0005_rename_foreign_keys_and_related_names.py +0 -1
  838. nautobot/tenancy/migrations/0006_created_datetime.py +0 -1
  839. nautobot/tenancy/migrations/0007_remove_tenant_tenantgroup_slug.py +20 -0
  840. nautobot/tenancy/migrations/0008_tagsfield.py +19 -0
  841. nautobot/tenancy/models.py +0 -30
  842. nautobot/tenancy/navigation.py +6 -39
  843. nautobot/tenancy/tables.py +4 -4
  844. nautobot/tenancy/templates/tenancy/tenant.html +12 -12
  845. nautobot/tenancy/templates/tenancy/tenant_edit.html +0 -1
  846. nautobot/tenancy/templates/tenancy/tenantgroup.html +1 -1
  847. nautobot/tenancy/tests/test_api.py +1 -12
  848. nautobot/tenancy/tests/test_filters.py +20 -12
  849. nautobot/tenancy/tests/test_views.py +11 -29
  850. nautobot/tenancy/urls.py +10 -10
  851. nautobot/tenancy/views.py +0 -3
  852. nautobot/ui/.eslintignore +6 -0
  853. nautobot/ui/.gitignore +10 -0
  854. nautobot/ui/.prettierignore +9 -0
  855. nautobot/ui/.prettierrc +4 -0
  856. nautobot/ui/README.md +33 -0
  857. nautobot/ui/app_imports.js.j2 +7 -0
  858. nautobot/ui/craco.config.js +46 -0
  859. nautobot/ui/jsconfig-base.json +11 -0
  860. nautobot/ui/jsconfig.json +5 -0
  861. nautobot/ui/lib/nautobot-craco-alias-plugin.js +40 -0
  862. nautobot/ui/package-lock.json +21451 -0
  863. nautobot/ui/package.json +70 -0
  864. nautobot/ui/public/index.html +47 -0
  865. nautobot/ui/public/logo192.png +0 -0
  866. nautobot/ui/public/logo512.png +0 -0
  867. nautobot/ui/public/manifest.json +25 -0
  868. nautobot/ui/public/nautobot_logo.svg +131 -0
  869. nautobot/ui/public/robots.txt +3 -0
  870. nautobot/ui/src/App.js +71 -0
  871. nautobot/ui/src/components/AppFullWidthComponents.js +8 -0
  872. nautobot/ui/src/components/AppTab.js +40 -0
  873. nautobot/ui/src/components/Apps.js +60 -0
  874. nautobot/ui/src/components/HomeChangelogPanel.js +98 -0
  875. nautobot/ui/src/components/HomePanel.js +58 -0
  876. nautobot/ui/src/components/JobHistoryTable.js +78 -0
  877. nautobot/ui/src/components/Layout.js +53 -0
  878. nautobot/ui/src/components/LoadingWidget.js +25 -0
  879. nautobot/ui/src/components/Navbar.js +116 -0
  880. nautobot/ui/src/components/NotificationPopover.js +27 -0
  881. nautobot/ui/src/components/ObjectListTable.js +209 -0
  882. nautobot/ui/src/components/ReferenceDataTag.js +35 -0
  883. nautobot/ui/src/components/RouterButton.js +10 -0
  884. nautobot/ui/src/components/RouterLink.js +10 -0
  885. nautobot/ui/src/components/SidebarNav.js +147 -0
  886. nautobot/ui/src/components/Table.js +48 -0
  887. nautobot/ui/src/components/TableItem.js +71 -0
  888. nautobot/ui/src/components/__tests__/AppFullWidthComponents.test.js +16 -0
  889. nautobot/ui/src/components/__tests__/AppTab.test.js +21 -0
  890. nautobot/ui/src/components/__tests__/Apps.test.js +14 -0
  891. nautobot/ui/src/components/__tests__/Layout.test.js +33 -0
  892. nautobot/ui/src/components/__tests__/Table.test.js +36 -0
  893. nautobot/ui/src/components/__tests__/TableItem.test.js +37 -0
  894. nautobot/ui/src/components/__tests__/paginator.test.js +43 -0
  895. nautobot/ui/src/components/__tests__/paginator_form.test.js +13 -0
  896. nautobot/ui/src/components/pagination.js +93 -0
  897. nautobot/ui/src/components/paginator.js +79 -0
  898. nautobot/ui/src/components/paginator_form.js +43 -0
  899. nautobot/ui/src/components/usePagination.js +57 -0
  900. nautobot/ui/src/constants/apiPath.js +10 -0
  901. nautobot/ui/src/constants/icons.js +15 -0
  902. nautobot/ui/src/constants/size.js +15 -0
  903. nautobot/ui/src/index.js +65 -0
  904. nautobot/ui/src/reportWebVitals.js +15 -0
  905. nautobot/ui/src/router.js +77 -0
  906. nautobot/ui/src/utils/api.js +131 -0
  907. nautobot/ui/src/utils/app-import.js +15 -0
  908. nautobot/ui/src/utils/color.js +15 -0
  909. nautobot/ui/src/utils/date.js +14 -0
  910. nautobot/ui/src/utils/index.js +15 -0
  911. nautobot/ui/src/utils/navigation.js +32 -0
  912. nautobot/ui/src/utils/session.js +64 -0
  913. nautobot/ui/src/utils/store.js +242 -0
  914. nautobot/ui/src/utils/string.js +6 -0
  915. nautobot/ui/src/utils/url.js +4 -0
  916. nautobot/ui/src/views/Home.js +138 -0
  917. nautobot/ui/src/views/InstalledApps.js +80 -0
  918. nautobot/ui/src/views/Login.js +48 -0
  919. nautobot/ui/src/views/Logout.js +20 -0
  920. nautobot/ui/src/views/__tests__/BSCreateViewTemplate.test.js +11 -0
  921. nautobot/ui/src/views/__tests__/BSListViewTemplate.test.js +107 -0
  922. nautobot/ui/src/views/__tests__/Login.test.js +15 -0
  923. nautobot/ui/src/views/generic/GenericView.js +142 -0
  924. nautobot/ui/src/views/generic/ObjectCreate.js +96 -0
  925. nautobot/ui/src/views/generic/ObjectList.js +127 -0
  926. nautobot/ui/src/views/generic/ObjectRetrieve.js +551 -0
  927. nautobot/users/admin.py +1 -1
  928. nautobot/users/api/serializers.py +51 -61
  929. nautobot/users/api/urls.py +1 -1
  930. nautobot/users/api/views.py +53 -2
  931. nautobot/users/migrations/0001_initial.py +0 -1
  932. nautobot/users/migrations/0002_token_ordering_by_created.py +0 -1
  933. nautobot/users/migrations/0003_alter_user_options.py +0 -1
  934. nautobot/users/migrations/0004_alter_user_managers.py +0 -1
  935. nautobot/users/tests/test_api.py +109 -28
  936. nautobot/users/tests/test_filters.py +0 -4
  937. nautobot/users/tests/test_models.py +0 -1
  938. nautobot/users/views.py +0 -7
  939. nautobot/virtualization/api/serializers.py +18 -132
  940. nautobot/virtualization/api/urls.py +1 -1
  941. nautobot/virtualization/api/views.py +1 -22
  942. nautobot/virtualization/choices.py +0 -2
  943. nautobot/virtualization/filters.py +12 -7
  944. nautobot/virtualization/forms.py +21 -117
  945. nautobot/virtualization/migrations/0001_initial.py +0 -1
  946. nautobot/virtualization/migrations/0002_virtualmachine_local_context_schema.py +0 -1
  947. nautobot/virtualization/migrations/0003_vminterface_verbose_name.py +0 -1
  948. nautobot/virtualization/migrations/0004_auto_slug.py +0 -1
  949. nautobot/virtualization/migrations/0005_add_natural_indexing.py +0 -1
  950. nautobot/virtualization/migrations/0006_vminterface_status.py +0 -1
  951. nautobot/virtualization/migrations/0007_vminterface_status_data_migration.py +0 -1
  952. nautobot/virtualization/migrations/0008_vminterface_parent.py +0 -1
  953. nautobot/virtualization/migrations/0009_cluster_location.py +0 -1
  954. nautobot/virtualization/migrations/0010_vminterface_mac_address_data_migration.py +0 -1
  955. nautobot/virtualization/migrations/0011_alter_vminterface_mac_address.py +0 -1
  956. nautobot/virtualization/migrations/0012_alter_virtualmachine_role_add_new_role.py +1 -2
  957. nautobot/virtualization/migrations/0013_migrate_virtualmachine_role_data.py +18 -12
  958. nautobot/virtualization/migrations/0014_rename_virtualmachine_roles.py +0 -1
  959. nautobot/virtualization/migrations/0015_rename_foreignkey_fields.py +1 -2
  960. nautobot/virtualization/migrations/0016_remove_site_foreign_key_from_cluster_class.py +0 -1
  961. nautobot/virtualization/migrations/0017_created_datetime.py +0 -1
  962. nautobot/virtualization/migrations/0018_related_name_changes.py +1 -2
  963. nautobot/virtualization/migrations/0019_vminterface_ip_addresses_m2m.py +0 -1
  964. nautobot/virtualization/migrations/0020_remove_clustergroup_clustertype_slug.py +20 -0
  965. nautobot/virtualization/migrations/0021_tagsfield_and_vminterface_to_primarymodel.py +39 -0
  966. nautobot/virtualization/migrations/0022_vminterface_timestamps_data_migration.py +17 -0
  967. nautobot/virtualization/migrations/0023_ipam__namespaces.py +25 -0
  968. nautobot/virtualization/migrations/0024_fixup_null_statuses.py +25 -0
  969. nautobot/virtualization/migrations/0025_status_nonnullable.py +29 -0
  970. nautobot/virtualization/models.py +39 -131
  971. nautobot/virtualization/navigation.py +18 -99
  972. nautobot/virtualization/tables.py +4 -4
  973. nautobot/virtualization/templates/virtualization/virtualmachine.html +13 -2
  974. nautobot/virtualization/templates/virtualization/virtualmachine_edit.html +6 -0
  975. nautobot/virtualization/tests/test_api.py +42 -52
  976. nautobot/virtualization/tests/test_filters.py +98 -75
  977. nautobot/virtualization/tests/test_models.py +36 -13
  978. nautobot/virtualization/tests/test_views.py +68 -73
  979. nautobot/virtualization/urls.py +10 -10
  980. nautobot/virtualization/views.py +8 -14
  981. {nautobot-2.0.0a2.dist-info → nautobot-2.0.0b1.dist-info}/METADATA +15 -22
  982. {nautobot-2.0.0a2.dist-info → nautobot-2.0.0b1.dist-info}/RECORD +987 -834
  983. {nautobot-2.0.0a2.dist-info → nautobot-2.0.0b1.dist-info}/WHEEL +1 -1
  984. nautobot/circuits/api/nested_serializers.py +0 -69
  985. nautobot/core/templates/plugin_template/navigation.py-tpl +0 -22
  986. nautobot/dcim/api/nested_serializers.py +0 -356
  987. nautobot/dcim/templates/dcim/device_import.html +0 -5
  988. nautobot/dcim/templates/dcim/device_import_child.html +0 -5
  989. nautobot/dcim/templates/dcim/inc/device_import_header.html +0 -4
  990. nautobot/extras/api/nested_serializers.py +0 -353
  991. nautobot/extras/migrations/0064_configcontext_data_migrations.py +0 -42
  992. nautobot/extras/migrations/0071_job__unique_name_data_migration.py +0 -47
  993. nautobot/extras/reports.py +0 -60
  994. nautobot/extras/scripts.py +0 -72
  995. nautobot/extras/tests/example_jobs/script_variables.py +0 -67
  996. nautobot/extras/tests/example_jobs/test_duplicate_name2.py +0 -5
  997. nautobot/extras/tests/example_jobs/test_fail.py +0 -16
  998. nautobot/extras/tests/example_jobs/test_file_upload_pass.py +0 -20
  999. nautobot/extras/tests/example_jobs/test_ipaddress_vars.py +0 -52
  1000. nautobot/extras/tests/example_jobs/test_job_button_receiver.py +0 -21
  1001. nautobot/extras/tests/example_jobs/test_job_hook_receiver.py +0 -20
  1002. nautobot/extras/tests/example_jobs/test_location_with_custom_field.py +0 -35
  1003. nautobot/extras/tests/example_jobs/test_log_redaction.py +0 -14
  1004. nautobot/extras/tests/example_jobs/test_modify_db.py +0 -19
  1005. nautobot/extras/tests/example_jobs/test_object_var_optional.py +0 -14
  1006. nautobot/extras/tests/example_jobs/test_object_var_required.py +0 -14
  1007. nautobot/extras/tests/example_jobs/test_object_vars.py +0 -29
  1008. nautobot/extras/tests/example_jobs/test_pass.py +0 -19
  1009. nautobot/extras/tests/example_jobs/test_read_only_fail.py +0 -24
  1010. nautobot/extras/tests/example_jobs/test_read_only_no_commit_field.py +0 -10
  1011. nautobot/extras/tests/example_jobs/test_read_only_pass.py +0 -22
  1012. nautobot/ipam/api/nested_serializers.py +0 -143
  1013. nautobot/project-static/docs/assets/javascripts/bundle.5a2dcb6a.min.js +0 -29
  1014. nautobot/project-static/docs/assets/javascripts/bundle.5a2dcb6a.min.js.map +0 -8
  1015. nautobot/project-static/docs/assets/javascripts/extra/bundle.5f09fbc3.min.js +0 -18
  1016. nautobot/project-static/docs/assets/javascripts/extra/bundle.5f09fbc3.min.js.map +0 -8
  1017. nautobot/project-static/docs/assets/stylesheets/extra.0d2c79a8.min.css +0 -1
  1018. nautobot/project-static/docs/assets/stylesheets/extra.0d2c79a8.min.css.map +0 -1
  1019. nautobot/project-static/docs/assets/stylesheets/main.975780f9.min.css +0 -1
  1020. nautobot/project-static/docs/assets/stylesheets/main.975780f9.min.css.map +0 -1
  1021. nautobot/project-static/docs/assets/stylesheets/palette.2505c338.min.css +0 -1
  1022. nautobot/project-static/docs/assets/stylesheets/palette.2505c338.min.css.map +0 -1
  1023. nautobot/tenancy/api/nested_serializers.py +0 -31
  1024. nautobot/users/api/nested_serializers.py +0 -67
  1025. nautobot/virtualization/api/nested_serializers.py +0 -65
  1026. /nautobot/extras/{tests/example_jobs → test_jobs}/__init__.py +0 -0
  1027. /nautobot/{dcim/models/sites.py → ipam/management/__init__.py} +0 -0
  1028. {nautobot-2.0.0a2.dist-info → nautobot-2.0.0b1.dist-info}/LICENSE.txt +0 -0
  1029. {nautobot-2.0.0a2.dist-info → nautobot-2.0.0b1.dist-info}/entry_points.txt +0 -0
@@ -50,32 +50,37 @@ from nautobot.tenancy.models import Tenant
50
50
 
51
51
 
52
52
  class CableLengthTestCase(TestCase):
53
- def setUp(self):
54
- self.location = Location.objects.filter(location_type=LocationType.objects.get(name="Campus")).first()
55
- self.manufacturer = Manufacturer.objects.create(name="Test Manufacturer 1", slug="test-manufacturer-1")
56
- self.devicetype = DeviceType.objects.create(
57
- manufacturer=self.manufacturer,
53
+ @classmethod
54
+ def setUpTestData(cls):
55
+ cls.location = Location.objects.filter(location_type=LocationType.objects.get(name="Campus")).first()
56
+ cls.manufacturer = Manufacturer.objects.first()
57
+ cls.devicetype = DeviceType.objects.create(
58
+ manufacturer=cls.manufacturer,
58
59
  model="Test Device Type 1",
59
60
  slug="test-device-type-1",
60
61
  )
61
- self.devicerole = Role.objects.get_for_model(Device).first()
62
- self.device1 = Device.objects.create(
63
- device_type=self.devicetype,
64
- role=self.devicerole,
62
+ cls.devicerole = Role.objects.get_for_model(Device).first()
63
+ devicestatus = Status.objects.get_for_model(Device).first()
64
+ cls.device1 = Device.objects.create(
65
+ device_type=cls.devicetype,
66
+ role=cls.devicerole,
65
67
  name="TestDevice1",
66
- location=self.location,
68
+ location=cls.location,
69
+ status=devicestatus,
67
70
  )
68
- self.device2 = Device.objects.create(
69
- device_type=self.devicetype,
70
- role=self.devicerole,
71
+ cls.device2 = Device.objects.create(
72
+ device_type=cls.devicetype,
73
+ role=cls.devicerole,
71
74
  name="TestDevice2",
72
- location=self.location,
75
+ location=cls.location,
76
+ status=devicestatus,
73
77
  )
74
- self.status = Status.objects.get_for_model(Cable).get(slug="connected")
78
+ cls.status = Status.objects.get_for_model(Cable).get(name="Connected")
75
79
 
76
80
  def test_cable_validated_save(self):
77
- interface1 = Interface.objects.create(device=self.device1, name="eth0")
78
- interface2 = Interface.objects.create(device=self.device2, name="eth0")
81
+ interfacestatus = Status.objects.get_for_model(Interface).first()
82
+ interface1 = Interface.objects.create(device=self.device1, name="eth0", status=interfacestatus)
83
+ interface2 = Interface.objects.create(device=self.device2, name="eth0", status=interfacestatus)
79
84
  cable = Cable(
80
85
  termination_a=interface1,
81
86
  termination_b=interface2,
@@ -87,8 +92,9 @@ class CableLengthTestCase(TestCase):
87
92
  cable.validated_save()
88
93
 
89
94
  def test_cable_full_clean(self):
90
- interface3 = Interface.objects.create(device=self.device1, name="eth1")
91
- interface4 = Interface.objects.create(device=self.device2, name="eth1")
95
+ interfacestatus = Status.objects.get_for_model(Interface).first()
96
+ interface3 = Interface.objects.create(device=self.device1, name="eth1", status=interfacestatus)
97
+ interface4 = Interface.objects.create(device=self.device2, name="eth1", status=interfacestatus)
92
98
  cable = Cable(
93
99
  termination_a=interface3,
94
100
  termination_b=interface4,
@@ -108,7 +114,7 @@ class InterfaceTemplateCustomFieldTestCase(TestCase):
108
114
  """
109
115
  statuses = Status.objects.get_for_model(Device)
110
116
  location = Location.objects.filter(location_type=LocationType.objects.get(name="Campus")).first()
111
- manufacturer = Manufacturer.objects.create(name="Acme", slug="acme")
117
+ manufacturer = Manufacturer.objects.first()
112
118
  device_role = Role.objects.get_for_model(Device).first()
113
119
  custom_fields = [
114
120
  CustomField.objects.create(type=CustomFieldTypeChoices.TYPE_TEXT, label="Field 1", default="value_1"),
@@ -157,7 +163,7 @@ class InterfaceTemplateTestCase(TestCase):
157
163
  """
158
164
  statuses = Status.objects.get_for_model(Device)
159
165
  location = Location.objects.filter(location_type=LocationType.objects.get(name="Campus")).first()
160
- manufacturer = Manufacturer.objects.create(name="Acme", slug="acme")
166
+ manufacturer = Manufacturer.objects.first()
161
167
  device_role = Role.objects.get_for_model(Device).first()
162
168
  device_type = DeviceType.objects.create(manufacturer=manufacturer, model="FrameForwarder 2048", slug="ff2048")
163
169
  InterfaceTemplate.objects.create(
@@ -174,12 +180,12 @@ class InterfaceTemplateTestCase(TestCase):
174
180
  location=location,
175
181
  )
176
182
 
177
- active_status = Status.objects.get(slug="active")
178
- self.assertEqual(device_1.interfaces.get(name="Test_Template_1").status, active_status)
183
+ status = Status.objects.get_for_model(Interface).get(name="Active")
184
+ self.assertEqual(device_1.interfaces.get(name="Test_Template_1").status, status)
179
185
 
180
186
  # Assert that a different status is picked if active status is not found for interface
181
187
  interface_ct = ContentType.objects.get_for_model(Interface)
182
- active_status.content_types.remove(interface_ct)
188
+ status.content_types.remove(interface_ct)
183
189
 
184
190
  device_2 = Device.objects.create(
185
191
  device_type=device_type,
@@ -195,7 +201,8 @@ class InterfaceTemplateTestCase(TestCase):
195
201
  class RackGroupTestCase(ModelTestCases.BaseModelTestCase):
196
202
  model = RackGroup
197
203
 
198
- def setUp(self):
204
+ @classmethod
205
+ def setUpTestData(cls):
199
206
  """
200
207
  Location A
201
208
  - RackGroup A1
@@ -204,25 +211,33 @@ class RackGroupTestCase(ModelTestCases.BaseModelTestCase):
204
211
  - Rack 1
205
212
  - PowerPanel 1
206
213
  """
207
- self.location_type_a = LocationType.objects.get(name="Campus")
208
- self.location_a = Location.objects.filter(location_type=self.location_type_a).first()
209
- self.rackgroup_a1 = RackGroup(location=self.location_a, name="RackGroup A1", slug="rackgroup-a1")
210
- self.rackgroup_a1.save()
211
- self.rackgroup_a2 = RackGroup(location=self.location_a, parent=self.rackgroup_a1, name="RackGroup A2")
212
- self.rackgroup_a2.save()
214
+ cls.location_type_a = LocationType.objects.get(name="Campus")
215
+ cls.location_a = Location.objects.filter(location_type=cls.location_type_a).first()
216
+ cls.location_status = Status.objects.get_for_model(Location).first()
217
+ cls.rackgroup_a1 = RackGroup(location=cls.location_a, name="RackGroup A1", slug="rackgroup-a1")
218
+ cls.rackgroup_a1.save()
219
+ cls.rackgroup_a2 = RackGroup(location=cls.location_a, parent=cls.rackgroup_a1, name="RackGroup A2")
220
+ cls.rackgroup_a2.save()
213
221
 
214
- self.rack1 = Rack.objects.create(location=self.location_a, rack_group=self.rackgroup_a1, name="Rack 1")
215
- self.rack2 = Rack.objects.create(location=self.location_a, rack_group=self.rackgroup_a2, name="Rack 2")
222
+ rack_status = Status.objects.get_for_model(Rack).first()
223
+ cls.rack1 = Rack.objects.create(
224
+ location=cls.location_a, rack_group=cls.rackgroup_a1, name="Rack 1", status=rack_status
225
+ )
226
+ cls.rack2 = Rack.objects.create(
227
+ location=cls.location_a, rack_group=cls.rackgroup_a2, name="Rack 2", status=rack_status
228
+ )
216
229
 
217
- self.powerpanel1 = PowerPanel.objects.create(
218
- location=self.location_a, rack_group=self.rackgroup_a1, name="Power Panel 1"
230
+ cls.powerpanel1 = PowerPanel.objects.create(
231
+ location=cls.location_a, rack_group=cls.rackgroup_a1, name="Power Panel 1"
219
232
  )
220
233
 
221
234
  def test_rackgroup_location_validation(self):
222
235
  """Check that rack group locations are validated correctly."""
223
236
  # Group location, if specified, must permit RackGroups
224
237
  location_type_c = LocationType.objects.get(name="Elevator")
225
- location_c = Location.objects.create(name="Location C", location_type=location_type_c)
238
+ location_c = Location.objects.create(
239
+ name="Location C", location_type=location_type_c, status=self.location_status
240
+ )
226
241
  child = RackGroup(parent=self.rackgroup_a1, location=location_c, name="Child Group")
227
242
  with self.assertRaises(ValidationError) as cm:
228
243
  child.validated_save()
@@ -231,7 +246,9 @@ class RackGroupTestCase(ModelTestCases.BaseModelTestCase):
231
246
  # Child group location must descend from parent group location
232
247
  location_type_d = LocationType.objects.get(name="Room")
233
248
  location_type_d.content_types.add(ContentType.objects.get_for_model(RackGroup))
234
- location_d = Location.objects.create(name="Location D", location_type=location_type_d, parent=location_c)
249
+ location_d = Location.objects.create(
250
+ name="Location D", location_type=location_type_d, parent=location_c, status=self.location_status
251
+ )
235
252
  child = RackGroup(parent=self.rackgroup_a1, location=location_d, name="Child Group")
236
253
  with self.assertRaises(ValidationError) as cm:
237
254
  child.validated_save()
@@ -246,7 +263,9 @@ class RackGroupTestCase(ModelTestCases.BaseModelTestCase):
246
263
 
247
264
  In this test, the new Location permits Racks and PowerPanels so the Location should match.
248
265
  """
249
- location_b = Location.objects.create(name="Location B", location_type=self.location_type_a)
266
+ location_b = Location.objects.create(
267
+ name="Location B", location_type=self.location_type_a, status=self.location_status
268
+ )
250
269
 
251
270
  self.rackgroup_a1.location = location_b
252
271
  self.rackgroup_a1.save()
@@ -265,7 +284,9 @@ class RackGroupTestCase(ModelTestCases.BaseModelTestCase):
265
284
  """
266
285
  location_type_c = LocationType.objects.create(name="Location Type C", parent=self.location_type_a)
267
286
  location_type_c.content_types.add(ContentType.objects.get_for_model(RackGroup))
268
- location_c = Location.objects.create(name="Location C", location_type=location_type_c, parent=self.location_a)
287
+ location_c = Location.objects.create(
288
+ name="Location C", location_type=location_type_c, parent=self.location_a, status=self.location_status
289
+ )
269
290
 
270
291
  self.rackgroup_a1.location = location_c
271
292
  with self.assertRaises(ValidationError) as cm:
@@ -280,64 +301,53 @@ class RackGroupTestCase(ModelTestCases.BaseModelTestCase):
280
301
  class RackTestCase(ModelTestCases.BaseModelTestCase):
281
302
  model = Rack
282
303
 
283
- def setUp(self):
284
-
285
- self.status = Status.objects.get_for_model(Rack).first()
286
- self.location_type_a = LocationType.objects.create(name="Location Type A")
287
- self.location_type_a.content_types.add(
304
+ @classmethod
305
+ def setUpTestData(cls):
306
+ cls.status = Status.objects.get_for_model(Rack).first()
307
+ cls.location_type_a = LocationType.objects.create(name="Location Type A")
308
+ cls.location_type_a.content_types.add(
288
309
  ContentType.objects.get_for_model(RackGroup),
289
310
  ContentType.objects.get_for_model(Rack),
290
311
  ContentType.objects.get_for_model(Device),
291
312
  )
292
313
 
293
- self.location1 = Location.objects.create(name="Location1", location_type=self.location_type_a)
294
- self.location2 = Location.objects.create(name="Location2", location_type=self.location_type_a)
295
- self.group1 = RackGroup.objects.create(name="TestGroup1", slug="test-group-1", location=self.location1)
296
- self.group2 = RackGroup.objects.create(name="TestGroup2", slug="test-group-2", location=self.location2)
297
- self.rack = Rack.objects.create(
314
+ cls.location_status = Status.objects.get_for_model(Location).first()
315
+ cls.location1 = Location.objects.create(
316
+ name="Location1", location_type=cls.location_type_a, status=cls.location_status
317
+ )
318
+ cls.location2 = Location.objects.create(
319
+ name="Location2", location_type=cls.location_type_a, status=cls.location_status
320
+ )
321
+ cls.group1 = RackGroup.objects.create(name="TestGroup1", slug="test-group-1", location=cls.location1)
322
+ cls.group2 = RackGroup.objects.create(name="TestGroup2", slug="test-group-2", location=cls.location2)
323
+ cls.rack = Rack.objects.create(
298
324
  name="TestRack1",
299
325
  facility_id="A101",
300
- location=self.location1,
301
- rack_group=self.group1,
302
- status=self.status,
326
+ location=cls.location1,
327
+ rack_group=cls.group1,
328
+ status=cls.status,
303
329
  u_height=42,
304
330
  )
305
- self.manufacturer = Manufacturer.objects.create(name="Acme", slug="acme")
331
+ cls.manufacturer = Manufacturer.objects.first()
306
332
 
307
- self.device_type = {
333
+ cls.device_type = {
308
334
  "ff2048": DeviceType.objects.create(
309
- manufacturer=self.manufacturer,
335
+ manufacturer=cls.manufacturer,
310
336
  model="FrameForwarder 2048",
311
337
  slug="ff2048",
312
338
  ),
313
339
  "cc5000": DeviceType.objects.create(
314
- manufacturer=self.manufacturer,
340
+ manufacturer=cls.manufacturer,
315
341
  model="CurrentCatapult 5000",
316
342
  slug="cc5000",
317
343
  u_height=0,
318
344
  ),
319
345
  }
320
- self.role = {
321
- "Server": Role.objects.create(
322
- name="Server",
323
- slug="server",
324
- ),
325
- "Switch": Role.objects.create(
326
- name="Switch",
327
- slug="switch",
328
- ),
329
- "Console Server": Role.objects.create(
330
- name="Console Server",
331
- slug="console-server",
332
- ),
333
- "PDU": Role.objects.create(
334
- name="PDU",
335
- slug="pdu",
336
- ),
337
- }
346
+ cls.roles = Role.objects.get_for_model(Rack)
347
+ cls.device_roles = Role.objects.get_for_model(Device)
348
+ cls.device_status = Status.objects.get_for_model(Device).first()
338
349
 
339
350
  def test_rack_device_outside_height(self):
340
-
341
351
  rack1 = Rack(
342
352
  name="TestRack2",
343
353
  facility_id="A102",
@@ -349,8 +359,9 @@ class RackTestCase(ModelTestCases.BaseModelTestCase):
349
359
 
350
360
  device1 = Device(
351
361
  name="TestSwitch1",
352
- device_type=DeviceType.objects.get(manufacturer__slug="acme", slug="ff2048"),
353
- role=Role.objects.get(slug="switch"),
362
+ device_type=self.device_type["ff2048"],
363
+ role=self.device_roles[0],
364
+ status=self.device_status,
354
365
  location=self.location1,
355
366
  rack=rack1,
356
367
  position=43,
@@ -362,11 +373,11 @@ class RackTestCase(ModelTestCases.BaseModelTestCase):
362
373
  rack1.clean()
363
374
 
364
375
  def test_mount_single_device(self):
365
-
366
376
  device1 = Device(
367
377
  name="TestSwitch1",
368
- device_type=DeviceType.objects.get(manufacturer__slug="acme", slug="ff2048"),
369
- role=Role.objects.get(slug="switch"),
378
+ device_type=self.device_type["ff2048"],
379
+ role=self.device_roles[1],
380
+ status=self.device_status,
370
381
  location=self.location1,
371
382
  rack=self.rack,
372
383
  position=10,
@@ -394,7 +405,8 @@ class RackTestCase(ModelTestCases.BaseModelTestCase):
394
405
  def test_mount_zero_ru(self):
395
406
  pdu = Device.objects.create(
396
407
  name="TestPDU",
397
- role=self.role.get("PDU"),
408
+ role=self.device_roles[3],
409
+ status=self.device_status,
398
410
  device_type=self.device_type.get("cc5000"),
399
411
  location=self.location1,
400
412
  rack=self.rack,
@@ -414,23 +426,24 @@ class RackTestCase(ModelTestCases.BaseModelTestCase):
414
426
  location=self.location1,
415
427
  rack=self.rack,
416
428
  device_type=self.device_type["cc5000"],
417
- role=self.role["Switch"],
429
+ role=self.device_roles[3],
430
+ status=self.device_status,
418
431
  )
419
432
  # Device2 is explicitly assigned to the same location as the Rack
420
433
  device2 = Device.objects.create(
421
434
  location=self.location1,
422
435
  rack=self.rack,
423
436
  device_type=self.device_type["cc5000"],
424
- role=self.role["Switch"],
437
+ role=self.device_roles[3],
438
+ status=self.device_status,
425
439
  )
426
440
 
427
441
  # Move self.rack to a new location
428
- location2 = Location.objects.create(name="Location2", location_type=self.location_type_a)
429
- self.rack.location = location2
442
+ self.rack.location = self.location2
430
443
  self.rack.save()
431
444
 
432
- self.assertEqual(Device.objects.get(pk=device1.pk).location, location2)
433
- self.assertEqual(Device.objects.get(pk=device2.pk).location, location2)
445
+ self.assertEqual(Device.objects.get(pk=device1.pk).location, self.location2)
446
+ self.assertEqual(Device.objects.get(pk=device2.pk).location, self.location2)
434
447
 
435
448
  def test_change_rack_location_devices_not_permitted(self):
436
449
  """
@@ -442,22 +455,24 @@ class RackTestCase(ModelTestCases.BaseModelTestCase):
442
455
  location=self.location1,
443
456
  rack=self.rack,
444
457
  device_type=self.device_type["cc5000"],
445
- role=self.role["Switch"],
458
+ role=self.device_roles[3],
459
+ status=self.device_status,
446
460
  )
447
461
 
448
462
  # Move self.rack to a new location that permits Racks but not Devices
449
463
  location_type_b = LocationType.objects.create(name="Location Type B")
450
464
  location_type_b.content_types.add(ContentType.objects.get_for_model(Rack))
451
- location2 = Location.objects.create(name="Location2", location_type=location_type_b)
452
- self.rack.location = location2
465
+ location3 = Location.objects.create(
466
+ name="Location3", location_type=location_type_b, status=self.location_status
467
+ )
468
+ self.rack.location = location3
453
469
  with self.assertRaises(ValidationError) as cm:
454
470
  self.rack.save()
455
471
  self.assertIn(f'Devices may not associate to locations of type "{location_type_b}"', str(cm.exception))
456
472
 
457
473
  def test_rack_location_validation(self):
458
474
  # Rack group location and rack location must relate
459
- location2 = Location.objects.create(name="Location2", location_type=self.location_type_a)
460
- rack = Rack(name="Rack", rack_group=self.group1, location=location2, status=self.status)
475
+ rack = Rack(name="Rack", rack_group=self.group1, location=self.location2, status=self.status)
461
476
  with self.assertRaises(ValidationError) as cm:
462
477
  rack.validated_save()
463
478
  self.assertIn(
@@ -467,7 +482,9 @@ class RackTestCase(ModelTestCases.BaseModelTestCase):
467
482
 
468
483
  # Location type must permit Racks
469
484
  location_type_b = LocationType.objects.create(name="Location Type B")
470
- locationb = Location.objects.create(name="Location2", location_type=location_type_b)
485
+ locationb = Location.objects.create(
486
+ name="Location3", location_type=location_type_b, status=self.location_status
487
+ )
471
488
  rack = Rack(name="Rack", location=locationb, status=self.status)
472
489
  with self.assertRaises(ValidationError) as cm:
473
490
  rack.validated_save()
@@ -528,7 +545,7 @@ class LocationTestCase(ModelTestCases.BaseModelTestCase):
528
545
  name="Pseudo-RackGroup", parent=self.root_nestable_type, nestable=True
529
546
  )
530
547
 
531
- self.status = Status.objects.get(slug="active")
548
+ self.status = Status.objects.get_for_model(Location).first()
532
549
 
533
550
  def test_custom_natural_key_field_lookups(self):
534
551
  """Test that the custom implementation of Location.natural_key_field_lookups works as intended."""
@@ -571,12 +588,12 @@ class LocationTestCase(ModelTestCases.BaseModelTestCase):
571
588
 
572
589
  def test_latitude_or_longitude(self):
573
590
  """Test latitude and longitude is parsed to string."""
574
- active_status = Status.objects.get_for_model(Location).get(slug="active")
591
+ status = Status.objects.get_for_model(Location).first()
575
592
  location = Location(
576
593
  location_type=self.root_type,
577
594
  name="Location A",
578
595
  slug="location-a",
579
- status=active_status,
596
+ status=status,
580
597
  longitude=55.1234567896,
581
598
  latitude=55.1234567896,
582
599
  )
@@ -662,15 +679,14 @@ class DeviceTestCase(ModelTestCases.BaseModelTestCase):
662
679
  model = Device
663
680
 
664
681
  def setUp(self):
665
-
666
- manufacturer = Manufacturer.objects.create(name="Test Manufacturer 1", slug="test-manufacturer-1")
682
+ manufacturer = Manufacturer.objects.first()
667
683
  self.device_type = DeviceType.objects.create(
668
684
  manufacturer=manufacturer,
669
685
  model="Test Device Type 1",
670
686
  slug="test-device-type-1",
671
687
  )
672
688
  self.device_role = Role.objects.get_for_model(Device).first()
673
- self.device_status = Status.objects.get_for_model(Device).get(slug="active")
689
+ self.device_status = Status.objects.get_for_model(Device).first()
674
690
  self.location_type_1 = LocationType.objects.get(name="Building")
675
691
  self.location_type_2 = LocationType.objects.get(name="Floor")
676
692
  self.location_type_3 = LocationType.objects.get(name="Campus")
@@ -780,7 +796,6 @@ class DeviceTestCase(ModelTestCases.BaseModelTestCase):
780
796
  DeviceBay.objects.get(device=self.device, name="Device Bay 1")
781
797
 
782
798
  def test_multiple_unnamed_devices(self):
783
-
784
799
  device1 = Device(
785
800
  location=self.location_3,
786
801
  device_type=self.device_type,
@@ -803,7 +818,6 @@ class DeviceTestCase(ModelTestCases.BaseModelTestCase):
803
818
  self.assertEqual(Device.objects.filter(name="").count(), 2)
804
819
 
805
820
  def test_device_duplicate_names(self):
806
-
807
821
  device2 = Device(
808
822
  location=self.device.location,
809
823
  device_type=self.device.device_type,
@@ -816,7 +830,7 @@ class DeviceTestCase(ModelTestCases.BaseModelTestCase):
816
830
  with self.assertRaises(ValidationError):
817
831
  device2.full_clean()
818
832
 
819
- tenant = Tenant.objects.create(name="Test Tenant 1", slug="test-tenant-1")
833
+ tenant = Tenant.objects.first()
820
834
  self.device.tenant = tenant
821
835
  self.device.save()
822
836
  device2.tenant = tenant
@@ -886,91 +900,101 @@ class DeviceTestCase(ModelTestCases.BaseModelTestCase):
886
900
  class CableTestCase(ModelTestCases.BaseModelTestCase):
887
901
  model = Cable
888
902
 
889
- def setUp(self):
890
-
903
+ @classmethod
904
+ def setUpTestData(cls):
891
905
  location = Location.objects.first()
892
- manufacturer = Manufacturer.objects.create(name="Test Manufacturer 1", slug="test-manufacturer-1")
906
+ manufacturer = Manufacturer.objects.first()
893
907
  devicetype = DeviceType.objects.create(
894
908
  manufacturer=manufacturer,
895
909
  model="Test Device Type 1",
896
910
  slug="test-device-type-1",
897
911
  )
898
912
  devicerole = Role.objects.get_for_model(Device).first()
899
- self.device1 = Device.objects.create(
913
+ devicestatus = Status.objects.get_for_model(Device).first()
914
+ cls.device1 = Device.objects.create(
900
915
  device_type=devicetype,
901
916
  role=devicerole,
902
917
  name="TestDevice1",
903
918
  location=location,
919
+ status=devicestatus,
904
920
  )
905
- self.device2 = Device.objects.create(
921
+ cls.device2 = Device.objects.create(
906
922
  device_type=devicetype,
907
923
  role=devicerole,
908
924
  name="TestDevice2",
909
925
  location=location,
910
- )
911
- self.interface1 = Interface.objects.create(device=self.device1, name="eth0")
912
- self.interface2 = Interface.objects.create(device=self.device2, name="eth0")
913
- self.interface3 = Interface.objects.create(device=self.device2, name="eth1")
914
- self.status = Status.objects.get_for_model(Cable).get(slug="connected")
915
- self.cable = Cable(
916
- termination_a=self.interface1,
917
- termination_b=self.interface2,
918
- status=self.status,
919
- )
920
- self.cable.save()
921
-
922
- self.power_port1 = PowerPort.objects.create(device=self.device2, name="psu1")
923
- self.patch_panel = Device.objects.create(
926
+ status=devicestatus,
927
+ )
928
+ interfacestatus = Status.objects.get_for_model(Interface).first()
929
+ cls.interface1 = Interface.objects.create(device=cls.device1, name="eth0", status=interfacestatus)
930
+ cls.interface2 = Interface.objects.create(device=cls.device2, name="eth0", status=interfacestatus)
931
+ cls.interface3 = Interface.objects.create(device=cls.device2, name="eth1", status=interfacestatus)
932
+ cls.status = Status.objects.get_for_model(Cable).get(name="Connected")
933
+ cls.cable = Cable(
934
+ termination_a=cls.interface1,
935
+ termination_b=cls.interface2,
936
+ status=cls.status,
937
+ )
938
+ cls.cable.save()
939
+
940
+ cls.power_port1 = PowerPort.objects.create(device=cls.device2, name="psu1")
941
+ cls.patch_panel = Device.objects.create(
924
942
  device_type=devicetype,
925
943
  role=devicerole,
926
944
  name="TestPatchPanel",
927
945
  location=location,
946
+ status=devicestatus,
928
947
  )
929
- self.rear_port1 = RearPort.objects.create(device=self.patch_panel, name="RP1", type="8p8c")
930
- self.front_port1 = FrontPort.objects.create(
931
- device=self.patch_panel,
948
+ cls.rear_port1 = RearPort.objects.create(device=cls.patch_panel, name="RP1", type="8p8c")
949
+ cls.front_port1 = FrontPort.objects.create(
950
+ device=cls.patch_panel,
932
951
  name="FP1",
933
952
  type="8p8c",
934
- rear_port=self.rear_port1,
953
+ rear_port=cls.rear_port1,
935
954
  rear_port_position=1,
936
955
  )
937
- self.rear_port2 = RearPort.objects.create(device=self.patch_panel, name="RP2", type="8p8c", positions=2)
938
- self.front_port2 = FrontPort.objects.create(
939
- device=self.patch_panel,
956
+ cls.rear_port2 = RearPort.objects.create(device=cls.patch_panel, name="RP2", type="8p8c", positions=2)
957
+ cls.front_port2 = FrontPort.objects.create(
958
+ device=cls.patch_panel,
940
959
  name="FP2",
941
960
  type="8p8c",
942
- rear_port=self.rear_port2,
961
+ rear_port=cls.rear_port2,
943
962
  rear_port_position=1,
944
963
  )
945
- self.rear_port3 = RearPort.objects.create(device=self.patch_panel, name="RP3", type="8p8c", positions=3)
946
- self.front_port3 = FrontPort.objects.create(
947
- device=self.patch_panel,
964
+ cls.rear_port3 = RearPort.objects.create(device=cls.patch_panel, name="RP3", type="8p8c", positions=3)
965
+ cls.front_port3 = FrontPort.objects.create(
966
+ device=cls.patch_panel,
948
967
  name="FP3",
949
968
  type="8p8c",
950
- rear_port=self.rear_port3,
969
+ rear_port=cls.rear_port3,
951
970
  rear_port_position=1,
952
971
  )
953
- self.rear_port4 = RearPort.objects.create(device=self.patch_panel, name="RP4", type="8p8c", positions=3)
954
- self.front_port4 = FrontPort.objects.create(
955
- device=self.patch_panel,
972
+ cls.rear_port4 = RearPort.objects.create(device=cls.patch_panel, name="RP4", type="8p8c", positions=3)
973
+ cls.front_port4 = FrontPort.objects.create(
974
+ device=cls.patch_panel,
956
975
  name="FP4",
957
976
  type="8p8c",
958
- rear_port=self.rear_port4,
977
+ rear_port=cls.rear_port4,
959
978
  rear_port_position=1,
960
979
  )
961
- self.provider = Provider.objects.create(name="Provider 1", slug="provider-1")
962
- provider_network = ProviderNetwork.objects.create(name="Provider Network 1", provider=self.provider)
963
- self.circuittype = CircuitType.objects.create(name="Circuit Type 1", slug="circuit-type-1")
964
- self.circuit1 = Circuit.objects.create(provider=self.provider, circuit_type=self.circuittype, cid="1")
965
- self.circuit2 = Circuit.objects.create(provider=self.provider, circuit_type=self.circuittype, cid="2")
966
- self.circuittermination1 = CircuitTermination.objects.create(
967
- circuit=self.circuit1, location=location, term_side="A"
980
+ cls.provider = Provider.objects.first()
981
+ provider_network = ProviderNetwork.objects.create(name="Provider Network 1", provider=cls.provider)
982
+ cls.circuittype = CircuitType.objects.first()
983
+ circuit_status = Status.objects.get_for_model(Circuit).first()
984
+ cls.circuit1 = Circuit.objects.create(
985
+ provider=cls.provider, circuit_type=cls.circuittype, cid="1", status=circuit_status
986
+ )
987
+ cls.circuit2 = Circuit.objects.create(
988
+ provider=cls.provider, circuit_type=cls.circuittype, cid="2", status=circuit_status
968
989
  )
969
- self.circuittermination2 = CircuitTermination.objects.create(
970
- circuit=self.circuit1, location=location, term_side="Z"
990
+ cls.circuittermination1 = CircuitTermination.objects.create(
991
+ circuit=cls.circuit1, location=location, term_side="A"
971
992
  )
972
- self.circuittermination3 = CircuitTermination.objects.create(
973
- circuit=self.circuit2, provider_network=provider_network, term_side="Z"
993
+ cls.circuittermination2 = CircuitTermination.objects.create(
994
+ circuit=cls.circuit1, location=location, term_side="Z"
995
+ )
996
+ cls.circuittermination3 = CircuitTermination.objects.create(
997
+ circuit=cls.circuit2, provider_network=provider_network, term_side="Z"
974
998
  )
975
999
 
976
1000
  def test_cable_creation(self):
@@ -1124,19 +1148,23 @@ class CableTestCase(ModelTestCases.BaseModelTestCase):
1124
1148
  """Test for https://github.com/nautobot/nautobot/issues/2081"""
1125
1149
  # Delete all cables because some cables has connected status.
1126
1150
  Cable.objects.all().delete()
1127
- Status.objects.get(slug=CableStatusChoices.STATUS_CONNECTED).delete()
1151
+ connected_status_name = CableStatusChoices.as_dict()[CableStatusChoices.STATUS_CONNECTED]
1152
+ Status.objects.get(name=connected_status_name).delete()
1128
1153
  device = Device.objects.first()
1129
1154
 
1155
+ interface_status = Status.objects.get_for_model(Interface).first()
1130
1156
  interfaces = (
1131
1157
  Interface.objects.create(
1132
1158
  device=device,
1133
1159
  name="eth-0",
1134
1160
  type=InterfaceTypeChoices.TYPE_1GE_FIXED,
1161
+ status=interface_status,
1135
1162
  ),
1136
1163
  Interface.objects.create(
1137
1164
  device=device,
1138
1165
  name="eth-1",
1139
1166
  type=InterfaceTypeChoices.TYPE_1GE_FIXED,
1167
+ status=interface_status,
1140
1168
  ),
1141
1169
  )
1142
1170
 
@@ -1144,6 +1172,7 @@ class CableTestCase(ModelTestCases.BaseModelTestCase):
1144
1172
  termination_a=interfaces[0],
1145
1173
  termination_b=interfaces[1],
1146
1174
  type=CableTypeChoices.TYPE_CAT6,
1175
+ status=Status.objects.get_for_model(Cable).first(),
1147
1176
  )
1148
1177
 
1149
1178
  self.assertTrue(Cable.objects.filter(id=cable.pk).exists())
@@ -1151,9 +1180,9 @@ class CableTestCase(ModelTestCases.BaseModelTestCase):
1151
1180
 
1152
1181
  class PowerPanelTestCase(TestCase): # TODO: change to BaseModelTestCase once we have a PowerPanelFactory
1153
1182
  def test_power_panel_validation(self):
1154
- active = Status.objects.get(name="Active")
1183
+ status = Status.objects.get_for_model(Location).first()
1155
1184
  location_type_1 = LocationType.objects.create(name="Location Type 1")
1156
- location_1 = Location.objects.create(name="Location 1", location_type=location_type_1, status=active)
1185
+ location_1 = Location.objects.create(name="Location 1", location_type=location_type_1, status=status)
1157
1186
  power_panel = PowerPanel(name="Power Panel 1", location=location_1)
1158
1187
  with self.assertRaises(ValidationError) as cm:
1159
1188
  power_panel.validated_save()
@@ -1162,7 +1191,7 @@ class PowerPanelTestCase(TestCase): # TODO: change to BaseModelTestCase once we
1162
1191
  location_type_1.content_types.add(ContentType.objects.get_for_model(PowerPanel))
1163
1192
  rack_group = RackGroup.objects.create(name="Rack Group 1", location=location_1)
1164
1193
  power_panel.rack_group = rack_group
1165
- location_2 = Location.objects.create(name="Location 2", location_type=location_type_1, status=active)
1194
+ location_2 = Location.objects.create(name="Location 2", location_type=location_type_1, status=status)
1166
1195
  rack_group.location = location_2
1167
1196
  rack_group.save()
1168
1197
  with self.assertRaises(ValidationError) as cm:
@@ -1174,26 +1203,31 @@ class PowerPanelTestCase(TestCase): # TODO: change to BaseModelTestCase once we
1174
1203
 
1175
1204
 
1176
1205
  class InterfaceTestCase(TestCase): # TODO: change to BaseModelTestCase once we have an InterfaceFactory
1177
- def setUp(self):
1178
- manufacturer = Manufacturer.objects.create(name="Manufacturer 1", slug="manufacturer-1")
1206
+ @classmethod
1207
+ def setUpTestData(cls):
1208
+ manufacturer = Manufacturer.objects.first()
1179
1209
  devicetype = DeviceType.objects.create(manufacturer=manufacturer, model="Device Type 1", slug="device-type-1")
1180
1210
  devicerole = Role.objects.get_for_model(Device).first()
1181
1211
  location = Location.objects.filter(location_type=LocationType.objects.get(name="Campus")).first()
1182
- self.vlan = VLAN.objects.create(name="VLAN 1", vid=100, location=location)
1212
+ vlan_status = Status.objects.get_for_model(VLAN).first()
1213
+ cls.vlan = VLAN.objects.create(name="VLAN 1", vid=100, location=location, status=vlan_status)
1183
1214
  status = Status.objects.get_for_model(Device)[0]
1184
- self.device = Device.objects.create(
1215
+ cls.device = Device.objects.create(
1185
1216
  name="Device 1",
1186
1217
  device_type=devicetype,
1187
1218
  role=devicerole,
1188
1219
  location=location,
1189
1220
  status=status,
1190
1221
  )
1191
- self.other_location_vlan = VLAN.objects.create(
1222
+ cls.other_location_vlan = VLAN.objects.create(
1192
1223
  name="Other Location VLAN",
1193
1224
  vid=100,
1194
1225
  location=Location.objects.create(
1195
- name="Other Location", location_type=LocationType.objects.get(name="Campus")
1226
+ name="Other Location",
1227
+ location_type=LocationType.objects.get(name="Campus"),
1228
+ status=Status.objects.get_for_model(Location).first(),
1196
1229
  ),
1230
+ status=vlan_status,
1197
1231
  )
1198
1232
 
1199
1233
  def test_tagged_vlan_raise_error_if_mode_not_set_to_tagged(self):
@@ -1201,6 +1235,7 @@ class InterfaceTestCase(TestCase): # TODO: change to BaseModelTestCase once we
1201
1235
  name="Int1",
1202
1236
  type=InterfaceTypeChoices.TYPE_VIRTUAL,
1203
1237
  device=self.device,
1238
+ status=Status.objects.get_for_model(Interface).first(),
1204
1239
  )
1205
1240
  with self.assertRaises(ValidationError) as err:
1206
1241
  interface.tagged_vlans.add(self.vlan)
@@ -1214,6 +1249,7 @@ class InterfaceTestCase(TestCase): # TODO: change to BaseModelTestCase once we
1214
1249
  name="Test Interface",
1215
1250
  mode=InterfaceModeChoices.MODE_TAGGED,
1216
1251
  device=self.device,
1252
+ status=Status.objects.get_for_model(Interface).first(),
1217
1253
  )
1218
1254
  interface.tagged_vlans.add(self.other_location_vlan)
1219
1255
  self.assertEqual(
@@ -1228,6 +1264,7 @@ class InterfaceTestCase(TestCase): # TODO: change to BaseModelTestCase once we
1228
1264
  name="Int1",
1229
1265
  type=InterfaceTypeChoices.TYPE_VIRTUAL,
1230
1266
  device=self.device,
1267
+ status=Status.objects.get_for_model(Interface).first(),
1231
1268
  )
1232
1269
  ips = list(IPAddress.objects.all()[:10])
1233
1270
 
@@ -1252,6 +1289,7 @@ class InterfaceTestCase(TestCase): # TODO: change to BaseModelTestCase once we
1252
1289
  name="Int1",
1253
1290
  type=InterfaceTypeChoices.TYPE_VIRTUAL,
1254
1291
  device=self.device,
1292
+ status=Status.objects.get_for_model(Interface).first(),
1255
1293
  )
1256
1294
  ips = list(IPAddress.objects.all()[:10])
1257
1295
 
@@ -1274,3 +1312,15 @@ class InterfaceTestCase(TestCase): # TODO: change to BaseModelTestCase once we
1274
1312
  count = interface.remove_ip_addresses(ips)
1275
1313
  self.assertEqual(count, 4)
1276
1314
  self.assertEqual(IPAddressToInterface.objects.filter(interface=interface).count(), 0)
1315
+
1316
+ # Test the pre_delete signal for IPAddressToInterface instances
1317
+ interface.add_ip_addresses(ips)
1318
+ self.device.primary_ip4 = interface.ip_addresses.all().filter(host__family=4).first()
1319
+ self.device.primary_ip6 = interface.ip_addresses.all().filter(host__family=6).first()
1320
+ self.device.save()
1321
+ interface.remove_ip_addresses(self.device.primary_ip4)
1322
+ self.device.refresh_from_db()
1323
+ self.assertEqual(self.device.primary_ip4, None)
1324
+ interface.remove_ip_addresses(self.device.primary_ip6)
1325
+ self.device.refresh_from_db()
1326
+ self.assertEqual(self.device.primary_ip6, None)