nautobot 2.0.0a3__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 (780) hide show
  1. nautobot/apps/api.py +6 -8
  2. nautobot/apps/forms.py +0 -2
  3. nautobot/apps/ui.py +0 -8
  4. nautobot/circuits/api/serializers.py +9 -117
  5. nautobot/circuits/api/urls.py +1 -1
  6. nautobot/circuits/api/views.py +0 -1
  7. nautobot/circuits/forms.py +0 -65
  8. nautobot/circuits/migrations/0014_related_name_changes.py +1 -1
  9. nautobot/circuits/migrations/0016_tagsfield.py +34 -0
  10. nautobot/circuits/migrations/0017_fixup_null_statuses.py +22 -0
  11. nautobot/circuits/migrations/0018_status_nonnullable.py +22 -0
  12. nautobot/circuits/models.py +3 -87
  13. nautobot/circuits/navigation.py +14 -69
  14. nautobot/circuits/signals.py +0 -2
  15. nautobot/circuits/tables.py +39 -1
  16. nautobot/circuits/tests/integration/test_relationships.py +9 -9
  17. nautobot/circuits/tests/test_api.py +4 -8
  18. nautobot/circuits/tests/test_filters.py +10 -4
  19. nautobot/circuits/tests/test_models.py +5 -1
  20. nautobot/circuits/tests/test_views.py +27 -5
  21. nautobot/circuits/views.py +18 -10
  22. nautobot/core/api/__init__.py +8 -2
  23. nautobot/core/api/fields.py +15 -6
  24. nautobot/core/api/filter_backends.py +3 -2
  25. nautobot/core/api/metadata.py +237 -30
  26. nautobot/core/api/mixins.py +94 -0
  27. nautobot/core/api/pagination.py +4 -0
  28. nautobot/core/api/parsers.py +154 -0
  29. nautobot/core/api/renderers.py +153 -2
  30. nautobot/core/api/schema.py +46 -2
  31. nautobot/core/api/serializers.py +377 -35
  32. nautobot/core/api/urls.py +11 -3
  33. nautobot/core/api/utils.py +174 -2
  34. nautobot/core/api/versioning.py +32 -10
  35. nautobot/core/api/views.py +266 -72
  36. nautobot/core/apps/__init__.py +138 -220
  37. nautobot/core/celery/__init__.py +112 -41
  38. nautobot/core/celery/backends.py +19 -12
  39. nautobot/core/celery/control.py +46 -0
  40. nautobot/core/celery/encoders.py +53 -0
  41. nautobot/core/celery/log.py +38 -0
  42. nautobot/core/celery/schedulers.py +23 -4
  43. nautobot/core/celery/task.py +1 -16
  44. nautobot/core/checks.py +0 -27
  45. nautobot/core/choices.py +0 -113
  46. nautobot/core/{cli.py → cli/__init__.py} +1 -1
  47. nautobot/core/cli/__main__.py +3 -0
  48. nautobot/core/constants.py +0 -24
  49. nautobot/core/context_processors.py +12 -0
  50. nautobot/core/filters.py +2 -2
  51. nautobot/core/forms/__init__.py +0 -4
  52. nautobot/core/forms/fields.py +38 -65
  53. nautobot/core/forms/forms.py +4 -1
  54. nautobot/core/forms/utils.py +0 -52
  55. nautobot/core/graphql/schema.py +4 -27
  56. nautobot/core/jobs/__init__.py +75 -0
  57. nautobot/core/management/commands/build_ui.py +255 -0
  58. nautobot/core/management/commands/generate_test_data.py +3 -2
  59. nautobot/core/management/commands/post_upgrade.py +24 -24
  60. nautobot/core/models/__init__.py +26 -1
  61. nautobot/core/models/fields.py +24 -5
  62. nautobot/core/models/generics.py +2 -42
  63. nautobot/core/models/managers.py +5 -0
  64. nautobot/core/models/name_color_content_types.py +0 -14
  65. nautobot/core/models/tree_queries.py +14 -4
  66. nautobot/core/models/utils.py +5 -6
  67. nautobot/core/models/validators.py +17 -8
  68. nautobot/core/releases.py +8 -10
  69. nautobot/core/settings.py +80 -42
  70. nautobot/core/tables.py +5 -5
  71. nautobot/core/tasks.py +4 -7
  72. nautobot/core/templates/base.html +1 -49
  73. nautobot/core/templates/base_django.html +49 -0
  74. nautobot/core/templates/base_react.html +55 -0
  75. nautobot/core/templates/buttons/export.html +6 -4
  76. nautobot/core/templates/generic/object_bulk_create.html +10 -21
  77. nautobot/core/templates/generic/object_list.html +3 -1
  78. nautobot/core/templates/generic/object_retrieve_plugin_full_width.html +3 -0
  79. nautobot/core/templates/inc/footer.html +1 -0
  80. nautobot/core/templates/inc/javascript.html +0 -14
  81. nautobot/core/templates/inc/nav_menu.html +28 -33
  82. nautobot/core/templates/inc/object_details_advanced_panel.html +13 -0
  83. nautobot/core/templates/inc/relationships_table_rows.html +2 -2
  84. nautobot/core/templates/nautobot_config.py.j2 +8 -20
  85. nautobot/core/templates/plugin_template/__init__.py-tpl +1 -2
  86. nautobot/core/templates/rest_framework/api.html +8 -0
  87. nautobot/core/templatetags/buttons.py +32 -28
  88. nautobot/core/testing/__init__.py +47 -44
  89. nautobot/core/testing/api.py +362 -47
  90. nautobot/core/testing/filters.py +1 -1
  91. nautobot/core/testing/migrations.py +2 -0
  92. nautobot/core/testing/mixins.py +22 -9
  93. nautobot/core/testing/schema.py +2 -1
  94. nautobot/core/testing/views.py +21 -46
  95. nautobot/core/tests/integration/test_filters.py +17 -8
  96. nautobot/core/tests/integration/test_navbar.py +11 -34
  97. nautobot/core/tests/integration/test_plugin_navbar.py +9 -103
  98. nautobot/core/tests/nautobot_config.py +2 -3
  99. nautobot/core/tests/test_api.py +290 -21
  100. nautobot/core/tests/test_checks.py +0 -7
  101. nautobot/core/tests/test_filters.py +107 -59
  102. nautobot/core/tests/test_forms.py +26 -92
  103. nautobot/core/tests/test_graphql.py +110 -77
  104. nautobot/core/tests/test_logging.py +4 -0
  105. nautobot/core/tests/test_managers.py +3 -1
  106. nautobot/core/tests/test_models.py +2 -0
  107. nautobot/core/tests/test_paginator.py +3 -1
  108. nautobot/core/tests/test_releases.py +12 -12
  109. nautobot/core/tests/test_templatetags_helpers.py +4 -4
  110. nautobot/core/tests/test_utils.py +32 -68
  111. nautobot/core/tests/test_views.py +12 -15
  112. nautobot/core/utils/data.py +17 -0
  113. nautobot/core/utils/deprecation.py +9 -6
  114. nautobot/core/utils/filtering.py +8 -3
  115. nautobot/core/utils/git.py +12 -4
  116. nautobot/core/utils/lookup.py +3 -1
  117. nautobot/core/utils/requests.py +1 -104
  118. nautobot/core/views/__init__.py +1 -0
  119. nautobot/core/views/generic.py +75 -110
  120. nautobot/core/views/mixins.py +52 -61
  121. nautobot/core/views/renderers.py +6 -7
  122. nautobot/core/views/utils.py +80 -0
  123. nautobot/dcim/api/serializers.py +160 -667
  124. nautobot/dcim/api/urls.py +1 -1
  125. nautobot/dcim/api/views.py +7 -44
  126. nautobot/dcim/choices.py +2 -0
  127. nautobot/dcim/filters/__init__.py +21 -0
  128. nautobot/dcim/form_mixins.py +1 -27
  129. nautobot/dcim/forms.py +19 -765
  130. nautobot/dcim/migrations/0024_alter_device_and_rack_role_add_new_role.py +2 -1
  131. nautobot/dcim/migrations/0025_device_and_rack_roles_data_migrations.py +19 -13
  132. nautobot/dcim/migrations/0027_remove_device_role_and_rack_role.py +1 -1
  133. nautobot/dcim/migrations/0028_rename_foreignkey_fields.py +1 -1
  134. nautobot/dcim/migrations/0030_migrate_region_and_site_data_to_locations.py +2 -2
  135. nautobot/dcim/migrations/0035_related_name_changes.py +1 -1
  136. nautobot/dcim/migrations/0036_remove_region_and_site.py +1 -1
  137. nautobot/dcim/migrations/0040_tagsfield.py +109 -0
  138. nautobot/dcim/migrations/{0040_ipam__namespaces.py → 0041_ipam__namespaces.py} +1 -1
  139. nautobot/dcim/migrations/0042_fixup_null_statuses.py +51 -0
  140. nautobot/dcim/migrations/0043_status_nonnullable.py +72 -0
  141. nautobot/dcim/models/cables.py +3 -33
  142. nautobot/dcim/models/device_component_templates.py +6 -0
  143. nautobot/dcim/models/device_components.py +12 -198
  144. nautobot/dcim/models/devices.py +30 -143
  145. nautobot/dcim/models/locations.py +3 -64
  146. nautobot/dcim/models/power.py +3 -50
  147. nautobot/dcim/models/racks.py +7 -84
  148. nautobot/dcim/navigation.py +141 -467
  149. nautobot/dcim/signals.py +0 -2
  150. nautobot/dcim/tables/locations.py +2 -2
  151. nautobot/dcim/tables/power.py +1 -2
  152. nautobot/dcim/templates/dcim/console_port_connection_list.html +7 -0
  153. nautobot/dcim/templates/dcim/devicetype.html +2 -2
  154. nautobot/dcim/templates/dcim/interface_connection_list.html +7 -0
  155. nautobot/dcim/templates/dcim/location.html +16 -1
  156. nautobot/dcim/templates/dcim/locationtype.html +15 -0
  157. nautobot/dcim/templates/dcim/power_port_connection_list.html +7 -0
  158. nautobot/dcim/templates/dcim/rackgroup.html +0 -12
  159. nautobot/dcim/tests/test_api.py +166 -81
  160. nautobot/dcim/tests/test_cablepaths.py +41 -35
  161. nautobot/dcim/tests/test_filters.py +67 -23
  162. nautobot/dcim/tests/test_forms.py +5 -205
  163. nautobot/dcim/tests/test_graphql.py +7 -2
  164. nautobot/dcim/tests/test_migrations.py +6 -11
  165. nautobot/dcim/tests/test_models.py +182 -110
  166. nautobot/dcim/tests/test_natural_ordering.py +11 -8
  167. nautobot/dcim/tests/test_signals.py +6 -3
  168. nautobot/dcim/tests/test_views.py +197 -175
  169. nautobot/dcim/urls.py +11 -16
  170. nautobot/dcim/views.py +7 -134
  171. nautobot/docs/additional-features/caching.md +6 -87
  172. nautobot/docs/additional-features/job-scheduling-and-approvals.md +3 -0
  173. nautobot/docs/additional-features/jobs.md +177 -195
  174. nautobot/docs/administration/nautobot-server.md +6 -21
  175. nautobot/docs/administration/replicating-nautobot.md +0 -10
  176. nautobot/docs/configuration/optional-settings.md +32 -41
  177. nautobot/docs/configuration/required-settings.md +11 -52
  178. nautobot/docs/development/application-registry.md +2 -13
  179. nautobot/docs/development/extending-models.md +15 -17
  180. nautobot/docs/development/generic-views.md +0 -2
  181. nautobot/docs/development/getting-started.md +55 -5
  182. nautobot/docs/development/navigation-menu.md +22 -93
  183. nautobot/docs/development/react-ui.md +105 -0
  184. nautobot/docs/development/role-internals.md +1 -3
  185. nautobot/docs/development/style-guide.md +6 -4
  186. nautobot/docs/index.md +3 -2
  187. nautobot/docs/installation/migrating-from-netbox.md +11 -42
  188. nautobot/docs/installation/nautobot.md +1 -1
  189. nautobot/docs/installation/tables/v2-api-behavior-changes.yaml +70 -0
  190. nautobot/docs/installation/tables/v2-api-removed-fields.yaml +142 -0
  191. nautobot/docs/installation/tables/v2-api-renamed-fields.yaml +124 -0
  192. nautobot/docs/installation/tables/v2-code-location-changes.yaml +241 -0
  193. nautobot/docs/installation/tables/v2-code-removals.yaml +67 -0
  194. nautobot/docs/installation/tables/v2-database-behavior-changes.yaml +37 -0
  195. nautobot/docs/installation/tables/v2-database-removed-fields.yaml +166 -0
  196. nautobot/docs/installation/tables/v2-database-renamed-fields.yaml +340 -0
  197. nautobot/docs/installation/tables/v2-filters-corrected-fields.yaml +28 -0
  198. nautobot/docs/installation/tables/v2-filters-enhanced-fields.yaml +241 -0
  199. nautobot/docs/installation/tables/v2-filters-removed-fields.yaml +553 -0
  200. nautobot/docs/installation/tables/v2-filters-renamed-fields.yaml +223 -0
  201. nautobot/docs/installation/tables/v2-logging-renamed-loggers.yaml +23 -0
  202. nautobot/docs/installation/upgrading-from-nautobot-v1.md +170 -747
  203. nautobot/docs/models/dcim/device.md +3 -0
  204. nautobot/docs/models/dcim/deviceredundancygroup.md +3 -3
  205. nautobot/docs/models/extras/computedfield.md +4 -4
  206. nautobot/docs/models/extras/gitrepository.md +3 -0
  207. nautobot/docs/models/extras/job.md +1 -0
  208. nautobot/docs/models/extras/jobbutton.md +18 -13
  209. nautobot/docs/models/extras/jobhook.md +7 -4
  210. nautobot/docs/models/extras/jobresult.md +6 -2
  211. nautobot/docs/models/extras/relationship.md +2 -2
  212. nautobot/docs/models/extras/status.md +6 -19
  213. nautobot/docs/models/ipam/ipaddress.md +3 -0
  214. nautobot/docs/models/virtualization/virtualmachine.md +3 -0
  215. nautobot/docs/plugins/development.md +83 -21
  216. nautobot/docs/release-notes/version-1.5.md +53 -0
  217. nautobot/docs/release-notes/version-2.0.md +180 -0
  218. nautobot/docs/requirements.txt +1 -0
  219. nautobot/docs/rest-api/overview.md +384 -215
  220. nautobot/docs/rest-api/ui-related-endpoints.md +9 -0
  221. nautobot/extras/admin.py +3 -5
  222. nautobot/extras/api/customfields.py +15 -39
  223. nautobot/extras/api/fields.py +0 -11
  224. nautobot/extras/api/mixins.py +45 -0
  225. nautobot/extras/api/relationships.py +63 -158
  226. nautobot/extras/api/serializers.py +165 -700
  227. nautobot/extras/api/urls.py +1 -1
  228. nautobot/extras/api/views.py +294 -280
  229. nautobot/extras/apps.py +4 -7
  230. nautobot/extras/choices.py +11 -9
  231. nautobot/extras/constants.py +9 -3
  232. nautobot/extras/datasources/__init__.py +2 -0
  233. nautobot/extras/datasources/git.py +135 -186
  234. nautobot/extras/datasources/registry.py +25 -35
  235. nautobot/extras/filters/__init__.py +20 -19
  236. nautobot/extras/filters/mixins.py +4 -4
  237. nautobot/extras/forms/forms.py +63 -127
  238. nautobot/extras/forms/mixins.py +23 -51
  239. nautobot/extras/health_checks.py +0 -33
  240. nautobot/extras/jobs.py +387 -565
  241. nautobot/extras/management/commands/runjob.py +24 -62
  242. nautobot/extras/managers.py +30 -7
  243. nautobot/extras/migrations/0058_jobresult_add_time_status_idxs.py +38 -0
  244. nautobot/extras/migrations/{0058_joblogentry_scheduledjob_webhook_data_migration.py → 0059_joblogentry_scheduledjob_webhook_data_migration.py} +1 -1
  245. nautobot/extras/migrations/{0059_alter_joblogentry_scheduledjob_webhook_fields.py → 0060_alter_joblogentry_scheduledjob_webhook_fields.py} +1 -1
  246. nautobot/extras/migrations/{0060_role_and_alter_status.py → 0061_role_and_alter_status.py} +1 -7
  247. nautobot/extras/migrations/{0061_collect_roles_from_related_apps_roles.py → 0062_collect_roles_from_related_apps_roles.py} +33 -32
  248. nautobot/extras/migrations/{0062_alter_role_options.py → 0063_alter_role_options.py} +1 -1
  249. nautobot/extras/migrations/{0063_alter_configcontext_and_add_new_role.py → 0064_alter_configcontext_and_add_new_role.py} +1 -1
  250. nautobot/extras/migrations/0065_configcontext_data_migrations.py +44 -0
  251. nautobot/extras/migrations/{0065_rename_configcontext_role.py → 0066_rename_configcontext_role.py} +1 -1
  252. nautobot/extras/migrations/{0066_jobresult__add_celery_fields.py → 0067_jobresult__add_celery_fields.py} +36 -2
  253. nautobot/extras/migrations/{0067_created_datetime.py → 0068_created_datetime.py} +1 -1
  254. nautobot/extras/migrations/{0068_remove_site_and_region_attributes_from_config_context.py → 0069_remove_site_and_region_attributes_from_config_context.py} +1 -1
  255. nautobot/extras/migrations/{0069_replace_related_names.py → 0070_replace_related_names.py} +1 -1
  256. nautobot/extras/migrations/{0070_rename_model_fields.py → 0071_rename_model_fields.py} +1 -1
  257. nautobot/extras/migrations/0072_job__unique_name_data_migration.py +86 -0
  258. nautobot/extras/migrations/{0072_job__unique_name.py → 0073_job__unique_name.py} +13 -9
  259. nautobot/extras/migrations/{0073_remove_gitrepository_fields.py → 0074_remove_gitrepository_fields.py} +1 -1
  260. nautobot/extras/migrations/{0074_rename_slug_to_key_for_custom_field.py → 0075_rename_slug_to_key_for_custom_field.py} +1 -1
  261. nautobot/extras/migrations/{0075_migrate_custom_field_data.py → 0076_migrate_custom_field_data.py} +1 -1
  262. 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
  263. nautobot/extras/migrations/{0077_remove_slug.py → 0078_remove_slug.py} +1 -5
  264. nautobot/extras/migrations/0079_tagsfield.py +28 -0
  265. nautobot/extras/migrations/0080_rename_relationship_slug_to_key.py +17 -0
  266. nautobot/extras/migrations/0081_rename_relationship_name_to_label.py +29 -0
  267. nautobot/extras/migrations/0082_ensure_relationship_keys_are_unique.py +43 -0
  268. nautobot/extras/migrations/0083_rename_computed_field_slug_to_key.py +21 -0
  269. nautobot/extras/migrations/0084_taggeditem_cleanup.py +43 -0
  270. nautobot/extras/migrations/0085_taggeditem_uniqueness.py +22 -0
  271. nautobot/extras/migrations/0086_job__celery_task_fields__dryrun_support.py +81 -0
  272. nautobot/extras/migrations/0087_job__commit_default_data_migration.py +26 -0
  273. nautobot/extras/migrations/0088_joblogentry__log_level_default.py +17 -0
  274. nautobot/extras/migrations/0089_joblogentry__log_level_data_migration.py +34 -0
  275. nautobot/extras/migrations/0090_scheduledjob__data_migration.py +57 -0
  276. nautobot/extras/models/__init__.py +2 -3
  277. nautobot/extras/models/change_logging.py +0 -36
  278. nautobot/extras/models/customfields.py +39 -33
  279. nautobot/extras/models/datasources.py +48 -50
  280. nautobot/extras/models/groups.py +5 -6
  281. nautobot/extras/models/jobs.py +189 -321
  282. nautobot/extras/models/mixins.py +0 -71
  283. nautobot/extras/models/models.py +0 -19
  284. nautobot/extras/models/relationships.py +19 -13
  285. nautobot/extras/models/roles.py +0 -34
  286. nautobot/extras/models/secrets.py +2 -26
  287. nautobot/extras/models/statuses.py +6 -5
  288. nautobot/extras/models/tags.py +2 -17
  289. nautobot/extras/navigation.py +89 -307
  290. nautobot/extras/plugins/__init__.py +3 -120
  291. nautobot/extras/plugins/utils.py +0 -3
  292. nautobot/extras/plugins/validators.py +5 -4
  293. nautobot/extras/plugins/views.py +16 -3
  294. nautobot/extras/querysets.py +1 -7
  295. nautobot/extras/registry.py +3 -0
  296. nautobot/extras/signals.py +26 -60
  297. nautobot/extras/tables.py +34 -40
  298. nautobot/extras/tasks.py +0 -12
  299. nautobot/extras/templates/extras/configcontext.html +1 -1
  300. nautobot/extras/templates/extras/configcontextschema.html +16 -1
  301. nautobot/extras/templates/extras/customfield.html +0 -13
  302. nautobot/extras/templates/extras/gitrepository.html +3 -3
  303. nautobot/extras/templates/extras/inc/jobresult.html +10 -0
  304. nautobot/extras/templates/extras/inc/panel_jobhistory.html +1 -1
  305. nautobot/extras/templates/extras/job.html +35 -25
  306. nautobot/extras/templates/extras/job_approval_request.html +15 -30
  307. nautobot/extras/templates/extras/job_detail.html +13 -31
  308. nautobot/extras/templates/extras/job_edit.html +15 -17
  309. nautobot/extras/templates/extras/jobresult.html +24 -6
  310. nautobot/extras/templates/extras/scheduledjob.html +2 -2
  311. nautobot/extras/templates/extras/secret.html +28 -0
  312. nautobot/extras/templatetags/job_buttons.py +1 -0
  313. nautobot/extras/{tests/example_jobs → test_jobs}/api_test_job.py +13 -6
  314. nautobot/extras/test_jobs/atomic_transaction.py +53 -0
  315. nautobot/extras/test_jobs/dry_run.py +29 -0
  316. nautobot/extras/{tests/example_jobs/test_duplicate_name.py → test_jobs/duplicate_name.py} +4 -0
  317. nautobot/extras/test_jobs/duplicate_name2.py +9 -0
  318. nautobot/extras/test_jobs/fail.py +23 -0
  319. nautobot/extras/{tests/example_jobs/test_field_default.py → test_jobs/field_default.py} +4 -0
  320. nautobot/extras/{tests/example_jobs/test_field_order.py → test_jobs/field_order.py} +4 -0
  321. nautobot/extras/{tests/example_jobs/test_file_upload_fail.py → test_jobs/file_upload_fail.py} +11 -6
  322. nautobot/extras/test_jobs/file_upload_pass.py +25 -0
  323. nautobot/extras/test_jobs/has_sensitive_variables.py +25 -0
  324. nautobot/extras/test_jobs/ipaddress_vars.py +66 -0
  325. nautobot/extras/test_jobs/job_button_receiver.py +28 -0
  326. nautobot/extras/test_jobs/job_hook_receiver.py +29 -0
  327. nautobot/extras/test_jobs/job_variables.py +88 -0
  328. nautobot/extras/test_jobs/location_with_custom_field.py +45 -0
  329. nautobot/extras/test_jobs/log_redaction.py +20 -0
  330. nautobot/extras/test_jobs/log_skip_db_logging.py +17 -0
  331. nautobot/extras/test_jobs/modify_db.py +25 -0
  332. nautobot/extras/{tests/example_jobs/test_no_field_order.py → test_jobs/no_field_order.py} +4 -0
  333. nautobot/extras/test_jobs/object_var_optional.py +21 -0
  334. nautobot/extras/test_jobs/object_var_required.py +21 -0
  335. nautobot/extras/test_jobs/object_vars.py +26 -0
  336. nautobot/extras/test_jobs/pass.py +25 -0
  337. nautobot/extras/test_jobs/profiling.py +32 -0
  338. nautobot/extras/test_jobs/read_only_job.py +15 -0
  339. nautobot/extras/{tests/example_jobs/test_required_args.py → test_jobs/required_args.py} +4 -0
  340. 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
  341. nautobot/extras/{tests/example_jobs/test_task_queues.py → test_jobs/task_queues.py} +5 -1
  342. nautobot/extras/tests/integration/test_computedfields.py +1 -1
  343. nautobot/extras/tests/integration/test_configcontextschema.py +5 -3
  344. nautobot/extras/tests/integration/test_customfields.py +4 -2
  345. nautobot/extras/tests/integration/test_dynamicgroups.py +1 -1
  346. nautobot/extras/tests/integration/test_jobs.py +25 -27
  347. nautobot/extras/tests/integration/test_notes.py +8 -4
  348. nautobot/extras/tests/integration/test_relationships.py +2 -2
  349. nautobot/extras/tests/test_api.py +649 -642
  350. nautobot/extras/tests/test_changelog.py +3 -3
  351. nautobot/extras/tests/test_context_managers.py +5 -3
  352. nautobot/extras/tests/test_customfields.py +92 -50
  353. nautobot/extras/tests/test_datasources.py +189 -112
  354. nautobot/extras/tests/test_dynamicgroups.py +7 -8
  355. nautobot/extras/tests/test_filters.py +137 -89
  356. nautobot/extras/tests/test_forms.py +73 -75
  357. nautobot/extras/tests/{test_scripts.py → test_job_variables.py} +43 -49
  358. nautobot/extras/tests/test_jobs.py +262 -263
  359. nautobot/extras/tests/test_migrations.py +4 -3
  360. nautobot/extras/tests/test_models.py +116 -161
  361. nautobot/extras/tests/test_plugins.py +38 -60
  362. nautobot/extras/tests/test_relationships.py +167 -120
  363. nautobot/extras/tests/test_tags.py +6 -11
  364. nautobot/extras/tests/test_utils.py +31 -1
  365. nautobot/extras/tests/test_views.py +201 -145
  366. nautobot/extras/tests/test_webhooks.py +6 -2
  367. nautobot/extras/urls.py +42 -42
  368. nautobot/extras/utils.py +137 -163
  369. nautobot/extras/views.py +78 -152
  370. nautobot/ipam/api/fields.py +17 -0
  371. nautobot/ipam/api/serializers.py +58 -164
  372. nautobot/ipam/api/urls.py +1 -1
  373. nautobot/ipam/api/views.py +3 -2
  374. nautobot/ipam/apps.py +1 -2
  375. nautobot/ipam/filters.py +1 -10
  376. nautobot/ipam/forms.py +4 -177
  377. nautobot/ipam/lookups.py +1 -0
  378. nautobot/ipam/management/commands/__init__.py +0 -0
  379. nautobot/ipam/management/commands/fix_prefix_broadcast.py +17 -0
  380. nautobot/ipam/migrations/0010_alter_ipam_role_add_new_role.py +1 -1
  381. nautobot/ipam/migrations/0011_migrate_ipam_role_data.py +32 -38
  382. nautobot/ipam/migrations/0020_related_name_changes.py +1 -1
  383. nautobot/ipam/migrations/0022_aggregate_to_prefix_data_migration.py +2 -2
  384. nautobot/ipam/migrations/0028_tagsfield.py +44 -0
  385. nautobot/ipam/migrations/0029_ip_address_to_interface_uniqueness_constraints.py +18 -0
  386. nautobot/ipam/migrations/{0028_ipam__namespaces.py → 0030_ipam__namespaces.py} +77 -28
  387. nautobot/ipam/migrations/0031_ipam__prefix__add_parent.py +58 -0
  388. nautobot/ipam/migrations/0032_ipam__namespaces_finish.py +63 -0
  389. nautobot/ipam/migrations/0033_fixup_null_statuses.py +26 -0
  390. nautobot/ipam/migrations/0034_status_nonnullable.py +36 -0
  391. nautobot/ipam/models.py +100 -236
  392. nautobot/ipam/navigation.py +36 -181
  393. nautobot/ipam/querysets.py +20 -25
  394. nautobot/ipam/signals.py +49 -6
  395. nautobot/ipam/tables.py +10 -3
  396. nautobot/ipam/templates/ipam/namespace_ipaddresses.html +11 -0
  397. nautobot/ipam/templates/ipam/namespace_prefixes.html +11 -0
  398. nautobot/ipam/templates/ipam/namespace_retrieve.html +17 -4
  399. nautobot/ipam/templates/ipam/namespace_vrfs.html +11 -0
  400. nautobot/ipam/templates/ipam/prefix.html +1 -1
  401. nautobot/ipam/templates/ipam/vlangroup.html +0 -13
  402. nautobot/ipam/templates/ipam/vrf_edit.html +6 -0
  403. nautobot/ipam/tests/integration/test_prefixes.py +3 -26
  404. nautobot/ipam/tests/test_api.py +22 -19
  405. nautobot/ipam/tests/test_filters.py +59 -23
  406. nautobot/ipam/tests/test_migrations.py +6 -10
  407. nautobot/ipam/tests/test_models.py +323 -198
  408. nautobot/ipam/tests/test_ordering.py +2 -2
  409. nautobot/ipam/tests/test_querysets.py +44 -24
  410. nautobot/ipam/tests/test_views.py +73 -26
  411. nautobot/ipam/urls.py +16 -0
  412. nautobot/ipam/{utils.py → utils/__init__.py} +2 -2
  413. nautobot/ipam/utils/migrations.py +713 -0
  414. nautobot/ipam/views.py +137 -20
  415. nautobot/project-static/docs/404.html +1178 -10
  416. nautobot/project-static/docs/additional-features/caching.html +1224 -159
  417. nautobot/project-static/docs/additional-features/change-logging.html +1180 -12
  418. nautobot/project-static/docs/additional-features/config-contexts.html +1180 -12
  419. nautobot/project-static/docs/additional-features/graphql.html +1179 -11
  420. nautobot/project-static/docs/additional-features/healthcheck.html +1180 -12
  421. nautobot/project-static/docs/additional-features/job-scheduling-and-approvals.html +1184 -12
  422. nautobot/project-static/docs/additional-features/jobs.html +1514 -328
  423. nautobot/project-static/docs/additional-features/napalm.html +1180 -12
  424. nautobot/project-static/docs/additional-features/prometheus-metrics.html +1180 -12
  425. nautobot/project-static/docs/additional-features/template-filters.html +1180 -12
  426. nautobot/project-static/docs/administration/celery-queues.html +1178 -10
  427. nautobot/project-static/docs/administration/nautobot-server.html +1451 -304
  428. nautobot/project-static/docs/administration/nautobot-shell.html +1178 -10
  429. nautobot/project-static/docs/administration/permissions.html +1178 -10
  430. nautobot/project-static/docs/administration/replicating-nautobot.html +1262 -113
  431. nautobot/project-static/docs/apps/index.html +1178 -10
  432. nautobot/project-static/docs/apps/nautobot-apps.html +1178 -10
  433. nautobot/project-static/docs/code-reference/nautobot/apps/__init__.html +1580 -426
  434. nautobot/project-static/docs/code-reference/nautobot/apps/admin.html +1178 -10
  435. nautobot/project-static/docs/code-reference/nautobot/apps/api.html +3481 -1838
  436. nautobot/project-static/docs/code-reference/nautobot/apps/choices.html +1178 -10
  437. nautobot/project-static/docs/code-reference/nautobot/apps/config.html +1178 -10
  438. nautobot/project-static/docs/code-reference/nautobot/apps/datasources.html +1185 -11
  439. nautobot/project-static/docs/code-reference/nautobot/apps/filters.html +1719 -551
  440. nautobot/project-static/docs/code-reference/nautobot/apps/forms.html +2062 -930
  441. nautobot/project-static/docs/code-reference/nautobot/apps/models.html +1946 -659
  442. nautobot/project-static/docs/code-reference/nautobot/apps/secrets.html +1180 -12
  443. nautobot/project-static/docs/code-reference/nautobot/apps/tables.html +1189 -21
  444. nautobot/project-static/docs/code-reference/nautobot/apps/testing.html +9283 -6218
  445. nautobot/project-static/docs/code-reference/nautobot/apps/ui.html +2734 -2122
  446. nautobot/project-static/docs/code-reference/nautobot/apps/urls.html +1178 -10
  447. nautobot/project-static/docs/code-reference/nautobot/apps/views.html +2337 -1300
  448. nautobot/project-static/docs/configuration/authentication/ldap.html +1178 -10
  449. nautobot/project-static/docs/configuration/authentication/remote.html +1178 -10
  450. nautobot/project-static/docs/configuration/authentication/sso.html +1178 -10
  451. nautobot/project-static/docs/configuration/index.html +1178 -10
  452. nautobot/project-static/docs/configuration/optional-settings.html +1311 -160
  453. nautobot/project-static/docs/configuration/required-settings.html +1312 -211
  454. nautobot/project-static/docs/core-functionality/circuits.html +1178 -10
  455. nautobot/project-static/docs/core-functionality/device-types.html +1178 -10
  456. nautobot/project-static/docs/core-functionality/devices.html +1182 -10
  457. nautobot/project-static/docs/core-functionality/ipam.html +1182 -10
  458. nautobot/project-static/docs/core-functionality/power.html +1178 -10
  459. nautobot/project-static/docs/core-functionality/secrets.html +1178 -10
  460. nautobot/project-static/docs/core-functionality/services.html +1178 -10
  461. nautobot/project-static/docs/core-functionality/sites-and-racks.html +1178 -10
  462. nautobot/project-static/docs/core-functionality/tenancy.html +1178 -10
  463. nautobot/project-static/docs/core-functionality/virtualization.html +1182 -10
  464. nautobot/project-static/docs/core-functionality/vlans.html +1179 -11
  465. nautobot/project-static/docs/development/application-registry.html +1190 -42
  466. nautobot/project-static/docs/development/best-practices.html +1178 -10
  467. nautobot/project-static/docs/development/docker-compose-advanced-use-cases.html +1178 -10
  468. nautobot/project-static/docs/development/extending-models.html +1238 -83
  469. nautobot/project-static/docs/development/generic-views.html +1180 -14
  470. nautobot/project-static/docs/development/getting-started.html +1365 -90
  471. nautobot/project-static/docs/development/homepage.html +1178 -10
  472. nautobot/project-static/docs/development/index.html +1178 -10
  473. nautobot/project-static/docs/development/model-features.html +1178 -10
  474. nautobot/project-static/docs/development/natural-keys.html +1178 -10
  475. nautobot/project-static/docs/development/navigation-menu.html +1215 -125
  476. nautobot/project-static/docs/development/react-ui.html +4199 -0
  477. nautobot/project-static/docs/development/release-checklist.html +1178 -10
  478. nautobot/project-static/docs/development/role-internals.html +1179 -12
  479. nautobot/project-static/docs/development/style-guide.html +1188 -19
  480. nautobot/project-static/docs/development/templates.html +1178 -10
  481. nautobot/project-static/docs/development/testing.html +1178 -10
  482. nautobot/project-static/docs/development/user-preferences.html +1178 -10
  483. nautobot/project-static/docs/docker/index.html +1178 -10
  484. nautobot/project-static/docs/index.html +1183 -12
  485. nautobot/project-static/docs/installation/centos.html +1178 -10
  486. nautobot/project-static/docs/installation/external-authentication.html +1178 -10
  487. nautobot/project-static/docs/installation/http-server.html +1178 -10
  488. nautobot/project-static/docs/installation/index.html +1178 -10
  489. nautobot/project-static/docs/installation/migrating-from-netbox.html +1305 -189
  490. nautobot/project-static/docs/installation/migrating-from-postgresql.html +1178 -10
  491. nautobot/project-static/docs/installation/nautobot.html +1179 -11
  492. nautobot/project-static/docs/installation/region-and-site-data-migration-guide.html +1178 -10
  493. nautobot/project-static/docs/installation/selinux-troubleshooting.html +1178 -10
  494. nautobot/project-static/docs/installation/services.html +1178 -10
  495. nautobot/project-static/docs/installation/tables/v2-api-behavior-changes.yaml +70 -0
  496. nautobot/project-static/docs/installation/tables/v2-api-removed-fields.yaml +142 -0
  497. nautobot/project-static/docs/installation/tables/v2-api-renamed-fields.yaml +124 -0
  498. nautobot/project-static/docs/installation/tables/v2-code-location-changes.yaml +241 -0
  499. nautobot/project-static/docs/installation/tables/v2-code-removals.yaml +67 -0
  500. nautobot/project-static/docs/installation/tables/v2-database-behavior-changes.yaml +37 -0
  501. nautobot/project-static/docs/installation/tables/v2-database-removed-fields.yaml +166 -0
  502. nautobot/project-static/docs/installation/tables/v2-database-renamed-fields.yaml +340 -0
  503. nautobot/project-static/docs/installation/tables/v2-filters-corrected-fields.yaml +28 -0
  504. nautobot/project-static/docs/installation/tables/v2-filters-enhanced-fields.yaml +241 -0
  505. nautobot/project-static/docs/installation/tables/v2-filters-removed-fields.yaml +553 -0
  506. nautobot/project-static/docs/installation/tables/v2-filters-renamed-fields.yaml +223 -0
  507. nautobot/project-static/docs/installation/tables/v2-logging-renamed-loggers.yaml +23 -0
  508. nautobot/project-static/docs/installation/ubuntu.html +1178 -10
  509. nautobot/project-static/docs/installation/upgrading-from-nautobot-v1.html +3823 -2152
  510. nautobot/project-static/docs/installation/upgrading.html +1178 -10
  511. nautobot/project-static/docs/models/circuits/circuit.html +1293 -103
  512. nautobot/project-static/docs/models/circuits/circuittermination.html +1293 -103
  513. nautobot/project-static/docs/models/circuits/circuittype.html +1293 -103
  514. nautobot/project-static/docs/models/circuits/provider.html +1293 -103
  515. nautobot/project-static/docs/models/circuits/providernetwork.html +1293 -103
  516. nautobot/project-static/docs/models/dcim/cable.html +1324 -103
  517. nautobot/project-static/docs/models/dcim/consoleport.html +1293 -103
  518. nautobot/project-static/docs/models/dcim/consoleporttemplate.html +1293 -103
  519. nautobot/project-static/docs/models/dcim/consoleserverport.html +1293 -103
  520. nautobot/project-static/docs/models/dcim/consoleserverporttemplate.html +1293 -103
  521. nautobot/project-static/docs/models/dcim/device.html +1326 -132
  522. nautobot/project-static/docs/models/dcim/devicebay.html +1293 -103
  523. nautobot/project-static/docs/models/dcim/devicebaytemplate.html +1293 -103
  524. nautobot/project-static/docs/models/dcim/deviceredundancygroup.html +1379 -97
  525. nautobot/project-static/docs/models/dcim/devicetype.html +1293 -103
  526. nautobot/project-static/docs/models/dcim/frontport.html +1293 -103
  527. nautobot/project-static/docs/models/dcim/frontporttemplate.html +1293 -103
  528. nautobot/project-static/docs/models/dcim/interface.html +1293 -103
  529. nautobot/project-static/docs/models/dcim/interfacetemplate.html +1293 -103
  530. nautobot/project-static/docs/models/dcim/inventoryitem.html +1293 -103
  531. nautobot/project-static/docs/models/dcim/location.html +1293 -103
  532. nautobot/project-static/docs/models/dcim/locationtype.html +1293 -103
  533. nautobot/project-static/docs/models/dcim/manufacturer.html +1292 -102
  534. nautobot/project-static/docs/models/dcim/platform.html +1272 -82
  535. nautobot/project-static/docs/models/dcim/powerfeed.html +1270 -80
  536. nautobot/project-static/docs/models/dcim/poweroutlet.html +1272 -82
  537. nautobot/project-static/docs/models/dcim/poweroutlettemplate.html +1272 -82
  538. nautobot/project-static/docs/models/dcim/powerpanel.html +1270 -80
  539. nautobot/project-static/docs/models/dcim/powerport.html +1272 -82
  540. nautobot/project-static/docs/models/dcim/powerporttemplate.html +1272 -82
  541. nautobot/project-static/docs/models/dcim/rack.html +1272 -82
  542. nautobot/project-static/docs/models/dcim/rackgroup.html +1272 -82
  543. nautobot/project-static/docs/models/dcim/rackreservation.html +1272 -82
  544. nautobot/project-static/docs/models/dcim/rearport.html +1286 -96
  545. nautobot/project-static/docs/models/dcim/rearporttemplate.html +1286 -96
  546. nautobot/project-static/docs/models/dcim/region.html +1178 -10
  547. nautobot/project-static/docs/models/dcim/site.html +1178 -10
  548. nautobot/project-static/docs/models/dcim/virtualchassis.html +1284 -94
  549. nautobot/project-static/docs/models/extras/computedfield.html +1184 -16
  550. nautobot/project-static/docs/models/extras/configcontext.html +1314 -86
  551. nautobot/project-static/docs/models/extras/configcontextschema.html +1276 -86
  552. nautobot/project-static/docs/models/extras/customfield.html +1180 -12
  553. nautobot/project-static/docs/models/extras/customlink.html +1180 -12
  554. nautobot/project-static/docs/models/extras/dynamicgroup.html +1180 -12
  555. nautobot/project-static/docs/models/extras/exporttemplate.html +1180 -12
  556. nautobot/project-static/docs/models/extras/gitrepository.html +1184 -12
  557. nautobot/project-static/docs/models/extras/graphqlquery.html +1321 -86
  558. nautobot/project-static/docs/models/extras/imageattachment.html +1276 -86
  559. nautobot/project-static/docs/models/extras/job.html +1277 -86
  560. nautobot/project-static/docs/models/extras/jobbutton.html +1201 -29
  561. nautobot/project-static/docs/models/extras/jobhook.html +1188 -16
  562. nautobot/project-static/docs/models/extras/joblogentry.html +1274 -84
  563. nautobot/project-static/docs/models/extras/jobresult.html +1364 -169
  564. nautobot/project-static/docs/models/extras/note.html +1180 -12
  565. nautobot/project-static/docs/models/extras/relationship.html +1182 -14
  566. nautobot/project-static/docs/models/extras/role.html +1320 -86
  567. nautobot/project-static/docs/models/extras/secret.html +1314 -86
  568. nautobot/project-static/docs/models/extras/secretsgroup.html +1276 -86
  569. nautobot/project-static/docs/models/extras/status.html +1188 -59
  570. nautobot/project-static/docs/models/extras/tag.html +1180 -12
  571. nautobot/project-static/docs/models/extras/webhook.html +1180 -12
  572. nautobot/project-static/docs/models/ipam/ipaddress.html +1327 -102
  573. nautobot/project-static/docs/models/ipam/prefix.html +1276 -86
  574. nautobot/project-static/docs/models/ipam/rir.html +1276 -86
  575. nautobot/project-static/docs/models/ipam/routetarget.html +1276 -86
  576. nautobot/project-static/docs/models/ipam/service.html +1276 -86
  577. nautobot/project-static/docs/models/ipam/vlan.html +1276 -86
  578. nautobot/project-static/docs/models/ipam/vlangroup.html +1276 -86
  579. nautobot/project-static/docs/models/ipam/vrf.html +1276 -86
  580. nautobot/project-static/docs/models/tenancy/tenant.html +1276 -86
  581. nautobot/project-static/docs/models/tenancy/tenantgroup.html +1276 -86
  582. nautobot/project-static/docs/models/users/objectpermission.html +1314 -86
  583. nautobot/project-static/docs/models/users/token.html +1276 -86
  584. nautobot/project-static/docs/models/virtualization/cluster.html +1276 -86
  585. nautobot/project-static/docs/models/virtualization/clustergroup.html +1276 -86
  586. nautobot/project-static/docs/models/virtualization/clustertype.html +1276 -86
  587. nautobot/project-static/docs/models/virtualization/virtualmachine.html +1321 -127
  588. nautobot/project-static/docs/models/virtualization/vminterface.html +1276 -86
  589. nautobot/project-static/docs/objects.inv +0 -0
  590. nautobot/project-static/docs/plugins/development.html +1726 -495
  591. nautobot/project-static/docs/plugins/index.html +1178 -10
  592. nautobot/project-static/docs/plugins/porting-from-netbox.html +1178 -10
  593. nautobot/project-static/docs/release-notes/index.html +1178 -10
  594. nautobot/project-static/docs/release-notes/version-1.0.html +1178 -10
  595. nautobot/project-static/docs/release-notes/version-1.1.html +1178 -10
  596. nautobot/project-static/docs/release-notes/version-1.2.html +1178 -10
  597. nautobot/project-static/docs/release-notes/version-1.3.html +1178 -10
  598. nautobot/project-static/docs/release-notes/version-1.4.html +1178 -10
  599. nautobot/project-static/docs/release-notes/version-1.5.html +1608 -225
  600. nautobot/project-static/docs/release-notes/version-2.0.html +1547 -47
  601. nautobot/project-static/docs/requirements.txt +1 -0
  602. nautobot/project-static/docs/rest-api/authentication.html +1179 -11
  603. nautobot/project-static/docs/rest-api/filtering.html +1178 -10
  604. nautobot/project-static/docs/rest-api/overview.html +1841 -446
  605. nautobot/project-static/docs/rest-api/ui-related-endpoints.html +4057 -0
  606. nautobot/project-static/docs/search/search_index.json +1 -1
  607. nautobot/project-static/docs/sitemap.xml +197 -187
  608. nautobot/project-static/docs/sitemap.xml.gz +0 -0
  609. nautobot/project-static/docs/user-guides/custom-fields.html +1178 -10
  610. nautobot/project-static/docs/user-guides/getting-started/creating-devices.html +1178 -10
  611. nautobot/project-static/docs/user-guides/getting-started/index.html +1178 -10
  612. nautobot/project-static/docs/user-guides/getting-started/interfaces.html +1178 -10
  613. nautobot/project-static/docs/user-guides/getting-started/ipam.html +1178 -10
  614. nautobot/project-static/docs/user-guides/getting-started/platforms.html +1178 -10
  615. nautobot/project-static/docs/user-guides/getting-started/regions.html +1178 -10
  616. nautobot/project-static/docs/user-guides/getting-started/search-bar.html +1178 -10
  617. nautobot/project-static/docs/user-guides/getting-started/tenants.html +1178 -10
  618. nautobot/project-static/docs/user-guides/getting-started/vlans-and-vlan-groups.html +1178 -10
  619. nautobot/project-static/docs/user-guides/git-data-source.html +1178 -10
  620. nautobot/project-static/docs/user-guides/graphql.html +1178 -10
  621. nautobot/project-static/docs/user-guides/relationships.html +1178 -10
  622. nautobot/project-static/docs/user-guides/s3-django-storage.html +1178 -10
  623. nautobot/project-static/js/forms.js +16 -9
  624. nautobot/project-static/js/theme.js +5 -0
  625. nautobot/tenancy/api/serializers.py +4 -32
  626. nautobot/tenancy/api/urls.py +1 -1
  627. nautobot/tenancy/forms.py +0 -28
  628. nautobot/tenancy/migrations/0008_tagsfield.py +19 -0
  629. nautobot/tenancy/models.py +0 -25
  630. nautobot/tenancy/navigation.py +6 -39
  631. nautobot/tenancy/templates/tenancy/tenant.html +12 -12
  632. nautobot/tenancy/templates/tenancy/tenantgroup.html +1 -1
  633. nautobot/tenancy/tests/test_api.py +1 -3
  634. nautobot/tenancy/tests/test_filters.py +10 -5
  635. nautobot/tenancy/views.py +0 -2
  636. nautobot/ui/.eslintignore +6 -0
  637. nautobot/ui/.gitignore +10 -0
  638. nautobot/ui/.prettierignore +9 -0
  639. nautobot/ui/.prettierrc +4 -0
  640. nautobot/ui/README.md +33 -0
  641. nautobot/ui/app_imports.js.j2 +7 -0
  642. nautobot/ui/craco.config.js +46 -0
  643. nautobot/ui/jsconfig-base.json +11 -0
  644. nautobot/ui/jsconfig.json +5 -0
  645. nautobot/ui/lib/nautobot-craco-alias-plugin.js +40 -0
  646. nautobot/ui/package-lock.json +21451 -0
  647. nautobot/ui/package.json +70 -0
  648. nautobot/ui/public/index.html +47 -0
  649. nautobot/ui/public/logo192.png +0 -0
  650. nautobot/ui/public/logo512.png +0 -0
  651. nautobot/ui/public/manifest.json +25 -0
  652. nautobot/ui/public/nautobot_logo.svg +131 -0
  653. nautobot/ui/public/robots.txt +3 -0
  654. nautobot/ui/src/App.js +71 -0
  655. nautobot/ui/src/components/AppFullWidthComponents.js +8 -0
  656. nautobot/ui/src/components/AppTab.js +40 -0
  657. nautobot/ui/src/components/Apps.js +60 -0
  658. nautobot/ui/src/components/HomeChangelogPanel.js +98 -0
  659. nautobot/ui/src/components/HomePanel.js +58 -0
  660. nautobot/ui/src/components/JobHistoryTable.js +78 -0
  661. nautobot/ui/src/components/Layout.js +53 -0
  662. nautobot/ui/src/components/LoadingWidget.js +25 -0
  663. nautobot/ui/src/components/Navbar.js +116 -0
  664. nautobot/ui/src/components/NotificationPopover.js +27 -0
  665. nautobot/ui/src/components/ObjectListTable.js +209 -0
  666. nautobot/ui/src/components/ReferenceDataTag.js +35 -0
  667. nautobot/ui/src/components/RouterButton.js +10 -0
  668. nautobot/ui/src/components/RouterLink.js +10 -0
  669. nautobot/ui/src/components/SidebarNav.js +147 -0
  670. nautobot/ui/src/components/Table.js +48 -0
  671. nautobot/ui/src/components/TableItem.js +71 -0
  672. nautobot/ui/src/components/__tests__/AppFullWidthComponents.test.js +16 -0
  673. nautobot/ui/src/components/__tests__/AppTab.test.js +21 -0
  674. nautobot/ui/src/components/__tests__/Apps.test.js +14 -0
  675. nautobot/ui/src/components/__tests__/Layout.test.js +33 -0
  676. nautobot/ui/src/components/__tests__/Table.test.js +36 -0
  677. nautobot/ui/src/components/__tests__/TableItem.test.js +37 -0
  678. nautobot/ui/src/components/__tests__/paginator.test.js +43 -0
  679. nautobot/ui/src/components/__tests__/paginator_form.test.js +13 -0
  680. nautobot/ui/src/components/pagination.js +93 -0
  681. nautobot/ui/src/components/paginator.js +79 -0
  682. nautobot/ui/src/components/paginator_form.js +43 -0
  683. nautobot/ui/src/components/usePagination.js +57 -0
  684. nautobot/ui/src/constants/apiPath.js +10 -0
  685. nautobot/ui/src/constants/icons.js +15 -0
  686. nautobot/ui/src/constants/size.js +15 -0
  687. nautobot/ui/src/index.js +65 -0
  688. nautobot/ui/src/reportWebVitals.js +15 -0
  689. nautobot/ui/src/router.js +77 -0
  690. nautobot/ui/src/utils/api.js +131 -0
  691. nautobot/ui/src/utils/app-import.js +15 -0
  692. nautobot/ui/src/utils/color.js +15 -0
  693. nautobot/ui/src/utils/date.js +14 -0
  694. nautobot/ui/src/utils/index.js +15 -0
  695. nautobot/ui/src/utils/navigation.js +32 -0
  696. nautobot/ui/src/utils/session.js +64 -0
  697. nautobot/ui/src/utils/store.js +242 -0
  698. nautobot/ui/src/utils/string.js +6 -0
  699. nautobot/ui/src/utils/url.js +4 -0
  700. nautobot/ui/src/views/Home.js +138 -0
  701. nautobot/ui/src/views/InstalledApps.js +80 -0
  702. nautobot/ui/src/views/Login.js +48 -0
  703. nautobot/ui/src/views/Logout.js +20 -0
  704. nautobot/ui/src/views/__tests__/BSCreateViewTemplate.test.js +11 -0
  705. nautobot/ui/src/views/__tests__/BSListViewTemplate.test.js +107 -0
  706. nautobot/ui/src/views/__tests__/Login.test.js +15 -0
  707. nautobot/ui/src/views/generic/GenericView.js +142 -0
  708. nautobot/ui/src/views/generic/ObjectCreate.js +96 -0
  709. nautobot/ui/src/views/generic/ObjectList.js +127 -0
  710. nautobot/ui/src/views/generic/ObjectRetrieve.js +551 -0
  711. nautobot/users/admin.py +1 -1
  712. nautobot/users/api/serializers.py +51 -61
  713. nautobot/users/api/urls.py +1 -1
  714. nautobot/users/api/views.py +53 -2
  715. nautobot/users/tests/test_api.py +110 -25
  716. nautobot/virtualization/api/serializers.py +18 -130
  717. nautobot/virtualization/api/urls.py +1 -1
  718. nautobot/virtualization/api/views.py +1 -22
  719. nautobot/virtualization/forms.py +13 -99
  720. nautobot/virtualization/migrations/0012_alter_virtualmachine_role_add_new_role.py +1 -1
  721. nautobot/virtualization/migrations/0013_migrate_virtualmachine_role_data.py +18 -11
  722. nautobot/virtualization/migrations/0015_rename_foreignkey_fields.py +1 -1
  723. nautobot/virtualization/migrations/0018_related_name_changes.py +1 -1
  724. nautobot/virtualization/migrations/0021_tagsfield_and_vminterface_to_primarymodel.py +39 -0
  725. nautobot/virtualization/migrations/0022_vminterface_timestamps_data_migration.py +17 -0
  726. nautobot/virtualization/migrations/{0021_ipam__namespaces.py → 0023_ipam__namespaces.py} +2 -2
  727. nautobot/virtualization/migrations/0024_fixup_null_statuses.py +25 -0
  728. nautobot/virtualization/migrations/0025_status_nonnullable.py +29 -0
  729. nautobot/virtualization/models.py +31 -123
  730. nautobot/virtualization/navigation.py +18 -99
  731. nautobot/virtualization/templates/virtualization/virtualmachine.html +2 -1
  732. nautobot/virtualization/templates/virtualization/virtualmachine_edit.html +6 -0
  733. nautobot/virtualization/tests/test_api.py +25 -26
  734. nautobot/virtualization/tests/test_filters.py +41 -15
  735. nautobot/virtualization/tests/test_models.py +31 -7
  736. nautobot/virtualization/tests/test_views.py +42 -25
  737. nautobot/virtualization/views.py +7 -6
  738. {nautobot-2.0.0a3.dist-info → nautobot-2.0.0b1.dist-info}/METADATA +3 -7
  739. {nautobot-2.0.0a3.dist-info → nautobot-2.0.0b1.dist-info}/RECORD +744 -602
  740. {nautobot-2.0.0a3.dist-info → nautobot-2.0.0b1.dist-info}/WHEEL +1 -1
  741. nautobot/circuits/api/nested_serializers.py +0 -69
  742. nautobot/core/templates/plugin_template/navigation.py-tpl +0 -22
  743. nautobot/dcim/api/nested_serializers.py +0 -356
  744. nautobot/dcim/templates/dcim/device_import.html +0 -5
  745. nautobot/dcim/templates/dcim/device_import_child.html +0 -5
  746. nautobot/dcim/templates/dcim/inc/device_import_header.html +0 -4
  747. nautobot/extras/api/nested_serializers.py +0 -353
  748. nautobot/extras/migrations/0064_configcontext_data_migrations.py +0 -41
  749. nautobot/extras/migrations/0071_job__unique_name_data_migration.py +0 -46
  750. nautobot/extras/reports.py +0 -60
  751. nautobot/extras/scripts.py +0 -72
  752. nautobot/extras/tests/example_jobs/script_variables.py +0 -67
  753. nautobot/extras/tests/example_jobs/test_duplicate_name2.py +0 -5
  754. nautobot/extras/tests/example_jobs/test_fail.py +0 -16
  755. nautobot/extras/tests/example_jobs/test_file_upload_pass.py +0 -20
  756. nautobot/extras/tests/example_jobs/test_ipaddress_vars.py +0 -52
  757. nautobot/extras/tests/example_jobs/test_job_button_receiver.py +0 -21
  758. nautobot/extras/tests/example_jobs/test_job_hook_receiver.py +0 -20
  759. nautobot/extras/tests/example_jobs/test_location_with_custom_field.py +0 -35
  760. nautobot/extras/tests/example_jobs/test_log_redaction.py +0 -14
  761. nautobot/extras/tests/example_jobs/test_modify_db.py +0 -18
  762. nautobot/extras/tests/example_jobs/test_object_var_optional.py +0 -14
  763. nautobot/extras/tests/example_jobs/test_object_var_required.py +0 -14
  764. nautobot/extras/tests/example_jobs/test_object_vars.py +0 -29
  765. nautobot/extras/tests/example_jobs/test_pass.py +0 -19
  766. nautobot/extras/tests/example_jobs/test_read_only_fail.py +0 -24
  767. nautobot/extras/tests/example_jobs/test_read_only_no_commit_field.py +0 -10
  768. nautobot/extras/tests/example_jobs/test_read_only_pass.py +0 -22
  769. nautobot/ipam/api/nested_serializers.py +0 -159
  770. nautobot/ipam/migrations/0029_ipam__prefix__add_parent.py +0 -31
  771. nautobot/ipam/migrations/0030_ipam__prefix__data_migration.py +0 -13
  772. nautobot/ipam/migrations/0031_ipam__ipaddress__add_parent.py +0 -41
  773. nautobot/ipam/migrations/0032_ipam__ipaddress__data_migration.py +0 -11
  774. nautobot/tenancy/api/nested_serializers.py +0 -31
  775. nautobot/users/api/nested_serializers.py +0 -67
  776. nautobot/virtualization/api/nested_serializers.py +0 -65
  777. /nautobot/extras/{tests/example_jobs → test_jobs}/__init__.py +0 -0
  778. /nautobot/{dcim/models/sites.py → ipam/management/__init__.py} +0 -0
  779. {nautobot-2.0.0a3.dist-info → nautobot-2.0.0b1.dist-info}/LICENSE.txt +0 -0
  780. {nautobot-2.0.0a3.dist-info → nautobot-2.0.0b1.dist-info}/entry_points.txt +0 -0
