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
@@ -66,10 +66,11 @@ from nautobot.extras.models import (
66
66
  Status,
67
67
  Webhook,
68
68
  )
69
- from nautobot.ipam.models import IPAddress, VLAN
69
+ from nautobot.ipam.models import IPAddress, VLAN, Namespace, Prefix
70
70
  from nautobot.users.models import ObjectPermission, Token
71
71
  from nautobot.tenancy.models import Tenant
72
- from nautobot.virtualization.models import Cluster, ClusterType, VirtualMachine, VMInterface
72
+ from nautobot.virtualization.factory import ClusterTypeFactory
73
+ from nautobot.virtualization.models import Cluster, VirtualMachine, VMInterface
73
74
 
74
75
  # Use the proper swappable User model
75
76
  User = get_user_model()
@@ -78,15 +79,20 @@ User = get_user_model()
78
79
  class GraphQLTestCase(TestCase):
79
80
  def setUp(self):
80
81
  self.user = create_test_user("graphql_testuser")
81
- GraphQLQuery.objects.create(name="GQL 1", slug="gql-1", query="{ query: locations {name} }")
82
- GraphQLQuery.objects.create(
83
- name="GQL 2", slug="gql-2", query="query ($name: [String!]) { locations(name:$name) {name} }"
84
- )
82
+ GraphQLQuery.objects.create(name="GQL 1", query="{ query: locations {name} }")
83
+ GraphQLQuery.objects.create(name="GQL 2", query="query ($name: [String!]) { locations(name:$name) {name} }")
85
84
  self.location_type = LocationType.objects.get(name="Campus")
85
+ location_status = Status.objects.get_for_model(Location).first()
86
86
  self.locations = (
87
- Location.objects.create(name="Location-1", slug="location-1", location_type=self.location_type),
88
- Location.objects.create(name="Location-2", slug="location-2", location_type=self.location_type),
89
- Location.objects.create(name="Location-3", slug="location-3", location_type=self.location_type),
87
+ Location.objects.create(
88
+ name="Location-1", slug="location-1", location_type=self.location_type, status=location_status
89
+ ),
90
+ Location.objects.create(
91
+ name="Location-2", slug="location-2", location_type=self.location_type, status=location_status
92
+ ),
93
+ Location.objects.create(
94
+ name="Location-3", slug="location-3", location_type=self.location_type, status=location_status
95
+ ),
90
96
  )
91
97
 
92
98
  @override_settings(EXEMPT_VIEW_PERMISSIONS=["*"])
@@ -109,17 +115,16 @@ class GraphQLTestCase(TestCase):
109
115
  execute_query(query, user=self.user).to_dict()
110
116
 
111
117
  def test_execute_saved_query(self):
112
- resp = execute_saved_query("gql-1", user=self.user).to_dict()
118
+ resp = execute_saved_query("GQL 1", user=self.user).to_dict()
113
119
  self.assertFalse(resp["data"].get("error"))
114
120
 
115
121
  def test_execute_saved_query_with_variable(self):
116
- resp = execute_saved_query("gql-2", user=self.user, variables={"name": "location-1"}).to_dict()
122
+ resp = execute_saved_query("GQL 2", user=self.user, variables={"name": "location-1"}).to_dict()
117
123
  self.assertFalse(resp["data"].get("error"))
118
124
 
119
125
 
120
126
  class GraphQLUtilsTestCase(TestCase):
121
127
  def test_str_to_var_name(self):
122
-
123
128
  self.assertEqual(str_to_var_name("IP Addresses"), "ip_addresses")
124
129
  self.assertEqual(str_to_var_name("My New VAR"), "my_new_var")
125
130
  self.assertEqual(str_to_var_name("My-VAR"), "my_var")
@@ -127,14 +132,12 @@ class GraphQLUtilsTestCase(TestCase):
127
132
 
128
133
  class GraphQLGenerateSchemaTypeTestCase(TestCase):
129
134
  def test_model_w_filterset(self):
130
-
131
135
  schema = generate_schema_type(app_name="dcim", model=Device)
132
136
  self.assertEqual(schema.__bases__[0], DjangoObjectType)
133
137
  self.assertEqual(schema._meta.model, Device)
134
138
  self.assertEqual(schema._meta.filterset_class, DeviceFilterSet)
135
139
 
136
140
  def test_model_wo_filterset(self):
137
-
138
141
  schema = generate_schema_type(app_name="wrong_app", model=ChangeLoggedModel)
139
142
  self.assertEqual(schema.__bases__[0], DjangoObjectType)
140
143
  self.assertEqual(schema._meta.model, ChangeLoggedModel)
@@ -143,7 +146,6 @@ class GraphQLGenerateSchemaTypeTestCase(TestCase):
143
146
 
144
147
  class GraphQLExtendSchemaType(TestCase):
145
148
  def setUp(self):
