nautobot 3.0.3__py3-none-any.whl → 3.0.5__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.
- nautobot/core/authentication.py +0 -1
- nautobot/core/celery/schedulers.py +1 -3
- nautobot/core/cli/__init__.py +81 -39
- nautobot/core/settings.yaml +12 -4
- nautobot/core/tables.py +28 -17
- nautobot/core/templates/graphene/graphiql.html +3 -5
- nautobot/core/templates/inc/javascript.html +5 -10
- nautobot/core/templates/inc/media.html +5 -4
- nautobot/core/templates/inc/media_failure.html +73 -0
- nautobot/core/templates/media_failure.html +1 -0
- nautobot/core/tests/test_cli.py +120 -1
- nautobot/core/tests/test_templatetags_helpers.py +9 -9
- nautobot/core/ui/object_detail.py +1 -0
- nautobot/dcim/forms.py +1 -0
- nautobot/dcim/tables/devices.py +6 -5
- nautobot/dcim/tables/template_code.py +8 -4
- nautobot/dcim/templates/dcim/platform_create.html +3 -4
- nautobot/dcim/tests/test_tables.py +5 -6
- nautobot/dcim/views.py +6 -7
- nautobot/extras/models/jobs.py +7 -1
- nautobot/extras/signals.py +143 -113
- nautobot/extras/tables.py +3 -3
- nautobot/extras/templates/extras/inc/jobresult_js.html +1 -2
- nautobot/extras/templates/extras/scheduledjob.html +3 -1
- nautobot/extras/tests/test_customfields.py +75 -9
- nautobot/extras/tests/test_utils.py +116 -1
- nautobot/extras/utils.py +18 -16
- nautobot/extras/views.py +2 -14
- nautobot/ipam/apps.py +1 -0
- nautobot/ipam/filters.py +58 -3
- nautobot/ipam/tables.py +8 -4
- nautobot/ipam/tests/test_filters.py +55 -0
- nautobot/project-static/dist/css/nautobot.css +1 -1
- nautobot/project-static/dist/css/nautobot.css.map +1 -1
- nautobot/project-static/docs/404.html +64 -8
- nautobot/project-static/docs/apps/index.html +64 -8
- nautobot/project-static/docs/apps/nautobot-apps.html +64 -8
- nautobot/project-static/docs/code-reference/nautobot/apps/__init__.html +64 -8
- nautobot/project-static/docs/code-reference/nautobot/apps/admin.html +64 -8
- nautobot/project-static/docs/code-reference/nautobot/apps/api.html +64 -8
- nautobot/project-static/docs/code-reference/nautobot/apps/change_logging.html +64 -8
- nautobot/project-static/docs/code-reference/nautobot/apps/choices.html +64 -8
- nautobot/project-static/docs/code-reference/nautobot/apps/config.html +64 -8
- nautobot/project-static/docs/code-reference/nautobot/apps/constants.html +64 -8
- nautobot/project-static/docs/code-reference/nautobot/apps/datasources.html +64 -8
- nautobot/project-static/docs/code-reference/nautobot/apps/events.html +64 -8
- nautobot/project-static/docs/code-reference/nautobot/apps/exceptions.html +64 -8
- nautobot/project-static/docs/code-reference/nautobot/apps/factory.html +64 -8
- nautobot/project-static/docs/code-reference/nautobot/apps/filters.html +64 -8
- nautobot/project-static/docs/code-reference/nautobot/apps/forms.html +64 -8
- nautobot/project-static/docs/code-reference/nautobot/apps/graphql.html +64 -8
- nautobot/project-static/docs/code-reference/nautobot/apps/jobs.html +64 -8
- nautobot/project-static/docs/code-reference/nautobot/apps/models.html +64 -8
- nautobot/project-static/docs/code-reference/nautobot/apps/querysets.html +64 -8
- nautobot/project-static/docs/code-reference/nautobot/apps/secrets.html +64 -8
- nautobot/project-static/docs/code-reference/nautobot/apps/tables.html +64 -8
- nautobot/project-static/docs/code-reference/nautobot/apps/templatetags.html +64 -8
- nautobot/project-static/docs/code-reference/nautobot/apps/testing.html +64 -8
- nautobot/project-static/docs/code-reference/nautobot/apps/ui.html +64 -8
- nautobot/project-static/docs/code-reference/nautobot/apps/urls.html +64 -8
- nautobot/project-static/docs/code-reference/nautobot/apps/utils.html +64 -8
- nautobot/project-static/docs/code-reference/nautobot/apps/views.html +64 -8
- nautobot/project-static/docs/development/apps/api/configuration-view.html +64 -8
- nautobot/project-static/docs/development/apps/api/database-backend-config.html +64 -8
- nautobot/project-static/docs/development/apps/api/models/django-admin.html +67 -11
- nautobot/project-static/docs/development/apps/api/models/global-search.html +64 -8
- nautobot/project-static/docs/development/apps/api/models/graphql.html +64 -8
- nautobot/project-static/docs/development/apps/api/models/index.html +64 -8
- nautobot/project-static/docs/development/apps/api/models/queryset.html +13440 -0
- nautobot/project-static/docs/development/apps/api/nautobot-app-config.html +64 -8
- nautobot/project-static/docs/development/apps/api/platform-features/custom-validators.html +64 -8
- nautobot/project-static/docs/development/apps/api/platform-features/filter-extensions.html +64 -8
- nautobot/project-static/docs/development/apps/api/platform-features/git-repository-content.html +64 -8
- nautobot/project-static/docs/development/apps/api/platform-features/index.html +64 -8
- nautobot/project-static/docs/development/apps/api/platform-features/jinja2-filters.html +64 -8
- nautobot/project-static/docs/development/apps/api/platform-features/jobs.html +64 -8
- nautobot/project-static/docs/development/apps/api/platform-features/prepopulating-data.html +64 -8
- nautobot/project-static/docs/development/apps/api/platform-features/secrets-providers.html +64 -8
- nautobot/project-static/docs/development/apps/api/platform-features/table-extensions.html +64 -8
- nautobot/project-static/docs/development/apps/api/platform-features/uniquely-identify-objects.html +64 -8
- nautobot/project-static/docs/development/apps/api/prometheus.html +64 -8
- nautobot/project-static/docs/development/apps/api/setup.html +64 -8
- nautobot/project-static/docs/development/apps/api/testing.html +64 -8
- nautobot/project-static/docs/development/apps/api/ui-extensions/banners.html +64 -8
- nautobot/project-static/docs/development/apps/api/ui-extensions/home-page.html +64 -8
- nautobot/project-static/docs/development/apps/api/ui-extensions/index.html +64 -8
- nautobot/project-static/docs/development/apps/api/ui-extensions/navigation.html +64 -8
- nautobot/project-static/docs/development/apps/api/ui-extensions/object-views.html +64 -8
- nautobot/project-static/docs/development/apps/api/views/base-template.html +64 -8
- nautobot/project-static/docs/development/apps/api/views/core-view-overrides.html +64 -8
- nautobot/project-static/docs/development/apps/api/views/django-generic-views.html +64 -8
- nautobot/project-static/docs/development/apps/api/views/help-documentation.html +64 -8
- nautobot/project-static/docs/development/apps/api/views/index.html +67 -11
- nautobot/project-static/docs/development/apps/api/views/nautobot-generic-views.html +64 -8
- nautobot/project-static/docs/development/apps/api/views/nautobotuiviewset.html +64 -8
- nautobot/project-static/docs/development/apps/api/views/nautobotuiviewsetrouter.html +64 -8
- nautobot/project-static/docs/development/apps/api/views/notes.html +64 -8
- nautobot/project-static/docs/development/apps/api/views/rest-api.html +64 -8
- nautobot/project-static/docs/development/apps/api/views/urls.html +64 -8
- nautobot/project-static/docs/development/apps/index.html +64 -8
- nautobot/project-static/docs/development/apps/migration/code-updates.html +64 -8
- nautobot/project-static/docs/development/apps/migration/dependency-updates.html +64 -8
- nautobot/project-static/docs/development/apps/migration/from-v1.html +64 -8
- nautobot/project-static/docs/development/apps/migration/from-v2/migrating-v2-to-v3.html +64 -8
- nautobot/project-static/docs/development/apps/migration/from-v2/new-nautobot-custom-ui-apis.html +64 -8
- nautobot/project-static/docs/development/apps/migration/from-v2/overview.html +68 -8
- nautobot/project-static/docs/development/apps/migration/from-v2/upgrading-from-bootstrap-v3-to-v5.html +64 -8
- nautobot/project-static/docs/development/apps/migration/model-updates/dcim.html +64 -8
- nautobot/project-static/docs/development/apps/migration/model-updates/extras.html +64 -8
- nautobot/project-static/docs/development/apps/migration/model-updates/global.html +64 -8
- nautobot/project-static/docs/development/apps/migration/model-updates/ipam.html +64 -8
- nautobot/project-static/docs/development/apps/migration/ui-component-framework/best-practices.html +64 -8
- nautobot/project-static/docs/development/apps/migration/ui-component-framework/breadcrumbs-titles.html +64 -8
- nautobot/project-static/docs/development/apps/migration/ui-component-framework/custom-content.html +64 -8
- nautobot/project-static/docs/development/apps/migration/ui-component-framework/index.html +64 -8
- nautobot/project-static/docs/development/apps/migration/ui-component-framework/migration-steps.html +64 -8
- nautobot/project-static/docs/development/apps/porting-from-netbox.html +64 -8
- nautobot/project-static/docs/development/core/application-registry.html +64 -8
- nautobot/project-static/docs/development/core/best-practices.html +64 -8
- nautobot/project-static/docs/development/core/caching.html +64 -8
- nautobot/project-static/docs/development/core/controllers.html +64 -8
- nautobot/project-static/docs/development/core/docker-compose-advanced-use-cases.html +64 -8
- nautobot/project-static/docs/development/core/docs-media-standards.html +64 -8
- nautobot/project-static/docs/development/core/generic-views.html +64 -8
- nautobot/project-static/docs/development/core/getting-started.html +64 -8
- nautobot/project-static/docs/development/core/homepage.html +64 -8
- nautobot/project-static/docs/development/core/index.html +64 -8
- nautobot/project-static/docs/development/core/minikube-dev-environment-for-k8s-jobs.html +64 -8
- nautobot/project-static/docs/development/core/model-checklist.html +64 -8
- nautobot/project-static/docs/development/core/model-features.html +64 -8
- nautobot/project-static/docs/development/core/natural-keys.html +64 -8
- nautobot/project-static/docs/development/core/navigation-menu.html +64 -8
- nautobot/project-static/docs/development/core/release-checklist.html +66 -8
- nautobot/project-static/docs/development/core/role-internals.html +64 -8
- nautobot/project-static/docs/development/core/settings.html +64 -8
- nautobot/project-static/docs/development/core/style-guide.html +64 -8
- nautobot/project-static/docs/development/core/templates.html +64 -8
- nautobot/project-static/docs/development/core/testing.html +64 -8
- nautobot/project-static/docs/development/core/ui-best-practices.html +64 -8
- nautobot/project-static/docs/development/core/ui-component-framework.html +64 -8
- nautobot/project-static/docs/development/core/user-preferences.html +64 -8
- nautobot/project-static/docs/development/index.html +64 -8
- nautobot/project-static/docs/development/jobs/getting-started.html +64 -8
- nautobot/project-static/docs/development/jobs/index.html +64 -8
- nautobot/project-static/docs/development/jobs/installation.html +64 -8
- nautobot/project-static/docs/development/jobs/job-extensions.html +64 -8
- nautobot/project-static/docs/development/jobs/job-logging.html +64 -8
- nautobot/project-static/docs/development/jobs/job-patterns.html +64 -8
- nautobot/project-static/docs/development/jobs/job-structure.html +64 -8
- nautobot/project-static/docs/development/jobs/migration/from-v1.html +64 -8
- nautobot/project-static/docs/development/jobs/testing.html +64 -8
- nautobot/project-static/docs/index.html +64 -8
- nautobot/project-static/docs/overview/application_stack.html +64 -8
- nautobot/project-static/docs/overview/design_philosophy.html +64 -8
- nautobot/project-static/docs/release-notes/index.html +64 -8
- nautobot/project-static/docs/release-notes/version-1.0.html +64 -8
- nautobot/project-static/docs/release-notes/version-1.1.html +64 -8
- nautobot/project-static/docs/release-notes/version-1.2.html +65 -9
- nautobot/project-static/docs/release-notes/version-1.3.html +64 -8
- nautobot/project-static/docs/release-notes/version-1.4.html +64 -8
- nautobot/project-static/docs/release-notes/version-1.5.html +64 -8
- nautobot/project-static/docs/release-notes/version-1.6.html +64 -8
- nautobot/project-static/docs/release-notes/version-2.0.html +64 -8
- nautobot/project-static/docs/release-notes/version-2.1.html +64 -8
- nautobot/project-static/docs/release-notes/version-2.2.html +64 -8
- nautobot/project-static/docs/release-notes/version-2.3.html +64 -8
- nautobot/project-static/docs/release-notes/version-2.4.html +584 -8
- nautobot/project-static/docs/release-notes/version-3.0.html +467 -8
- nautobot/project-static/docs/search/search_index.json +1 -1
- nautobot/project-static/docs/sitemap.xml +337 -329
- nautobot/project-static/docs/sitemap.xml.gz +0 -0
- nautobot/project-static/docs/user-guide/administration/configuration/authentication/ldap.html +64 -8
- nautobot/project-static/docs/user-guide/administration/configuration/authentication/remote.html +64 -8
- nautobot/project-static/docs/user-guide/administration/configuration/authentication/sso.html +64 -8
- nautobot/project-static/docs/user-guide/administration/configuration/index.html +64 -8
- nautobot/project-static/docs/user-guide/administration/configuration/redis.html +64 -8
- nautobot/project-static/docs/user-guide/administration/configuration/settings.html +75 -12
- nautobot/project-static/docs/user-guide/administration/configuration/time-zones.html +64 -8
- nautobot/project-static/docs/user-guide/administration/guides/celery-queues.html +64 -8
- nautobot/project-static/docs/user-guide/administration/guides/docker.html +64 -8
- nautobot/project-static/docs/user-guide/administration/guides/health-checks.html +64 -8
- nautobot/project-static/docs/user-guide/administration/guides/permissions.html +64 -8
- nautobot/project-static/docs/user-guide/administration/guides/prometheus-metrics.html +64 -8
- nautobot/project-static/docs/user-guide/administration/guides/replicating-nautobot.html +64 -8
- nautobot/project-static/docs/user-guide/administration/guides/request-profiling.html +64 -8
- nautobot/project-static/docs/user-guide/administration/guides/s3-django-storage.html +64 -8
- nautobot/project-static/docs/user-guide/administration/guides/selinux-troubleshooting.html +64 -8
- nautobot/project-static/docs/user-guide/administration/installation/app-install.html +64 -8
- nautobot/project-static/docs/user-guide/administration/installation/external-authentication.html +64 -8
- nautobot/project-static/docs/user-guide/administration/installation/http-server.html +72 -9
- nautobot/project-static/docs/user-guide/administration/installation/index.html +64 -8
- nautobot/project-static/docs/user-guide/administration/installation/install_system.html +64 -8
- nautobot/project-static/docs/user-guide/administration/installation/nautobot.html +64 -8
- nautobot/project-static/docs/user-guide/administration/installation/services.html +64 -8
- nautobot/project-static/docs/user-guide/administration/migration/migrating-from-netbox.html +65 -9
- nautobot/project-static/docs/user-guide/administration/migration/migrating-from-postgresql.html +64 -8
- nautobot/project-static/docs/user-guide/administration/security/index.html +64 -8
- nautobot/project-static/docs/user-guide/administration/security/notices.html +64 -8
- nautobot/project-static/docs/user-guide/administration/tools/nautobot-server.html +64 -8
- nautobot/project-static/docs/user-guide/administration/tools/nautobot-shell.html +64 -8
- nautobot/project-static/docs/user-guide/administration/upgrading/database-backup.html +67 -11
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/after-you-upgrade.html +64 -8
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/before-you-upgrade.html +64 -8
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/for-developers.html +64 -8
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/index.html +64 -8
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/whats-changed.html +64 -8
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/region-and-site-data-migration-guide.html +64 -8
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/upgrading-from-nautobot-v1.html +64 -8
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v2/index.html +68 -8
- nautobot/project-static/docs/user-guide/administration/upgrading/postgresql.html +13391 -0
- nautobot/project-static/docs/user-guide/administration/upgrading/upgrading.html +125 -15
- nautobot/project-static/docs/user-guide/core-data-model/circuits/circuit.html +64 -8
- nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittermination.html +64 -8
- nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittype.html +64 -8
- nautobot/project-static/docs/user-guide/core-data-model/circuits/provider.html +64 -8
- nautobot/project-static/docs/user-guide/core-data-model/circuits/providernetwork.html +64 -8
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloud.html +64 -8
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudaccount.html +64 -8
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudnetwork.html +64 -8
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudnetworkprefixassignment.html +64 -8
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudresourcetype.html +64 -8
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudservice.html +64 -8
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudservicenetworkassignment.html +64 -8
- nautobot/project-static/docs/user-guide/core-data-model/dcim/cable.html +64 -8
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleport.html +64 -8
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleporttemplate.html +64 -8
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverport.html +64 -8
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverporttemplate.html +64 -8
- nautobot/project-static/docs/user-guide/core-data-model/dcim/controller.html +64 -8
- nautobot/project-static/docs/user-guide/core-data-model/dcim/controllermanageddevicegroup.html +64 -8
- nautobot/project-static/docs/user-guide/core-data-model/dcim/device.html +64 -8
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebay.html +64 -8
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebaytemplate.html +64 -8
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicefamily.html +64 -8
- nautobot/project-static/docs/user-guide/core-data-model/dcim/deviceredundancygroup.html +64 -8
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicetype.html +64 -8
- nautobot/project-static/docs/user-guide/core-data-model/dcim/frontport.html +64 -8
- nautobot/project-static/docs/user-guide/core-data-model/dcim/frontporttemplate.html +64 -8
- nautobot/project-static/docs/user-guide/core-data-model/dcim/interface.html +64 -8
- nautobot/project-static/docs/user-guide/core-data-model/dcim/interfaceredundancygroup.html +64 -8
- nautobot/project-static/docs/user-guide/core-data-model/dcim/interfacetemplate.html +64 -8
- nautobot/project-static/docs/user-guide/core-data-model/dcim/inventoryitem.html +64 -8
- nautobot/project-static/docs/user-guide/core-data-model/dcim/location.html +64 -8
- nautobot/project-static/docs/user-guide/core-data-model/dcim/locationtype.html +64 -8
- nautobot/project-static/docs/user-guide/core-data-model/dcim/manufacturer.html +64 -8
- nautobot/project-static/docs/user-guide/core-data-model/dcim/module.html +64 -8
- nautobot/project-static/docs/user-guide/core-data-model/dcim/modulebay.html +64 -8
- nautobot/project-static/docs/user-guide/core-data-model/dcim/modulebaytemplate.html +64 -8
- nautobot/project-static/docs/user-guide/core-data-model/dcim/modulefamily.html +64 -8
- nautobot/project-static/docs/user-guide/core-data-model/dcim/moduletype.html +64 -8
- nautobot/project-static/docs/user-guide/core-data-model/dcim/platform.html +64 -8
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerfeed.html +64 -8
- nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlet.html +64 -8
- nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlettemplate.html +64 -8
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerpanel.html +64 -8
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerport.html +64 -8
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerporttemplate.html +64 -8
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rack.html +64 -8
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rackgroup.html +64 -8
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rackreservation.html +64 -8
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rearport.html +64 -8
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rearporttemplate.html +64 -8
- nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareimagefile.html +64 -8
- nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareversion.html +64 -8
- nautobot/project-static/docs/user-guide/core-data-model/dcim/virtualchassis.html +64 -8
- nautobot/project-static/docs/user-guide/core-data-model/dcim/virtualdevicecontext.html +64 -8
- nautobot/project-static/docs/user-guide/core-data-model/extras/configcontext.html +64 -8
- nautobot/project-static/docs/user-guide/core-data-model/extras/configcontextschema.html +64 -8
- nautobot/project-static/docs/user-guide/core-data-model/extras/contact.html +64 -8
- nautobot/project-static/docs/user-guide/core-data-model/extras/team.html +64 -8
- nautobot/project-static/docs/user-guide/core-data-model/ipam/ipaddress.html +64 -8
- nautobot/project-static/docs/user-guide/core-data-model/ipam/namespace.html +64 -8
- nautobot/project-static/docs/user-guide/core-data-model/ipam/prefix.html +64 -8
- nautobot/project-static/docs/user-guide/core-data-model/ipam/rir.html +64 -8
- nautobot/project-static/docs/user-guide/core-data-model/ipam/routetarget.html +64 -8
- nautobot/project-static/docs/user-guide/core-data-model/ipam/service.html +64 -8
- nautobot/project-static/docs/user-guide/core-data-model/ipam/vlan.html +64 -8
- nautobot/project-static/docs/user-guide/core-data-model/ipam/vlangroup.html +64 -8
- nautobot/project-static/docs/user-guide/core-data-model/ipam/vrf.html +64 -8
- nautobot/project-static/docs/user-guide/core-data-model/load-balancers/certificateprofile.html +64 -8
- nautobot/project-static/docs/user-guide/core-data-model/load-balancers/healthcheckmonitor.html +64 -8
- nautobot/project-static/docs/user-guide/core-data-model/load-balancers/index.html +64 -8
- nautobot/project-static/docs/user-guide/core-data-model/load-balancers/loadbalancerpool.html +64 -8
- nautobot/project-static/docs/user-guide/core-data-model/load-balancers/loadbalancerpoolmember.html +64 -8
- nautobot/project-static/docs/user-guide/core-data-model/load-balancers/virtualserver.html +64 -8
- nautobot/project-static/docs/user-guide/core-data-model/overview/introduction.html +64 -8
- nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenant.html +64 -8
- nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenantgroup.html +64 -8
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/cluster.html +64 -8
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustergroup.html +64 -8
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustertype.html +64 -8
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/virtualmachine.html +64 -8
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/vminterface.html +64 -8
- nautobot/project-static/docs/user-guide/core-data-model/vpn/index.html +64 -8
- nautobot/project-static/docs/user-guide/core-data-model/vpn/vpn.html +64 -8
- nautobot/project-static/docs/user-guide/core-data-model/vpn/vpnphase1policy.html +64 -8
- nautobot/project-static/docs/user-guide/core-data-model/vpn/vpnphase2policy.html +64 -8
- nautobot/project-static/docs/user-guide/core-data-model/vpn/vpnprofile.html +64 -8
- nautobot/project-static/docs/user-guide/core-data-model/vpn/vpntunnel.html +64 -8
- nautobot/project-static/docs/user-guide/core-data-model/vpn/vpntunnelendpoint.html +64 -8
- nautobot/project-static/docs/user-guide/core-data-model/wireless/index.html +64 -8
- nautobot/project-static/docs/user-guide/core-data-model/wireless/radioprofile.html +64 -8
- nautobot/project-static/docs/user-guide/core-data-model/wireless/supporteddatarate.html +64 -8
- nautobot/project-static/docs/user-guide/core-data-model/wireless/wirelessnetwork.html +64 -8
- nautobot/project-static/docs/user-guide/feature-guides/contacts-and-teams.html +64 -8
- nautobot/project-static/docs/user-guide/feature-guides/custom-fields.html +64 -8
- nautobot/project-static/docs/user-guide/feature-guides/data-compliance.html +64 -8
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-devices.html +64 -8
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-location-types-and-locations.html +64 -8
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/index.html +64 -8
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/interfaces.html +64 -8
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/ipam.html +64 -8
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/platforms.html +64 -8
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/search-bar.html +64 -8
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/tenants.html +75 -12
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/vlans-and-vlan-groups.html +85 -17
- nautobot/project-static/docs/user-guide/feature-guides/git-data-source.html +64 -8
- nautobot/project-static/docs/user-guide/feature-guides/graphql.html +64 -8
- nautobot/project-static/docs/user-guide/feature-guides/images/getting-started-nautobot-ui/12-add-tenant-dark.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/getting-started-nautobot-ui/12-add-tenant-light.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/getting-started-nautobot-ui/13-assign-tenant-to-device-dark.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/getting-started-nautobot-ui/13-assign-tenant-to-device-light.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/getting-started-nautobot-ui/14-assign-tenant-to-device-2-dark.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/getting-started-nautobot-ui/14-assign-tenant-to-device-2-light.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/getting-started-nautobot-ui/22-create-vlans-dark.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/getting-started-nautobot-ui/22-create-vlans-light.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/getting-started-nautobot-ui/23-create-vlans-2-dark.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/getting-started-nautobot-ui/23-create-vlans-2-light.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/getting-started-nautobot-ui/24-vlan-main-page-dark.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/getting-started-nautobot-ui/24-vlan-main-page-light.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/getting-started-nautobot-ui/25-add-vlan-to-interface-dark.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/getting-started-nautobot-ui/25-add-vlan-to-interface-light.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/getting-started-nautobot-ui/26-add-vlan-to-interface-2-dark.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/getting-started-nautobot-ui/26-add-vlan-to-interface-2-light.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/ip-address-merge-tool.html +64 -8
- nautobot/project-static/docs/user-guide/feature-guides/load-balancers.html +64 -8
- nautobot/project-static/docs/user-guide/feature-guides/relationships.html +64 -8
- nautobot/project-static/docs/user-guide/feature-guides/software-image-files-and-versions.html +64 -8
- nautobot/project-static/docs/user-guide/feature-guides/wireless-networks-and-controllers.html +64 -8
- nautobot/project-static/docs/user-guide/index.html +64 -8
- nautobot/project-static/docs/user-guide/platform-functionality/approval-workflow.html +64 -8
- nautobot/project-static/docs/user-guide/platform-functionality/change-logging.html +64 -8
- nautobot/project-static/docs/user-guide/platform-functionality/computedfield.html +64 -8
- nautobot/project-static/docs/user-guide/platform-functionality/customfield.html +64 -8
- nautobot/project-static/docs/user-guide/platform-functionality/customlink.html +64 -8
- nautobot/project-static/docs/user-guide/platform-functionality/data-validation.html +64 -8
- nautobot/project-static/docs/user-guide/platform-functionality/dynamicgroup.html +64 -8
- nautobot/project-static/docs/user-guide/platform-functionality/echarts.html +64 -8
- nautobot/project-static/docs/user-guide/platform-functionality/events.html +64 -8
- nautobot/project-static/docs/user-guide/platform-functionality/exporttemplate.html +64 -8
- nautobot/project-static/docs/user-guide/platform-functionality/externalintegration.html +64 -8
- nautobot/project-static/docs/user-guide/platform-functionality/gitrepository.html +64 -8
- nautobot/project-static/docs/user-guide/platform-functionality/graphql.html +64 -8
- nautobot/project-static/docs/user-guide/platform-functionality/graphqlquery.html +64 -8
- nautobot/project-static/docs/user-guide/platform-functionality/imageattachment.html +64 -8
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/index.html +64 -8
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/job-scheduling-and-approvals.html +64 -8
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobbutton.html +64 -8
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobhook.html +64 -8
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobqueue.html +64 -8
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/kubernetes-job-support.html +64 -8
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/managing-jobs.html +64 -8
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/models.html +64 -8
- nautobot/project-static/docs/user-guide/platform-functionality/napalm.html +64 -8
- nautobot/project-static/docs/user-guide/platform-functionality/note.html +64 -8
- nautobot/project-static/docs/user-guide/platform-functionality/objectmetadata.html +64 -8
- nautobot/project-static/docs/user-guide/platform-functionality/relationship.html +64 -8
- nautobot/project-static/docs/user-guide/platform-functionality/rendering-jinja-templates.html +64 -8
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/authentication.html +64 -8
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/filtering.html +116 -34
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/overview.html +64 -8
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/ui-related-endpoints.html +64 -8
- nautobot/project-static/docs/user-guide/platform-functionality/role.html +64 -8
- nautobot/project-static/docs/user-guide/platform-functionality/secret.html +64 -8
- nautobot/project-static/docs/user-guide/platform-functionality/staticgroupassociation.html +64 -8
- nautobot/project-static/docs/user-guide/platform-functionality/status.html +64 -8
- nautobot/project-static/docs/user-guide/platform-functionality/tag.html +64 -8
- nautobot/project-static/docs/user-guide/platform-functionality/template-filters.html +64 -8
- nautobot/project-static/docs/user-guide/platform-functionality/user-interface/configurablecolumns.html +64 -8
- nautobot/project-static/docs/user-guide/platform-functionality/user-interface/savedview.html +64 -8
- nautobot/project-static/docs/user-guide/platform-functionality/user-interface/search.html +64 -8
- nautobot/project-static/docs/user-guide/platform-functionality/users/groups.html +64 -8
- nautobot/project-static/docs/user-guide/platform-functionality/users/objectpermission.html +64 -8
- nautobot/project-static/docs/user-guide/platform-functionality/users/token.html +64 -8
- nautobot/project-static/docs/user-guide/platform-functionality/webhook.html +64 -8
- nautobot/tenancy/tables.py +1 -1
- nautobot/ui/package-lock.json +36 -36
- nautobot/ui/package.json +3 -3
- nautobot/ui/src/scss/nautobot.scss +2 -1
- nautobot/users/models.py +33 -0
- nautobot/users/tests/test_models.py +83 -0
- {nautobot-3.0.3.dist-info → nautobot-3.0.5.dist-info}/METADATA +4 -4
- {nautobot-3.0.3.dist-info → nautobot-3.0.5.dist-info}/RECORD +397 -386
- nautobot/project-static/docs/user-guide/feature-guides/images/getting-started-nautobot-ui/12-add-tenant.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/getting-started-nautobot-ui/13-assign-tenant-to-device.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/getting-started-nautobot-ui/14-assign-tenant-to-device-2.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/getting-started-nautobot-ui/22-create-vlans.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/getting-started-nautobot-ui/23-create-vlans-2.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/getting-started-nautobot-ui/24-vlan-main-page.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/getting-started-nautobot-ui/25-add-vlan-to-interface.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/getting-started-nautobot-ui/26-add-vlan-to-interface-2.png +0 -0
- {nautobot-3.0.3.dist-info → nautobot-3.0.5.dist-info}/LICENSE.txt +0 -0
- {nautobot-3.0.3.dist-info → nautobot-3.0.5.dist-info}/NOTICE +0 -0
- {nautobot-3.0.3.dist-info → nautobot-3.0.5.dist-info}/WHEEL +0 -0
- {nautobot-3.0.3.dist-info → nautobot-3.0.5.dist-info}/entry_points.txt +0 -0
nautobot/core/authentication.py
CHANGED
|
@@ -52,7 +52,6 @@ class ObjectPermissionBackend(ModelBackend):
|
|
|
52
52
|
return user_obj.is_active and (user_obj.is_staff or user_obj.is_superuser)
|
|
53
53
|
|
|
54
54
|
app_label, _action, model_name = resolve_permission(perm)
|
|
55
|
-
|
|
56
55
|
if app_label == "users" and model_name == "admingroup":
|
|
57
56
|
perm = perm.replace("users", "auth").replace("admingroup", "group")
|
|
58
57
|
|
|
@@ -138,9 +138,7 @@ class NautobotDatabaseScheduler(DatabaseScheduler):
|
|
|
138
138
|
task_name=scheduled_job.job_model.class_path,
|
|
139
139
|
celery_kwargs=entry.options,
|
|
140
140
|
)
|
|
141
|
-
job_result = run_kubernetes_job_and_return_job_result(
|
|
142
|
-
job_queue, job_result, json.dumps(entry_kwargs)
|
|
143
|
-
)
|
|
141
|
+
job_result = run_kubernetes_job_and_return_job_result(job_result, json.dumps(entry_kwargs))
|
|
144
142
|
# Return an AsyncResult object to mimic the behavior of Celery tasks after the job is finished by Kubernetes Job Pod.
|
|
145
143
|
resp = AsyncResult(job_result.id)
|
|
146
144
|
else:
|
nautobot/core/cli/__init__.py
CHANGED
|
@@ -3,7 +3,9 @@ Utilities and primitives for the `nautobot-server` CLI command.
|
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
5
|
import argparse
|
|
6
|
+
from copy import deepcopy
|
|
6
7
|
import importlib.util
|
|
8
|
+
import logging
|
|
7
9
|
import os
|
|
8
10
|
import sys
|
|
9
11
|
|
|
@@ -34,43 +36,46 @@ USAGE = """%(prog)s --help
|
|
|
34
36
|
%(prog)s [-c CONFIG_PATH] SUBCOMMAND ..."""
|
|
35
37
|
|
|
36
38
|
|
|
37
|
-
|
|
39
|
+
logger = logging.getLogger(__name__)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def _preprocess_settings(settings_module, config_path):
|
|
38
43
|
"""
|
|
39
44
|
After loading nautobot_config.py and nautobot.core.settings, but before starting Django, modify the settings module.
|
|
40
45
|
|
|
41
|
-
- Set
|
|
46
|
+
- Set settings_module.SETTINGS_PATH for ease of reference
|
|
42
47
|
- Handle `EXTRA_*` settings
|
|
43
48
|
- Create Nautobot storage directories if they don't already exist
|
|
44
49
|
- Change database backends to django-prometheus if appropriate
|
|
45
50
|
- Set up 'job_logs' database mirror
|
|
46
51
|
- Handle our custom `STORAGE_BACKEND` setting.
|
|
47
|
-
- Load plugins based on
|
|
48
|
-
- Load event brokers based on
|
|
52
|
+
- Load plugins based on settings_module.PLUGINS (may affect INSTALLED_APPS, MIDDLEWARE, and CONSTANCE_CONFIG)
|
|
53
|
+
- Load event brokers based on settings_module.EVENT_BROKERS
|
|
49
54
|
"""
|
|
50
|
-
|
|
55
|
+
settings_module.SETTINGS_PATH = config_path
|
|
51
56
|
|
|
52
57
|
# Any setting that starts with EXTRA_ and matches a setting that is a list or tuple
|
|
53
58
|
# will automatically append the values to the current setting.
|
|
54
59
|
# "It might make sense to make this less magical"
|
|
55
60
|
extras = {}
|
|
56
|
-
for setting in dir(
|
|
61
|
+
for setting in dir(settings_module):
|
|
57
62
|
if setting == setting.upper() and setting.startswith("EXTRA_"):
|
|
58
63
|
base_setting = setting[6:]
|
|
59
|
-
if isinstance(getattr(
|
|
60
|
-
extras[base_setting] = getattr(
|
|
64
|
+
if isinstance(getattr(settings_module, base_setting), (list, tuple)):
|
|
65
|
+
extras[base_setting] = getattr(settings_module, setting)
|
|
61
66
|
for base_setting, extra_values in extras.items():
|
|
62
|
-
base_value = getattr(
|
|
63
|
-
setattr(
|
|
67
|
+
base_value = getattr(settings_module, base_setting)
|
|
68
|
+
setattr(settings_module, base_setting, base_value + type(base_value)(extra_values))
|
|
64
69
|
|
|
65
70
|
#
|
|
66
71
|
# Storage directories
|
|
67
72
|
#
|
|
68
|
-
os.makedirs(
|
|
69
|
-
os.makedirs(
|
|
70
|
-
os.makedirs(
|
|
71
|
-
os.makedirs(os.path.join(
|
|
72
|
-
os.makedirs(os.path.join(
|
|
73
|
-
os.makedirs(
|
|
73
|
+
os.makedirs(settings_module.GIT_ROOT, exist_ok=True)
|
|
74
|
+
os.makedirs(settings_module.JOBS_ROOT, exist_ok=True)
|
|
75
|
+
os.makedirs(settings_module.MEDIA_ROOT, exist_ok=True)
|
|
76
|
+
os.makedirs(os.path.join(settings_module.MEDIA_ROOT, "devicetype-images"), exist_ok=True)
|
|
77
|
+
os.makedirs(os.path.join(settings_module.MEDIA_ROOT, "image-attachments"), exist_ok=True)
|
|
78
|
+
os.makedirs(settings_module.STATIC_ROOT, exist_ok=True)
|
|
74
79
|
|
|
75
80
|
#
|
|
76
81
|
# Databases
|
|
@@ -78,62 +83,99 @@ def _preprocess_settings(settings, config_path):
|
|
|
78
83
|
|
|
79
84
|
# If metrics are enabled and postgres is the backend, set the driver to the
|
|
80
85
|
# one provided by django-prometheus.
|
|
81
|
-
if
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
+
if settings_module.METRICS_ENABLED:
|
|
87
|
+
# Avoid modifying nautobot.core.settings.DATABASES by accident!
|
|
88
|
+
settings_module.DATABASES = deepcopy(settings_module.DATABASES)
|
|
89
|
+
|
|
90
|
+
if "postgres" in settings_module.DATABASES["default"]["ENGINE"]:
|
|
91
|
+
settings_module.DATABASES["default"]["ENGINE"] = "django_prometheus.db.backends.postgresql"
|
|
92
|
+
elif "mysql" in settings_module.DATABASES["default"]["ENGINE"]:
|
|
93
|
+
settings_module.DATABASES["default"]["ENGINE"] = "django_prometheus.db.backends.mysql"
|
|
86
94
|
|
|
87
95
|
# Create secondary db connection for job logging. This still writes to the default db, but because it's a separate
|
|
88
96
|
# connection, it allows allows us to "escape" from transaction.atomic() and ensure that job log entries are saved
|
|
89
97
|
# to the database even when the rest of the job transaction is rolled back.
|
|
90
|
-
|
|
98
|
+
settings_module.DATABASES["job_logs"] = deepcopy(settings_module.DATABASES["default"])
|
|
91
99
|
# When running unit tests, treat it as a mirror of the default test DB, not a separate test DB of its own
|
|
92
|
-
|
|
100
|
+
settings_module.DATABASES["job_logs"]["TEST"] = {"MIRROR": "default"}
|
|
93
101
|
|
|
94
102
|
#
|
|
95
103
|
# Media storage
|
|
96
104
|
#
|
|
97
105
|
|
|
98
|
-
|
|
99
|
-
|
|
106
|
+
# Avoid modifying nautobot.core.settings.STORAGES by accident!
|
|
107
|
+
settings_module.STORAGES = deepcopy(settings_module.STORAGES)
|
|
100
108
|
|
|
101
|
-
if hasattr(
|
|
102
|
-
|
|
109
|
+
if hasattr(settings_module, "JOB_FILE_IO_STORAGE"):
|
|
110
|
+
settings_module.STORAGES.setdefault("nautobotjobfiles", {})["BACKEND"] = settings_module.JOB_FILE_IO_STORAGE
|
|
111
|
+
|
|
112
|
+
if hasattr(settings_module, "STORAGE_BACKEND") and settings_module.STORAGE_BACKEND is not None:
|
|
113
|
+
settings_module.STORAGES["default"]["BACKEND"] = settings_module.STORAGE_BACKEND
|
|
103
114
|
|
|
104
115
|
# django-storages
|
|
105
|
-
if hasattr(
|
|
116
|
+
if hasattr(settings_module, "STORAGE_BACKEND") and settings_module.STORAGE_BACKEND.startswith("storages."):
|
|
106
117
|
try:
|
|
107
118
|
import storages.utils
|
|
108
119
|
except ModuleNotFoundError as e:
|
|
109
120
|
if getattr(e, "name") == "storages":
|
|
110
121
|
raise ImproperlyConfigured(
|
|
111
|
-
f"STORAGE_BACKEND is set to {
|
|
112
|
-
|
|
122
|
+
f"STORAGE_BACKEND is set to {settings_module.STORAGE_BACKEND} but django-storages is not present. "
|
|
123
|
+
"It can be installed by running 'pip install django-storages'."
|
|
113
124
|
)
|
|
114
125
|
raise e
|
|
115
126
|
|
|
116
127
|
# Monkey-patch django-storages to fetch settings from STORAGE_CONFIG or fall back to settings
|
|
117
128
|
def _setting(name, default=None):
|
|
118
|
-
if name in
|
|
119
|
-
return
|
|
120
|
-
return getattr(
|
|
129
|
+
if name in settings_module.STORAGE_CONFIG:
|
|
130
|
+
return settings_module.STORAGE_CONFIG[name]
|
|
131
|
+
return getattr(settings_module, name, default)
|
|
121
132
|
|
|
122
133
|
storages.utils.setting = _setting
|
|
123
134
|
|
|
135
|
+
# Django 4.2 will throw an exception if both:
|
|
136
|
+
# - DEFAULT_FILE_STORAGE/STATICFILES_STORAGE is set in nautobot_config.py (recommended until Nautobot v2.4.24)
|
|
137
|
+
# - STORAGES is configured in nautobot.core.settings (which it is nowadays).
|
|
138
|
+
# Unfortunately, it's not implemented as a standard system check (which we could opt out of) but is instead
|
|
139
|
+
# hard-coded, so we hack around it instead by explicitly copying any non-default *_STORAGE to STORAGES
|
|
140
|
+
# and then unsetting *_STORAGE.
|
|
141
|
+
for setting_name, storages_key, default_value in [
|
|
142
|
+
("DEFAULT_FILE_STORAGE", "default", "django.core.files.storage.FileSystemStorage"),
|
|
143
|
+
("STATICFILES_STORAGE", "staticfiles", "django.contrib.staticfiles.storage.StaticFilesStorage"),
|
|
144
|
+
]:
|
|
145
|
+
if hasattr(settings_module, setting_name):
|
|
146
|
+
# Make sure we don't clobber any existing explicit configuration in STORAGES:
|
|
147
|
+
if settings_module.STORAGES[storages_key]["BACKEND"] not in (
|
|
148
|
+
default_value, # Nautobot/Django default
|
|
149
|
+
getattr(settings_module, setting_name), # same as explicitly set value for setting_name
|
|
150
|
+
):
|
|
151
|
+
raise ImproperlyConfigured(
|
|
152
|
+
f"It looks like you've configured both {setting_name} and STORAGES['{storages_key}']['BACKEND'],"
|
|
153
|
+
"but their values do not match."
|
|
154
|
+
)
|
|
155
|
+
|
|
156
|
+
# No clobbering, but undesired, so warn the user and handle it:
|
|
157
|
+
logger.warning(
|
|
158
|
+
f"It looks like you've configured {setting_name} in {settings_module.SETTINGS_PATH}. "
|
|
159
|
+
"This setting is deprecated since Nautobot v2.4.24, and support will be removed in Nautobot v3.1. "
|
|
160
|
+
f"You should migrate to configuring STORAGES['{storages_key}']['BACKEND'] instead. Refer to "
|
|
161
|
+
"https://docs.nautobot.com/projects/core/en/stable/user-guide/administration/configuration/settings/#storages for guidance."
|
|
162
|
+
)
|
|
163
|
+
settings_module.STORAGES[storages_key]["BACKEND"] = getattr(settings_module, setting_name)
|
|
164
|
+
delattr(settings_module, setting_name)
|
|
165
|
+
|
|
124
166
|
#
|
|
125
167
|
# Plugins
|
|
126
168
|
#
|
|
127
169
|
|
|
128
170
|
# Process the plugins and manipulate the specified config settings that are
|
|
129
171
|
# passed in.
|
|
130
|
-
load_plugins(
|
|
172
|
+
load_plugins(settings_module)
|
|
131
173
|
|
|
132
174
|
#
|
|
133
175
|
# Event Broker
|
|
134
176
|
#
|
|
135
177
|
|
|
136
|
-
load_event_brokers(
|
|
178
|
+
load_event_brokers(settings_module.EVENT_BROKERS)
|
|
137
179
|
|
|
138
180
|
|
|
139
181
|
def load_settings(config_path):
|
|
@@ -144,10 +186,10 @@ def load_settings(config_path):
|
|
|
144
186
|
"Please provide a valid --config-path path, or use 'nautobot-server init' to create a new configuration."
|
|
145
187
|
)
|
|
146
188
|
spec = importlib.util.spec_from_file_location("nautobot_config", config_path)
|
|
147
|
-
|
|
148
|
-
sys.modules["nautobot_config"] =
|
|
149
|
-
spec.loader.exec_module(
|
|
150
|
-
_preprocess_settings(
|
|
189
|
+
settings_module = importlib.util.module_from_spec(spec)
|
|
190
|
+
sys.modules["nautobot_config"] = settings_module
|
|
191
|
+
spec.loader.exec_module(settings_module)
|
|
192
|
+
_preprocess_settings(settings_module, config_path)
|
|
151
193
|
|
|
152
194
|
|
|
153
195
|
class _VerboseHelpFormatter(argparse.ArgumentDefaultsHelpFormatter, argparse.RawDescriptionHelpFormatter):
|
nautobot/core/settings.yaml
CHANGED
|
@@ -1886,8 +1886,8 @@ properties:
|
|
|
1886
1886
|
For an example of using `django-storages` with AWS S3 buckets, visit the
|
|
1887
1887
|
[django-storages with S3](../guides/s3-django-storage.md) user-guide.
|
|
1888
1888
|
|
|
1889
|
-
The configuration parameters for the specified storage backend are defined under the
|
|
1890
|
-
[`STORAGE_CONFIG`](#storage_config)
|
|
1889
|
+
The configuration parameters for the specified storage backend are defined under the settings
|
|
1890
|
+
[`STORAGE_CONFIG`](#storage_config) (deprecated) or [`STORAGES`](#storages) (recommended).
|
|
1891
1891
|
see_also:
|
|
1892
1892
|
"`STORAGES`": "#storages"
|
|
1893
1893
|
type: "string"
|
|
@@ -1895,8 +1895,16 @@ properties:
|
|
|
1895
1895
|
description: "(Deprecated) Dictionary of config parameters for the storage backend configured as STORAGE_BACKEND."
|
|
1896
1896
|
details: |-
|
|
1897
1897
|
!!! warning
|
|
1898
|
-
This setting is deprecated and will be removed in Nautobot v3.1.
|
|
1899
|
-
|
|
1898
|
+
This setting is deprecated and will be removed in Nautobot v3.1. In its place, you should set
|
|
1899
|
+
[`STORAGES["default"]["OPTIONS"]` and/or `STORAGES["staticfiles"]["OPTIONS"]`](#storages).
|
|
1900
|
+
|
|
1901
|
+
Note that `STORAGE_CONFIG` is implemented to provide a bit of configuration "magic" that
|
|
1902
|
+
`STORAGES["..."]["OPTIONS"]` does not; specifically, when `STORAGE_BACKEND` is using any module from
|
|
1903
|
+
`django-storages`, if `STATICFILES_STORAGE` is also using `django-storages`, the `STORAGE_CONFIG` will be
|
|
1904
|
+
automatically applied to both file storage types. When using `STORAGES` instead of `STORAGE_CONFIG`, this is
|
|
1905
|
+
not automatically the case, permitting the two types to be configured independently, but also potentially
|
|
1906
|
+
requiring duplicate configuration under `STORAGES["default"]["OPTIONS"]` and
|
|
1907
|
+
`STORAGES["staticfiles"]["OPTIONS"]` if both types are using the same backend.
|
|
1900
1908
|
|
|
1901
1909
|
The specific parameters to be used here are specific to each backend.
|
|
1902
1910
|
|
nautobot/core/tables.py
CHANGED
|
@@ -9,7 +9,7 @@ from django.db.models import Prefetch, QuerySet
|
|
|
9
9
|
from django.db.models.fields.related import ForeignKey, RelatedField
|
|
10
10
|
from django.db.models.fields.reverse_related import ManyToOneRel
|
|
11
11
|
from django.urls import reverse
|
|
12
|
-
from django.utils.html import
|
|
12
|
+
from django.utils.html import format_html, format_html_join
|
|
13
13
|
from django.utils.http import urlencode
|
|
14
14
|
from django.utils.safestring import mark_safe
|
|
15
15
|
from django.utils.text import Truncator
|
|
@@ -36,6 +36,7 @@ class BaseTable(django_tables2.Table):
|
|
|
36
36
|
attrs = {
|
|
37
37
|
"class": "table table-hover nb-table-headings",
|
|
38
38
|
}
|
|
39
|
+
default = helpers.HTML_NONE
|
|
39
40
|
|
|
40
41
|
def __init__(
|
|
41
42
|
self,
|
|
@@ -579,7 +580,13 @@ class ColoredLabelColumn(django_tables2.TemplateColumn):
|
|
|
579
580
|
|
|
580
581
|
template_code = """
|
|
581
582
|
{% load helpers %}
|
|
582
|
-
{% if value %}
|
|
583
|
+
{% if value %}
|
|
584
|
+
<span class="badge" style="color: {{ value.color|fgcolor }}; background-color: #{{ value.color }}">
|
|
585
|
+
{{ value }}
|
|
586
|
+
</span>
|
|
587
|
+
{% else %}
|
|
588
|
+
<span class="text-secondary">—</span>
|
|
589
|
+
{% endif %}
|
|
583
590
|
"""
|
|
584
591
|
|
|
585
592
|
def __init__(self, *args, **kwargs):
|
|
@@ -757,29 +764,33 @@ class CustomFieldColumn(django_tables2.Column):
|
|
|
757
764
|
Display custom fields in the appropriate format.
|
|
758
765
|
"""
|
|
759
766
|
|
|
760
|
-
# Add [] to empty_values so when there is no choice populated for multiselect_cf i.e. [], "—" is returned automatically.
|
|
761
|
-
empty_values = (None, "", [])
|
|
762
|
-
|
|
763
767
|
def __init__(self, customfield, *args, **kwargs):
|
|
764
768
|
self.customfield = customfield
|
|
765
769
|
kwargs["accessor"] = Accessor(f"_custom_field_data__{customfield.key}")
|
|
766
770
|
kwargs["verbose_name"] = customfield.label
|
|
771
|
+
if self.customfield.type == choices.CustomFieldTypeChoices.TYPE_MULTISELECT:
|
|
772
|
+
# Add [] to empty_values so when there is no choice populated i.e. [], "—" is returned automatically.
|
|
773
|
+
kwargs.setdefault("empty_values", (None, "", []))
|
|
767
774
|
|
|
768
775
|
super().__init__(*args, **kwargs)
|
|
769
776
|
|
|
770
777
|
def render(self, *, record, bound_column, value): # pylint: disable=arguments-differ # tables2 varies its kwargs
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
778
|
+
# TODO: this logic could be unified with _ObjectCustomFieldsPanel.render_value
|
|
779
|
+
if self.customfield.type == choices.CustomFieldTypeChoices.TYPE_BOOLEAN and value is not None:
|
|
780
|
+
value = helpers.render_boolean(value)
|
|
781
|
+
elif self.customfield.type == choices.CustomFieldTypeChoices.TYPE_JSON and value is not None:
|
|
782
|
+
value = helpers.render_json(value, pretty_print=True)
|
|
783
|
+
elif self.customfield.type == choices.CustomFieldTypeChoices.TYPE_MARKDOWN and value is not None:
|
|
784
|
+
value = helpers.render_markdown(value)
|
|
785
|
+
elif self.customfield.type == choices.CustomFieldTypeChoices.TYPE_MULTISELECT and value:
|
|
786
|
+
value = format_html_join(" ", '<span class="badge bg-secondary">{}</span>', ((v,) for v in value))
|
|
787
|
+
elif self.customfield.type == choices.CustomFieldTypeChoices.TYPE_SELECT and value is not None:
|
|
788
|
+
value = format_html('<span class="badge bg-secondary">{}</span>', value)
|
|
789
|
+
elif self.customfield.type == choices.CustomFieldTypeChoices.TYPE_URL and value:
|
|
790
|
+
value = format_html('<a href="{}">{}</a>', value, value)
|
|
791
|
+
# else (TEXT, INTEGER, DATE) or None value -- no need to do special rendering
|
|
781
792
|
|
|
782
|
-
return
|
|
793
|
+
return value
|
|
783
794
|
|
|
784
795
|
|
|
785
796
|
class RelationshipColumn(django_tables2.Column):
|
|
@@ -811,7 +822,7 @@ class RelationshipColumn(django_tables2.Column):
|
|
|
811
822
|
# Handle Symmetric Relationships
|
|
812
823
|
# List `value` could be empty here [] after the filtering from above
|
|
813
824
|
if len(value) < 1:
|
|
814
|
-
return
|
|
825
|
+
return helpers.HTML_NONE
|
|
815
826
|
|
|
816
827
|
v = value[0]
|
|
817
828
|
peer = v.get_peer(record)
|
|
@@ -81,11 +81,9 @@ add "&raw" to the end of the URL within a browser.
|
|
|
81
81
|
<!-- As Nautobot may be run without internet access, we source these files locally rather than from an online CDN -->
|
|
82
82
|
<link rel="stylesheet"
|
|
83
83
|
href="{% static 'dist/css/graphql-libraries.css' %}"
|
|
84
|
-
onerror="
|
|
85
|
-
<script src="{% static 'dist/js/graphql-libraries.js' %}"
|
|
86
|
-
|
|
87
|
-
<script src="{% static 'dist/js/nautobot-graphiql.js' %}"
|
|
88
|
-
onerror="window.location='{% url 'media_failure' %}?filename=dist/js/nautobot-graphiql.js'"></script>
|
|
84
|
+
onerror="nb.media.handleFailure(this)">
|
|
85
|
+
<script src="{% static 'dist/js/graphql-libraries.js' %}" onerror="nb.media.handleFailure(this)"></script>
|
|
86
|
+
<script src="{% static 'dist/js/nautobot-graphiql.js' %}" onerror="nb.media.handleFailure(this)"></script>
|
|
89
87
|
</head>
|
|
90
88
|
<body>
|
|
91
89
|
<!-- Nautobot page contents -->
|
|
@@ -2,16 +2,11 @@
|
|
|
2
2
|
{% load plugins %}
|
|
3
3
|
{% load static %}
|
|
4
4
|
|
|
5
|
-
<script src="{% static 'dist/js/nautobot.js' %}"
|
|
6
|
-
|
|
7
|
-
<script src="{%
|
|
8
|
-
|
|
9
|
-
<script src="{% versioned_static 'js/
|
|
10
|
-
onerror="window.location='{% url 'media_failure' %}?filename=js/forms.js'"></script>
|
|
11
|
-
<script src="{% versioned_static 'js/table_sorting_indicator.js' %}"
|
|
12
|
-
onerror="window.location='{% url 'media_failure' %}?filename=js/table_sorting_indicator.js'"></script>
|
|
13
|
-
<script src="{% versioned_static 'js/dropdown.js' %}"
|
|
14
|
-
onerror="window.location='{% url 'media_failure' %}?filename=js/dropdown.js'"></script>
|
|
5
|
+
<script src="{% static 'dist/js/nautobot.js' %}" onerror="nb.media.handleFailure(this)"></script>
|
|
6
|
+
<script src="{% static 'dist/js/libraries.js' %}" onerror="nb.media.handleFailure(this)"></script>
|
|
7
|
+
<script src="{% versioned_static 'js/forms.js' %}" onerror="nb.media.handleFailure(this)"></script>
|
|
8
|
+
<script src="{% versioned_static 'js/table_sorting_indicator.js' %}" onerror="nb.media.handleFailure(this)"></script>
|
|
9
|
+
<script src="{% versioned_static 'js/dropdown.js' %}" onerror="nb.media.handleFailure(this)"></script>
|
|
15
10
|
<script type="text/javascript">
|
|
16
11
|
var nautobot_static_url = "{% static '' %}";
|
|
17
12
|
var nautobot_api_path = "{% url 'api-root' %}";
|
|
@@ -1,25 +1,26 @@
|
|
|
1
1
|
{% load static %}
|
|
2
2
|
{% load helpers %}
|
|
3
3
|
{% load plugins %}
|
|
4
|
+
{% include 'inc/media_failure.html' %}
|
|
4
5
|
<link rel="stylesheet" id="template-theme"
|
|
5
6
|
href="{% url 'template_css' %}">
|
|
6
7
|
<link rel="stylesheet"
|
|
7
8
|
href="{% static 'dist/css/nautobot.css' %}"
|
|
8
|
-
onerror="
|
|
9
|
+
onerror="nb.media.handleFailure(this)">
|
|
9
10
|
<link rel="stylesheet"
|
|
10
11
|
href="{% static 'dist/css/materialdesignicons.css' %}"
|
|
11
|
-
onerror="
|
|
12
|
+
onerror="nb.media.handleFailure(this)">
|
|
12
13
|
{% with cookie_theme=request.COOKIES|get_item:'theme' %}
|
|
13
14
|
{% if not cookie_theme or cookie_theme == 'light' %}
|
|
14
15
|
<link rel="stylesheet"
|
|
15
16
|
href="{% static 'dist/css/github.min.css' %}"
|
|
16
|
-
onerror="
|
|
17
|
+
onerror="nb.media.handleFailure(this)"
|
|
17
18
|
{% if not cookie_theme %}media="not (prefers-color-scheme: dark)"{% endif %}>
|
|
18
19
|
{% endif %}
|
|
19
20
|
{% if not cookie_theme or cookie_theme == 'dark' %}
|
|
20
21
|
<link rel="stylesheet"
|
|
21
22
|
href="{% static 'dist/css/github-dark.min.css' %}"
|
|
22
|
-
onerror="
|
|
23
|
+
onerror="nb.media.handleFailure(this)"
|
|
23
24
|
{% if not cookie_theme %}media="(prefers-color-scheme: dark)"{% endif %}>
|
|
24
25
|
{% endif %}
|
|
25
26
|
{% endwith %}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
{% load static %}
|
|
2
|
+
|
|
3
|
+
<script>
|
|
4
|
+
(function initMediaFailure() {
|
|
5
|
+
// Create React-style `ref` reference to the media failure alert element.
|
|
6
|
+
const failureAlertRef = { current: null };
|
|
7
|
+
|
|
8
|
+
// Store all media failures inside `Map` containing `Set` values to ensure uniqueness of all reported failures.
|
|
9
|
+
const failures = new Map();
|
|
10
|
+
|
|
11
|
+
function handleFailure(element) {
|
|
12
|
+
const url = element.href || element.src || '';
|
|
13
|
+
|
|
14
|
+
if (url) {
|
|
15
|
+
// Update `failures` with a proper entry corresponding to the current media failure and update media failure alert.
|
|
16
|
+
const elements = failures.get(url) || new Set();
|
|
17
|
+
elements.add(element);
|
|
18
|
+
failures.set(url, elements);
|
|
19
|
+
updateFailureAlert();
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function updateFailureAlert() {
|
|
24
|
+
const count = Array.from(failures.values()).reduce((count, elements) => count + elements.size, 0);
|
|
25
|
+
|
|
26
|
+
const innerHTML = `
|
|
27
|
+
<div style="margin: auto; max-width: 50rem;">
|
|
28
|
+
<h2 style="margin-top: 0; text-align: center;">Static Media Failure</h2>
|
|
29
|
+
<p><strong>${count}</strong> static media file${count > 1 ? 's' : ''} failed to load.</p>
|
|
30
|
+
<p style="margin-bottom: 0;">
|
|
31
|
+
Check whether
|
|
32
|
+
<code><strong>nautobot-server collectstatic</strong></code>
|
|
33
|
+
was run during the most recent upgrade and that the HTTP service (e.g. NGINX) is configured to serve static files.
|
|
34
|
+
Refer to
|
|
35
|
+
<a href="https://docs.nautobot.com/projects/core/en/v{{ settings.VERSION }}/installation/http-server/#static-media-failure" target="_blank">
|
|
36
|
+
the installation documentation
|
|
37
|
+
</a>
|
|
38
|
+
for further guidance.
|
|
39
|
+
</p>
|
|
40
|
+
</div>
|
|
41
|
+
`;
|
|
42
|
+
|
|
43
|
+
// If media failure alert already exists, just update its content and return early.
|
|
44
|
+
if (failureAlertRef.current) {
|
|
45
|
+
failureAlertRef.current.innerHTML = innerHTML;
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// If media failure alert does not exist yet, create one.
|
|
50
|
+
const alert = document.createElement('div');
|
|
51
|
+
alert.classList.add('alert', 'alert-danger', 'media-failure-banner');
|
|
52
|
+
alert.setAttribute('role', 'alert');
|
|
53
|
+
alert.innerHTML = innerHTML;
|
|
54
|
+
|
|
55
|
+
// Copy and hardcode Bootstrap `"alert alert-danger"` styles here to make the alert core styles independent of other CSS.
|
|
56
|
+
alert.style.setProperty('background-color', 'var(--bs-alert-bg, var(--bs-danger-bg-subtle, #fce8e8))');
|
|
57
|
+
alert.style.setProperty('border', 'var(--bs-alert-border, var(--bs-border-width, 0.0625rem) solid var(--bs-alert-border-color, var(--bs-danger-border-subtle, #f9d2d2)))');
|
|
58
|
+
alert.style.setProperty('border-radius', '0');
|
|
59
|
+
alert.style.setProperty('color', 'var(--bs-alert-color, var(--bs-danger-text-emphasis, #e01f1f))');
|
|
60
|
+
alert.style.setProperty('grid-area', 'banner-global-area');
|
|
61
|
+
alert.style.setProperty('padding', 'var(--bs-alert-padding-y, 1rem) 1.25rem');
|
|
62
|
+
alert.style.setProperty('position', 'relative');
|
|
63
|
+
|
|
64
|
+
// Update React-style `ref` to simplify later alert updates if required and place the alert as the first child of document body.
|
|
65
|
+
failureAlertRef.current = alert;
|
|
66
|
+
document.body.prepend(alert);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Export `media` "API" to `window` global object to enable accessing it from other scripts.
|
|
70
|
+
window.nb = window.nb || {};
|
|
71
|
+
window.nb.media = { failures, handleFailure }
|
|
72
|
+
})();
|
|
73
|
+
</script>
|
nautobot/core/tests/test_cli.py
CHANGED
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
|
|
1
|
+
import importlib.util
|
|
2
|
+
import os.path
|
|
3
|
+
import sys
|
|
4
|
+
from unittest import mock
|
|
5
|
+
|
|
6
|
+
from nautobot.core.cli import _preprocess_settings, migrate_deprecated_templates
|
|
2
7
|
from nautobot.core.testing import TestCase
|
|
3
8
|
|
|
4
9
|
|
|
@@ -38,3 +43,117 @@ class TestMigrateTemplates(TestCase):
|
|
|
38
43
|
replaced_content, was_updated = migrate_deprecated_templates.replace_template_references(original_content)
|
|
39
44
|
self.assertTrue(was_updated)
|
|
40
45
|
self.assertEqual(replaced_content, new_content)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
@mock.patch("nautobot.core.cli.load_plugins")
|
|
49
|
+
@mock.patch("nautobot.core.cli.load_event_brokers")
|
|
50
|
+
class TestPreprocessSettings(TestCase):
|
|
51
|
+
"""Tests for the `_preprocess_settings` function in nautobot.core.cli, as it's important to Nautobot startup."""
|
|
52
|
+
|
|
53
|
+
def load_settings_module(self):
|
|
54
|
+
# Load the testing nautobot_config.py as a self-contained module
|
|
55
|
+
config_path = os.path.join(os.path.dirname(__file__), "nautobot_config.py")
|
|
56
|
+
spec = importlib.util.spec_from_file_location("test_nautobot_config", config_path)
|
|
57
|
+
settings_module = importlib.util.module_from_spec(spec)
|
|
58
|
+
# nautobot.core.cli.load_settings would do the below, but obviously we don't want to do that here:
|
|
59
|
+
# sys.modules["nautobot_config"] = settings_module
|
|
60
|
+
spec.loader.exec_module(settings_module)
|
|
61
|
+
return settings_module, config_path
|
|
62
|
+
|
|
63
|
+
def test_basic_path(self, mock_load_event_brokers, mock_load_plugins):
|
|
64
|
+
"""Basic operation of the function."""
|
|
65
|
+
settings_module, config_path = self.load_settings_module()
|
|
66
|
+
|
|
67
|
+
# Process the settings module
|
|
68
|
+
_preprocess_settings(settings_module, config_path)
|
|
69
|
+
|
|
70
|
+
# _preprocess_settings should have set SETTINGS_PATH on the module
|
|
71
|
+
self.assertEqual(settings_module.SETTINGS_PATH, config_path)
|
|
72
|
+
|
|
73
|
+
# the default test settings have no EXTRA_* settings to handle
|
|
74
|
+
|
|
75
|
+
# all media paths should exist
|
|
76
|
+
self.assertTrue(os.path.isdir(settings_module.GIT_ROOT))
|
|
77
|
+
self.assertTrue(os.path.isdir(settings_module.JOBS_ROOT))
|
|
78
|
+
self.assertTrue(os.path.isdir(settings_module.MEDIA_ROOT))
|
|
79
|
+
self.assertTrue(os.path.isdir(os.path.join(settings_module.MEDIA_ROOT, "devicetype-images")))
|
|
80
|
+
self.assertTrue(os.path.isdir(os.path.join(settings_module.MEDIA_ROOT, "image-attachments")))
|
|
81
|
+
self.assertTrue(os.path.isdir(settings_module.STATIC_ROOT))
|
|
82
|
+
|
|
83
|
+
# databases should be using the prometheus backends
|
|
84
|
+
self.assertTrue(settings_module.METRICS_ENABLED)
|
|
85
|
+
self.assertIn("django_prometheus.db.backends", settings_module.DATABASES["default"]["ENGINE"])
|
|
86
|
+
|
|
87
|
+
# job_logs database connection should exist
|
|
88
|
+
self.assertIn("job_logs", settings_module.DATABASES)
|
|
89
|
+
self.assertIn("TEST", settings_module.DATABASES["job_logs"])
|
|
90
|
+
self.assertEqual(settings_module.DATABASES["job_logs"]["TEST"], {"MIRROR": "default"})
|
|
91
|
+
for key, value in settings_module.DATABASES["default"].items():
|
|
92
|
+
if key == "TEST":
|
|
93
|
+
continue
|
|
94
|
+
self.assertEqual(value, settings_module.DATABASES["job_logs"][key])
|
|
95
|
+
|
|
96
|
+
# STORAGES should remain as default
|
|
97
|
+
self.assertEqual(
|
|
98
|
+
settings_module.STORAGES,
|
|
99
|
+
{
|
|
100
|
+
"default": {"BACKEND": "django.core.files.storage.FileSystemStorage"},
|
|
101
|
+
"staticfiles": {"BACKEND": "django.contrib.staticfiles.storage.StaticFilesStorage"},
|
|
102
|
+
"nautobotjobfiles": {"BACKEND": "db_file_storage.storage.DatabaseFileStorage"},
|
|
103
|
+
},
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
mock_load_plugins.assert_called_with(settings_module)
|
|
107
|
+
mock_load_event_brokers.assert_called_with(settings_module.EVENT_BROKERS)
|
|
108
|
+
|
|
109
|
+
def test_EXTRA_behavior(self, *args):
|
|
110
|
+
"""Handling of special settings like EXTRA_INSTALLED_APPS and EXTRA_MIDDLEWARE."""
|
|
111
|
+
settings_module, config_path = self.load_settings_module()
|
|
112
|
+
|
|
113
|
+
# Inject EXTRA_INSTALLED_APPS and EXTRA_MIDDLEWARE to the settings module for test purposes
|
|
114
|
+
settings_module.EXTRA_INSTALLED_APPS = ["foo.bar"]
|
|
115
|
+
settings_module.EXTRA_MIDDLEWARE = ("baz.bat",)
|
|
116
|
+
|
|
117
|
+
# Process the settings module
|
|
118
|
+
_preprocess_settings(settings_module, config_path)
|
|
119
|
+
|
|
120
|
+
self.assertIn("foo.bar", settings_module.INSTALLED_APPS)
|
|
121
|
+
# more specifically:
|
|
122
|
+
self.assertEqual("foo.bar", settings_module.INSTALLED_APPS[-1])
|
|
123
|
+
self.assertIn("baz.bat", settings_module.MIDDLEWARE)
|
|
124
|
+
# more specifically:
|
|
125
|
+
self.assertEqual("baz.bat", settings_module.MIDDLEWARE[-1])
|
|
126
|
+
|
|
127
|
+
def test_legacy_storage_behavior(self, *args):
|
|
128
|
+
"""Handling legacy storage settings."""
|
|
129
|
+
settings_module, config_path = self.load_settings_module()
|
|
130
|
+
|
|
131
|
+
settings_module.DEFAULT_FILE_STORAGE = "storages.some_custom_backend"
|
|
132
|
+
settings_module.JOB_FILE_IO_STORAGE = "some_custom_job_file_storage"
|
|
133
|
+
settings_module.STATICFILES_STORAGE = "some_custom_static_storage"
|
|
134
|
+
settings_module.STORAGE_BACKEND = "storages.some_custom_backend"
|
|
135
|
+
settings_module.STORAGE_CONFIG = {"MY_BACKEND_OPTION": "some_value"}
|
|
136
|
+
|
|
137
|
+
import storages.utils
|
|
138
|
+
|
|
139
|
+
original_setting = storages.utils.setting
|
|
140
|
+
del sys.modules["storages.utils"]
|
|
141
|
+
del storages.utils
|
|
142
|
+
|
|
143
|
+
try:
|
|
144
|
+
# Process the settings module
|
|
145
|
+
_preprocess_settings(settings_module, config_path)
|
|
146
|
+
|
|
147
|
+
self.assertFalse(hasattr(settings_module, "DEFAULT_FILE_STORAGE")) # unset to avoid a Django exception
|
|
148
|
+
self.assertEqual("storages.some_custom_backend", settings_module.STORAGES["default"]["BACKEND"])
|
|
149
|
+
self.assertEqual("some_custom_job_file_storage", settings_module.STORAGES["nautobotjobfiles"]["BACKEND"])
|
|
150
|
+
self.assertFalse(hasattr(settings_module, "STATICFILES_STORAGE")) # unset to avoid a Django exception
|
|
151
|
+
self.assertEqual("some_custom_static_storage", settings_module.STORAGES["staticfiles"]["BACKEND"])
|
|
152
|
+
|
|
153
|
+
self.assertEqual("some_value", storages.utils.setting("MY_BACKEND_OPTION"))
|
|
154
|
+
finally:
|
|
155
|
+
# Clean up the STORAGE_CONFIG monkeypatch
|
|
156
|
+
import storages.utils # pylint: disable=reimported
|
|
157
|
+
|
|
158
|
+
storages.utils.setting = original_setting
|
|
159
|
+
self.assertIsNone(storages.utils.setting("MY_BACKEND_OPTION"))
|