@@ -1336,6 +1336,1160 @@
1336
1336
 
1337
1337
 
1338
1338
 
1339
+
1340
+
1341
+ <li class="md-nav__item md-nav__item--nested">
1342
+
1343
+
1344
+
1345
+
1346
+ <input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_2_8" >
1347
+
1348
+
1349
+
1350
+ <label class="md-nav__link" for="__nav_2_8" id="__nav_2_8_label" tabindex="0">
1351
+ Model Details
1352
+ <span class="md-nav__icon md-icon"></span>
1353
+ </label>
1354
+
1355
+ <nav class="md-nav" data-md-level="2" aria-labelledby="__nav_2_8_label" aria-expanded="false">
1356
+ <label class="md-nav__title" for="__nav_2_8">
1357
+ <span class="md-nav__icon md-icon"></span>
1358
+ Model Details
1359
+ </label>
1360
+ <ul class="md-nav__list" data-md-scrollfix>
1361
+
1362
+
1363
+
1364
+
1365
+
1366
+
1367
+
1368
+ <li class="md-nav__item md-nav__item--nested">
1369
+
1370
+
1371
+
1372
+
1373
+ <input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_2_8_1" >
1374
+
1375
+
1376
+
1377
+ <label class="md-nav__link" for="__nav_2_8_1" id="__nav_2_8_1_label" tabindex="0">
1378
+ Circuits
1379
+ <span class="md-nav__icon md-icon"></span>
1380
+ </label>
1381
+
1382
+ <nav class="md-nav" data-md-level="3" aria-labelledby="__nav_2_8_1_label" aria-expanded="false">
1383
+ <label class="md-nav__title" for="__nav_2_8_1">
1384
+ <span class="md-nav__icon md-icon"></span>
1385
+ Circuits
1386
+ </label>
1387
+ <ul class="md-nav__list" data-md-scrollfix>
1388
+
1389
+
1390
+
1391
+
1392
+
1393
+
1394
+ <li class="md-nav__item">
1395
+ <a href="../models/circuits/circuit.html" class="md-nav__link">
1396
+ Circuit
1397
+ </a>
1398
+ </li>
1399
+
1400
+
1401
+
1402
+
1403
+
1404
+
1405
+
1406
+
1407
+
1408
+ <li class="md-nav__item">
1409
+ <a href="../models/circuits/circuittermination.html" class="md-nav__link">
1410
+ Circuit Termination
1411
+ </a>
1412
+ </li>
1413
+
1414
+
1415
+
1416
+
1417
+
1418
+
1419
+
1420
+
1421
+
1422
+ <li class="md-nav__item">
1423
+ <a href="../models/circuits/circuittype.html" class="md-nav__link">
1424
+ Circuit Type
1425
+ </a>
1426
+ </li>
1427
+
1428
+
1429
+
1430
+
1431
+
1432
+
1433
+
1434
+
1435
+
1436
+ <li class="md-nav__item">
1437
+ <a href="../models/circuits/provider.html" class="md-nav__link">
1438
+ Circuit Provider
1439
+ </a>
1440
+ </li>
1441
+
1442
+
1443
+
1444
+
1445
+
1446
+
1447
+
1448
+
1449
+
1450
+ <li class="md-nav__item">
1451
+ <a href="../models/circuits/providernetwork.html" class="md-nav__link">
1452
+ Circuit Provider Network
1453
+ </a>
1454
+ </li>
1455
+
1456
+
1457
+
1458
+
1459
+ </ul>
1460
+ </nav>
1461
+ </li>
1462
+
1463
+
1464
+
1465
+
1466
+
1467
+
1468
+
1469
+
1470
+
1471
+
1472
+ <li class="md-nav__item md-nav__item--nested">
1473
+
1474
+
1475
+
1476
+
1477
+ <input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_2_8_2" >
1478
+
1479
+
1480
+
1481
+ <label class="md-nav__link" for="__nav_2_8_2" id="__nav_2_8_2_label" tabindex="0">
1482
+ DCIM
1483
+ <span class="md-nav__icon md-icon"></span>
1484
+ </label>
1485
+
1486
+ <nav class="md-nav" data-md-level="3" aria-labelledby="__nav_2_8_2_label" aria-expanded="false">
1487
+ <label class="md-nav__title" for="__nav_2_8_2">
1488
+ <span class="md-nav__icon md-icon"></span>
1489
+ DCIM
1490
+ </label>
1491
+ <ul class="md-nav__list" data-md-scrollfix>
1492
+
1493
+
1494
+
1495
+
1496
+
1497
+
1498
+ <li class="md-nav__item">
1499
+ <a href="../models/dcim/cable.html" class="md-nav__link">
1500
+ Cable
1501
+ </a>
1502
+ </li>
1503
+
1504
+
1505
+
1506
+
1507
+
1508
+
1509
+
1510
+
1511
+
1512
+ <li class="md-nav__item">
1513
+ <a href="../models/dcim/consoleport.html" class="md-nav__link">
1514
+ Console Port
1515
+ </a>
1516
+ </li>
1517
+
1518
+
1519
+
1520
+
1521
+
1522
+
1523
+
1524
+
1525
+
1526
+ <li class="md-nav__item">
1527
+ <a href="../models/dcim/consoleporttemplate.html" class="md-nav__link">
1528
+ Console Port Template
1529
+ </a>
1530
+ </li>
1531
+
1532
+
1533
+
1534
+
1535
+
1536
+
1537
+
1538
+
1539
+
1540
+ <li class="md-nav__item">
1541
+ <a href="../models/dcim/consoleserverport.html" class="md-nav__link">
1542
+ Console Server Port
1543
+ </a>
1544
+ </li>
1545
+
1546
+
1547
+
1548
+
1549
+
1550
+
1551
+
1552
+
1553
+
1554
+ <li class="md-nav__item">
1555
+ <a href="../models/dcim/consoleserverporttemplate.html" class="md-nav__link">
1556
+ Console Server Port Template
1557
+ </a>
1558
+ </li>
1559
+
1560
+
1561
+
1562
+
1563
+
1564
+
1565
+
1566
+
1567
+
1568
+ <li class="md-nav__item">
1569
+ <a href="../models/dcim/device.html" class="md-nav__link">
1570
+ Device
1571
+ </a>
1572
+ </li>
1573
+
1574
+
1575
+
1576
+
1577
+
1578
+
1579
+
1580
+
1581
+
1582
+ <li class="md-nav__item">
1583
+ <a href="../models/dcim/devicebay.html" class="md-nav__link">
1584
+ Device Bay
1585
+ </a>
1586
+ </li>
1587
+
1588
+
1589
+
1590
+
1591
+
1592
+
1593
+
1594
+
1595
+
1596
+ <li class="md-nav__item">
1597
+ <a href="../models/dcim/devicebaytemplate.html" class="md-nav__link">
1598
+ Device Bay Template
1599
+ </a>
1600
+ </li>
1601
+
1602
+
1603
+
1604
+
1605
+
1606
+
1607
+
1608
+
1609
+
1610
+ <li class="md-nav__item">
1611
+ <a href="../models/dcim/deviceredundancygroup.html" class="md-nav__link">
1612
+ Device Redundancy Group
1613
+ </a>
1614
+ </li>
1615
+
1616
+
1617
+
1618
+
1619
+
1620
+
1621
+
1622
+
1623
+
1624
+ <li class="md-nav__item">
1625
+ <a href="../models/dcim/devicetype.html" class="md-nav__link">
1626
+ Device Type
1627
+ </a>
1628
+ </li>
1629
+
1630
+
1631
+
1632
+
1633
+
1634
+
1635
+
1636
+
1637
+
1638
+ <li class="md-nav__item">
1639
+ <a href="../models/dcim/frontport.html" class="md-nav__link">
1640
+ Front Port
1641
+ </a>
1642
+ </li>
1643
+
1644
+
1645
+
1646
+
1647
+
1648
+
1649
+
1650
+
1651
+
1652
+ <li class="md-nav__item">
1653
+ <a href="../models/dcim/frontporttemplate.html" class="md-nav__link">
1654
+ Front Port Template
1655
+ </a>
1656
+ </li>
1657
+
1658
+
1659
+
1660
+
1661
+
1662
+
1663
+
1664
+
1665
+
1666
+ <li class="md-nav__item">
1667
+ <a href="../models/dcim/interface.html" class="md-nav__link">
1668
+ Interface
1669
+ </a>
1670
+ </li>
1671
+
1672
+
1673
+
1674
+
1675
+
1676
+
1677
+
1678
+
1679
+
1680
+ <li class="md-nav__item">
1681
+ <a href="../models/dcim/interfacetemplate.html" class="md-nav__link">
1682
+ Interface Template
1683
+ </a>
1684
+ </li>
1685
+
1686
+
1687
+
1688
+
1689
+
1690
+
1691
+
1692
+
1693
+
1694
+ <li class="md-nav__item">
1695
+ <a href="../models/dcim/inventoryitem.html" class="md-nav__link">
1696
+ Inventory Item
1697
+ </a>
1698
+ </li>
1699
+
1700
+
1701
+
1702
+
1703
+
1704
+
1705
+
1706
+
1707
+
1708
+ <li class="md-nav__item">
1709
+ <a href="../models/dcim/location.html" class="md-nav__link">
1710
+ Location
1711
+ </a>
1712
+ </li>
1713
+
1714
+
1715
+
1716
+
1717
+
1718
+
1719
+
1720
+
1721
+
1722
+ <li class="md-nav__item">
1723
+ <a href="../models/dcim/locationtype.html" class="md-nav__link">
1724
+ Location Type
1725
+ </a>
1726
+ </li>
1727
+
1728
+
1729
+
1730
+
1731
+
1732
+
1733
+
1734
+
1735
+
1736
+ <li class="md-nav__item">
1737
+ <a href="../models/dcim/manufacturer.html" class="md-nav__link">
1738
+ Manufacturer
1739
+ </a>
1740
+ </li>
1741
+
1742
+
1743
+
1744
+
1745
+
1746
+
1747
+
1748
+
1749
+
1750
+ <li class="md-nav__item">
1751
+ <a href="../models/dcim/platform.html" class="md-nav__link">
1752
+ Platform
1753
+ </a>
1754
+ </li>
1755
+
1756
+
1757
+
1758
+
1759
+
1760
+
1761
+
1762
+
1763
+
1764
+ <li class="md-nav__item">
1765
+ <a href="../models/dcim/powerfeed.html" class="md-nav__link">
1766
+ Power Feed
1767
+ </a>
1768
+ </li>
1769
+
1770
+
1771
+
1772
+
1773
+
1774
+
1775
+
1776
+
1777
+
1778
+ <li class="md-nav__item">
1779
+ <a href="../models/dcim/poweroutlet.html" class="md-nav__link">
1780
+ Power Outlet
1781
+ </a>
1782
+ </li>
1783
+
1784
+
1785
+
1786
+
1787
+
1788
+
1789
+
1790
+
1791
+
1792
+ <li class="md-nav__item">
1793
+ <a href="../models/dcim/poweroutlettemplate.html" class="md-nav__link">
1794
+ Power Outlet Template
1795
+ </a>
1796
+ </li>
1797
+
1798
+
1799
+
1800
+
1801
+
1802
+
1803
+
1804
+
1805
+
1806
+ <li class="md-nav__item">
1807
+ <a href="../models/dcim/powerpanel.html" class="md-nav__link">
1808
+ Power Panel
1809
+ </a>
1810
+ </li>
1811
+
1812
+
1813
+
1814
+
1815
+
1816
+
1817
+
1818
+
1819
+
1820
+ <li class="md-nav__item">
1821
+ <a href="../models/dcim/powerport.html" class="md-nav__link">
1822
+ Power Port
1823
+ </a>
1824
+ </li>
1825
+
1826
+
1827
+
1828
+
1829
+
1830
+
1831
+
1832
+
1833
+
1834
+ <li class="md-nav__item">
1835
+ <a href="../models/dcim/powerporttemplate.html" class="md-nav__link">
1836
+ Power Port Template
1837
+ </a>
1838
+ </li>
1839
+
1840
+
1841
+
1842
+
1843
+
1844
+
1845
+
1846
+
1847
+
1848
+ <li class="md-nav__item">
1849
+ <a href="../models/dcim/rack.html" class="md-nav__link">
1850
+ Rack
1851
+ </a>
1852
+ </li>
1853
+
1854
+
1855
+
1856
+
1857
+
1858
+
1859
+
1860
+
1861
+
1862
+ <li class="md-nav__item">
1863
+ <a href="../models/dcim/rackgroup.html" class="md-nav__link">
1864
+ Rack Group
1865
+ </a>
1866
+ </li>
1867
+
1868
+
1869
+
1870
+
1871
+
1872
+
1873
+
1874
+
1875
+
1876
+ <li class="md-nav__item">
1877
+ <a href="../models/dcim/rackreservation.html" class="md-nav__link">
1878
+ Rack Reservation
1879
+ </a>
1880
+ </li>
1881
+
1882
+
1883
+
1884
+
1885
+
1886
+
1887
+
1888
+
1889
+
1890
+ <li class="md-nav__item">
1891
+ <a href="../models/dcim/rearport.html" class="md-nav__link">
1892
+ Rear Port
1893
+ </a>
1894
+ </li>
1895
+
1896
+
1897
+
1898
+
1899
+
1900
+
1901
+
1902
+
1903
+
1904
+ <li class="md-nav__item">
1905
+ <a href="../models/dcim/rearporttemplate.html" class="md-nav__link">
1906
+ Rear Port Template
1907
+ </a>
1908
+ </li>
1909
+
1910
+
1911
+
1912
+
1913
+
1914
+
1915
+
1916
+
1917
+
1918
+ <li class="md-nav__item">
1919
+ <a href="../models/dcim/virtualchassis.html" class="md-nav__link">
1920
+ Virtual Chassis
1921
+ </a>
1922
+ </li>
1923
+
1924
+
1925
+
1926
+
1927
+ </ul>
1928
+ </nav>
1929
+ </li>
1930
+
1931
+
1932
+
1933
+
1934
+
1935
+
1936
+
1937
+
1938
+
1939
+
1940
+ <li class="md-nav__item md-nav__item--nested">
1941
+
1942
+
1943
+
1944
+
1945
+ <input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_2_8_3" >
1946
+
1947
+
1948
+
1949
+ <label class="md-nav__link" for="__nav_2_8_3" id="__nav_2_8_3_label" tabindex="0">
1950
+ Extras
1951
+ <span class="md-nav__icon md-icon"></span>
1952
+ </label>
1953
+
1954
+ <nav class="md-nav" data-md-level="3" aria-labelledby="__nav_2_8_3_label" aria-expanded="false">
1955
+ <label class="md-nav__title" for="__nav_2_8_3">
1956
+ <span class="md-nav__icon md-icon"></span>
1957
+ Extras
1958
+ </label>
1959
+ <ul class="md-nav__list" data-md-scrollfix>
1960
+
1961
+
1962
+
1963
+
1964
+
1965
+
1966
+ <li class="md-nav__item">
1967
+ <a href="../models/extras/configcontext.html" class="md-nav__link">
1968
+ Config Context
1969
+ </a>
1970
+ </li>
1971
+
1972
+
1973
+
1974
+
1975
+
1976
+
1977
+
1978
+
1979
+
1980
+ <li class="md-nav__item">
1981
+ <a href="../models/extras/configcontextschema.html" class="md-nav__link">
1982
+ Config Context Schema
1983
+ </a>
1984
+ </li>
1985
+
1986
+
1987
+
1988
+
1989
+
1990
+
1991
+
1992
+
1993
+
1994
+ <li class="md-nav__item">
1995
+ <a href="../models/extras/graphqlquery.html" class="md-nav__link">
1996
+ GraphQL Query
1997
+ </a>
1998
+ </li>
1999
+
2000
+
2001
+
2002
+
2003
+
2004
+
2005
+
2006
+
2007
+
2008
+ <li class="md-nav__item">
2009
+ <a href="../models/extras/imageattachment.html" class="md-nav__link">
2010
+ Image Attachment
2011
+ </a>
2012
+ </li>
2013
+
2014
+
2015
+
2016
+
2017
+
2018
+
2019
+
2020
+
2021
+
2022
+ <li class="md-nav__item">
2023
+ <a href="../models/extras/job.html" class="md-nav__link">
2024
+ Job
2025
+ </a>
2026
+ </li>
2027
+
2028
+
2029
+
2030
+
2031
+
2032
+
2033
+
2034
+
2035
+
2036
+ <li class="md-nav__item">
2037
+ <a href="../models/extras/joblogentry.html" class="md-nav__link">
2038
+ Job Log Entry
2039
+ </a>
2040
+ </li>
2041
+
2042
+
2043
+
2044
+
2045
+
2046
+
2047
+
2048
+
2049
+
2050
+ <li class="md-nav__item">
2051
+ <a href="../models/extras/jobresult.html" class="md-nav__link">
2052
+ Job Result
2053
+ </a>
2054
+ </li>
2055
+
2056
+
2057
+
2058
+
2059
+
2060
+
2061
+
2062
+
2063
+
2064
+ <li class="md-nav__item">
2065
+ <a href="../models/extras/role.html" class="md-nav__link">
2066
+ Role
2067
+ </a>
2068
+ </li>
2069
+
2070
+
2071
+
2072
+
2073
+
2074
+
2075
+
2076
+
2077
+
2078
+ <li class="md-nav__item">
2079
+ <a href="../models/extras/secret.html" class="md-nav__link">
2080
+ Secret
2081
+ </a>
2082
+ </li>
2083
+
2084
+
2085
+
2086
+
2087
+
2088
+
2089
+
2090
+
2091
+
2092
+ <li class="md-nav__item">
2093
+ <a href="../models/extras/secretsgroup.html" class="md-nav__link">
2094
+ Secrets group
2095
+ </a>
2096
+ </li>
2097
+
2098
+
2099
+
2100
+
2101
+ </ul>
2102
+ </nav>
2103
+ </li>
2104
+
2105
+
2106
+
2107
+
2108
+
2109
+
2110
+
2111
+
2112
+
2113
+
2114
+ <li class="md-nav__item md-nav__item--nested">
2115
+
2116
+
2117
+
2118
+
2119
+ <input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_2_8_4" >
2120
+
2121
+
2122
+
2123
+ <label class="md-nav__link" for="__nav_2_8_4" id="__nav_2_8_4_label" tabindex="0">
2124
+ IPAM
2125
+ <span class="md-nav__icon md-icon"></span>
2126
+ </label>
2127
+
2128
+ <nav class="md-nav" data-md-level="3" aria-labelledby="__nav_2_8_4_label" aria-expanded="false">
2129
+ <label class="md-nav__title" for="__nav_2_8_4">
2130
+ <span class="md-nav__icon md-icon"></span>
2131
+ IPAM
2132
+ </label>
2133
+ <ul class="md-nav__list" data-md-scrollfix>
2134
+
2135
+
2136
+
2137
+
2138
+
2139
+
2140
+ <li class="md-nav__item">
2141
+ <a href="../models/ipam/ipaddress.html" class="md-nav__link">
2142
+ IP Address
2143
+ </a>
2144
+ </li>
2145
+
2146
+
2147
+
2148
+
2149
+
2150
+
2151
+
2152
+
2153
+
2154
+ <li class="md-nav__item">
2155
+ <a href="../models/ipam/prefix.html" class="md-nav__link">
2156
+ Prefix
2157
+ </a>
2158
+ </li>
2159
+
2160
+
2161
+
2162
+
2163
+
2164
+
2165
+
2166
+
2167
+
2168
+ <li class="md-nav__item">
2169
+ <a href="../models/ipam/rir.html" class="md-nav__link">
2170
+ Rir
2171
+ </a>
2172
+ </li>
2173
+
2174
+
2175
+
2176
+
2177
+
2178
+
2179
+
2180
+
2181
+
2182
+ <li class="md-nav__item">
2183
+ <a href="../models/ipam/routetarget.html" class="md-nav__link">
2184
+ Route Target
2185
+ </a>
2186
+ </li>
2187
+
2188
+
2189
+
2190
+
2191
+
2192
+
2193
+
2194
+
2195
+
2196
+ <li class="md-nav__item">
2197
+ <a href="../models/ipam/service.html" class="md-nav__link">
2198
+ Service
2199
+ </a>
2200
+ </li>
2201
+
2202
+
2203
+
2204
+
2205
+
2206
+
2207
+
2208
+
2209
+
2210
+ <li class="md-nav__item">
2211
+ <a href="../models/ipam/vlan.html" class="md-nav__link">
2212
+ VLAN
2213
+ </a>
2214
+ </li>
2215
+
2216
+
2217
+
2218
+
2219
+
2220
+
2221
+
2222
+
2223
+
2224
+ <li class="md-nav__item">
2225
+ <a href="../models/ipam/vlangroup.html" class="md-nav__link">
2226
+ VLAN Group
2227
+ </a>
2228
+ </li>
2229
+
2230
+
2231
+
2232
+
2233
+
2234
+
2235
+
2236
+
2237
+
2238
+ <li class="md-nav__item">
2239
+ <a href="../models/ipam/vrf.html" class="md-nav__link">
2240
+ VRF
2241
+ </a>
2242
+ </li>
2243
+
2244
+
2245
+
2246
+
2247
+ </ul>
2248
+ </nav>
2249
+ </li>
2250
+
2251
+
2252
+
2253
+
2254
+
2255
+
2256
+
2257
+
2258
+
2259
+
2260
+ <li class="md-nav__item md-nav__item--nested">
2261
+
2262
+
2263
+
2264
+
2265
+ <input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_2_8_5" >
2266
+
2267
+
2268
+
2269
+ <label class="md-nav__link" for="__nav_2_8_5" id="__nav_2_8_5_label" tabindex="0">
2270
+ Tenancy
2271
+ <span class="md-nav__icon md-icon"></span>
2272
+ </label>
2273
+
2274
+ <nav class="md-nav" data-md-level="3" aria-labelledby="__nav_2_8_5_label" aria-expanded="false">
2275
+ <label class="md-nav__title" for="__nav_2_8_5">
2276
+ <span class="md-nav__icon md-icon"></span>
2277
+ Tenancy
2278
+ </label>
2279
+ <ul class="md-nav__list" data-md-scrollfix>
2280
+
2281
+
2282
+
2283
+
2284
+
2285
+
2286
+ <li class="md-nav__item">
2287
+ <a href="../models/tenancy/tenant.html" class="md-nav__link">
2288
+ Tenant
2289
+ </a>
2290
+ </li>
2291
+
2292
+
2293
+
2294
+
2295
+
2296
+
2297
+
2298
+
2299
+
2300
+ <li class="md-nav__item">
2301
+ <a href="../models/tenancy/tenantgroup.html" class="md-nav__link">
2302
+ Tenant Group
2303
+ </a>
2304
+ </li>
2305
+
2306
+
2307
+
2308
+
2309
+ </ul>
2310
+ </nav>
2311
+ </li>
2312
+
2313
+
2314
+
2315
+
2316
+
2317
+
2318
+
2319
+
2320
+
2321
+
2322
+ <li class="md-nav__item md-nav__item--nested">
2323
+
2324
+
2325
+
2326
+
2327
+ <input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_2_8_6" >
2328
+
2329
+
2330
+
2331
+ <label class="md-nav__link" for="__nav_2_8_6" id="__nav_2_8_6_label" tabindex="0">
2332
+ Users
2333
+ <span class="md-nav__icon md-icon"></span>
2334
+ </label>
2335
+
2336
+ <nav class="md-nav" data-md-level="3" aria-labelledby="__nav_2_8_6_label" aria-expanded="false">
2337
+ <label class="md-nav__title" for="__nav_2_8_6">
2338
+ <span class="md-nav__icon md-icon"></span>
2339
+ Users
2340
+ </label>
2341
+ <ul class="md-nav__list" data-md-scrollfix>
2342
+
2343
+
2344
+
2345
+
2346
+
2347
+
2348
+ <li class="md-nav__item">
2349
+ <a href="../models/users/objectpermission.html" class="md-nav__link">
2350
+ Object Permission
2351
+ </a>
2352
+ </li>
2353
+
2354
+
2355
+
2356
+
2357
+
2358
+
2359
+
2360
+
2361
+
2362
+ <li class="md-nav__item">
2363
+ <a href="../models/users/token.html" class="md-nav__link">
2364
+ Token
2365
+ </a>
2366
+ </li>
2367
+
2368
+
2369
+
2370
+
2371
+ </ul>
2372
+ </nav>
2373
+ </li>
2374
+
2375
+
2376
+
2377
+
2378
+
2379
+
2380
+
2381
+
2382
+
2383
+
2384
+ <li class="md-nav__item md-nav__item--nested">
2385
+
2386
+
2387
+
2388
+
2389
+ <input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_2_8_7" >
2390
+
2391
+
2392
+
2393
+ <label class="md-nav__link" for="__nav_2_8_7" id="__nav_2_8_7_label" tabindex="0">
2394
+ Virtualization
2395
+ <span class="md-nav__icon md-icon"></span>
2396
+ </label>
2397
+
2398
+ <nav class="md-nav" data-md-level="3" aria-labelledby="__nav_2_8_7_label" aria-expanded="false">
2399
+ <label class="md-nav__title" for="__nav_2_8_7">
2400
+ <span class="md-nav__icon md-icon"></span>
2401
+ Virtualization
2402
+ </label>
2403
+ <ul class="md-nav__list" data-md-scrollfix>
2404
+
2405
+
2406
+
2407
+
2408
+
2409
+
2410
+ <li class="md-nav__item">
2411
+ <a href="../models/virtualization/cluster.html" class="md-nav__link">
2412
+ Cluster
2413
+ </a>
2414
+ </li>
2415
+
2416
+
2417
+
2418
+
2419
+
2420
+
2421
+
2422
+
2423
+
2424
+ <li class="md-nav__item">
2425
+ <a href="../models/virtualization/clustergroup.html" class="md-nav__link">
2426
+ Cluster Group
2427
+ </a>
2428
+ </li>
2429
+
2430
+
2431
+
2432
+
2433
+
2434
+
2435
+
2436
+
2437
+
2438
+ <li class="md-nav__item">
2439
+ <a href="../models/virtualization/clustertype.html" class="md-nav__link">
2440
+ Cluster Type
2441
+ </a>
2442
+ </li>
2443
+
2444
+
2445
+
2446
+
2447
+
2448
+
2449
+
2450
+
2451
+
2452
+ <li class="md-nav__item">
2453
+ <a href="../models/virtualization/virtualmachine.html" class="md-nav__link">
2454
+ Virtual Machine
2455
+ </a>
2456
+ </li>
2457
+
2458
+
2459
+
2460
+
2461
+
2462
+
2463
+
2464
+
2465
+
2466
+ <li class="md-nav__item">
2467
+ <a href="../models/virtualization/vminterface.html" class="md-nav__link">
2468
+ VM Interface
2469
+ </a>
2470
+ </li>
2471
+
2472
+
2473
+
2474
+
2475
+ </ul>
2476
+ </nav>
2477
+ </li>
2478
+
2479
+
2480
+
2481
+
2482
+ </ul>
2483
+ </nav>
2484
+ </li>
2485
+
2486
+
2487
+
2488
+
2489
+
2490
+
2491
+
2492
+
1339
2493
 
