nautobot 2.3.0b1__py3-none-any.whl → 2.3.2__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/cloud/factory.py +2 -0
- nautobot/cloud/filters.py +3 -0
- nautobot/cloud/forms.py +8 -2
- nautobot/cloud/migrations/0001_initial.py +1 -1
- nautobot/cloud/models.py +1 -2
- nautobot/cloud/tables.py +1 -17
- nautobot/cloud/templates/cloud/cloudnetwork_retrieve.html +1 -7
- nautobot/cloud/templates/cloud/cloudresourcetype_retrieve.html +11 -0
- nautobot/cloud/templates/cloud/cloudservice_retrieve.html +4 -0
- nautobot/cloud/tests/test_filters.py +12 -0
- nautobot/cloud/tests/test_views.py +17 -0
- nautobot/cloud/views.py +1 -1
- nautobot/core/celery/__init__.py +5 -2
- nautobot/core/celery/schedulers.py +18 -0
- nautobot/core/filters.py +15 -1
- nautobot/core/forms/forms.py +10 -2
- nautobot/core/graphql/generators.py +2 -2
- nautobot/core/graphql/schema.py +6 -14
- nautobot/core/jobs/__init__.py +4 -1
- nautobot/core/management/commands/generate_test_data.py +2 -2
- nautobot/core/models/__init__.py +2 -2
- nautobot/core/settings.py +13 -2
- nautobot/core/settings.yaml +19 -5
- nautobot/core/tables.py +4 -1
- nautobot/core/templates/generic/object_retrieve.html +6 -6
- nautobot/core/templates/home.html +4 -3
- nautobot/core/templates/inc/computed_fields/panel_data.html +36 -24
- nautobot/core/templates/inc/object_details_advanced_panel.html +1 -1
- nautobot/core/templates/nautobot_config.py.j2 +15 -0
- nautobot/core/templatetags/buttons.py +1 -1
- nautobot/core/testing/filters.py +12 -1
- nautobot/core/tests/integration/test_general_functionality.py +1 -1
- nautobot/core/tests/test_jobs.py +74 -1
- nautobot/core/views/__init__.py +1 -1
- nautobot/core/views/generic.py +1 -1
- nautobot/core/views/mixins.py +1 -1
- nautobot/core/views/utils.py +11 -9
- nautobot/dcim/factory.py +7 -4
- nautobot/dcim/filters/__init__.py +4 -0
- nautobot/dcim/forms.py +24 -0
- nautobot/dcim/migrations/0061_module_models.py +1 -0
- nautobot/dcim/models/device_components.py +7 -0
- nautobot/dcim/models/devices.py +18 -19
- nautobot/dcim/models/racks.py +0 -1
- nautobot/dcim/tables/devices.py +24 -10
- nautobot/dcim/tables/devicetypes.py +1 -1
- nautobot/dcim/templates/dcim/device/base.html +1 -1
- nautobot/dcim/templates/dcim/device.html +15 -3
- nautobot/dcim/templates/dcim/deviceredundancygroup_retrieve.html +6 -0
- nautobot/dcim/templates/dcim/moduletype_retrieve.html +17 -0
- nautobot/dcim/templates/dcim/softwareimagefile_retrieve.html +15 -3
- nautobot/dcim/tests/test_api.py +2 -0
- nautobot/dcim/tests/test_filters.py +14 -7
- nautobot/dcim/tests/test_forms.py +54 -0
- nautobot/dcim/tests/test_models.py +40 -1
- nautobot/dcim/tests/test_views.py +45 -2
- nautobot/dcim/utils.py +9 -6
- nautobot/dcim/views.py +4 -1
- nautobot/extras/api/serializers.py +2 -1
- nautobot/extras/api/views.py +7 -59
- nautobot/extras/factory.py +50 -12
- nautobot/extras/filters/__init__.py +18 -3
- nautobot/extras/forms/base.py +10 -4
- nautobot/extras/forms/forms.py +7 -0
- nautobot/extras/forms/mixins.py +2 -2
- nautobot/extras/homepage.py +12 -2
- nautobot/extras/jobs.py +2 -2
- nautobot/extras/management/__init__.py +3 -0
- nautobot/extras/migrations/0111_metadata.py +4 -4
- nautobot/extras/migrations/0114_computedfield_grouping.py +17 -0
- nautobot/extras/migrations/0115_scheduledjob_time_zone.py +23 -0
- nautobot/extras/models/customfields.py +54 -0
- nautobot/extras/models/jobs.py +105 -9
- nautobot/extras/models/metadata.py +18 -18
- nautobot/extras/models/models.py +2 -0
- nautobot/extras/signals.py +14 -1
- nautobot/extras/tables.py +77 -18
- nautobot/extras/templates/extras/computedfield.html +4 -0
- nautobot/extras/templates/extras/job_detail.html +11 -0
- nautobot/extras/templates/extras/scheduledjob.html +13 -2
- nautobot/extras/tests/test_api.py +33 -27
- nautobot/extras/tests/test_filters.py +57 -1
- nautobot/extras/tests/test_jobs.py +2 -2
- nautobot/extras/tests/test_models.py +319 -19
- nautobot/extras/tests/test_views.py +26 -5
- nautobot/extras/utils.py +35 -6
- nautobot/extras/views.py +35 -51
- nautobot/ipam/api/views.py +9 -2
- nautobot/ipam/choices.py +17 -0
- nautobot/ipam/factory.py +6 -0
- nautobot/ipam/filters.py +2 -2
- nautobot/ipam/forms.py +6 -4
- nautobot/ipam/migrations/0048_vrf_status.py +23 -0
- nautobot/ipam/migrations/0049_vrf_data_migration.py +25 -0
- nautobot/ipam/models.py +11 -20
- nautobot/ipam/querysets.py +26 -0
- nautobot/ipam/tables.py +7 -2
- nautobot/ipam/templates/ipam/vrf.html +4 -0
- nautobot/ipam/templates/ipam/vrf_edit.html +1 -0
- nautobot/ipam/tests/test_api.py +33 -3
- nautobot/ipam/tests/test_models.py +89 -2
- nautobot/ipam/tests/test_views.py +3 -0
- nautobot/ipam/views.py +10 -15
- nautobot/project-static/css/base.css +7 -0
- nautobot/project-static/docs/404.html +18 -18
- nautobot/project-static/docs/apps/index.html +18 -18
- nautobot/project-static/docs/apps/nautobot-apps.html +18 -18
- nautobot/project-static/docs/assets/stylesheets/main.3cba04c6.min.css +1 -0
- nautobot/project-static/docs/assets/stylesheets/main.3cba04c6.min.css.map +1 -0
- nautobot/project-static/docs/code-reference/nautobot/apps/__init__.html +18 -18
- nautobot/project-static/docs/code-reference/nautobot/apps/admin.html +18 -18
- nautobot/project-static/docs/code-reference/nautobot/apps/api.html +66 -18
- nautobot/project-static/docs/code-reference/nautobot/apps/change_logging.html +18 -18
- nautobot/project-static/docs/code-reference/nautobot/apps/choices.html +18 -18
- nautobot/project-static/docs/code-reference/nautobot/apps/config.html +18 -18
- nautobot/project-static/docs/code-reference/nautobot/apps/constants.html +18 -18
- nautobot/project-static/docs/code-reference/nautobot/apps/datasources.html +18 -18
- nautobot/project-static/docs/code-reference/nautobot/apps/exceptions.html +66 -18
- nautobot/project-static/docs/code-reference/nautobot/apps/factory.html +34 -18
- nautobot/project-static/docs/code-reference/nautobot/apps/filters.html +82 -63
- nautobot/project-static/docs/code-reference/nautobot/apps/forms.html +75 -111
- nautobot/project-static/docs/code-reference/nautobot/apps/graphql.html +18 -18
- nautobot/project-static/docs/code-reference/nautobot/apps/jobs.html +34 -18
- nautobot/project-static/docs/code-reference/nautobot/apps/models.html +161 -18
- nautobot/project-static/docs/code-reference/nautobot/apps/querysets.html +18 -18
- nautobot/project-static/docs/code-reference/nautobot/apps/secrets.html +18 -18
- nautobot/project-static/docs/code-reference/nautobot/apps/tables.html +18 -18
- nautobot/project-static/docs/code-reference/nautobot/apps/testing.html +18 -18
- nautobot/project-static/docs/code-reference/nautobot/apps/ui.html +18 -18
- nautobot/project-static/docs/code-reference/nautobot/apps/urls.html +18 -18
- nautobot/project-static/docs/code-reference/nautobot/apps/utils.html +21 -19
- nautobot/project-static/docs/code-reference/nautobot/apps/views.html +34 -18
- nautobot/project-static/docs/development/apps/api/configuration-view.html +18 -18
- nautobot/project-static/docs/development/apps/api/database-backend-config.html +18 -18
- nautobot/project-static/docs/development/apps/api/models/django-admin.html +18 -18
- nautobot/project-static/docs/development/apps/api/models/global-search.html +18 -18
- nautobot/project-static/docs/development/apps/api/models/graphql.html +18 -18
- nautobot/project-static/docs/development/apps/api/models/index.html +33 -22
- nautobot/project-static/docs/development/apps/api/nautobot-app-config.html +18 -18
- nautobot/project-static/docs/development/apps/api/platform-features/custom-validators.html +18 -18
- nautobot/project-static/docs/development/apps/api/platform-features/filter-extensions.html +18 -18
- nautobot/project-static/docs/development/apps/api/platform-features/git-repository-content.html +18 -18
- nautobot/project-static/docs/development/apps/api/platform-features/index.html +18 -18
- nautobot/project-static/docs/development/apps/api/platform-features/jinja2-filters.html +18 -18
- nautobot/project-static/docs/development/apps/api/platform-features/jobs.html +18 -18
- nautobot/project-static/docs/development/apps/api/platform-features/populating-extensibility-features.html +18 -18
- nautobot/project-static/docs/development/apps/api/platform-features/secrets-providers.html +18 -18
- nautobot/project-static/docs/development/apps/api/platform-features/uniquely-identify-objects.html +18 -18
- nautobot/project-static/docs/development/apps/api/prometheus.html +18 -18
- nautobot/project-static/docs/development/apps/api/setup.html +18 -18
- nautobot/project-static/docs/development/apps/api/testing.html +18 -18
- nautobot/project-static/docs/development/apps/api/ui-extensions/banners.html +18 -18
- nautobot/project-static/docs/development/apps/api/ui-extensions/home-page.html +18 -18
- nautobot/project-static/docs/development/apps/api/ui-extensions/index.html +18 -18
- nautobot/project-static/docs/development/apps/api/ui-extensions/navigation.html +18 -18
- nautobot/project-static/docs/development/apps/api/ui-extensions/object-views.html +18 -18
- nautobot/project-static/docs/development/apps/api/views/base-template.html +18 -18
- nautobot/project-static/docs/development/apps/api/views/core-view-overrides.html +18 -18
- nautobot/project-static/docs/development/apps/api/views/django-generic-views.html +18 -18
- nautobot/project-static/docs/development/apps/api/views/help-documentation.html +18 -18
- nautobot/project-static/docs/development/apps/api/views/index.html +18 -18
- nautobot/project-static/docs/development/apps/api/views/nautobot-generic-views.html +18 -18
- nautobot/project-static/docs/development/apps/api/views/nautobotuiviewset.html +18 -18
- nautobot/project-static/docs/development/apps/api/views/nautobotuiviewsetrouter.html +18 -18
- nautobot/project-static/docs/development/apps/api/views/notes.html +18 -18
- nautobot/project-static/docs/development/apps/api/views/rest-api.html +18 -18
- nautobot/project-static/docs/development/apps/api/views/urls.html +18 -18
- nautobot/project-static/docs/development/apps/index.html +18 -18
- nautobot/project-static/docs/development/apps/migration/code-updates.html +18 -18
- nautobot/project-static/docs/development/apps/migration/dependency-updates.html +18 -18
- nautobot/project-static/docs/development/apps/migration/from-v1.html +18 -18
- nautobot/project-static/docs/development/apps/migration/model-updates/dcim.html +18 -18
- nautobot/project-static/docs/development/apps/migration/model-updates/extras.html +18 -18
- nautobot/project-static/docs/development/apps/migration/model-updates/global.html +18 -18
- nautobot/project-static/docs/development/apps/migration/model-updates/ipam.html +18 -18
- nautobot/project-static/docs/development/apps/porting-from-netbox.html +18 -18
- nautobot/project-static/docs/development/core/application-registry.html +18 -18
- nautobot/project-static/docs/development/core/best-practices.html +18 -18
- nautobot/project-static/docs/development/core/bootstrap-ui.html +18 -18
- nautobot/project-static/docs/development/core/caching.html +18 -18
- nautobot/project-static/docs/development/core/controllers.html +18 -18
- nautobot/project-static/docs/development/core/docker-compose-advanced-use-cases.html +18 -18
- nautobot/project-static/docs/development/core/generic-views.html +18 -18
- nautobot/project-static/docs/development/core/getting-started.html +18 -18
- nautobot/project-static/docs/development/core/homepage.html +18 -18
- nautobot/project-static/docs/development/core/index.html +29 -18
- nautobot/project-static/docs/development/core/model-checklist.html +26 -20
- nautobot/project-static/docs/development/core/model-features.html +18 -18
- nautobot/project-static/docs/development/core/natural-keys.html +18 -18
- nautobot/project-static/docs/development/core/navigation-menu.html +18 -18
- nautobot/project-static/docs/development/core/release-checklist.html +18 -18
- nautobot/project-static/docs/development/core/role-internals.html +18 -18
- nautobot/project-static/docs/development/core/settings.html +18 -18
- nautobot/project-static/docs/development/core/style-guide.html +19 -19
- nautobot/project-static/docs/development/core/templates.html +18 -18
- nautobot/project-static/docs/development/core/testing.html +18 -18
- nautobot/project-static/docs/development/core/user-preferences.html +18 -18
- nautobot/project-static/docs/development/index.html +18 -18
- nautobot/project-static/docs/development/jobs/index.html +393 -379
- nautobot/project-static/docs/development/jobs/migration/from-v1.html +18 -18
- nautobot/project-static/docs/index.html +9032 -13
- nautobot/project-static/docs/models/extras/metadatachoice.html +3 -3
- nautobot/project-static/docs/models/extras/metadatatype.html +3 -3
- nautobot/project-static/docs/models/extras/objectmetadata.html +3 -3
- nautobot/project-static/docs/objects.inv +0 -0
- nautobot/project-static/docs/overview/application_stack.html +18 -18
- nautobot/project-static/docs/overview/design_philosophy.html +20 -20
- nautobot/project-static/docs/overview/index.html +13 -9032
- nautobot/project-static/docs/release-notes/index.html +252 -19
- nautobot/project-static/docs/release-notes/version-1.0.html +18 -18
- nautobot/project-static/docs/release-notes/version-1.1.html +18 -18
- nautobot/project-static/docs/release-notes/version-1.2.html +18 -18
- nautobot/project-static/docs/release-notes/version-1.3.html +18 -18
- nautobot/project-static/docs/release-notes/version-1.4.html +18 -18
- nautobot/project-static/docs/release-notes/version-1.5.html +18 -18
- nautobot/project-static/docs/release-notes/version-1.6.html +18 -18
- nautobot/project-static/docs/release-notes/version-2.0.html +18 -18
- nautobot/project-static/docs/release-notes/version-2.1.html +18 -18
- nautobot/project-static/docs/release-notes/version-2.2.html +248 -111
- nautobot/project-static/docs/release-notes/version-2.3.html +775 -91
- nautobot/project-static/docs/requirements.txt +3 -3
- nautobot/project-static/docs/search/search_index.json +1 -1
- nautobot/project-static/docs/sitemap.xml +278 -278
- nautobot/project-static/docs/sitemap.xml.gz +0 -0
- nautobot/project-static/docs/user-guide/administration/configuration/authentication/ldap.html +18 -18
- nautobot/project-static/docs/user-guide/administration/configuration/authentication/remote.html +18 -18
- nautobot/project-static/docs/user-guide/administration/configuration/authentication/sso.html +18 -18
- nautobot/project-static/docs/user-guide/administration/configuration/index.html +18 -18
- nautobot/project-static/docs/user-guide/administration/configuration/optional-settings.html +55 -23
- nautobot/project-static/docs/user-guide/administration/configuration/required-settings.html +18 -18
- nautobot/project-static/docs/user-guide/administration/configuration/time-zones.html +18 -18
- nautobot/project-static/docs/user-guide/administration/guides/caching.html +18 -18
- nautobot/project-static/docs/user-guide/administration/guides/celery-queues.html +22 -18
- nautobot/project-static/docs/user-guide/administration/guides/healthcheck.html +18 -18
- nautobot/project-static/docs/user-guide/administration/guides/permissions.html +18 -18
- nautobot/project-static/docs/user-guide/administration/guides/prometheus-metrics.html +18 -18
- nautobot/project-static/docs/user-guide/administration/guides/replicating-nautobot.html +18 -18
- nautobot/project-static/docs/user-guide/administration/guides/request-profiling.html +18 -18
- nautobot/project-static/docs/user-guide/administration/guides/s3-django-storage.html +18 -18
- nautobot/project-static/docs/user-guide/administration/installation/app-install.html +18 -18
- nautobot/project-static/docs/user-guide/administration/installation/external-authentication.html +18 -18
- nautobot/project-static/docs/user-guide/administration/installation/http-server.html +69 -82
- nautobot/project-static/docs/user-guide/administration/installation/index.html +24 -24
- nautobot/project-static/docs/user-guide/administration/installation/install_system.html +60 -52
- nautobot/project-static/docs/user-guide/administration/installation/nautobot.html +80 -87
- nautobot/project-static/docs/user-guide/administration/installation/services.html +37 -44
- nautobot/project-static/docs/user-guide/administration/installation-extras/docker.html +18 -18
- nautobot/project-static/docs/user-guide/administration/installation-extras/health-checks.html +18 -18
- nautobot/project-static/docs/user-guide/administration/installation-extras/selinux-troubleshooting.html +18 -18
- nautobot/project-static/docs/user-guide/administration/migration/migrating-from-netbox.html +18 -18
- nautobot/project-static/docs/user-guide/administration/migration/migrating-from-postgresql.html +18 -18
- nautobot/project-static/docs/user-guide/administration/tools/nautobot-server.html +76 -24
- nautobot/project-static/docs/user-guide/administration/tools/nautobot-shell.html +18 -18
- nautobot/project-static/docs/user-guide/administration/upgrading/database-backup.html +18 -18
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/after-you-upgrade.html +18 -18
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/before-you-upgrade.html +18 -18
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/for-developers.html +18 -18
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/index.html +18 -18
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/whats-changed.html +18 -18
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/region-and-site-data-migration-guide.html +18 -18
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/upgrading-from-nautobot-v1.html +18 -18
- nautobot/project-static/docs/user-guide/administration/upgrading/upgrading.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/circuits/circuit.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittermination.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittype.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/circuits/provider.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/circuits/providernetwork.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloud.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudaccount.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudnetwork.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudnetworkprefixassignment.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudresourcetype.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudservice.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudservicenetworkassignment.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/dcim/cable.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleport.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleporttemplate.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverport.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverporttemplate.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/dcim/controller.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/dcim/controllermanageddevicegroup.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/dcim/device.html +19 -19
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebay.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebaytemplate.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicefamily.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/dcim/deviceredundancygroup.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicetype.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/dcim/frontport.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/dcim/frontporttemplate.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/dcim/interface.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/dcim/interfaceredundancygroup.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/dcim/interfacetemplate.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/dcim/inventoryitem.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/dcim/location.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/dcim/locationtype.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/dcim/manufacturer.html +19 -19
- nautobot/project-static/docs/user-guide/core-data-model/dcim/module.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/dcim/modulebay.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/dcim/modulebaytemplate.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/dcim/moduletype.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/dcim/platform.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerfeed.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlet.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlettemplate.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerpanel.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerport.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerporttemplate.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rack.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rackgroup.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rackreservation.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rearport.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rearporttemplate.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareimagefile.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareversion.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/dcim/virtualchassis.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/extras/configcontext.html +62 -18
- nautobot/project-static/docs/user-guide/core-data-model/extras/configcontextschema.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/extras/contact.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/extras/team.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/ipam/ipaddress.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/ipam/namespace.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/ipam/prefix.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/ipam/rir.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/ipam/routetarget.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/ipam/service.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/ipam/vlan.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/ipam/vlangroup.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/ipam/vrf.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/overview/introduction.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenant.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenantgroup.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/cluster.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustergroup.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustertype.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/virtualmachine.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/vminterface.html +18 -18
- nautobot/project-static/docs/user-guide/feature-guides/contacts-and-teams.html +18 -18
- nautobot/project-static/docs/user-guide/feature-guides/custom-fields.html +18 -18
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-devices.html +18 -18
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-location-types-and-locations.html +18 -18
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/index.html +18 -18
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/interfaces.html +18 -18
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/ipam.html +18 -18
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/platforms.html +18 -18
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/search-bar.html +18 -18
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/tenants.html +18 -18
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/vlans-and-vlan-groups.html +18 -18
- nautobot/project-static/docs/user-guide/feature-guides/git-data-source.html +18 -18
- nautobot/project-static/docs/user-guide/feature-guides/graphql.html +18 -18
- nautobot/project-static/docs/user-guide/feature-guides/ip-address-merge-tool.html +18 -18
- nautobot/project-static/docs/user-guide/feature-guides/relationships.html +18 -18
- nautobot/project-static/docs/user-guide/feature-guides/software-image-files-and-versions.html +18 -18
- nautobot/project-static/docs/user-guide/index.html +18 -18
- nautobot/project-static/docs/user-guide/platform-functionality/change-logging.html +18 -18
- nautobot/project-static/docs/user-guide/platform-functionality/computedfield.html +18 -18
- nautobot/project-static/docs/user-guide/platform-functionality/customfield.html +18 -18
- nautobot/project-static/docs/user-guide/platform-functionality/customlink.html +18 -18
- nautobot/project-static/docs/user-guide/platform-functionality/dynamicgroup.html +18 -18
- nautobot/project-static/docs/user-guide/platform-functionality/exporttemplate.html +18 -18
- nautobot/project-static/docs/user-guide/platform-functionality/externalintegration.html +18 -18
- nautobot/project-static/docs/user-guide/platform-functionality/gitrepository.html +18 -18
- nautobot/project-static/docs/user-guide/platform-functionality/graphql.html +18 -18
- nautobot/project-static/docs/user-guide/platform-functionality/graphqlquery.html +18 -18
- nautobot/project-static/docs/user-guide/platform-functionality/imageattachment.html +18 -18
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/index.html +18 -18
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/job-scheduling-and-approvals.html +21 -21
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobbutton.html +18 -18
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobhook.html +18 -18
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/models.html +18 -18
- nautobot/project-static/docs/user-guide/platform-functionality/napalm.html +36 -36
- nautobot/project-static/docs/user-guide/platform-functionality/note.html +33 -33
- nautobot/project-static/docs/user-guide/platform-functionality/{metadata.html → objectmetadata.html} +197 -84
- nautobot/project-static/docs/user-guide/platform-functionality/relationship.html +21 -21
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/authentication.html +18 -18
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/filtering.html +18 -18
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/overview.html +18 -18
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/ui-related-endpoints.html +18 -18
- nautobot/project-static/docs/user-guide/platform-functionality/role.html +18 -18
- nautobot/project-static/docs/user-guide/platform-functionality/savedview.html +18 -18
- nautobot/project-static/docs/user-guide/platform-functionality/secret.html +18 -18
- nautobot/project-static/docs/user-guide/platform-functionality/staticgroupassociation.html +18 -18
- nautobot/project-static/docs/user-guide/platform-functionality/status.html +18 -18
- nautobot/project-static/docs/user-guide/platform-functionality/tag.html +18 -18
- nautobot/project-static/docs/user-guide/platform-functionality/template-filters.html +18 -18
- nautobot/project-static/docs/user-guide/platform-functionality/users/objectpermission.html +18 -18
- nautobot/project-static/docs/user-guide/platform-functionality/users/token.html +18 -18
- nautobot/project-static/docs/user-guide/platform-functionality/webhook.html +18 -18
- nautobot/project-static/js/homepage_layout.js +3 -0
- nautobot/tenancy/templates/tenancy/tenant.html +4 -4
- nautobot/virtualization/models.py +0 -2
- nautobot/virtualization/tables.py +2 -5
- {nautobot-2.3.0b1.dist-info → nautobot-2.3.2.dist-info}/METADATA +3 -3
- {nautobot-2.3.0b1.dist-info → nautobot-2.3.2.dist-info}/RECORD +397 -393
- nautobot/project-static/docs/assets/stylesheets/main.76a95c52.min.css +0 -1
- nautobot/project-static/docs/assets/stylesheets/main.76a95c52.min.css.map +0 -1
- {nautobot-2.3.0b1.dist-info → nautobot-2.3.2.dist-info}/LICENSE.txt +0 -0
- {nautobot-2.3.0b1.dist-info → nautobot-2.3.2.dist-info}/NOTICE +0 -0
- {nautobot-2.3.0b1.dist-info → nautobot-2.3.2.dist-info}/WHEEL +0 -0
- {nautobot-2.3.0b1.dist-info → nautobot-2.3.2.dist-info}/entry_points.txt +0 -0
|
@@ -1,25 +1,37 @@
|
|
|
1
|
-
{%
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
</
|
|
1
|
+
{% load helpers %}
|
|
2
|
+
{% if computed_fields %}
|
|
3
|
+
<style>
|
|
4
|
+
.accordion-toggle {
|
|
5
|
+
font-size: 14px;
|
|
6
|
+
}
|
|
7
|
+
</style>
|
|
8
|
+
<div class="panel panel-default">
|
|
9
|
+
<div class="panel-heading">
|
|
10
|
+
<strong>Computed Fields</strong>
|
|
11
|
+
<button type="button" class="btn-xs btn-primary pull-right" id="accordion-toggle-all">Collapse All</button>
|
|
11
12
|
</div>
|
|
12
|
-
|
|
13
|
-
{%
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
{% endif %}
|
|
13
|
+
<table id="accordion" class="table table-hover panel-body attr-table">
|
|
14
|
+
{% for grouping, fields in computed_fields.items %}
|
|
15
|
+
{% with forloop.counter0 as count %}
|
|
16
|
+
{% if grouping != "" %}
|
|
17
|
+
<tr>
|
|
18
|
+
<td colspan="2"><strong>
|
|
19
|
+
<button type="button" class="accordion-toggle mdi mdi-chevron-down"
|
|
20
|
+
name="grouping.{{ grouping }}" data-toggle="collapse"
|
|
21
|
+
data-target=".collapseme-computed-{{ count }}">
|
|
22
|
+
{{ grouping }}
|
|
23
|
+
</button></strong>
|
|
24
|
+
</td>
|
|
25
|
+
</tr>
|
|
26
|
+
{% endif %}
|
|
27
|
+
{% for field, value in fields %}
|
|
28
|
+
<tr class="collapseme-computed-{{ count }} collapse in" data-parent="#accordion">
|
|
29
|
+
<td><span title="{{ field.description }}">{{ field }}</span></td>
|
|
30
|
+
<td>{{ value }}</td>
|
|
31
|
+
</tr>
|
|
32
|
+
{% endfor %}
|
|
33
|
+
{% endwith %}
|
|
34
|
+
{% endfor %}
|
|
35
|
+
</table>
|
|
36
|
+
</div>
|
|
37
|
+
{% endif %}
|
|
@@ -88,6 +88,6 @@
|
|
|
88
88
|
</tbody>
|
|
89
89
|
</table>
|
|
90
90
|
</div>
|
|
91
|
-
{% include 'inc/custom_fields/panel.html' with custom_fields=object.get_custom_field_groupings_advanced computed_fields_advanced_ui=True %}
|
|
91
|
+
{% include 'inc/custom_fields/panel.html' with custom_fields=object.get_custom_field_groupings_advanced computed_fields=object.get_computed_fields_grouping_advanced computed_fields_advanced_ui=True %}
|
|
92
92
|
{% include 'inc/relationships/panel_override.html' with relationships_fields_override=object.get_relationships_data_advanced_fields %}
|
|
93
93
|
{% endif %}
|
|
@@ -295,6 +295,15 @@ SECRET_KEY = os.getenv("NAUTOBOT_SECRET_KEY", "{{ secret_key }}")
|
|
|
295
295
|
# CELERY_TASK_SOFT_TIME_LIMIT = int(os.getenv("NAUTOBOT_CELERY_TASK_SOFT_TIME_LIMIT", str(5 * 60)))
|
|
296
296
|
# CELERY_TASK_TIME_LIMIT = int(os.getenv("NAUTOBOT_CELERY_TASK_TIME_LIMIT", str(10 * 60)))
|
|
297
297
|
|
|
298
|
+
# How many tasks a worker is allowed to reserve for its own consumption and execution.
|
|
299
|
+
# If set to zero (not recommended) a single worker can reserve all tasks even if other workers are free.
|
|
300
|
+
# For short running tasks (such as webhooks) you may want to set this to a larger number to increase throughput.
|
|
301
|
+
# Conversely, for long running tasks (such as SSoT or Golden-Config Jobs at scale) you may want to set this to 1
|
|
302
|
+
# so that a worker executing a long-running task will not prefetch other tasks, which would block their execution
|
|
303
|
+
# until the long-running task completes.
|
|
304
|
+
# https://docs.celeryq.dev/en/stable/userguide/optimizing.html#prefetch-limits
|
|
305
|
+
# CELERY_WORKER_PREFETCH_MULTIPLIER = int(os.getenv("NAUTOBOT_CELERY_WORKER_PREFETCH_MULTIPLIER", "4"))
|
|
306
|
+
|
|
298
307
|
# Ports for prometheus metric HTTP server running on the celery worker.
|
|
299
308
|
# Normally this should be set to a single port, unless you have multiple workers running on a single machine, i.e.
|
|
300
309
|
# sharing the same available ports. In that case you need to specify a range of ports greater than or equal to the
|
|
@@ -307,6 +316,12 @@ SECRET_KEY = os.getenv("NAUTOBOT_SECRET_KEY", "{{ secret_key }}")
|
|
|
307
316
|
# int(value) for value in os.getenv("NAUTOBOT_CELERY_WORKER_PROMETHEUS_PORTS").split(",")
|
|
308
317
|
# ]
|
|
309
318
|
|
|
319
|
+
# If enabled stdout and stderr of running jobs will be redirected to the task logger.
|
|
320
|
+
# CELERY_WORKER_REDIRECT_STDOUTS = is_truthy(os.getenv("NAUTOBOT_CELERY_WORKER_REDIRECT_STDOUTS", "True"))
|
|
321
|
+
|
|
322
|
+
# The log level of log messages generated by redirected job stdout and stderr.
|
|
323
|
+
# Can be one of `DEBUG`, `INFO`, `WARNING`, `ERROR`, or `CRITICAL`.
|
|
324
|
+
# CELERY_WORKER_REDIRECT_STDOUTS_LEVEL = os.getenv("NAUTOBOT_CELERY_WORKER_REDIRECT_STDOUTS_LEVEL", "WARNING")
|
|
310
325
|
|
|
311
326
|
# Number of days to retain changelog entries. Set to 0 to retain changes indefinitely. Defaults to 90 if not set here.
|
|
312
327
|
#
|
|
@@ -165,7 +165,7 @@ def consolidate_bulk_action_buttons(context):
|
|
|
165
165
|
|
|
166
166
|
render_edit_button = bool(context["bulk_edit_url"] and context["permissions"]["change"])
|
|
167
167
|
render_static_group_assign_button = bool(
|
|
168
|
-
context["model"]
|
|
168
|
+
getattr(context["model"], "is_dynamic_group_associable_model", False)
|
|
169
169
|
and context["user"].has_perms(["extras.add_staticgroupassociation"])
|
|
170
170
|
)
|
|
171
171
|
render_delete_button = bool(context["bulk_delete_url"] and context["permissions"]["delete"])
|
nautobot/core/testing/filters.py
CHANGED
|
@@ -132,6 +132,17 @@ class FilterTestCases:
|
|
|
132
132
|
if generic_filter_test not in self.generic_filter_tests:
|
|
133
133
|
self.generic_filter_tests = (*self.generic_filter_tests, generic_filter_test)
|
|
134
134
|
|
|
135
|
+
# Make sure we have at least 3 contacts and 3 teams in the database
|
|
136
|
+
if Contact.objects.count() < 3:
|
|
137
|
+
Contact.objects.create(name="Generic Filter Test Contact 1")
|
|
138
|
+
Contact.objects.create(name="Generic Filter Test Contact 2")
|
|
139
|
+
Contact.objects.create(name="Generic Filter Test Contact 3")
|
|
140
|
+
|
|
141
|
+
if Team.objects.count() < 3:
|
|
142
|
+
Team.objects.create(name="Generic Filter Test Team 1")
|
|
143
|
+
Team.objects.create(name="Generic Filter Test Team 2")
|
|
144
|
+
Team.objects.create(name="Generic Filter Test Team 3")
|
|
145
|
+
|
|
135
146
|
# Make sure we have some valid contact-associations:
|
|
136
147
|
for contact, team, instance in zip(Contact.objects.all()[:3], Team.objects.all()[:3], self.queryset):
|
|
137
148
|
ContactAssociation.objects.create(
|
|
@@ -272,7 +283,7 @@ class FilterTestCases:
|
|
|
272
283
|
# if lookup_method is iexact use the full updated attr
|
|
273
284
|
if lookup_method == "iexact":
|
|
274
285
|
lookup = randomized_attr_value.upper()
|
|
275
|
-
model_queryset = self.queryset.filter(**{f"{filter_field_name}": lookup})
|
|
286
|
+
model_queryset = self.queryset.filter(**{f"{filter_field_name}__iexact": lookup})
|
|
276
287
|
else:
|
|
277
288
|
lookup = randomized_attr_value[1:].upper()
|
|
278
289
|
model_queryset = self.queryset.filter(**{f"{filter_field_name}__icontains": lookup})
|
nautobot/core/tests/test_jobs.py
CHANGED
|
@@ -3,24 +3,27 @@ from pathlib import Path
|
|
|
3
3
|
|
|
4
4
|
from django.contrib.contenttypes.models import ContentType
|
|
5
5
|
from django.core.cache import cache
|
|
6
|
+
from django.core.files.base import ContentFile
|
|
6
7
|
from django.utils import timezone
|
|
7
8
|
import yaml
|
|
8
9
|
|
|
9
10
|
from nautobot.core.jobs.cleanup import CleanupTypes
|
|
10
11
|
from nautobot.core.testing import create_job_result_and_run_job, TransactionTestCase
|
|
11
|
-
from nautobot.dcim.models import DeviceType, Location, LocationType, Manufacturer
|
|
12
|
+
from nautobot.dcim.models import Device, DeviceType, Location, LocationType, Manufacturer
|
|
12
13
|
from nautobot.extras.choices import JobResultStatusChoices, LogLevelChoices
|
|
13
14
|
from nautobot.extras.factory import JobResultFactory, ObjectChangeFactory
|
|
14
15
|
from nautobot.extras.models import (
|
|
15
16
|
Contact,
|
|
16
17
|
ContactAssociation,
|
|
17
18
|
ExportTemplate,
|
|
19
|
+
FileProxy,
|
|
18
20
|
JobLogEntry,
|
|
19
21
|
JobResult,
|
|
20
22
|
ObjectChange,
|
|
21
23
|
Role,
|
|
22
24
|
Status,
|
|
23
25
|
)
|
|
26
|
+
from nautobot.ipam.models import Prefix
|
|
24
27
|
from nautobot.users.models import ObjectPermission
|
|
25
28
|
|
|
26
29
|
|
|
@@ -218,6 +221,76 @@ class ImportObjectsTestCase(TransactionTestCase):
|
|
|
218
221
|
)
|
|
219
222
|
self.assertEqual(4, Status.objects.filter(name__startswith="test_status").count())
|
|
220
223
|
|
|
224
|
+
def test_csv_import_with_utf_8_with_bom_encoding(self):
|
|
225
|
+
"""
|
|
226
|
+
A superuser running the job with a .csv file with utf_8 with bom encoding should successfully create all specified objects.
|
|
227
|
+
Test for bug fix https://github.com/nautobot/nautobot/issues/5812 and https://github.com/nautobot/nautobot/issues/5985
|
|
228
|
+
"""
|
|
229
|
+
|
|
230
|
+
status = Status.objects.get(name="Active").pk
|
|
231
|
+
content = f"prefix,status\n192.168.1.1/32,{status}"
|
|
232
|
+
content = content.encode("utf-8-sig")
|
|
233
|
+
filename = "test.csv"
|
|
234
|
+
csv_file = FileProxy.objects.create(name=filename, file=ContentFile(content, name=filename))
|
|
235
|
+
job_result = create_job_result_and_run_job(
|
|
236
|
+
"nautobot.core.jobs",
|
|
237
|
+
"ImportObjects",
|
|
238
|
+
content_type=ContentType.objects.get_for_model(Prefix).pk,
|
|
239
|
+
csv_file=csv_file.id,
|
|
240
|
+
)
|
|
241
|
+
self.assertEqual(job_result.status, JobResultStatusChoices.STATUS_SUCCESS)
|
|
242
|
+
self.assertFalse(
|
|
243
|
+
JobLogEntry.objects.filter(job_result=job_result, log_level=LogLevelChoices.LOG_WARNING).exists()
|
|
244
|
+
)
|
|
245
|
+
self.assertFalse(
|
|
246
|
+
JobLogEntry.objects.filter(job_result=job_result, log_level=LogLevelChoices.LOG_ERROR).exists()
|
|
247
|
+
)
|
|
248
|
+
self.assertEqual(
|
|
249
|
+
1, Prefix.objects.filter(status=Status.objects.get(name="Active"), prefix="192.168.1.1/32").count()
|
|
250
|
+
)
|
|
251
|
+
mfr = Manufacturer.objects.create(name="Test Cisco Manufacturer")
|
|
252
|
+
device_type = DeviceType.objects.create(
|
|
253
|
+
manufacturer=mfr,
|
|
254
|
+
model="Cisco CSR1000v",
|
|
255
|
+
u_height=0,
|
|
256
|
+
)
|
|
257
|
+
location_type = LocationType.objects.create(name="Test Location Type")
|
|
258
|
+
location_type.content_types.set([ContentType.objects.get_for_model(Device)])
|
|
259
|
+
location = Location.objects.create(
|
|
260
|
+
name="Device Location",
|
|
261
|
+
location_type=location_type,
|
|
262
|
+
status=Status.objects.get_for_model(Location).first(),
|
|
263
|
+
)
|
|
264
|
+
role = Role.objects.create(name="Device Status")
|
|
265
|
+
role.content_types.set([ContentType.objects.get_for_model(Device)])
|
|
266
|
+
content = "\n".join(
|
|
267
|
+
[
|
|
268
|
+
"serial,asset_tag,device_type,location,status,name,role",
|
|
269
|
+
f"1021C4,CA211,{device_type.pk},{location.pk},{status},Test-AC-01,{role}",
|
|
270
|
+
f"1021C5,CA212,{device_type.pk},{location.pk},{status},Test-AC-02,{role}",
|
|
271
|
+
]
|
|
272
|
+
)
|
|
273
|
+
content = content.encode("utf-8-sig")
|
|
274
|
+
filename = "test.csv"
|
|
275
|
+
csv_file = FileProxy.objects.create(name=filename, file=ContentFile(content, name=filename))
|
|
276
|
+
job_result = create_job_result_and_run_job(
|
|
277
|
+
"nautobot.core.jobs",
|
|
278
|
+
"ImportObjects",
|
|
279
|
+
content_type=ContentType.objects.get_for_model(Device).pk,
|
|
280
|
+
csv_file=csv_file.id,
|
|
281
|
+
)
|
|
282
|
+
self.assertEqual(job_result.status, JobResultStatusChoices.STATUS_SUCCESS)
|
|
283
|
+
self.assertFalse(
|
|
284
|
+
JobLogEntry.objects.filter(job_result=job_result, log_level=LogLevelChoices.LOG_WARNING).exists()
|
|
285
|
+
)
|
|
286
|
+
self.assertFalse(
|
|
287
|
+
JobLogEntry.objects.filter(job_result=job_result, log_level=LogLevelChoices.LOG_ERROR).exists()
|
|
288
|
+
)
|
|
289
|
+
device_1 = Device.objects.get(name="Test-AC-01")
|
|
290
|
+
device_2 = Device.objects.get(name="Test-AC-02")
|
|
291
|
+
self.assertEqual(device_1.serial, "1021C4")
|
|
292
|
+
self.assertEqual(device_2.serial, "1021C5")
|
|
293
|
+
|
|
221
294
|
def test_csv_import_bad_row(self):
|
|
222
295
|
"""A row of incorrect data should fail validation for that object but import all others successfully if `roll_back_if_error` is False."""
|
|
223
296
|
csv_data = self.csv_data.split("\n")
|
nautobot/core/views/__init__.py
CHANGED
|
@@ -299,7 +299,7 @@ class SearchView(AccessMixin, View):
|
|
|
299
299
|
|
|
300
300
|
# Construct the results table for this object type
|
|
301
301
|
filtered_queryset = filterset({"q": form.cleaned_data["q"]}, queryset=queryset).qs
|
|
302
|
-
table = table(filtered_queryset, orderable=False)
|
|
302
|
+
table = table(filtered_queryset, hide_hierarchy_ui=True, orderable=False)
|
|
303
303
|
table.paginate(per_page=SEARCH_MAX_RESULTS)
|
|
304
304
|
|
|
305
305
|
if table.page:
|
nautobot/core/views/generic.py
CHANGED
|
@@ -586,6 +586,7 @@ class ObjectDeleteView(GetReturnURLMixin, ObjectPermissionRequiredMixin, View):
|
|
|
586
586
|
|
|
587
587
|
if form.is_valid():
|
|
588
588
|
logger.debug("Form validation was successful")
|
|
589
|
+
msg = f"Deleted {self.queryset.model._meta.verbose_name} {obj}"
|
|
589
590
|
|
|
590
591
|
try:
|
|
591
592
|
obj.delete()
|
|
@@ -594,7 +595,6 @@ class ObjectDeleteView(GetReturnURLMixin, ObjectPermissionRequiredMixin, View):
|
|
|
594
595
|
handle_protectederror([obj], request, e)
|
|
595
596
|
return redirect(obj.get_absolute_url())
|
|
596
597
|
|
|
597
|
-
msg = f"Deleted {self.queryset.model._meta.verbose_name} {obj}"
|
|
598
598
|
logger.info(msg)
|
|
599
599
|
messages.success(request, msg)
|
|
600
600
|
|
nautobot/core/views/mixins.py
CHANGED
|
@@ -745,8 +745,8 @@ class ObjectDestroyViewMixin(NautobotViewSetMixin, mixins.DestroyModelMixin):
|
|
|
745
745
|
queryset = self.get_queryset()
|
|
746
746
|
try:
|
|
747
747
|
with transaction.atomic():
|
|
748
|
-
obj.delete()
|
|
749
748
|
msg = f"Deleted {queryset.model._meta.verbose_name} {obj}"
|
|
749
|
+
obj.delete()
|
|
750
750
|
self.logger.info(msg)
|
|
751
751
|
messages.success(request, msg)
|
|
752
752
|
self.success_url = self.get_return_url(request, obj)
|
nautobot/core/views/utils.py
CHANGED
|
@@ -337,7 +337,7 @@ def common_detail_view_context(request, instance):
|
|
|
337
337
|
context["created_by"] = created_by
|
|
338
338
|
context["last_updated_by"] = last_updated_by
|
|
339
339
|
|
|
340
|
-
if instance
|
|
340
|
+
if getattr(instance, "is_contact_associable_model", False):
|
|
341
341
|
paginate = {"paginator_class": EnhancedPaginator, "per_page": get_paginate_count(request)}
|
|
342
342
|
associations = instance.associated_contacts.restrict(request.user, "view").order_by("role__name")
|
|
343
343
|
associations_table = AssociatedContactsTable(associations, orderable=False)
|
|
@@ -347,7 +347,7 @@ def common_detail_view_context(request, instance):
|
|
|
347
347
|
else:
|
|
348
348
|
context["associated_contacts_table"] = None
|
|
349
349
|
|
|
350
|
-
if instance
|
|
350
|
+
if getattr(instance, "is_dynamic_group_associable_model", False):
|
|
351
351
|
paginate = {"paginator_class": EnhancedPaginator, "per_page": get_paginate_count(request)}
|
|
352
352
|
dynamic_groups = instance.dynamic_groups.restrict(request.user, "view")
|
|
353
353
|
dynamic_groups_table = DynamicGroupTable(dynamic_groups, orderable=False)
|
|
@@ -358,14 +358,16 @@ def common_detail_view_context(request, instance):
|
|
|
358
358
|
else:
|
|
359
359
|
context["associated_dynamic_groups_table"] = None
|
|
360
360
|
|
|
361
|
-
if instance
|
|
361
|
+
if getattr(instance, "is_metadata_associable_model", False):
|
|
362
362
|
paginate = {"paginator_class": EnhancedPaginator, "per_page": get_paginate_count(request)}
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
363
|
+
object_metadata = instance.associated_object_metadata.restrict(request.user, "view").order_by(
|
|
364
|
+
"metadata_type", "scoped_fields"
|
|
365
|
+
)
|
|
366
|
+
object_metadata_table = ObjectMetadataTable(object_metadata, orderable=False)
|
|
367
|
+
object_metadata_table.columns.hide("assigned_object")
|
|
368
|
+
RequestConfig(request, paginate).configure(object_metadata_table)
|
|
369
|
+
context["associated_object_metadata_table"] = object_metadata_table
|
|
368
370
|
else:
|
|
369
|
-
context["
|
|
371
|
+
context["associated_object_metadata_table"] = None
|
|
370
372
|
|
|
371
373
|
return context
|
nautobot/dcim/factory.py
CHANGED
|
@@ -110,7 +110,7 @@ NETWORK_DRIVERS = {
|
|
|
110
110
|
"Palo Alto": ["paloalto_panos"],
|
|
111
111
|
}
|
|
112
112
|
|
|
113
|
-
TIME_ZONES =
|
|
113
|
+
TIME_ZONES = sorted(timezone for timezone, _ in TimeZoneFormField().choices)
|
|
114
114
|
|
|
115
115
|
|
|
116
116
|
# Retrieve correct rack reservation units
|
|
@@ -296,7 +296,7 @@ class DeviceTypeFactory(PrimaryModelFactory):
|
|
|
296
296
|
while not unused_models:
|
|
297
297
|
unused_models = {f"{device_type} {count}" for device_type in device_types}.difference(current_models)
|
|
298
298
|
count += 1
|
|
299
|
-
return factory.random.randgen.choice(
|
|
299
|
+
return factory.random.randgen.choice(sorted(unused_models))
|
|
300
300
|
|
|
301
301
|
has_part_number = NautobotBoolIterator()
|
|
302
302
|
part_number = factory.Maybe("has_part_number", factory.Faker("ean", length=8), "")
|
|
@@ -760,13 +760,16 @@ module_types = (
|
|
|
760
760
|
class ModuleTypeFactory(PrimaryModelFactory):
|
|
761
761
|
class Meta:
|
|
762
762
|
model = ModuleType
|
|
763
|
-
exclude = ("has_part_number",)
|
|
763
|
+
exclude = ("has_part_number", "has_comments")
|
|
764
764
|
|
|
765
765
|
manufacturer = random_instance(Manufacturer, allow_null=False)
|
|
766
766
|
|
|
767
767
|
has_part_number = NautobotBoolIterator()
|
|
768
768
|
part_number = factory.Maybe("has_part_number", factory.Faker("ean", length=8), "")
|
|
769
769
|
|
|
770
|
+
has_comments = NautobotBoolIterator()
|
|
771
|
+
comments = factory.Maybe("has_comments", factory.Faker("bs"))
|
|
772
|
+
|
|
770
773
|
@factory.lazy_attribute
|
|
771
774
|
def model(self):
|
|
772
775
|
"""
|
|
@@ -781,7 +784,7 @@ class ModuleTypeFactory(PrimaryModelFactory):
|
|
|
781
784
|
while not unused_models:
|
|
782
785
|
unused_models = {f"{module_type} {count}" for module_type in module_types}.difference(current_models)
|
|
783
786
|
count += 1
|
|
784
|
-
return factory.random.randgen.choice(
|
|
787
|
+
return factory.random.randgen.choice(sorted(unused_models))
|
|
785
788
|
|
|
786
789
|
|
|
787
790
|
class ModuleFactory(PrimaryModelFactory):
|
|
@@ -1999,6 +1999,10 @@ class ModuleTypeFilterSet(DeviceTypeModuleTypeCommonFiltersMixin, NautobotFilter
|
|
|
1999
1999
|
"lookup_expr": "icontains",
|
|
2000
2000
|
"preprocessor": str.strip,
|
|
2001
2001
|
},
|
|
2002
|
+
"comments": {
|
|
2003
|
+
"lookup_expr": "icontains",
|
|
2004
|
+
"preprocessor": str.strip,
|
|
2005
|
+
},
|
|
2002
2006
|
},
|
|
2003
2007
|
)
|
|
2004
2008
|
has_modules = RelatedMembershipBooleanFilter(
|
nautobot/dcim/forms.py
CHANGED
|
@@ -886,6 +886,7 @@ class DeviceTypeBulkEditForm(TagsBulkEditFormMixin, NautobotBulkEditForm):
|
|
|
886
886
|
software_image_files = DynamicModelMultipleChoiceField(queryset=SoftwareImageFile.objects.all(), required=False)
|
|
887
887
|
u_height = forms.IntegerField(required=False)
|
|
888
888
|
is_full_depth = forms.NullBooleanField(required=False, widget=BulkEditNullBooleanSelect(), label="Is full depth")
|
|
889
|
+
comments = CommentField(label="Comments", required=False)
|
|
889
890
|
|
|
890
891
|
class Meta:
|
|
891
892
|
nullable_fields = ["device_family", "software_image_files"]
|
|
@@ -946,6 +947,7 @@ class DeviceTypeFilterForm(NautobotFilterForm):
|
|
|
946
947
|
|
|
947
948
|
class ModuleTypeForm(NautobotModelForm):
|
|
948
949
|
manufacturer = DynamicModelChoiceField(queryset=Manufacturer.objects.all())
|
|
950
|
+
comments = CommentField(label="Comments")
|
|
949
951
|
|
|
950
952
|
class Meta:
|
|
951
953
|
model = ModuleType
|
|
@@ -953,6 +955,7 @@ class ModuleTypeForm(NautobotModelForm):
|
|
|
953
955
|
"manufacturer",
|
|
954
956
|
"model",
|
|
955
957
|
"part_number",
|
|
958
|
+
"comments",
|
|
956
959
|
"tags",
|
|
957
960
|
]
|
|
958
961
|
|
|
@@ -974,6 +977,7 @@ class ModuleTypeImportForm(BootstrapMixin, forms.ModelForm):
|
|
|
974
977
|
"manufacturer",
|
|
975
978
|
"model",
|
|
976
979
|
"part_number",
|
|
980
|
+
"comments",
|
|
977
981
|
]
|
|
978
982
|
|
|
979
983
|
|
|
@@ -981,6 +985,7 @@ class ModuleTypeBulkEditForm(TagsBulkEditFormMixin, NautobotBulkEditForm):
|
|
|
981
985
|
pk = forms.ModelMultipleChoiceField(queryset=ModuleType.objects.all(), widget=forms.MultipleHiddenInput())
|
|
982
986
|
manufacturer = DynamicModelChoiceField(queryset=Manufacturer.objects.all(), required=False)
|
|
983
987
|
part_number = forms.CharField(required=False)
|
|
988
|
+
comments = CommentField(label="Comments", required=False)
|
|
984
989
|
|
|
985
990
|
class Meta:
|
|
986
991
|
nullable_fields = []
|
|
@@ -2059,6 +2064,25 @@ class DeviceForm(LocatableModelFormMixin, NautobotModelForm, TenancyForm, LocalC
|
|
|
2059
2064
|
if position:
|
|
2060
2065
|
self.fields["position"].widget.choices = [(position, f"U{position}")]
|
|
2061
2066
|
|
|
2067
|
+
def clean(self):
|
|
2068
|
+
super().clean()
|
|
2069
|
+
|
|
2070
|
+
device_type = self.cleaned_data["device_type"]
|
|
2071
|
+
software_image_files = self.cleaned_data["software_image_files"]
|
|
2072
|
+
|
|
2073
|
+
# If any software image file is specified, validate that
|
|
2074
|
+
# each of the software image files belongs to the device's device type or is a default image
|
|
2075
|
+
for image_file in software_image_files:
|
|
2076
|
+
if not image_file.default_image and device_type not in image_file.device_types.all():
|
|
2077
|
+
raise ValidationError(
|
|
2078
|
+
{
|
|
2079
|
+
"software_image_files": (
|
|
2080
|
+
f"Software image file {image_file} for version '{image_file.software_version}' is not "
|
|
2081
|
+
f"valid for device type {device_type}."
|
|
2082
|
+
)
|
|
2083
|
+
}
|
|
2084
|
+
)
|
|
2085
|
+
|
|
2062
2086
|
def save(self, *args, **kwargs):
|
|
2063
2087
|
instance = super().save(*args, **kwargs)
|
|
2064
2088
|
instance.vrfs.set(self.cleaned_data["vrfs"])
|
|
@@ -138,6 +138,7 @@ class Migration(migrations.Migration):
|
|
|
138
138
|
),
|
|
139
139
|
("model", models.CharField(max_length=255)),
|
|
140
140
|
("part_number", models.CharField(blank=True, max_length=255)),
|
|
141
|
+
("comments", models.TextField(blank=True)),
|
|
141
142
|
],
|
|
142
143
|
options={
|
|
143
144
|
"ordering": ("manufacturer", "model"),
|
|
@@ -26,6 +26,7 @@ from nautobot.dcim.choices import (
|
|
|
26
26
|
PowerOutletFeedLegChoices,
|
|
27
27
|
PowerOutletTypeChoices,
|
|
28
28
|
PowerPortTypeChoices,
|
|
29
|
+
SubdeviceRoleChoices,
|
|
29
30
|
)
|
|
30
31
|
from nautobot.dcim.constants import (
|
|
31
32
|
NONCONNECTABLE_IFACE_TYPES,
|
|
@@ -1096,6 +1097,12 @@ class DeviceBay(ComponentModel):
|
|
|
1096
1097
|
"installed_device": f"Cannot install the specified device; device is already installed in {current_bay}"
|
|
1097
1098
|
}
|
|
1098
1099
|
)
|
|
1100
|
+
if self.installed_device.device_type.subdevice_role != SubdeviceRoleChoices.ROLE_CHILD:
|
|
1101
|
+
raise ValidationError(
|
|
1102
|
+
{
|
|
1103
|
+
"installed_device": f'Cannot install device "{self.installed_device}"; device-type "{self.installed_device.device_type}" subdevice_role is not "child".'
|
|
1104
|
+
}
|
|
1105
|
+
)
|
|
1099
1106
|
|
|
1100
1107
|
|
|
1101
1108
|
#
|
nautobot/dcim/models/devices.py
CHANGED
|
@@ -452,7 +452,6 @@ class Platform(OrganizationalModel):
|
|
|
452
452
|
@extras_features(
|
|
453
453
|
"custom_links",
|
|
454
454
|
"custom_validators",
|
|
455
|
-
"dynamic_groups",
|
|
456
455
|
"export_templates",
|
|
457
456
|
"graphql",
|
|
458
457
|
"locations",
|
|
@@ -819,21 +818,18 @@ class Device(PrimaryModel, ConfigContextModel):
|
|
|
819
818
|
}
|
|
820
819
|
)
|
|
821
820
|
|
|
822
|
-
#
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
)
|
|
835
|
-
}
|
|
836
|
-
)
|
|
821
|
+
# If any software image file is specified, validate that
|
|
822
|
+
# each of the software image files belongs to the device's device type or is a default image
|
|
823
|
+
for image_file in self.software_image_files.all():
|
|
824
|
+
if not image_file.default_image and self.device_type not in image_file.device_types.all():
|
|
825
|
+
raise ValidationError(
|
|
826
|
+
{
|
|
827
|
+
"software_image_files": (
|
|
828
|
+
f"Software image file {image_file} for version '{image_file.software_version}' is not "
|
|
829
|
+
f"valid for device type {self.device_type}."
|
|
830
|
+
)
|
|
831
|
+
}
|
|
832
|
+
)
|
|
837
833
|
|
|
838
834
|
def save(self, *args, **kwargs):
|
|
839
835
|
is_new = not self.present_in_database
|
|
@@ -1109,7 +1105,6 @@ class VirtualChassis(PrimaryModel):
|
|
|
1109
1105
|
@extras_features(
|
|
1110
1106
|
"custom_links",
|
|
1111
1107
|
"custom_validators",
|
|
1112
|
-
"dynamic_groups",
|
|
1113
1108
|
"export_templates",
|
|
1114
1109
|
"graphql",
|
|
1115
1110
|
"statuses",
|
|
@@ -1155,6 +1150,10 @@ class DeviceRedundancyGroup(PrimaryModel):
|
|
|
1155
1150
|
def devices_sorted(self):
|
|
1156
1151
|
return self.devices.order_by("device_redundancy_group_priority")
|
|
1157
1152
|
|
|
1153
|
+
@property
|
|
1154
|
+
def controllers_sorted(self):
|
|
1155
|
+
return self.controllers.order_by("name")
|
|
1156
|
+
|
|
1158
1157
|
def __str__(self):
|
|
1159
1158
|
return self.name
|
|
1160
1159
|
|
|
@@ -1337,7 +1336,6 @@ class SoftwareVersion(PrimaryModel):
|
|
|
1337
1336
|
@extras_features(
|
|
1338
1337
|
"custom_links",
|
|
1339
1338
|
"custom_validators",
|
|
1340
|
-
"dynamic_groups",
|
|
1341
1339
|
"export_templates",
|
|
1342
1340
|
"graphql",
|
|
1343
1341
|
"locations",
|
|
@@ -1421,7 +1419,6 @@ class Controller(PrimaryModel):
|
|
|
1421
1419
|
@extras_features(
|
|
1422
1420
|
"custom_links",
|
|
1423
1421
|
"custom_validators",
|
|
1424
|
-
"dynamic_groups",
|
|
1425
1422
|
"export_templates",
|
|
1426
1423
|
"graphql",
|
|
1427
1424
|
"webhooks",
|
|
@@ -1510,6 +1507,7 @@ class ModuleType(PrimaryModel):
|
|
|
1510
1507
|
part_number = models.CharField(
|
|
1511
1508
|
max_length=CHARFIELD_MAX_LENGTH, blank=True, help_text="Discrete part number (optional)"
|
|
1512
1509
|
)
|
|
1510
|
+
comments = models.TextField(blank=True)
|
|
1513
1511
|
|
|
1514
1512
|
clone_fields = [
|
|
1515
1513
|
"manufacturer",
|
|
@@ -1530,6 +1528,7 @@ class ModuleType(PrimaryModel):
|
|
|
1530
1528
|
("manufacturer", self.manufacturer.name),
|
|
1531
1529
|
("model", self.model),
|
|
1532
1530
|
("part_number", self.part_number),
|
|
1531
|
+
("comments", self.comments),
|
|
1533
1532
|
)
|
|
1534
1533
|
)
|
|
1535
1534
|
|