146
-
147
149
  self.datas = (
148
150
  {"field_name": "my_text", "field_type": CustomFieldTypeChoices.TYPE_TEXT},
149
151
  {
@@ -181,7 +183,6 @@ class GraphQLExtendSchemaType(TestCase):
181
183
 
182
184
  @override_settings(GRAPHQL_CUSTOM_FIELD_PREFIX="pr")
183
185
  def test_extend_custom_field_w_prefix(self):
184
-
185
186
  schema = extend_schema_type_custom_field(self.schema, Location)
186
187
 
187
188
  for data in self.datas:
@@ -190,7 +191,6 @@ class GraphQLExtendSchemaType(TestCase):
190
191
 
191
192
  @override_settings(GRAPHQL_CUSTOM_FIELD_PREFIX="")
192
193
  def test_extend_custom_field_wo_prefix(self):
193
-
194
194
  schema = extend_schema_type_custom_field(self.schema, Location)
195
195
 
196
196
  for data in self.datas:
@@ -199,7 +199,6 @@ class GraphQLExtendSchemaType(TestCase):
199
199
 
200
200
  @override_settings(GRAPHQL_CUSTOM_FIELD_PREFIX=None)
201
201
  def test_extend_custom_field_prefix_none(self):
202
-
203
202
  schema = extend_schema_type_custom_field(self.schema, Location)
204
203
 
205
204
  for data in self.datas:
@@ -207,19 +206,16 @@ class GraphQLExtendSchemaType(TestCase):
207
206
  self.assertIn(field_name, schema._meta.fields.keys())
208
207
 
209
208
  def test_extend_tags_enabled(self):
210
-
211
209
  schema = extend_schema_type_tags(self.schema, Location)
212
210
 
213
211
  self.assertTrue(hasattr(schema, "resolve_tags"))
214
212
  self.assertIsInstance(getattr(schema, "resolve_tags"), types.FunctionType)
215
213
 
216
214
  def test_extend_config_context(self):
217
-
218
215
  schema = extend_schema_type_config_context(DeviceTypeGraphQL, Device)
219
216
  self.assertIn("config_context", schema._meta.fields.keys())
220
217
 
221
218
  def test_extend_schema_device(self):
222
-
223
219
  # The below *will* log an error as DeviceTypeGraphQL has already been extended automatically...?
224
220
  schema = extend_schema_type(DeviceTypeGraphQL)
225
221
  self.assertIn("config_context", schema._meta.fields.keys())
@@ -227,14 +223,12 @@ class GraphQLExtendSchemaType(TestCase):
227
223
  self.assertIsInstance(getattr(schema, "resolve_tags"), types.FunctionType)
228
224
 
229
225
  def test_extend_schema_location(self):
230
-
231
226
  schema = extend_schema_type(self.schema)
232
227
  self.assertNotIn("config_context", schema._meta.fields.keys())
233
228
  self.assertTrue(hasattr(schema, "resolve_tags"))
234
229
  self.assertIsInstance(getattr(schema, "resolve_tags"), types.FunctionType)
235
230
 
236
231
  def test_extend_schema_null_field_choices(self):
237
-
238
232
  schema = extend_schema_type_null_field_choice(self.schema, Interface)
239
233
 
240
234
  self.assertTrue(hasattr(schema, "resolve_mode"))
@@ -243,14 +237,13 @@ class GraphQLExtendSchemaType(TestCase):
243
237
 
244
238
  class GraphQLExtendSchemaRelationship(TestCase):
245
239
  def setUp(self):
246
-
247
240
  location_ct = ContentType.objects.get_for_model(Location)
248
241
  rack_ct = ContentType.objects.get_for_model(Rack)
249
242
  vlan_ct = ContentType.objects.get_for_model(VLAN)
250
243
 
251
244
  self.m2m_1 = Relationship(
252
- name="Vlan to Rack",
253
- slug="vlan-rack",
245
+ label="Vlan to Rack",
246
+ key="vlan_rack",
254
247
  source_type=rack_ct,
255
248
  source_label="My Vlans",
256
249
  destination_type=vlan_ct,
@@ -260,8 +253,8 @@ class GraphQLExtendSchemaRelationship(TestCase):
260
253
  self.m2m_1.validated_save()
261
254
 
262
255
  self.m2m_2 = Relationship(
263
- name="Another Vlan to Rack",
264
- slug="vlan-rack-2",
256
+ label="Another Vlan to Rack",
257
+ key="vlan_rack_2",
265
258
  source_type=rack_ct,
266
259
  destination_type=vlan_ct,
267
260
  type="many-to-many",
@@ -269,8 +262,8 @@ class GraphQLExtendSchemaRelationship(TestCase):
269
262
  self.m2m_2.validated_save()
270
263
 
271
264
  self.o2m_1 = Relationship(
272
- name="generic location to vlan",
273
- slug="location-vlan",
265
+ label="generic location to vlan",
266
+ key="location_vlan",
274
267
  source_type=location_ct,
275
268
  destination_type=vlan_ct,
276
269
  type="one-to-many",
@@ -278,8 +271,8 @@ class GraphQLExtendSchemaRelationship(TestCase):
278
271
  self.o2m_1.validated_save()
279
272
 
280
273
  self.o2o_1 = Relationship(
281
- name="Primary Rack per Location",
282
- slug="primary-rack-location",
274
+ label="Primary Rack per Location",
275
+ key="primary_rack_location",
283
276
  source_type=rack_ct,
284
277
  source_hidden=True,
285
278
  destination_type=location_ct,
@@ -289,8 +282,8 @@ class GraphQLExtendSchemaRelationship(TestCase):
289
282
  self.o2o_1.validated_save()
290
283
 
291
284
  self.o2os_1 = Relationship(
292
- name="Redundant Location",
293
- slug="redundant-location",
285
+ label="Redundant Location",
286
+ key="redundant_location",
294
287
  source_type=location_ct,
295
288
  destination_type=location_ct,
296
289
  type="symmetric-one-to-one",
@@ -298,8 +291,8 @@ class GraphQLExtendSchemaRelationship(TestCase):
298
291
  self.o2os_1.validated_save()
299
292
 
300
293
  self.o2m_same_type_1 = Relationship(
301
- name="Some sort of location hierarchy?",
302
- slug="location-hierarchy",
294
+ label="Some sort of location hierarchy?",
295
+ key="location_hierarchy",
303
296
  source_type=location_ct,
304
297
  destination_type=location_ct,
305
298
  type="one-to-many",
@@ -319,7 +312,7 @@ class GraphQLExtendSchemaRelationship(TestCase):
319
312
  (self.m2m_2, "source"),
320
313
  (self.o2m_1, "source"),
321
314
  ]:
322
- field_name = f"rel_{str_to_var_name(rel.slug)}"
315
+ field_name = f"rel_{str_to_var_name(rel.key)}"
323
316
  self.assertIn(field_name, schema._meta.fields.keys())
324
317
  self.assertIsInstance(schema._meta.fields[field_name], graphene.types.field.Field)
325
318
  if rel.has_many(peer_side):
@@ -329,7 +322,7 @@ class GraphQLExtendSchemaRelationship(TestCase):
329
322
 
330
323
  # Relationships not on VLAN
331
324
  for rel in [self.o2o_1, self.o2os_1]:
332
- field_name = f"rel_{str_to_var_name(rel.slug)}"
325
+ field_name = f"rel_{str_to_var_name(rel.key)}"
333
326
  self.assertNotIn(field_name, schema._meta.fields.keys())
334
327
 
335
328
  @override_settings(GRAPHQL_RELATIONSHIP_PREFIX="pr")
@@ -343,7 +336,7 @@ class GraphQLExtendSchemaRelationship(TestCase):
343
336
  (self.o2o_1, "source"),
344
337
  (self.o2os_1, "peer"),
345
338
  ]:
346
- field_name = f"pr_{str_to_var_name(rel.slug)}"
339
+ field_name = f"pr_{str_to_var_name(rel.key)}"
347
340
  self.assertIn(field_name, schema._meta.fields.keys())
348
341
  self.assertIsInstance(schema._meta.fields[field_name], graphene.types.field.Field)
349
342
  if rel.has_many(peer_side):
@@ -354,7 +347,7 @@ class GraphQLExtendSchemaRelationship(TestCase):
354
347
  # Special handling of same-type non-symmetric relationships
355
348
  for rel in [self.o2m_same_type_1]:
356
349
  for peer_side in ["source", "destination"]:
357
- field_name = f"pr_{str_to_var_name(rel.slug)}_{peer_side}"
350
+ field_name = f"pr_{str_to_var_name(rel.key)}_{peer_side}"
358
351
  self.assertIn(field_name, schema._meta.fields.keys())
359
352
  self.assertIsInstance(schema._meta.fields[field_name], graphene.types.field.Field)
360
353
  if rel.has_many(peer_side):
@@ -364,17 +357,15 @@ class GraphQLExtendSchemaRelationship(TestCase):
364
357
 
365
358
  # Relationships not on Location
366
359
  for rel in [self.m2m_1, self.m2m_2]:
367
- field_name = f"pr_{str_to_var_name(rel.slug)}"
360
+ field_name = f"pr_{str_to_var_name(rel.key)}"
368
361
  self.assertNotIn(field_name, schema._meta.fields.keys())
369
362
 
370
363
 
371
364
  class GraphQLSearchParameters(TestCase):
372
365
  def setUp(self):
373
-
374
366
  self.schema = generate_schema_type(app_name="dcim", model=Location)
375
367
 
376
368
  def test_search_parameters(self):
377
-
378
369
  fields = LocationFilterSet().filters.keys()
379
370
  params = generate_list_search_parameters(self.schema)
380
371
  exclude_filters = ["type"]
@@ -390,37 +381,43 @@ class GraphQLSearchParameters(TestCase):
390
381
  class GraphQLAPIPermissionTest(TestCase):
391
382
  client_class = NautobotTestClient
392
383
 
393
- def setUp(self):
384
+ @classmethod
385
+ def setUpTestData(cls):
394
386
  """Initialize the Database with some datas and multiple users associated with different permissions."""
395
- self.groups = (
387
+ cls.groups = (
396
388
  Group.objects.create(name="Group 1"),
397
389
  Group.objects.create(name="Group 2"),
398
390
  )
399
391
 
400
- self.users = (
392
+ cls.users = (
401
393
  User.objects.create(username="User 1", is_active=True),
402
394
  User.objects.create(username="User 2", is_active=True),
403
395
  User.objects.create(username="Super User", is_active=True, is_superuser=True),
404
396
  User.objects.create(username="Nobody", is_active=True),
405
397
  )
406
398
 
407
- self.tokens = (
408
- Token.objects.create(user=self.users[0], key="0123456789abcdef0123456789abcdef01234567"),
409
- Token.objects.create(user=self.users[1], key="abcd456789abcdef0123456789abcdef01234567"),
410
- Token.objects.create(user=self.users[2], key="efgh456789abcdef0123456789abcdef01234567"),
411
- Token.objects.create(user=self.users[3], key="ijkl456789abcdef0123456789abcdef01234567"),
399
+ cls.tokens = (
400
+ Token.objects.create(user=cls.users[0], key="0123456789abcdef0123456789abcdef01234567"),
401
+ Token.objects.create(user=cls.users[1], key="abcd456789abcdef0123456789abcdef01234567"),
402
+ Token.objects.create(user=cls.users[2], key="efgh456789abcdef0123456789abcdef01234567"),
403
+ Token.objects.create(user=cls.users[3], key="ijkl456789abcdef0123456789abcdef01234567"),
412
404
  )
413
405
 
414
- self.clients = [self.client_class(), self.client_class(), self.client_class(), self.client_class()]
415
- self.clients[0].credentials(HTTP_AUTHORIZATION=f"Token {self.tokens[0].key}")
416
- self.clients[1].credentials(HTTP_AUTHORIZATION=f"Token {self.tokens[1].key}")
417
- self.clients[2].credentials(HTTP_AUTHORIZATION=f"Token {self.tokens[2].key}")
418
- self.clients[3].credentials(HTTP_AUTHORIZATION=f"Token {self.tokens[3].key}")
406
+ cls.clients = [cls.client_class(), cls.client_class(), cls.client_class(), cls.client_class()]
407
+ cls.clients[0].credentials(HTTP_AUTHORIZATION=f"Token {cls.tokens[0].key}")
408
+ cls.clients[1].credentials(HTTP_AUTHORIZATION=f"Token {cls.tokens[1].key}")
409
+ cls.clients[2].credentials(HTTP_AUTHORIZATION=f"Token {cls.tokens[2].key}")
410
+ cls.clients[3].credentials(HTTP_AUTHORIZATION=f"Token {cls.tokens[3].key}")
419
411
 
420
- self.location_type = LocationType.objects.get(name="Campus")
421
- self.locations = (
422
- Location.objects.create(name="Location 1", slug="test1", location_type=self.location_type),
423
- Location.objects.create(name="Location 2", slug="test2", location_type=self.location_type),
412
+ cls.location_type = LocationType.objects.get(name="Campus")
413
+ location_status = Status.objects.get_for_model(Location).first()
414
+ cls.locations = (
415
+ Location.objects.create(
416
+ name="Location 1", slug="test1", location_type=cls.location_type, status=location_status
417
+ ),
418
+ Location.objects.create(
419
+ name="Location 2", slug="test2", location_type=cls.location_type, status=location_status
420
+ ),
424
421
  )
425
422
 
426
423
  location_object_type = ContentType.objects.get(app_label="dcim", model="location")
@@ -435,8 +432,8 @@ class GraphQLAPIPermissionTest(TestCase):
435
432
  constraints={"location__slug": f"test{i+1}"},
436
433
  )
437
434
  rack_obj_permission.object_types.add(rack_object_type)
438
- rack_obj_permission.groups.add(self.groups[i])
439
- rack_obj_permission.users.add(self.users[i])
435
+ rack_obj_permission.groups.add(cls.groups[i])
436
+ rack_obj_permission.users.add(cls.users[i])
440
437
 
441
438
  location_obj_permission = ObjectPermission.objects.create(
442
439
  name=f"Permission Location {i+1}",
@@ -444,21 +441,22 @@ class GraphQLAPIPermissionTest(TestCase):
444
441
  constraints={"slug": f"test{i+1}"},
445
442
  )
446
443
  location_obj_permission.object_types.add(location_object_type)
447
- location_obj_permission.groups.add(self.groups[i])
448
- location_obj_permission.users.add(self.users[i])
444
+ location_obj_permission.groups.add(cls.groups[i])
445
+ location_obj_permission.users.add(cls.users[i])
449
446
 
450
- self.rack_grp1 = (
451
- Rack.objects.create(name="Rack 1-1", location=self.locations[0]),
452
- Rack.objects.create(name="Rack 1-2", location=self.locations[0]),
447
+ rack_status = Status.objects.get_for_model(Rack).first()
448
+ cls.rack_grp1 = (
449
+ Rack.objects.create(name="Rack 1-1", location=cls.locations[0], status=rack_status),
450
+ Rack.objects.create(name="Rack 1-2", location=cls.locations[0], status=rack_status),
453
451
  )
454
- self.rack_grp2 = (
455
- Rack.objects.create(name="Rack 2-1", location=self.locations[1]),
456
- Rack.objects.create(name="Rack 2-2", location=self.locations[1]),
452
+ cls.rack_grp2 = (
453
+ Rack.objects.create(name="Rack 2-1", location=cls.locations[1], status=rack_status),
454
+ Rack.objects.create(name="Rack 2-2", location=cls.locations[1], status=rack_status),
457
455
  )
458
456
 
459
- self.api_url = reverse("graphql-api")
457
+ cls.api_url = reverse("graphql-api")
460
458
 
461
- self.get_racks_query = """
459
+ cls.get_racks_query = """
462
460
  query {
463
461
  racks {
464
462
  name
@@ -466,7 +464,7 @@ class GraphQLAPIPermissionTest(TestCase):
466
464
  }
467
465
  """
468
466
 
469
- self.get_racks_params_query = """
467
+ cls.get_racks_params_query = """
470
468
  query {
471
469
  racks(location: "test1") {
472
470
  name
@@ -474,7 +472,7 @@ class GraphQLAPIPermissionTest(TestCase):
474
472
  }
475
473
  """
476
474
 
477
- self.get_racks_var_query = """
475
+ cls.get_racks_var_query = """
478
476
  query ($location: [String]) {
479
477
  racks(location: $location) {
480
478
  name
@@ -482,7 +480,7 @@ class GraphQLAPIPermissionTest(TestCase):
482
480
  }
483
481
  """
484
482
 
485
- self.get_locations_racks_query = """
483
+ cls.get_locations_racks_query = """
486
484
  query {
487
485
  locations {
488
486
  name
@@ -493,7 +491,7 @@ class GraphQLAPIPermissionTest(TestCase):
493
491
  }
494
492
  """
495
493
 
496
- self.get_rack_query = """
494
+ cls.get_rack_query = """
497
495
  query ($id: ID!) {
498
496
  rack (id: $id) {
499
497
  name
@@ -656,28 +654,31 @@ class GraphQLQueryTest(TestCase):
656
654
  cls.location2.status = cls.location_statuses[1]
657
655
  cls.location1.validated_save()
658
656
  cls.location2.validated_save()
659
- cls.rack1 = Rack.objects.create(name="Rack 1", location=cls.location1)
660
- cls.rack2 = Rack.objects.create(name="Rack 2", location=cls.location2)
661
- cls.tenant1 = Tenant.objects.create(name="Tenant 1", slug="tenant-1")
662
- cls.tenant2 = Tenant.objects.create(name="Tenant 2", slug="tenant-2")
657
+ rack_statuses = Status.objects.get_for_model(Rack)
658
+ cls.rack1 = Rack.objects.create(name="Rack 1", location=cls.location1, status=rack_statuses[0])
659
+ cls.rack2 = Rack.objects.create(name="Rack 2", location=cls.location2, status=rack_statuses[1])
660
+ cls.tenant1 = Tenant.objects.create(name="Tenant 1")
661
+ cls.tenant2 = Tenant.objects.create(name="Tenant 2")
663
662
 
664
- cls.vlan1 = VLAN.objects.create(name="VLAN 1", vid=100, location=cls.location1)
665
- cls.vlan2 = VLAN.objects.create(name="VLAN 2", vid=200, location=cls.location2)
663
+ vlan_statuses = Status.objects.get_for_model(VLAN)
664
+ cls.vlan1 = VLAN.objects.create(name="VLAN 1", vid=100, location=cls.location1, status=vlan_statuses[0])
665
+ cls.vlan2 = VLAN.objects.create(name="VLAN 2", vid=200, location=cls.location2, status=vlan_statuses[1])
666
666
 
667
667
  cls.location1_power_panels = [
668
668
  PowerPanel.objects.create(name="location1-powerpanel1", location=cls.location1),
669
669
  PowerPanel.objects.create(name="location1-powerpanel2", location=cls.location1),
670
670
  PowerPanel.objects.create(name="location1-powerpanel3", location=cls.location1),
671
671
  ]
672
+ powerfeed_status = Status.objects.get_for_model(PowerFeed).first()
672
673
  cls.location1_power_feeds = [
673
674
  PowerFeed.objects.create(
674
675
  name="location1-powerfeed1",
675
- status=Status.objects.get(name="Active"),
676
+ status=powerfeed_status,
676
677
  power_panel=cls.location1_power_panels[0],
677
678
  ),
678
679
  PowerFeed.objects.create(
679
680
  name="location1-powerfeed2",
680
- status=Status.objects.get(name="Active"),
681
+ status=powerfeed_status,
681
682
  power_panel=cls.location1_power_panels[1],
682
683
  ),
683
684
  ]
@@ -772,6 +773,7 @@ class GraphQLQueryTest(TestCase):
772
773
  ),
773
774
  ]
774
775
 
776
+ interface_status = Status.objects.get_for_model(Interface).first()
775
777
  cls.interface11 = Interface.objects.create(
776
778
  name="Int1",
777
779
  type=InterfaceTypeChoices.TYPE_VIRTUAL,
@@ -779,14 +781,23 @@ class GraphQLQueryTest(TestCase):
779
781
  mac_address="00:11:11:11:11:11",
780
782
  mode=InterfaceModeChoices.MODE_ACCESS,
781
783
  untagged_vlan=cls.vlan1,
784
+ status=interface_status,
782
785
  )
783
786
  cls.interface12 = Interface.objects.create(
784
787
  name="Int2",
785
788
  type=InterfaceTypeChoices.TYPE_VIRTUAL,
786
789
  device=cls.device1,
790
+ status=interface_status,
787
791
  )
788
792
  cls.ip_statuses = list(Status.objects.get_for_model(IPAddress))[:2]
789
- cls.ipaddr1 = IPAddress.objects.create(address="10.0.1.1/24", status=cls.ip_statuses[0])
793
+ cls.prefix_statuses = list(Status.objects.get_for_model(Prefix))[:2]
794
+ cls.namespace = Namespace.objects.first()
795
+ cls.prefix1 = Prefix.objects.create(
796
+ prefix="10.0.1.0/24", namespace=cls.namespace, status=cls.prefix_statuses[0]
797
+ )
798
+ cls.ipaddr1 = IPAddress.objects.create(
799
+ address="10.0.1.1/24", namespace=cls.namespace, status=cls.ip_statuses[0]
800
+ )
790
801
  cls.interface11.add_ip_addresses(cls.ipaddr1)
791
802
 
792
803
  cls.device2 = Device.objects.create(
@@ -806,11 +817,21 @@ class GraphQLQueryTest(TestCase):
806
817
  device=cls.device2,
807
818
  untagged_vlan=cls.vlan2,
808
819
  mode=InterfaceModeChoices.MODE_ACCESS,
820
+ status=interface_status,
809
821
  )
810
822
  cls.interface22 = Interface.objects.create(
811
- name="Int2", type=InterfaceTypeChoices.TYPE_1GE_FIXED, device=cls.device2, mac_address="00:12:12:12:12:12"
823
+ name="Int2",
824
+ type=InterfaceTypeChoices.TYPE_1GE_FIXED,
825
+ device=cls.device2,
826
+ mac_address="00:12:12:12:12:12",
827
+ status=interface_status,
828
+ )
829
+ cls.prefix2 = Prefix.objects.create(
830
+ prefix="10.0.2.0/24", namespace=cls.namespace, status=cls.prefix_statuses[1]
831
+ )
832
+ cls.ipaddr2 = IPAddress.objects.create(
833
+ address="10.0.2.1/30", namespace=cls.namespace, status=cls.ip_statuses[1]
812
834
  )
813
- cls.ipaddr2 = IPAddress.objects.create(address="10.0.2.1/30", status=cls.ip_statuses[1])
814
835
  cls.interface12.add_ip_addresses(cls.ipaddr2)
815
836
 
816
837
  cls.device3 = Device.objects.create(
@@ -822,7 +843,7 @@ class GraphQLQueryTest(TestCase):
822
843
  )
823
844
 
824
845
  cls.interface31 = Interface.objects.create(
825
- name="Int1", type=InterfaceTypeChoices.TYPE_VIRTUAL, device=cls.device3
846
+ name="Int1", type=InterfaceTypeChoices.TYPE_VIRTUAL, device=cls.device3, status=interface_status
826
847
  )
827
848
  cls.interface31 = Interface.objects.create(
828
849
  name="Mgmt1",
@@ -830,58 +851,67 @@ class GraphQLQueryTest(TestCase):
830
851
  device=cls.device3,
831
852
  mgmt_only=True,
832
853
  enabled=False,
854
+ status=interface_status,
833
855
  )
834
856
 
857
+ cable_statuses = Status.objects.get_for_model(Cable)
835
858
  cls.cable1 = Cable.objects.create(
836
859
  termination_a=cls.interface11,
837
860
  termination_b=cls.interface12,
838
- status=Status.objects.get_for_model(Cable)[0],
861
+ status=cable_statuses[0],
839
862
  )
840
863
  cls.cable2 = Cable.objects.create(
841
864
  termination_a=cls.interface31,
842
865
  termination_b=cls.interface21,
843
- status=Status.objects.get_for_model(Cable)[1],
866
+ status=cable_statuses[1],
844
867
  )
845
868
 
846
869
  # Power Cables
847
870
  cls.cable3 = Cable.objects.create(
848
871
  termination_a=cls.device1_power_ports[0],
849
872
  termination_b=cls.upsdevice1_power_outlets[0],
850
- status=Status.objects.get(name="Active"),
873
+ status=cable_statuses[0],
851
874
  )
852
875
  cls.cable3 = Cable.objects.create(
853
876
  termination_a=cls.upsdevice1_power_ports[0],
854
877
  termination_b=cls.location1_power_feeds[0],
855
- status=Status.objects.get(name="Active"),
878
+ status=cable_statuses[0],
856
879
  )
857
880
 
858
881
  ConfigContext.objects.create(name="context 1", weight=101, data={"a": 123, "b": 456, "c": 777})
859
882
 
860
- Provider.objects.create(name="provider 1", slug="provider-1", asn=1)
861
- Provider.objects.create(name="provider 2", slug="provider-2", asn=4294967295)
883
+ Provider.objects.create(name="provider 1", asn=1)
884
+ Provider.objects.create(name="provider 2", asn=4294967295)
862
885
 
863
886
  webhook1 = Webhook.objects.create(name="webhook 1", type_delete=True, enabled=False)
864
887
  webhook1.content_types.add(ContentType.objects.get_for_model(Device))
865
888
  webhook2 = Webhook.objects.create(name="webhook 2", type_update=True, enabled=False)
866
889
  webhook2.content_types.add(ContentType.objects.get_for_model(Interface))
867
890
 
868
- clustertype = ClusterType.objects.create(name="Cluster Type 1", slug="cluster-type-1")
891
+ clustertype = ClusterTypeFactory.create()
869
892
  cluster = Cluster.objects.create(name="Cluster 1", cluster_type=clustertype)
870
893
  cls.virtualmachine = VirtualMachine.objects.create(
871
894
  name="Virtual Machine 1",
872
895
  cluster=cluster,
873
896
  status=Status.objects.get_for_model(VirtualMachine)[0],
874
897
  )
898
+ vmintf_status = Status.objects.get_for_model(VMInterface).first()
875
899
  cls.vminterface = VMInterface.objects.create(
876
900
  virtual_machine=cls.virtualmachine,
877
901
  name="eth0",
902
+ status=vmintf_status,
903
+ )
904
+ cls.vmprefix = Prefix.objects.create(
905
+ prefix="1.1.1.0/24", namespace=cls.namespace, status=cls.prefix_statuses[0]
906
+ )
907
+ cls.vmipaddr = IPAddress.objects.create(
908
+ address="1.1.1.1/32", namespace=cls.namespace, status=cls.ip_statuses[0]
878
909
  )
879
- cls.vmipaddr = IPAddress.objects.create(address="1.1.1.1/32", status=cls.ip_statuses[0])
880
910
  cls.vminterface.add_ip_addresses(cls.vmipaddr)
881
911
 
882
912
  cls.relationship_o2o_1 = Relationship(
883
- name="Device to VirtualMachine",
884
- slug="device-to-vm",
913
+ label="Device to VirtualMachine",
914
+ key="device_to_vm",
885
915
  source_type=ContentType.objects.get_for_model(Device),
886
916
  destination_type=ContentType.objects.get_for_model(VirtualMachine),
887
917
  type="one-to-one",
@@ -896,8 +926,8 @@ class GraphQLQueryTest(TestCase):
896
926
  cls.ro2o_assoc_1.validated_save()
897
927
 
898
928
  cls.relationship_m2ms_1 = Relationship(
899
- name="Device Group",
900
- slug="device-group",
929
+ label="Device Group",
930
+ key="device_group",
901
931
  source_type=ContentType.objects.get_for_model(Device),
902
932
  destination_type=ContentType.objects.get_for_model(Device),
903
933
  type="symmetric-many-to-many",
@@ -927,7 +957,6 @@ class GraphQLQueryTest(TestCase):
927
957
  cls.schema = graphene_settings.SCHEMA
928
958
 
929
959
  def execute_query(self, query, variables=None):
930
-
931
960
  document = self.backend.document_from_string(self.schema, query)
932
961
  if variables:
933
962
  return document.execute(context_value=self.request, variable_values=variables)
@@ -1004,7 +1033,6 @@ query {
1004
1033
 
1005
1034
  @override_settings(EXEMPT_VIEW_PERMISSIONS=["*"])
1006
1035
  def test_query_config_context_and_custom_field_data(self):
1007
-
1008
1036
  query = (
1009
1037
  # pylint: disable=consider-using-f-string
1010
1038
  """
@@ -1163,7 +1191,9 @@ query {
1163
1191
  # Assert GraphQL returned properties match those expected
1164
1192
  self.assertEqual(console_server_port_entry["connected_console_port"], connected_console_port)
1165
1193
 
1166
- @skip("Works in isolation, fails as part of the overall test suite due to issue #446")
1194
+ @skip(
1195
+ "Works in isolation, fails as part of the overall test suite due to issue #446, also something is broken with content types"
1196
+ )
1167
1197
  @override_settings(EXEMPT_VIEW_PERMISSIONS=["*"])
1168
1198
  def test_query_relationship_associations(self):
1169
1199
  """Test queries involving relationship associations."""
@@ -1200,7 +1230,6 @@ query {
1200
1230
 
1201
1231
  @override_settings(EXEMPT_VIEW_PERMISSIONS=["*"])
1202
1232
  def test_query_device_role_filter(self):
1203
-
1204
1233
  query = (
1205
1234
  # pylint: disable=consider-using-f-string
1206
1235
  """
@@ -1211,7 +1240,7 @@ query {
1211
1240
  }
1212
1241
  }
1213
1242
  """
1214
- % (self.device_role1.slug,)
1243
+ % (self.device_role1.name,)
1215
1244
  )
1216
1245
  result = self.execute_query(query)
1217
1246
 
@@ -1222,7 +1251,6 @@ query {
1222
1251
 
1223
1252
  @override_settings(EXEMPT_VIEW_PERMISSIONS=["*"])
1224
1253
  def test_query_with_bad_filter(self):
1225
-
1226
1254
  query = """
1227
1255
  query {
1228
1256
  devices(role: "EXPECT NO ENTRIES") {
@@ -1238,7 +1266,6 @@ query {
1238
1266
 
1239
1267
  @override_settings(EXEMPT_VIEW_PERMISSIONS=["*"])
1240
1268
  def test_query_locations_filter(self):
1241
-
1242
1269
  filters = (
1243
1270
  ('name: "Location-1"', 1),
1244
1271
  ('name: ["Location-1"]', 1),
@@ -1254,15 +1281,15 @@ query {
1254
1281
  (f'id: ["{self.location1.pk}"]', 1),
1255
1282
  (f'id: ["{self.location1.pk}", "{self.location2.pk}"]', 2),
1256
1283
  (
1257
- f'status: "{self.location_statuses[0].slug}"',
1284
+ f'status: "{self.location_statuses[0].name}"',
1258
1285
  Location.objects.filter(status=self.location_statuses[0]).count(),
1259
1286
  ),
1260
1287
  (
1261
- f'status: ["{self.location_statuses[1].slug}"]',
1288
+ f'status: ["{self.location_statuses[1].name}"]',
1262
1289
  Location.objects.filter(status=self.location_statuses[1]).count(),
1263
1290
  ),
1264
1291
  (
1265
- f'status: ["{self.location_statuses[0].slug}", "{self.location_statuses[1].slug}"]',
1292
+ f'status: ["{self.location_statuses[0].name}", "{self.location_statuses[1].name}"]',
1266
1293
  Location.objects.filter(status__in=self.location_statuses[:2]).count(),
1267
1294
  ),
1268
1295
  )
@@ -1276,7 +1303,6 @@ query {
1276
1303
 
1277
1304
  @override_settings(EXEMPT_VIEW_PERMISSIONS=["*"])
1278
1305
  def test_query_devices_filter(self):
1279
-
1280
1306
  filterset_class = DeviceFilterSet
1281
1307
  queryset = Device.objects.all()
1282
1308
 
@@ -1296,10 +1322,10 @@ query {
1296
1322
  f'id: "{self.device1.pk}"': _count({"id": [self.device1.pk]}),
1297
1323
  f'id: ["{self.device1.pk}"]': _count({"id": [self.device1.pk]}),
1298
1324
  f'id: ["{self.device1.pk}", "{self.device2.pk}"]': _count({"id": [self.device1.pk, self.device2.pk]}),
1299
- f'role: "{self.device_role1.slug}"': _count({"role": [self.device_role1.slug]}),
1300
- f'role: ["{self.device_role1.slug}"]': _count({"role": [self.device_role1.slug]}),
1301
- f'role: ["{self.device_role1.slug}", "{self.device_role2.slug}"]': _count(
1302
- {"role": [self.device_role1.slug, self.device_role2.slug]}
1325
+ f'role: "{self.device_role1.name}"': _count({"role": [self.device_role1.name]}),
1326
+ f'role: ["{self.device_role1.name}"]': _count({"role": [self.device_role1.name]}),
1327
+ f'role: ["{self.device_role1.name}", "{self.device_role2.name}"]': _count(
1328
+ {"role": [self.device_role1.name, self.device_role2.name]}
1303
1329
  ),
1304
1330
  f'location: "{self.location1.slug}"': _count({"location": [self.location1.slug]}),
1305
1331
  f'location: ["{self.location1.slug}"]': _count({"location": [self.location1.slug]}),
@@ -1308,10 +1334,10 @@ query {
1308
1334
  ),
1309
1335
  'face: "front"': _count({"face": ["front"]}),
1310
1336
  'face: "rear"': _count({"face": ["rear"]}),
1311
- f'status: "{self.device_statuses[0].slug}"': _count({"status": [self.device_statuses[0].slug]}),
1312
- f'status: ["{self.device_statuses[1].slug}"]': _count({"status": [self.device_statuses[1].slug]}),
1313
- f'status: ["{self.device_statuses[0].slug}", "{self.device_statuses[1].slug}"]': _count(
1314
- {"status": [self.device_statuses[0].slug, self.device_statuses[1].slug]}
1337
+ f'status: "{self.device_statuses[0].name}"': _count({"status": [self.device_statuses[0].name]}),
1338
+ f'status: ["{self.device_statuses[1].name}"]': _count({"status": [self.device_statuses[1].name]}),
1339
+ f'status: ["{self.device_statuses[0].name}", "{self.device_statuses[1].name}"]': _count(
1340
+ {"status": [self.device_statuses[0].name, self.device_statuses[1].name]}
1315
1341
  ),
1316
1342
  "is_full_depth: true": _count({"is_full_depth": True}),
1317
1343
  "is_full_depth: false": _count({"is_full_depth": False}),
@@ -1336,43 +1362,42 @@ query {
1336
1362
 
1337
1363
  @override_settings(EXEMPT_VIEW_PERMISSIONS=["*"])
1338
1364
  def test_query_ip_addresses_filter(self):
1339
-
1340
1365
  filters = (
1341
1366
  (
1342
1367
  'address: "10.0.1.1"',
1343
1368
  IPAddress.objects.filter(host="10.0.1.1").count(),
1344
1369
  ),
1345
1370
  (
1346
- "family: 4",
1347
- IPAddress.objects.ip_family(4).count(),
1371
+ 'ip_version: "4"', # TODO: should be int, GraphQL bug?
1372
+ IPAddress.objects.filter(ip_version=4).count(),
1348
1373
  ),
1349
1374
  (
1350
- f'status: "{self.ip_statuses[0].slug}"',
1375
+ f'status: "{self.ip_statuses[0].name}"',
1351
1376
  IPAddress.objects.filter(status=self.ip_statuses[0]).count(),
1352
1377
  ),
1353
1378
  (
1354
- f'status: ["{self.ip_statuses[1].slug}"]',
1379
+ f'status: ["{self.ip_statuses[1].name}"]',
1355
1380
  IPAddress.objects.filter(status=self.ip_statuses[1]).count(),
1356
1381
  ),
1357
1382
  (
1358
- f'status: ["{self.ip_statuses[0].slug}", "{self.ip_statuses[1].slug}"]',
1383
+ f'status: ["{self.ip_statuses[0].name}", "{self.ip_statuses[1].name}"]',
1359
1384
  IPAddress.objects.filter(status__in=[self.ip_statuses[0], self.ip_statuses[1]]).count(),
1360
1385
  ),
1361
1386
  (
1362
1387
  "mask_length: 24",
1363
- IPAddress.objects.filter(prefix_length=24).count(),
1388
+ IPAddress.objects.filter(mask_length=24).count(),
1364
1389
  ),
1365
1390
  (
1366
1391
  "mask_length: 30",
1367
- IPAddress.objects.filter(prefix_length=30).count(),
1392
+ IPAddress.objects.filter(mask_length=30).count(),
1368
1393
  ),
1369
1394
  (
1370
1395
  "mask_length: 32",
1371
- IPAddress.objects.filter(prefix_length=32).count(),
1396
+ IPAddress.objects.filter(mask_length=32).count(),
1372
1397
  ),
1373
1398
  (
1374
1399
  "mask_length: 28",
1375
- IPAddress.objects.filter(prefix_length=28).count(),
1400
+ IPAddress.objects.filter(mask_length=28).count(),
1376
1401
  ),
1377
1402
  (
1378
1403
  'parent: "10.0.0.0/16"',
@@ -1410,7 +1435,7 @@ query {
1410
1435
  virtual_machine { name }
1411
1436
  }
1412
1437
  }
1413
- family
1438
+ ip_version
1414
1439
  interface { name }
1415
1440
  vminterface { name }
1416
1441
  }
@@ -1423,7 +1448,7 @@ query {
1423
1448
  entry["address"], (str(self.ipaddr1.address), str(self.ipaddr2.address), str(self.vmipaddr.address))
1424
1449
  )
1425
1450
  self.assertIn("assigned_object", entry)
1426
- self.assertIn(entry["family"], (4, 6))
1451
+ self.assertIn(entry["ip_version"], (4, 6))
1427
1452
  if entry["address"] == str(self.vmipaddr.address):
1428
1453
  self.assertEqual(entry["assigned_object"]["name"], self.vminterface.name)
1429
1454
  self.assertEqual(entry["vminterface"]["name"], self.vminterface.name)
@@ -1441,7 +1466,6 @@ query {
1441
1466
 
1442
1467
  @override_settings(EXEMPT_VIEW_PERMISSIONS=["*"])
1443
1468
  def test_query_cables_filter(self):
1444
-
1445
1469
  filters = (
1446
1470
  (f'device_id: "{self.device1.id}"', 2),
1447
1471
  ('device: "Device 3"', 1),
@@ -1453,8 +1477,8 @@ query {
1453
1477
  (f'location: "{self.location2.slug}"', 1),
1454
1478
  (f'location: ["{self.location1.slug}", "{self.location2.slug}"]', 4),
1455
1479
  (f'tenant_id: "{self.tenant1.id}"', 3),
1456
- ('tenant: "tenant-2"', 1),
1457
- ('tenant: ["tenant-1", "tenant-2"]', 4),
1480
+ ('tenant: "Tenant 2"', 1),
1481
+ ('tenant: ["Tenant 1", "Tenant 2"]', 4),
1458
1482
  )
1459
1483
 
1460
1484
  for filterv, nbr_expected_results in filters:
@@ -1899,7 +1923,6 @@ query {
1899
1923
 
1900
1924
  @override_settings(EXEMPT_VIEW_PERMISSIONS=["*"])
1901
1925
  def test_query_interface_pagination(self):
1902
-
1903
1926
  query_pagination = """\
1904
1927
  query {
1905
1928
  interfaces(limit: 2, offset: 3) {