1340
2494
 
1341
2495
 
@@ -1345,17 +2499,17 @@
1345
2499
 
1346
2500
 
1347
2501
 
1348
- <input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_2_8" checked>
2502
+ <input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_2_9" checked>
1349
2503
 
1350
2504
 
1351
2505
 
1352
- <label class="md-nav__link" for="__nav_2_8" id="__nav_2_8_label" tabindex="0">
2506
+ <label class="md-nav__link" for="__nav_2_9" id="__nav_2_9_label" tabindex="0">
1353
2507
  Additional Features
1354
2508
  <span class="md-nav__icon md-icon"></span>
1355
2509
  </label>
1356
2510
 
1357
- <nav class="md-nav" data-md-level="2" aria-labelledby="__nav_2_8_label" aria-expanded="true">
1358
- <label class="md-nav__title" for="__nav_2_8">
2511
+ <nav class="md-nav" data-md-level="2" aria-labelledby="__nav_2_9_label" aria-expanded="true">
2512
+ <label class="md-nav__title" for="__nav_2_9">
1359
2513
  <span class="md-nav__icon md-icon"></span>
1360
2514
  Additional Features
1361
2515
  </label>
@@ -1598,8 +2752,8 @@
1598
2752
  </li>
1599
2753
 
1600
2754
  <li class="md-nav__item">
1601
- <a href="#commit_default" class="md-nav__link">
1602
- commit_default
2755
+ <a href="#dryrun_default" class="md-nav__link">
2756
+ dryrun_default
1603
2757
  </a>
1604
2758
 
1605
2759
  </li>
@@ -1706,6 +2860,13 @@
1706
2860
  BooleanVar
1707
2861
  </a>
1708
2862
 
2863
+ </li>
2864
+
2865
+ <li class="md-nav__item">
2866
+ <a href="#dryrunvar" class="md-nav__link">
2867
+ DryRunVar
2868
+ </a>
2869
+
1709
2870
  </li>
1710
2871
 
1711
2872
  <li class="md-nav__item">
@@ -1777,29 +2938,22 @@
1777
2938
  </li>
1778
2939
 
