nautobot 2.2.3__py3-none-any.whl → 2.2.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.
Potentially problematic release.
This version of nautobot might be problematic. Click here for more details.
- nautobot/circuits/forms.py +15 -0
- nautobot/circuits/navigation.py +9 -1
- nautobot/circuits/views.py +2 -0
- nautobot/core/filters.py +11 -0
- nautobot/core/settings.py +6 -4
- nautobot/core/settings.yaml +54 -19
- nautobot/core/templates/admin/base.html +2 -2
- nautobot/core/templates/base_django.html +2 -2
- nautobot/core/templates/buttons/export.html +47 -47
- nautobot/core/templates/inc/javascript.html +3 -0
- nautobot/core/templates/inc/media.html +3 -0
- nautobot/core/templates/login.html +2 -2
- nautobot/core/templates/nautobot_config.py.j2 +2 -0
- nautobot/core/testing/filters.py +24 -1
- nautobot/core/testing/views.py +13 -1
- nautobot/core/tests/test_jobs.py +79 -2
- nautobot/core/tests/test_views.py +33 -0
- nautobot/core/views/mixins.py +4 -0
- nautobot/core/views/utils.py +18 -1
- nautobot/dcim/filters/__init__.py +1 -1
- nautobot/dcim/forms.py +23 -4
- nautobot/dcim/tables/devicetypes.py +15 -4
- nautobot/dcim/tests/test_views.py +323 -55
- nautobot/dcim/views.py +26 -20
- nautobot/extras/api/serializers.py +17 -6
- nautobot/extras/api/views.py +2 -2
- nautobot/extras/context_managers.py +3 -0
- nautobot/extras/filters/__init__.py +15 -1
- nautobot/extras/forms/forms.py +33 -0
- nautobot/extras/forms/mixins.py +0 -6
- nautobot/extras/signals.py +6 -1
- nautobot/extras/tests/test_api.py +24 -2
- nautobot/extras/tests/test_context_managers.py +51 -1
- nautobot/extras/tests/test_filters.py +69 -0
- nautobot/extras/tests/test_forms.py +0 -3
- nautobot/extras/tests/test_views.py +48 -4
- nautobot/extras/utils.py +2 -1
- nautobot/extras/views.py +47 -31
- nautobot/ipam/forms.py +18 -0
- nautobot/ipam/tests/test_views.py +9 -2
- nautobot/ipam/views.py +17 -6
- nautobot/project-static/docs/404.html +107 -51
- nautobot/project-static/docs/apps/index.html +107 -51
- nautobot/project-static/docs/apps/nautobot-apps.html +107 -51
- nautobot/project-static/docs/assets/_mkdocstrings.css +6 -1
- nautobot/project-static/docs/assets/extra.css +7 -0
- nautobot/project-static/docs/assets/javascripts/bundle.ebd0bdb7.min.js +29 -0
- nautobot/project-static/docs/assets/javascripts/bundle.ebd0bdb7.min.js.map +7 -0
- nautobot/project-static/docs/assets/stylesheets/main.6543a935.min.css +1 -0
- nautobot/project-static/docs/assets/stylesheets/main.6543a935.min.css.map +1 -0
- nautobot/project-static/docs/code-reference/nautobot/apps/__init__.html +107 -51
- nautobot/project-static/docs/code-reference/nautobot/apps/admin.html +107 -51
- nautobot/project-static/docs/code-reference/nautobot/apps/api.html +107 -51
- nautobot/project-static/docs/code-reference/nautobot/apps/change_logging.html +107 -51
- nautobot/project-static/docs/code-reference/nautobot/apps/choices.html +107 -51
- nautobot/project-static/docs/code-reference/nautobot/apps/config.html +107 -51
- nautobot/project-static/docs/code-reference/nautobot/apps/constants.html +107 -51
- nautobot/project-static/docs/code-reference/nautobot/apps/datasources.html +107 -51
- nautobot/project-static/docs/code-reference/nautobot/apps/exceptions.html +107 -51
- nautobot/project-static/docs/code-reference/nautobot/apps/factory.html +107 -51
- nautobot/project-static/docs/code-reference/nautobot/apps/filters.html +107 -51
- nautobot/project-static/docs/code-reference/nautobot/apps/forms.html +107 -51
- nautobot/project-static/docs/code-reference/nautobot/apps/graphql.html +107 -51
- nautobot/project-static/docs/code-reference/nautobot/apps/jobs.html +107 -51
- nautobot/project-static/docs/code-reference/nautobot/apps/models.html +107 -51
- nautobot/project-static/docs/code-reference/nautobot/apps/querysets.html +107 -51
- nautobot/project-static/docs/code-reference/nautobot/apps/secrets.html +107 -51
- nautobot/project-static/docs/code-reference/nautobot/apps/tables.html +107 -51
- nautobot/project-static/docs/code-reference/nautobot/apps/testing.html +107 -51
- nautobot/project-static/docs/code-reference/nautobot/apps/ui.html +107 -51
- nautobot/project-static/docs/code-reference/nautobot/apps/urls.html +107 -51
- nautobot/project-static/docs/code-reference/nautobot/apps/utils.html +107 -51
- nautobot/project-static/docs/code-reference/nautobot/apps/views.html +107 -51
- nautobot/project-static/docs/development/apps/api/configuration-view.html +110 -54
- nautobot/project-static/docs/development/apps/api/database-backend-config.html +110 -54
- nautobot/project-static/docs/development/apps/api/models/django-admin.html +107 -51
- nautobot/project-static/docs/development/apps/api/models/global-search.html +110 -54
- nautobot/project-static/docs/development/apps/api/models/graphql.html +113 -57
- nautobot/project-static/docs/development/apps/api/models/index.html +107 -51
- nautobot/project-static/docs/development/apps/api/nautobot-app-config.html +113 -57
- nautobot/project-static/docs/development/apps/api/platform-features/custom-validators.html +107 -51
- nautobot/project-static/docs/development/apps/api/platform-features/filter-extensions.html +111 -55
- nautobot/project-static/docs/development/apps/api/platform-features/git-repository-content.html +107 -51
- nautobot/project-static/docs/development/apps/api/platform-features/index.html +107 -51
- nautobot/project-static/docs/development/apps/api/platform-features/jinja2-filters.html +110 -54
- nautobot/project-static/docs/development/apps/api/platform-features/jobs.html +110 -54
- nautobot/project-static/docs/development/apps/api/platform-features/populating-extensibility-features.html +110 -54
- nautobot/project-static/docs/development/apps/api/platform-features/secrets-providers.html +110 -54
- nautobot/project-static/docs/development/apps/api/platform-features/uniquely-identify-objects.html +107 -51
- nautobot/project-static/docs/development/apps/api/prometheus.html +110 -54
- nautobot/project-static/docs/development/apps/api/setup.html +107 -51
- nautobot/project-static/docs/development/apps/api/testing.html +113 -57
- nautobot/project-static/docs/development/apps/api/ui-extensions/banners.html +110 -54
- nautobot/project-static/docs/development/apps/api/ui-extensions/home-page.html +110 -54
- nautobot/project-static/docs/development/apps/api/ui-extensions/index.html +107 -51
- nautobot/project-static/docs/development/apps/api/ui-extensions/navigation.html +107 -51
- nautobot/project-static/docs/development/apps/api/ui-extensions/object-views.html +113 -57
- nautobot/project-static/docs/development/apps/api/views/base-template.html +107 -51
- nautobot/project-static/docs/development/apps/api/views/core-view-overrides.html +110 -54
- nautobot/project-static/docs/development/apps/api/views/django-generic-views.html +107 -51
- nautobot/project-static/docs/development/apps/api/views/help-documentation.html +110 -54
- nautobot/project-static/docs/development/apps/api/views/index.html +107 -51
- nautobot/project-static/docs/development/apps/api/views/nautobot-generic-views.html +113 -57
- nautobot/project-static/docs/development/apps/api/views/nautobotuiviewset.html +122 -66
- nautobot/project-static/docs/development/apps/api/views/nautobotuiviewsetrouter.html +110 -54
- nautobot/project-static/docs/development/apps/api/views/notes.html +110 -54
- nautobot/project-static/docs/development/apps/api/views/rest-api.html +107 -51
- nautobot/project-static/docs/development/apps/api/views/urls.html +107 -51
- nautobot/project-static/docs/development/apps/index.html +128 -72
- nautobot/project-static/docs/development/apps/migration/code-updates.html +107 -51
- nautobot/project-static/docs/development/apps/migration/dependency-updates.html +107 -51
- nautobot/project-static/docs/development/apps/migration/from-v1.html +109 -53
- nautobot/project-static/docs/development/apps/migration/model-updates/dcim.html +107 -51
- nautobot/project-static/docs/development/apps/migration/model-updates/extras.html +107 -51
- nautobot/project-static/docs/development/apps/migration/model-updates/global.html +107 -51
- nautobot/project-static/docs/development/apps/migration/model-updates/ipam.html +107 -51
- nautobot/project-static/docs/development/apps/porting-from-netbox.html +110 -54
- nautobot/project-static/docs/development/core/application-registry.html +120 -64
- nautobot/project-static/docs/development/core/best-practices.html +122 -66
- nautobot/project-static/docs/development/core/bootstrap-ui.html +107 -51
- nautobot/project-static/docs/development/core/caching.html +107 -51
- nautobot/project-static/docs/development/core/controllers.html +107 -51
- nautobot/project-static/docs/development/core/docker-compose-advanced-use-cases.html +113 -57
- nautobot/project-static/docs/development/core/generic-views.html +110 -54
- nautobot/project-static/docs/development/core/getting-started.html +137 -81
- nautobot/project-static/docs/development/core/homepage.html +110 -54
- nautobot/project-static/docs/development/core/index.html +107 -51
- nautobot/project-static/docs/development/core/model-checklist.html +107 -51
- nautobot/project-static/docs/development/core/model-features.html +107 -51
- nautobot/project-static/docs/development/core/natural-keys.html +110 -54
- nautobot/project-static/docs/development/core/navigation-menu.html +107 -51
- nautobot/project-static/docs/development/core/release-checklist.html +107 -51
- nautobot/project-static/docs/development/core/role-internals.html +107 -51
- nautobot/project-static/docs/development/core/settings.html +107 -51
- nautobot/project-static/docs/development/core/style-guide.html +110 -54
- nautobot/project-static/docs/development/core/templates.html +113 -57
- nautobot/project-static/docs/development/core/testing.html +126 -70
- nautobot/project-static/docs/development/core/user-preferences.html +107 -51
- nautobot/project-static/docs/development/index.html +107 -51
- nautobot/project-static/docs/development/jobs/index.html +173 -117
- nautobot/project-static/docs/development/jobs/migration/from-v1.html +110 -54
- nautobot/project-static/docs/docker/index.html +3 -3
- nautobot/project-static/docs/index.html +125 -69
- nautobot/project-static/docs/installation/selinux-troubleshooting.html +3 -3
- nautobot/project-static/docs/release-notes/index.html +107 -51
- nautobot/project-static/docs/release-notes/version-1.0.html +108 -52
- nautobot/project-static/docs/release-notes/version-1.1.html +107 -51
- nautobot/project-static/docs/release-notes/version-1.2.html +109 -53
- nautobot/project-static/docs/release-notes/version-1.3.html +108 -52
- nautobot/project-static/docs/release-notes/version-1.4.html +109 -53
- nautobot/project-static/docs/release-notes/version-1.5.html +118 -62
- nautobot/project-static/docs/release-notes/version-1.6.html +721 -285
- nautobot/project-static/docs/release-notes/version-2.0.html +113 -57
- nautobot/project-static/docs/release-notes/version-2.1.html +107 -51
- nautobot/project-static/docs/release-notes/version-2.2.html +503 -120
- nautobot/project-static/docs/requirements.txt +4 -4
- nautobot/project-static/docs/search/search_index.json +1 -1
- nautobot/project-static/docs/sitemap.xml +262 -262
- nautobot/project-static/docs/sitemap.xml.gz +0 -0
- nautobot/project-static/docs/user-guide/administration/configuration/authentication/ldap.html +107 -51
- nautobot/project-static/docs/user-guide/administration/configuration/authentication/remote.html +107 -51
- nautobot/project-static/docs/user-guide/administration/configuration/authentication/sso.html +109 -53
- nautobot/project-static/docs/user-guide/administration/configuration/index.html +108 -52
- nautobot/project-static/docs/user-guide/administration/configuration/optional-settings.html +254 -167
- nautobot/project-static/docs/user-guide/administration/configuration/required-settings.html +113 -57
- nautobot/project-static/docs/user-guide/administration/configuration/time-zones.html +107 -51
- nautobot/project-static/docs/user-guide/administration/guides/caching.html +113 -57
- nautobot/project-static/docs/user-guide/administration/guides/celery-queues.html +107 -51
- nautobot/project-static/docs/user-guide/administration/guides/healthcheck.html +107 -51
- nautobot/project-static/docs/user-guide/administration/guides/permissions.html +107 -51
- nautobot/project-static/docs/user-guide/administration/guides/prometheus-metrics.html +113 -57
- nautobot/project-static/docs/user-guide/administration/guides/replicating-nautobot.html +108 -52
- nautobot/project-static/docs/user-guide/administration/guides/request-profiling.html +107 -51
- nautobot/project-static/docs/user-guide/administration/guides/s3-django-storage.html +107 -51
- nautobot/project-static/docs/user-guide/administration/installation/app-install.html +171 -112
- nautobot/project-static/docs/user-guide/administration/installation/docker.html +13 -8626
- nautobot/project-static/docs/user-guide/administration/installation/external-authentication.html +117 -61
- nautobot/project-static/docs/user-guide/administration/installation/health-checks.html +13 -8614
- nautobot/project-static/docs/user-guide/administration/installation/http-server.html +252 -165
- nautobot/project-static/docs/user-guide/administration/installation/index.html +165 -192
- nautobot/project-static/docs/user-guide/administration/installation/install_system.html +411 -691
- nautobot/project-static/docs/user-guide/administration/installation/nautobot.html +249 -230
- nautobot/project-static/docs/user-guide/administration/installation/selinux-troubleshooting.html +13 -8118
- nautobot/project-static/docs/user-guide/administration/installation/services.html +351 -241
- nautobot/project-static/docs/user-guide/administration/installation-extras/docker.html +8684 -0
- nautobot/project-static/docs/user-guide/administration/installation-extras/health-checks.html +8672 -0
- nautobot/project-static/docs/user-guide/administration/installation-extras/selinux-troubleshooting.html +8176 -0
- nautobot/project-static/docs/user-guide/administration/migration/migrating-from-netbox.html +110 -54
- nautobot/project-static/docs/user-guide/administration/migration/migrating-from-postgresql.html +110 -54
- nautobot/project-static/docs/user-guide/administration/tools/nautobot-server.html +155 -99
- nautobot/project-static/docs/user-guide/administration/tools/nautobot-shell.html +107 -51
- nautobot/project-static/docs/user-guide/administration/upgrading/database-backup.html +109 -53
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/after-you-upgrade.html +107 -51
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/before-you-upgrade.html +107 -51
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/for-developers.html +108 -52
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/index.html +107 -51
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/whats-changed.html +107 -51
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/region-and-site-data-migration-guide.html +107 -70
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/upgrading-from-nautobot-v1.html +115 -59
- nautobot/project-static/docs/user-guide/administration/upgrading/upgrading.html +113 -57
- nautobot/project-static/docs/user-guide/core-data-model/circuits/circuit.html +107 -51
- nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittermination.html +107 -51
- nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittype.html +107 -51
- nautobot/project-static/docs/user-guide/core-data-model/circuits/provider.html +107 -51
- nautobot/project-static/docs/user-guide/core-data-model/circuits/providernetwork.html +110 -54
- nautobot/project-static/docs/user-guide/core-data-model/dcim/cable.html +107 -51
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleport.html +110 -54
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleporttemplate.html +110 -54
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverport.html +110 -54
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverporttemplate.html +110 -54
- nautobot/project-static/docs/user-guide/core-data-model/dcim/controller.html +107 -51
- nautobot/project-static/docs/user-guide/core-data-model/dcim/controllermanageddevicegroup.html +107 -51
- nautobot/project-static/docs/user-guide/core-data-model/dcim/device.html +115 -59
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebay.html +110 -54
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebaytemplate.html +110 -54
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicefamily.html +110 -54
- nautobot/project-static/docs/user-guide/core-data-model/dcim/deviceredundancygroup.html +110 -54
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicetype.html +117 -61
- nautobot/project-static/docs/user-guide/core-data-model/dcim/frontport.html +110 -54
- nautobot/project-static/docs/user-guide/core-data-model/dcim/frontporttemplate.html +110 -54
- nautobot/project-static/docs/user-guide/core-data-model/dcim/interface.html +119 -63
- nautobot/project-static/docs/user-guide/core-data-model/dcim/interfaceredundancygroup.html +110 -54
- nautobot/project-static/docs/user-guide/core-data-model/dcim/interfacetemplate.html +110 -54
- nautobot/project-static/docs/user-guide/core-data-model/dcim/inventoryitem.html +113 -57
- nautobot/project-static/docs/user-guide/core-data-model/dcim/location.html +113 -57
- nautobot/project-static/docs/user-guide/core-data-model/dcim/locationtype.html +113 -57
- nautobot/project-static/docs/user-guide/core-data-model/dcim/manufacturer.html +107 -51
- nautobot/project-static/docs/user-guide/core-data-model/dcim/platform.html +113 -57
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerfeed.html +107 -51
- nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlet.html +110 -54
- nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlettemplate.html +110 -54
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerpanel.html +107 -51
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerport.html +110 -54
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerporttemplate.html +110 -54
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rack.html +107 -51
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rackgroup.html +107 -51
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rackreservation.html +107 -51
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rearport.html +110 -54
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rearporttemplate.html +110 -54
- nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareimagefile.html +110 -54
- nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareversion.html +110 -54
- nautobot/project-static/docs/user-guide/core-data-model/dcim/virtualchassis.html +107 -51
- nautobot/project-static/docs/user-guide/core-data-model/extras/configcontext.html +113 -57
- nautobot/project-static/docs/user-guide/core-data-model/extras/configcontextschema.html +110 -54
- nautobot/project-static/docs/user-guide/core-data-model/extras/contact.html +110 -54
- nautobot/project-static/docs/user-guide/core-data-model/extras/team.html +110 -54
- nautobot/project-static/docs/user-guide/core-data-model/ipam/ipaddress.html +125 -69
- nautobot/project-static/docs/user-guide/core-data-model/ipam/namespace.html +113 -57
- nautobot/project-static/docs/user-guide/core-data-model/ipam/prefix.html +128 -72
- nautobot/project-static/docs/user-guide/core-data-model/ipam/rir.html +110 -54
- nautobot/project-static/docs/user-guide/core-data-model/ipam/routetarget.html +107 -51
- nautobot/project-static/docs/user-guide/core-data-model/ipam/service.html +110 -54
- nautobot/project-static/docs/user-guide/core-data-model/ipam/vlan.html +116 -60
- nautobot/project-static/docs/user-guide/core-data-model/ipam/vlangroup.html +107 -51
- nautobot/project-static/docs/user-guide/core-data-model/ipam/vrf.html +113 -57
- nautobot/project-static/docs/user-guide/core-data-model/overview/introduction.html +107 -51
- nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenant.html +110 -54
- nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenantgroup.html +107 -51
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/cluster.html +107 -51
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustergroup.html +107 -51
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustertype.html +107 -51
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/virtualmachine.html +113 -57
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/vminterface.html +113 -57
- nautobot/project-static/docs/user-guide/feature-guides/contacts-and-teams.html +107 -51
- nautobot/project-static/docs/user-guide/feature-guides/custom-fields.html +113 -57
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-devices.html +110 -54
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-location-types-and-locations.html +107 -51
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/index.html +107 -51
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/interfaces.html +108 -52
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/ipam.html +107 -51
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/platforms.html +107 -51
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/search-bar.html +107 -51
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/tenants.html +107 -51
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/vlans-and-vlan-groups.html +108 -52
- nautobot/project-static/docs/user-guide/feature-guides/git-data-source.html +110 -54
- nautobot/project-static/docs/user-guide/feature-guides/graphql.html +113 -57
- nautobot/project-static/docs/user-guide/feature-guides/ip-address-merge-tool.html +107 -51
- nautobot/project-static/docs/user-guide/feature-guides/relationships.html +110 -54
- nautobot/project-static/docs/user-guide/feature-guides/software-image-files-and-versions.html +107 -51
- nautobot/project-static/docs/user-guide/index.html +109 -53
- nautobot/project-static/docs/user-guide/platform-functionality/change-logging.html +107 -51
- nautobot/project-static/docs/user-guide/platform-functionality/computedfield.html +113 -57
- nautobot/project-static/docs/user-guide/platform-functionality/customfield.html +128 -72
- nautobot/project-static/docs/user-guide/platform-functionality/customlink.html +107 -51
- nautobot/project-static/docs/user-guide/platform-functionality/dynamicgroup.html +125 -69
- nautobot/project-static/docs/user-guide/platform-functionality/exporttemplate.html +107 -51
- nautobot/project-static/docs/user-guide/platform-functionality/externalintegration.html +110 -54
- nautobot/project-static/docs/user-guide/platform-functionality/gitrepository.html +125 -69
- nautobot/project-static/docs/user-guide/platform-functionality/graphql.html +110 -54
- nautobot/project-static/docs/user-guide/platform-functionality/graphqlquery.html +107 -51
- nautobot/project-static/docs/user-guide/platform-functionality/imageattachment.html +107 -51
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/index.html +128 -72
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/job-scheduling-and-approvals.html +114 -58
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobbutton.html +113 -57
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobhook.html +110 -54
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/models.html +121 -65
- nautobot/project-static/docs/user-guide/platform-functionality/napalm.html +109 -53
- nautobot/project-static/docs/user-guide/platform-functionality/note.html +110 -54
- nautobot/project-static/docs/user-guide/platform-functionality/relationship.html +116 -60
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/authentication.html +110 -54
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/filtering.html +131 -75
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/overview.html +149 -93
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/ui-related-endpoints.html +110 -54
- nautobot/project-static/docs/user-guide/platform-functionality/role.html +108 -84
- nautobot/project-static/docs/user-guide/platform-functionality/secret.html +116 -60
- nautobot/project-static/docs/user-guide/platform-functionality/status.html +119 -63
- nautobot/project-static/docs/user-guide/platform-functionality/tag.html +110 -54
- nautobot/project-static/docs/user-guide/platform-functionality/template-filters.html +137 -81
- nautobot/project-static/docs/user-guide/platform-functionality/users/objectpermission.html +110 -54
- nautobot/project-static/docs/user-guide/platform-functionality/users/token.html +107 -51
- nautobot/project-static/docs/user-guide/platform-functionality/webhook.html +110 -54
- nautobot/project-static/js/forms.js +2 -1
- nautobot/tenancy/forms.py +9 -0
- nautobot/tenancy/views.py +3 -6
- nautobot/virtualization/forms.py +18 -6
- nautobot/virtualization/templates/virtualization/clustertype.html +2 -2
- nautobot/virtualization/views.py +7 -9
- {nautobot-2.2.3.dist-info → nautobot-2.2.5.dist-info}/METADATA +2 -2
- {nautobot-2.2.3.dist-info → nautobot-2.2.5.dist-info}/RECORD +323 -320
- nautobot/project-static/docs/assets/javascripts/bundle.bd41221c.min.js +0 -29
- nautobot/project-static/docs/assets/javascripts/bundle.bd41221c.min.js.map +0 -7
- nautobot/project-static/docs/assets/stylesheets/main.bcfcd587.min.css +0 -1
- nautobot/project-static/docs/assets/stylesheets/main.bcfcd587.min.css.map +0 -1
- {nautobot-2.2.3.dist-info → nautobot-2.2.5.dist-info}/LICENSE.txt +0 -0
- {nautobot-2.2.3.dist-info → nautobot-2.2.5.dist-info}/NOTICE +0 -0
- {nautobot-2.2.3.dist-info → nautobot-2.2.5.dist-info}/WHEEL +0 -0
- {nautobot-2.2.3.dist-info → nautobot-2.2.5.dist-info}/entry_points.txt +0 -0
|
@@ -14,8 +14,15 @@ import yaml
|
|
|
14
14
|
from nautobot.circuits.choices import CircuitTerminationSideChoices
|
|
15
15
|
from nautobot.circuits.models import Circuit, CircuitTermination, CircuitType, Provider
|
|
16
16
|
from nautobot.core.templatetags.buttons import job_export_url, job_import_url
|
|
17
|
-
from nautobot.core.testing import
|
|
18
|
-
|
|
17
|
+
from nautobot.core.testing import (
|
|
18
|
+
extract_page_body,
|
|
19
|
+
ModelViewTestCase,
|
|
20
|
+
post_data,
|
|
21
|
+
ViewTestCases,
|
|
22
|
+
)
|
|
23
|
+
from nautobot.core.testing.utils import (
|
|
24
|
+
generate_random_device_asset_tag_of_specified_size,
|
|
25
|
+
)
|
|
19
26
|
from nautobot.dcim.choices import (
|
|
20
27
|
CableLengthUnitChoices,
|
|
21
28
|
CableTypeChoices,
|
|
@@ -90,7 +97,11 @@ from nautobot.dcim.models import (
|
|
|
90
97
|
SoftwareVersion,
|
|
91
98
|
VirtualChassis,
|
|
92
99
|
)
|
|
93
|
-
from nautobot.dcim.views import
|
|
100
|
+
from nautobot.dcim.views import (
|
|
101
|
+
ConsoleConnectionsListView,
|
|
102
|
+
InterfaceConnectionsListView,
|
|
103
|
+
PowerConnectionsListView,
|
|
104
|
+
)
|
|
94
105
|
from nautobot.extras.choices import CustomFieldTypeChoices, RelationshipTypeChoices
|
|
95
106
|
from nautobot.extras.models import (
|
|
96
107
|
ConfigContextSchema,
|
|
@@ -132,7 +143,11 @@ def create_test_device(name):
|
|
|
132
143
|
devicerole.content_types.add(device_ct)
|
|
133
144
|
devicestatus = Status.objects.get_for_model(Device).first()
|
|
134
145
|
device = Device.objects.create(
|
|
135
|
-
name=name,
|
|
146
|
+
name=name,
|
|
147
|
+
location=location,
|
|
148
|
+
device_type=devicetype,
|
|
149
|
+
role=devicerole,
|
|
150
|
+
status=devicestatus,
|
|
136
151
|
)
|
|
137
152
|
|
|
138
153
|
return device
|
|
@@ -165,7 +180,10 @@ class LocationTypeTestCase(ViewTestCases.OrganizationalObjectViewTestCase):
|
|
|
165
180
|
"name": "Intermediate 2",
|
|
166
181
|
# "parent": lt1.pk, # TODO: Either overload how EditObjectViewTestCase finds an editable object or write a specific test case for this.
|
|
167
182
|
"description": "Another intermediate type",
|
|
168
|
-
"content_types": [
|
|
183
|
+
"content_types": [
|
|
184
|
+
ContentType.objects.get_for_model(Rack).pk,
|
|
185
|
+
ContentType.objects.get_for_model(Device).pk,
|
|
186
|
+
],
|
|
169
187
|
"nestable": True,
|
|
170
188
|
}
|
|
171
189
|
|
|
@@ -192,7 +210,13 @@ class LocationTestCase(ViewTestCases.PrimaryObjectViewTestCase):
|
|
|
192
210
|
loc1 = Location.objects.create(name="Root 1", location_type=lt1, status=status)
|
|
193
211
|
loc2 = Location.objects.create(name="Root 2", location_type=lt1, status=status, tenant=tenant)
|
|
194
212
|
loc3 = Location.objects.create(name="Intermediate 1", location_type=lt2, parent=loc2, status=status)
|
|
195
|
-
loc4 = Location.objects.create(
|
|
213
|
+
loc4 = Location.objects.create(
|
|
214
|
+
name="Leaf 1",
|
|
215
|
+
location_type=lt3,
|
|
216
|
+
parent=loc3,
|
|
217
|
+
status=status,
|
|
218
|
+
description="Hi!",
|
|
219
|
+
)
|
|
196
220
|
for loc in [loc1, loc2, loc3, loc4]:
|
|
197
221
|
loc.validated_save()
|
|
198
222
|
|
|
@@ -228,7 +252,9 @@ class LocationTestCase(ViewTestCases.PrimaryObjectViewTestCase):
|
|
|
228
252
|
}
|
|
229
253
|
|
|
230
254
|
@override_settings(EXEMPT_VIEW_PERMISSIONS=["*"])
|
|
231
|
-
def test_create_child_location_under_a_non_globally_unique_named_parent_location(
|
|
255
|
+
def test_create_child_location_under_a_non_globally_unique_named_parent_location(
|
|
256
|
+
self,
|
|
257
|
+
):
|
|
232
258
|
self.add_permissions("dcim.add_location")
|
|
233
259
|
status = Status.objects.get_for_model(Location).first()
|
|
234
260
|
region_type = LocationType.objects.create(name="Region")
|
|
@@ -477,7 +503,11 @@ class RackTestCase(ViewTestCases.PrimaryObjectViewTestCase):
|
|
|
477
503
|
cls.cable_connected = cable_statuses.get(name="Connected")
|
|
478
504
|
|
|
479
505
|
cls.custom_fields = (
|
|
480
|
-
CustomField.objects.create(
|
|
506
|
+
CustomField.objects.create(
|
|
507
|
+
type=CustomFieldTypeChoices.TYPE_MULTISELECT,
|
|
508
|
+
label="Rack Colors",
|
|
509
|
+
default=[],
|
|
510
|
+
),
|
|
481
511
|
)
|
|
482
512
|
|
|
483
513
|
CustomFieldChoice.objects.create(custom_field=cls.custom_fields[0], value="red")
|
|
@@ -526,7 +556,9 @@ class RackTestCase(ViewTestCases.PrimaryObjectViewTestCase):
|
|
|
526
556
|
|
|
527
557
|
for rack in racks:
|
|
528
558
|
RelationshipAssociation(
|
|
529
|
-
relationship=cls.relationships[0],
|
|
559
|
+
relationship=cls.relationships[0],
|
|
560
|
+
source=rack,
|
|
561
|
+
destination=cls.locations[1],
|
|
530
562
|
).validated_save()
|
|
531
563
|
|
|
532
564
|
cls.form_data = {
|
|
@@ -635,19 +667,31 @@ class RackTestCase(ViewTestCases.PrimaryObjectViewTestCase):
|
|
|
635
667
|
poweroutlet1 = PowerOutlet.objects.create(device=devices[0], name="Power Outlet 11", power_port=powerport1)
|
|
636
668
|
|
|
637
669
|
# connect power port to power feed (single-phase)
|
|
638
|
-
cable1 = Cable(
|
|
670
|
+
cable1 = Cable(
|
|
671
|
+
termination_a=powerfeed1,
|
|
672
|
+
termination_b=powerport1,
|
|
673
|
+
status=self.cable_connected,
|
|
674
|
+
)
|
|
639
675
|
cable1.save()
|
|
640
676
|
|
|
641
677
|
# Create power port for 2nd device
|
|
642
678
|
powerport2 = PowerPort.objects.create(device=devices[1], name="Power Port 12", allocated_draw=1200)
|
|
643
679
|
|
|
644
680
|
# Connect power port to power outlet (dev1)
|
|
645
|
-
cable2 = Cable(
|
|
681
|
+
cable2 = Cable(
|
|
682
|
+
termination_a=powerport2,
|
|
683
|
+
termination_b=poweroutlet1,
|
|
684
|
+
status=self.cable_connected,
|
|
685
|
+
)
|
|
646
686
|
cable2.save()
|
|
647
687
|
|
|
648
688
|
# Create another power port for 2nd device and directly connect to the second PowerFeed.
|
|
649
689
|
powerport3 = PowerPort.objects.create(device=devices[1], name="Power Port 13", allocated_draw=2400)
|
|
650
|
-
cable3 = Cable(
|
|
690
|
+
cable3 = Cable(
|
|
691
|
+
termination_a=powerfeed2,
|
|
692
|
+
termination_b=powerport3,
|
|
693
|
+
status=self.cable_connected,
|
|
694
|
+
)
|
|
651
695
|
cable3.save()
|
|
652
696
|
|
|
653
697
|
# Test the view
|
|
@@ -791,7 +835,10 @@ class DeviceTypeTestCase(
|
|
|
791
835
|
content,
|
|
792
836
|
)
|
|
793
837
|
self.assertInHTML('<input type="hidden" name="export_format" value="yaml">', content)
|
|
794
|
-
self.assertInHTML(
|
|
838
|
+
self.assertInHTML(
|
|
839
|
+
'<button type="submit" class="btn btn-link" form="export_default">YAML format</button>',
|
|
840
|
+
content,
|
|
841
|
+
)
|
|
795
842
|
self.assertInHTML('<button type="submit" class="btn btn-link">CSV format</button>', content)
|
|
796
843
|
|
|
797
844
|
@override_settings(EXEMPT_VIEW_PERMISSIONS=["*"])
|
|
@@ -1431,7 +1478,12 @@ class DeviceTestCase(ViewTestCases.PrimaryObjectViewTestCase):
|
|
|
1431
1478
|
|
|
1432
1479
|
rack_status = Status.objects.get_for_model(Rack).first()
|
|
1433
1480
|
racks = (
|
|
1434
|
-
Rack.objects.create(
|
|
1481
|
+
Rack.objects.create(
|
|
1482
|
+
name="Rack 1",
|
|
1483
|
+
location=locations[0],
|
|
1484
|
+
rack_group=rack_group,
|
|
1485
|
+
status=rack_status,
|
|
1486
|
+
),
|
|
1435
1487
|
Rack.objects.create(name="Rack 2", location=locations[1], status=rack_status),
|
|
1436
1488
|
)
|
|
1437
1489
|
|
|
@@ -1470,7 +1522,11 @@ class DeviceTestCase(ViewTestCases.PrimaryObjectViewTestCase):
|
|
|
1470
1522
|
devicetypes[1].software_image_files.set(software_image_files[2:])
|
|
1471
1523
|
|
|
1472
1524
|
cls.custom_fields = (
|
|
1473
|
-
CustomField.objects.create(
|
|
1525
|
+
CustomField.objects.create(
|
|
1526
|
+
type=CustomFieldTypeChoices.TYPE_INTEGER,
|
|
1527
|
+
label="Crash Counter",
|
|
1528
|
+
default=0,
|
|
1529
|
+
),
|
|
1474
1530
|
)
|
|
1475
1531
|
cls.custom_fields[0].content_types.set([ContentType.objects.get_for_model(Device)])
|
|
1476
1532
|
|
|
@@ -1655,7 +1711,11 @@ class DeviceTestCase(ViewTestCases.PrimaryObjectViewTestCase):
|
|
|
1655
1711
|
def test_device_interface_assign_ipaddress(self):
|
|
1656
1712
|
device = Device.objects.first()
|
|
1657
1713
|
self.add_permissions(
|
|
1658
|
-
"ipam.add_ipaddress",
|
|
1714
|
+
"ipam.add_ipaddress",
|
|
1715
|
+
"extras.view_status",
|
|
1716
|
+
"ipam.view_namespace",
|
|
1717
|
+
"dcim.view_device",
|
|
1718
|
+
"dcim.view_interface",
|
|
1659
1719
|
)
|
|
1660
1720
|
device_list_url = reverse("dcim:device_interfaces", args=(device.pk,))
|
|
1661
1721
|
namespace = Namespace.objects.first()
|
|
@@ -1691,7 +1751,10 @@ class DeviceTestCase(ViewTestCases.PrimaryObjectViewTestCase):
|
|
|
1691
1751
|
self.assertHttpStatus(response, 200)
|
|
1692
1752
|
self.interfaces[0].refresh_from_db()
|
|
1693
1753
|
self.assertEqual(self.interfaces[0].ip_addresses.all().count(), 0)
|
|
1694
|
-
self.assertIn(
|
|
1754
|
+
self.assertIn(
|
|
1755
|
+
f"Interface with id "{self.interfaces[0].pk}" not found",
|
|
1756
|
+
response_body,
|
|
1757
|
+
)
|
|
1695
1758
|
|
|
1696
1759
|
with self.subTest("Assert Cannnot assign IPAddress(Exsisting IP) without permission"):
|
|
1697
1760
|
# Assert Assign Exsisting IPAddress
|
|
@@ -1700,7 +1763,10 @@ class DeviceTestCase(ViewTestCases.PrimaryObjectViewTestCase):
|
|
|
1700
1763
|
self.assertHttpStatus(response, 200)
|
|
1701
1764
|
self.interfaces[1].refresh_from_db()
|
|
1702
1765
|
self.assertEqual(self.interfaces[1].ip_addresses.all().count(), 0)
|
|
1703
|
-
self.assertIn(
|
|
1766
|
+
self.assertIn(
|
|
1767
|
+
f"Interface with id "{self.interfaces[1].pk}" not found",
|
|
1768
|
+
response_body,
|
|
1769
|
+
)
|
|
1704
1770
|
|
|
1705
1771
|
self.add_permissions("dcim.change_interface", "ipam.view_ipaddress")
|
|
1706
1772
|
|
|
@@ -1708,7 +1774,8 @@ class DeviceTestCase(ViewTestCases.PrimaryObjectViewTestCase):
|
|
|
1708
1774
|
self.assertHttpStatus(self.client.post(**add_new_ip_request), 302)
|
|
1709
1775
|
self.interfaces[0].refresh_from_db()
|
|
1710
1776
|
self.assertEqual(
|
|
1711
|
-
str(self.interfaces[0].ip_addresses.all().first().address),
|
|
1777
|
+
str(self.interfaces[0].ip_addresses.all().first().address),
|
|
1778
|
+
add_new_ip_form_data["address"],
|
|
1712
1779
|
)
|
|
1713
1780
|
|
|
1714
1781
|
with self.subTest("Assert Assign IPAddress"):
|
|
@@ -1818,7 +1885,8 @@ class DeviceTestCase(ViewTestCases.PrimaryObjectViewTestCase):
|
|
|
1818
1885
|
Assert that the local context passes schema validation via full_clean()
|
|
1819
1886
|
"""
|
|
1820
1887
|
schema = ConfigContextSchema.objects.create(
|
|
1821
|
-
name="Schema 1",
|
|
1888
|
+
name="Schema 1",
|
|
1889
|
+
data_schema={"type": "object", "properties": {"foo": {"type": "string"}}},
|
|
1822
1890
|
)
|
|
1823
1891
|
self.add_permissions("dcim.add_device")
|
|
1824
1892
|
|
|
@@ -1832,7 +1900,10 @@ class DeviceTestCase(ViewTestCases.PrimaryObjectViewTestCase):
|
|
|
1832
1900
|
"data": post_data(form_data),
|
|
1833
1901
|
}
|
|
1834
1902
|
self.assertHttpStatus(self.client.post(**request), 302)
|
|
1835
|
-
self.assertEqual(
|
|
1903
|
+
self.assertEqual(
|
|
1904
|
+
self._get_queryset().get(name="Device X").local_config_context_schema.pk,
|
|
1905
|
+
schema.pk,
|
|
1906
|
+
)
|
|
1836
1907
|
|
|
1837
1908
|
@override_settings(EXEMPT_VIEW_PERMISSIONS=["*"])
|
|
1838
1909
|
def test_local_config_context_schema_validation_fails(self):
|
|
@@ -1842,7 +1913,8 @@ class DeviceTestCase(ViewTestCases.PrimaryObjectViewTestCase):
|
|
|
1842
1913
|
Assert that the local context fails schema validation via full_clean()
|
|
1843
1914
|
"""
|
|
1844
1915
|
schema = ConfigContextSchema.objects.create(
|
|
1845
|
-
name="Schema 1",
|
|
1916
|
+
name="Schema 1",
|
|
1917
|
+
data_schema={"type": "object", "properties": {"foo": {"type": "integer"}}},
|
|
1846
1918
|
)
|
|
1847
1919
|
self.add_permissions("dcim.add_device")
|
|
1848
1920
|
|
|
@@ -2058,10 +2130,16 @@ class InterfaceTestCase(ViewTestCases.DeviceComponentViewTestCase):
|
|
|
2058
2130
|
Interface.objects.create(device=device, name="Interface 2", status=status_active),
|
|
2059
2131
|
Interface.objects.create(device=device, name="Interface 3", status=status_active),
|
|
2060
2132
|
Interface.objects.create(
|
|
2061
|
-
device=device,
|
|
2133
|
+
device=device,
|
|
2134
|
+
name="LAG",
|
|
2135
|
+
status=status_active,
|
|
2136
|
+
type=InterfaceTypeChoices.TYPE_LAG,
|
|
2062
2137
|
),
|
|
2063
2138
|
Interface.objects.create(
|
|
2064
|
-
device=device,
|
|
2139
|
+
device=device,
|
|
2140
|
+
name="BRIDGE",
|
|
2141
|
+
status=status_active,
|
|
2142
|
+
type=InterfaceTypeChoices.TYPE_BRIDGE,
|
|
2065
2143
|
),
|
|
2066
2144
|
)
|
|
2067
2145
|
cls.lag_interface = interfaces[3]
|
|
@@ -2073,16 +2151,32 @@ class InterfaceTestCase(ViewTestCases.DeviceComponentViewTestCase):
|
|
|
2073
2151
|
vlan_group = VLANGroup.objects.first()
|
|
2074
2152
|
vlans = (
|
|
2075
2153
|
VLAN.objects.create(
|
|
2076
|
-
vid=1,
|
|
2154
|
+
vid=1,
|
|
2155
|
+
name="VLAN1",
|
|
2156
|
+
location=device.location,
|
|
2157
|
+
status=vlan_status,
|
|
2158
|
+
vlan_group=vlan_group,
|
|
2077
2159
|
),
|
|
2078
2160
|
VLAN.objects.create(
|
|
2079
|
-
vid=101,
|
|
2161
|
+
vid=101,
|
|
2162
|
+
name="VLAN101",
|
|
2163
|
+
location=device.location,
|
|
2164
|
+
status=vlan_status,
|
|
2165
|
+
vlan_group=vlan_group,
|
|
2080
2166
|
),
|
|
2081
2167
|
VLAN.objects.create(
|
|
2082
|
-
vid=102,
|
|
2168
|
+
vid=102,
|
|
2169
|
+
name="VLAN102",
|
|
2170
|
+
location=device.location,
|
|
2171
|
+
status=vlan_status,
|
|
2172
|
+
vlan_group=vlan_group,
|
|
2083
2173
|
),
|
|
2084
2174
|
VLAN.objects.create(
|
|
2085
|
-
vid=103,
|
|
2175
|
+
vid=103,
|
|
2176
|
+
name="VLAN103",
|
|
2177
|
+
location=device.location,
|
|
2178
|
+
status=vlan_status,
|
|
2179
|
+
vlan_group=vlan_group,
|
|
2086
2180
|
),
|
|
2087
2181
|
)
|
|
2088
2182
|
|
|
@@ -2569,22 +2663,37 @@ class CableTestCase(
|
|
|
2569
2663
|
circuittype = CircuitType.objects.first()
|
|
2570
2664
|
circuit_status = Status.objects.get_for_model(Circuit).first()
|
|
2571
2665
|
circuit = Circuit.objects.create(
|
|
2572
|
-
cid="Circuit 1",
|
|
2666
|
+
cid="Circuit 1",
|
|
2667
|
+
provider=provider,
|
|
2668
|
+
circuit_type=circuittype,
|
|
2669
|
+
status=circuit_status,
|
|
2573
2670
|
)
|
|
2574
2671
|
|
|
2575
2672
|
circuit_terminations = [
|
|
2576
2673
|
CircuitTermination.objects.create(
|
|
2577
|
-
circuit=circuit,
|
|
2674
|
+
circuit=circuit,
|
|
2675
|
+
term_side=CircuitTerminationSideChoices.SIDE_A,
|
|
2676
|
+
location=location,
|
|
2578
2677
|
),
|
|
2579
2678
|
CircuitTermination.objects.create(
|
|
2580
|
-
circuit=circuit,
|
|
2679
|
+
circuit=circuit,
|
|
2680
|
+
term_side=CircuitTerminationSideChoices.SIDE_Z,
|
|
2681
|
+
location=location,
|
|
2581
2682
|
),
|
|
2582
2683
|
]
|
|
2583
2684
|
|
|
2584
2685
|
status = Status.objects.get_for_model(Cable).get(name="Connected")
|
|
2585
2686
|
cables = [
|
|
2586
|
-
Cable.objects.create(
|
|
2587
|
-
|
|
2687
|
+
Cable.objects.create(
|
|
2688
|
+
termination_a=circuit_terminations[0],
|
|
2689
|
+
termination_b=interfaces[0],
|
|
2690
|
+
status=status,
|
|
2691
|
+
),
|
|
2692
|
+
Cable.objects.create(
|
|
2693
|
+
termination_a=circuit_terminations[1],
|
|
2694
|
+
termination_b=interfaces[1],
|
|
2695
|
+
status=status,
|
|
2696
|
+
),
|
|
2588
2697
|
]
|
|
2589
2698
|
|
|
2590
2699
|
request = {
|
|
@@ -2604,7 +2713,10 @@ class CableTestCase(
|
|
|
2604
2713
|
cable_path_1 = CablePath.objects.filter(
|
|
2605
2714
|
Q(origin_type=termination_ct, origin_id=circuit_terminations[0].pk)
|
|
2606
2715
|
| Q(origin_type=interface_ct, origin_id=interfaces[0].pk)
|
|
2607
|
-
| Q(
|
|
2716
|
+
| Q(
|
|
2717
|
+
destination_type=termination_ct,
|
|
2718
|
+
destination_id=circuit_terminations[0].pk,
|
|
2719
|
+
)
|
|
2608
2720
|
| Q(destination_type=interface_ct, destination_id=interfaces[0].pk)
|
|
2609
2721
|
)
|
|
2610
2722
|
# pylint: enable=unsupported-binary-operation
|
|
@@ -2615,7 +2727,10 @@ class CableTestCase(
|
|
|
2615
2727
|
cable_path_2 = CablePath.objects.filter(
|
|
2616
2728
|
Q(origin_type=termination_ct, origin_id=circuit_terminations[1].pk)
|
|
2617
2729
|
| Q(origin_type=interface_ct, origin_id=interfaces[1].pk)
|
|
2618
|
-
| Q(
|
|
2730
|
+
| Q(
|
|
2731
|
+
destination_type=termination_ct,
|
|
2732
|
+
destination_id=circuit_terminations[1].pk,
|
|
2733
|
+
)
|
|
2619
2734
|
| Q(destination_type=interface_ct, destination_id=interfaces[1].pk)
|
|
2620
2735
|
)
|
|
2621
2736
|
# pylint: enable=unsupported-binary-operation
|
|
@@ -2660,9 +2775,21 @@ class ConsoleConnectionsTestCase(ViewTestCases.ListObjectsViewTestCase):
|
|
|
2660
2775
|
)
|
|
2661
2776
|
status_connected = Status.objects.get(name="Connected")
|
|
2662
2777
|
|
|
2663
|
-
Cable.objects.create(
|
|
2664
|
-
|
|
2665
|
-
|
|
2778
|
+
Cable.objects.create(
|
|
2779
|
+
termination_a=consoleports[0],
|
|
2780
|
+
termination_b=serverports[0],
|
|
2781
|
+
status=status_connected,
|
|
2782
|
+
)
|
|
2783
|
+
Cable.objects.create(
|
|
2784
|
+
termination_a=consoleports[1],
|
|
2785
|
+
termination_b=serverports[1],
|
|
2786
|
+
status=status_connected,
|
|
2787
|
+
)
|
|
2788
|
+
Cable.objects.create(
|
|
2789
|
+
termination_a=consoleports[2],
|
|
2790
|
+
termination_b=rearport,
|
|
2791
|
+
status=status_connected,
|
|
2792
|
+
)
|
|
2666
2793
|
|
|
2667
2794
|
|
|
2668
2795
|
class PowerConnectionsTestCase(ViewTestCases.ListObjectsViewTestCase):
|
|
@@ -2709,10 +2836,22 @@ class PowerConnectionsTestCase(ViewTestCases.ListObjectsViewTestCase):
|
|
|
2709
2836
|
|
|
2710
2837
|
status_connected = Status.objects.get(name="Connected")
|
|
2711
2838
|
|
|
2712
|
-
Cable.objects.create(
|
|
2839
|
+
Cable.objects.create(
|
|
2840
|
+
termination_a=powerports[2],
|
|
2841
|
+
termination_b=powerfeed,
|
|
2842
|
+
status=status_connected,
|
|
2843
|
+
)
|
|
2713
2844
|
# Creating a PowerOutlet with a PowerPort via the ORM does *not* automatically cable the two together. Bug?
|
|
2714
|
-
Cable.objects.create(
|
|
2715
|
-
|
|
2845
|
+
Cable.objects.create(
|
|
2846
|
+
termination_a=powerports[0],
|
|
2847
|
+
termination_b=poweroutlets[0],
|
|
2848
|
+
status=status_connected,
|
|
2849
|
+
)
|
|
2850
|
+
Cable.objects.create(
|
|
2851
|
+
termination_a=powerports[1],
|
|
2852
|
+
termination_b=poweroutlets[1],
|
|
2853
|
+
status=status_connected,
|
|
2854
|
+
)
|
|
2716
2855
|
|
|
2717
2856
|
|
|
2718
2857
|
class InterfaceConnectionsTestCase(ViewTestCases.ListObjectsViewTestCase):
|
|
@@ -2745,18 +2884,30 @@ class InterfaceConnectionsTestCase(ViewTestCases.ListObjectsViewTestCase):
|
|
|
2745
2884
|
interface_status = Status.objects.get_for_model(Interface).first()
|
|
2746
2885
|
cls.interfaces = (
|
|
2747
2886
|
Interface.objects.create(
|
|
2748
|
-
device=device_1,
|
|
2887
|
+
device=device_1,
|
|
2888
|
+
name="Interface 1",
|
|
2889
|
+
type=InterfaceTypeChoices.TYPE_1GE_SFP,
|
|
2890
|
+
status=interface_status,
|
|
2749
2891
|
),
|
|
2750
2892
|
Interface.objects.create(
|
|
2751
|
-
device=device_1,
|
|
2893
|
+
device=device_1,
|
|
2894
|
+
name="Interface 2",
|
|
2895
|
+
type=InterfaceTypeChoices.TYPE_1GE_SFP,
|
|
2896
|
+
status=interface_status,
|
|
2752
2897
|
),
|
|
2753
2898
|
Interface.objects.create(
|
|
2754
|
-
device=device_1,
|
|
2899
|
+
device=device_1,
|
|
2900
|
+
name="Interface 3",
|
|
2901
|
+
type=InterfaceTypeChoices.TYPE_1GE_SFP,
|
|
2902
|
+
status=interface_status,
|
|
2755
2903
|
),
|
|
2756
2904
|
)
|
|
2757
2905
|
|
|
2758
2906
|
cls.device_2_interface = Interface.objects.create(
|
|
2759
|
-
device=device_2,
|
|
2907
|
+
device=device_2,
|
|
2908
|
+
name="Interface 1",
|
|
2909
|
+
type=InterfaceTypeChoices.TYPE_1GE_SFP,
|
|
2910
|
+
status=interface_status,
|
|
2760
2911
|
)
|
|
2761
2912
|
rearport = RearPort.objects.create(device=device_2, type=PortTypeChoices.TYPE_8P8C)
|
|
2762
2913
|
|
|
@@ -2764,16 +2915,29 @@ class InterfaceConnectionsTestCase(ViewTestCases.ListObjectsViewTestCase):
|
|
|
2764
2915
|
circuittype = CircuitType.objects.first()
|
|
2765
2916
|
circuit_status = Status.objects.get_for_model(Circuit).first()
|
|
2766
2917
|
circuit = Circuit.objects.create(
|
|
2767
|
-
cid="Circuit 1",
|
|
2918
|
+
cid="Circuit 1",
|
|
2919
|
+
provider=provider,
|
|
2920
|
+
circuit_type=circuittype,
|
|
2921
|
+
status=circuit_status,
|
|
2768
2922
|
)
|
|
2769
2923
|
circuittermination = CircuitTermination.objects.create(
|
|
2770
|
-
circuit=circuit,
|
|
2924
|
+
circuit=circuit,
|
|
2925
|
+
term_side=CircuitTerminationSideChoices.SIDE_A,
|
|
2926
|
+
location=location,
|
|
2771
2927
|
)
|
|
2772
2928
|
|
|
2773
2929
|
connected = Status.objects.get(name="Connected")
|
|
2774
2930
|
|
|
2775
|
-
Cable.objects.create(
|
|
2776
|
-
|
|
2931
|
+
Cable.objects.create(
|
|
2932
|
+
termination_a=cls.interfaces[0],
|
|
2933
|
+
termination_b=cls.device_2_interface,
|
|
2934
|
+
status=connected,
|
|
2935
|
+
)
|
|
2936
|
+
Cable.objects.create(
|
|
2937
|
+
termination_a=cls.interfaces[1],
|
|
2938
|
+
termination_b=circuittermination,
|
|
2939
|
+
status=connected,
|
|
2940
|
+
)
|
|
2777
2941
|
Cable.objects.create(termination_a=cls.interfaces[2], termination_b=rearport, status=connected)
|
|
2778
2942
|
|
|
2779
2943
|
@override_settings(EXEMPT_VIEW_PERMISSIONS=["*"])
|
|
@@ -2951,12 +3115,23 @@ class PowerFeedTestCase(ViewTestCases.PrimaryObjectViewTestCase):
|
|
|
2951
3115
|
status_planned = statuses[0]
|
|
2952
3116
|
|
|
2953
3117
|
powerfeed_1 = PowerFeed.objects.create(
|
|
2954
|
-
name="Power Feed 1",
|
|
3118
|
+
name="Power Feed 1",
|
|
3119
|
+
power_panel=powerpanels[0],
|
|
3120
|
+
rack=racks[0],
|
|
3121
|
+
status=status_planned,
|
|
2955
3122
|
)
|
|
2956
3123
|
powerfeed_2 = PowerFeed.objects.create(
|
|
2957
|
-
name="Power Feed 2",
|
|
3124
|
+
name="Power Feed 2",
|
|
3125
|
+
power_panel=powerpanels[0],
|
|
3126
|
+
rack=racks[0],
|
|
3127
|
+
status=status_planned,
|
|
3128
|
+
)
|
|
3129
|
+
PowerFeed.objects.create(
|
|
3130
|
+
name="Power Feed 3",
|
|
3131
|
+
power_panel=powerpanels[0],
|
|
3132
|
+
rack=racks[0],
|
|
3133
|
+
status=status_planned,
|
|
2958
3134
|
)
|
|
2959
|
-
PowerFeed.objects.create(name="Power Feed 3", power_panel=powerpanels[0], rack=racks[0], status=status_planned)
|
|
2960
3135
|
|
|
2961
3136
|
# Assign power feeds for the tests later
|
|
2962
3137
|
cls.powerfeeds = (powerfeed_1, powerfeed_2)
|
|
@@ -3009,7 +3184,9 @@ class PowerFeedTestCase(ViewTestCases.PrimaryObjectViewTestCase):
|
|
|
3009
3184
|
powerfeed = self.powerfeeds[0]
|
|
3010
3185
|
|
|
3011
3186
|
Cable.objects.create(
|
|
3012
|
-
termination_a=powerport,
|
|
3187
|
+
termination_a=powerport,
|
|
3188
|
+
termination_b=powerfeed,
|
|
3189
|
+
status=Status.objects.get(name="Connected"),
|
|
3013
3190
|
)
|
|
3014
3191
|
|
|
3015
3192
|
url = reverse("dcim:powerfeed", kwargs={"pk": powerfeed.pk})
|
|
@@ -3032,7 +3209,11 @@ class PathTraceViewTestCase(ModelViewTestCase):
|
|
|
3032
3209
|
location_type = LocationType.objects.get(name="Campus")
|
|
3033
3210
|
location = Location.objects.create(location_type=location_type, name="Location 1", status=active)
|
|
3034
3211
|
device = Device.objects.create(
|
|
3035
|
-
device_type=devicetype,
|
|
3212
|
+
device_type=devicetype,
|
|
3213
|
+
role=devicerole,
|
|
3214
|
+
name="Device 1",
|
|
3215
|
+
location=location,
|
|
3216
|
+
status=active,
|
|
3036
3217
|
)
|
|
3037
3218
|
obj = RearPort.objects.create(device=device, name="Rear Port 1", type=PortTypeChoices.TYPE_8P8C)
|
|
3038
3219
|
peer_obj = Interface.objects.create(device=device, name="eth0", status=active)
|
|
@@ -3163,7 +3344,10 @@ class InterfaceRedundancyGroupTestCase(ViewTestCases.PrimaryObjectViewTestCase):
|
|
|
3163
3344
|
|
|
3164
3345
|
# Assign unconstrained permission
|
|
3165
3346
|
self.add_permissions("dcim.add_interfaceredundancygroupassociation")
|
|
3166
|
-
return_url = reverse(
|
|
3347
|
+
return_url = reverse(
|
|
3348
|
+
"dcim:interfaceredundancygroup",
|
|
3349
|
+
kwargs={"pk": self.interface_redundancy_groups[0].pk},
|
|
3350
|
+
)
|
|
3167
3351
|
url = reverse("dcim:interfaceredundancygroupassociation_add")
|
|
3168
3352
|
url = url + f"?interface_redundancy_group={self.interface_redundancy_groups[0].pk}&return_url={return_url}"
|
|
3169
3353
|
self.assertHttpStatus(self.client.get(url), 200)
|
|
@@ -3214,6 +3398,48 @@ class SoftwareImageFileTestCase(ViewTestCases.PrimaryObjectViewTestCase):
|
|
|
3214
3398
|
"download_url": "https://example.com/software_image_file_test_case.bin",
|
|
3215
3399
|
}
|
|
3216
3400
|
|
|
3401
|
+
@override_settings(EXEMPT_VIEW_PERMISSIONS=["*"])
|
|
3402
|
+
def test_correct_handling_for_model_protected_error(self):
|
|
3403
|
+
platform = Platform.objects.first()
|
|
3404
|
+
software_version_status = Status.objects.get_for_model(SoftwareVersion).first()
|
|
3405
|
+
software_image_file_status = Status.objects.get_for_model(SoftwareImageFile).first()
|
|
3406
|
+
software_version = SoftwareVersion.objects.create(
|
|
3407
|
+
platform=platform, version="Test version 1.0.0", status=software_version_status
|
|
3408
|
+
)
|
|
3409
|
+
software_image_file = SoftwareImageFile.objects.create(
|
|
3410
|
+
software_version=software_version,
|
|
3411
|
+
image_file_name="software_image_file_qs_test_1.bin",
|
|
3412
|
+
status=software_image_file_status,
|
|
3413
|
+
)
|
|
3414
|
+
device_type = DeviceType.objects.first()
|
|
3415
|
+
device_role = Role.objects.get_for_model(Device).first()
|
|
3416
|
+
device_status = Status.objects.get_for_model(Device).first()
|
|
3417
|
+
location = Location.objects.filter(location_type__name="Campus").first()
|
|
3418
|
+
Device.objects.create(
|
|
3419
|
+
device_type=device_type,
|
|
3420
|
+
role=device_role,
|
|
3421
|
+
name="Device 1",
|
|
3422
|
+
location=location,
|
|
3423
|
+
status=device_status,
|
|
3424
|
+
software_version=software_version,
|
|
3425
|
+
)
|
|
3426
|
+
device_type_to_software_image_file = DeviceTypeToSoftwareImageFile.objects.create(
|
|
3427
|
+
device_type=device_type, software_image_file=software_image_file
|
|
3428
|
+
)
|
|
3429
|
+
|
|
3430
|
+
self.add_permissions("dcim.delete_softwareimagefile")
|
|
3431
|
+
pk_list = [software_image_file.pk]
|
|
3432
|
+
data = {
|
|
3433
|
+
"pk": pk_list,
|
|
3434
|
+
"confirm": True,
|
|
3435
|
+
"_confirm": True, # Form button
|
|
3436
|
+
}
|
|
3437
|
+
response = self.client.post(self._get_url("bulk_delete"), data, follow=True)
|
|
3438
|
+
self.assertHttpStatus(response, 200)
|
|
3439
|
+
response_body = response.content.decode(response.charset)
|
|
3440
|
+
# Assert protected error message included in the response body
|
|
3441
|
+
self.assertInHTML(f"<span>{device_type_to_software_image_file}</span>", response_body)
|
|
3442
|
+
|
|
3217
3443
|
|
|
3218
3444
|
class SoftwareVersionTestCase(ViewTestCases.PrimaryObjectViewTestCase):
|
|
3219
3445
|
model = SoftwareVersion
|
|
@@ -3252,6 +3478,48 @@ class SoftwareVersionTestCase(ViewTestCases.PrimaryObjectViewTestCase):
|
|
|
3252
3478
|
"pre_release": True,
|
|
3253
3479
|
}
|
|
3254
3480
|
|
|
3481
|
+
@override_settings(EXEMPT_VIEW_PERMISSIONS=["*"])
|
|
3482
|
+
def test_correct_handling_for_model_protected_error(self):
|
|
3483
|
+
platform = Platform.objects.first()
|
|
3484
|
+
software_version_status = Status.objects.get_for_model(SoftwareVersion).first()
|
|
3485
|
+
software_image_file_status = Status.objects.get_for_model(SoftwareImageFile).first()
|
|
3486
|
+
software_version = SoftwareVersion.objects.create(
|
|
3487
|
+
platform=platform, version="Test version 1.0.0", status=software_version_status
|
|
3488
|
+
)
|
|
3489
|
+
software_image_file = SoftwareImageFile.objects.create(
|
|
3490
|
+
software_version=software_version,
|
|
3491
|
+
image_file_name="software_image_file_qs_test_1.bin",
|
|
3492
|
+
status=software_image_file_status,
|
|
3493
|
+
)
|
|
3494
|
+
device_type = DeviceType.objects.first()
|
|
3495
|
+
device_role = Role.objects.get_for_model(Device).first()
|
|
3496
|
+
device_status = Status.objects.get_for_model(Device).first()
|
|
3497
|
+
location = Location.objects.filter(location_type__name="Campus").first()
|
|
3498
|
+
Device.objects.create(
|
|
3499
|
+
device_type=device_type,
|
|
3500
|
+
role=device_role,
|
|
3501
|
+
name="Device 1",
|
|
3502
|
+
location=location,
|
|
3503
|
+
status=device_status,
|
|
3504
|
+
software_version=software_version,
|
|
3505
|
+
)
|
|
3506
|
+
device_type_to_software_image_file = DeviceTypeToSoftwareImageFile.objects.create(
|
|
3507
|
+
device_type=device_type, software_image_file=software_image_file
|
|
3508
|
+
)
|
|
3509
|
+
|
|
3510
|
+
self.add_permissions("dcim.delete_softwareversion")
|
|
3511
|
+
pk_list = [software_version.pk]
|
|
3512
|
+
data = {
|
|
3513
|
+
"pk": pk_list,
|
|
3514
|
+
"confirm": True,
|
|
3515
|
+
"_confirm": True, # Form button
|
|
3516
|
+
}
|
|
3517
|
+
response = self.client.post(self._get_url("bulk_delete"), data, follow=True)
|
|
3518
|
+
self.assertHttpStatus(response, 200)
|
|
3519
|
+
response_body = response.content.decode(response.charset)
|
|
3520
|
+
# Assert protected error message included in the response body
|
|
3521
|
+
self.assertInHTML(f"<span>{device_type_to_software_image_file}</span>", response_body)
|
|
3522
|
+
|
|
3255
3523
|
|
|
3256
3524
|
class ControllerTestCase(ViewTestCases.PrimaryObjectViewTestCase):
|
|
3257
3525
|
model = Controller
|