nautobot 2.2.2__py3-none-any.whl → 2.2.4__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.
Potentially problematic release.
This version of nautobot might be problematic. Click here for more details.
- nautobot/apps/jobs.py +2 -0
- nautobot/core/api/utils.py +12 -9
- nautobot/core/apps/__init__.py +2 -2
- nautobot/core/celery/__init__.py +79 -68
- nautobot/core/celery/backends.py +9 -1
- nautobot/core/celery/control.py +4 -7
- nautobot/core/celery/schedulers.py +4 -2
- nautobot/core/celery/task.py +78 -5
- nautobot/core/graphql/schema.py +2 -1
- nautobot/core/jobs/__init__.py +2 -1
- nautobot/core/settings.py +6 -4
- nautobot/core/settings.yaml +51 -16
- nautobot/core/templates/admin/base.html +2 -2
- nautobot/core/templates/base_django.html +2 -2
- nautobot/core/templates/buttons/export.html +47 -47
- nautobot/core/templates/generic/object_list.html +3 -3
- nautobot/core/templates/inc/javascript.html +3 -0
- nautobot/core/templates/inc/media.html +3 -0
- nautobot/core/templates/login.html +2 -2
- nautobot/core/templates/nautobot_config.py.j2 +2 -0
- nautobot/core/templatetags/helpers.py +66 -9
- nautobot/core/testing/__init__.py +6 -1
- nautobot/core/testing/api.py +12 -13
- nautobot/core/testing/mixins.py +2 -2
- nautobot/core/testing/views.py +50 -51
- nautobot/core/tests/test_api.py +23 -2
- nautobot/core/tests/test_jobs.py +79 -2
- nautobot/core/tests/test_templatetags_helpers.py +32 -0
- nautobot/core/tests/test_views.py +52 -0
- nautobot/core/tests/test_views_utils.py +22 -1
- nautobot/core/utils/module_loading.py +89 -0
- nautobot/core/views/mixins.py +4 -0
- nautobot/core/views/utils.py +3 -2
- nautobot/dcim/choices.py +14 -0
- nautobot/dcim/forms.py +51 -1
- nautobot/dcim/models/device_components.py +9 -5
- nautobot/dcim/templates/dcim/location.html +32 -13
- nautobot/dcim/templates/dcim/location_migrate_data_to_contact.html +102 -0
- nautobot/dcim/tests/test_views.py +376 -55
- nautobot/dcim/urls.py +5 -0
- nautobot/dcim/views.py +172 -21
- nautobot/extras/api/serializers.py +17 -6
- nautobot/extras/api/views.py +21 -10
- nautobot/extras/constants.py +3 -3
- nautobot/extras/datasources/git.py +47 -58
- nautobot/extras/forms/forms.py +3 -1
- nautobot/extras/jobs.py +79 -146
- nautobot/extras/models/datasources.py +0 -2
- nautobot/extras/models/jobs.py +36 -18
- nautobot/extras/plugins/__init__.py +1 -20
- nautobot/extras/signals.py +6 -9
- nautobot/extras/test_jobs/__init__.py +8 -0
- nautobot/extras/test_jobs/dry_run.py +3 -2
- nautobot/extras/test_jobs/fail.py +43 -0
- nautobot/extras/test_jobs/ipaddress_vars.py +40 -1
- nautobot/extras/test_jobs/jobs_module/__init__.py +5 -0
- nautobot/extras/test_jobs/jobs_module/jobs_submodule/__init__.py +1 -0
- nautobot/extras/test_jobs/jobs_module/jobs_submodule/jobs.py +6 -0
- nautobot/extras/test_jobs/pass.py +40 -0
- nautobot/extras/test_jobs/relative_import.py +11 -0
- nautobot/extras/tests/test_api.py +3 -0
- nautobot/extras/tests/test_context_managers.py +18 -0
- nautobot/extras/tests/test_datasources.py +125 -118
- nautobot/extras/tests/test_job_variables.py +57 -15
- nautobot/extras/tests/test_jobs.py +135 -1
- nautobot/extras/tests/test_models.py +26 -19
- nautobot/extras/tests/test_plugins.py +1 -3
- nautobot/extras/tests/test_views.py +2 -4
- nautobot/extras/utils.py +2 -1
- nautobot/extras/views.py +82 -116
- nautobot/ipam/api/views.py +8 -1
- nautobot/ipam/graphql/types.py +11 -0
- nautobot/ipam/mixins.py +32 -0
- nautobot/ipam/models.py +2 -1
- nautobot/ipam/querysets.py +6 -1
- nautobot/ipam/tests/test_models.py +82 -0
- nautobot/ipam/views.py +6 -6
- nautobot/project-static/docs/404.html +107 -51
- nautobot/project-static/docs/apps/index.html +107 -51
- nautobot/project-static/docs/apps/nautobot-apps.html +107 -51
- nautobot/project-static/docs/assets/_mkdocstrings.css +6 -1
- nautobot/project-static/docs/assets/extra.css +11 -0
- nautobot/project-static/docs/assets/javascripts/bundle.3220b9d7.min.js +29 -0
- nautobot/project-static/docs/assets/javascripts/bundle.3220b9d7.min.js.map +7 -0
- nautobot/project-static/docs/assets/stylesheets/main.66ac8b77.min.css +1 -0
- nautobot/project-static/docs/assets/stylesheets/main.66ac8b77.min.css.map +1 -0
- nautobot/project-static/docs/code-reference/nautobot/apps/__init__.html +107 -51
- nautobot/project-static/docs/code-reference/nautobot/apps/admin.html +107 -51
- nautobot/project-static/docs/code-reference/nautobot/apps/api.html +108 -52
- nautobot/project-static/docs/code-reference/nautobot/apps/change_logging.html +107 -51
- nautobot/project-static/docs/code-reference/nautobot/apps/choices.html +107 -51
- nautobot/project-static/docs/code-reference/nautobot/apps/config.html +107 -51
- nautobot/project-static/docs/code-reference/nautobot/apps/constants.html +107 -51
- nautobot/project-static/docs/code-reference/nautobot/apps/datasources.html +107 -51
- nautobot/project-static/docs/code-reference/nautobot/apps/exceptions.html +107 -51
- nautobot/project-static/docs/code-reference/nautobot/apps/factory.html +107 -51
- nautobot/project-static/docs/code-reference/nautobot/apps/filters.html +107 -51
- nautobot/project-static/docs/code-reference/nautobot/apps/forms.html +107 -51
- nautobot/project-static/docs/code-reference/nautobot/apps/graphql.html +107 -51
- nautobot/project-static/docs/code-reference/nautobot/apps/jobs.html +287 -262
- nautobot/project-static/docs/code-reference/nautobot/apps/models.html +107 -51
- nautobot/project-static/docs/code-reference/nautobot/apps/querysets.html +107 -51
- nautobot/project-static/docs/code-reference/nautobot/apps/secrets.html +107 -51
- nautobot/project-static/docs/code-reference/nautobot/apps/tables.html +107 -51
- nautobot/project-static/docs/code-reference/nautobot/apps/testing.html +107 -51
- nautobot/project-static/docs/code-reference/nautobot/apps/ui.html +107 -51
- nautobot/project-static/docs/code-reference/nautobot/apps/urls.html +107 -51
- nautobot/project-static/docs/code-reference/nautobot/apps/utils.html +107 -51
- nautobot/project-static/docs/code-reference/nautobot/apps/views.html +107 -51
- nautobot/project-static/docs/development/apps/api/configuration-view.html +110 -54
- nautobot/project-static/docs/development/apps/api/database-backend-config.html +110 -54
- nautobot/project-static/docs/development/apps/api/models/django-admin.html +107 -51
- nautobot/project-static/docs/development/apps/api/models/global-search.html +110 -54
- nautobot/project-static/docs/development/apps/api/models/graphql.html +113 -57
- nautobot/project-static/docs/development/apps/api/models/index.html +107 -51
- nautobot/project-static/docs/development/apps/api/nautobot-app-config.html +113 -57
- nautobot/project-static/docs/development/apps/api/platform-features/custom-validators.html +107 -51
- nautobot/project-static/docs/development/apps/api/platform-features/filter-extensions.html +110 -54
- nautobot/project-static/docs/development/apps/api/platform-features/git-repository-content.html +107 -51
- nautobot/project-static/docs/development/apps/api/platform-features/index.html +107 -51
- nautobot/project-static/docs/development/apps/api/platform-features/jinja2-filters.html +110 -54
- nautobot/project-static/docs/development/apps/api/platform-features/jobs.html +111 -55
- nautobot/project-static/docs/development/apps/api/platform-features/populating-extensibility-features.html +110 -54
- nautobot/project-static/docs/development/apps/api/platform-features/secrets-providers.html +110 -54
- nautobot/project-static/docs/development/apps/api/platform-features/uniquely-identify-objects.html +107 -51
- nautobot/project-static/docs/development/apps/api/prometheus.html +110 -54
- nautobot/project-static/docs/development/apps/api/setup.html +107 -51
- nautobot/project-static/docs/development/apps/api/testing.html +113 -57
- nautobot/project-static/docs/development/apps/api/ui-extensions/banners.html +110 -54
- nautobot/project-static/docs/development/apps/api/ui-extensions/home-page.html +110 -54
- nautobot/project-static/docs/development/apps/api/ui-extensions/index.html +107 -51
- nautobot/project-static/docs/development/apps/api/ui-extensions/navigation.html +107 -51
- nautobot/project-static/docs/development/apps/api/ui-extensions/object-views.html +113 -57
- nautobot/project-static/docs/development/apps/api/views/base-template.html +107 -51
- nautobot/project-static/docs/development/apps/api/views/core-view-overrides.html +110 -54
- nautobot/project-static/docs/development/apps/api/views/django-generic-views.html +107 -51
- nautobot/project-static/docs/development/apps/api/views/help-documentation.html +110 -54
- nautobot/project-static/docs/development/apps/api/views/index.html +107 -51
- nautobot/project-static/docs/development/apps/api/views/nautobot-generic-views.html +113 -57
- nautobot/project-static/docs/development/apps/api/views/nautobotuiviewset.html +122 -66
- nautobot/project-static/docs/development/apps/api/views/nautobotuiviewsetrouter.html +110 -54
- nautobot/project-static/docs/development/apps/api/views/notes.html +110 -54
- nautobot/project-static/docs/development/apps/api/views/rest-api.html +107 -51
- nautobot/project-static/docs/development/apps/api/views/urls.html +107 -51
- nautobot/project-static/docs/development/apps/index.html +128 -72
- nautobot/project-static/docs/development/apps/migration/code-updates.html +107 -51
- nautobot/project-static/docs/development/apps/migration/dependency-updates.html +107 -51
- nautobot/project-static/docs/development/apps/migration/from-v1.html +107 -51
- nautobot/project-static/docs/development/apps/migration/model-updates/dcim.html +107 -51
- nautobot/project-static/docs/development/apps/migration/model-updates/extras.html +107 -51
- nautobot/project-static/docs/development/apps/migration/model-updates/global.html +107 -51
- nautobot/project-static/docs/development/apps/migration/model-updates/ipam.html +107 -51
- nautobot/project-static/docs/development/apps/porting-from-netbox.html +110 -54
- nautobot/project-static/docs/development/core/application-registry.html +242 -144
- nautobot/project-static/docs/development/core/best-practices.html +122 -66
- nautobot/project-static/docs/development/core/bootstrap-ui.html +107 -51
- nautobot/project-static/docs/development/core/caching.html +107 -51
- nautobot/project-static/docs/development/core/controllers.html +107 -51
- nautobot/project-static/docs/development/core/docker-compose-advanced-use-cases.html +113 -57
- nautobot/project-static/docs/development/core/generic-views.html +110 -54
- nautobot/project-static/docs/development/core/getting-started.html +135 -79
- nautobot/project-static/docs/development/core/homepage.html +110 -54
- nautobot/project-static/docs/development/core/index.html +107 -51
- nautobot/project-static/docs/development/core/model-checklist.html +156 -52
- nautobot/project-static/docs/development/core/model-features.html +108 -52
- nautobot/project-static/docs/development/core/natural-keys.html +110 -54
- nautobot/project-static/docs/development/core/navigation-menu.html +107 -51
- nautobot/project-static/docs/development/core/release-checklist.html +107 -51
- nautobot/project-static/docs/development/core/role-internals.html +107 -51
- nautobot/project-static/docs/development/core/settings.html +107 -51
- nautobot/project-static/docs/development/core/style-guide.html +110 -54
- nautobot/project-static/docs/development/core/templates.html +113 -57
- nautobot/project-static/docs/development/core/testing.html +125 -69
- nautobot/project-static/docs/development/core/user-preferences.html +107 -51
- nautobot/project-static/docs/development/index.html +107 -51
- nautobot/project-static/docs/development/jobs/index.html +504 -172
- nautobot/project-static/docs/development/jobs/migration/from-v1.html +111 -55
- nautobot/project-static/docs/docker/index.html +3 -3
- nautobot/project-static/docs/index.html +125 -69
- nautobot/project-static/docs/installation/selinux-troubleshooting.html +3 -3
- nautobot/project-static/docs/objects.inv +0 -0
- nautobot/project-static/docs/release-notes/index.html +107 -51
- nautobot/project-static/docs/release-notes/version-1.0.html +107 -51
- nautobot/project-static/docs/release-notes/version-1.1.html +107 -51
- nautobot/project-static/docs/release-notes/version-1.2.html +107 -51
- nautobot/project-static/docs/release-notes/version-1.3.html +107 -51
- nautobot/project-static/docs/release-notes/version-1.4.html +107 -51
- nautobot/project-static/docs/release-notes/version-1.5.html +116 -60
- nautobot/project-static/docs/release-notes/version-1.6.html +107 -51
- nautobot/project-static/docs/release-notes/version-2.0.html +110 -54
- nautobot/project-static/docs/release-notes/version-2.1.html +107 -51
- nautobot/project-static/docs/release-notes/version-2.2.html +500 -114
- nautobot/project-static/docs/requirements.txt +2 -2
- nautobot/project-static/docs/search/search_index.json +1 -1
- nautobot/project-static/docs/sitemap.xml +262 -262
- nautobot/project-static/docs/sitemap.xml.gz +0 -0
- nautobot/project-static/docs/user-guide/administration/configuration/authentication/ldap.html +107 -51
- nautobot/project-static/docs/user-guide/administration/configuration/authentication/remote.html +107 -51
- nautobot/project-static/docs/user-guide/administration/configuration/authentication/sso.html +107 -51
- nautobot/project-static/docs/user-guide/administration/configuration/index.html +107 -51
- nautobot/project-static/docs/user-guide/administration/configuration/optional-settings.html +251 -164
- nautobot/project-static/docs/user-guide/administration/configuration/required-settings.html +113 -57
- nautobot/project-static/docs/user-guide/administration/configuration/time-zones.html +107 -51
- nautobot/project-static/docs/user-guide/administration/guides/caching.html +113 -57
- nautobot/project-static/docs/user-guide/administration/guides/celery-queues.html +107 -51
- nautobot/project-static/docs/user-guide/administration/guides/healthcheck.html +107 -51
- nautobot/project-static/docs/user-guide/administration/guides/permissions.html +107 -51
- nautobot/project-static/docs/user-guide/administration/guides/prometheus-metrics.html +113 -57
- nautobot/project-static/docs/user-guide/administration/guides/replicating-nautobot.html +107 -51
- nautobot/project-static/docs/user-guide/administration/guides/request-profiling.html +107 -51
- nautobot/project-static/docs/user-guide/administration/guides/s3-django-storage.html +107 -51
- nautobot/project-static/docs/user-guide/administration/installation/app-install.html +171 -112
- nautobot/project-static/docs/user-guide/administration/installation/docker.html +13 -8626
- nautobot/project-static/docs/user-guide/administration/installation/external-authentication.html +117 -61
- nautobot/project-static/docs/user-guide/administration/installation/health-checks.html +13 -8614
- nautobot/project-static/docs/user-guide/administration/installation/http-server.html +252 -165
- nautobot/project-static/docs/user-guide/administration/installation/index.html +165 -192
- nautobot/project-static/docs/user-guide/administration/installation/install_system.html +411 -691
- nautobot/project-static/docs/user-guide/administration/installation/nautobot.html +248 -229
- nautobot/project-static/docs/user-guide/administration/installation/selinux-troubleshooting.html +13 -8118
- nautobot/project-static/docs/user-guide/administration/installation/services.html +350 -240
- nautobot/project-static/docs/user-guide/administration/installation-extras/docker.html +8684 -0
- nautobot/project-static/docs/user-guide/administration/installation-extras/health-checks.html +8672 -0
- nautobot/project-static/docs/user-guide/administration/installation-extras/selinux-troubleshooting.html +8176 -0
- nautobot/project-static/docs/user-guide/administration/migration/migrating-from-netbox.html +110 -54
- nautobot/project-static/docs/user-guide/administration/migration/migrating-from-postgresql.html +110 -54
- nautobot/project-static/docs/user-guide/administration/tools/nautobot-server.html +155 -99
- nautobot/project-static/docs/user-guide/administration/tools/nautobot-shell.html +107 -51
- nautobot/project-static/docs/user-guide/administration/upgrading/database-backup.html +109 -53
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/after-you-upgrade.html +107 -51
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/before-you-upgrade.html +107 -51
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/for-developers.html +107 -51
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/index.html +107 -51
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/whats-changed.html +107 -51
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/region-and-site-data-migration-guide.html +107 -51
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/upgrading-from-nautobot-v1.html +117 -58
- nautobot/project-static/docs/user-guide/administration/upgrading/upgrading.html +113 -57
- nautobot/project-static/docs/user-guide/core-data-model/circuits/circuit.html +107 -51
- nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittermination.html +107 -51
- nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittype.html +107 -51
- nautobot/project-static/docs/user-guide/core-data-model/circuits/provider.html +107 -51
- nautobot/project-static/docs/user-guide/core-data-model/circuits/providernetwork.html +110 -54
- nautobot/project-static/docs/user-guide/core-data-model/dcim/cable.html +107 -51
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleport.html +110 -54
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleporttemplate.html +110 -54
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverport.html +110 -54
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverporttemplate.html +110 -54
- nautobot/project-static/docs/user-guide/core-data-model/dcim/controller.html +107 -51
- nautobot/project-static/docs/user-guide/core-data-model/dcim/controllermanageddevicegroup.html +107 -51
- nautobot/project-static/docs/user-guide/core-data-model/dcim/device.html +113 -57
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebay.html +110 -54
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebaytemplate.html +110 -54
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicefamily.html +110 -54
- nautobot/project-static/docs/user-guide/core-data-model/dcim/deviceredundancygroup.html +110 -54
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicetype.html +116 -60
- nautobot/project-static/docs/user-guide/core-data-model/dcim/frontport.html +110 -54
- nautobot/project-static/docs/user-guide/core-data-model/dcim/frontporttemplate.html +110 -54
- nautobot/project-static/docs/user-guide/core-data-model/dcim/interface.html +119 -63
- nautobot/project-static/docs/user-guide/core-data-model/dcim/interfaceredundancygroup.html +110 -54
- nautobot/project-static/docs/user-guide/core-data-model/dcim/interfacetemplate.html +110 -54
- nautobot/project-static/docs/user-guide/core-data-model/dcim/inventoryitem.html +113 -57
- nautobot/project-static/docs/user-guide/core-data-model/dcim/location.html +113 -57
- nautobot/project-static/docs/user-guide/core-data-model/dcim/locationtype.html +113 -57
- nautobot/project-static/docs/user-guide/core-data-model/dcim/manufacturer.html +107 -51
- nautobot/project-static/docs/user-guide/core-data-model/dcim/platform.html +113 -57
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerfeed.html +107 -51
- nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlet.html +110 -54
- nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlettemplate.html +110 -54
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerpanel.html +107 -51
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerport.html +110 -54
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerporttemplate.html +110 -54
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rack.html +107 -51
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rackgroup.html +107 -51
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rackreservation.html +107 -51
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rearport.html +110 -54
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rearporttemplate.html +110 -54
- nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareimagefile.html +110 -54
- nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareversion.html +110 -54
- nautobot/project-static/docs/user-guide/core-data-model/dcim/virtualchassis.html +107 -51
- nautobot/project-static/docs/user-guide/core-data-model/extras/configcontext.html +113 -57
- nautobot/project-static/docs/user-guide/core-data-model/extras/configcontextschema.html +110 -54
- nautobot/project-static/docs/user-guide/core-data-model/extras/contact.html +110 -54
- nautobot/project-static/docs/user-guide/core-data-model/extras/team.html +110 -54
- nautobot/project-static/docs/user-guide/core-data-model/ipam/ipaddress.html +125 -69
- nautobot/project-static/docs/user-guide/core-data-model/ipam/namespace.html +113 -57
- nautobot/project-static/docs/user-guide/core-data-model/ipam/prefix.html +128 -72
- nautobot/project-static/docs/user-guide/core-data-model/ipam/rir.html +110 -54
- nautobot/project-static/docs/user-guide/core-data-model/ipam/routetarget.html +107 -51
- nautobot/project-static/docs/user-guide/core-data-model/ipam/service.html +110 -54
- nautobot/project-static/docs/user-guide/core-data-model/ipam/vlan.html +227 -60
- nautobot/project-static/docs/user-guide/core-data-model/ipam/vlangroup.html +107 -51
- nautobot/project-static/docs/user-guide/core-data-model/ipam/vrf.html +113 -57
- nautobot/project-static/docs/user-guide/core-data-model/overview/introduction.html +107 -51
- nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenant.html +110 -54
- nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenantgroup.html +107 -51
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/cluster.html +107 -51
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustergroup.html +107 -51
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustertype.html +107 -51
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/virtualmachine.html +113 -57
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/vminterface.html +113 -57
- nautobot/project-static/docs/user-guide/feature-guides/contacts-and-teams.html +107 -51
- nautobot/project-static/docs/user-guide/feature-guides/custom-fields.html +113 -57
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-devices.html +107 -51
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-location-types-and-locations.html +107 -51
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/index.html +107 -51
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/interfaces.html +107 -51
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/ipam.html +107 -51
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/platforms.html +107 -51
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/search-bar.html +107 -51
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/tenants.html +107 -51
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/vlans-and-vlan-groups.html +107 -51
- nautobot/project-static/docs/user-guide/feature-guides/git-data-source.html +110 -54
- nautobot/project-static/docs/user-guide/feature-guides/graphql.html +113 -57
- nautobot/project-static/docs/user-guide/feature-guides/ip-address-merge-tool.html +107 -51
- nautobot/project-static/docs/user-guide/feature-guides/relationships.html +110 -54
- nautobot/project-static/docs/user-guide/feature-guides/software-image-files-and-versions.html +107 -51
- nautobot/project-static/docs/user-guide/index.html +109 -53
- nautobot/project-static/docs/user-guide/platform-functionality/change-logging.html +107 -51
- nautobot/project-static/docs/user-guide/platform-functionality/computedfield.html +113 -57
- nautobot/project-static/docs/user-guide/platform-functionality/customfield.html +128 -72
- nautobot/project-static/docs/user-guide/platform-functionality/customlink.html +107 -51
- nautobot/project-static/docs/user-guide/platform-functionality/dynamicgroup.html +125 -69
- nautobot/project-static/docs/user-guide/platform-functionality/exporttemplate.html +107 -51
- nautobot/project-static/docs/user-guide/platform-functionality/externalintegration.html +110 -54
- nautobot/project-static/docs/user-guide/platform-functionality/gitrepository.html +125 -69
- nautobot/project-static/docs/user-guide/platform-functionality/graphql.html +110 -54
- nautobot/project-static/docs/user-guide/platform-functionality/graphqlquery.html +107 -51
- nautobot/project-static/docs/user-guide/platform-functionality/imageattachment.html +107 -51
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/index.html +143 -100
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/job-scheduling-and-approvals.html +113 -57
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobbutton.html +113 -57
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobhook.html +110 -54
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/models.html +123 -67
- nautobot/project-static/docs/user-guide/platform-functionality/napalm.html +107 -51
- nautobot/project-static/docs/user-guide/platform-functionality/note.html +110 -54
- nautobot/project-static/docs/user-guide/platform-functionality/relationship.html +116 -60
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/authentication.html +110 -54
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/filtering.html +131 -75
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/overview.html +149 -93
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/ui-related-endpoints.html +110 -54
- nautobot/project-static/docs/user-guide/platform-functionality/role.html +107 -51
- nautobot/project-static/docs/user-guide/platform-functionality/secret.html +116 -60
- nautobot/project-static/docs/user-guide/platform-functionality/status.html +119 -63
- nautobot/project-static/docs/user-guide/platform-functionality/tag.html +110 -54
- nautobot/project-static/docs/user-guide/platform-functionality/template-filters.html +137 -81
- nautobot/project-static/docs/user-guide/platform-functionality/users/objectpermission.html +110 -54
- nautobot/project-static/docs/user-guide/platform-functionality/users/token.html +107 -51
- nautobot/project-static/docs/user-guide/platform-functionality/webhook.html +110 -54
- nautobot/project-static/js/forms.js +18 -11
- nautobot/tenancy/views.py +2 -6
- nautobot/virtualization/views.py +5 -9
- {nautobot-2.2.2.dist-info → nautobot-2.2.4.dist-info}/METADATA +4 -4
- {nautobot-2.2.2.dist-info → nautobot-2.2.4.dist-info}/RECORD +357 -348
- nautobot/extras/test_jobs/job_variables.py +0 -93
- nautobot/project-static/docs/assets/javascripts/bundle.bd41221c.min.js +0 -29
- nautobot/project-static/docs/assets/javascripts/bundle.bd41221c.min.js.map +0 -7
- nautobot/project-static/docs/assets/stylesheets/main.bcfcd587.min.css +0 -1
- nautobot/project-static/docs/assets/stylesheets/main.bcfcd587.min.css.map +0 -1
- {nautobot-2.2.2.dist-info → nautobot-2.2.4.dist-info}/LICENSE.txt +0 -0
- {nautobot-2.2.2.dist-info → nautobot-2.2.4.dist-info}/NOTICE +0 -0
- {nautobot-2.2.2.dist-info → nautobot-2.2.4.dist-info}/WHEEL +0 -0
- {nautobot-2.2.2.dist-info → nautobot-2.2.4.dist-info}/entry_points.txt +0 -0
|
@@ -31,7 +31,6 @@ logger = getLogger(__name__)
|
|
|
31
31
|
registry["plugin_banners"] = []
|
|
32
32
|
registry["plugin_custom_validators"] = collections.defaultdict(list)
|
|
33
33
|
registry["plugin_graphql_types"] = []
|
|
34
|
-
registry["plugin_jobs"] = []
|
|
35
34
|
registry["plugin_template_extensions"] = collections.defaultdict(list)
|
|
36
35
|
registry["app_metrics"] = []
|
|
37
36
|
|
|
@@ -141,9 +140,9 @@ class NautobotAppConfig(NautobotConfig):
|
|
|
141
140
|
register_graphql_types(graphql_types)
|
|
142
141
|
|
|
143
142
|
# Import jobs (if present)
|
|
143
|
+
# Note that we do *not* auto-call `register_jobs()` - the App is responsible for doing so when imported.
|
|
144
144
|
jobs = import_object(f"{self.__module__}.{self.jobs}")
|
|
145
145
|
if jobs is not None:
|
|
146
|
-
register_jobs(jobs)
|
|
147
146
|
self.features["jobs"] = jobs
|
|
148
147
|
|
|
149
148
|
# Import metrics (if present)
|
|
@@ -423,24 +422,6 @@ def register_graphql_types(class_list):
|
|
|
423
422
|
registry["plugin_graphql_types"].append(item)
|
|
424
423
|
|
|
425
424
|
|
|
426
|
-
def register_jobs(class_list):
|
|
427
|
-
"""
|
|
428
|
-
Register a list of Job classes
|
|
429
|
-
"""
|
|
430
|
-
from nautobot.extras.jobs import Job
|
|
431
|
-
|
|
432
|
-
for job in class_list:
|
|
433
|
-
if not inspect.isclass(job):
|
|
434
|
-
raise TypeError(f"Job class {job} was passed as an instance!")
|
|
435
|
-
if not issubclass(job, Job):
|
|
436
|
-
raise TypeError(f"{job} is not a subclass of extras.jobs.Job!")
|
|
437
|
-
|
|
438
|
-
registry["plugin_jobs"].append(job)
|
|
439
|
-
|
|
440
|
-
# Note that we do not (and cannot) update the Job records in the Nautobot database at this time.
|
|
441
|
-
# That is done in response to the `nautobot_database_ready` signal, see nautobot.extras.signals.refresh_job_models
|
|
442
|
-
|
|
443
|
-
|
|
444
425
|
def register_metrics(function_list):
|
|
445
426
|
"""
|
|
446
427
|
Register a list of metric functions
|
nautobot/extras/signals.py
CHANGED
|
@@ -21,7 +21,7 @@ from django.utils import timezone
|
|
|
21
21
|
from django_prometheus.models import model_deletes, model_inserts, model_updates
|
|
22
22
|
import redis.exceptions
|
|
23
23
|
|
|
24
|
-
from nautobot.core.celery import app,
|
|
24
|
+
from nautobot.core.celery import app, import_jobs
|
|
25
25
|
from nautobot.core.models import BaseModel
|
|
26
26
|
from nautobot.core.utils.config import get_settings_or_config
|
|
27
27
|
from nautobot.core.utils.logging import sanitize
|
|
@@ -333,7 +333,7 @@ def git_repository_pre_delete(instance, **kwargs):
|
|
|
333
333
|
app.control.broadcast("discard_git_repository", repository_slug=instance.slug)
|
|
334
334
|
# But we don't have an equivalent way to broadcast to any other Django instances.
|
|
335
335
|
# For now we just delete the one that we have locally and rely on other methods,
|
|
336
|
-
# such as the
|
|
336
|
+
# such as the import_jobs() signal that runs on server startup,
|
|
337
337
|
# to clean up other clones as they're encountered.
|
|
338
338
|
if os.path.isdir(instance.filesystem_path):
|
|
339
339
|
shutil.rmtree(instance.filesystem_path)
|
|
@@ -462,7 +462,7 @@ def refresh_job_models(sender, *, apps, **kwargs):
|
|
|
462
462
|
"""
|
|
463
463
|
Callback for the nautobot_database_ready signal; updates Jobs in the database based on Job source file availability.
|
|
464
464
|
"""
|
|
465
|
-
from nautobot.extras.jobs import
|
|
465
|
+
from nautobot.extras.jobs import get_jobs # avoid circular import
|
|
466
466
|
|
|
467
467
|
Job = apps.get_model("extras", "Job")
|
|
468
468
|
|
|
@@ -471,15 +471,12 @@ def refresh_job_models(sender, *, apps, **kwargs):
|
|
|
471
471
|
logger.info("Skipping refresh_job_models() as it appears Job model has not yet been migrated to latest.")
|
|
472
472
|
return
|
|
473
473
|
|
|
474
|
-
|
|
474
|
+
import_jobs()
|
|
475
475
|
|
|
476
476
|
job_models = []
|
|
477
|
-
for task in app.tasks.values():
|
|
478
|
-
# Skip Celery tasks that aren't Jobs
|
|
479
|
-
if not isinstance(task, JobClass):
|
|
480
|
-
continue
|
|
481
477
|
|
|
482
|
-
|
|
478
|
+
for job_class in get_jobs().values():
|
|
479
|
+
job_model, _ = refresh_job_model_from_job_class(Job, job_class)
|
|
483
480
|
if job_model is not None:
|
|
484
481
|
job_models.append(job_model)
|
|
485
482
|
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
def load_tests(*args):
|
|
2
|
+
"""Implement unittest discovery for this submodule as a no-op.
|
|
3
|
+
|
|
4
|
+
This prevents unittest from recursively loading all of the modules under this directory to inspect whether they
|
|
5
|
+
define test cases. This is necessary because otherwise the `jobs_module` submodule will get loaded when tests run,
|
|
6
|
+
which will in turn call `register_jobs()`, incorrectly/unexpectedly registering the test Job defined in that module
|
|
7
|
+
as if it were a system Job, which will cause tests to fail due to the unexpected presence of this Job.
|
|
8
|
+
"""
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
from nautobot.core.celery import register_jobs
|
|
2
|
-
from nautobot.extras.jobs import DryRunVar, get_task_logger, Job
|
|
2
|
+
from nautobot.extras.jobs import DryRunVar, get_task_logger, IntegerVar, Job
|
|
3
3
|
from nautobot.extras.models import Status
|
|
4
4
|
|
|
5
5
|
logger = get_task_logger(__name__)
|
|
@@ -11,8 +11,9 @@ class TestDryRun(Job):
|
|
|
11
11
|
"""
|
|
12
12
|
|
|
13
13
|
dryrun = DryRunVar()
|
|
14
|
+
value = IntegerVar(required=False)
|
|
14
15
|
|
|
15
|
-
def run(self, dryrun):
|
|
16
|
+
def run(self, dryrun, value=None):
|
|
16
17
|
"""
|
|
17
18
|
Job function.
|
|
18
19
|
"""
|
|
@@ -1,4 +1,7 @@
|
|
|
1
|
+
from billiard.einfo import ExceptionInfo
|
|
2
|
+
|
|
1
3
|
from nautobot.core.celery import register_jobs
|
|
4
|
+
from nautobot.extras.choices import JobResultStatusChoices
|
|
2
5
|
from nautobot.extras.jobs import get_task_logger, Job, RunJobTaskFailed
|
|
3
6
|
|
|
4
7
|
logger = get_task_logger(__name__)
|
|
@@ -11,6 +14,15 @@ class TestFail(Job):
|
|
|
11
14
|
|
|
12
15
|
description = "Validate job import"
|
|
13
16
|
|
|
17
|
+
def before_start(self, task_id, args, kwargs):
|
|
18
|
+
if task_id != self.request.id:
|
|
19
|
+
raise RuntimeError(f"Expected task_id {task_id} to equal self.request.id {self.request.id}")
|
|
20
|
+
if args:
|
|
21
|
+
raise RuntimeError(f"Expected args to be empty, but it was {args!r}")
|
|
22
|
+
if kwargs:
|
|
23
|
+
raise RuntimeError(f"Expected kwargs to be empty, but it was {kwargs!r}")
|
|
24
|
+
logger.info("before_start() was called as expected")
|
|
25
|
+
|
|
14
26
|
def run(self):
|
|
15
27
|
"""
|
|
16
28
|
Job function.
|
|
@@ -18,6 +30,37 @@ class TestFail(Job):
|
|
|
18
30
|
logger.info("I'm a test job that fails!")
|
|
19
31
|
raise RunJobTaskFailed("Test failure")
|
|
20
32
|
|
|
33
|
+
def on_success(self, retval, task_id, args, kwargs):
|
|
34
|
+
raise RuntimeError("on_success() was unexpectedly called!")
|
|
35
|
+
|
|
36
|
+
def on_failure(self, exc, task_id, args, kwargs, einfo):
|
|
37
|
+
if not isinstance(exc, RunJobTaskFailed):
|
|
38
|
+
raise RuntimeError(f"Expected exc to be a RunJobTaskFailed, but it was {exc!r}")
|
|
39
|
+
if task_id != self.request.id:
|
|
40
|
+
raise RuntimeError(f"Expected task_id {task_id} to equal self.request.id {self.request.id}")
|
|
41
|
+
if args:
|
|
42
|
+
raise RuntimeError(f"Expected args to be empty, but it was {args!r}")
|
|
43
|
+
if kwargs:
|
|
44
|
+
raise RuntimeError(f"Expected kwargs to be empty, but it was {kwargs!r}")
|
|
45
|
+
if not isinstance(einfo, ExceptionInfo):
|
|
46
|
+
raise RuntimeError(f"Expected einfo to be an ExceptionInfo, but it was {einfo!r}")
|
|
47
|
+
logger.info("on_failure() was called as expected")
|
|
48
|
+
|
|
49
|
+
def after_return(self, status, retval, task_id, args, kwargs, einfo):
|
|
50
|
+
if status is not JobResultStatusChoices.STATUS_FAILURE:
|
|
51
|
+
raise RuntimeError(f"Expected status to be {JobResultStatusChoices.STATUS_FAILURE}, but it was {status!r}")
|
|
52
|
+
if not isinstance(retval, RunJobTaskFailed):
|
|
53
|
+
raise RuntimeError(f"Expected retval to be a RunJobTaskFailed, but it was {retval!r}")
|
|
54
|
+
if task_id != self.request.id:
|
|
55
|
+
raise RuntimeError(f"Expected task_id {task_id} to equal self.request.id {self.request.id}")
|
|
56
|
+
if args:
|
|
57
|
+
raise RuntimeError(f"Expected args to be empty, but it was {args!r}")
|
|
58
|
+
if kwargs:
|
|
59
|
+
raise RuntimeError(f"Expected kwargs to be empty, but it was {kwargs!r}")
|
|
60
|
+
if not isinstance(einfo, ExceptionInfo):
|
|
61
|
+
raise RuntimeError(f"Expected einfo to be an ExceptionInfo, but it was {einfo!r}")
|
|
62
|
+
logger.info("after_return() was called as expected")
|
|
63
|
+
|
|
21
64
|
|
|
22
65
|
class TestFailWithSanitization(Job):
|
|
23
66
|
"""
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import json
|
|
2
2
|
|
|
3
|
+
import netaddr
|
|
4
|
+
|
|
3
5
|
from nautobot.core.celery import register_jobs
|
|
4
6
|
from nautobot.extras.jobs import get_task_logger, IPAddressVar, IPAddressWithMaskVar, Job
|
|
5
7
|
|
|
@@ -30,7 +32,26 @@ class TestIPAddresses(Job):
|
|
|
30
32
|
description="IPv6 network",
|
|
31
33
|
)
|
|
32
34
|
|
|
33
|
-
def
|
|
35
|
+
def before_start(self, task_id, args, kwargs):
|
|
36
|
+
for expected_kwarg in self._get_vars().keys():
|
|
37
|
+
if expected_kwarg not in kwargs:
|
|
38
|
+
raise RuntimeError(f"kwargs should contain {expected_kwarg} but it doesn't!")
|
|
39
|
+
if kwargs[expected_kwarg] is None:
|
|
40
|
+
raise RuntimeError(f"kwargs[{expected_kwarg}] is unexpectedly None!")
|
|
41
|
+
|
|
42
|
+
def run(self, *, ipv4_address, ipv4_with_mask, ipv4_network, ipv6_address, ipv6_with_mask, ipv6_network):
|
|
43
|
+
if not isinstance(ipv4_address, netaddr.IPAddress):
|
|
44
|
+
raise RuntimeError(f"Expected ipv4_address to be a netaddr.IPAddress, but it was {ipv4_address!r}")
|
|
45
|
+
if not isinstance(ipv4_with_mask, netaddr.IPNetwork):
|
|
46
|
+
raise RuntimeError(f"Expected ipv4_with_mask to be a netaddr.IPNetwork, but it was {ipv4_with_mask!r}")
|
|
47
|
+
if not isinstance(ipv4_network, netaddr.IPNetwork):
|
|
48
|
+
raise RuntimeError(f"Expected ipv4_network to be a netaddr.IPNetwork, but it was {ipv4_network!r}")
|
|
49
|
+
if not isinstance(ipv6_address, netaddr.IPAddress):
|
|
50
|
+
raise RuntimeError(f"Expected ipv6_address to be a netaddr.IPAddress, but it was {ipv6_address!r}")
|
|
51
|
+
if not isinstance(ipv6_with_mask, netaddr.IPNetwork):
|
|
52
|
+
raise RuntimeError(f"Expected ipv6_with_mask to be a netaddr.IPNetwork, but it was {ipv6_with_mask!r}")
|
|
53
|
+
if not isinstance(ipv6_network, netaddr.IPNetwork):
|
|
54
|
+
raise RuntimeError(f"Expected ipv6_network to be a netaddr.IPNetwork, but it was {ipv6_network!r}")
|
|
34
55
|
# Log the data as JSON so we can pull it back out for testing.
|
|
35
56
|
logger.info(
|
|
36
57
|
"IP Address Test",
|
|
@@ -59,5 +80,23 @@ class TestIPAddresses(Job):
|
|
|
59
80
|
|
|
60
81
|
return "Nice IPs, bro."
|
|
61
82
|
|
|
83
|
+
def on_success(self, retval, task_id, args, kwargs):
|
|
84
|
+
if retval != "Nice IPs, bro.":
|
|
85
|
+
raise RuntimeError(f"retval is unexpected: {retval!r}")
|
|
86
|
+
for expected_kwarg in self._get_vars().keys():
|
|
87
|
+
if expected_kwarg not in kwargs:
|
|
88
|
+
raise RuntimeError(f"kwargs should contain {expected_kwarg} but it doesn't!")
|
|
89
|
+
if kwargs[expected_kwarg] is None:
|
|
90
|
+
raise RuntimeError(f"kwargs[{expected_kwarg}] is unexpectedly None!")
|
|
91
|
+
|
|
92
|
+
def after_return(self, status, retval, task_id, args, kwargs, einfo):
|
|
93
|
+
if retval != "Nice IPs, bro.":
|
|
94
|
+
raise RuntimeError(f"retval is unexpected: {retval!r}")
|
|
95
|
+
for expected_kwarg in self._get_vars().keys():
|
|
96
|
+
if expected_kwarg not in kwargs:
|
|
97
|
+
raise RuntimeError(f"kwargs should contain {expected_kwarg} but it doesn't!")
|
|
98
|
+
if kwargs[expected_kwarg] is None:
|
|
99
|
+
raise RuntimeError(f"kwargs[{expected_kwarg}] is unexpectedly None!")
|
|
100
|
+
|
|
62
101
|
|
|
63
102
|
register_jobs(TestIPAddresses)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from .jobs import ChildJob # noqa: F401
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
from nautobot.core.celery import register_jobs
|
|
2
|
+
from nautobot.extras.choices import JobResultStatusChoices
|
|
2
3
|
from nautobot.extras.jobs import get_task_logger, Job
|
|
3
4
|
|
|
4
5
|
logger = get_task_logger(__name__)
|
|
@@ -14,11 +15,50 @@ class TestPass(Job):
|
|
|
14
15
|
class Meta:
|
|
15
16
|
has_sensitive_variables = False
|
|
16
17
|
|
|
18
|
+
def before_start(self, task_id, args, kwargs):
|
|
19
|
+
if task_id != self.request.id:
|
|
20
|
+
raise RuntimeError(f"Expected task_id {task_id} to equal self.request.id {self.request.id}")
|
|
21
|
+
if args:
|
|
22
|
+
raise RuntimeError(f"Expected args to be empty, but it was {args!r}")
|
|
23
|
+
if kwargs:
|
|
24
|
+
raise RuntimeError(f"Expected kwargs to be empty, but it was {kwargs!r}")
|
|
25
|
+
logger.info("before_start() was called as expected")
|
|
26
|
+
|
|
17
27
|
def run(self):
|
|
18
28
|
"""
|
|
19
29
|
Job function.
|
|
20
30
|
"""
|
|
21
31
|
logger.info("Success")
|
|
32
|
+
return True
|
|
33
|
+
|
|
34
|
+
def on_success(self, retval, task_id, args, kwargs):
|
|
35
|
+
if retval is not True:
|
|
36
|
+
raise RuntimeError(f"Expected retval to be True, but it was {retval!r}")
|
|
37
|
+
if task_id != self.request.id:
|
|
38
|
+
raise RuntimeError(f"Expected task_id {task_id} to equal self.request.id {self.request.id}")
|
|
39
|
+
if args:
|
|
40
|
+
raise RuntimeError(f"Expected args to be empty, but it was {args!r}")
|
|
41
|
+
if kwargs:
|
|
42
|
+
raise RuntimeError(f"Expected kwargs to be empty, but it was {kwargs!r}")
|
|
43
|
+
logger.info("on_success() was called as expected")
|
|
44
|
+
|
|
45
|
+
def on_failure(self, exc, task_id, args, kwargs, einfo):
|
|
46
|
+
raise RuntimeError("on_failure() was unexpectedly called!")
|
|
47
|
+
|
|
48
|
+
def after_return(self, status, retval, task_id, args, kwargs, einfo):
|
|
49
|
+
if status is not JobResultStatusChoices.STATUS_SUCCESS:
|
|
50
|
+
raise RuntimeError(f"Expected status to be {JobResultStatusChoices.STATUS_SUCCESS}, but it was {status!r}")
|
|
51
|
+
if retval is not True:
|
|
52
|
+
raise RuntimeError(f"Expected retval to be True, but it was {retval!r}")
|
|
53
|
+
if task_id != self.request.id:
|
|
54
|
+
raise RuntimeError(f"Expected task_id {task_id} to equal self.request.id {self.request.id}")
|
|
55
|
+
if args:
|
|
56
|
+
raise RuntimeError(f"Expected args to be empty, but it was {args!r}")
|
|
57
|
+
if kwargs:
|
|
58
|
+
raise RuntimeError(f"Expected kwargs to be empty, but it was {kwargs!r}")
|
|
59
|
+
if einfo is not None:
|
|
60
|
+
raise RuntimeError(f"Expected einfo to be None, but it was {einfo!r}")
|
|
61
|
+
logger.info("after_return() was called as expected")
|
|
22
62
|
|
|
23
63
|
|
|
24
64
|
register_jobs(TestPass)
|
|
@@ -2303,6 +2303,7 @@ class JobApprovalTest(APITestCase):
|
|
|
2303
2303
|
name="test dryrun",
|
|
2304
2304
|
task="dry_run.TestDryRun",
|
|
2305
2305
|
job_model=cls.dryrun_job_model,
|
|
2306
|
+
kwargs={"value": 1},
|
|
2306
2307
|
interval=JobExecutionType.TYPE_IMMEDIATELY,
|
|
2307
2308
|
user=cls.additional_user,
|
|
2308
2309
|
approval_required=True,
|
|
@@ -2442,6 +2443,8 @@ class JobApprovalTest(APITestCase):
|
|
|
2442
2443
|
url = reverse("extras-api:scheduledjob-dry-run", kwargs={"pk": self.dryrun_scheduled_job.pk})
|
|
2443
2444
|
response = self.client.post(url, **self.header)
|
|
2444
2445
|
self.assertHttpStatus(response, status.HTTP_200_OK)
|
|
2446
|
+
# The below fails because JobResult.task_kwargs doesn't get set until *after* the task begins executing.
|
|
2447
|
+
# self.assertEqual(response.data["task_kwargs"], {"dryrun": True, "value": 1}, response.data)
|
|
2445
2448
|
|
|
2446
2449
|
@override_settings(EXEMPT_VIEW_PERMISSIONS=["*"])
|
|
2447
2450
|
def test_dry_run_not_supported(self):
|
|
@@ -12,6 +12,7 @@ from nautobot.extras.context_managers import (
|
|
|
12
12
|
web_request_context,
|
|
13
13
|
)
|
|
14
14
|
from nautobot.extras.models import Status, Webhook
|
|
15
|
+
from nautobot.extras.utils import bulk_delete_with_bulk_change_logging
|
|
15
16
|
|
|
16
17
|
# Use the proper swappable User model
|
|
17
18
|
User = get_user_model()
|
|
@@ -231,6 +232,23 @@ class BulkEditDeleteChangeLogging(TestCase):
|
|
|
231
232
|
location.save()
|
|
232
233
|
location.delete()
|
|
233
234
|
|
|
235
|
+
def test_bulk_delete_has_user_in_change_log(self):
|
|
236
|
+
"""Test that the bulk delete operation adds the user to the change log"""
|
|
237
|
+
location_type = LocationType.objects.get(name="Campus")
|
|
238
|
+
location_status = Status.objects.get_for_model(Location).first()
|
|
239
|
+
with web_request_context(self.user):
|
|
240
|
+
location = Location(name="Test Location 1", location_type=location_type, status=location_status)
|
|
241
|
+
location.save()
|
|
242
|
+
location_pk = location.pk
|
|
243
|
+
location_qs = Location.objects.filter(pk=location_pk)
|
|
244
|
+
bulk_delete_with_bulk_change_logging(location_qs)
|
|
245
|
+
|
|
246
|
+
oc_list = get_changes_for_model(location)
|
|
247
|
+
self.assertEqual(len(oc_list), 2)
|
|
248
|
+
self.assertEqual(oc_list[0].action, ObjectChangeActionChoices.ACTION_DELETE)
|
|
249
|
+
self.assertEqual(oc_list[0].user, self.user)
|
|
250
|
+
self.assertEqual(oc_list[0].user_name, self.user.username)
|
|
251
|
+
|
|
234
252
|
def test_create_then_update(self):
|
|
235
253
|
"""Test that a create followed by an update is logged as a single create"""
|
|
236
254
|
location_type = LocationType.objects.get(name="Campus")
|