1779
2940
  <li class="md-nav__item">
1780
- <a href="#the-test_-methods" class="md-nav__link">
1781
- The test_*() Methods
1782
- </a>
1783
-
1784
- </li>
1785
-
1786
- <li class="md-nav__item">
1787
- <a href="#the-post_run-method" class="md-nav__link">
1788
- The post_run() Method
2941
+ <a href="#logging" class="md-nav__link">
2942
+ Logging
1789
2943
  </a>
1790
2944
 
1791
2945
  </li>
1792
2946
 
1793
2947
  <li class="md-nav__item">
1794
- <a href="#logging" class="md-nav__link">
1795
- Logging
2948
+ <a href="#marking-a-job-as-failed" class="md-nav__link">
2949
+ Marking a Job as Failed
1796
2950
  </a>
1797
2951
 
1798
2952
  </li>
1799
2953
 
1800
2954
  <li class="md-nav__item">
1801
- <a href="#accessing-request-data" class="md-nav__link">
1802
- Accessing Request Data
2955
+ <a href="#accessing-user-and-job-result" class="md-nav__link">
2956
+ Accessing User and Job Result
1803
2957
  </a>
1804
2958
 
1805
2959
  </li>
@@ -1919,9 +3073,22 @@
1919
3073
 
1920
3074
  </li>
1921
3075
 
3076
+ </ul>
3077
+ </nav>
3078
+
3079
+ </li>
3080
+
3081
+ <li class="md-nav__item">
3082
+ <a href="#debugging-job-performance" class="md-nav__link">
3083
+ Debugging job performance
3084
+ </a>
3085
+
3086
+ <nav class="md-nav" aria-label="Debugging job performance">
3087
+ <ul class="md-nav__list">
3088
+
1922
3089
  <li class="md-nav__item">
1923
- <a href="#nautobot-132-and-earlier-including-12" class="md-nav__link">
1924
- Nautobot 1.3.2 and earlier (including 1.2)
3090
+ <a href="#reading-profiling-reports" class="md-nav__link">
3091
+ Reading profiling reports
1925
3092
  </a>
1926
3093
 
1927
3094
  </li>
@@ -1940,8 +3107,8 @@
1940
3107
  <ul class="md-nav__list">
1941
3108
 
1942
3109
  <li class="md-nav__item">
1943
- <a href="#creating-objects-for-a-planned-site" class="md-nav__link">
1944
- Creating objects for a planned site
3110
+ <a href="#creating-objects-for-a-planned-location" class="md-nav__link">
3111
+ Creating objects for a planned location
1945
3112
  </a>
1946
3113
 
1947
3114
  </li>
@@ -2139,17 +3306,17 @@
2139
3306
 
2140
3307
 
2141
3308
 
2142
- <input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_2_9" >
3309
+ <input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_2_10" >
2143
3310
 
2144
3311
 
2145
3312
 
2146
- <label class="md-nav__link" for="__nav_2_9" id="__nav_2_9_label" tabindex="0">
3313
+ <label class="md-nav__link" for="__nav_2_10" id="__nav_2_10_label" tabindex="0">
2147
3314
  REST API
2148
3315
  <span class="md-nav__icon md-icon"></span>
2149
3316
  </label>
2150
3317
 
2151
- <nav class="md-nav" data-md-level="2" aria-labelledby="__nav_2_9_label" aria-expanded="false">
2152
- <label class="md-nav__title" for="__nav_2_9">
3318
+ <nav class="md-nav" data-md-level="2" aria-labelledby="__nav_2_10_label" aria-expanded="false">
3319
+ <label class="md-nav__title" for="__nav_2_10">
2153
3320
  <span class="md-nav__icon md-icon"></span>
2154
3321
  REST API
2155
3322
  </label>
@@ -2197,6 +3364,20 @@
2197
3364
 
2198
3365
 
2199
3366
 
3367
+
3368
+
3369
+
3370
+
3371
+
3372
+ <li class="md-nav__item">
3373
+ <a href="../rest-api/ui-related-endpoints.html" class="md-nav__link">
3374
+ UI Endpoints
3375
+ </a>
3376
+ </li>
3377
+
3378
+
3379
+
3380
+
2200
3381
  </ul>
2201
3382
  </nav>
2202
3383
  </li>
@@ -2215,17 +3396,17 @@
2215
3396
 
2216
3397
 
2217
3398
 
2218
- <input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_2_10" >
3399
+ <input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_2_11" >
2219
3400
 
2220
3401
 
2221
3402
 
2222
- <label class="md-nav__link" for="__nav_2_10" id="__nav_2_10_label" tabindex="0">
3403
+ <label class="md-nav__link" for="__nav_2_11" id="__nav_2_11_label" tabindex="0">
2223
3404
  GraphQL API
2224
3405
  <span class="md-nav__icon md-icon"></span>
2225
3406
  </label>
2226
3407
 
2227
- <nav class="md-nav" data-md-level="2" aria-labelledby="__nav_2_10_label" aria-expanded="false">
2228
- <label class="md-nav__title" for="__nav_2_10">
3408
+ <nav class="md-nav" data-md-level="2" aria-labelledby="__nav_2_11_label" aria-expanded="false">
3409
+ <label class="md-nav__title" for="__nav_2_11">
2229
3410
  <span class="md-nav__icon md-icon"></span>
2230
3411
  GraphQL API
2231
3412
  </label>
@@ -3265,8 +4446,8 @@
3265
4446
  </li>
3266
4447
 
3267
4448
  <li class="md-nav__item">
3268
- <a href="#commit_default" class="md-nav__link">
3269
- commit_default
4449
+ <a href="#dryrun_default" class="md-nav__link">
4450
+ dryrun_default
3270
4451
  </a>
3271
4452
 
3272
4453
  </li>
@@ -3373,6 +4554,13 @@
3373
4554
  BooleanVar
3374
4555
  </a>
3375
4556
 
4557
+ </li>
4558
+
4559
+ <li class="md-nav__item">
4560
+ <a href="#dryrunvar" class="md-nav__link">
4561
+ DryRunVar
4562
+ </a>
4563
+
3376
4564
  </li>
3377
4565
 
3378
4566
  <li class="md-nav__item">
@@ -3444,29 +4632,22 @@
3444
4632
  </li>
3445
4633
 
3446
4634
  <li class="md-nav__item">
3447
- <a href="#the-test_-methods" class="md-nav__link">
3448
- The test_*() Methods
3449
- </a>
3450
-
3451
- </li>
3452
-
3453
- <li class="md-nav__item">
3454
- <a href="#the-post_run-method" class="md-nav__link">
3455
- The post_run() Method
4635
+ <a href="#logging" class="md-nav__link">
4636
+ Logging
3456
4637
  </a>
3457
4638
 
3458
4639
  </li>
3459
4640
 
3460
4641
  <li class="md-nav__item">
3461
- <a href="#logging" class="md-nav__link">
3462
- Logging
4642
+ <a href="#marking-a-job-as-failed" class="md-nav__link">
4643
+ Marking a Job as Failed
3463
4644
  </a>
3464
4645
 
3465
4646
  </li>
3466
4647
 
3467
4648
  <li class="md-nav__item">
3468
- <a href="#accessing-request-data" class="md-nav__link">
3469
- Accessing Request Data
4649
+ <a href="#accessing-user-and-job-result" class="md-nav__link">
4650
+ Accessing User and Job Result
3470
4651
  </a>
3471
4652
 
3472
4653
  </li>
@@ -3586,9 +4767,22 @@
3586
4767
 
3587
4768
  </li>
3588
4769
 
4770
+ </ul>
4771
+ </nav>
4772
+
4773
+ </li>
4774
+
4775
+ <li class="md-nav__item">
4776
+ <a href="#debugging-job-performance" class="md-nav__link">
4777
+ Debugging job performance
4778
+ </a>
4779
+
4780
+ <nav class="md-nav" aria-label="Debugging job performance">
4781
+ <ul class="md-nav__list">
4782
+
3589
4783
  <li class="md-nav__item">
3590
- <a href="#nautobot-132-and-earlier-including-12" class="md-nav__link">
3591
- Nautobot 1.3.2 and earlier (including 1.2)
4784
+ <a href="#reading-profiling-reports" class="md-nav__link">
4785
+ Reading profiling reports
3592
4786
  </a>
3593
4787
 
3594
4788
  </li>
@@ -3607,8 +4801,8 @@
3607
4801
  <ul class="md-nav__list">
3608
4802
 
3609
4803
  <li class="md-nav__item">
3610
- <a href="#creating-objects-for-a-planned-site" class="md-nav__link">
3611
- Creating objects for a planned site
4804
+ <a href="#creating-objects-for-a-planned-location" class="md-nav__link">
4805
+ Creating objects for a planned location
3612
4806
  </a>
3613
4807
 
3614
4808
  </li>
@@ -3654,9 +4848,13 @@
3654
4848
  <li>Check and report whether all IP addresses have a parent prefix</li>
3655
4849
  </ul>
3656
4850
  <p>...and so on. Jobs are Python code and exist outside of the official Nautobot code base, so they can be updated and changed without interfering with the core Nautobot installation. And because they're completely customizable, there's practically no limit to what a job can accomplish.</p>
4851
+ <div class="admonition version-changed">
4852
+ <p class="admonition-title">Changed in version 2.0.0</p>
4853
+ <p>Backwards compatibility with NetBox scripts and reports has been removed. This includes removal of automatic calls to the <code>post_run()</code> and <code>test_*()</code> methods.</p>
4854
+ </div>
3657
4855
  <div class="admonition note">
3658
4856
  <p class="admonition-title">Note</p>
3659
- <p>Jobs unify and supersede the functionality previously provided in NetBox by "custom scripts" and "reports". Jobs are backwards-compatible for now with the <code>Script</code> and <code>Report</code> class APIs, but you are urged to move to the new <code>Job</code> class API described below. Jobs may be optionally marked as <a href="#read_only">read-only</a> which equates to the <code>Report</code> functionally, but in all cases, user input is supported via <a href="#variables">job variables</a>.</p>
4857
+ <p>Jobs unify and supersede the functionality previously provided in NetBox by "custom scripts" and "reports". User input is supported via <a href="#variables">job variables</a>.</p>
3660
4858
  </div>
3661
4859
  <h2 id="writing-jobs">Writing Jobs<a class="headerlink" href="#writing-jobs" title="Permanent link">&para;</a></h2>
3662
4860
  <p>Jobs may be installed in one of three ways:</p>
@@ -3678,34 +4876,34 @@
3678
4876
  </ul>
3679
4877
  <p>In any case, each module holds one or more Jobs (Python classes), each of which serves a specific purpose. The logic of each job can be split into a number of distinct methods, each of which performs a discrete portion of the overall job logic.</p>
3680
4878
  <p>For example, we can create a module named <code>devices.py</code> to hold all of our jobs which pertain to devices in Nautobot. Within that module, we might define several jobs. Each job is defined as a Python class inheriting from <code>extras.jobs.Job</code>, which provides the base functionality needed to accept user input and log activity.</p>
4879
+ <div class="admonition version-changed">
4880
+ <p class="admonition-title">Changed in version 2.0.0</p>
4881
+ <p>All job classes must now be registered with <code>nautobot.core.celery.register_jobs</code> on module import. For plugins providing jobs, the module containing the jobs must be imported by the plugin's <code>__init__.py</code> and the <code>register_jobs</code> method called at import time. The <code>register_jobs</code> method accepts one or more job classes as arguments.</p>
4882
+ </div>
3681
4883
  <div class="admonition warning">
3682
4884
  <p class="admonition-title">Warning</p>
3683
4885
  <p>Make sure you are <em>not</em> inheriting <code>extras.jobs.models.Job</code> instead, otherwise Django will think you want to define a new database model.</p>
3684
4886
  </div>
3685
- <div class="highlight"><pre><span></span><code><a id="__codelineno-0-1" name="__codelineno-0-1" href="#__codelineno-0-1"></a><span class="kn">from</span> <span class="nn">nautobot.extras.jobs</span> <span class="kn">import</span> <span class="n">Job</span>
3686
- <a id="__codelineno-0-2" name="__codelineno-0-2" href="#__codelineno-0-2"></a>
3687
- <a id="__codelineno-0-3" name="__codelineno-0-3" href="#__codelineno-0-3"></a><span class="k">class</span> <span class="nc">CreateDevices</span><span class="p">(</span><span class="n">Job</span><span class="p">):</span>
3688
- <a id="__codelineno-0-4" name="__codelineno-0-4" href="#__codelineno-0-4"></a> <span class="o">...</span>
3689
- <a id="__codelineno-0-5" name="__codelineno-0-5" href="#__codelineno-0-5"></a>
3690
- <a id="__codelineno-0-6" name="__codelineno-0-6" href="#__codelineno-0-6"></a><span class="k">class</span> <span class="nc">DeviceConnectionsReport</span><span class="p">(</span><span class="n">Job</span><span class="p">):</span>
3691
- <a id="__codelineno-0-7" name="__codelineno-0-7" href="#__codelineno-0-7"></a> <span class="o">...</span>
3692
- <a id="__codelineno-0-8" name="__codelineno-0-8" href="#__codelineno-0-8"></a>
3693
- <a id="__codelineno-0-9" name="__codelineno-0-9" href="#__codelineno-0-9"></a><span class="k">class</span> <span class="nc">DeviceIPsReport</span><span class="p">(</span><span class="n">Job</span><span class="p">):</span>
3694
- <a id="__codelineno-0-10" name="__codelineno-0-10" href="#__codelineno-0-10"></a> <span class="o">...</span>
4887
+ <div class="highlight"><pre><span></span><code><a id="__codelineno-0-1" name="__codelineno-0-1" href="#__codelineno-0-1"></a><span class="kn">from</span> <span class="nn">nautobot.core.celery</span> <span class="kn">import</span> <span class="n">register_jobs</span>
4888
+ <a id="__codelineno-0-2" name="__codelineno-0-2" href="#__codelineno-0-2"></a><span class="kn">from</span> <span class="nn">nautobot.extras.jobs</span> <span class="kn">import</span> <span class="n">Job</span>
4889
+ <a id="__codelineno-0-3" name="__codelineno-0-3" href="#__codelineno-0-3"></a>
4890
+ <a id="__codelineno-0-4" name="__codelineno-0-4" href="#__codelineno-0-4"></a><span class="k">class</span> <span class="nc">CreateDevices</span><span class="p">(</span><span class="n">Job</span><span class="p">):</span>
4891
+ <a id="__codelineno-0-5" name="__codelineno-0-5" href="#__codelineno-0-5"></a> <span class="o">...</span>
4892
+ <a id="__codelineno-0-6" name="__codelineno-0-6" href="#__codelineno-0-6"></a>
4893
+ <a id="__codelineno-0-7" name="__codelineno-0-7" href="#__codelineno-0-7"></a><span class="k">class</span> <span class="nc">DeviceConnectionsReport</span><span class="p">(</span><span class="n">Job</span><span class="p">):</span>
4894
+ <a id="__codelineno-0-8" name="__codelineno-0-8" href="#__codelineno-0-8"></a> <span class="o">...</span>
4895
+ <a id="__codelineno-0-9" name="__codelineno-0-9" href="#__codelineno-0-9"></a>
4896
+ <a id="__codelineno-0-10" name="__codelineno-0-10" href="#__codelineno-0-10"></a><span class="k">class</span> <span class="nc">DeviceIPsReport</span><span class="p">(</span><span class="n">Job</span><span class="p">):</span>
4897
+ <a id="__codelineno-0-11" name="__codelineno-0-11" href="#__codelineno-0-11"></a> <span class="o">...</span>
4898
+ <a id="__codelineno-0-12" name="__codelineno-0-12" href="#__codelineno-0-12"></a>
4899
+ <a id="__codelineno-0-13" name="__codelineno-0-13" href="#__codelineno-0-13"></a><span class="n">register_jobs</span><span class="p">(</span><span class="n">CreateDevices</span><span class="p">,</span> <span class="n">DeviceConnectionsReport</span><span class="p">,</span> <span class="n">DeviceIPsReport</span><span class="p">)</span>
3695
4900
  </code></pre></div>
3696
4901
  <p>Each job class will implement some or all of the following components:</p>
3697
4902
  <ul>
3698
4903
  <li>Module and class attributes, providing for default behavior, documentation and discoverability</li>
3699
4904
  <li>a set of variables for user input via the Nautobot UI (if your job requires any user inputs)</li>
3700
- <li>a <code>run()</code> method, which is executed first and receives the user input values, if any</li>
3701
- <li>any number of <code>test_*()</code> methods, which will be invoked next in order of declaration. Log messages generated by the job will be grouped together by the test method they were invoked from.</li>
3702
- <li>a <code>post_run()</code> method, which is executed last and can be used to handle any necessary cleanup or final events (such as sending an email or triggering a webhook). The status of the overall job is available at this time as <code>self.failed</code> and the <code>JobResult</code> data object is available as <code>self.result</code>.</li>
4905
+ <li>a <code>run()</code> method, which is the only required attribute on a Job class and receives the user input values, if any</li>
3703
4906
  </ul>
3704
- <p>You can implement the entire job within the <code>run()</code> function, but for more complex jobs, you may want to provide more granularity in the output and logging of activity. For this purpose, you can implement portions of the logic as <code>test_*()</code> methods (i.e., methods whose name begins with <code>test_*</code>) and/or a <code>post_run()</code> method. Log messages generated by the job logging APIs (more below on this topic) will be grouped together according to their base method (<code>run</code>, <code>test_a</code>, <code>test_b</code>, ..., <code>post_run</code>) which can aid in understanding the operation of the job.</p>
3705
- <div class="admonition note">
3706
- <p class="admonition-title">Note</p>
3707
- <p>Your job can of course define additional Python methods to compartmentalize and reuse logic as required; however the <code>run</code>, <code>test_*</code>, and <code>post_run</code> methods are the only ones that will be automatically invoked by Nautobot.</p>
3708
- </div>
3709
4907
  <p>It's important to understand that jobs execute on the server asynchronously as background tasks; they log messages and report their status to the database by updating <a href="../models/extras/jobresult.html"><code>JobResult</code></a> records and creating <a href="../models/extras/joblogentry.html"><code>JobLogEntry</code></a> records.</p>
3710
4908
  <div class="admonition note">
3711
4909
  <p class="admonition-title">Note</p>
@@ -3744,12 +4942,16 @@ This can accept either plain text or Markdown-formatted text. It can also be mul
3744
4942
  <h4 id="approval_required"><code>approval_required</code><a class="headerlink" href="#approval_required" title="Permanent link">&para;</a></h4>
3745
4943
  <p>Default: <code>False</code></p>
3746
4944
  <p>A boolean that will mark this job as requiring approval from another user to be run. For more details on approvals, <a href="job-scheduling-and-approvals.html">please refer to the section on scheduling and approvals</a>.</p>
3747
- <h4 id="commit_default"><code>commit_default</code><a class="headerlink" href="#commit_default" title="Permanent link">&para;</a></h4>
3748
- <p>Default: <code>True</code></p>
3749
- <p>The checkbox to commit database changes when executing a job is checked by default in the Nautobot UI. You can set <code>commit_default</code> to <code>False</code> under the <code>Meta</code> class if you want this option to instead be unchecked by default.</p>
4945
+ <h4 id="dryrun_default"><code>dryrun_default</code><a class="headerlink" href="#dryrun_default" title="Permanent link">&para;</a></h4>
4946
+ <div class="admonition version-changed">
4947
+ <p class="admonition-title">Changed in version 2.0.0</p>
4948
+ <p>The <code>commit_default</code> field was renamed to <code>dryrun_default</code> and the default value was changed from <code>True</code> to <code>False</code>. The <code>commit</code> functionality that provided an automatic rollback of database changes if the job failed was removed. The <code>dryrun</code> functionality was added to provide a way to bypass job approval if a job implements a <a href="#dryrunvar"><code>DryRunVar</code></a>.</p>
4949
+ </div>
4950
+ <p>Default: <code>False</code></p>
4951
+ <p>The checkbox to enable dryrun when executing a job is unchecked by default in the Nautobot UI. You can set <code>dryrun_default</code> to <code>True</code> under the <code>Meta</code> class if you want this option to instead be checked by default.</p>
3750
4952
  <div class="highlight"><pre><span></span><code><a id="__codelineno-2-1" name="__codelineno-2-1" href="#__codelineno-2-1"></a><span class="k">class</span> <span class="nc">MyJob</span><span class="p">(</span><span class="n">Job</span><span class="p">):</span>
3751
4953
  <a id="__codelineno-2-2" name="__codelineno-2-2" href="#__codelineno-2-2"></a> <span class="k">class</span> <span class="nc">Meta</span><span class="p">:</span>
3752
- <a id="__codelineno-2-3" name="__codelineno-2-3" href="#__codelineno-2-3"></a> <span class="n">commit_default</span> <span class="o">=</span> <span class="kc">False</span>
4954
+ <a id="__codelineno-2-3" name="__codelineno-2-3" href="#__codelineno-2-3"></a> <span class="n">dryrun_default</span> <span class="o">=</span> <span class="kc">True</span>
3753
4955
  </code></pre></div>
3754
4956
  <h4 id="field_order"><code>field_order</code><a class="headerlink" href="#field_order" title="Permanent link">&para;</a></h4>
3755
4957
  <p>Default: <code>[]</code></p>
@@ -3781,8 +4983,12 @@ This can accept either plain text or Markdown-formatted text. It can also be mul
3781
4983
  <div class="admonition version-added">
3782
4984
  <p class="admonition-title">Added in version 1.1.0</p>
3783
4985
  </div>
4986
+ <div class="admonition version-changed">
4987
+ <p class="admonition-title">Changed in version 2.0.0</p>
4988
+ <p>The <code>read_only</code> flag no longer changes the behavior of Nautobot core and is up to the job author to decide whether their job should be considered read only.</p>
4989
+ </div>
3784
4990
  <p>Default: <code>False</code></p>
3785
- <p>A boolean that designates whether the job is able to make changes to data in the database. The value defaults to <code>False</code> but when set to <code>True</code>, any data modifications executed from the job's code will be automatically aborted at the end of the job. The job input form is also modified to remove the <code>commit</code> checkbox as it is irrelevant for read-only jobs. When a job is marked as read-only, log messages that are normally automatically emitted about the DB transaction state are not included because no changes to data are allowed. Note that user input may still be optionally collected with read-only jobs via job variables, as described below.</p>
4991
+ <p>A boolean that can be set by the job author to indicate that the job does not make any changes to the environment. What behavior makes each job "read only" is up to the individual job author to decide. Note that user input may still be optionally collected with read-only jobs via job variables, as described below.</p>
3786
4992
  <h4 id="soft_time_limit"><code>soft_time_limit</code><a class="headerlink" href="#soft_time_limit" title="Permanent link">&para;</a></h4>
3787
4993
  <div class="admonition version-added">
3788
4994
  <p class="admonition-title">Added in version 1.3.0</p>
@@ -3798,7 +5004,7 @@ This can accept either plain text or Markdown-formatted text. It can also be mul
3798
5004
  <a id="__codelineno-3-7" name="__codelineno-3-7" href="#__codelineno-3-7"></a> <span class="n">description</span> <span class="o">=</span> <span class="s2">&quot;Set a soft time limit of 10 seconds`&quot;</span>
3799
5005
  <a id="__codelineno-3-8" name="__codelineno-3-8" href="#__codelineno-3-8"></a> <span class="n">soft_time_limit</span> <span class="o">=</span> <span class="mi">10</span>
3800
5006
  <a id="__codelineno-3-9" name="__codelineno-3-9" href="#__codelineno-3-9"></a>
3801
- <a id="__codelineno-3-10" name="__codelineno-3-10" href="#__codelineno-3-10"></a> <span class="k">def</span> <span class="nf">run</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">data</span><span class="p">,</span> <span class="n">commit</span><span class="p">):</span>
5007
+ <a id="__codelineno-3-10" name="__codelineno-3-10" href="#__codelineno-3-10"></a> <span class="k">def</span> <span class="nf">run</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
3802
5008
  <a id="__codelineno-3-11" name="__codelineno-3-11" href="#__codelineno-3-11"></a> <span class="k">try</span><span class="p">:</span>
3803
5009
  <a id="__codelineno-3-12" name="__codelineno-3-12" href="#__codelineno-3-12"></a> <span class="c1"># code which might take longer than 10 seconds to run</span>
3804
5010
  <a id="__codelineno-3-13" name="__codelineno-3-13" href="#__codelineno-3-13"></a> <span class="n">job_code</span><span class="p">()</span>
@@ -3853,7 +5059,7 @@ default <a href="../configuration/optional-settings.html#celery_task_time_limit"
3853
5059
  <a id="__codelineno-5-6" name="__codelineno-5-6" href="#__codelineno-5-6"></a> <span class="n">description</span> <span class="o">=</span> <span class="s2">&quot;Set a hard time limit of 10 seconds`&quot;</span>
3854
5060
  <a id="__codelineno-5-7" name="__codelineno-5-7" href="#__codelineno-5-7"></a> <span class="n">time_limit</span> <span class="o">=</span> <span class="mi">10</span>
3855
5061
  <a id="__codelineno-5-8" name="__codelineno-5-8" href="#__codelineno-5-8"></a>
3856
- <a id="__codelineno-5-9" name="__codelineno-5-9" href="#__codelineno-5-9"></a> <span class="k">def</span> <span class="nf">run</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">data</span><span class="p">,</span> <span class="n">commit</span><span class="p">):</span>
5062
+ <a id="__codelineno-5-9" name="__codelineno-5-9" href="#__codelineno-5-9"></a> <span class="k">def</span> <span class="nf">run</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
3857
5063
  <a id="__codelineno-5-10" name="__codelineno-5-10" href="#__codelineno-5-10"></a> <span class="c1"># code which might take longer than 10 seconds to run</span>
3858
5064
  <a id="__codelineno-5-11" name="__codelineno-5-11" href="#__codelineno-5-11"></a> <span class="c1"># this code will fail silently if the time_limit is exceeded</span>
3859
5065
  <a id="__codelineno-5-12" name="__codelineno-5-12" href="#__codelineno-5-12"></a> <span class="n">job_code</span><span class="p">()</span>
@@ -3871,7 +5077,7 @@ default <a href="../configuration/optional-settings.html#celery_task_time_limit"
3871
5077
  <a id="__codelineno-6-5" name="__codelineno-6-5" href="#__codelineno-6-5"></a> <span class="n">var2</span> <span class="o">=</span> <span class="n">IntegerVar</span><span class="p">(</span><span class="o">...</span><span class="p">)</span>
3872
5078
  <a id="__codelineno-6-6" name="__codelineno-6-6" href="#__codelineno-6-6"></a> <span class="n">var3</span> <span class="o">=</span> <span class="n">ObjectVar</span><span class="p">(</span><span class="o">...</span><span class="p">)</span>
3873
5079
  <a id="__codelineno-6-7" name="__codelineno-6-7" href="#__codelineno-6-7"></a>
3874
- <a id="__codelineno-6-8" name="__codelineno-6-8" href="#__codelineno-6-8"></a> <span class="k">def</span> <span class="nf">run</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">data</span><span class="p">,</span> <span class="n">commit</span><span class="p">):</span>
5080
+ <a id="__codelineno-6-8" name="__codelineno-6-8" href="#__codelineno-6-8"></a> <span class="k">def</span> <span class="nf">run</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">var1</span><span class="p">,</span> <span class="n">var2</span><span class="p">,</span> <span class="n">var3</span><span class="p">):</span>
3875
5081
  <a id="__codelineno-6-9" name="__codelineno-6-9" href="#__codelineno-6-9"></a> <span class="o">...</span>
3876
5082
  </code></pre></div>
3877
5083
  <p>The remainder of this section documents the various supported variable types and how to make use of them.</p>
@@ -3902,6 +5108,8 @@ default <a href="../configuration/optional-settings.html#celery_task_time_limit"
3902
5108
  </ul>
3903
5109
  <h4 id="booleanvar"><code>BooleanVar</code><a class="headerlink" href="#booleanvar" title="Permanent link">&para;</a></h4>
3904
5110
  <p>A true/false flag. This field has no options beyond the defaults listed above.</p>
5111
+ <h4 id="dryrunvar"><code>DryRunVar</code><a class="headerlink" href="#dryrunvar" title="Permanent link">&para;</a></h4>
5112
+ <p>A true/false flag with special handling for jobs that require approval. If <code>dryrun = DryRunVar()</code> is declared on a job class, approval may be bypassed if <code>dryrun</code> is set to <code>True</code> on job execution.</p>
3905
5113
  <h4 id="choicevar"><code>ChoiceVar</code><a class="headerlink" href="#choicevar" title="Permanent link">&para;</a></h4>
3906
5114
  <p>A set of choices from which the user can select one.</p>
3907
5115
  <ul>
@@ -3941,18 +5149,18 @@ default <a href="../configuration/optional-settings.html#celery_task_time_limit"
3941
5149
  <a id="__codelineno-9-5" name="__codelineno-9-5" href="#__codelineno-9-5"></a> <span class="p">}</span>
3942
5150
  <a id="__codelineno-9-6" name="__codelineno-9-6" href="#__codelineno-9-6"></a><span class="p">)</span>
3943
5151
  </code></pre></div>
