nautobot 2.3.3__py3-none-any.whl → 2.3.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/core/celery/schedulers.py +2 -2
- nautobot/core/settings.py +3 -1
- nautobot/core/settings.yaml +40 -23
- nautobot/core/tests/runner.py +13 -6
- nautobot/core/tests/test_settings_schema.py +7 -3
- nautobot/core/tests/test_views.py +40 -1
- nautobot/core/views/generic.py +15 -15
- nautobot/core/views/mixins.py +12 -1
- nautobot/core/views/renderers.py +3 -1
- nautobot/core/views/utils.py +1 -1
- nautobot/dcim/api/serializers.py +1 -0
- nautobot/dcim/api/views.py +2 -0
- nautobot/dcim/forms.py +1 -1
- nautobot/dcim/tables/power.py +1 -1
- nautobot/dcim/templates/dcim/devicefamily_retrieve.html +1 -1
- nautobot/dcim/tests/test_api.py +58 -4
- nautobot/dcim/tests/test_filters.py +1 -1
- nautobot/dcim/tests/test_models.py +0 -2
- nautobot/dcim/views.py +5 -2
- nautobot/extras/api/views.py +9 -0
- nautobot/extras/models/jobs.py +9 -1
- nautobot/extras/querysets.py +10 -1
- nautobot/extras/tables.py +3 -0
- nautobot/extras/tests/test_api.py +36 -0
- nautobot/extras/tests/test_views.py +76 -1
- nautobot/extras/views.py +10 -7
- nautobot/ipam/forms.py +6 -1
- nautobot/ipam/models.py +5 -11
- nautobot/ipam/navigation.py +8 -1
- nautobot/ipam/templates/ipam/prefix.html +1 -1
- nautobot/ipam/tests/test_filters.py +1 -1
- nautobot/ipam/tests/test_views.py +41 -41
- nautobot/ipam/views.py +1 -1
- nautobot/project-static/docs/404.html +60 -148
- 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 +60 -148
- nautobot/project-static/docs/apps/nautobot-apps.html +60 -148
- nautobot/project-static/docs/assets/javascripts/workers/{search.07f07601.min.js → search.6ce7567c.min.js} +3 -3
- nautobot/project-static/docs/assets/javascripts/workers/{search.07f07601.min.js.map → search.6ce7567c.min.js.map} +2 -2
- nautobot/project-static/docs/code-reference/nautobot/apps/__init__.html +60 -148
- nautobot/project-static/docs/code-reference/nautobot/apps/admin.html +60 -148
- nautobot/project-static/docs/code-reference/nautobot/apps/api.html +60 -148
- nautobot/project-static/docs/code-reference/nautobot/apps/change_logging.html +60 -148
- nautobot/project-static/docs/code-reference/nautobot/apps/choices.html +60 -148
- nautobot/project-static/docs/code-reference/nautobot/apps/config.html +60 -148
- nautobot/project-static/docs/code-reference/nautobot/apps/constants.html +60 -148
- nautobot/project-static/docs/code-reference/nautobot/apps/datasources.html +60 -148
- nautobot/project-static/docs/code-reference/nautobot/apps/exceptions.html +60 -148
- nautobot/project-static/docs/code-reference/nautobot/apps/factory.html +60 -148
- nautobot/project-static/docs/code-reference/nautobot/apps/filters.html +60 -148
- nautobot/project-static/docs/code-reference/nautobot/apps/forms.html +60 -148
- nautobot/project-static/docs/code-reference/nautobot/apps/graphql.html +60 -148
- nautobot/project-static/docs/code-reference/nautobot/apps/jobs.html +60 -148
- nautobot/project-static/docs/code-reference/nautobot/apps/models.html +60 -148
- nautobot/project-static/docs/code-reference/nautobot/apps/querysets.html +60 -148
- nautobot/project-static/docs/code-reference/nautobot/apps/secrets.html +60 -148
- nautobot/project-static/docs/code-reference/nautobot/apps/tables.html +60 -148
- nautobot/project-static/docs/code-reference/nautobot/apps/testing.html +60 -148
- nautobot/project-static/docs/code-reference/nautobot/apps/ui.html +60 -148
- nautobot/project-static/docs/code-reference/nautobot/apps/urls.html +60 -148
- nautobot/project-static/docs/code-reference/nautobot/apps/utils.html +60 -148
- nautobot/project-static/docs/code-reference/nautobot/apps/views.html +60 -148
- 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 +60 -148
- nautobot/project-static/docs/development/apps/api/database-backend-config.html +60 -148
- nautobot/project-static/docs/development/apps/api/models/django-admin.html +60 -148
- nautobot/project-static/docs/development/apps/api/models/global-search.html +60 -148
- nautobot/project-static/docs/development/apps/api/models/graphql.html +60 -148
- nautobot/project-static/docs/development/apps/api/models/index.html +60 -148
- nautobot/project-static/docs/development/apps/api/nautobot-app-config.html +60 -148
- nautobot/project-static/docs/development/apps/api/platform-features/custom-validators.html +60 -148
- nautobot/project-static/docs/development/apps/api/platform-features/filter-extensions.html +60 -148
- nautobot/project-static/docs/development/apps/api/platform-features/git-repository-content.html +60 -148
- nautobot/project-static/docs/development/apps/api/platform-features/index.html +60 -148
- nautobot/project-static/docs/development/apps/api/platform-features/jinja2-filters.html +60 -148
- nautobot/project-static/docs/development/apps/api/platform-features/jobs.html +60 -148
- nautobot/project-static/docs/development/apps/api/platform-features/populating-extensibility-features.html +60 -148
- nautobot/project-static/docs/development/apps/api/platform-features/secrets-providers.html +60 -148
- nautobot/project-static/docs/development/apps/api/platform-features/uniquely-identify-objects.html +62 -150
- nautobot/project-static/docs/development/apps/api/prometheus.html +60 -148
- nautobot/project-static/docs/development/apps/api/setup.html +60 -148
- nautobot/project-static/docs/development/apps/api/testing.html +61 -149
- nautobot/project-static/docs/development/apps/api/ui-extensions/banners.html +60 -148
- nautobot/project-static/docs/development/apps/api/ui-extensions/home-page.html +60 -148
- nautobot/project-static/docs/development/apps/api/ui-extensions/index.html +60 -148
- nautobot/project-static/docs/development/apps/api/ui-extensions/navigation.html +60 -148
- nautobot/project-static/docs/development/apps/api/ui-extensions/object-views.html +60 -148
- nautobot/project-static/docs/development/apps/api/views/base-template.html +60 -148
- nautobot/project-static/docs/development/apps/api/views/core-view-overrides.html +60 -148
- nautobot/project-static/docs/development/apps/api/views/django-generic-views.html +60 -148
- nautobot/project-static/docs/development/apps/api/views/help-documentation.html +60 -148
- nautobot/project-static/docs/development/apps/api/views/index.html +60 -148
- nautobot/project-static/docs/development/apps/api/views/nautobot-generic-views.html +60 -148
- nautobot/project-static/docs/development/apps/api/views/nautobotuiviewset.html +60 -148
- nautobot/project-static/docs/development/apps/api/views/nautobotuiviewsetrouter.html +60 -148
- nautobot/project-static/docs/development/apps/api/views/notes.html +60 -148
- nautobot/project-static/docs/development/apps/api/views/rest-api.html +60 -148
- nautobot/project-static/docs/development/apps/api/views/urls.html +60 -148
- nautobot/project-static/docs/development/apps/index.html +61 -149
- nautobot/project-static/docs/development/apps/migration/code-updates.html +60 -148
- nautobot/project-static/docs/development/apps/migration/dependency-updates.html +60 -148
- nautobot/project-static/docs/development/apps/migration/from-v1.html +60 -148
- nautobot/project-static/docs/development/apps/migration/model-updates/dcim.html +60 -148
- nautobot/project-static/docs/development/apps/migration/model-updates/extras.html +60 -148
- nautobot/project-static/docs/development/apps/migration/model-updates/global.html +60 -148
- nautobot/project-static/docs/development/apps/migration/model-updates/ipam.html +60 -148
- nautobot/project-static/docs/development/apps/porting-from-netbox.html +60 -148
- nautobot/project-static/docs/development/core/application-registry.html +60 -148
- nautobot/project-static/docs/development/core/best-practices.html +60 -148
- nautobot/project-static/docs/development/core/bootstrap-ui.html +60 -148
- nautobot/project-static/docs/development/core/caching.html +60 -148
- nautobot/project-static/docs/development/core/controllers.html +60 -148
- nautobot/project-static/docs/development/core/docker-compose-advanced-use-cases.html +60 -148
- nautobot/project-static/docs/development/core/generic-views.html +60 -148
- nautobot/project-static/docs/development/core/getting-started.html +85 -169
- nautobot/project-static/docs/development/core/homepage.html +60 -148
- nautobot/project-static/docs/development/core/index.html +60 -148
- nautobot/project-static/docs/development/core/model-checklist.html +60 -148
- nautobot/project-static/docs/development/core/model-features.html +60 -148
- nautobot/project-static/docs/development/core/natural-keys.html +60 -148
- nautobot/project-static/docs/development/core/navigation-menu.html +60 -148
- nautobot/project-static/docs/development/core/release-checklist.html +60 -148
- nautobot/project-static/docs/development/core/role-internals.html +60 -148
- nautobot/project-static/docs/development/core/settings.html +60 -148
- nautobot/project-static/docs/development/core/style-guide.html +60 -148
- nautobot/project-static/docs/development/core/templates.html +60 -148
- nautobot/project-static/docs/development/core/testing.html +72 -152
- nautobot/project-static/docs/development/core/user-preferences.html +60 -148
- nautobot/project-static/docs/development/index.html +60 -148
- nautobot/project-static/docs/development/jobs/index.html +68 -156
- nautobot/project-static/docs/development/jobs/migration/from-v1.html +61 -149
- nautobot/project-static/docs/docker/index.html +3 -3
- nautobot/project-static/docs/index.html +60 -148
- nautobot/project-static/docs/installation/selinux-troubleshooting.html +3 -3
- nautobot/project-static/docs/overview/application_stack.html +60 -148
- nautobot/project-static/docs/overview/design_philosophy.html +60 -148
- nautobot/project-static/docs/release-notes/index.html +60 -148
- nautobot/project-static/docs/release-notes/version-1.0.html +60 -148
- nautobot/project-static/docs/release-notes/version-1.1.html +61 -149
- nautobot/project-static/docs/release-notes/version-1.2.html +63 -151
- nautobot/project-static/docs/release-notes/version-1.3.html +61 -149
- nautobot/project-static/docs/release-notes/version-1.4.html +62 -150
- nautobot/project-static/docs/release-notes/version-1.5.html +62 -150
- nautobot/project-static/docs/release-notes/version-1.6.html +64 -152
- nautobot/project-static/docs/release-notes/version-2.0.html +61 -149
- nautobot/project-static/docs/release-notes/version-2.1.html +62 -150
- nautobot/project-static/docs/release-notes/version-2.2.html +60 -148
- nautobot/project-static/docs/release-notes/version-2.3.html +475 -236
- nautobot/project-static/docs/search/search_index.json +1 -1
- nautobot/project-static/docs/sitemap.xml +277 -285
- nautobot/project-static/docs/sitemap.xml.gz +0 -0
- nautobot/project-static/docs/user-guide/administration/configuration/authentication/ldap.html +62 -150
- nautobot/project-static/docs/user-guide/administration/configuration/authentication/remote.html +61 -149
- nautobot/project-static/docs/user-guide/administration/configuration/authentication/sso.html +62 -150
- nautobot/project-static/docs/user-guide/administration/configuration/index.html +71 -169
- 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 +64 -152
- nautobot/project-static/docs/user-guide/administration/guides/caching.html +13 -9108
- nautobot/project-static/docs/user-guide/administration/guides/celery-queues.html +61 -149
- 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 +64 -152
- nautobot/project-static/docs/user-guide/administration/guides/prometheus-metrics.html +61 -149
- nautobot/project-static/docs/user-guide/administration/guides/replicating-nautobot.html +61 -149
- nautobot/project-static/docs/user-guide/administration/guides/request-profiling.html +60 -148
- nautobot/project-static/docs/user-guide/administration/guides/s3-django-storage.html +60 -148
- nautobot/project-static/docs/user-guide/administration/guides/selinux-troubleshooting.html +8978 -0
- nautobot/project-static/docs/user-guide/administration/installation/app-install.html +60 -148
- nautobot/project-static/docs/user-guide/administration/installation/docker.html +3 -3
- nautobot/project-static/docs/user-guide/administration/installation/external-authentication.html +63 -151
- nautobot/project-static/docs/user-guide/administration/installation/health-checks.html +3 -3
- nautobot/project-static/docs/user-guide/administration/installation/http-server.html +61 -151
- nautobot/project-static/docs/user-guide/administration/installation/index.html +62 -150
- nautobot/project-static/docs/user-guide/administration/installation/install_system.html +60 -148
- nautobot/project-static/docs/user-guide/administration/installation/nautobot.html +76 -161
- nautobot/project-static/docs/user-guide/administration/installation/selinux-troubleshooting.html +3 -3
- nautobot/project-static/docs/user-guide/administration/installation/services.html +62 -150
- 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 +62 -150
- nautobot/project-static/docs/user-guide/administration/migration/migrating-from-postgresql.html +60 -148
- nautobot/project-static/docs/user-guide/administration/tools/nautobot-server.html +66 -154
- nautobot/project-static/docs/user-guide/administration/tools/nautobot-shell.html +63 -151
- nautobot/project-static/docs/user-guide/administration/upgrading/database-backup.html +66 -154
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/after-you-upgrade.html +63 -151
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/before-you-upgrade.html +63 -151
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/for-developers.html +63 -151
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/index.html +63 -151
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/whats-changed.html +63 -151
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/region-and-site-data-migration-guide.html +63 -151
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/upgrading-from-nautobot-v1.html +65 -153
- nautobot/project-static/docs/user-guide/administration/upgrading/upgrading.html +63 -151
- nautobot/project-static/docs/user-guide/core-data-model/circuits/circuit.html +60 -148
- nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittermination.html +60 -148
- nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittype.html +60 -148
- nautobot/project-static/docs/user-guide/core-data-model/circuits/provider.html +60 -148
- nautobot/project-static/docs/user-guide/core-data-model/circuits/providernetwork.html +60 -148
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloud.html +60 -148
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudaccount.html +60 -148
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudnetwork.html +60 -148
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudnetworkprefixassignment.html +60 -148
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudresourcetype.html +60 -148
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudservice.html +60 -148
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudservicenetworkassignment.html +60 -148
- nautobot/project-static/docs/user-guide/core-data-model/dcim/cable.html +60 -148
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleport.html +60 -148
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleporttemplate.html +60 -148
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverport.html +60 -148
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverporttemplate.html +60 -148
- nautobot/project-static/docs/user-guide/core-data-model/dcim/controller.html +60 -148
- nautobot/project-static/docs/user-guide/core-data-model/dcim/controllermanageddevicegroup.html +60 -148
- nautobot/project-static/docs/user-guide/core-data-model/dcim/device.html +60 -148
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebay.html +60 -148
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebaytemplate.html +60 -148
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicefamily.html +60 -148
- nautobot/project-static/docs/user-guide/core-data-model/dcim/deviceredundancygroup.html +60 -148
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicetype.html +60 -148
- nautobot/project-static/docs/user-guide/core-data-model/dcim/frontport.html +60 -148
- nautobot/project-static/docs/user-guide/core-data-model/dcim/frontporttemplate.html +60 -148
- nautobot/project-static/docs/user-guide/core-data-model/dcim/interface.html +60 -148
- nautobot/project-static/docs/user-guide/core-data-model/dcim/interfaceredundancygroup.html +60 -148
- nautobot/project-static/docs/user-guide/core-data-model/dcim/interfacetemplate.html +60 -148
- nautobot/project-static/docs/user-guide/core-data-model/dcim/inventoryitem.html +60 -148
- nautobot/project-static/docs/user-guide/core-data-model/dcim/location.html +60 -148
- nautobot/project-static/docs/user-guide/core-data-model/dcim/locationtype.html +60 -148
- nautobot/project-static/docs/user-guide/core-data-model/dcim/manufacturer.html +60 -148
- nautobot/project-static/docs/user-guide/core-data-model/dcim/module.html +60 -148
- nautobot/project-static/docs/user-guide/core-data-model/dcim/modulebay.html +60 -148
- nautobot/project-static/docs/user-guide/core-data-model/dcim/modulebaytemplate.html +60 -148
- nautobot/project-static/docs/user-guide/core-data-model/dcim/moduletype.html +60 -148
- nautobot/project-static/docs/user-guide/core-data-model/dcim/platform.html +61 -149
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerfeed.html +60 -148
- nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlet.html +60 -148
- nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlettemplate.html +60 -148
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerpanel.html +60 -148
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerport.html +60 -148
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerporttemplate.html +60 -148
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rack.html +60 -148
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rackgroup.html +60 -148
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rackreservation.html +60 -148
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rearport.html +60 -148
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rearporttemplate.html +60 -148
- nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareimagefile.html +60 -148
- nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareversion.html +60 -148
- nautobot/project-static/docs/user-guide/core-data-model/dcim/virtualchassis.html +60 -148
- nautobot/project-static/docs/user-guide/core-data-model/extras/configcontext.html +61 -149
- nautobot/project-static/docs/user-guide/core-data-model/extras/configcontextschema.html +60 -148
- nautobot/project-static/docs/user-guide/core-data-model/extras/contact.html +60 -148
- nautobot/project-static/docs/user-guide/core-data-model/extras/team.html +60 -148
- nautobot/project-static/docs/user-guide/core-data-model/ipam/ipaddress.html +60 -148
- nautobot/project-static/docs/user-guide/core-data-model/ipam/namespace.html +60 -148
- nautobot/project-static/docs/user-guide/core-data-model/ipam/prefix.html +60 -148
- nautobot/project-static/docs/user-guide/core-data-model/ipam/rir.html +60 -148
- nautobot/project-static/docs/user-guide/core-data-model/ipam/routetarget.html +60 -148
- nautobot/project-static/docs/user-guide/core-data-model/ipam/service.html +60 -148
- nautobot/project-static/docs/user-guide/core-data-model/ipam/vlan.html +60 -148
- nautobot/project-static/docs/user-guide/core-data-model/ipam/vlangroup.html +60 -148
- nautobot/project-static/docs/user-guide/core-data-model/ipam/vrf.html +60 -148
- nautobot/project-static/docs/user-guide/core-data-model/overview/introduction.html +60 -148
- nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenant.html +60 -148
- nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenantgroup.html +60 -148
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/cluster.html +60 -148
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustergroup.html +60 -148
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustertype.html +60 -148
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/virtualmachine.html +60 -148
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/vminterface.html +60 -148
- nautobot/project-static/docs/user-guide/feature-guides/contacts-and-teams.html +60 -148
- nautobot/project-static/docs/user-guide/feature-guides/custom-fields.html +60 -148
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-devices.html +60 -148
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-location-types-and-locations.html +60 -148
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/index.html +60 -148
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/interfaces.html +60 -148
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/ipam.html +60 -148
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/platforms.html +60 -148
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/search-bar.html +60 -148
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/tenants.html +60 -148
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/vlans-and-vlan-groups.html +60 -148
- nautobot/project-static/docs/user-guide/feature-guides/git-data-source.html +61 -149
- nautobot/project-static/docs/user-guide/feature-guides/graphql.html +60 -148
- nautobot/project-static/docs/user-guide/feature-guides/ip-address-merge-tool.html +60 -148
- nautobot/project-static/docs/user-guide/feature-guides/relationships.html +60 -148
- nautobot/project-static/docs/user-guide/feature-guides/software-image-files-and-versions.html +60 -148
- nautobot/project-static/docs/user-guide/index.html +60 -148
- nautobot/project-static/docs/user-guide/platform-functionality/change-logging.html +60 -148
- nautobot/project-static/docs/user-guide/platform-functionality/computedfield.html +60 -148
- nautobot/project-static/docs/user-guide/platform-functionality/customfield.html +60 -148
- nautobot/project-static/docs/user-guide/platform-functionality/customlink.html +60 -148
- nautobot/project-static/docs/user-guide/platform-functionality/dynamicgroup.html +61 -149
- nautobot/project-static/docs/user-guide/platform-functionality/exporttemplate.html +60 -148
- nautobot/project-static/docs/user-guide/platform-functionality/externalintegration.html +60 -148
- nautobot/project-static/docs/user-guide/platform-functionality/gitrepository.html +61 -149
- nautobot/project-static/docs/user-guide/platform-functionality/graphql.html +62 -150
- nautobot/project-static/docs/user-guide/platform-functionality/graphqlquery.html +60 -148
- nautobot/project-static/docs/user-guide/platform-functionality/imageattachment.html +61 -149
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/index.html +60 -148
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/job-scheduling-and-approvals.html +60 -148
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobbutton.html +60 -148
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobhook.html +60 -148
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/models.html +60 -148
- nautobot/project-static/docs/user-guide/platform-functionality/napalm.html +61 -149
- nautobot/project-static/docs/user-guide/platform-functionality/note.html +60 -148
- nautobot/project-static/docs/user-guide/platform-functionality/objectmetadata.html +60 -148
- nautobot/project-static/docs/user-guide/platform-functionality/relationship.html +60 -148
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/authentication.html +61 -149
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/filtering.html +61 -149
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/overview.html +62 -150
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/ui-related-endpoints.html +60 -148
- nautobot/project-static/docs/user-guide/platform-functionality/role.html +60 -148
- nautobot/project-static/docs/user-guide/platform-functionality/savedview.html +60 -148
- nautobot/project-static/docs/user-guide/platform-functionality/secret.html +60 -148
- nautobot/project-static/docs/user-guide/platform-functionality/staticgroupassociation.html +60 -148
- nautobot/project-static/docs/user-guide/platform-functionality/status.html +60 -148
- nautobot/project-static/docs/user-guide/platform-functionality/tag.html +60 -148
- nautobot/project-static/docs/user-guide/platform-functionality/template-filters.html +60 -148
- nautobot/project-static/docs/user-guide/platform-functionality/users/objectpermission.html +60 -148
- nautobot/project-static/docs/user-guide/platform-functionality/users/token.html +60 -148
- nautobot/project-static/docs/user-guide/platform-functionality/webhook.html +60 -148
- nautobot/virtualization/filters.py +6 -1
- nautobot/virtualization/tables.py +2 -2
- {nautobot-2.3.3.dist-info → nautobot-2.3.5.dist-info}/METADATA +2 -2
- {nautobot-2.3.3.dist-info → nautobot-2.3.5.dist-info}/RECORD +332 -328
- nautobot/project-static/docs/user-guide/administration/configuration/render-settings-fragment.j2 +0 -76
- {nautobot-2.3.3.dist-info → nautobot-2.3.5.dist-info}/LICENSE.txt +0 -0
- {nautobot-2.3.3.dist-info → nautobot-2.3.5.dist-info}/NOTICE +0 -0
- {nautobot-2.3.3.dist-info → nautobot-2.3.5.dist-info}/WHEEL +0 -0
- {nautobot-2.3.3.dist-info → nautobot-2.3.5.dist-info}/entry_points.txt +0 -0
nautobot/dcim/views.py
CHANGED
|
@@ -3148,7 +3148,7 @@ class DeviceBayPopulateView(generic.ObjectEditView):
|
|
|
3148
3148
|
f"Added {device_bay.installed_device} to {device_bay}.",
|
|
3149
3149
|
)
|
|
3150
3150
|
|
|
3151
|
-
return redirect("dcim:
|
|
3151
|
+
return redirect("dcim:device_devicebays", pk=device_bay.device.pk)
|
|
3152
3152
|
|
|
3153
3153
|
return render(
|
|
3154
3154
|
request,
|
|
@@ -3191,7 +3191,7 @@ class DeviceBayDepopulateView(generic.ObjectEditView):
|
|
|
3191
3191
|
f"Removed {removed_device} from {device_bay}.",
|
|
3192
3192
|
)
|
|
3193
3193
|
|
|
3194
|
-
return redirect("dcim:
|
|
3194
|
+
return redirect("dcim:device_devicebays", pk=device_bay.device.pk)
|
|
3195
3195
|
|
|
3196
3196
|
return render(
|
|
3197
3197
|
request,
|
|
@@ -4139,9 +4139,12 @@ class DeviceFamilyUIViewSet(NautobotUIViewSet):
|
|
|
4139
4139
|
context["device_type_table"] = device_type_table
|
|
4140
4140
|
|
|
4141
4141
|
total_devices = 0
|
|
4142
|
+
device_type_count = 0
|
|
4142
4143
|
for device_type in device_types:
|
|
4143
4144
|
total_devices += device_type.device_count
|
|
4145
|
+
device_type_count += 1
|
|
4144
4146
|
context["total_devices"] = total_devices
|
|
4147
|
+
context["device_type_count"] = device_type_count
|
|
4145
4148
|
|
|
4146
4149
|
return context
|
|
4147
4150
|
|
nautobot/extras/api/views.py
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
from django.conf import settings
|
|
2
2
|
from django.contrib.contenttypes.models import ContentType
|
|
3
|
+
from django.db.models import ProtectedError
|
|
3
4
|
from django.forms import ValidationError as FormsValidationError
|
|
4
5
|
from django.http import FileResponse, Http404
|
|
5
6
|
from django.shortcuts import get_object_or_404
|
|
@@ -729,6 +730,14 @@ class JobViewSet(
|
|
|
729
730
|
):
|
|
730
731
|
lookup_value_regex = r"[-0-9a-fA-F]+"
|
|
731
732
|
|
|
733
|
+
def perform_destroy(self, obj):
|
|
734
|
+
if obj.module_name.startswith("nautobot."):
|
|
735
|
+
raise ProtectedError(
|
|
736
|
+
f"Unable to delete Job {obj}. System Job cannot be deleted",
|
|
737
|
+
[],
|
|
738
|
+
)
|
|
739
|
+
super().perform_destroy(obj)
|
|
740
|
+
|
|
732
741
|
|
|
733
742
|
@extend_schema_view(
|
|
734
743
|
destroy=extend_schema(operation_id="extras_jobs_destroy_by_name"),
|
nautobot/extras/models/jobs.py
CHANGED
|
@@ -11,7 +11,7 @@ from django.contrib.contenttypes.models import ContentType
|
|
|
11
11
|
from django.core.exceptions import ValidationError
|
|
12
12
|
from django.core.validators import MinValueValidator
|
|
13
13
|
from django.db import models, transaction
|
|
14
|
-
from django.db.models import signals
|
|
14
|
+
from django.db.models import ProtectedError, signals
|
|
15
15
|
from django.utils import timezone
|
|
16
16
|
from django.utils.functional import cached_property
|
|
17
17
|
from django_celery_beat.clockedschedule import clocked
|
|
@@ -234,6 +234,14 @@ class Job(PrimaryModel):
|
|
|
234
234
|
def __str__(self):
|
|
235
235
|
return self.name
|
|
236
236
|
|
|
237
|
+
def delete(self):
|
|
238
|
+
if self.module_name.startswith("nautobot."):
|
|
239
|
+
raise ProtectedError(
|
|
240
|
+
f"Unable to delete Job {self}. System Job cannot be deleted",
|
|
241
|
+
[],
|
|
242
|
+
)
|
|
243
|
+
super().delete()
|
|
244
|
+
|
|
237
245
|
@property
|
|
238
246
|
def job_class(self):
|
|
239
247
|
"""
|
nautobot/extras/querysets.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
from django.conf import settings
|
|
2
2
|
from django.contrib.contenttypes.models import ContentType
|
|
3
|
-
from django.db.models import F, Model, OuterRef, Q, Subquery
|
|
3
|
+
from django.db.models import F, Model, OuterRef, ProtectedError, Q, Subquery
|
|
4
4
|
from django.db.models.functions import JSONObject
|
|
5
5
|
|
|
6
6
|
from nautobot.core.models.query_functions import EmptyGroupByJSONBAgg
|
|
@@ -224,6 +224,15 @@ class JobQuerySet(RestrictedQuerySet):
|
|
|
224
224
|
Extend the standard queryset with a get_for_class_path method.
|
|
225
225
|
"""
|
|
226
226
|
|
|
227
|
+
def delete(self):
|
|
228
|
+
for job in self:
|
|
229
|
+
if job.module_name.startswith("nautobot."):
|
|
230
|
+
raise ProtectedError(
|
|
231
|
+
f"Unable to delete Job {job}. System Job cannot be deleted",
|
|
232
|
+
[],
|
|
233
|
+
)
|
|
234
|
+
return super().delete()
|
|
235
|
+
|
|
227
236
|
def get_for_class_path(self, class_path):
|
|
228
237
|
try:
|
|
229
238
|
module_name, job_class_name = class_path.rsplit(".", 1)
|
nautobot/extras/tables.py
CHANGED
|
@@ -1031,6 +1031,9 @@ class ObjectMetadataTable(BaseTable):
|
|
|
1031
1031
|
class NoteTable(BaseTable):
|
|
1032
1032
|
actions = ButtonsColumn(Note)
|
|
1033
1033
|
created = tables.LinkColumn()
|
|
1034
|
+
note = tables.Column(
|
|
1035
|
+
attrs={"td": {"class": "rendered-markdown"}},
|
|
1036
|
+
)
|
|
1034
1037
|
|
|
1035
1038
|
class Meta(BaseTable.Meta):
|
|
1036
1039
|
model = Note
|
|
@@ -1388,6 +1388,42 @@ class JobTest(
|
|
|
1388
1388
|
job_model = Job.objects.get_for_class_path(class_path)
|
|
1389
1389
|
return reverse("extras-api:job-run", kwargs={"pk": job_model.pk})
|
|
1390
1390
|
|
|
1391
|
+
def get_deletable_object(self):
|
|
1392
|
+
"""
|
|
1393
|
+
Get an instance that can be deleted.
|
|
1394
|
+
Exclude system jobs
|
|
1395
|
+
"""
|
|
1396
|
+
# filter out the system jobs:
|
|
1397
|
+
queryset = self._get_queryset().exclude(module_name__startswith="nautobot.")
|
|
1398
|
+
instance = get_deletable_objects(self.model, queryset).first()
|
|
1399
|
+
if instance is None:
|
|
1400
|
+
self.fail("Couldn't find a single deletable object!")
|
|
1401
|
+
return instance
|
|
1402
|
+
|
|
1403
|
+
def get_deletable_object_pks(self):
|
|
1404
|
+
"""
|
|
1405
|
+
Get a list of PKs corresponding to jobs that can be safely bulk-deleted.
|
|
1406
|
+
Exclude system jobs
|
|
1407
|
+
"""
|
|
1408
|
+
queryset = self._get_queryset().exclude(module_name__startswith="nautobot.")
|
|
1409
|
+
instances = get_deletable_objects(self.model, queryset).values_list("pk", flat=True)[:3]
|
|
1410
|
+
if len(instances) < 3:
|
|
1411
|
+
self.fail(f"Couldn't find 3 deletable objects, only found {len(instances)}!")
|
|
1412
|
+
return instances
|
|
1413
|
+
|
|
1414
|
+
def test_delete_system_jobs_fail(self):
|
|
1415
|
+
self.add_permissions("extras.delete_job")
|
|
1416
|
+
instance = self._get_queryset().filter(module_name__startswith="nautobot.").first()
|
|
1417
|
+
job_name = instance.name
|
|
1418
|
+
url = self._get_detail_url(instance)
|
|
1419
|
+
self.client.delete(url, **self.header)
|
|
1420
|
+
# assert Job still exists
|
|
1421
|
+
self.assertTrue(self._get_queryset().filter(name=job_name).exists())
|
|
1422
|
+
self.user.is_superuser = True
|
|
1423
|
+
self.client.delete(url, **self.header)
|
|
1424
|
+
# assert Job still exists
|
|
1425
|
+
self.assertTrue(self._get_queryset().filter(name=job_name).exists())
|
|
1426
|
+
|
|
1391
1427
|
def test_get_job_variables(self):
|
|
1392
1428
|
"""Test the job/<pk>/variables API endpoint."""
|
|
1393
1429
|
self.add_permissions("extras.view_job")
|
|
@@ -18,7 +18,7 @@ from nautobot.core.choices import ColorChoices
|
|
|
18
18
|
from nautobot.core.models.fields import slugify_dashes_to_underscores
|
|
19
19
|
from nautobot.core.templatetags.helpers import bettertitle
|
|
20
20
|
from nautobot.core.testing import extract_form_failures, extract_page_body, ModelViewTestCase, TestCase, ViewTestCases
|
|
21
|
-
from nautobot.core.testing.utils import disable_warnings, post_data
|
|
21
|
+
from nautobot.core.testing.utils import disable_warnings, get_deletable_objects, post_data
|
|
22
22
|
from nautobot.core.utils.permissions import get_permission_for_model
|
|
23
23
|
from nautobot.dcim.models import (
|
|
24
24
|
ConsolePort,
|
|
@@ -1840,6 +1840,9 @@ class ApprovalQueueTestCase(
|
|
|
1840
1840
|
return reverse("extras:scheduledjob_approval_request_view", kwargs={"pk": instance.pk})
|
|
1841
1841
|
raise ValueError("This override is only valid for list and view test cases")
|
|
1842
1842
|
|
|
1843
|
+
def get_list_url(self):
|
|
1844
|
+
return reverse("extras:scheduledjob_approval_queue_list")
|
|
1845
|
+
|
|
1843
1846
|
def setUp(self):
|
|
1844
1847
|
super().setUp()
|
|
1845
1848
|
self.job_model = Job.objects.get_for_class_path("dry_run.TestDryRun")
|
|
@@ -2363,6 +2366,78 @@ class JobTestCase(
|
|
|
2363
2366
|
"clear_task_queues_override": False,
|
|
2364
2367
|
}
|
|
2365
2368
|
|
|
2369
|
+
def get_deletable_object(self):
|
|
2370
|
+
"""
|
|
2371
|
+
Get an instance that can be deleted.
|
|
2372
|
+
Exclude system jobs
|
|
2373
|
+
"""
|
|
2374
|
+
# filter out the system jobs:
|
|
2375
|
+
queryset = self._get_queryset().exclude(module_name__startswith="nautobot.")
|
|
2376
|
+
return get_deletable_objects(self.model, queryset).first()
|
|
2377
|
+
|
|
2378
|
+
def get_deletable_object_pks(self):
|
|
2379
|
+
"""
|
|
2380
|
+
Get a list of PKs corresponding to jobs that can be safely bulk-deleted.
|
|
2381
|
+
Excluding system jobs
|
|
2382
|
+
"""
|
|
2383
|
+
queryset = self._get_queryset().exclude(module_name__startswith="nautobot.")
|
|
2384
|
+
return get_deletable_objects(self.model, queryset).values_list("pk", flat=True)[:3]
|
|
2385
|
+
|
|
2386
|
+
def test_delete_system_jobs_fail(self):
|
|
2387
|
+
instance = self._get_queryset().filter(module_name__startswith="nautobot.").first()
|
|
2388
|
+
job_name = instance.name
|
|
2389
|
+
request = {
|
|
2390
|
+
"path": self._get_url("delete", instance),
|
|
2391
|
+
"data": post_data({"confirm": True}),
|
|
2392
|
+
}
|
|
2393
|
+
|
|
2394
|
+
# Try delete with delete job permission
|
|
2395
|
+
self.add_permissions("extras.delete_job")
|
|
2396
|
+
response = self.client.post(**request, follow=True)
|
|
2397
|
+
self.assertHttpStatus(response, 403)
|
|
2398
|
+
response_body = extract_page_body(response.content.decode(response.charset))
|
|
2399
|
+
self.assertIn(f"Unable to delete Job {instance}. System Job cannot be deleted", response_body)
|
|
2400
|
+
# assert Job still exists
|
|
2401
|
+
self.assertTrue(self._get_queryset().filter(name=job_name).exists())
|
|
2402
|
+
|
|
2403
|
+
# Try delete as a superuser
|
|
2404
|
+
self.user.is_superuser = True
|
|
2405
|
+
response = self.client.post(**request, follow=True)
|
|
2406
|
+
self.assertHttpStatus(response, 403)
|
|
2407
|
+
response_body = extract_page_body(response.content.decode(response.charset))
|
|
2408
|
+
self.assertIn(f"Unable to delete Job {instance}. System Job cannot be deleted", response_body)
|
|
2409
|
+
# assert Job still exists
|
|
2410
|
+
self.assertTrue(self._get_queryset().filter(name=job_name).exists())
|
|
2411
|
+
|
|
2412
|
+
def test_bulk_delete_system_jobs_fail(self):
|
|
2413
|
+
system_job_queryset = self.model.objects.filter(module_name__startswith="nautobot.")
|
|
2414
|
+
pk_list = system_job_queryset.values_list("pk", flat=True)[:3]
|
|
2415
|
+
initial_count = self._get_queryset().count()
|
|
2416
|
+
data = {
|
|
2417
|
+
"pk": pk_list,
|
|
2418
|
+
"confirm": True,
|
|
2419
|
+
"_confirm": True, # Form button
|
|
2420
|
+
}
|
|
2421
|
+
# Try bulk delete with delete job permission
|
|
2422
|
+
self.add_permissions("extras.delete_job")
|
|
2423
|
+
response = self.client.post(self._get_url("bulk_delete"), data, follow=True)
|
|
2424
|
+
self.assertHttpStatus(response, 403)
|
|
2425
|
+
self.assertEqual(self._get_queryset().count(), initial_count)
|
|
2426
|
+
response_body = extract_page_body(response.content.decode(response.charset))
|
|
2427
|
+
self.assertIn(
|
|
2428
|
+
f"Unable to delete Job {system_job_queryset.first()}. System Job cannot be deleted", response_body
|
|
2429
|
+
)
|
|
2430
|
+
|
|
2431
|
+
# Try bulk delete as a superuser
|
|
2432
|
+
self.user.is_superuser = True
|
|
2433
|
+
response = self.client.post(self._get_url("bulk_delete"), data, follow=True)
|
|
2434
|
+
self.assertHttpStatus(response, 403)
|
|
2435
|
+
self.assertEqual(self._get_queryset().count(), initial_count)
|
|
2436
|
+
response_body = extract_page_body(response.content.decode(response.charset))
|
|
2437
|
+
self.assertIn(
|
|
2438
|
+
f"Unable to delete Job {system_job_queryset.first()}. System Job cannot be deleted", response_body
|
|
2439
|
+
)
|
|
2440
|
+
|
|
2366
2441
|
def validate_job_data_after_bulk_edit(self, pk_list, old_data):
|
|
2367
2442
|
# Name is bulk-editable
|
|
2368
2443
|
overridable_fields = [field for field in JOB_OVERRIDABLE_FIELDS if field != "name"]
|
nautobot/extras/views.py
CHANGED
|
@@ -4,7 +4,6 @@ from urllib.parse import parse_qs
|
|
|
4
4
|
from celery import chain
|
|
5
5
|
from django.conf import settings
|
|
6
6
|
from django.contrib import messages
|
|
7
|
-
from django.contrib.auth.models import AnonymousUser
|
|
8
7
|
from django.contrib.contenttypes.models import ContentType
|
|
9
8
|
from django.core.exceptions import ObjectDoesNotExist, ValidationError
|
|
10
9
|
from django.db import IntegrityError, transaction
|
|
@@ -23,6 +22,7 @@ from django.views.generic import View
|
|
|
23
22
|
from django_tables2 import RequestConfig
|
|
24
23
|
from jsonschema.validators import Draft7Validator
|
|
25
24
|
from rest_framework.decorators import action
|
|
25
|
+
from rest_framework.permissions import IsAuthenticated
|
|
26
26
|
|
|
27
27
|
try:
|
|
28
28
|
from zoneinfo import ZoneInfo
|
|
@@ -1650,6 +1650,9 @@ class SavedViewUIViewSet(
|
|
|
1650
1650
|
serializer_class = serializers.SavedViewSerializer
|
|
1651
1651
|
table_class = tables.SavedViewTable
|
|
1652
1652
|
action_buttons = ("export",)
|
|
1653
|
+
permission_classes = [
|
|
1654
|
+
IsAuthenticated,
|
|
1655
|
+
]
|
|
1653
1656
|
|
|
1654
1657
|
def alter_queryset(self, request):
|
|
1655
1658
|
"""
|
|
@@ -1676,15 +1679,15 @@ class SavedViewUIViewSet(
|
|
|
1676
1679
|
|
|
1677
1680
|
def check_permissions(self, request):
|
|
1678
1681
|
"""
|
|
1679
|
-
Override this method to not check any permissions.
|
|
1682
|
+
Override this method to not check any nautobot-specific object permissions and to only check if the user is authenticated.
|
|
1680
1683
|
Since users with <app_label>.view_<model_name> permissions should be able to view saved views related to this model.
|
|
1681
1684
|
And those permissions will be enforced in the related view.
|
|
1682
1685
|
"""
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1686
|
+
for permission in self.get_permissions():
|
|
1687
|
+
if not permission.has_permission(request, self):
|
|
1688
|
+
self.permission_denied(
|
|
1689
|
+
request, message=getattr(permission, "message", None), code=getattr(permission, "code", None)
|
|
1690
|
+
)
|
|
1688
1691
|
|
|
1689
1692
|
def extra_message_context(self, obj):
|
|
1690
1693
|
"""
|
nautobot/ipam/forms.py
CHANGED
|
@@ -873,6 +873,12 @@ class ServiceForm(NautobotModelForm):
|
|
|
873
873
|
base_field=forms.IntegerField(min_value=SERVICE_PORT_MIN, max_value=SERVICE_PORT_MAX),
|
|
874
874
|
help_text="Comma-separated list of one or more port numbers. A range may be specified using a hyphen.",
|
|
875
875
|
)
|
|
876
|
+
ip_addresses = DynamicModelMultipleChoiceField(
|
|
877
|
+
queryset=IPAddress.objects.all(),
|
|
878
|
+
required=False,
|
|
879
|
+
label="IP addresses",
|
|
880
|
+
query_params={"device_id": "$device", "virtual_machine_id": "$virtual_machine"},
|
|
881
|
+
)
|
|
876
882
|
|
|
877
883
|
class Meta:
|
|
878
884
|
model = Service
|
|
@@ -892,7 +898,6 @@ class ServiceForm(NautobotModelForm):
|
|
|
892
898
|
}
|
|
893
899
|
widgets = {
|
|
894
900
|
"protocol": StaticSelect2(),
|
|
895
|
-
"ip_addresses": StaticSelect2Multiple(),
|
|
896
901
|
}
|
|
897
902
|
|
|
898
903
|
def __init__(self, *args, **kwargs):
|
nautobot/ipam/models.py
CHANGED
|
@@ -889,22 +889,16 @@ class Prefix(PrimaryModel):
|
|
|
889
889
|
)
|
|
890
890
|
return available_ips
|
|
891
891
|
|
|
892
|
-
def
|
|
892
|
+
def get_all_ips(self):
|
|
893
893
|
"""
|
|
894
|
-
Return IP addresses
|
|
895
|
-
|
|
896
|
-
In a future release, if this prefix is a pool, it will return IP addresses within the pool's address space.
|
|
894
|
+
Return all IP addresses contained within this prefix, including child prefixes' IP addresses.
|
|
897
895
|
|
|
898
896
|
Returns:
|
|
899
897
|
IPAddress QuerySet
|
|
900
898
|
"""
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
# parent__namespace=self.namespace, host__gte=self.network, host__lte=self.broadcast
|
|
905
|
-
# )
|
|
906
|
-
# else:
|
|
907
|
-
return self.ip_addresses.all()
|
|
899
|
+
return IPAddress.objects.filter(
|
|
900
|
+
parent__namespace=self.namespace, host__gte=self.network, host__lte=self.broadcast
|
|
901
|
+
)
|
|
908
902
|
|
|
909
903
|
def get_first_available_prefix(self):
|
|
910
904
|
"""
|
nautobot/ipam/navigation.py
CHANGED
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
</li>
|
|
34
34
|
{% if perms.ipam.view_ipaddress %}
|
|
35
35
|
<li role="presentation"{% if active_tab == 'ip-addresses' %} class="active"{% endif %}>
|
|
36
|
-
<a href="{% url 'ipam:prefix_ipaddresses' pk=object.pk %}">IP Addresses <span class="badge">{{ object.
|
|
36
|
+
<a href="{% url 'ipam:prefix_ipaddresses' pk=object.pk %}">IP Addresses <span class="badge">{{ object.get_all_ips.count }}</span></a>
|
|
37
37
|
</li>
|
|
38
38
|
{% endif %}
|
|
39
39
|
{% endblock extra_nav_tabs %}
|
|
@@ -1256,7 +1256,7 @@ class VLANLocationAssignmentTestCase(FilterTestCases.FilterTestCase):
|
|
|
1256
1256
|
params = {"q": vlan_vid}
|
|
1257
1257
|
queryset = VLANLocationAssignment.objects.exclude(location__name__icontains=vlan_vid)
|
|
1258
1258
|
filterset = VLANLocationAssignmentFilterSet(params, queryset).qs
|
|
1259
|
-
expected_queryset =
|
|
1259
|
+
expected_queryset = queryset.filter(vlan__vid__exact=vlan_vid)
|
|
1260
1260
|
self.assertQuerysetEqualAndNotEmpty(filterset, expected_queryset)
|
|
1261
1261
|
|
|
1262
1262
|
|
|
@@ -328,6 +328,44 @@ class PrefixTestCase(ViewTestCases.PrimaryObjectViewTestCase, ViewTestCases.List
|
|
|
328
328
|
strip_tags(content),
|
|
329
329
|
)
|
|
330
330
|
|
|
331
|
+
@override_settings(EXEMPT_VIEW_PERMISSIONS=["*"])
|
|
332
|
+
def test_prefix_ipaddresses_table_list_includes_child_ips(self):
|
|
333
|
+
ip_status = Status.objects.get_for_model(IPAddress).first()
|
|
334
|
+
instance = Prefix.objects.create(
|
|
335
|
+
prefix="5.5.10.0/23",
|
|
336
|
+
namespace=self.namespace,
|
|
337
|
+
type=PrefixTypeChoices.TYPE_NETWORK,
|
|
338
|
+
status=self.statuses[1],
|
|
339
|
+
)
|
|
340
|
+
Prefix.objects.create(
|
|
341
|
+
prefix="5.5.10.0/30",
|
|
342
|
+
namespace=self.namespace,
|
|
343
|
+
type=PrefixTypeChoices.TYPE_POOL,
|
|
344
|
+
status=self.statuses[1],
|
|
345
|
+
)
|
|
346
|
+
IPAddress.objects.create(
|
|
347
|
+
address="5.5.10.1/23",
|
|
348
|
+
status=ip_status,
|
|
349
|
+
namespace=self.namespace,
|
|
350
|
+
)
|
|
351
|
+
IPAddress.objects.create(
|
|
352
|
+
address="5.5.10.4/23",
|
|
353
|
+
status=ip_status,
|
|
354
|
+
namespace=self.namespace,
|
|
355
|
+
)
|
|
356
|
+
url = reverse("ipam:prefix_ipaddresses", args=(instance.pk,))
|
|
357
|
+
response = self.client.get(url)
|
|
358
|
+
self.assertHttpStatus(response, 200)
|
|
359
|
+
content = response.content.decode(response.charset)
|
|
360
|
+
# This validates that both parent prefix and child prefix IPAddresses are present in parent prefix IPAddresses list
|
|
361
|
+
self.assertIn("5.5.10.1/23", strip_tags(content))
|
|
362
|
+
self.assertIn("5.5.10.4/23", strip_tags(content))
|
|
363
|
+
print(response.content.decode(response.charset))
|
|
364
|
+
ip_address_tab = (
|
|
365
|
+
f'<li role="presentation" class="active"><a href="{url}">IP Addresses <span class="badge">2</span></a></li>'
|
|
366
|
+
)
|
|
367
|
+
self.assertInHTML(ip_address_tab, content)
|
|
368
|
+
|
|
331
369
|
|
|
332
370
|
class IPAddressTestCase(ViewTestCases.PrimaryObjectViewTestCase):
|
|
333
371
|
model = IPAddress
|
|
@@ -1005,7 +1043,6 @@ class VLANTestCase(ViewTestCases.PrimaryObjectViewTestCase):
|
|
|
1005
1043
|
@classmethod
|
|
1006
1044
|
def setUpTestData(cls):
|
|
1007
1045
|
cls.locations = Location.objects.filter(location_type=LocationType.objects.get(name="Campus"))
|
|
1008
|
-
location_1 = cls.locations.first()
|
|
1009
1046
|
|
|
1010
1047
|
vlangroups = (
|
|
1011
1048
|
VLANGroup.objects.create(name="VLAN Group 1", location=cls.locations.first()),
|
|
@@ -1014,51 +1051,14 @@ class VLANTestCase(ViewTestCases.PrimaryObjectViewTestCase):
|
|
|
1014
1051
|
|
|
1015
1052
|
roles = Role.objects.get_for_model(VLAN)[:2]
|
|
1016
1053
|
|
|
1017
|
-
|
|
1018
|
-
status_1 = statuses[0]
|
|
1019
|
-
status_2 = statuses[1]
|
|
1020
|
-
|
|
1021
|
-
vlans = (
|
|
1022
|
-
VLAN.objects.create(
|
|
1023
|
-
vlan_group=vlangroups[0],
|
|
1024
|
-
vid=101,
|
|
1025
|
-
name="VLAN101",
|
|
1026
|
-
role=roles[0],
|
|
1027
|
-
status=status_1,
|
|
1028
|
-
_custom_field_data={"custom_field": "Value"},
|
|
1029
|
-
),
|
|
1030
|
-
VLAN.objects.create(
|
|
1031
|
-
vlan_group=vlangroups[0],
|
|
1032
|
-
vid=102,
|
|
1033
|
-
name="VLAN102",
|
|
1034
|
-
role=roles[0],
|
|
1035
|
-
status=status_1,
|
|
1036
|
-
_custom_field_data={"custom_field": "Value"},
|
|
1037
|
-
),
|
|
1038
|
-
VLAN.objects.create(
|
|
1039
|
-
vlan_group=vlangroups[0],
|
|
1040
|
-
vid=103,
|
|
1041
|
-
name="VLAN103",
|
|
1042
|
-
role=roles[0],
|
|
1043
|
-
status=status_1,
|
|
1044
|
-
_custom_field_data={"custom_field": "Value"},
|
|
1045
|
-
),
|
|
1046
|
-
)
|
|
1047
|
-
vlans[0].locations.add(location_1)
|
|
1048
|
-
vlans[1].locations.add(location_1)
|
|
1049
|
-
vlans[2].locations.add(location_1)
|
|
1050
|
-
|
|
1051
|
-
custom_field = CustomField.objects.create(
|
|
1052
|
-
type=CustomFieldTypeChoices.TYPE_TEXT, label="Custom Field", default=""
|
|
1053
|
-
)
|
|
1054
|
-
custom_field.content_types.set([ContentType.objects.get_for_model(VLAN)])
|
|
1054
|
+
status = Status.objects.get_for_model(VLAN).first()
|
|
1055
1055
|
|
|
1056
1056
|
cls.form_data = {
|
|
1057
1057
|
"vlan_group": vlangroups[1].pk,
|
|
1058
1058
|
"vid": 999,
|
|
1059
1059
|
"name": "VLAN999 with an unwieldy long name since we increased the limit to more than 64 characters",
|
|
1060
1060
|
"tenant": None,
|
|
1061
|
-
"status":
|
|
1061
|
+
"status": status.pk,
|
|
1062
1062
|
"role": roles[1].pk,
|
|
1063
1063
|
"locations": list(cls.locations.values_list("pk", flat=True)[:2]),
|
|
1064
1064
|
"description": "A new VLAN",
|
|
@@ -1068,7 +1068,7 @@ class VLANTestCase(ViewTestCases.PrimaryObjectViewTestCase):
|
|
|
1068
1068
|
cls.bulk_edit_data = {
|
|
1069
1069
|
"vlan_group": vlangroups[0].pk,
|
|
1070
1070
|
"tenant": Tenant.objects.first().pk,
|
|
1071
|
-
"status":
|
|
1071
|
+
"status": status.pk,
|
|
1072
1072
|
"role": roles[0].pk,
|
|
1073
1073
|
"description": "New description",
|
|
1074
1074
|
}
|
nautobot/ipam/views.py
CHANGED
|
@@ -522,7 +522,7 @@ class PrefixIPAddressesView(generic.ObjectView):
|
|
|
522
522
|
def get_extra_context(self, request, instance):
|
|
523
523
|
# Find all IPAddresses belonging to this Prefix
|
|
524
524
|
ipaddresses = (
|
|
525
|
-
instance.
|
|
525
|
+
instance.get_all_ips()
|
|
526
526
|
.restrict(request.user, "view")
|
|
527
527
|
.select_related("role", "status", "tenant")
|
|
528
528
|
.prefetch_related("primary_ip4_for", "primary_ip6_for")
|