nautobot 2.3.2__py3-none-any.whl → 2.3.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/core/celery/schedulers.py +2 -2
- nautobot/core/settings.py +3 -1
- nautobot/core/settings.yaml +40 -23
- nautobot/core/tests/runner.py +27 -9
- nautobot/core/tests/test_settings_schema.py +7 -3
- nautobot/core/tests/test_utils.py +13 -0
- nautobot/core/utils/lookup.py +7 -1
- nautobot/dcim/tables/power.py +1 -1
- nautobot/dcim/tests/test_filters.py +1 -1
- nautobot/extras/context_managers.py +11 -4
- nautobot/extras/jobs.py +0 -1
- nautobot/extras/models/groups.py +4 -1
- nautobot/extras/tests/test_context_managers.py +33 -14
- nautobot/extras/tests/test_dynamicgroups.py +11 -0
- nautobot/extras/tests/test_models.py +5 -0
- nautobot/extras/tests/test_views.py +1 -0
- nautobot/ipam/models.py +4 -0
- nautobot/ipam/tests/test_api.py +11 -0
- nautobot/project-static/docs/404.html +81 -169
- nautobot/project-static/docs/additional-features/caching.html +3 -3
- nautobot/project-static/docs/additional-features/healthcheck.html +3 -3
- nautobot/project-static/docs/apps/index.html +83 -171
- nautobot/project-static/docs/apps/nautobot-apps.html +82 -170
- nautobot/project-static/docs/assets/javascripts/bundle.56dfad97.min.js +16 -0
- nautobot/project-static/docs/assets/javascripts/bundle.56dfad97.min.js.map +7 -0
- nautobot/project-static/docs/assets/javascripts/workers/{search.b8dbb3d2.min.js → search.07f07601.min.js} +1 -1
- nautobot/project-static/docs/assets/javascripts/workers/{search.b8dbb3d2.min.js.map → search.07f07601.min.js.map} +1 -1
- nautobot/project-static/docs/assets/stylesheets/main.35f28582.min.css +1 -0
- nautobot/project-static/docs/assets/stylesheets/main.35f28582.min.css.map +1 -0
- nautobot/project-static/docs/code-reference/nautobot/apps/__init__.html +84 -172
- nautobot/project-static/docs/code-reference/nautobot/apps/admin.html +84 -172
- nautobot/project-static/docs/code-reference/nautobot/apps/api.html +116 -204
- nautobot/project-static/docs/code-reference/nautobot/apps/change_logging.html +90 -177
- nautobot/project-static/docs/code-reference/nautobot/apps/choices.html +89 -177
- nautobot/project-static/docs/code-reference/nautobot/apps/config.html +83 -171
- nautobot/project-static/docs/code-reference/nautobot/apps/constants.html +83 -171
- nautobot/project-static/docs/code-reference/nautobot/apps/datasources.html +88 -176
- nautobot/project-static/docs/code-reference/nautobot/apps/exceptions.html +92 -180
- nautobot/project-static/docs/code-reference/nautobot/apps/factory.html +99 -187
- nautobot/project-static/docs/code-reference/nautobot/apps/filters.html +106 -194
- nautobot/project-static/docs/code-reference/nautobot/apps/forms.html +150 -238
- nautobot/project-static/docs/code-reference/nautobot/apps/graphql.html +99 -187
- nautobot/project-static/docs/code-reference/nautobot/apps/jobs.html +143 -231
- nautobot/project-static/docs/code-reference/nautobot/apps/models.html +142 -230
- nautobot/project-static/docs/code-reference/nautobot/apps/querysets.html +84 -172
- nautobot/project-static/docs/code-reference/nautobot/apps/secrets.html +86 -174
- nautobot/project-static/docs/code-reference/nautobot/apps/tables.html +98 -186
- nautobot/project-static/docs/code-reference/nautobot/apps/testing.html +136 -224
- nautobot/project-static/docs/code-reference/nautobot/apps/ui.html +135 -223
- nautobot/project-static/docs/code-reference/nautobot/apps/urls.html +84 -172
- nautobot/project-static/docs/code-reference/nautobot/apps/utils.html +138 -226
- nautobot/project-static/docs/code-reference/nautobot/apps/views.html +125 -213
- nautobot/project-static/docs/configuration/optional-settings.html +3 -3
- nautobot/project-static/docs/configuration/required-settings.html +3 -3
- nautobot/project-static/docs/development/apps/api/configuration-view.html +83 -171
- nautobot/project-static/docs/development/apps/api/database-backend-config.html +83 -171
- nautobot/project-static/docs/development/apps/api/models/django-admin.html +83 -171
- nautobot/project-static/docs/development/apps/api/models/global-search.html +83 -171
- nautobot/project-static/docs/development/apps/api/models/graphql.html +83 -171
- nautobot/project-static/docs/development/apps/api/models/index.html +83 -171
- nautobot/project-static/docs/development/apps/api/nautobot-app-config.html +83 -171
- nautobot/project-static/docs/development/apps/api/platform-features/custom-validators.html +83 -171
- nautobot/project-static/docs/development/apps/api/platform-features/filter-extensions.html +83 -171
- nautobot/project-static/docs/development/apps/api/platform-features/git-repository-content.html +83 -171
- nautobot/project-static/docs/development/apps/api/platform-features/index.html +83 -171
- nautobot/project-static/docs/development/apps/api/platform-features/jinja2-filters.html +83 -171
- nautobot/project-static/docs/development/apps/api/platform-features/jobs.html +83 -171
- nautobot/project-static/docs/development/apps/api/platform-features/populating-extensibility-features.html +83 -171
- nautobot/project-static/docs/development/apps/api/platform-features/secrets-providers.html +83 -171
- nautobot/project-static/docs/development/apps/api/platform-features/uniquely-identify-objects.html +85 -173
- nautobot/project-static/docs/development/apps/api/prometheus.html +83 -171
- nautobot/project-static/docs/development/apps/api/setup.html +83 -171
- nautobot/project-static/docs/development/apps/api/testing.html +84 -172
- nautobot/project-static/docs/development/apps/api/ui-extensions/banners.html +83 -171
- nautobot/project-static/docs/development/apps/api/ui-extensions/home-page.html +83 -171
- nautobot/project-static/docs/development/apps/api/ui-extensions/index.html +83 -171
- nautobot/project-static/docs/development/apps/api/ui-extensions/navigation.html +83 -171
- nautobot/project-static/docs/development/apps/api/ui-extensions/object-views.html +83 -171
- nautobot/project-static/docs/development/apps/api/views/base-template.html +83 -171
- nautobot/project-static/docs/development/apps/api/views/core-view-overrides.html +83 -171
- nautobot/project-static/docs/development/apps/api/views/django-generic-views.html +83 -171
- nautobot/project-static/docs/development/apps/api/views/help-documentation.html +83 -171
- nautobot/project-static/docs/development/apps/api/views/index.html +83 -171
- nautobot/project-static/docs/development/apps/api/views/nautobot-generic-views.html +83 -171
- nautobot/project-static/docs/development/apps/api/views/nautobotuiviewset.html +83 -171
- nautobot/project-static/docs/development/apps/api/views/nautobotuiviewsetrouter.html +83 -171
- nautobot/project-static/docs/development/apps/api/views/notes.html +83 -171
- nautobot/project-static/docs/development/apps/api/views/rest-api.html +83 -171
- nautobot/project-static/docs/development/apps/api/views/urls.html +83 -171
- nautobot/project-static/docs/development/apps/index.html +84 -172
- nautobot/project-static/docs/development/apps/migration/code-updates.html +83 -171
- nautobot/project-static/docs/development/apps/migration/dependency-updates.html +83 -171
- nautobot/project-static/docs/development/apps/migration/from-v1.html +83 -171
- nautobot/project-static/docs/development/apps/migration/model-updates/dcim.html +83 -171
- nautobot/project-static/docs/development/apps/migration/model-updates/extras.html +83 -171
- nautobot/project-static/docs/development/apps/migration/model-updates/global.html +83 -171
- nautobot/project-static/docs/development/apps/migration/model-updates/ipam.html +83 -171
- nautobot/project-static/docs/development/apps/porting-from-netbox.html +83 -171
- nautobot/project-static/docs/development/core/application-registry.html +83 -171
- nautobot/project-static/docs/development/core/best-practices.html +83 -171
- nautobot/project-static/docs/development/core/bootstrap-ui.html +83 -171
- nautobot/project-static/docs/development/core/caching.html +83 -171
- nautobot/project-static/docs/development/core/controllers.html +83 -171
- nautobot/project-static/docs/development/core/docker-compose-advanced-use-cases.html +83 -171
- nautobot/project-static/docs/development/core/generic-views.html +83 -171
- nautobot/project-static/docs/development/core/getting-started.html +106 -191
- nautobot/project-static/docs/development/core/homepage.html +83 -171
- nautobot/project-static/docs/development/core/index.html +83 -171
- nautobot/project-static/docs/development/core/model-checklist.html +83 -171
- nautobot/project-static/docs/development/core/model-features.html +83 -171
- nautobot/project-static/docs/development/core/natural-keys.html +83 -171
- nautobot/project-static/docs/development/core/navigation-menu.html +83 -171
- nautobot/project-static/docs/development/core/release-checklist.html +83 -171
- nautobot/project-static/docs/development/core/role-internals.html +83 -171
- nautobot/project-static/docs/development/core/settings.html +83 -171
- nautobot/project-static/docs/development/core/style-guide.html +83 -171
- nautobot/project-static/docs/development/core/templates.html +83 -171
- nautobot/project-static/docs/development/core/testing.html +85 -173
- nautobot/project-static/docs/development/core/user-preferences.html +83 -171
- nautobot/project-static/docs/development/index.html +83 -171
- nautobot/project-static/docs/development/jobs/index.html +91 -179
- nautobot/project-static/docs/development/jobs/migration/from-v1.html +84 -172
- nautobot/project-static/docs/docker/index.html +3 -3
- nautobot/project-static/docs/index.html +88 -176
- nautobot/project-static/docs/installation/selinux-troubleshooting.html +3 -3
- nautobot/project-static/docs/overview/application_stack.html +89 -177
- nautobot/project-static/docs/overview/design_philosophy.html +83 -171
- nautobot/project-static/docs/release-notes/index.html +83 -171
- nautobot/project-static/docs/release-notes/version-1.0.html +83 -171
- nautobot/project-static/docs/release-notes/version-1.1.html +84 -172
- nautobot/project-static/docs/release-notes/version-1.2.html +86 -174
- nautobot/project-static/docs/release-notes/version-1.3.html +84 -172
- nautobot/project-static/docs/release-notes/version-1.4.html +85 -173
- nautobot/project-static/docs/release-notes/version-1.5.html +85 -173
- nautobot/project-static/docs/release-notes/version-1.6.html +87 -175
- nautobot/project-static/docs/release-notes/version-2.0.html +84 -172
- nautobot/project-static/docs/release-notes/version-2.1.html +85 -173
- nautobot/project-static/docs/release-notes/version-2.2.html +83 -171
- nautobot/project-static/docs/release-notes/version-2.3.html +425 -235
- nautobot/project-static/docs/search/search_index.json +1 -1
- nautobot/project-static/docs/sitemap.xml +277 -556
- nautobot/project-static/docs/sitemap.xml.gz +0 -0
- nautobot/project-static/docs/user-guide/administration/configuration/authentication/ldap.html +85 -173
- nautobot/project-static/docs/user-guide/administration/configuration/authentication/remote.html +84 -172
- nautobot/project-static/docs/user-guide/administration/configuration/authentication/sso.html +85 -173
- nautobot/project-static/docs/user-guide/administration/configuration/index.html +94 -192
- nautobot/project-static/docs/user-guide/administration/configuration/optional-settings.html +13 -12524
- nautobot/project-static/docs/user-guide/administration/configuration/redis.html +8966 -0
- nautobot/project-static/docs/user-guide/administration/configuration/required-settings.html +13 -9218
- nautobot/project-static/docs/user-guide/administration/configuration/settings.html +12734 -0
- nautobot/project-static/docs/user-guide/administration/configuration/time-zones.html +87 -175
- nautobot/project-static/docs/user-guide/administration/guides/caching.html +13 -9108
- nautobot/project-static/docs/user-guide/administration/guides/celery-queues.html +84 -172
- nautobot/project-static/docs/user-guide/administration/guides/docker.html +9491 -0
- nautobot/project-static/docs/user-guide/administration/guides/health-checks.html +9478 -0
- nautobot/project-static/docs/user-guide/administration/guides/healthcheck.html +13 -8833
- nautobot/project-static/docs/user-guide/administration/guides/permissions.html +87 -175
- nautobot/project-static/docs/user-guide/administration/guides/prometheus-metrics.html +84 -172
- nautobot/project-static/docs/user-guide/administration/guides/replicating-nautobot.html +84 -172
- nautobot/project-static/docs/user-guide/administration/guides/request-profiling.html +83 -171
- nautobot/project-static/docs/user-guide/administration/guides/s3-django-storage.html +83 -171
- nautobot/project-static/docs/user-guide/administration/guides/selinux-troubleshooting.html +8978 -0
- nautobot/project-static/docs/user-guide/administration/installation/app-install.html +83 -171
- nautobot/project-static/docs/user-guide/administration/installation/docker.html +3 -3
- nautobot/project-static/docs/user-guide/administration/installation/external-authentication.html +86 -174
- nautobot/project-static/docs/user-guide/administration/installation/health-checks.html +3 -3
- nautobot/project-static/docs/user-guide/administration/installation/http-server.html +84 -174
- nautobot/project-static/docs/user-guide/administration/installation/index.html +85 -173
- nautobot/project-static/docs/user-guide/administration/installation/install_system.html +83 -171
- nautobot/project-static/docs/user-guide/administration/installation/nautobot.html +99 -184
- nautobot/project-static/docs/user-guide/administration/installation/selinux-troubleshooting.html +3 -3
- nautobot/project-static/docs/user-guide/administration/installation/services.html +85 -173
- nautobot/project-static/docs/user-guide/administration/installation-extras/docker.html +13 -9577
- nautobot/project-static/docs/user-guide/administration/installation-extras/health-checks.html +13 -9560
- nautobot/project-static/docs/user-guide/administration/installation-extras/selinux-troubleshooting.html +13 -9064
- nautobot/project-static/docs/user-guide/administration/migration/migrating-from-netbox.html +85 -173
- nautobot/project-static/docs/user-guide/administration/migration/migrating-from-postgresql.html +83 -171
- nautobot/project-static/docs/user-guide/administration/tools/nautobot-server.html +89 -177
- nautobot/project-static/docs/user-guide/administration/tools/nautobot-shell.html +86 -174
- nautobot/project-static/docs/user-guide/administration/upgrading/database-backup.html +89 -177
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/after-you-upgrade.html +86 -174
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/before-you-upgrade.html +86 -174
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/for-developers.html +86 -174
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/index.html +86 -174
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/whats-changed.html +86 -174
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/region-and-site-data-migration-guide.html +86 -174
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/upgrading-from-nautobot-v1.html +88 -176
- nautobot/project-static/docs/user-guide/administration/upgrading/upgrading.html +86 -174
- nautobot/project-static/docs/user-guide/core-data-model/circuits/circuit.html +83 -171
- nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittermination.html +83 -171
- nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittype.html +83 -171
- nautobot/project-static/docs/user-guide/core-data-model/circuits/provider.html +83 -171
- nautobot/project-static/docs/user-guide/core-data-model/circuits/providernetwork.html +83 -171
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloud.html +83 -171
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudaccount.html +83 -171
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudnetwork.html +83 -171
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudnetworkprefixassignment.html +83 -171
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudresourcetype.html +83 -171
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudservice.html +83 -171
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudservicenetworkassignment.html +83 -171
- nautobot/project-static/docs/user-guide/core-data-model/dcim/cable.html +83 -171
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleport.html +83 -171
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleporttemplate.html +83 -171
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverport.html +83 -171
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverporttemplate.html +83 -171
- nautobot/project-static/docs/user-guide/core-data-model/dcim/controller.html +83 -171
- nautobot/project-static/docs/user-guide/core-data-model/dcim/controllermanageddevicegroup.html +83 -171
- nautobot/project-static/docs/user-guide/core-data-model/dcim/device.html +83 -171
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebay.html +83 -171
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebaytemplate.html +83 -171
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicefamily.html +83 -171
- nautobot/project-static/docs/user-guide/core-data-model/dcim/deviceredundancygroup.html +83 -171
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicetype.html +83 -171
- nautobot/project-static/docs/user-guide/core-data-model/dcim/frontport.html +83 -171
- nautobot/project-static/docs/user-guide/core-data-model/dcim/frontporttemplate.html +83 -171
- nautobot/project-static/docs/user-guide/core-data-model/dcim/interface.html +83 -171
- nautobot/project-static/docs/user-guide/core-data-model/dcim/interfaceredundancygroup.html +83 -171
- nautobot/project-static/docs/user-guide/core-data-model/dcim/interfacetemplate.html +83 -171
- nautobot/project-static/docs/user-guide/core-data-model/dcim/inventoryitem.html +83 -171
- nautobot/project-static/docs/user-guide/core-data-model/dcim/location.html +83 -171
- nautobot/project-static/docs/user-guide/core-data-model/dcim/locationtype.html +83 -171
- nautobot/project-static/docs/user-guide/core-data-model/dcim/manufacturer.html +83 -171
- nautobot/project-static/docs/user-guide/core-data-model/dcim/module.html +83 -171
- nautobot/project-static/docs/user-guide/core-data-model/dcim/modulebay.html +83 -171
- nautobot/project-static/docs/user-guide/core-data-model/dcim/modulebaytemplate.html +83 -171
- nautobot/project-static/docs/user-guide/core-data-model/dcim/moduletype.html +83 -171
- nautobot/project-static/docs/user-guide/core-data-model/dcim/platform.html +84 -172
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerfeed.html +83 -171
- nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlet.html +83 -171
- nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlettemplate.html +83 -171
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerpanel.html +83 -171
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerport.html +83 -171
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerporttemplate.html +83 -171
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rack.html +83 -171
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rackgroup.html +83 -171
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rackreservation.html +83 -171
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rearport.html +83 -171
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rearporttemplate.html +83 -171
- nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareimagefile.html +83 -171
- nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareversion.html +83 -171
- nautobot/project-static/docs/user-guide/core-data-model/dcim/virtualchassis.html +83 -171
- nautobot/project-static/docs/user-guide/core-data-model/extras/configcontext.html +84 -172
- nautobot/project-static/docs/user-guide/core-data-model/extras/configcontextschema.html +83 -171
- nautobot/project-static/docs/user-guide/core-data-model/extras/contact.html +83 -171
- nautobot/project-static/docs/user-guide/core-data-model/extras/team.html +83 -171
- nautobot/project-static/docs/user-guide/core-data-model/ipam/ipaddress.html +83 -171
- nautobot/project-static/docs/user-guide/core-data-model/ipam/namespace.html +83 -171
- nautobot/project-static/docs/user-guide/core-data-model/ipam/prefix.html +83 -171
- nautobot/project-static/docs/user-guide/core-data-model/ipam/rir.html +83 -171
- nautobot/project-static/docs/user-guide/core-data-model/ipam/routetarget.html +83 -171
- nautobot/project-static/docs/user-guide/core-data-model/ipam/service.html +83 -171
- nautobot/project-static/docs/user-guide/core-data-model/ipam/vlan.html +83 -171
- nautobot/project-static/docs/user-guide/core-data-model/ipam/vlangroup.html +83 -171
- nautobot/project-static/docs/user-guide/core-data-model/ipam/vrf.html +83 -171
- nautobot/project-static/docs/user-guide/core-data-model/overview/introduction.html +83 -171
- nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenant.html +83 -171
- nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenantgroup.html +83 -171
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/cluster.html +83 -171
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustergroup.html +83 -171
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustertype.html +83 -171
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/virtualmachine.html +83 -171
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/vminterface.html +83 -171
- nautobot/project-static/docs/user-guide/feature-guides/contacts-and-teams.html +83 -171
- nautobot/project-static/docs/user-guide/feature-guides/custom-fields.html +83 -171
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-devices.html +83 -171
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-location-types-and-locations.html +83 -171
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/index.html +83 -171
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/interfaces.html +83 -171
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/ipam.html +83 -171
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/platforms.html +83 -171
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/search-bar.html +83 -171
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/tenants.html +83 -171
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/vlans-and-vlan-groups.html +83 -171
- nautobot/project-static/docs/user-guide/feature-guides/git-data-source.html +84 -172
- nautobot/project-static/docs/user-guide/feature-guides/graphql.html +83 -171
- nautobot/project-static/docs/user-guide/feature-guides/ip-address-merge-tool.html +83 -171
- nautobot/project-static/docs/user-guide/feature-guides/relationships.html +83 -171
- nautobot/project-static/docs/user-guide/feature-guides/software-image-files-and-versions.html +83 -171
- nautobot/project-static/docs/user-guide/index.html +83 -171
- nautobot/project-static/docs/user-guide/platform-functionality/change-logging.html +83 -171
- nautobot/project-static/docs/user-guide/platform-functionality/computedfield.html +83 -171
- nautobot/project-static/docs/user-guide/platform-functionality/customfield.html +83 -171
- nautobot/project-static/docs/user-guide/platform-functionality/customlink.html +83 -171
- nautobot/project-static/docs/user-guide/platform-functionality/dynamicgroup.html +84 -172
- nautobot/project-static/docs/user-guide/platform-functionality/exporttemplate.html +83 -171
- nautobot/project-static/docs/user-guide/platform-functionality/externalintegration.html +83 -171
- nautobot/project-static/docs/user-guide/platform-functionality/gitrepository.html +84 -172
- nautobot/project-static/docs/user-guide/platform-functionality/graphql.html +85 -173
- nautobot/project-static/docs/user-guide/platform-functionality/graphqlquery.html +83 -171
- nautobot/project-static/docs/user-guide/platform-functionality/imageattachment.html +84 -172
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/index.html +83 -171
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/job-scheduling-and-approvals.html +83 -171
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobbutton.html +83 -171
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobhook.html +83 -171
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/models.html +83 -171
- nautobot/project-static/docs/user-guide/platform-functionality/napalm.html +84 -172
- nautobot/project-static/docs/user-guide/platform-functionality/note.html +83 -171
- nautobot/project-static/docs/user-guide/platform-functionality/objectmetadata.html +83 -171
- nautobot/project-static/docs/user-guide/platform-functionality/relationship.html +83 -171
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/authentication.html +84 -172
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/filtering.html +84 -172
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/overview.html +85 -173
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/ui-related-endpoints.html +83 -171
- nautobot/project-static/docs/user-guide/platform-functionality/role.html +83 -171
- nautobot/project-static/docs/user-guide/platform-functionality/savedview.html +83 -171
- nautobot/project-static/docs/user-guide/platform-functionality/secret.html +83 -171
- nautobot/project-static/docs/user-guide/platform-functionality/staticgroupassociation.html +83 -171
- nautobot/project-static/docs/user-guide/platform-functionality/status.html +83 -171
- nautobot/project-static/docs/user-guide/platform-functionality/tag.html +83 -171
- nautobot/project-static/docs/user-guide/platform-functionality/template-filters.html +83 -171
- nautobot/project-static/docs/user-guide/platform-functionality/users/objectpermission.html +83 -171
- nautobot/project-static/docs/user-guide/platform-functionality/users/token.html +83 -171
- nautobot/project-static/docs/user-guide/platform-functionality/webhook.html +83 -171
- nautobot/virtualization/filters.py +6 -1
- nautobot/virtualization/tables.py +2 -2
- {nautobot-2.3.2.dist-info → nautobot-2.3.4.dist-info}/METADATA +4 -4
- {nautobot-2.3.2.dist-info → nautobot-2.3.4.dist-info}/RECORD +321 -317
- nautobot/project-static/docs/assets/javascripts/bundle.fe8b6f2b.min.js +0 -29
- nautobot/project-static/docs/assets/javascripts/bundle.fe8b6f2b.min.js.map +0 -7
- nautobot/project-static/docs/assets/stylesheets/main.3cba04c6.min.css +0 -1
- nautobot/project-static/docs/assets/stylesheets/main.3cba04c6.min.css.map +0 -1
- nautobot/project-static/docs/user-guide/administration/configuration/render-settings-fragment.j2 +0 -76
- {nautobot-2.3.2.dist-info → nautobot-2.3.4.dist-info}/LICENSE.txt +0 -0
- {nautobot-2.3.2.dist-info → nautobot-2.3.4.dist-info}/NOTICE +0 -0
- {nautobot-2.3.2.dist-info → nautobot-2.3.4.dist-info}/WHEEL +0 -0
- {nautobot-2.3.2.dist-info → nautobot-2.3.4.dist-info}/entry_points.txt +0 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
from collections.abc import Mapping
|
|
2
|
-
from datetime import datetime
|
|
2
|
+
from datetime import datetime, timedelta
|
|
3
3
|
import logging
|
|
4
4
|
from pathlib import Path
|
|
5
5
|
|
|
@@ -83,7 +83,7 @@ class NautobotScheduleEntry(ModelEntry):
|
|
|
83
83
|
# This will trigger the job to run at start_time
|
|
84
84
|
# and avoid the heap block.
|
|
85
85
|
if model.start_time:
|
|
86
|
-
model.last_run_at = model.last_run_at -
|
|
86
|
+
model.last_run_at = model.last_run_at - timedelta(days=365 * 30)
|
|
87
87
|
|
|
88
88
|
self.last_run_at = model.last_run_at
|
|
89
89
|
|
nautobot/core/settings.py
CHANGED
|
@@ -641,6 +641,8 @@ LOGIN_REDIRECT_URL = "home"
|
|
|
641
641
|
CONSTANCE_BACKEND = "constance.backends.database.DatabaseBackend"
|
|
642
642
|
CONSTANCE_DATABASE_PREFIX = "constance:nautobot:"
|
|
643
643
|
CONSTANCE_DATABASE_CACHE_BACKEND = "default"
|
|
644
|
+
# Constance defaults to a 24-hour timeout when autofilling its cache, which is undesirable in many cases.
|
|
645
|
+
CONSTANCE_DATABASE_CACHE_AUTOFILL_TIMEOUT = int(os.getenv("NAUTOBOT_CACHES_TIMEOUT", "300"))
|
|
644
646
|
CONSTANCE_IGNORE_ADMIN_VERSION_CHECK = True # avoid potential errors in a multi-node deployment
|
|
645
647
|
|
|
646
648
|
CONSTANCE_ADDITIONAL_FIELDS = {
|
|
@@ -853,7 +855,7 @@ CACHES = {
|
|
|
853
855
|
"django_prometheus.cache.backends.redis.RedisCache" if METRICS_ENABLED else "django_redis.cache.RedisCache",
|
|
854
856
|
),
|
|
855
857
|
"LOCATION": parse_redis_connection(redis_database=1),
|
|
856
|
-
"TIMEOUT": 300,
|
|
858
|
+
"TIMEOUT": int(os.getenv("NAUTOBOT_CACHES_TIMEOUT", "300")),
|
|
857
859
|
"OPTIONS": {
|
|
858
860
|
"CLIENT_CLASS": "django_redis.client.DefaultClient",
|
|
859
861
|
"PASSWORD": "",
|
nautobot/core/settings.yaml
CHANGED
|
@@ -47,7 +47,7 @@ properties:
|
|
|
47
47
|
description: >-
|
|
48
48
|
A list of valid fully-qualified domain names (FQDNs) and/or IP addresses that can be used to reach the
|
|
49
49
|
Nautobot service. (If provided as an environment variable, it should be a space-separated string, for example
|
|
50
|
-
`NAUTOBOT_ALLOWED_HOSTS="localhost 127.0.0.1 example.com"`)
|
|
50
|
+
`NAUTOBOT_ALLOWED_HOSTS="localhost 127.0.0.1 nautobot.example.com"`)
|
|
51
51
|
details: |-
|
|
52
52
|
Usually this is the same as the hostname for the Nautobot server, but can also be different; for example,
|
|
53
53
|
when using a reverse proxy serving the Nautobot website under a different FQDN than the hostname of the
|
|
@@ -70,7 +70,7 @@ properties:
|
|
|
70
70
|
|
|
71
71
|
!!! tip
|
|
72
72
|
If there is more than one hostname in this list, you may also need to set
|
|
73
|
-
[CSRF_TRUSTED_ORIGINS](
|
|
73
|
+
[CSRF_TRUSTED_ORIGINS](settings.md#csrf_trusted_origins) as well.
|
|
74
74
|
|
|
75
75
|
If you are not yet sure what the domain name and/or IP address of the Nautobot installation will be,
|
|
76
76
|
and are comfortable accepting the risks in doing so, you can set this to a wildcard (asterisk) to
|
|
@@ -83,7 +83,6 @@ properties:
|
|
|
83
83
|
!!! warning
|
|
84
84
|
It is not recommended to leave this value as `['*']` for production deployments.
|
|
85
85
|
environment_variable: "NAUTOBOT_ALLOWED_HOSTS"
|
|
86
|
-
is_required_setting: true
|
|
87
86
|
items:
|
|
88
87
|
type: "string"
|
|
89
88
|
see_also:
|
|
@@ -297,19 +296,21 @@ properties:
|
|
|
297
296
|
TIMEOUT: 300
|
|
298
297
|
description: "The `CACHES` setting is required to simplify the configuration for `django-redis`."
|
|
299
298
|
details: |-
|
|
300
|
-
The [`django-redis`](https://github.com/jazzband/django-redis) Django plugin is used to enable Redis
|
|
301
|
-
|
|
299
|
+
The [`django-redis`](https://github.com/jazzband/django-redis) Django plugin is used to enable Redis as a
|
|
300
|
+
concurrent write lock for preventing race conditions when allocating IP address objects.
|
|
301
|
+
Nautobot also uses the built-in [Django cache framework](https://docs.djangoproject.com/en/stable/topics/cache/)
|
|
302
|
+
(which also relies on the `CACHES` setting) to perform caching. This includes caching of the values of
|
|
303
|
+
[administratively configurable settings](#administratively-configurable-settings) as stored in the database.
|
|
302
304
|
|
|
303
|
-
!!!
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
(
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
is_required_setting: true
|
|
305
|
+
!!! tip
|
|
306
|
+
Rather than directly setting `CACHES["default"]["LOCATION"]`, we recommend managing this setting via
|
|
307
|
+
the various `NAUTOBOT_REDIS_*` environment variables, as those variables apply to both `CACHES` and
|
|
308
|
+
[`CELERY_BROKER_URL`](#celery_broker_url) alike, which is typically preferable.
|
|
309
|
+
|
|
310
|
+
+++ 2.3.4 "`NAUTOBOT_CACHES_TIMEOUT` environment variable"
|
|
311
|
+
Added support for the environment variable `NAUTOBOT_CACHES_TIMEOUT` for configuring the
|
|
312
|
+
`CACHES["default"]["TIMEOUT"]` setting. This environment variable also controls the cache timeout
|
|
313
|
+
for administratively configurable settings.
|
|
313
314
|
properties:
|
|
314
315
|
default:
|
|
315
316
|
properties:
|
|
@@ -322,6 +323,13 @@ properties:
|
|
|
322
323
|
type: "string"
|
|
323
324
|
LOCATION:
|
|
324
325
|
default: "redis://localhost:6379/1"
|
|
326
|
+
environment_variables:
|
|
327
|
+
- "NAUTOBOT_REDIS_SCHEME"
|
|
328
|
+
- "NAUTOBOT_REDIS_SSL"
|
|
329
|
+
- "NAUTOBOT_REDIS_USERNAME"
|
|
330
|
+
- "NAUTOBOT_REDIS_PASSWORD"
|
|
331
|
+
- "NAUTOBOT_REDIS_HOST"
|
|
332
|
+
- "NAUTOBOT_REDIS_PORT"
|
|
325
333
|
format: "uri"
|
|
326
334
|
type: "string"
|
|
327
335
|
OPTIONS:
|
|
@@ -336,10 +344,11 @@ properties:
|
|
|
336
344
|
type: "object"
|
|
337
345
|
TIMEOUT:
|
|
338
346
|
default: 300
|
|
347
|
+
environment_variable: "NAUTOBOT_CACHES_TIMEOUT"
|
|
339
348
|
type: "integer"
|
|
340
349
|
type: "object"
|
|
341
350
|
see_also:
|
|
342
|
-
"Guide to Nautobot
|
|
351
|
+
"Guide to Nautobot Redis configuration, including TLS and HA configuration": "redis.md"
|
|
343
352
|
type: "object"
|
|
344
353
|
CELERY_BEAT_HEARTBEAT_FILE:
|
|
345
354
|
default: "/tmp/nautobot_celery_beat_heartbeat"
|
|
@@ -351,8 +360,7 @@ properties:
|
|
|
351
360
|
default: {}
|
|
352
361
|
description: "A dict of additional options passed to the Celery broker transport."
|
|
353
362
|
details: >-
|
|
354
|
-
This is only required when
|
|
355
|
-
[configuring Celery to utilize Redis Sentinel](../../administration/guides/caching.md#celery-sentinel-configuration).
|
|
363
|
+
This is only required when [configuring Celery to utilize Redis Sentinel](redis.md#celery-sentinel-configuration).
|
|
356
364
|
properties:
|
|
357
365
|
master_name:
|
|
358
366
|
type: "string"
|
|
@@ -366,7 +374,18 @@ properties:
|
|
|
366
374
|
CELERY_BROKER_URL:
|
|
367
375
|
default: "redis://localhost:6379/0"
|
|
368
376
|
description: "Celery broker URL used to tell workers where queues are located."
|
|
369
|
-
|
|
377
|
+
details: >-
|
|
378
|
+
If the `NAUTOBOT_CELERY_BROKER_URL` environment variable is not set, the default for this setting will be
|
|
379
|
+
influenced by the various `NAUTOBOT_REDIS_*` environment variables instead, which is often preferable as those
|
|
380
|
+
variables also influence the [`CACHES`](#caches) configuration as well.
|
|
381
|
+
environment_variables:
|
|
382
|
+
- "NAUTOBOT_CELERY_BROKER_URL"
|
|
383
|
+
- "NAUTOBOT_REDIS_SCHEME"
|
|
384
|
+
- "NAUTOBOT_REDIS_SSL"
|
|
385
|
+
- "NAUTOBOT_REDIS_USERNAME"
|
|
386
|
+
- "NAUTOBOT_REDIS_PASSWORD"
|
|
387
|
+
- "NAUTOBOT_REDIS_HOST"
|
|
388
|
+
- "NAUTOBOT_REDIS_PORT"
|
|
370
389
|
format: "uri"
|
|
371
390
|
type: "string"
|
|
372
391
|
CELERY_BROKER_USE_SSL:
|
|
@@ -628,7 +647,6 @@ properties:
|
|
|
628
647
|
|
|
629
648
|
As of Nautobot 1.1.5 and later, if you have generated a new `nautobot_config.py` using
|
|
630
649
|
`nautobot-server init`, this line is already present in your config and no action is required.
|
|
631
|
-
is_required_setting: true
|
|
632
650
|
properties:
|
|
633
651
|
default:
|
|
634
652
|
additionalProperties: true
|
|
@@ -828,7 +846,7 @@ properties:
|
|
|
828
846
|
FORCE_SCRIPT_NAME:
|
|
829
847
|
default: null
|
|
830
848
|
description: >-
|
|
831
|
-
If not None, this will be used as the value of the SCRIPT_NAME environment variable in any HTTP request.
|
|
849
|
+
If not None, this will be used as the value of the `SCRIPT_NAME` environment variable in any HTTP request.
|
|
832
850
|
details: |-
|
|
833
851
|
This setting can be used to override the server-provided value of `SCRIPT_NAME`, which is most commonly used
|
|
834
852
|
for hosting Nautobot in a subdirectory (e.g. _example.com/nautobot/_).
|
|
@@ -1205,7 +1223,7 @@ properties:
|
|
|
1205
1223
|
!!! note
|
|
1206
1224
|
The Docker container normally attempts to run migrations on startup; however, if the database is
|
|
1207
1225
|
in a read-only state the Docker container will fail to start. Setting the environment variable
|
|
1208
|
-
[`NAUTOBOT_DOCKER_SKIP_INIT`](../
|
|
1226
|
+
[`NAUTOBOT_DOCKER_SKIP_INIT`](../guides/docker.md#nautobot_docker_skip_init) to `true`
|
|
1209
1227
|
will prevent the migrations from occurring.
|
|
1210
1228
|
|
|
1211
1229
|
!!! note
|
|
@@ -1609,7 +1627,6 @@ properties:
|
|
|
1609
1627
|
In the case of a highly available installation with multiple web servers, `SECRET_KEY` must be identical
|
|
1610
1628
|
among all servers in order to maintain a persistent user session state.
|
|
1611
1629
|
environment_variable: "NAUTOBOT_SECRET_KEY"
|
|
1612
|
-
is_required_setting: true
|
|
1613
1630
|
type: "string"
|
|
1614
1631
|
SESSION_CACHE_ALIAS:
|
|
1615
1632
|
default: "default"
|
nautobot/core/tests/runner.py
CHANGED
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
import copy
|
|
2
2
|
import hashlib
|
|
3
3
|
|
|
4
|
+
try:
|
|
5
|
+
from coverage import Coverage
|
|
6
|
+
|
|
7
|
+
has_coverage = True
|
|
8
|
+
except ImportError:
|
|
9
|
+
has_coverage = False
|
|
10
|
+
|
|
4
11
|
from django.conf import settings
|
|
5
12
|
from django.core.management import call_command
|
|
6
13
|
from django.db import connections
|
|
@@ -49,6 +56,15 @@ class NautobotTestRunner(DiscoverRunner):
|
|
|
49
56
|
|
|
50
57
|
exclude_tags = ["integration"]
|
|
51
58
|
|
|
59
|
+
@classmethod
|
|
60
|
+
def add_arguments(cls, parser):
|
|
61
|
+
super().add_arguments(parser)
|
|
62
|
+
parser.add_argument(
|
|
63
|
+
"--cache-test-fixtures",
|
|
64
|
+
action="store_true",
|
|
65
|
+
help="Save test database to a json fixture file to re-use on subsequent tests.",
|
|
66
|
+
)
|
|
67
|
+
|
|
52
68
|
def __init__(self, cache_test_fixtures=False, **kwargs):
|
|
53
69
|
self.cache_test_fixtures = cache_test_fixtures
|
|
54
70
|
|
|
@@ -64,15 +80,6 @@ class NautobotTestRunner(DiscoverRunner):
|
|
|
64
80
|
|
|
65
81
|
super().__init__(**kwargs)
|
|
66
82
|
|
|
67
|
-
@classmethod
|
|
68
|
-
def add_arguments(cls, parser):
|
|
69
|
-
super().add_arguments(parser)
|
|
70
|
-
parser.add_argument(
|
|
71
|
-
"--cache-test-fixtures",
|
|
72
|
-
action="store_true",
|
|
73
|
-
help="Save test database to a json fixture file to re-use on subsequent tests.",
|
|
74
|
-
)
|
|
75
|
-
|
|
76
83
|
def setup_test_environment(self, **kwargs):
|
|
77
84
|
super().setup_test_environment(**kwargs)
|
|
78
85
|
# Remove 'testserver' that Django "helpfully" adds automatically to ALLOWED_HOSTS, masking issues like #3065
|
|
@@ -91,6 +98,13 @@ class NautobotTestRunner(DiscoverRunner):
|
|
|
91
98
|
|
|
92
99
|
old_names = []
|
|
93
100
|
|
|
101
|
+
# Nautobot specific - disable coverage measurement to improve performance of (slow) database setup
|
|
102
|
+
cov = None
|
|
103
|
+
if has_coverage:
|
|
104
|
+
cov = Coverage.current()
|
|
105
|
+
if cov is not None:
|
|
106
|
+
cov.stop()
|
|
107
|
+
|
|
94
108
|
for db_name, aliases in test_databases.values():
|
|
95
109
|
first_alias = None
|
|
96
110
|
for alias in aliases:
|
|
@@ -150,6 +164,10 @@ class NautobotTestRunner(DiscoverRunner):
|
|
|
150
164
|
for alias in connections:
|
|
151
165
|
connections[alias].force_debug_cursor = True
|
|
152
166
|
|
|
167
|
+
# Nautobot specific - resume test coverage measurement
|
|
168
|
+
if cov is not None:
|
|
169
|
+
cov.start()
|
|
170
|
+
|
|
153
171
|
return old_names
|
|
154
172
|
|
|
155
173
|
def teardown_databases(self, old_config, **kwargs):
|
|
@@ -35,10 +35,13 @@ SETTINGS_DOCUMENTATION_SCHEMA = {
|
|
|
35
35
|
"environment_variable": {
|
|
36
36
|
"type": "string",
|
|
37
37
|
},
|
|
38
|
-
"
|
|
39
|
-
"type": "
|
|
38
|
+
"environment_variables": {
|
|
39
|
+
"type": "array",
|
|
40
|
+
"items": {
|
|
41
|
+
"type": "string",
|
|
42
|
+
},
|
|
40
43
|
},
|
|
41
|
-
"
|
|
44
|
+
"is_constance_config": {
|
|
42
45
|
"type": "boolean",
|
|
43
46
|
},
|
|
44
47
|
"see_also": {
|
|
@@ -122,6 +125,7 @@ class SettingsJSONSchemaTestCase(TestCase):
|
|
|
122
125
|
"CONSTANCE_BACKEND",
|
|
123
126
|
"CONSTANCE_CONFIG",
|
|
124
127
|
"CONSTANCE_CONFIG_FIELDSETS",
|
|
128
|
+
"CONSTANCE_DATABASE_CACHE_AUTOFILL_TIMEOUT",
|
|
125
129
|
"CONSTANCE_DATABASE_CACHE_BACKEND",
|
|
126
130
|
"CONSTANCE_DATABASE_PREFIX",
|
|
127
131
|
"CSRF_FAILURE_VIEW",
|
|
@@ -234,6 +234,19 @@ class GetFooForModelTest(TestCase):
|
|
|
234
234
|
self.assertEqual(lookup.get_model_from_name("dcim.device"), dcim_models.Device)
|
|
235
235
|
self.assertEqual(lookup.get_model_from_name("dcim.location"), dcim_models.Location)
|
|
236
236
|
|
|
237
|
+
def test_get_model_for_view_name(self):
|
|
238
|
+
"""
|
|
239
|
+
Test the util function `get_model_for_view_name` returns the appropriate Model, if the colon separated view name provided.
|
|
240
|
+
"""
|
|
241
|
+
with self.subTest("Test core view."):
|
|
242
|
+
self.assertEqual(lookup.get_model_for_view_name("dcim:device_list"), dcim_models.Device)
|
|
243
|
+
with self.subTest("Test app view."):
|
|
244
|
+
self.assertEqual(lookup.get_model_for_view_name("plugins:example_app:examplemodel_list"), ExampleModel)
|
|
245
|
+
with self.subTest("Test unexpected view."):
|
|
246
|
+
with self.assertRaises(ValueError) as err:
|
|
247
|
+
lookup.get_model_for_view_name("unknown:plugins:example_app:examplemodel_list")
|
|
248
|
+
self.assertEqual(str(err.exception), "Unexpected View Name: unknown:plugins:example_app:examplemodel_list")
|
|
249
|
+
|
|
237
250
|
|
|
238
251
|
class IsTaggableTest(TestCase):
|
|
239
252
|
def test_is_taggable_true(self):
|
nautobot/core/utils/lookup.py
CHANGED
|
@@ -213,7 +213,13 @@ def get_model_for_view_name(view_name):
|
|
|
213
213
|
Return the model class associated with the given view_name e.g. "circuits:circuit_detail", "dcim:device_list" and etc.
|
|
214
214
|
If the app_label or model_name contained by the given view_name is invalid, this will return `None`.
|
|
215
215
|
"""
|
|
216
|
-
|
|
216
|
+
split_view_name = view_name.split(":")
|
|
217
|
+
if len(split_view_name) == 2:
|
|
218
|
+
app_label, model_name = split_view_name # dcim, device_list
|
|
219
|
+
elif len(split_view_name) == 3:
|
|
220
|
+
_, app_label, model_name = split_view_name # plugins, app_name, model_list
|
|
221
|
+
else:
|
|
222
|
+
raise ValueError(f"Unexpected View Name: {view_name}")
|
|
217
223
|
model_name = model_name.split("_")[0] # device
|
|
218
224
|
|
|
219
225
|
try:
|
nautobot/dcim/tables/power.py
CHANGED
|
@@ -29,7 +29,7 @@ class PowerPanelTable(BaseTable):
|
|
|
29
29
|
location = tables.Column(linkify=True)
|
|
30
30
|
power_feed_count = LinkedCountColumn(
|
|
31
31
|
viewname="dcim:powerfeed_list",
|
|
32
|
-
url_params={"
|
|
32
|
+
url_params={"power_panel": "pk"},
|
|
33
33
|
verbose_name="Feeds",
|
|
34
34
|
)
|
|
35
35
|
tags = TagColumn(url_name="dcim:powerpanel_list")
|
|
@@ -3349,7 +3349,7 @@ class CableTestCase(FilterTestCases.FilterTestCase):
|
|
|
3349
3349
|
|
|
3350
3350
|
def test_device(self):
|
|
3351
3351
|
"""Test that the device filter returns all cables for a device and its modules."""
|
|
3352
|
-
interfaces = Interface.objects.filter(cable__isnull=True)[:3]
|
|
3352
|
+
interfaces = list(Interface.objects.filter(cable__isnull=True)[:3])
|
|
3353
3353
|
manufacturer = Manufacturer.objects.first()
|
|
3354
3354
|
device_type = DeviceType.objects.create(
|
|
3355
3355
|
manufacturer=manufacturer, model="Test Device Filter for Cable Device Type"
|
|
@@ -175,11 +175,12 @@ def web_request_context(
|
|
|
175
175
|
:param user: User object
|
|
176
176
|
:param context_detail: Optional extra details about the transaction (ex: the plugin name that initiated the change)
|
|
177
177
|
:param change_id: Optional uuid object to uniquely identify the transaction. One will be generated if not supplied
|
|
178
|
-
:param context: Optional string value of the generated change log entries' "change_context" field
|
|
179
|
-
|
|
178
|
+
:param context: Optional string value of the generated change log entries' "change_context" field.
|
|
179
|
+
Defaults to `ObjectChangeEventContextChoices.CONTEXT_ORM`.
|
|
180
|
+
Valid choices are in `nautobot.extras.choices.ObjectChangeEventContextChoices`.
|
|
180
181
|
:param request: Optional web request instance, one will be generated if not supplied
|
|
181
182
|
"""
|
|
182
|
-
from nautobot.extras.jobs import enqueue_job_hooks # prevent circular import
|
|
183
|
+
from nautobot.extras.jobs import enqueue_job_hooks, get_jobs # prevent circular import
|
|
183
184
|
|
|
184
185
|
valid_contexts = {
|
|
185
186
|
ObjectChangeEventContextChoices.CONTEXT_JOB: JobChangeContext,
|
|
@@ -202,9 +203,15 @@ def web_request_context(
|
|
|
202
203
|
with change_logging(change_context):
|
|
203
204
|
yield request
|
|
204
205
|
finally:
|
|
206
|
+
jobs_refreshed = False
|
|
205
207
|
# enqueue jobhooks and webhooks, use change_context.change_id in case change_id was not supplied
|
|
206
208
|
for object_change in ObjectChange.objects.filter(request_id=change_context.change_id).iterator():
|
|
207
|
-
|
|
209
|
+
if context != ObjectChangeEventContextChoices.CONTEXT_JOB_HOOK:
|
|
210
|
+
# Make sure JobHooks are up to date (once) before calling them
|
|
211
|
+
if not jobs_refreshed:
|
|
212
|
+
get_jobs(reload=True)
|
|
213
|
+
jobs_refreshed = True
|
|
214
|
+
enqueue_job_hooks(object_change)
|
|
208
215
|
enqueue_webhooks(object_change)
|
|
209
216
|
|
|
210
217
|
|
nautobot/extras/jobs.py
CHANGED
|
@@ -1168,7 +1168,6 @@ def enqueue_job_hooks(object_change):
|
|
|
1168
1168
|
job_hooks = JobHook.objects.filter(content_types=content_type, enabled=True, **{action_flag: True})
|
|
1169
1169
|
|
|
1170
1170
|
# Enqueue the jobs related to the job_hooks
|
|
1171
|
-
get_jobs(reload=True)
|
|
1172
1171
|
for job_hook in job_hooks:
|
|
1173
1172
|
job_model = job_hook.job
|
|
1174
1173
|
if not job_model.installed or not job_model.enabled:
|
nautobot/extras/models/groups.py
CHANGED
|
@@ -251,7 +251,10 @@ class DynamicGroup(PrimaryModel):
|
|
|
251
251
|
# Skip filter fields that have methods defined. They are not reversible.
|
|
252
252
|
if skip_method_filters and filterset_field.method is not None:
|
|
253
253
|
# Don't skip method fields that also have a "generate_query_" method
|
|
254
|
-
|
|
254
|
+
query_attr = (
|
|
255
|
+
filterset_field.method.__name__ if callable(filterset_field.method) else filterset_field.method
|
|
256
|
+
)
|
|
257
|
+
if hasattr(filterset, f"generate_query_{query_attr}"):
|
|
255
258
|
logger.debug(
|
|
256
259
|
"Keeping %s for filterform: has a `generate_query_` filter method", filterset_field_name
|
|
257
260
|
)
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
from unittest import mock
|
|
2
|
+
|
|
1
3
|
from django.contrib.auth import get_user_model
|
|
2
4
|
from django.contrib.contenttypes.models import ContentType
|
|
3
5
|
from django.test import TestCase
|
|
@@ -72,7 +74,9 @@ class WebRequestContextTestCase(TestCase):
|
|
|
72
74
|
self.assertEqual(oc_list[0].changed_object, location)
|
|
73
75
|
self.assertEqual(oc_list[0].action, ObjectChangeActionChoices.ACTION_CREATE)
|
|
74
76
|
|
|
75
|
-
|
|
77
|
+
@mock.patch("nautobot.extras.jobs.enqueue_job_hooks")
|
|
78
|
+
@mock.patch("nautobot.extras.context_managers.enqueue_webhooks")
|
|
79
|
+
def test_create_then_delete(self, mock_enqueue_webhooks, mock_enqueue_job_hooks):
|
|
76
80
|
"""Test that a create followed by a delete is logged as two changes"""
|
|
77
81
|
location_type = LocationType.objects.get(name="Campus")
|
|
78
82
|
location_status = Status.objects.get_for_model(Location).first()
|
|
@@ -88,6 +92,8 @@ class WebRequestContextTestCase(TestCase):
|
|
|
88
92
|
self.assertEqual(len(oc_list), 2)
|
|
89
93
|
self.assertEqual(oc_list[0].action, ObjectChangeActionChoices.ACTION_DELETE)
|
|
90
94
|
self.assertEqual(oc_list[1].action, ObjectChangeActionChoices.ACTION_CREATE)
|
|
95
|
+
mock_enqueue_job_hooks.assert_has_calls([mock.call(oc_list[0]), mock.call(oc_list[1])])
|
|
96
|
+
mock_enqueue_webhooks.assert_has_calls([mock.call(oc_list[0]), mock.call(oc_list[1])])
|
|
91
97
|
|
|
92
98
|
def test_update_then_delete(self):
|
|
93
99
|
"""Test that an update followed by a delete is logged as a single delete"""
|
|
@@ -179,21 +185,30 @@ class WebRequestContextTestCase(TestCase):
|
|
|
179
185
|
with self.subTest():
|
|
180
186
|
self.assertEqual(oc_list[0].change_context_detail, "test_change_log_context")
|
|
181
187
|
|
|
182
|
-
|
|
188
|
+
@mock.patch("nautobot.extras.webhooks.process_webhook.apply_async")
|
|
189
|
+
def test_change_webhook_enqueued(self, mock_apply_async):
|
|
183
190
|
"""Test that the webhook resides on the queue"""
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
191
|
+
with web_request_context(self.user):
|
|
192
|
+
location = Location(
|
|
193
|
+
name="Test Location 2",
|
|
194
|
+
location_type=LocationType.objects.get(name="Campus"),
|
|
195
|
+
status=Status.objects.get_for_model(Location).first(),
|
|
196
|
+
)
|
|
197
|
+
location.save()
|
|
190
198
|
|
|
191
199
|
# Verify that a job was queued for the object creation webhook
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
200
|
+
oc_list = get_changes_for_model(location)
|
|
201
|
+
mock_apply_async.assert_called_once()
|
|
202
|
+
call_args = mock_apply_async.call_args.kwargs["args"]
|
|
203
|
+
self.assertEqual(8, len(call_args), call_args)
|
|
204
|
+
self.assertEqual(call_args[0], Webhook.objects.get(type_create=True).pk)
|
|
205
|
+
self.assertEqual(call_args[1], oc_list[0].object_data_v2)
|
|
206
|
+
self.assertEqual(call_args[2], "location")
|
|
207
|
+
self.assertEqual(call_args[3], "create")
|
|
208
|
+
self.assertIsInstance(call_args[4], str) # str(timezone.now())
|
|
209
|
+
self.assertEqual(call_args[5], self.user.username)
|
|
210
|
+
self.assertEqual(call_args[6], oc_list[0].request_id)
|
|
211
|
+
self.assertEqual(call_args[7], oc_list[0].get_snapshots())
|
|
197
212
|
|
|
198
213
|
|
|
199
214
|
class WebRequestContextTransactionTestCase(TransactionTestCase):
|
|
@@ -282,7 +297,8 @@ class BulkEditDeleteChangeLogging(TestCase):
|
|
|
282
297
|
self.assertIsNone(snapshots["differences"]["removed"])
|
|
283
298
|
self.assertEqual(snapshots["differences"]["added"]["description"], "changed")
|
|
284
299
|
|
|
285
|
-
|
|
300
|
+
@mock.patch("nautobot.extras.jobs.import_jobs")
|
|
301
|
+
def test_bulk_edit(self, mock_import_jobs):
|
|
286
302
|
"""Test that edits to multiple objects are correctly logged"""
|
|
287
303
|
location_type = LocationType.objects.get(name="Campus")
|
|
288
304
|
location_status = Status.objects.get_for_model(Location).first()
|
|
@@ -309,6 +325,9 @@ class BulkEditDeleteChangeLogging(TestCase):
|
|
|
309
325
|
self.assertIsNone(snapshots["differences"]["removed"])
|
|
310
326
|
self.assertEqual(snapshots["differences"]["added"]["description"], "changed")
|
|
311
327
|
|
|
328
|
+
# Check for regression of https://github.com/nautobot/nautobot/issues/6203
|
|
329
|
+
mock_import_jobs.assert_called_once()
|
|
330
|
+
|
|
312
331
|
def test_bulk_edit_device_type_software_image_file(self):
|
|
313
332
|
"""Test that bulk edits to null does not cause integrity error"""
|
|
314
333
|
manufacturer = Manufacturer.objects.create(name="Test")
|
|
@@ -494,6 +494,17 @@ class DynamicGroupModelTest(DynamicGroupTestBase): # TODO: BaseModelTestCase mi
|
|
|
494
494
|
self.assertIsInstance(fields["cluster"], MultiMatchModelMultipleChoiceField)
|
|
495
495
|
self.assertIsInstance(fields["cluster"].widget, APISelectMultiple)
|
|
496
496
|
|
|
497
|
+
def test_map_filter_fields_with_custom_filter_method(self):
|
|
498
|
+
"""
|
|
499
|
+
Test that extension_filters with custom methods can be concatenated into `generate_query_{filter_method}`
|
|
500
|
+
and _map_filter_fields method doesn't brake on string concatenation.
|
|
501
|
+
This is a regression test for issue #6184.
|
|
502
|
+
"""
|
|
503
|
+
tenant_content_type = ContentType.objects.get_for_model(Tenant)
|
|
504
|
+
# using Tenant as example app has a custom filter with a custom method.
|
|
505
|
+
group = DynamicGroup(name="tenant", content_type=tenant_content_type)
|
|
506
|
+
self.assertIsInstance(group._map_filter_fields, dict)
|
|
507
|
+
|
|
497
508
|
def test_map_filter_fields_skip_missing(self):
|
|
498
509
|
"""
|
|
499
510
|
Test that missing fields are skipped in `DynamicGroup._map_filter_fields`
|
|
@@ -1091,12 +1091,15 @@ class JobModelTest(ModelTestCases.BaseModelTestCase):
|
|
|
1091
1091
|
cls.app_job = JobModel.objects.get(job_class_name="ExampleJob")
|
|
1092
1092
|
|
|
1093
1093
|
def test_job_class(self):
|
|
1094
|
+
self.assertIsNotNone(self.local_job.job_class)
|
|
1094
1095
|
self.assertEqual(self.local_job.job_class.description, "Validate job import")
|
|
1095
1096
|
|
|
1097
|
+
self.assertIsNotNone(self.app_job.job_class)
|
|
1096
1098
|
self.assertEqual(self.app_job.job_class, ExampleJob)
|
|
1097
1099
|
|
|
1098
1100
|
def test_class_path(self):
|
|
1099
1101
|
self.assertEqual(self.local_job.class_path, "pass.TestPass")
|
|
1102
|
+
self.assertIsNotNone(self.local_job.job_class)
|
|
1100
1103
|
self.assertEqual(self.local_job.class_path, self.local_job.job_class.class_path)
|
|
1101
1104
|
|
|
1102
1105
|
self.assertEqual(self.app_job.class_path, "example_app.jobs.ExampleJob")
|
|
@@ -1118,6 +1121,7 @@ class JobModelTest(ModelTestCases.BaseModelTestCase):
|
|
|
1118
1121
|
self.assertTrue(job_model.enabled)
|
|
1119
1122
|
else:
|
|
1120
1123
|
self.assertFalse(job_model.enabled)
|
|
1124
|
+
self.assertIsNotNone(job_model.job_class)
|
|
1121
1125
|
for field_name in JOB_OVERRIDABLE_FIELDS:
|
|
1122
1126
|
if field_name == "name" and "duplicate_name" in job_model.job_class.__module__:
|
|
1123
1127
|
pass # name field for test_duplicate_name jobs tested in test_duplicate_job_name below
|
|
@@ -1173,6 +1177,7 @@ class JobModelTest(ModelTestCases.BaseModelTestCase):
|
|
|
1173
1177
|
setattr(self.job_containing_sensitive_variables, f"{field_name}_override", False)
|
|
1174
1178
|
self.job_containing_sensitive_variables.validated_save()
|
|
1175
1179
|
self.job_containing_sensitive_variables.refresh_from_db()
|
|
1180
|
+
self.assertIsNotNone(self.job_containing_sensitive_variables.job_class)
|
|
1176
1181
|
for field_name in overridden_attrs:
|
|
1177
1182
|
self.assertEqual(
|
|
1178
1183
|
getattr(self.job_containing_sensitive_variables, field_name),
|
|
@@ -3008,6 +3008,7 @@ class JobCustomTemplateTestCase(TestCase):
|
|
|
3008
3008
|
cls.run_url = reverse("extras:job_run", kwargs={"pk": cls.example_job.pk})
|
|
3009
3009
|
|
|
3010
3010
|
def test_rendering_custom_template(self):
|
|
3011
|
+
self.assertIsNotNone(self.example_job.job_class)
|
|
3011
3012
|
obj_perm = ObjectPermission(name="Test permission", actions=["view", "run"])
|
|
3012
3013
|
obj_perm.save()
|
|
3013
3014
|
obj_perm.users.add(self.user)
|
nautobot/ipam/models.py
CHANGED
|
@@ -535,6 +535,10 @@ class Prefix(PrimaryModel):
|
|
|
535
535
|
def __str__(self):
|
|
536
536
|
return str(self.prefix)
|
|
537
537
|
|
|
538
|
+
@property
|
|
539
|
+
def display(self):
|
|
540
|
+
return f"{self.prefix}: {self.namespace}"
|
|
541
|
+
|
|
538
542
|
def _deconstruct_prefix(self, prefix):
|
|
539
543
|
if prefix:
|
|
540
544
|
if isinstance(prefix, str):
|
nautobot/ipam/tests/test_api.py
CHANGED
|
@@ -443,6 +443,17 @@ class PrefixTest(APIViewTestCases.APIViewTestCase):
|
|
|
443
443
|
for i, p in enumerate(response.data):
|
|
444
444
|
self.assertEqual(p["prefix"], str(available_prefixes[i]))
|
|
445
445
|
|
|
446
|
+
def test_prefix_display_value(self):
|
|
447
|
+
"""
|
|
448
|
+
Test that the `display` field is correctly populated.
|
|
449
|
+
"""
|
|
450
|
+
url = reverse("ipam-api:prefix-list")
|
|
451
|
+
self.add_permissions("ipam.view_prefix")
|
|
452
|
+
|
|
453
|
+
response = self.client.get(f"{url}?depth=1", **self.header)
|
|
454
|
+
for p in response.data["results"]:
|
|
455
|
+
self.assertEqual(p["display"], f'{p["prefix"]}: {p["namespace"]["name"]}')
|
|
456
|
+
|
|
446
457
|
def test_create_single_available_prefix(self):
|
|
447
458
|
"""
|
|
448
459
|
Test retrieval of the first available prefix within a parent prefix.
|