3944
- <p>Multiple values can be specified by assigning a list to the dictionary key. It is also possible to reference the value of other fields in the form by prepending a dollar sign (<code>$</code>) to the variable's name. The keys you can use in this dictionary are the same ones that are available in the REST API - as an example it is also possible to filter the <code>Site</code> <code>ObjectVar</code> for its <code>tenant_group</code>.</p>
3945
- <div class="highlight"><pre><span></span><code><a id="__codelineno-10-1" name="__codelineno-10-1" href="#__codelineno-10-1"></a><span class="n">region</span> <span class="o">=</span> <span class="n">ObjectVar</span><span class="p">(</span>
3946
- <a id="__codelineno-10-2" name="__codelineno-10-2" href="#__codelineno-10-2"></a> <span class="n">model</span><span class="o">=</span><span class="n">Region</span>
5152
+ <p>Multiple values can be specified by assigning a list to the dictionary key. It is also possible to reference the value of other fields in the form by prepending a dollar sign (<code>$</code>) to the variable's name. The keys you can use in this dictionary are the same ones that are available in the REST API - as an example it is also possible to filter the <code>Location</code> <code>ObjectVar</code> for its <code>location_type</code> and <code>tenant_group</code>.</p>
5153
+ <div class="highlight"><pre><span></span><code><a id="__codelineno-10-1" name="__codelineno-10-1" href="#__codelineno-10-1"></a><span class="n">location_type</span> <span class="o">=</span> <span class="n">ObjectVar</span><span class="p">(</span>
5154
+ <a id="__codelineno-10-2" name="__codelineno-10-2" href="#__codelineno-10-2"></a> <span class="n">model</span><span class="o">=</span><span class="n">LocationType</span>
3947
5155
  <a id="__codelineno-10-3" name="__codelineno-10-3" href="#__codelineno-10-3"></a><span class="p">)</span>
3948
5156
  <a id="__codelineno-10-4" name="__codelineno-10-4" href="#__codelineno-10-4"></a><span class="n">tenant_group</span> <span class="o">=</span> <span class="n">ObjectVar</span><span class="p">(</span>
3949
5157
  <a id="__codelineno-10-5" name="__codelineno-10-5" href="#__codelineno-10-5"></a> <span class="n">model</span><span class="o">=</span><span class="n">TenantGroup</span>
3950
5158
  <a id="__codelineno-10-6" name="__codelineno-10-6" href="#__codelineno-10-6"></a><span class="p">)</span>
3951
- <a id="__codelineno-10-7" name="__codelineno-10-7" href="#__codelineno-10-7"></a><span class="n">site</span> <span class="o">=</span> <span class="n">ObjectVar</span><span class="p">(</span>
3952
- <a id="__codelineno-10-8" name="__codelineno-10-8" href="#__codelineno-10-8"></a> <span class="n">model</span><span class="o">=</span><span class="n">Site</span><span class="p">,</span>
5159
+ <a id="__codelineno-10-7" name="__codelineno-10-7" href="#__codelineno-10-7"></a><span class="n">location</span> <span class="o">=</span> <span class="n">ObjectVar</span><span class="p">(</span>
5160
+ <a id="__codelineno-10-8" name="__codelineno-10-8" href="#__codelineno-10-8"></a> <span class="n">model</span><span class="o">=</span><span class="n">Location</span><span class="p">,</span>
3953
5161
  <a id="__codelineno-10-9" name="__codelineno-10-9" href="#__codelineno-10-9"></a> <span class="n">query_params</span><span class="o">=</span><span class="p">{</span>
3954
- <a id="__codelineno-10-10" name="__codelineno-10-10" href="#__codelineno-10-10"></a> <span class="s1">&#39;region&#39;</span><span class="p">:</span> <span class="s1">&#39;$region&#39;</span><span class="p">,</span>
3955
- <a id="__codelineno-10-11" name="__codelineno-10-11" href="#__codelineno-10-11"></a> <span class="s1">&#39;tenant_group&#39;</span><span class="p">:</span> <span class="s1">&#39;$tenant_group&#39;</span>
5162
+ <a id="__codelineno-10-10" name="__codelineno-10-10" href="#__codelineno-10-10"></a> <span class="s2">&quot;location_type&quot;</span><span class="p">:</span> <span class="s2">&quot;$location_type&quot;</span><span class="p">,</span>
5163
+ <a id="__codelineno-10-11" name="__codelineno-10-11" href="#__codelineno-10-11"></a> <span class="s2">&quot;tenant_group&quot;</span><span class="p">:</span> <span class="s2">&quot;$tenant_group&quot;</span>
3956
5164
  <a id="__codelineno-10-12" name="__codelineno-10-12" href="#__codelineno-10-12"></a> <span class="p">}</span>
3957
5165
  <a id="__codelineno-10-13" name="__codelineno-10-13" href="#__codelineno-10-13"></a><span class="p">)</span>
3958
5166
  </code></pre></div>
@@ -3971,11 +5179,7 @@ default <a href="../configuration/optional-settings.html#celery_task_time_limit"
3971
5179
  <li><code>max_prefix_length</code> - Maximum length of the mask</li>
3972
5180
  </ul>
3973
5181
  <h3 id="the-run-method">The <code>run()</code> Method<a class="headerlink" href="#the-run-method" title="Permanent link">&para;</a></h3>
3974
- <p>The <code>run()</code> method, if you choose to implement it, should accept two arguments:</p>
3975
- <ol>
3976
- <li><code>data</code> - A dictionary which will contain all of the variable data passed in by the user (via the web UI or REST API)</li>
3977
- <li><code>commit</code> - A boolean indicating whether database changes should be committed. If this is <code>False</code>, even if your Job attempts to make database changes, they will be automatically rolled back when the Job completes.</li>
3978
- </ol>
5182
+ <p>The <code>run()</code> method must be implemented. After the <code>self</code> argument, it should accept keyword arguments for any variables defined on the job:</p>
3979
5183
  <div class="highlight"><pre><span></span><code><a id="__codelineno-11-1" name="__codelineno-11-1" href="#__codelineno-11-1"></a><span class="kn">from</span> <span class="nn">nautobot.extras.jobs</span> <span class="kn">import</span> <span class="n">Job</span><span class="p">,</span> <span class="n">StringVar</span><span class="p">,</span> <span class="n">IntegerVar</span><span class="p">,</span> <span class="n">ObjectVar</span>
3980
5184
  <a id="__codelineno-11-2" name="__codelineno-11-2" href="#__codelineno-11-2"></a>
3981
5185
  <a id="__codelineno-11-3" name="__codelineno-11-3" href="#__codelineno-11-3"></a><span class="k">class</span> <span class="nc">CreateDevices</span><span class="p">(</span><span class="n">Job</span><span class="p">):</span>
@@ -3983,18 +5187,10 @@ default <a href="../configuration/optional-settings.html#celery_task_time_limit"
3983
5187
  <a id="__codelineno-11-5" name="__codelineno-11-5" href="#__codelineno-11-5"></a> <span class="n">var2</span> <span class="o">=</span> <span class="n">IntegerVar</span><span class="p">(</span><span class="o">...</span><span class="p">)</span>
3984
5188
  <a id="__codelineno-11-6" name="__codelineno-11-6" href="#__codelineno-11-6"></a> <span class="n">var3</span> <span class="o">=</span> <span class="n">ObjectVar</span><span class="p">(</span><span class="o">...</span><span class="p">)</span>
3985
5189
  <a id="__codelineno-11-7" name="__codelineno-11-7" href="#__codelineno-11-7"></a>
3986
- <a id="__codelineno-11-8" name="__codelineno-11-8" href="#__codelineno-11-8"></a> <span class="k">def</span> <span class="nf">run</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">data</span><span class="p">,</span> <span class="n">commit</span><span class="p">):</span>
5190
+ <a id="__codelineno-11-8" name="__codelineno-11-8" href="#__codelineno-11-8"></a> <span class="k">def</span> <span class="nf">run</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">var1</span><span class="p">,</span> <span class="n">var2</span><span class="p">,</span> <span class="n">var3</span><span class="p">):</span>
3987
5191
  <a id="__codelineno-11-9" name="__codelineno-11-9" href="#__codelineno-11-9"></a> <span class="o">...</span>
3988
5192
  </code></pre></div>
3989
- <p>Again, defining user variables is totally optional; you may create a job with just a <code>run()</code> method if no user input is needed, in which case <code>data</code> will be an empty dictionary.</p>
3990
- <div class="admonition note">
3991
- <p class="admonition-title">Note</p>
3992
- <p>The <code>test_*()</code> and <code>post_run()</code> methods do not accept any arguments; if you need to access user <code>data</code> or the <code>commit</code> flag, your <code>run()</code> method is responsible for storing these values in the job instance, such as:</p>
3993
- <div class="highlight"><pre><span></span><code><a id="__codelineno-12-1" name="__codelineno-12-1" href="#__codelineno-12-1"></a>def run(self, data, commit):
3994
- <a id="__codelineno-12-2" name="__codelineno-12-2" href="#__codelineno-12-2"></a> self.data = data
3995
- <a id="__codelineno-12-3" name="__codelineno-12-3" href="#__codelineno-12-3"></a> self.commit = commit
3996
- </code></pre></div>
3997
- </div>
5193
+ <p>Again, defining user variables is totally optional; you may create a job with a <code>run()</code> method with only the <code>self</code> argument if no user input is needed.</p>
3998
5194
  <div class="admonition warning">
3999
5195
  <p class="admonition-title">Warning</p>
4000
5196
  <p>When writing Jobs that create and manipulate data it is recommended to make use of the <code>validated_save()</code> convenience method which exists on all core models. This method saves the instance data but first enforces model validation logic. Simply calling <code>save()</code> on the model instance <strong>does not</strong> enforce validation automatically and may lead to bad data. See the development <a href="../development/best-practices.html">best practices</a>.</p>
@@ -4003,44 +5199,74 @@ default <a href="../configuration/optional-settings.html#celery_task_time_limit"
4003
5199
  <p class="admonition-title">Warning</p>
4004
5200
  <p>The Django ORM provides methods to create/edit many objects at once, namely <code>bulk_create()</code> and <code>update()</code>. These are best avoided in most cases as they bypass a model's built-in validation and can easily lead to database corruption if not used carefully.</p>
4005
5201
  </div>
4006
- <h3 id="the-test_-methods">The <code>test_*()</code> Methods<a class="headerlink" href="#the-test_-methods" title="Permanent link">&para;</a></h3>
4007
- <p>If your job class defines any number of methods whose names begin with <code>test_</code>, these will be automatically invoked after the <code>run()</code> method (if any) completes. These methods must take no arguments (other than <code>self</code>).</p>
4008
- <p>Log messages generated by any of these methods will be automatically grouped together by the test method they were invoked from, which can be helpful for readability.</p>
4009
- <h3 id="the-post_run-method">The <code>post_run()</code> Method<a class="headerlink" href="#the-post_run-method" title="Permanent link">&para;</a></h3>
4010
- <p>If your job class implements a <code>post_run()</code> method (which must take no arguments other than <code>self</code>), this method will be automatically invoked after the <code>run()</code> and <code>test_*()</code> methods (if any). It will be called even if one of the other methods raises an exception, so this method can be used to handle any necessary cleanup or final events (such as sending an email or triggering a webhook). The status of the overall job is available at this time as <code>self.failed</code> and the associated <a href="../models/extras/jobresult.html"><code>JobResult</code></a> <code>data</code> field is available as <code>self.results</code>.</p>
5202
+ <div class="admonition version-removed">
5203
+ <p class="admonition-title">Removed in version 2.0.0</p>
5204
+ <p>The NetBox backwards compatible <code>test_*()</code> and <code>post_run()</code> methods have been removed.</p>
5205
+ </div>
4011
5206
  <h3 id="logging">Logging<a class="headerlink" href="#logging" title="Permanent link">&para;</a></h3>
4012
- <p>The following instance methods are available to log results from an executing job to be stored into <a href="../models/extras/joblogentry.html"><code>JobLogEntry</code></a> records associated with the current <a href="../models/extras/jobresult.html"><code>JobResult</code></a>:</p>
4013
- <ul>
4014
- <li><code>self.log(message)</code></li>
4015
- <li><code>self.log_debug(message)</code></li>
4016
- <li><code>self.log_success(obj=None, message=None)</code></li>
4017
- <li><code>self.log_info(obj=None, message=None)</code></li>
4018
- <li><code>self.log_warning(obj=None, message=None)</code></li>
4019
- <li><code>self.log_failure(obj=None, message=None)</code></li>
4020
- </ul>
4021
- <p>Messages recorded with <code>log()</code> or <code>log_debug()</code> will appear in a job's results but are never associated with a particular object; the other <code>log_*</code> functions may be invoked with or without a provided object to associate the message with.</p>
4022
- <p>It is advised to log a message for each object that is evaluated so that the results will reflect how many objects are being manipulated or reported on.</p>
5207
+ <div class="admonition version-changed">
5208
+ <p class="admonition-title">Changed in version 2.0.0</p>
5209
+ </div>
5210
+ <p>Messages logged from a job's logger will be stored in <a href="../models/extras/joblogentry.html"><code>JobLogEntry</code></a> records associated with the current <a href="../models/extras/jobresult.html"><code>JobResult</code></a>.</p>
5211
+ <p>The logger can be accessed either by using the <code>logger</code> property on the job class or <code>nautobot.extras.jobs.get_task_logger(__name__)</code>. Both will return the same logger instance. For more information on the standard Python logging module, see the <a href="https://docs.python.org/3/library/logging.html">Python documentation</a>.</p>
5212
+ <p>An optional <code>grouping</code> and/or <code>object</code> may be provided in log messages by passing them in the log function call's <code>extra</code> kwarg. If a <code>grouping</code> is not provided it will default to the function name that logged the message. The <code>object</code> will default to <code>None</code>.</p>
5213
+ <div class="admonition example">
5214
+ <p class="admonition-title">Example</p>
5215
+ <div class="highlight"><pre><span></span><code><a id="__codelineno-12-1" name="__codelineno-12-1" href="#__codelineno-12-1"></a><span class="kn">from</span> <span class="nn">nautobot.extras.jobs</span> <span class="kn">import</span> <span class="n">BaseJob</span>
5216
+ <a id="__codelineno-12-2" name="__codelineno-12-2" href="#__codelineno-12-2"></a>
5217
+ <a id="__codelineno-12-3" name="__codelineno-12-3" href="#__codelineno-12-3"></a><span class="k">class</span> <span class="nc">MyJob</span><span class="p">(</span><span class="n">BaseJob</span><span class="p">):</span>
5218
+ <a id="__codelineno-12-4" name="__codelineno-12-4" href="#__codelineno-12-4"></a> <span class="k">def</span> <span class="nf">run</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
5219
+ <a id="__codelineno-12-5" name="__codelineno-12-5" href="#__codelineno-12-5"></a> <span class="n">logger</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="s2">&quot;This job is running!&quot;</span><span class="p">,</span> <span class="n">extra</span><span class="o">=</span><span class="p">{</span><span class="s2">&quot;grouping&quot;</span><span class="p">:</span> <span class="s2">&quot;myjobisrunning&quot;</span><span class="p">,</span> <span class="s2">&quot;object&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">job_result</span><span class="p">})</span>
5220
+ </code></pre></div>
5221
+ </div>
5222
+ <p>To skip writing a log entry to the database, set the <code>skip_db_logging</code> key in the "extra" kwarg to <code>True</code> when calling the log function. The output will still be written to the console.</p>
5223
+ <div class="admonition example">
5224
+ <p class="admonition-title">Example</p>
5225
+ <div class="highlight"><pre><span></span><code><a id="__codelineno-13-1" name="__codelineno-13-1" href="#__codelineno-13-1"></a><span class="kn">from</span> <span class="nn">nautobot.extras.jobs</span> <span class="kn">import</span> <span class="n">BaseJob</span>
5226
+ <a id="__codelineno-13-2" name="__codelineno-13-2" href="#__codelineno-13-2"></a>
5227
+ <a id="__codelineno-13-3" name="__codelineno-13-3" href="#__codelineno-13-3"></a><span class="k">class</span> <span class="nc">MyJob</span><span class="p">(</span><span class="n">BaseJob</span><span class="p">):</span>
5228
+ <a id="__codelineno-13-4" name="__codelineno-13-4" href="#__codelineno-13-4"></a> <span class="k">def</span> <span class="nf">run</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
5229
+ <a id="__codelineno-13-5" name="__codelineno-13-5" href="#__codelineno-13-5"></a> <span class="n">logger</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="s2">&quot;This job is running!&quot;</span><span class="p">,</span> <span class="n">extra</span><span class="o">=</span><span class="p">{</span><span class="s2">&quot;skip_db_logging&quot;</span><span class="p">:</span> <span class="kc">True</span><span class="p">})</span>
5230
+ </code></pre></div>
5231
+ </div>
4023
5232
  <p>Markdown rendering is supported for log messages.</p>
4024
5233
  <div class="admonition version-changed">
4025
5234
  <p class="admonition-title">Changed in version 1.3.4</p>
4026
5235
  <p>As a security measure, the <code>message</code> passed to any of these methods will be passed through the <code>nautobot.core.utils.logging.sanitize()</code> function in an attempt to strip out information such as usernames/passwords that should not be saved to the logs. This is of course best-effort only, and Job authors should take pains to ensure that such information is not passed to the logging APIs in the first place. The set of redaction rules used by the <code>sanitize()</code> function can be configured as <a href="../configuration/optional-settings.html#sanitizer_patterns">settings.SANITIZER_PATTERNS</a>.</p>
4027
5236
  </div>
4028
- <div class="admonition note">
4029
- <p class="admonition-title">Note</p>
4030
- <p>Using <code>self.log_failure()</code>, in addition to recording a log message, will flag the overall job as failed, but it will <strong>not</strong> stop the execution of the job, nor will it result in an automatic rollback of any database changes made by the job. To end a job early, you can use a Python <code>raise</code> or <code>return</code> as appropriate. Raising any exception (e.g. <code>ValueError</code> for malformed input values) will ensure that any database changes are rolled back as part of the process of ending the job. <code>AbortTransaction</code> from Nautobot, which was recommended in past versions of the docs, should explicitly <strong>not</strong> be used, as it is only intended for use by Nautobot's internal job handling.</p>
5237
+ <div class="admonition version-changed">
5238
+ <p class="admonition-title">Changed in version 2.0.0</p>
5239
+ <p>The Job class logging functions (example: <code>self.log(message)</code>, <code>self.log_success(obj=None, message=message)</code>, etc) have been removed. Also, the convenience method to mark a job as failed, <code>log_failure()</code>, has been removed. To replace the functionality of this method, you can log an error message with <code>self.logger.error()</code> and then raise an exception to fail the job. Note that it is no longer possible to manually set the job result status as failed without raising an exception in the job.</p>
4031
5240
  </div>
4032
5241
  <div class="admonition version-changed">
4033
5242
  <p class="admonition-title">Changed in version 2.0.0</p>
4034
5243
  <p>The <code>AbortTransaction</code> class was moved from the <code>nautobot.utilities.exceptions</code> module to <code>nautobot.core.exceptions</code>.</p>
4035
5244
  </div>
4036
- <h3 id="accessing-request-data">Accessing Request Data<a class="headerlink" href="#accessing-request-data" title="Permanent link">&para;</a></h3>
4037
- <p>Details of the current HTTP request (the one being made to execute the job) are available as the instance attribute <code>self.request</code>. This can be used to infer, for example, the user executing the job and their client IP address:</p>
4038
- <div class="highlight"><pre><span></span><code><a id="__codelineno-13-1" name="__codelineno-13-1" href="#__codelineno-13-1"></a><span class="n">username</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">request</span><span class="o">.</span><span class="n">user</span><span class="o">.</span><span class="n">username</span>
4039
- <a id="__codelineno-13-2" name="__codelineno-13-2" href="#__codelineno-13-2"></a><span class="n">ip_address</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">request</span><span class="o">.</span><span class="n">META</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;HTTP_X_FORWARDED_FOR&#39;</span><span class="p">)</span> <span class="ow">or</span> \
4040
- <a id="__codelineno-13-3" name="__codelineno-13-3" href="#__codelineno-13-3"></a> <span class="bp">self</span><span class="o">.</span><span class="n">request</span><span class="o">.</span><span class="n">META</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;REMOTE_ADDR&#39;</span><span class="p">)</span>
4041
- <a id="__codelineno-13-4" name="__codelineno-13-4" href="#__codelineno-13-4"></a><span class="bp">self</span><span class="o">.</span><span class="n">log_info</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Running as user </span><span class="si">{</span><span class="n">username</span><span class="si">}</span><span class="s2"> (IP: </span><span class="si">{</span><span class="n">ip_address</span><span class="si">}</span><span class="s2">)...&quot;</span><span class="p">)</span>
5245
+ <h3 id="marking-a-job-as-failed">Marking a Job as Failed<a class="headerlink" href="#marking-a-job-as-failed" title="Permanent link">&para;</a></h3>
5246
+ <p>To mark a job as failed, raise an exception from within the <code>run()</code> method. The exception message will be logged to the traceback of the job result. The job result status will be set to <code>failed</code>. To output a job log message you can use the <code>self.logger.error()</code> method.</p>
5247
+ <div class="highlight"><pre><span></span><code><a id="__codelineno-14-1" name="__codelineno-14-1" href="#__codelineno-14-1"></a><span class="n">As</span> <span class="n">an</span> <span class="n">example</span><span class="p">,</span> <span class="n">the</span> <span class="n">following</span> <span class="n">job</span> <span class="n">will</span> <span class="n">fail</span> <span class="k">if</span> <span class="n">the</span> <span class="n">user</span> <span class="n">does</span> <span class="ow">not</span> <span class="n">put</span> <span class="n">the</span> <span class="n">word</span> <span class="s2">&quot;Taco&quot;</span> <span class="ow">in</span> <span class="err">`</span><span class="n">var1</span><span class="err">`</span><span class="p">:</span>
5248
+ <a id="__codelineno-14-2" name="__codelineno-14-2" href="#__codelineno-14-2"></a>
5249
+ <a id="__codelineno-14-3" name="__codelineno-14-3" href="#__codelineno-14-3"></a><span class="err">```</span><span class="n">python</span>
5250
+ <a id="__codelineno-14-4" name="__codelineno-14-4" href="#__codelineno-14-4"></a><span class="kn">from</span> <span class="nn">nautobot.extras.jobs</span> <span class="kn">import</span> <span class="n">Job</span><span class="p">,</span> <span class="n">StringVar</span>
5251
+ <a id="__codelineno-14-5" name="__codelineno-14-5" href="#__codelineno-14-5"></a>
5252
+ <a id="__codelineno-14-6" name="__codelineno-14-6" href="#__codelineno-14-6"></a><span class="k">class</span> <span class="nc">MyJob</span><span class="p">(</span><span class="n">Job</span><span class="p">):</span>
5253
+ <a id="__codelineno-14-7" name="__codelineno-14-7" href="#__codelineno-14-7"></a> <span class="n">var1</span> <span class="o">=</span> <span class="n">StringVar</span><span class="p">(</span><span class="o">...</span><span class="p">)</span>
5254
+ <a id="__codelineno-14-8" name="__codelineno-14-8" href="#__codelineno-14-8"></a>
5255
+ <a id="__codelineno-14-9" name="__codelineno-14-9" href="#__codelineno-14-9"></a> <span class="k">def</span> <span class="nf">run</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">var1</span><span class="p">):</span>
5256
+ <a id="__codelineno-14-10" name="__codelineno-14-10" href="#__codelineno-14-10"></a> <span class="k">if</span> <span class="n">var1</span> <span class="o">!=</span> <span class="s2">&quot;Taco&quot;</span><span class="p">:</span>
5257
+ <a id="__codelineno-14-11" name="__codelineno-14-11" href="#__codelineno-14-11"></a> <span class="bp">self</span><span class="o">.</span><span class="n">logger</span><span class="o">.</span><span class="n">error</span><span class="p">(</span><span class="s2">&quot;var1 must be &#39;Taco&#39;&quot;</span><span class="p">)</span>
5258
+ <a id="__codelineno-14-12" name="__codelineno-14-12" href="#__codelineno-14-12"></a> <span class="k">raise</span> <span class="ne">Exception</span><span class="p">(</span><span class="s2">&quot;Argument input validation failed.&quot;</span><span class="p">)</span>
5259
+ </code></pre></div>
5260
+ <h3 id="accessing-user-and-job-result">Accessing User and Job Result<a class="headerlink" href="#accessing-user-and-job-result" title="Permanent link">&para;</a></h3>
5261
+ <div class="admonition version-changed">
5262
+ <p class="admonition-title">Changed in version 2.0.0</p>
5263
+ <p>The web request is no longer accessible to running jobs.</p>
5264
+ </div>
5265
+ <p>The user that initiated the job and the job result associated to the job can be accessed through properties on the job class:</p>
5266
+ <div class="highlight"><pre><span></span><code><a id="__codelineno-15-1" name="__codelineno-15-1" href="#__codelineno-15-1"></a><span class="n">username</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">user</span><span class="o">.</span><span class="n">username</span>
5267
+ <a id="__codelineno-15-2" name="__codelineno-15-2" href="#__codelineno-15-2"></a><span class="n">job_result_id</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">job_result</span><span class="o">.</span><span class="n">id</span>
5268
+ <a id="__codelineno-15-3" name="__codelineno-15-3" href="#__codelineno-15-3"></a><span class="bp">self</span><span class="o">.</span><span class="n">logger</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="s2">&quot;Job </span><span class="si">%s</span><span class="s2"> initiated by user </span><span class="si">%s</span><span class="s2"> is running.&quot;</span><span class="p">,</span> <span class="n">job_result_id</span><span class="p">,</span> <span class="n">username</span><span class="p">)</span>
4042
5269
  </code></pre></div>
4043
- <p>For a complete list of available request parameters, please see the <a href="https://docs.djangoproject.com/en/stable/ref/request-response/">Django documentation</a>.</p>
4044
5270
  <h3 id="reading-data-from-files">Reading Data from Files<a class="headerlink" href="#reading-data-from-files" title="Permanent link">&para;</a></h3>
4045
5271
  <p>The <code>Job</code> class provides two convenience methods for reading data from files:</p>
4046
5272
  <ul>
@@ -4064,10 +5290,9 @@ default <a href="../configuration/optional-settings.html#celery_task_time_limit"
4064
5290
  <li><code>name</code></li>
4065
5291
  <li><code>description</code></li>
4066
5292
  <li><code>approval_required</code></li>
4067
- <li><code>commit_default</code></li>
5293
+ <li><code>dryrun_default</code></li>
4068
5294
  <li><code>has_sensitive_variables</code></li>
4069
5295
  <li><code>hidden</code></li>
4070
- <li><code>read_only</code></li>
4071
5296
  <li><code>soft_time_limit</code></li>
4072
5297
  <li><code>time_limit</code></li>
4073
5298
  <li><code>task_queues</code></li>
@@ -4101,21 +5326,25 @@ elements will be important in running jobs programmatically.</p>
4101
5326
  <p>Jobs can be run via the web UI by navigating to the job, completing any required form data (if any), and clicking the "Run Job" button.</p>
4102
5327
  <p>Once a job has been run, the latest <a href="../models/extras/jobresult.html"><code>JobResult</code></a> for that job will be summarized in the job list view.</p>
4103
5328
  <h3 id="via-the-api">Via the API<a class="headerlink" href="#via-the-api" title="Permanent link">&para;</a></h3>
4104
- <p>To run a job via the REST API, issue a POST request to the job's endpoint <code>/api/extras/jobs/&lt;uuid&gt;/run/</code>. You can optionally provide JSON data to set the <code>commit</code> flag, specify any required user input <code>data</code>, optional <code>task_queue</code>, and/or provide optional scheduling information as described in <a href="job-scheduling-and-approvals.html">the section on scheduling and approvals</a>.</p>
4105
- <p>For example, to run a job with no user inputs and without committing any anything to the database:</p>
4106
- <div class="highlight"><pre><span></span><code><a id="__codelineno-14-1" name="__codelineno-14-1" href="#__codelineno-14-1"></a>curl -X POST \
4107
- <a id="__codelineno-14-2" name="__codelineno-14-2" href="#__codelineno-14-2"></a>-H &quot;Authorization: Token $TOKEN&quot; \
4108
- <a id="__codelineno-14-3" name="__codelineno-14-3" href="#__codelineno-14-3"></a>-H &quot;Content-Type: application/json&quot; \
4109
- <a id="__codelineno-14-4" name="__codelineno-14-4" href="#__codelineno-14-4"></a>-H &quot;Accept: application/json; version=1.3; indent=4&quot; \
4110
- <a id="__codelineno-14-5" name="__codelineno-14-5" href="#__codelineno-14-5"></a>http://nautobot/api/extras/jobs/$JOB_ID/run/
5329
+ <div class="admonition version-removed">
5330
+ <p class="admonition-title">Removed in version 2.0.0</p>
5331
+ <p>The <code>commit</code> parameter was removed. All job input should be provided via the <code>data</code> parameter.</p>
5332
+ </div>
5333
+ <p>To run a job via the REST API, issue a POST request to the job's endpoint <code>/api/extras/jobs/&lt;uuid&gt;/run/</code>. You can optionally provide JSON data to specify any required user input <code>data</code>, optional <code>task_queue</code>, and/or provide optional scheduling information as described in <a href="job-scheduling-and-approvals.html">the section on scheduling and approvals</a>.</p>
5334
+ <p>For example, to run a job with no user inputs:</p>
5335
+ <div class="highlight"><pre><span></span><code><a id="__codelineno-16-1" name="__codelineno-16-1" href="#__codelineno-16-1"></a>curl -X POST \
5336
+ <a id="__codelineno-16-2" name="__codelineno-16-2" href="#__codelineno-16-2"></a>-H &quot;Authorization: Token $TOKEN&quot; \
5337
+ <a id="__codelineno-16-3" name="__codelineno-16-3" href="#__codelineno-16-3"></a>-H &quot;Content-Type: application/json&quot; \
5338
+ <a id="__codelineno-16-4" name="__codelineno-16-4" href="#__codelineno-16-4"></a>-H &quot;Accept: application/json; version=1.3; indent=4&quot; \
5339
+ <a id="__codelineno-16-5" name="__codelineno-16-5" href="#__codelineno-16-5"></a>http://nautobot/api/extras/jobs/$JOB_ID/run/
4111
5340
  </code></pre></div>
4112
- <p>Or to run a job that expects user inputs, and commit changes to the database:</p>
4113
- <div class="highlight"><pre><span></span><code><a id="__codelineno-15-1" name="__codelineno-15-1" href="#__codelineno-15-1"></a>curl -X POST \
4114
- <a id="__codelineno-15-2" name="__codelineno-15-2" href="#__codelineno-15-2"></a>-H &quot;Authorization: Token $TOKEN&quot; \
4115
- <a id="__codelineno-15-3" name="__codelineno-15-3" href="#__codelineno-15-3"></a>-H &quot;Content-Type: application/json&quot; \
4116
- <a id="__codelineno-15-4" name="__codelineno-15-4" href="#__codelineno-15-4"></a>-H &quot;Accept: application/json; version=1.3; indent=4&quot; \
4117
- <a id="__codelineno-15-5" name="__codelineno-15-5" href="#__codelineno-15-5"></a>http://nautobot/api/extras/jobs/$JOB_ID/run/ \
4118
- <a id="__codelineno-15-6" name="__codelineno-15-6" href="#__codelineno-15-6"></a>--data &#39;{&quot;data&quot;: {&quot;string_variable&quot;: &quot;somevalue&quot;, &quot;integer_variable&quot;: 123}, &quot;commit&quot;: true}&#39;
5341
+ <p>Or to run a job that expects user inputs:</p>
5342
+ <div class="highlight"><pre><span></span><code><a id="__codelineno-17-1" name="__codelineno-17-1" href="#__codelineno-17-1"></a>curl -X POST \
5343
+ <a id="__codelineno-17-2" name="__codelineno-17-2" href="#__codelineno-17-2"></a>-H &quot;Authorization: Token $TOKEN&quot; \
5344
+ <a id="__codelineno-17-3" name="__codelineno-17-3" href="#__codelineno-17-3"></a>-H &quot;Content-Type: application/json&quot; \
5345
+ <a id="__codelineno-17-4" name="__codelineno-17-4" href="#__codelineno-17-4"></a>-H &quot;Accept: application/json; version=1.3; indent=4&quot; \
5346
+ <a id="__codelineno-17-5" name="__codelineno-17-5" href="#__codelineno-17-5"></a>http://nautobot/api/extras/jobs/$JOB_ID/run/ \
5347
+ <a id="__codelineno-17-6" name="__codelineno-17-6" href="#__codelineno-17-6"></a>--data &#39;{&quot;data&quot;: {&quot;string_variable&quot;: &quot;somevalue&quot;, &quot;integer_variable&quot;: 123}}&#39;
4119
5348
  </code></pre></div>
4120
5349
  <p>When providing input data, it is possible to specify complex values contained in <code>ObjectVar</code>s, <code>MultiObjectVar</code>s, and <code>IPAddressVar</code>s.</p>
4121
5350
  <ul>
@@ -4124,22 +5353,21 @@ elements will be important in running jobs programmatically.</p>
4124
5353
  <li><code>IPAddressVar</code>s can be provided as strings in CIDR notation.</li>
4125
5354
  </ul>
4126
5355
  <h4 id="jobs-with-files">Jobs with Files<a class="headerlink" href="#jobs-with-files" title="Permanent link">&para;</a></h4>
4127
- <p>To run a job that contains <code>FileVar</code> inputs via the REST API, you must use <code>multipart/form-data</code> content type requests instead of <code>application/json</code>. This also requires a slightly different request payload than the example above. The <code>commit</code>, <code>task_queue</code>, and <code>schedule</code> data are flattened and prefixed with underscore to differentiate them from job-specific data. Job specific data is also flattened and not located under the top-level <code>data</code> dictionary key.</p>
5356
+ <p>To run a job that contains <code>FileVar</code> inputs via the REST API, you must use <code>multipart/form-data</code> content type requests instead of <code>application/json</code>. This also requires a slightly different request payload than the example above. The <code>task_queue</code> and <code>schedule</code> data are flattened and prefixed with underscore to differentiate them from job-specific data. Job specific data is also flattened and not located under the top-level <code>data</code> dictionary key.</p>
4128
5357
  <p>An example of running a job with both <code>FileVar</code> (named <code>myfile</code>) and <code>StringVar</code> (named <code>interval</code>) input:</p>
4129
- <div class="highlight"><pre><span></span><code><a id="__codelineno-16-1" name="__codelineno-16-1" href="#__codelineno-16-1"></a>curl -X POST \
4130
- <a id="__codelineno-16-2" name="__codelineno-16-2" href="#__codelineno-16-2"></a>-H &#39;Authorization: Token $TOKEN&#39; \
4131
- <a id="__codelineno-16-3" name="__codelineno-16-3" href="#__codelineno-16-3"></a>-H &#39;Content-Type: multipart/form-data&#39; \
4132
- <a id="__codelineno-16-4" name="__codelineno-16-4" href="#__codelineno-16-4"></a>-H &quot;Accept: application/json; version=1.3; indent=4&quot; \
4133
- <a id="__codelineno-16-5" name="__codelineno-16-5" href="#__codelineno-16-5"></a>&#39;http://nautobot/api/extras/jobs/$JOB_ID/run/&#39; \
4134
- <a id="__codelineno-16-6" name="__codelineno-16-6" href="#__codelineno-16-6"></a>-F &#39;_commit=&quot;true&quot;&#39; \
4135
- <a id="__codelineno-16-7" name="__codelineno-16-7" href="#__codelineno-16-7"></a>-F &#39;_schedule_interval=&quot;immediately&quot;&#39; \
4136
- <a id="__codelineno-16-8" name="__codelineno-16-8" href="#__codelineno-16-8"></a>-F &#39;_schedule_start_time=&quot;2022-10-18T17:31:23.698Z&quot;&#39; \
4137
- <a id="__codelineno-16-9" name="__codelineno-16-9" href="#__codelineno-16-9"></a>-F &#39;interval=&quot;3&quot;&#39; \
4138
- <a id="__codelineno-16-10" name="__codelineno-16-10" href="#__codelineno-16-10"></a>-F &#39;myfile=@&quot;/path/to/my/file.txt&quot;&#39; \
5358
+ <div class="highlight"><pre><span></span><code><a id="__codelineno-18-1" name="__codelineno-18-1" href="#__codelineno-18-1"></a>curl -X POST \
5359
+ <a id="__codelineno-18-2" name="__codelineno-18-2" href="#__codelineno-18-2"></a>-H &#39;Authorization: Token $TOKEN&#39; \
5360
+ <a id="__codelineno-18-3" name="__codelineno-18-3" href="#__codelineno-18-3"></a>-H &#39;Content-Type: multipart/form-data&#39; \
5361
+ <a id="__codelineno-18-4" name="__codelineno-18-4" href="#__codelineno-18-4"></a>-H &quot;Accept: application/json; version=1.3; indent=4&quot; \
5362
+ <a id="__codelineno-18-5" name="__codelineno-18-5" href="#__codelineno-18-5"></a>&#39;http://nautobot/api/extras/jobs/$JOB_ID/run/&#39; \
5363
+ <a id="__codelineno-18-6" name="__codelineno-18-6" href="#__codelineno-18-6"></a>-F &#39;_schedule_interval=&quot;immediately&quot;&#39; \
5364
+ <a id="__codelineno-18-7" name="__codelineno-18-7" href="#__codelineno-18-7"></a>-F &#39;_schedule_start_time=&quot;2022-10-18T17:31:23.698Z&quot;&#39; \
5365
+ <a id="__codelineno-18-8" name="__codelineno-18-8" href="#__codelineno-18-8"></a>-F &#39;interval=&quot;3&quot;&#39; \
5366
+ <a id="__codelineno-18-9" name="__codelineno-18-9" href="#__codelineno-18-9"></a>-F &#39;myfile=@&quot;/path/to/my/file.txt&quot;&#39; \
4139
5367
  </code></pre></div>
4140
5368
  <h3 id="via-the-cli">Via the CLI<a class="headerlink" href="#via-the-cli" title="Permanent link">&para;</a></h3>
4141
5369
  <p>Jobs can be run from the CLI by invoking the management command:</p>
4142
- <div class="highlight"><pre><span></span><code><a id="__codelineno-17-1" name="__codelineno-17-1" href="#__codelineno-17-1"></a>nautobot-server runjob [--username &lt;username&gt;] [--commit] [--local] [--data &lt;data&gt;] &lt;class_path&gt;
5370
+ <div class="highlight"><pre><span></span><code><a id="__codelineno-19-1" name="__codelineno-19-1" href="#__codelineno-19-1"></a>nautobot-server runjob [--username &lt;username&gt;] [--local] [--data &lt;data&gt;] &lt;class_path&gt;
4143
5371
  </code></pre></div>
4144
5372
  <div class="admonition note">
4145
5373
  <p class="admonition-title">Note</p>
@@ -4151,177 +5379,127 @@ elements will be important in running jobs programmatically.</p>
4151
5379
  <p>The <code>--data</code> parameter must be a JSON string, e.g. <code>--data='{"string_variable": "somevalue", "integer_variable": 123}'</code></p>
4152
5380
  </div>
4153
5381
  <p>Using the same example shown in the API:</p>
4154
- <div class="highlight"><pre><span></span><code><a id="__codelineno-18-1" name="__codelineno-18-1" href="#__codelineno-18-1"></a>nautobot-server runjob --username myusername local/example/MyJobWithNoVars
5382
+ <div class="highlight"><pre><span></span><code><a id="__codelineno-20-1" name="__codelineno-20-1" href="#__codelineno-20-1"></a>nautobot-server runjob --username myusername local/example/MyJobWithNoVars
4155
5383
  </code></pre></div>
4156
5384
  <div class="admonition warning">
4157
5385
  <p class="admonition-title">Warning</p>
4158
- <p>The <code>--username &lt;username&gt;</code> parameter can be used to specify the user that will be identified as the requester of the job. It is optional if the job will not be modifying the database, but is mandatory if you are running with <code>--commit</code>, as the specified user will own any resulting database changes.</p>
5386
+ <p>The <code>--username &lt;username&gt;</code> must be supplied to specify the user that will be identified as the requester of the job.</p>
4159
5387
  <p>Note that <code>nautobot-server</code> commands, like all management commands and other direct interactions with the Django database, are not gated by the usual Nautobot user authentication flow. It is possible to specify any existing <code>--username</code> with the <code>nautobot-server runjob</code> command in order to impersonate any defined user in Nautobot. Use this power wisely and be cautious who you allow to access it.</p>
4160
5388
  </div>
4161
5389
  <h2 id="testing-jobs">Testing Jobs<a class="headerlink" href="#testing-jobs" title="Permanent link">&para;</a></h2>
4162
5390
  <p>Jobs are Python code and can be tested as such, usually via <a href="https://docs.djangoproject.com/en/stable/topics/testing/">Django unit-test features</a>. That said, there are a few useful tricks specific to testing Jobs.</p>
4163
5391
  <p>While individual methods within your Job can and should be tested in isolation, you'll likely also want to test the entire execution of the Job. Nautobot 1.3.3 introduced a few enhancements to make this simpler to do, but it's also quite possible to test in earlier releases with a bit more effort.</p>
4164
5392
  <h3 id="nautobot-133-and-later">Nautobot 1.3.3 and later<a class="headerlink" href="#nautobot-133-and-later" title="Permanent link">&para;</a></h3>
4165
- <p>The simplest way to test the entire execution of Jobs from 1.3.3 on is via calling the <code>nautobot.core.testing.run_job_for_testing()</code> method, which is a helper wrapper around the <code>run_job</code> function used to execute a Job via Nautobot's Celery worker process.</p>
5393
+ <p>The simplest way to test the entire execution of Jobs from 1.3.3 on is via calling the <code>nautobot.core.testing.run_job_for_testing()</code> method, which is a helper wrapper around the <code>JobResult.enqueue_job</code> function used to execute a Job via Nautobot's Celery worker process.</p>
4166
5394
  <div class="admonition version-changed">
4167
5395
  <p class="admonition-title">Changed in version 2.0.0</p>
4168
5396
  <p><code>run_job_for_testing</code> was moved from the <code>nautobot.utilities.testing</code> module to <code>nautobot.core.testing</code>.</p>
4169
5397
  </div>
4170
- <p>Because of the way <code>run_job_for_testing</code> and more specifically <code>run_job()</code> works, which is somewhat complex behind the scenes, you need to inherit from <code>nautobot.core.testing.TransactionTestCase</code> instead of <code>django.test.TestCase</code> (Refer to the <a href="https://docs.djangoproject.com/en/stable/topics/testing/tools/#provided-test-case-classes">Django documentation</a> if you're interested in the differences between these classes - <code>TransactionTestCase</code> from Nautobot is a small wrapper around Django's <code>TransactionTestCase</code>).</p>
5398
+ <p>Because of the way <code>run_job_for_testing</code> and more specifically Celery tasks work, which is somewhat complex behind the scenes, you need to inherit from <code>nautobot.core.testing.TransactionTestCase</code> instead of <code>django.test.TestCase</code> (Refer to the <a href="https://docs.djangoproject.com/en/stable/topics/testing/tools/#provided-test-case-classes">Django documentation</a> if you're interested in the differences between these classes - <code>TransactionTestCase</code> from Nautobot is a small wrapper around Django's <code>TransactionTestCase</code>).</p>
4171
5399
  <p>When using <code>TransactionTestCase</code> (whether from Django or from Nautobot) each tests runs on a completely empty database. Furthermore, Nautobot requires new jobs to be enabled before they can run. Therefore, we need to make sure the job is enabled before each run which <code>run_job_for_testing</code> handles for us.</p>
4172
5400
  <p>A simple example of a Job test case for 1.3.3 and forward might look like the following:</p>
4173
- <div class="highlight"><pre><span></span><code><a id="__codelineno-19-1" name="__codelineno-19-1" href="#__codelineno-19-1"></a><span class="kn">from</span> <span class="nn">nautobot.core.testing</span> <span class="kn">import</span> <span class="n">run_job_for_testing</span><span class="p">,</span> <span class="n">TransactionTestCase</span>
4174
- <a id="__codelineno-19-2" name="__codelineno-19-2" href="#__codelineno-19-2"></a><span class="kn">from</span> <span class="nn">nautobot.extras.models</span> <span class="kn">import</span> <span class="n">Job</span><span class="p">,</span> <span class="n">JobLogEntry</span>
4175
- <a id="__codelineno-19-3" name="__codelineno-19-3" href="#__codelineno-19-3"></a>
4176
- <a id="__codelineno-19-4" name="__codelineno-19-4" href="#__codelineno-19-4"></a>
4177
- <a id="__codelineno-19-5" name="__codelineno-19-5" href="#__codelineno-19-5"></a><span class="k">class</span> <span class="nc">MyJobTestCase</span><span class="p">(</span><span class="n">TransactionTestCase</span><span class="p">):</span>
4178
- <a id="__codelineno-19-6" name="__codelineno-19-6" href="#__codelineno-19-6"></a> <span class="k">def</span> <span class="nf">test_my_job</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
4179
- <a id="__codelineno-19-7" name="__codelineno-19-7" href="#__codelineno-19-7"></a> <span class="c1"># Testing of Job &quot;MyJob&quot; in file &quot;my_job_file.py&quot; in $JOBS_ROOT</span>
4180
- <a id="__codelineno-19-8" name="__codelineno-19-8" href="#__codelineno-19-8"></a> <span class="n">job</span> <span class="o">=</span> <span class="n">Job</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">job_class_name</span><span class="o">=</span><span class="s2">&quot;MyJob&quot;</span><span class="p">,</span> <span class="n">module_name</span><span class="o">=</span><span class="s2">&quot;my_job_file&quot;</span><span class="p">,</span> <span class="n">source</span><span class="o">=</span><span class="s2">&quot;local&quot;</span><span class="p">)</span>
4181
- <a id="__codelineno-19-9" name="__codelineno-19-9" href="#__codelineno-19-9"></a> <span class="c1"># or, job = Job.objects.get_for_class_path(&quot;local/my_job_file/MyJob&quot;)</span>
4182
- <a id="__codelineno-19-10" name="__codelineno-19-10" href="#__codelineno-19-10"></a> <span class="n">job_result</span> <span class="o">=</span> <span class="n">run_job_for_testing</span><span class="p">(</span><span class="n">job</span><span class="p">,</span> <span class="n">data</span><span class="o">=</span><span class="p">{},</span> <span class="n">commit</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
4183
- <a id="__codelineno-19-11" name="__codelineno-19-11" href="#__codelineno-19-11"></a>
4184
- <a id="__codelineno-19-12" name="__codelineno-19-12" href="#__codelineno-19-12"></a> <span class="c1"># Since we ran with commit=False, any database changes made by the job won&#39;t persist,</span>
4185
- <a id="__codelineno-19-13" name="__codelineno-19-13" href="#__codelineno-19-13"></a> <span class="c1"># but we can still inspect the logs created by running the job</span>
4186
- <a id="__codelineno-19-14" name="__codelineno-19-14" href="#__codelineno-19-14"></a> <span class="n">log_entries</span> <span class="o">=</span> <span class="n">JobLogEntry</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="n">job_result</span><span class="o">=</span><span class="n">job_result</span><span class="p">)</span>
4187
- <a id="__codelineno-19-15" name="__codelineno-19-15" href="#__codelineno-19-15"></a> <span class="k">for</span> <span class="n">log_entry</span> <span class="ow">in</span> <span class="n">log_entries</span><span class="p">:</span>
4188
- <a id="__codelineno-19-16" name="__codelineno-19-16" href="#__codelineno-19-16"></a> <span class="bp">self</span><span class="o">.</span><span class="n">assertEqual</span><span class="p">(</span><span class="n">log_entry</span><span class="o">.</span><span class="n">message</span><span class="p">,</span> <span class="s2">&quot;...&quot;</span><span class="p">)</span>
5401
+ <div class="highlight"><pre><span></span><code><a id="__codelineno-21-1" name="__codelineno-21-1" href="#__codelineno-21-1"></a><span class="kn">from</span> <span class="nn">nautobot.core.testing</span> <span class="kn">import</span> <span class="n">run_job_for_testing</span><span class="p">,</span> <span class="n">TransactionTestCase</span>
5402
+ <a id="__codelineno-21-2" name="__codelineno-21-2" href="#__codelineno-21-2"></a><span class="kn">from</span> <span class="nn">nautobot.extras.models</span> <span class="kn">import</span> <span class="n">Job</span><span class="p">,</span> <span class="n">JobLogEntry</span>
5403
+ <a id="__codelineno-21-3" name="__codelineno-21-3" href="#__codelineno-21-3"></a>
5404
+ <a id="__codelineno-21-4" name="__codelineno-21-4" href="#__codelineno-21-4"></a>
5405
+ <a id="__codelineno-21-5" name="__codelineno-21-5" href="#__codelineno-21-5"></a><span class="k">class</span> <span class="nc">MyJobTestCase</span><span class="p">(</span><span class="n">TransactionTestCase</span><span class="p">):</span>
5406
+ <a id="__codelineno-21-6" name="__codelineno-21-6" href="#__codelineno-21-6"></a> <span class="k">def</span> <span class="nf">test_my_job</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
5407
+ <a id="__codelineno-21-7" name="__codelineno-21-7" href="#__codelineno-21-7"></a> <span class="c1"># Testing of Job &quot;MyJob&quot; in file &quot;my_job_file.py&quot; in $JOBS_ROOT</span>
5408
+ <a id="__codelineno-21-8" name="__codelineno-21-8" href="#__codelineno-21-8"></a> <span class="n">job</span> <span class="o">=</span> <span class="n">Job</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">job_class_name</span><span class="o">=</span><span class="s2">&quot;MyJob&quot;</span><span class="p">,</span> <span class="n">module_name</span><span class="o">=</span><span class="s2">&quot;my_job_file&quot;</span><span class="p">,</span> <span class="n">source</span><span class="o">=</span><span class="s2">&quot;local&quot;</span><span class="p">)</span>
5409
+ <a id="__codelineno-21-9" name="__codelineno-21-9" href="#__codelineno-21-9"></a> <span class="c1"># or, job = Job.objects.get_for_class_path(&quot;local/my_job_file/MyJob&quot;)</span>
5410
+ <a id="__codelineno-21-10" name="__codelineno-21-10" href="#__codelineno-21-10"></a> <span class="n">job_result</span> <span class="o">=</span> <span class="n">run_job_for_testing</span><span class="p">(</span><span class="n">job</span><span class="p">,</span> <span class="n">var1</span><span class="o">=</span><span class="s2">&quot;abc&quot;</span><span class="p">,</span> <span class="n">var2</span><span class="o">=</span><span class="mi">123</span><span class="p">)</span>
5411
+ <a id="__codelineno-21-11" name="__codelineno-21-11" href="#__codelineno-21-11"></a>
5412
+ <a id="__codelineno-21-12" name="__codelineno-21-12" href="#__codelineno-21-12"></a> <span class="c1"># Inspect the logs created by running the job</span>
5413
+ <a id="__codelineno-21-13" name="__codelineno-21-13" href="#__codelineno-21-13"></a> <span class="n">log_entries</span> <span class="o">=</span> <span class="n">JobLogEntry</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="n">job_result</span><span class="o">=</span><span class="n">job_result</span><span class="p">)</span>
5414
+ <a id="__codelineno-21-14" name="__codelineno-21-14" href="#__codelineno-21-14"></a> <span class="k">for</span> <span class="n">log_entry</span> <span class="ow">in</span> <span class="n">log_entries</span><span class="p">:</span>
5415
+ <a id="__codelineno-21-15" name="__codelineno-21-15" href="#__codelineno-21-15"></a> <span class="bp">self</span><span class="o">.</span><span class="n">assertEqual</span><span class="p">(</span><span class="n">log_entry</span><span class="o">.</span><span class="n">message</span><span class="p">,</span> <span class="s2">&quot;...&quot;</span><span class="p">)</span>
4189
5416
  </code></pre></div>
4190
5417
  <div class="admonition tip">
4191
5418
  <p class="admonition-title">Tip</p>
4192
- <p>For more advanced examples (such as testing jobs executed with <code>commit=True</code>, for example) refer to the Nautobot source code, specifically <code>nautobot/extras/tests/test_jobs.py</code>.</p>
5419
+ <p>For more advanced examples refer to the Nautobot source code, specifically <code>nautobot/extras/tests/test_jobs.py</code>.</p>
4193
5420
  </div>
4194
- <h3 id="nautobot-132-and-earlier-including-12">Nautobot 1.3.2 and earlier (including 1.2)<a class="headerlink" href="#nautobot-132-and-earlier-including-12" title="Permanent link">&para;</a></h3>
4195
- <p>If your test case needs to be backwards-compatible with test execution against Nautobot 1.3.2 and/or earlier, you need to handle a couple more things manually:</p>
4196
- <p>Set up the <code>"job_logs"</code> database correctly for testing:</p>
4197
- <div class="highlight"><pre><span></span><code><a id="__codelineno-20-1" name="__codelineno-20-1" href="#__codelineno-20-1"></a><span class="kn">from</span> <span class="nn">django.conf</span> <span class="kn">import</span> <span class="n">settings</span>
4198
- <a id="__codelineno-20-2" name="__codelineno-20-2" href="#__codelineno-20-2"></a>
4199
- <a id="__codelineno-20-3" name="__codelineno-20-3" href="#__codelineno-20-3"></a><span class="k">if</span> <span class="s2">&quot;job_logs&quot;</span> <span class="ow">in</span> <span class="n">settings</span><span class="o">.</span><span class="n">DATABASES</span><span class="p">:</span>
4200
- <a id="__codelineno-20-4" name="__codelineno-20-4" href="#__codelineno-20-4"></a> <span class="n">settings</span><span class="o">.</span><span class="n">DATABASES</span><span class="p">[</span><span class="s2">&quot;job_logs&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">settings</span><span class="o">.</span><span class="n">DATABASES</span><span class="p">[</span><span class="s2">&quot;job_logs&quot;</span><span class="p">]</span><span class="o">.</span><span class="n">copy</span><span class="p">()</span>
4201
- <a id="__codelineno-20-5" name="__codelineno-20-5" href="#__codelineno-20-5"></a> <span class="n">settings</span><span class="o">.</span><span class="n">DATABASES</span><span class="p">[</span><span class="s2">&quot;job_logs&quot;</span><span class="p">][</span><span class="s2">&quot;TEST&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span><span class="s2">&quot;MIRROR&quot;</span><span class="p">:</span> <span class="s2">&quot;default&quot;</span><span class="p">}</span>
4202
- </code></pre></div>
4203
- <p>Replicate the behavior of <code>run_job_for_testing</code> manually so that your test execution most closely resembles the way the celery worker would run the test:</p>
4204
- <div class="highlight"><pre><span></span><code><a id="__codelineno-21-1" name="__codelineno-21-1" href="#__codelineno-21-1"></a><span class="kn">import</span> <span class="nn">uuid</span>
4205
- <a id="__codelineno-21-2" name="__codelineno-21-2" href="#__codelineno-21-2"></a><span class="kn">from</span> <span class="nn">django.contrib.auth</span> <span class="kn">import</span> <span class="n">get_user_model</span>
4206
- <a id="__codelineno-21-3" name="__codelineno-21-3" href="#__codelineno-21-3"></a><span class="kn">from</span> <span class="nn">django.contrib.contenttypes.models</span> <span class="kn">import</span> <span class="n">ContentType</span>
4207
- <a id="__codelineno-21-4" name="__codelineno-21-4" href="#__codelineno-21-4"></a>
4208
- <a id="__codelineno-21-5" name="__codelineno-21-5" href="#__codelineno-21-5"></a><span class="kn">from</span> <span class="nn">nautobot.extras.context_managers</span> <span class="kn">import</span> <span class="n">web_request_context</span>
4209
- <a id="__codelineno-21-6" name="__codelineno-21-6" href="#__codelineno-21-6"></a><span class="kn">from</span> <span class="nn">nautobot.extras.jobs</span> <span class="kn">import</span> <span class="n">run_job</span>
4210
- <a id="__codelineno-21-7" name="__codelineno-21-7" href="#__codelineno-21-7"></a><span class="kn">from</span> <span class="nn">nautobot.extras.models</span> <span class="kn">import</span> <span class="n">JobResult</span><span class="p">,</span> <span class="n">Job</span>
4211
- <a id="__codelineno-21-8" name="__codelineno-21-8" href="#__codelineno-21-8"></a>
4212
- <a id="__codelineno-21-9" name="__codelineno-21-9" href="#__codelineno-21-9"></a><span class="k">def</span> <span class="nf">run_job_for_testing</span><span class="p">(</span><span class="n">job</span><span class="p">,</span> <span class="n">data</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">commit</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="n">username</span><span class="o">=</span><span class="s2">&quot;test-user&quot;</span><span class="p">):</span>
4213
- <a id="__codelineno-21-10" name="__codelineno-21-10" href="#__codelineno-21-10"></a> <span class="k">if</span> <span class="n">data</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
4214
- <a id="__codelineno-21-11" name="__codelineno-21-11" href="#__codelineno-21-11"></a> <span class="n">data</span> <span class="o">=</span> <span class="p">{}</span>
4215
- <a id="__codelineno-21-12" name="__codelineno-21-12" href="#__codelineno-21-12"></a> <span class="n">user_model</span> <span class="o">=</span> <span class="n">get_user_model</span><span class="p">()</span>
4216
- <a id="__codelineno-21-13" name="__codelineno-21-13" href="#__codelineno-21-13"></a> <span class="n">user</span><span class="p">,</span> <span class="n">_</span> <span class="o">=</span> <span class="n">user_model</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">get_or_create</span><span class="p">(</span><span class="n">username</span><span class="o">=</span><span class="n">username</span><span class="p">,</span> <span class="n">is_superuser</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="n">password</span><span class="o">=</span><span class="s2">&quot;password&quot;</span><span class="p">)</span>
4217
- <a id="__codelineno-21-14" name="__codelineno-21-14" href="#__codelineno-21-14"></a> <span class="n">job_result</span> <span class="o">=</span> <span class="n">JobResult</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">create</span><span class="p">(</span>
4218
- <a id="__codelineno-21-15" name="__codelineno-21-15" href="#__codelineno-21-15"></a> <span class="n">name</span><span class="o">=</span><span class="n">job</span><span class="o">.</span><span class="n">class_path</span><span class="p">,</span>
4219
- <a id="__codelineno-21-16" name="__codelineno-21-16" href="#__codelineno-21-16"></a> <span class="n">obj_type</span><span class="o">=</span><span class="n">ContentType</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">get_for_model</span><span class="p">(</span><span class="n">Job</span><span class="p">),</span>
4220
- <a id="__codelineno-21-17" name="__codelineno-21-17" href="#__codelineno-21-17"></a> <span class="n">user</span><span class="o">=</span><span class="n">user</span><span class="p">,</span>
4221
- <a id="__codelineno-21-18" name="__codelineno-21-18" href="#__codelineno-21-18"></a> <span class="n">task_id</span><span class="o">=</span><span class="n">uuid</span><span class="o">.</span><span class="n">uuid4</span><span class="p">(),</span>
4222
- <a id="__codelineno-21-19" name="__codelineno-21-19" href="#__codelineno-21-19"></a> <span class="p">)</span>
4223
- <a id="__codelineno-21-20" name="__codelineno-21-20" href="#__codelineno-21-20"></a> <span class="k">with</span> <span class="n">web_request_context</span><span class="p">(</span><span class="n">user</span><span class="o">=</span><span class="n">user</span><span class="p">)</span> <span class="k">as</span> <span class="n">request</span><span class="p">:</span>
4224
- <a id="__codelineno-21-21" name="__codelineno-21-21" href="#__codelineno-21-21"></a> <span class="n">run_job</span><span class="p">(</span><span class="n">data</span><span class="o">=</span><span class="n">data</span><span class="p">,</span> <span class="n">request</span><span class="o">=</span><span class="n">request</span><span class="p">,</span> <span class="n">commit</span><span class="o">=</span><span class="n">commit</span><span class="p">,</span> <span class="n">job_result_pk</span><span class="o">=</span><span class="n">job_result</span><span class="o">.</span><span class="n">pk</span><span class="p">)</span>
4225
- <a id="__codelineno-21-22" name="__codelineno-21-22" href="#__codelineno-21-22"></a> <span class="k">return</span> <span class="n">job_result</span>
4226
- </code></pre></div>
4227
- <p>Setup the <code>databases</code> field on the test class correctly, and re-create the default Statuses on <code>setUp</code> in your test classes, because <code>django.test.TransactionTestCase</code> truncates them on every <code>tearDown</code>:</p>
4228
- <div class="highlight"><pre><span></span><code><a id="__codelineno-22-1" name="__codelineno-22-1" href="#__codelineno-22-1"></a><span class="kn">from</span> <span class="nn">django.apps</span> <span class="kn">import</span> <span class="n">apps</span>
4229
- <a id="__codelineno-22-2" name="__codelineno-22-2" href="#__codelineno-22-2"></a><span class="kn">from</span> <span class="nn">django.conf</span> <span class="kn">import</span> <span class="n">settings</span>
4230
- <a id="__codelineno-22-3" name="__codelineno-22-3" href="#__codelineno-22-3"></a><span class="kn">from</span> <span class="nn">django.test</span> <span class="kn">import</span> <span class="n">TransactionTestCase</span>
4231
- <a id="__codelineno-22-4" name="__codelineno-22-4" href="#__codelineno-22-4"></a>
4232
- <a id="__codelineno-22-5" name="__codelineno-22-5" href="#__codelineno-22-5"></a><span class="kn">from</span> <span class="nn">nautobot.extras.management</span> <span class="kn">import</span> <span class="n">populate_status_choices</span>
4233
- <a id="__codelineno-22-6" name="__codelineno-22-6" href="#__codelineno-22-6"></a>
4234
- <a id="__codelineno-22-7" name="__codelineno-22-7" href="#__codelineno-22-7"></a><span class="k">class</span> <span class="nc">MyJobTestCase</span><span class="p">(</span><span class="n">TransactionTestCase</span><span class="p">):</span>
4235
- <a id="__codelineno-22-8" name="__codelineno-22-8" href="#__codelineno-22-8"></a> <span class="c1"># &#39;job_logs&#39; is a proxy connection to the same (default) database that&#39;s used exclusively for Job logging</span>
4236
- <a id="__codelineno-22-9" name="__codelineno-22-9" href="#__codelineno-22-9"></a> <span class="k">if</span> <span class="s2">&quot;job_logs&quot;</span> <span class="ow">in</span> <span class="n">settings</span><span class="o">.</span><span class="n">DATABASES</span><span class="p">:</span>
4237
- <a id="__codelineno-22-10" name="__codelineno-22-10" href="#__codelineno-22-10"></a> <span class="n">databases</span> <span class="o">=</span> <span class="p">(</span><span class="s2">&quot;default&quot;</span><span class="p">,</span> <span class="s2">&quot;job_logs&quot;</span><span class="p">)</span>
4238
- <a id="__codelineno-22-11" name="__codelineno-22-11" href="#__codelineno-22-11"></a>
4239
- <a id="__codelineno-22-12" name="__codelineno-22-12" href="#__codelineno-22-12"></a> <span class="k">def</span> <span class="nf">setUp</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
4240
- <a id="__codelineno-22-13" name="__codelineno-22-13" href="#__codelineno-22-13"></a> <span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="n">setUp</span><span class="p">()</span>
4241
- <a id="__codelineno-22-14" name="__codelineno-22-14" href="#__codelineno-22-14"></a> <span class="n">populate_status_choices</span><span class="p">(</span><span class="n">apps</span><span class="p">,</span> <span class="kc">None</span><span class="p">)</span>
5421
+ <h2 id="debugging-job-performance">Debugging job performance<a class="headerlink" href="#debugging-job-performance" title="Permanent link">&para;</a></h2>
5422
+ <div class="admonition version-added">
5423
+ <p class="admonition-title">Added in version 1.5.17</p>
5424
+ </div>
5425
+ <p>Debugging the performance of Nautobot jobs can be tricky, because they are executed in the worker context. In order to gain extra visibility, <a href="https://docs.python.org/3/library/profile.html">cProfile</a> can be used to profile the job execution.</p>
5426
+ <p>The 'profile' form field on jobs is automatically available when the <code>DEBUG</code> settings is <code>True</code>. When you select that checkbox, a profiling report in the pstats format will be written to the file system of the environment where the job runs. Normally, this is on the file system of the worker process, but if you are using the <code>nautobot-server runjob</code> command with <code>--local</code>, it will end up in the file system of the web application itself. The path of the written file will be logged in the job.</p>
5427
+ <div class="admonition note">
5428
+ <p class="admonition-title">Note</p>
5429
+ <p>If you need to run this in an environment where <code>DEBUG</code> is <code>False</code>, you have the option of using <code>nautobot-server runjob</code> with the <code>--profile</code> flag. According to the docs, <code>cProfile</code> should have minimal impact on the performance of the job; still, proceed with caution when using this in a production environment.</p>
5430
+ </div>
5431
+ <h3 id="reading-profiling-reports">Reading profiling reports<a class="headerlink" href="#reading-profiling-reports" title="Permanent link">&para;</a></h3>
5432
+ <p>A full description on how to deal with the output of <code>cProfile</code> can be found in the <a href="https://docs.python.org/3/library/profile.html#instant-user-s-manual">Instant User's Manual</a>, but here is something to get you started:</p>
5433
+ <div class="highlight"><pre><span></span><code><a id="__codelineno-22-1" name="__codelineno-22-1" href="#__codelineno-22-1"></a><span class="kn">import</span> <span class="nn">pstats</span>
5434
+ <a id="__codelineno-22-2" name="__codelineno-22-2" href="#__codelineno-22-2"></a><span class="n">job_result_uuid</span> <span class="o">=</span> <span class="s2">&quot;66b70231-002f-412b-8cc4-1cc9609c2c9b&quot;</span>
5435
+ <a id="__codelineno-22-3" name="__codelineno-22-3" href="#__codelineno-22-3"></a><span class="n">stats</span> <span class="o">=</span> <span class="n">pstats</span><span class="o">.</span><span class="n">Stats</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;/tmp/job-result-</span><span class="si">{</span><span class="n">job_result_uuid</span><span class="si">}</span><span class="s2">.pstats&quot;</span><span class="p">)</span>
5436
+ <a id="__codelineno-22-4" name="__codelineno-22-4" href="#__codelineno-22-4"></a><span class="n">stats</span><span class="o">.</span><span class="n">sort_stats</span><span class="p">(</span><span class="n">pstats</span><span class="o">.</span><span class="n">SortKey</span><span class="o">.</span><span class="n">CUMULATIVE</span><span class="p">)</span><span class="o">.</span><span class="n">print_stats</span><span class="p">(</span><span class="mi">10</span><span class="p">)</span>
4242
5437
  </code></pre></div>
5438
+ <p>This will print the 10 functions that the job execution spent the most time in - adapt this to your needs!</p>
4243
5439
  <h2 id="example-jobs">Example Jobs<a class="headerlink" href="#example-jobs" title="Permanent link">&para;</a></h2>
4244
- <h3 id="creating-objects-for-a-planned-site">Creating objects for a planned site<a class="headerlink" href="#creating-objects-for-a-planned-site" title="Permanent link">&para;</a></h3>
5440
+ <h3 id="creating-objects-for-a-planned-location">Creating objects for a planned location<a class="headerlink" href="#creating-objects-for-a-planned-location" title="Permanent link">&para;</a></h3>
4245
5441
  <p>This job prompts the user for three variables:</p>
4246
5442
  <ul>
4247
- <li>The name of the new site</li>
5443
+ <li>The name of the new location</li>
4248
5444
  <li>The device model (a filtered list of defined device types)</li>
4249
5445
  <li>The number of access switches to create</li>
4250
5446
  </ul>
4251
5447
  <p>These variables are presented as a web form to be completed by the user. Once submitted, the job's <code>run()</code> method is called to create the appropriate objects, and it returns simple CSV output to the user summarizing the created objects.</p>
4252
5448
  <div class="highlight"><pre><span></span><code><a id="__codelineno-23-1" name="__codelineno-23-1" href="#__codelineno-23-1"></a><span class="kn">from</span> <span class="nn">django.contrib.contenttypes.models</span> <span class="kn">import</span> <span class="n">ContentType</span>
4253
- <a id="__codelineno-23-2" name="__codelineno-23-2" href="#__codelineno-23-2"></a><span class="kn">from</span> <span class="nn">django.utils.text</span> <span class="kn">import</span> <span class="n">slugify</span>
4254
- <a id="__codelineno-23-3" name="__codelineno-23-3" href="#__codelineno-23-3"></a>
4255
- <a id="__codelineno-23-4" name="__codelineno-23-4" href="#__codelineno-23-4"></a><span class="kn">from</span> <span class="nn">nautobot.dcim.models</span> <span class="kn">import</span> <span class="n">Device</span><span class="p">,</span> <span class="n">DeviceType</span><span class="p">,</span> <span class="n">Manufacturer</span><span class="p">,</span> <span class="n">Site</span>
4256
- <a id="__codelineno-23-5" name="__codelineno-23-5" href="#__codelineno-23-5"></a><span class="kn">from</span> <span class="nn">nautobot.extras.models</span> <span class="kn">import</span> <span class="n">Role</span><span class="p">,</span> <span class="n">Status</span>
4257
- <a id="__codelineno-23-6" name="__codelineno-23-6" href="#__codelineno-23-6"></a><span class="kn">from</span> <span class="nn">nautobot.extras.jobs</span> <span class="kn">import</span> <span class="o">*</span>
5449
+ <a id="__codelineno-23-2" name="__codelineno-23-2" href="#__codelineno-23-2"></a>
5450
+ <a id="__codelineno-23-3" name="__codelineno-23-3" href="#__codelineno-23-3"></a><span class="kn">from</span> <span class="nn">nautobot.dcim.models</span> <span class="kn">import</span> <span class="n">Location</span><span class="p">,</span> <span class="n">LocationType</span><span class="p">,</span> <span class="n">Device</span><span class="p">,</span> <span class="n">Manufacturer</span><span class="p">,</span> <span class="n">DeviceType</span>
5451
+ <a id="__codelineno-23-4" name="__codelineno-23-4" href="#__codelineno-23-4"></a><span class="kn">from</span> <span class="nn">nautobot.extras.models</span> <span class="kn">import</span> <span class="n">Status</span><span class="p">,</span> <span class="n">Role</span>
5452
+ <a id="__codelineno-23-5" name="__codelineno-23-5" href="#__codelineno-23-5"></a><span class="kn">from</span> <span class="nn">nautobot.extras.jobs</span> <span class="kn">import</span> <span class="n">Job</span><span class="p">,</span> <span class="n">StringVar</span><span class="p">,</span> <span class="n">IntegerVar</span><span class="p">,</span> <span class="n">ObjectVar</span>
5453
+ <a id="__codelineno-23-6" name="__codelineno-23-6" href="#__codelineno-23-6"></a>
4258
5454
  <a id="__codelineno-23-7" name="__codelineno-23-7" href="#__codelineno-23-7"></a>
4259
- <a id="__codelineno-23-8" name="__codelineno-23-8" href="#__codelineno-23-8"></a>
4260
- <a id="__codelineno-23-9" name="__codelineno-23-9" href="#__codelineno-23-9"></a><span class="k">class</span> <span class="nc">NewBranch</span><span class="p">(</span><span class="n">Job</span><span class="p">):</span>
4261
- <a id="__codelineno-23-10" name="__codelineno-23-10" href="#__codelineno-23-10"></a>
4262
- <a id="__codelineno-23-11" name="__codelineno-23-11" href="#__codelineno-23-11"></a> <span class="k">class</span> <span class="nc">Meta</span><span class="p">:</span>
4263
- <a id="__codelineno-23-12" name="__codelineno-23-12" href="#__codelineno-23-12"></a> <span class="n">name</span> <span class="o">=</span> <span class="s2">&quot;New Branch&quot;</span>
4264
- <a id="__codelineno-23-13" name="__codelineno-23-13" href="#__codelineno-23-13"></a> <span class="n">description</span> <span class="o">=</span> <span class="s2">&quot;Provision a new branch site&quot;</span>
4265
- <a id="__codelineno-23-14" name="__codelineno-23-14" href="#__codelineno-23-14"></a> <span class="n">field_order</span> <span class="o">=</span> <span class="p">[</span><span class="s1">&#39;site_name&#39;</span><span class="p">,</span> <span class="s1">&#39;switch_count&#39;</span><span class="p">,</span> <span class="s1">&#39;switch_model&#39;</span><span class="p">]</span>
4266
- <a id="__codelineno-23-15" name="__codelineno-23-15" href="#__codelineno-23-15"></a>
4267
- <a id="__codelineno-23-16" name="__codelineno-23-16" href="#__codelineno-23-16"></a> <span class="n">site_name</span> <span class="o">=</span> <span class="n">StringVar</span><span class="p">(</span>
4268
- <a id="__codelineno-23-17" name="__codelineno-23-17" href="#__codelineno-23-17"></a> <span class="n">description</span><span class="o">=</span><span class="s2">&quot;Name of the new site&quot;</span>
4269
- <a id="__codelineno-23-18" name="__codelineno-23-18" href="#__codelineno-23-18"></a> <span class="p">)</span>
4270
- <a id="__codelineno-23-19" name="__codelineno-23-19" href="#__codelineno-23-19"></a> <span class="n">switch_count</span> <span class="o">=</span> <span class="n">IntegerVar</span><span class="p">(</span>
4271
- <a id="__codelineno-23-20" name="__codelineno-23-20" href="#__codelineno-23-20"></a> <span class="n">description</span><span class="o">=</span><span class="s2">&quot;Number of access switches to create&quot;</span>
4272
- <a id="__codelineno-23-21" name="__codelineno-23-21" href="#__codelineno-23-21"></a> <span class="p">)</span>
4273
- <a id="__codelineno-23-22" name="__codelineno-23-22" href="#__codelineno-23-22"></a> <span class="n">manufacturer</span> <span class="o">=</span> <span class="n">ObjectVar</span><span class="p">(</span>
4274
- <a id="__codelineno-23-23" name="__codelineno-23-23" href="#__codelineno-23-23"></a> <span class="n">model</span><span class="o">=</span><span class="n">Manufacturer</span><span class="p">,</span>
4275
- <a id="__codelineno-23-24" name="__codelineno-23-24" href="#__codelineno-23-24"></a> <span class="n">required</span><span class="o">=</span><span class="kc">False</span>
4276
- <a id="__codelineno-23-25" name="__codelineno-23-25" href="#__codelineno-23-25"></a> <span class="p">)</span>
4277
- <a id="__codelineno-23-26" name="__codelineno-23-26" href="#__codelineno-23-26"></a> <span class="n">switch_model</span> <span class="o">=</span> <span class="n">ObjectVar</span><span class="p">(</span>
4278
- <a id="__codelineno-23-27" name="__codelineno-23-27" href="#__codelineno-23-27"></a> <span class="n">description</span><span class="o">=</span><span class="s2">&quot;Access switch model&quot;</span><span class="p">,</span>
4279
- <a id="__codelineno-23-28" name="__codelineno-23-28" href="#__codelineno-23-28"></a> <span class="n">model</span><span class="o">=</span><span class="n">DeviceType</span><span class="p">,</span>
4280
- <a id="__codelineno-23-29" name="__codelineno-23-29" href="#__codelineno-23-29"></a> <span class="n">query_params</span><span class="o">=</span><span class="p">{</span>
4281
- <a id="__codelineno-23-30" name="__codelineno-23-30" href="#__codelineno-23-30"></a> <span class="s1">&#39;manufacturer_id&#39;</span><span class="p">:</span> <span class="s1">&#39;$manufacturer&#39;</span>
4282
- <a id="__codelineno-23-31" name="__codelineno-23-31" href="#__codelineno-23-31"></a> <span class="p">}</span>
4283
- <a id="__codelineno-23-32" name="__codelineno-23-32" href="#__codelineno-23-32"></a> <span class="p">)</span>
5455
+ <a id="__codelineno-23-8" name="__codelineno-23-8" href="#__codelineno-23-8"></a><span class="k">class</span> <span class="nc">NewBranch</span><span class="p">(</span><span class="n">Job</span><span class="p">):</span>
5456
+ <a id="__codelineno-23-9" name="__codelineno-23-9" href="#__codelineno-23-9"></a> <span class="k">class</span> <span class="nc">Meta</span><span class="p">:</span>
5457
+ <a id="__codelineno-23-10" name="__codelineno-23-10" href="#__codelineno-23-10"></a> <span class="n">name</span> <span class="o">=</span> <span class="s2">&quot;New Branch&quot;</span>
5458
+ <a id="__codelineno-23-11" name="__codelineno-23-11" href="#__codelineno-23-11"></a> <span class="n">description</span> <span class="o">=</span> <span class="s2">&quot;Provision a new branch location&quot;</span>
5459
+ <a id="__codelineno-23-12" name="__codelineno-23-12" href="#__codelineno-23-12"></a> <span class="n">field_order</span> <span class="o">=</span> <span class="p">[</span><span class="s2">&quot;location_name&quot;</span><span class="p">,</span> <span class="s2">&quot;switch_count&quot;</span><span class="p">,</span> <span class="s2">&quot;switch_model&quot;</span><span class="p">]</span>
5460
+ <a id="__codelineno-23-13" name="__codelineno-23-13" href="#__codelineno-23-13"></a>
5461
+ <a id="__codelineno-23-14" name="__codelineno-23-14" href="#__codelineno-23-14"></a> <span class="n">location_name</span> <span class="o">=</span> <span class="n">StringVar</span><span class="p">(</span><span class="n">description</span><span class="o">=</span><span class="s2">&quot;Name of the new location&quot;</span><span class="p">)</span>
5462
+ <a id="__codelineno-23-15" name="__codelineno-23-15" href="#__codelineno-23-15"></a> <span class="n">switch_count</span> <span class="o">=</span> <span class="n">IntegerVar</span><span class="p">(</span><span class="n">description</span><span class="o">=</span><span class="s2">&quot;Number of access switches to create&quot;</span><span class="p">)</span>
5463
+ <a id="__codelineno-23-16" name="__codelineno-23-16" href="#__codelineno-23-16"></a> <span class="n">manufacturer</span> <span class="o">=</span> <span class="n">ObjectVar</span><span class="p">(</span><span class="n">model</span><span class="o">=</span><span class="n">Manufacturer</span><span class="p">,</span> <span class="n">required</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
5464
+ <a id="__codelineno-23-17" name="__codelineno-23-17" href="#__codelineno-23-17"></a> <span class="n">switch_model</span> <span class="o">=</span> <span class="n">ObjectVar</span><span class="p">(</span>
5465
+ <a id="__codelineno-23-18" name="__codelineno-23-18" href="#__codelineno-23-18"></a> <span class="n">description</span><span class="o">=</span><span class="s2">&quot;Access switch model&quot;</span><span class="p">,</span> <span class="n">model</span><span class="o">=</span><span class="n">DeviceType</span><span class="p">,</span> <span class="n">query_params</span><span class="o">=</span><span class="p">{</span><span class="s2">&quot;manufacturer_id&quot;</span><span class="p">:</span> <span class="s2">&quot;$manufacturer&quot;</span><span class="p">}</span>
5466
+ <a id="__codelineno-23-19" name="__codelineno-23-19" href="#__codelineno-23-19"></a> <span class="p">)</span>
5467
+ <a id="__codelineno-23-20" name="__codelineno-23-20" href="#__codelineno-23-20"></a>
5468
+ <a id="__codelineno-23-21" name="__codelineno-23-21" href="#__codelineno-23-21"></a> <span class="k">def</span> <span class="nf">run</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">location_name</span><span class="p">,</span> <span class="n">switch_count</span><span class="p">,</span> <span class="n">switch_model</span><span class="p">):</span>
5469
+ <a id="__codelineno-23-22" name="__codelineno-23-22" href="#__codelineno-23-22"></a> <span class="n">STATUS_PLANNED</span> <span class="o">=</span> <span class="n">Status</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s2">&quot;Planned&quot;</span><span class="p">)</span>
5470
+ <a id="__codelineno-23-23" name="__codelineno-23-23" href="#__codelineno-23-23"></a>
5471
+ <a id="__codelineno-23-24" name="__codelineno-23-24" href="#__codelineno-23-24"></a> <span class="c1"># Create the new location</span>
5472
+ <a id="__codelineno-23-25" name="__codelineno-23-25" href="#__codelineno-23-25"></a> <span class="n">root_type</span> <span class="o">=</span> <span class="n">LocationType</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">get_or_create</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s2">&quot;Campus&quot;</span><span class="p">)</span>
5473
+ <a id="__codelineno-23-26" name="__codelineno-23-26" href="#__codelineno-23-26"></a> <span class="n">location</span> <span class="o">=</span> <span class="n">Location</span><span class="p">(</span>
5474
+ <a id="__codelineno-23-27" name="__codelineno-23-27" href="#__codelineno-23-27"></a> <span class="n">name</span><span class="o">=</span><span class="n">location_name</span><span class="p">,</span>
5475
+ <a id="__codelineno-23-28" name="__codelineno-23-28" href="#__codelineno-23-28"></a> <span class="n">location_type</span><span class="o">=</span><span class="n">root_type</span><span class="p">,</span>
5476
+ <a id="__codelineno-23-29" name="__codelineno-23-29" href="#__codelineno-23-29"></a> <span class="n">status</span><span class="o">=</span><span class="n">STATUS_PLANNED</span><span class="p">,</span>
5477
+ <a id="__codelineno-23-30" name="__codelineno-23-30" href="#__codelineno-23-30"></a> <span class="p">)</span>
5478
+ <a id="__codelineno-23-31" name="__codelineno-23-31" href="#__codelineno-23-31"></a> <span class="n">location</span><span class="o">.</span><span class="n">validated_save</span><span class="p">()</span>
5479
+ <a id="__codelineno-23-32" name="__codelineno-23-32" href="#__codelineno-23-32"></a> <span class="bp">self</span><span class="o">.</span><span class="n">logger</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="s2">&quot;Created new location&quot;</span><span class="p">,</span> <span class="n">extra</span><span class="o">=</span><span class="p">{</span><span class="s2">&quot;object&quot;</span><span class="p">:</span> <span class="n">location</span><span class="p">})</span>
4284
5480
  <a id="__codelineno-23-33" name="__codelineno-23-33" href="#__codelineno-23-33"></a>
4285
- <a id="__codelineno-23-34" name="__codelineno-23-34" href="#__codelineno-23-34"></a> <span class="k">def</span> <span class="nf">run</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">data</span><span class="p">,</span> <span class="n">commit</span><span class="p">):</span>
4286
- <a id="__codelineno-23-35" name="__codelineno-23-35" href="#__codelineno-23-35"></a> <span class="n">STATUS_PLANNED</span> <span class="o">=</span> <span class="n">Status</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s1">&#39;Planned&#39;</span><span class="p">)</span>
4287
- <a id="__codelineno-23-36" name="__codelineno-23-36" href="#__codelineno-23-36"></a>
4288
- <a id="__codelineno-23-37" name="__codelineno-23-37" href="#__codelineno-23-37"></a> <span class="c1"># Create the new site</span>
4289
- <a id="__codelineno-23-38" name="__codelineno-23-38" href="#__codelineno-23-38"></a> <span class="n">site</span> <span class="o">=</span> <span class="n">Site</span><span class="p">(</span>
4290
- <a id="__codelineno-23-39" name="__codelineno-23-39" href="#__codelineno-23-39"></a> <span class="n">name</span><span class="o">=</span><span class="n">data</span><span class="p">[</span><span class="s1">&#39;site_name&#39;</span><span class="p">],</span>
4291
- <a id="__codelineno-23-40" name="__codelineno-23-40" href="#__codelineno-23-40"></a> <span class="n">slug</span><span class="o">=</span><span class="n">slugify</span><span class="p">(</span><span class="n">data</span><span class="p">[</span><span class="s1">&#39;site_name&#39;</span><span class="p">]),</span>
4292
- <a id="__codelineno-23-41" name="__codelineno-23-41" href="#__codelineno-23-41"></a> <span class="n">status</span><span class="o">=</span><span class="n">STATUS_PLANNED</span><span class="p">,</span>
4293
- <a id="__codelineno-23-42" name="__codelineno-23-42" href="#__codelineno-23-42"></a> <span class="p">)</span>
4294
- <a id="__codelineno-23-43" name="__codelineno-23-43" href="#__codelineno-23-43"></a> <span class="n">site</span><span class="o">.</span><span class="n">validated_save</span><span class="p">()</span>
4295
- <a id="__codelineno-23-44" name="__codelineno-23-44" href="#__codelineno-23-44"></a> <span class="bp">self</span><span class="o">.</span><span class="n">log_success</span><span class="p">(</span><span class="n">obj</span><span class="o">=</span><span class="n">site</span><span class="p">,</span> <span class="n">message</span><span class="o">=</span><span class="s2">&quot;Created new site&quot;</span><span class="p">)</span>
4296
- <a id="__codelineno-23-45" name="__codelineno-23-45" href="#__codelineno-23-45"></a>
4297
- <a id="__codelineno-23-46" name="__codelineno-23-46" href="#__codelineno-23-46"></a> <span class="c1"># Create access switches</span>
4298
- <a id="__codelineno-23-47" name="__codelineno-23-47" href="#__codelineno-23-47"></a> <span class="n">device_ct</span> <span class="o">=</span> <span class="n">ContentType</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">get_for_model</span><span class="p">(</span><span class="n">Device</span><span class="p">)</span>
4299
- <a id="__codelineno-23-48" name="__codelineno-23-48" href="#__codelineno-23-48"></a> <span class="n">switch_role</span> <span class="o">=</span> <span class="n">Role</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s1">&#39;Access Switch&#39;</span><span class="p">)</span>
4300
- <a id="__codelineno-23-49" name="__codelineno-23-49" href="#__codelineno-23-49"></a> <span class="n">switch_role</span><span class="o">.</span><span class="n">content_types</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">device_ct</span><span class="p">)</span>
4301
- <a id="__codelineno-23-50" name="__codelineno-23-50" href="#__codelineno-23-50"></a> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="n">data</span><span class="p">[</span><span class="s1">&#39;switch_count&#39;</span><span class="p">]</span> <span class="o">+</span> <span class="mi">1</span><span class="p">):</span>
4302
- <a id="__codelineno-23-51" name="__codelineno-23-51" href="#__codelineno-23-51"></a> <span class="n">switch</span> <span class="o">=</span> <span class="n">Device</span><span class="p">(</span>
4303
- <a id="__codelineno-23-52" name="__codelineno-23-52" href="#__codelineno-23-52"></a> <span class="n">device_type</span><span class="o">=</span><span class="n">data</span><span class="p">[</span><span class="s1">&#39;switch_model&#39;</span><span class="p">],</span>
4304
- <a id="__codelineno-23-53" name="__codelineno-23-53" href="#__codelineno-23-53"></a> <span class="n">name</span><span class="o">=</span><span class="sa">f</span><span class="s1">&#39;</span><span class="si">{</span><span class="n">site</span><span class="o">.</span><span class="n">slug</span><span class="si">}</span><span class="s1">-switch</span><span class="si">{</span><span class="n">i</span><span class="si">}</span><span class="s1">&#39;</span><span class="p">,</span>
4305
- <a id="__codelineno-23-54" name="__codelineno-23-54" href="#__codelineno-23-54"></a> <span class="n">site</span><span class="o">=</span><span class="n">site</span><span class="p">,</span>
4306
- <a id="__codelineno-23-55" name="__codelineno-23-55" href="#__codelineno-23-55"></a> <span class="n">status</span><span class="o">=</span><span class="n">STATUS_PLANNED</span><span class="p">,</span>
4307
- <a id="__codelineno-23-56" name="__codelineno-23-56" href="#__codelineno-23-56"></a> <span class="n">role</span><span class="o">=</span><span class="n">switch_role</span>
4308
- <a id="__codelineno-23-57" name="__codelineno-23-57" href="#__codelineno-23-57"></a> <span class="p">)</span>
4309
- <a id="__codelineno-23-58" name="__codelineno-23-58" href="#__codelineno-23-58"></a> <span class="n">switch</span><span class="o">.</span><span class="n">validated_save</span><span class="p">()</span>
4310
- <a id="__codelineno-23-59" name="__codelineno-23-59" href="#__codelineno-23-59"></a> <span class="bp">self</span><span class="o">.</span><span class="n">log_success</span><span class="p">(</span><span class="n">obj</span><span class="o">=</span><span class="n">switch</span><span class="p">,</span> <span class="n">message</span><span class="o">=</span><span class="s2">&quot;Created new switch&quot;</span><span class="p">)</span>
4311
- <a id="__codelineno-23-60" name="__codelineno-23-60" href="#__codelineno-23-60"></a>
4312
- <a id="__codelineno-23-61" name="__codelineno-23-61" href="#__codelineno-23-61"></a> <span class="c1"># Generate a CSV table of new devices</span>
4313
- <a id="__codelineno-23-62" name="__codelineno-23-62" href="#__codelineno-23-62"></a> <span class="n">output</span> <span class="o">=</span> <span class="p">[</span>
4314
- <a id="__codelineno-23-63" name="__codelineno-23-63" href="#__codelineno-23-63"></a> <span class="s1">&#39;name,make,model&#39;</span>
4315
- <a id="__codelineno-23-64" name="__codelineno-23-64" href="#__codelineno-23-64"></a> <span class="p">]</span>
4316
- <a id="__codelineno-23-65" name="__codelineno-23-65" href="#__codelineno-23-65"></a> <span class="k">for</span> <span class="n">switch</span> <span class="ow">in</span> <span class="n">Device</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="n">site</span><span class="o">=</span><span class="n">site</span><span class="p">):</span>
4317
- <a id="__codelineno-23-66" name="__codelineno-23-66" href="#__codelineno-23-66"></a> <span class="n">attrs</span> <span class="o">=</span> <span class="p">[</span>
4318
- <a id="__codelineno-23-67" name="__codelineno-23-67" href="#__codelineno-23-67"></a> <span class="n">switch</span><span class="o">.</span><span class="n">name</span><span class="p">,</span>
4319
- <a id="__codelineno-23-68" name="__codelineno-23-68" href="#__codelineno-23-68"></a> <span class="n">switch</span><span class="o">.</span><span class="n">device_type</span><span class="o">.</span><span class="n">manufacturer</span><span class="o">.</span><span class="n">name</span><span class="p">,</span>
4320
- <a id="__codelineno-23-69" name="__codelineno-23-69" href="#__codelineno-23-69"></a> <span class="n">switch</span><span class="o">.</span><span class="n">device_type</span><span class="o">.</span><span class="n">model</span>
4321
- <a id="__codelineno-23-70" name="__codelineno-23-70" href="#__codelineno-23-70"></a> <span class="p">]</span>
4322
- <a id="__codelineno-23-71" name="__codelineno-23-71" href="#__codelineno-23-71"></a> <span class="n">output</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="s1">&#39;,&#39;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">attrs</span><span class="p">))</span>
4323
- <a id="__codelineno-23-72" name="__codelineno-23-72" href="#__codelineno-23-72"></a>
4324
- <a id="__codelineno-23-73" name="__codelineno-23-73" href="#__codelineno-23-73"></a> <span class="k">return</span> <span class="s1">&#39;</span><span class="se">\n</span><span class="s1">&#39;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">output</span><span class="p">)</span>
5481
+ <a id="__codelineno-23-34" name="__codelineno-23-34" href="#__codelineno-23-34"></a> <span class="c1"># Create access switches</span>
5482
+ <a id="__codelineno-23-35" name="__codelineno-23-35" href="#__codelineno-23-35"></a> <span class="n">device_ct</span> <span class="o">=</span> <span class="n">ContentType</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">get_for_model</span><span class="p">(</span><span class="n">Device</span><span class="p">)</span>
5483
+ <a id="__codelineno-23-36" name="__codelineno-23-36" href="#__codelineno-23-36"></a> <span class="n">switch_role</span> <span class="o">=</span> <span class="n">Role</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s2">&quot;Access Switch&quot;</span><span class="p">)</span>
5484
+ <a id="__codelineno-23-37" name="__codelineno-23-37" href="#__codelineno-23-37"></a> <span class="n">switch_role</span><span class="o">.</span><span class="n">content_types</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">device_ct</span><span class="p">)</span>
5485
+ <a id="__codelineno-23-38" name="__codelineno-23-38" href="#__codelineno-23-38"></a> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="n">switch_count</span> <span class="o">+</span> <span class="mi">1</span><span class="p">):</span>
5486
+ <a id="__codelineno-23-39" name="__codelineno-23-39" href="#__codelineno-23-39"></a> <span class="n">switch</span> <span class="o">=</span> <span class="n">Device</span><span class="p">(</span>
5487
+ <a id="__codelineno-23-40" name="__codelineno-23-40" href="#__codelineno-23-40"></a> <span class="n">device_type</span><span class="o">=</span><span class="n">switch_model</span><span class="p">,</span>
5488
+ <a id="__codelineno-23-41" name="__codelineno-23-41" href="#__codelineno-23-41"></a> <span class="n">name</span><span class="o">=</span><span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">location</span><span class="o">.</span><span class="n">name</span><span class="si">}</span><span class="s2">-switch</span><span class="si">{</span><span class="n">i</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">,</span>
5489
+ <a id="__codelineno-23-42" name="__codelineno-23-42" href="#__codelineno-23-42"></a> <span class="n">location</span><span class="o">=</span><span class="n">location</span><span class="p">,</span>
5490
+ <a id="__codelineno-23-43" name="__codelineno-23-43" href="#__codelineno-23-43"></a> <span class="n">status</span><span class="o">=</span><span class="n">STATUS_PLANNED</span><span class="p">,</span>
5491
+ <a id="__codelineno-23-44" name="__codelineno-23-44" href="#__codelineno-23-44"></a> <span class="n">role</span><span class="o">=</span><span class="n">switch_role</span><span class="p">,</span>
5492
+ <a id="__codelineno-23-45" name="__codelineno-23-45" href="#__codelineno-23-45"></a> <span class="p">)</span>
5493
+ <a id="__codelineno-23-46" name="__codelineno-23-46" href="#__codelineno-23-46"></a> <span class="n">switch</span><span class="o">.</span><span class="n">validated_save</span><span class="p">()</span>
5494
+ <a id="__codelineno-23-47" name="__codelineno-23-47" href="#__codelineno-23-47"></a> <span class="bp">self</span><span class="o">.</span><span class="n">logger</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="s2">&quot;Created new switch&quot;</span><span class="p">,</span> <span class="n">extra</span><span class="o">=</span><span class="p">{</span><span class="s2">&quot;object&quot;</span><span class="p">:</span> <span class="n">switch</span><span class="p">})</span>
5495
+ <a id="__codelineno-23-48" name="__codelineno-23-48" href="#__codelineno-23-48"></a>
5496
+ <a id="__codelineno-23-49" name="__codelineno-23-49" href="#__codelineno-23-49"></a> <span class="c1"># Generate a CSV table of new devices</span>
5497
+ <a id="__codelineno-23-50" name="__codelineno-23-50" href="#__codelineno-23-50"></a> <span class="n">output</span> <span class="o">=</span> <span class="p">[</span><span class="s2">&quot;name,make,model&quot;</span><span class="p">]</span>
5498
+ <a id="__codelineno-23-51" name="__codelineno-23-51" href="#__codelineno-23-51"></a> <span class="k">for</span> <span class="n">switch</span> <span class="ow">in</span> <span class="n">Device</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="n">location</span><span class="o">=</span><span class="n">location</span><span class="p">):</span>
5499
+ <a id="__codelineno-23-52" name="__codelineno-23-52" href="#__codelineno-23-52"></a> <span class="n">attrs</span> <span class="o">=</span> <span class="p">[</span><span class="n">switch</span><span class="o">.</span><span class="n">name</span><span class="p">,</span> <span class="n">switch</span><span class="o">.</span><span class="n">device_type</span><span class="o">.</span><span class="n">manufacturer</span><span class="o">.</span><span class="n">name</span><span class="p">,</span> <span class="n">switch</span><span class="o">.</span><span class="n">device_type</span><span class="o">.</span><span class="n">model</span><span class="p">]</span>
5500
+ <a id="__codelineno-23-53" name="__codelineno-23-53" href="#__codelineno-23-53"></a> <span class="n">output</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="s2">&quot;,&quot;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">attrs</span><span class="p">))</span>
5501
+ <a id="__codelineno-23-54" name="__codelineno-23-54" href="#__codelineno-23-54"></a>
5502
+ <a id="__codelineno-23-55" name="__codelineno-23-55" href="#__codelineno-23-55"></a> <span class="k">return</span> <span class="s2">&quot;</span><span class="se">\n</span><span class="s2">&quot;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">output</span><span class="p">)</span>
4325
5503
  </code></pre></div>
4326
5504
  <h3 id="device-validation">Device validation<a class="headerlink" href="#device-validation" title="Permanent link">&para;</a></h3>
4327
5505
  <p>A job to perform various validation of Device data in Nautobot. As this job does not require any user input, it does not define any variables, nor does it implement a <code>run()</code> method.</p>
@@ -4337,41 +5515,49 @@ elements will be important in running jobs programmatically.</p>
4337
5515
  <a id="__codelineno-24-10" name="__codelineno-24-10" href="#__codelineno-24-10"></a> <span class="n">STATUS_ACTIVE</span> <span class="o">=</span> <span class="n">Status</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s1">&#39;Active&#39;</span><span class="p">)</span>
4338
5516
  <a id="__codelineno-24-11" name="__codelineno-24-11" href="#__codelineno-24-11"></a>
4339
5517
  <a id="__codelineno-24-12" name="__codelineno-24-12" href="#__codelineno-24-12"></a> <span class="c1"># Check that every console port for every active device has a connection defined.</span>
4340
- <a id="__codelineno-24-13" name="__codelineno-24-13" href="#__codelineno-24-13"></a> <span class="k">for</span> <span class="n">console_port</span> <span class="ow">in</span> <span class="n">ConsolePort</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">prefetch_related</span><span class="p">(</span><span class="s1">&#39;device&#39;</span><span class="p">)</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="n">device__status</span><span class="o">=</span><span class="n">STATUS_ACTIVE</span><span class="p">):</span>
5518
+ <a id="__codelineno-24-13" name="__codelineno-24-13" href="#__codelineno-24-13"></a> <span class="k">for</span> <span class="n">console_port</span> <span class="ow">in</span> <span class="n">ConsolePort</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">select_related</span><span class="p">(</span><span class="s1">&#39;device&#39;</span><span class="p">)</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="n">device__status</span><span class="o">=</span><span class="n">STATUS_ACTIVE</span><span class="p">):</span>
4341
5519
  <a id="__codelineno-24-14" name="__codelineno-24-14" href="#__codelineno-24-14"></a> <span class="k">if</span> <span class="n">console_port</span><span class="o">.</span><span class="n">connected_endpoint</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
4342
- <a id="__codelineno-24-15" name="__codelineno-24-15" href="#__codelineno-24-15"></a> <span class="bp">self</span><span class="o">.</span><span class="n">log_failure</span><span class="p">(</span>
4343
- <a id="__codelineno-24-16" name="__codelineno-24-16" href="#__codelineno-24-16"></a> <span class="n">obj</span><span class="o">=</span><span class="n">console_port</span><span class="o">.</span><span class="n">device</span><span class="p">,</span>
4344
- <a id="__codelineno-24-17" name="__codelineno-24-17" href="#__codelineno-24-17"></a> <span class="n">message</span><span class="o">=</span><span class="s2">&quot;No console connection defined for </span><span class="si">{}</span><span class="s2">&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">console_port</span><span class="o">.</span><span class="n">name</span><span class="p">)</span>
4345
- <a id="__codelineno-24-18" name="__codelineno-24-18" href="#__codelineno-24-18"></a> <span class="p">)</span>
4346
- <a id="__codelineno-24-19" name="__codelineno-24-19" href="#__codelineno-24-19"></a> <span class="k">elif</span> <span class="ow">not</span> <span class="n">console_port</span><span class="o">.</span><span class="n">connection_status</span><span class="p">:</span>
4347
- <a id="__codelineno-24-20" name="__codelineno-24-20" href="#__codelineno-24-20"></a> <span class="bp">self</span><span class="o">.</span><span class="n">log_warning</span><span class="p">(</span>
4348
- <a id="__codelineno-24-21" name="__codelineno-24-21" href="#__codelineno-24-21"></a> <span class="n">obj</span><span class="o">=</span><span class="n">console_port</span><span class="o">.</span><span class="n">device</span><span class="p">,</span>
4349
- <a id="__codelineno-24-22" name="__codelineno-24-22" href="#__codelineno-24-22"></a> <span class="n">message</span><span class="o">=</span><span class="s2">&quot;Console connection for </span><span class="si">{}</span><span class="s2"> marked as planned&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">console_port</span><span class="o">.</span><span class="n">name</span><span class="p">)</span>
4350
- <a id="__codelineno-24-23" name="__codelineno-24-23" href="#__codelineno-24-23"></a> <span class="p">)</span>
4351
- <a id="__codelineno-24-24" name="__codelineno-24-24" href="#__codelineno-24-24"></a> <span class="k">else</span><span class="p">:</span>
4352
- <a id="__codelineno-24-25" name="__codelineno-24-25" href="#__codelineno-24-25"></a> <span class="bp">self</span><span class="o">.</span><span class="n">log_success</span><span class="p">(</span><span class="n">obj</span><span class="o">=</span><span class="n">console_port</span><span class="o">.</span><span class="n">device</span><span class="p">)</span>
4353
- <a id="__codelineno-24-26" name="__codelineno-24-26" href="#__codelineno-24-26"></a>
4354
- <a id="__codelineno-24-27" name="__codelineno-24-27" href="#__codelineno-24-27"></a> <span class="k">def</span> <span class="nf">test_power_connections</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
4355
- <a id="__codelineno-24-28" name="__codelineno-24-28" href="#__codelineno-24-28"></a> <span class="n">STATUS_ACTIVE</span> <span class="o">=</span> <span class="n">Status</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s1">&#39;Active&#39;</span><span class="p">)</span>
4356
- <a id="__codelineno-24-29" name="__codelineno-24-29" href="#__codelineno-24-29"></a>
4357
- <a id="__codelineno-24-30" name="__codelineno-24-30" href="#__codelineno-24-30"></a> <span class="c1"># Check that every active device has at least two connected power supplies.</span>
4358
- <a id="__codelineno-24-31" name="__codelineno-24-31" href="#__codelineno-24-31"></a> <span class="k">for</span> <span class="n">device</span> <span class="ow">in</span> <span class="n">Device</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="n">status</span><span class="o">=</span><span class="n">STATUS_ACTIVE</span><span class="p">):</span>
4359
- <a id="__codelineno-24-32" name="__codelineno-24-32" href="#__codelineno-24-32"></a> <span class="n">connected_ports</span> <span class="o">=</span> <span class="mi">0</span>
4360
- <a id="__codelineno-24-33" name="__codelineno-24-33" href="#__codelineno-24-33"></a> <span class="k">for</span> <span class="n">power_port</span> <span class="ow">in</span> <span class="n">PowerPort</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="n">device</span><span class="o">=</span><span class="n">device</span><span class="p">):</span>
4361
- <a id="__codelineno-24-34" name="__codelineno-24-34" href="#__codelineno-24-34"></a> <span class="k">if</span> <span class="n">power_port</span><span class="o">.</span><span class="n">connected_endpoint</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
4362
- <a id="__codelineno-24-35" name="__codelineno-24-35" href="#__codelineno-24-35"></a> <span class="n">connected_ports</span> <span class="o">+=</span> <span class="mi">1</span>
4363
- <a id="__codelineno-24-36" name="__codelineno-24-36" href="#__codelineno-24-36"></a> <span class="k">if</span> <span class="ow">not</span> <span class="n">power_port</span><span class="o">.</span><span class="n">connection_status</span><span class="p">:</span>
4364
- <a id="__codelineno-24-37" name="__codelineno-24-37" href="#__codelineno-24-37"></a> <span class="bp">self</span><span class="o">.</span><span class="n">log_warning</span><span class="p">(</span>
4365
- <a id="__codelineno-24-38" name="__codelineno-24-38" href="#__codelineno-24-38"></a> <span class="n">obj</span><span class="o">=</span><span class="n">device</span><span class="p">,</span>
4366
- <a id="__codelineno-24-39" name="__codelineno-24-39" href="#__codelineno-24-39"></a> <span class="n">message</span><span class="o">=</span><span class="s2">&quot;Power connection for </span><span class="si">{}</span><span class="s2"> marked as planned&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">power_port</span><span class="o">.</span><span class="n">name</span><span class="p">)</span>
4367
- <a id="__codelineno-24-40" name="__codelineno-24-40" href="#__codelineno-24-40"></a> <span class="p">)</span>
4368
- <a id="__codelineno-24-41" name="__codelineno-24-41" href="#__codelineno-24-41"></a> <span class="k">if</span> <span class="n">connected_ports</span> <span class="o">&lt;</span> <span class="mi">2</span><span class="p">:</span>
4369
- <a id="__codelineno-24-42" name="__codelineno-24-42" href="#__codelineno-24-42"></a> <span class="bp">self</span><span class="o">.</span><span class="n">log_failure</span><span class="p">(</span>
4370
- <a id="__codelineno-24-43" name="__codelineno-24-43" href="#__codelineno-24-43"></a> <span class="n">obj</span><span class="o">=</span><span class="n">device</span><span class="p">,</span>
4371
- <a id="__codelineno-24-44" name="__codelineno-24-44" href="#__codelineno-24-44"></a> <span class="n">message</span><span class="o">=</span><span class="s2">&quot;</span><span class="si">{}</span><span class="s2"> connected power supplies found (2 needed)&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">connected_ports</span><span class="p">)</span>
4372
- <a id="__codelineno-24-45" name="__codelineno-24-45" href="#__codelineno-24-45"></a> <span class="p">)</span>
4373
- <a id="__codelineno-24-46" name="__codelineno-24-46" href="#__codelineno-24-46"></a> <span class="k">else</span><span class="p">:</span>
4374
- <a id="__codelineno-24-47" name="__codelineno-24-47" href="#__codelineno-24-47"></a> <span class="bp">self</span><span class="o">.</span><span class="n">log_success</span><span class="p">(</span><span class="n">obj</span><span class="o">=</span><span class="n">device</span><span class="p">)</span>
5520
+ <a id="__codelineno-24-15" name="__codelineno-24-15" href="#__codelineno-24-15"></a> <span class="bp">self</span><span class="o">.</span><span class="n">logger</span><span class="o">.</span><span class="n">error</span><span class="p">(</span>
5521
+ <a id="__codelineno-24-16" name="__codelineno-24-16" href="#__codelineno-24-16"></a> <span class="s2">&quot;No console connection defined for </span><span class="si">%s</span><span class="s2">&quot;</span><span class="p">,</span>
5522
+ <a id="__codelineno-24-17" name="__codelineno-24-17" href="#__codelineno-24-17"></a> <span class="n">console_port</span><span class="o">.</span><span class="n">name</span><span class="p">,</span>
5523
+ <a id="__codelineno-24-18" name="__codelineno-24-18" href="#__codelineno-24-18"></a> <span class="n">extra</span><span class="o">=</span><span class="p">{</span><span class="s2">&quot;object&quot;</span><span class="p">:</span> <span class="n">console_port</span><span class="o">.</span><span class="n">device</span><span class="p">},</span>
5524
+ <a id="__codelineno-24-19" name="__codelineno-24-19" href="#__codelineno-24-19"></a> <span class="p">)</span>
5525
+ <a id="__codelineno-24-20" name="__codelineno-24-20" href="#__codelineno-24-20"></a> <span class="k">elif</span> <span class="ow">not</span> <span class="n">console_port</span><span class="o">.</span><span class="n">connection_status</span><span class="p">:</span>
5526
+ <a id="__codelineno-24-21" name="__codelineno-24-21" href="#__codelineno-24-21"></a> <span class="bp">self</span><span class="o">.</span><span class="n">logger</span><span class="o">.</span><span class="n">warning</span><span class="p">(</span>
5527
+ <a id="__codelineno-24-22" name="__codelineno-24-22" href="#__codelineno-24-22"></a> <span class="s2">&quot;Console connection for </span><span class="si">%s</span><span class="s2"> marked as planned&quot;</span><span class="p">,</span>
5528
+ <a id="__codelineno-24-23" name="__codelineno-24-23" href="#__codelineno-24-23"></a> <span class="n">console_port</span><span class="o">.</span><span class="n">name</span><span class="p">,</span>
5529
+ <a id="__codelineno-24-24" name="__codelineno-24-24" href="#__codelineno-24-24"></a> <span class="n">extra</span><span class="o">=</span><span class="p">{</span><span class="s2">&quot;object&quot;</span><span class="p">:</span> <span class="n">console_port</span><span class="o">.</span><span class="n">device</span><span class="p">},</span>
5530
+ <a id="__codelineno-24-25" name="__codelineno-24-25" href="#__codelineno-24-25"></a> <span class="p">)</span>
5531
+ <a id="__codelineno-24-26" name="__codelineno-24-26" href="#__codelineno-24-26"></a> <span class="k">else</span><span class="p">:</span>
5532
+ <a id="__codelineno-24-27" name="__codelineno-24-27" href="#__codelineno-24-27"></a> <span class="bp">self</span><span class="o">.</span><span class="n">logger</span><span class="o">.</span><span class="n">info</span><span class="p">(</span>
5533
+ <a id="__codelineno-24-28" name="__codelineno-24-28" href="#__codelineno-24-28"></a> <span class="s2">&quot;Console port </span><span class="si">%s</span><span class="s2"> has a connection defined&quot;</span><span class="p">,</span>
5534
+ <a id="__codelineno-24-29" name="__codelineno-24-29" href="#__codelineno-24-29"></a> <span class="n">console_port</span><span class="o">.</span><span class="n">name</span><span class="p">,</span>
5535
+ <a id="__codelineno-24-30" name="__codelineno-24-30" href="#__codelineno-24-30"></a> <span class="n">extra</span><span class="o">=</span><span class="p">{</span><span class="s2">&quot;object&quot;</span><span class="p">:</span> <span class="n">console_port</span><span class="o">.</span><span class="n">device</span><span class="p">},</span>
5536
+ <a id="__codelineno-24-31" name="__codelineno-24-31" href="#__codelineno-24-31"></a> <span class="p">)</span>
5537
+ <a id="__codelineno-24-32" name="__codelineno-24-32" href="#__codelineno-24-32"></a>
5538
+ <a id="__codelineno-24-33" name="__codelineno-24-33" href="#__codelineno-24-33"></a> <span class="k">def</span> <span class="nf">test_power_connections</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
5539
+ <a id="__codelineno-24-34" name="__codelineno-24-34" href="#__codelineno-24-34"></a> <span class="n">STATUS_ACTIVE</span> <span class="o">=</span> <span class="n">Status</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s1">&#39;Active&#39;</span><span class="p">)</span>
5540
+ <a id="__codelineno-24-35" name="__codelineno-24-35" href="#__codelineno-24-35"></a>
5541
+ <a id="__codelineno-24-36" name="__codelineno-24-36" href="#__codelineno-24-36"></a> <span class="c1"># Check that every active device has at least two connected power supplies.</span>
5542
+ <a id="__codelineno-24-37" name="__codelineno-24-37" href="#__codelineno-24-37"></a> <span class="k">for</span> <span class="n">device</span> <span class="ow">in</span> <span class="n">Device</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="n">status</span><span class="o">=</span><span class="n">STATUS_ACTIVE</span><span class="p">):</span>
5543
+ <a id="__codelineno-24-38" name="__codelineno-24-38" href="#__codelineno-24-38"></a> <span class="n">connected_ports</span> <span class="o">=</span> <span class="mi">0</span>
5544
+ <a id="__codelineno-24-39" name="__codelineno-24-39" href="#__codelineno-24-39"></a> <span class="k">for</span> <span class="n">power_port</span> <span class="ow">in</span> <span class="n">PowerPort</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="n">device</span><span class="o">=</span><span class="n">device</span><span class="p">):</span>
5545
+ <a id="__codelineno-24-40" name="__codelineno-24-40" href="#__codelineno-24-40"></a> <span class="k">if</span> <span class="n">power_port</span><span class="o">.</span><span class="n">connected_endpoint</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
5546
+ <a id="__codelineno-24-41" name="__codelineno-24-41" href="#__codelineno-24-41"></a> <span class="n">connected_ports</span> <span class="o">+=</span> <span class="mi">1</span>
5547
+ <a id="__codelineno-24-42" name="__codelineno-24-42" href="#__codelineno-24-42"></a> <span class="k">if</span> <span class="ow">not</span> <span class="n">power_port</span><span class="o">.</span><span class="n">connection_status</span><span class="p">:</span>
5548
+ <a id="__codelineno-24-43" name="__codelineno-24-43" href="#__codelineno-24-43"></a> <span class="bp">self</span><span class="o">.</span><span class="n">logger</span><span class="o">.</span><span class="n">warning</span><span class="p">(</span>
5549
+ <a id="__codelineno-24-44" name="__codelineno-24-44" href="#__codelineno-24-44"></a> <span class="s2">&quot;Power connection for </span><span class="si">%s</span><span class="s2"> marked as planned&quot;</span><span class="p">,</span>
5550
+ <a id="__codelineno-24-45" name="__codelineno-24-45" href="#__codelineno-24-45"></a> <span class="n">power_port</span><span class="o">.</span><span class="n">name</span><span class="p">,</span>
5551
+ <a id="__codelineno-24-46" name="__codelineno-24-46" href="#__codelineno-24-46"></a> <span class="n">extra</span><span class="o">=</span><span class="p">{</span><span class="s2">&quot;object&quot;</span><span class="p">:</span> <span class="n">device</span><span class="p">},</span>
5552
+ <a id="__codelineno-24-47" name="__codelineno-24-47" href="#__codelineno-24-47"></a> <span class="p">)</span>
5553
+ <a id="__codelineno-24-48" name="__codelineno-24-48" href="#__codelineno-24-48"></a> <span class="k">if</span> <span class="n">connected_ports</span> <span class="o">&lt;</span> <span class="mi">2</span><span class="p">:</span>
5554
+ <a id="__codelineno-24-49" name="__codelineno-24-49" href="#__codelineno-24-49"></a> <span class="bp">self</span><span class="o">.</span><span class="n">logger</span><span class="o">.</span><span class="n">error</span><span class="p">(</span>
5555
+ <a id="__codelineno-24-50" name="__codelineno-24-50" href="#__codelineno-24-50"></a> <span class="s2">&quot;</span><span class="si">%s</span><span class="s2"> connected power supplies found (2 needed)&quot;</span><span class="p">,</span>
5556
+ <a id="__codelineno-24-51" name="__codelineno-24-51" href="#__codelineno-24-51"></a> <span class="n">connected_ports</span><span class="p">,</span>
5557
+ <a id="__codelineno-24-52" name="__codelineno-24-52" href="#__codelineno-24-52"></a> <span class="n">extra</span><span class="o">=</span><span class="p">{</span><span class="s2">&quot;object&quot;</span><span class="p">:</span> <span class="n">device</span><span class="p">},</span>
5558
+ <a id="__codelineno-24-53" name="__codelineno-24-53" href="#__codelineno-24-53"></a> <span class="p">)</span>
5559
+ <a id="__codelineno-24-54" name="__codelineno-24-54" href="#__codelineno-24-54"></a> <span class="k">else</span><span class="p">:</span>
5560
+ <a id="__codelineno-24-55" name="__codelineno-24-55" href="#__codelineno-24-55"></a> <span class="bp">self</span><span class="o">.</span><span class="n">logger</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="s2">&quot;At least two connected power supplies found&quot;</span><span class="p">,</span> <span class="n">extra</span><span class="o">=</span><span class="p">{</span><span class="s2">&quot;object&quot;</span><span class="p">:</span> <span class="n">device</span><span class="p">})</span>
4375
5561
  </code></pre></div>
4376
5562
 
4377
5563