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
nautobot/extras/views.py
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
from datetime import timedelta
|
|
2
1
|
import logging
|
|
3
2
|
from urllib.parse import parse_qs
|
|
4
3
|
|
|
5
4
|
from celery import chain
|
|
5
|
+
from django.conf import settings
|
|
6
6
|
from django.contrib import messages
|
|
7
7
|
from django.contrib.auth.models import AnonymousUser
|
|
8
8
|
from django.contrib.contenttypes.models import ContentType
|
|
@@ -24,6 +24,11 @@ from django_tables2 import RequestConfig
|
|
|
24
24
|
from jsonschema.validators import Draft7Validator
|
|
25
25
|
from rest_framework.decorators import action
|
|
26
26
|
|
|
27
|
+
try:
|
|
28
|
+
from zoneinfo import ZoneInfo
|
|
29
|
+
except ImportError: # python 3.8
|
|
30
|
+
from backports.zoneinfo import ZoneInfo
|
|
31
|
+
|
|
27
32
|
from nautobot.core.forms import restrict_form_fields
|
|
28
33
|
from nautobot.core.models.querysets import count_related
|
|
29
34
|
from nautobot.core.models.utils import pretty_print_query
|
|
@@ -1388,55 +1393,25 @@ class JobRunView(ObjectPermissionRequiredMixin, View):
|
|
|
1388
1393
|
schedule_type = schedule_form.cleaned_data["_schedule_type"]
|
|
1389
1394
|
|
|
1390
1395
|
if (not dryrun and job_model.approval_required) or schedule_type in JobExecutionType.SCHEDULE_CHOICES:
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
# as a once in the future task with the due date set to the current time. This means
|
|
1397
|
-
# when approval is granted, the task is immediately due for execution.
|
|
1398
|
-
schedule_type = JobExecutionType.TYPE_FUTURE
|
|
1399
|
-
schedule_datetime = timezone.now()
|
|
1400
|
-
schedule_name = f"{job_model} - {schedule_datetime}"
|
|
1401
|
-
|
|
1402
|
-
else:
|
|
1403
|
-
schedule_name = schedule_form.cleaned_data["_schedule_name"]
|
|
1404
|
-
|
|
1405
|
-
if schedule_type == JobExecutionType.TYPE_CUSTOM:
|
|
1406
|
-
crontab = schedule_form.cleaned_data["_recurrence_custom_time"]
|
|
1407
|
-
# doing .get("key", "default") returns None instead of "default" here for some reason
|
|
1408
|
-
schedule_datetime = schedule_form.cleaned_data.get("_schedule_start_time")
|
|
1409
|
-
if schedule_datetime is None:
|
|
1410
|
-
# "_schedule_start_time" is checked against ScheduledJob.earliest_possible_time()
|
|
1411
|
-
# which returns timezone.now() + timedelta(seconds=15)
|
|
1412
|
-
schedule_datetime = timezone.now() + timedelta(seconds=20)
|
|
1413
|
-
else:
|
|
1414
|
-
schedule_datetime = schedule_form.cleaned_data["_schedule_start_time"]
|
|
1415
|
-
|
|
1416
|
-
celery_kwargs = {"nautobot_job_profile": profile, "queue": task_queue}
|
|
1417
|
-
scheduled_job = ScheduledJob(
|
|
1418
|
-
name=schedule_name,
|
|
1419
|
-
task=job_model.class_path,
|
|
1420
|
-
job_model=job_model,
|
|
1421
|
-
start_time=schedule_datetime,
|
|
1422
|
-
description=f"Nautobot job {schedule_name} scheduled by {request.user} for {schedule_datetime}",
|
|
1423
|
-
kwargs=job_class.serialize_data(job_form.cleaned_data),
|
|
1424
|
-
celery_kwargs=celery_kwargs,
|
|
1396
|
+
scheduled_job = ScheduledJob.create_schedule(
|
|
1397
|
+
job_model,
|
|
1398
|
+
request.user,
|
|
1399
|
+
name=schedule_form.cleaned_data.get("_schedule_name"),
|
|
1400
|
+
start_time=schedule_form.cleaned_data.get("_schedule_start_time"),
|
|
1425
1401
|
interval=schedule_type,
|
|
1426
|
-
|
|
1427
|
-
queue=task_queue,
|
|
1428
|
-
user=request.user,
|
|
1402
|
+
crontab=schedule_form.cleaned_data.get("_recurrence_custom_time"),
|
|
1429
1403
|
approval_required=job_model.approval_required,
|
|
1430
|
-
|
|
1404
|
+
task_queue=task_queue,
|
|
1405
|
+
profile=profile,
|
|
1406
|
+
**job_class.serialize_data(job_form.cleaned_data),
|
|
1431
1407
|
)
|
|
1432
|
-
scheduled_job.validated_save()
|
|
1433
1408
|
|
|
1434
1409
|
if job_model.approval_required:
|
|
1435
|
-
messages.success(request, f"Job {
|
|
1436
|
-
return redirect(return_url
|
|
1410
|
+
messages.success(request, f"Job {scheduled_job.name} successfully submitted for approval")
|
|
1411
|
+
return redirect(return_url or "extras:scheduledjob_approval_queue_list")
|
|
1437
1412
|
else:
|
|
1438
|
-
messages.success(request, f"Job {
|
|
1439
|
-
return redirect(return_url
|
|
1413
|
+
messages.success(request, f"Job {scheduled_job.name} successfully scheduled")
|
|
1414
|
+
return redirect(return_url or "extras:scheduledjob_list")
|
|
1440
1415
|
|
|
1441
1416
|
else:
|
|
1442
1417
|
# Enqueue job for immediate execution
|
|
@@ -1722,7 +1697,12 @@ class SavedViewUIViewSet(
|
|
|
1722
1697
|
view_name = new_global_default_view.view
|
|
1723
1698
|
message = ""
|
|
1724
1699
|
if new_global_default_view.is_global_default:
|
|
1725
|
-
message
|
|
1700
|
+
message = format_html(
|
|
1701
|
+
'<br>The global default saved view for "{}" is set to <a href="{}">{}</a>',
|
|
1702
|
+
view_name,
|
|
1703
|
+
new_global_default_view.get_absolute_url(),
|
|
1704
|
+
new_global_default_view.name,
|
|
1705
|
+
)
|
|
1726
1706
|
return message
|
|
1727
1707
|
|
|
1728
1708
|
def list(self, request, *args, **kwargs):
|
|
@@ -1942,6 +1922,7 @@ class ScheduledJobView(generic.ObjectView):
|
|
|
1942
1922
|
return {
|
|
1943
1923
|
"labels": labels,
|
|
1944
1924
|
"job_class_found": (job_class is not None),
|
|
1925
|
+
"default_time_zone": ZoneInfo(settings.TIME_ZONE),
|
|
1945
1926
|
**super().get_extra_context(request, instance),
|
|
1946
1927
|
}
|
|
1947
1928
|
|
|
@@ -2076,8 +2057,13 @@ class JobLogEntryTableView(generic.GenericView):
|
|
|
2076
2057
|
else:
|
|
2077
2058
|
queryset = instance.job_log_entries.all()
|
|
2078
2059
|
log_table = tables.JobLogEntryTable(data=queryset, user=request.user)
|
|
2079
|
-
|
|
2080
|
-
|
|
2060
|
+
paginate = {
|
|
2061
|
+
"paginator_class": EnhancedPaginator,
|
|
2062
|
+
"per_page": get_paginate_count(request),
|
|
2063
|
+
}
|
|
2064
|
+
RequestConfig(request, paginate).configure(log_table)
|
|
2065
|
+
table = log_table.as_html(request)
|
|
2066
|
+
return HttpResponse(table)
|
|
2081
2067
|
|
|
2082
2068
|
|
|
2083
2069
|
#
|
|
@@ -2237,15 +2223,13 @@ class MetadataTypeUIViewSet(NautobotUIViewSet):
|
|
|
2237
2223
|
|
|
2238
2224
|
|
|
2239
2225
|
class ObjectMetadataUIViewSet(
|
|
2240
|
-
ObjectBulkDestroyViewMixin,
|
|
2241
2226
|
ObjectChangeLogViewMixin,
|
|
2242
|
-
ObjectDestroyViewMixin,
|
|
2243
2227
|
ObjectDetailViewMixin,
|
|
2244
2228
|
ObjectListViewMixin,
|
|
2245
2229
|
):
|
|
2246
2230
|
filterset_class = filters.ObjectMetadataFilterSet
|
|
2247
2231
|
filterset_form_class = forms.ObjectMetadataFilterForm
|
|
2248
|
-
queryset = ObjectMetadata.objects.all().order_by("assigned_object_type", "scoped_fields")
|
|
2232
|
+
queryset = ObjectMetadata.objects.all().order_by("assigned_object_type", "assigned_object_id", "scoped_fields")
|
|
2249
2233
|
serializer_class = serializers.ObjectMetadataSerializer
|
|
2250
2234
|
table_class = tables.ObjectMetadataTable
|
|
2251
2235
|
action_buttons = ("export",)
|
|
@@ -2444,7 +2428,7 @@ class RoleUIViewSet(viewsets.NautobotUIViewSet):
|
|
|
2444
2428
|
|
|
2445
2429
|
if ContentType.objects.get_for_model(Prefix) in context["content_types"]:
|
|
2446
2430
|
prefixes = instance.prefixes.restrict(request.user, "view")
|
|
2447
|
-
prefix_table = PrefixTable(prefixes)
|
|
2431
|
+
prefix_table = PrefixTable(prefixes, hide_hierarchy_ui=True)
|
|
2448
2432
|
prefix_table.columns.hide("role")
|
|
2449
2433
|
RequestConfig(request, paginate).configure(prefix_table)
|
|
2450
2434
|
context["prefix_table"] = prefix_table
|
nautobot/ipam/api/views.py
CHANGED
|
@@ -202,7 +202,7 @@ class PrefixViewSet(NautobotModelViewSet):
|
|
|
202
202
|
if requested_prefix["prefix_length"] >= available_prefix.prefixlen:
|
|
203
203
|
allocated_prefix = f"{available_prefix.network}/{requested_prefix['prefix_length']}"
|
|
204
204
|
requested_prefix["prefix"] = allocated_prefix
|
|
205
|
-
requested_prefix["namespace"] = prefix.namespace
|
|
205
|
+
requested_prefix["namespace"] = prefix.namespace
|
|
206
206
|
break
|
|
207
207
|
else:
|
|
208
208
|
return Response(
|
|
@@ -210,6 +210,10 @@ class PrefixViewSet(NautobotModelViewSet):
|
|
|
210
210
|
status=status.HTTP_204_NO_CONTENT,
|
|
211
211
|
)
|
|
212
212
|
|
|
213
|
+
# The serializer usage above has mapped "custom_fields" dict to "_custom_field_data".
|
|
214
|
+
# We need to convert it back to "custom_fields" as we're going to deserialize it a second time below
|
|
215
|
+
requested_prefix["custom_fields"] = requested_prefix.pop("_custom_field_data", {})
|
|
216
|
+
|
|
213
217
|
# Remove the allocated prefix from the list of available prefixes
|
|
214
218
|
available_prefixes.remove(allocated_prefix)
|
|
215
219
|
|
|
@@ -299,7 +303,10 @@ class PrefixViewSet(NautobotModelViewSet):
|
|
|
299
303
|
prefix_length = prefix.prefix.prefixlen
|
|
300
304
|
for requested_ip in requested_ips:
|
|
301
305
|
requested_ip["address"] = f"{next(available_ips)}/{prefix_length}"
|
|
302
|
-
requested_ip["namespace"] = prefix.namespace
|
|
306
|
+
requested_ip["namespace"] = prefix.namespace
|
|
307
|
+
# The serializer usage above has mapped "custom_fields" dict to "_custom_field_data".
|
|
308
|
+
# We need to convert it back to "custom_fields" as we're going to deserialize it a second time below
|
|
309
|
+
requested_ip["custom_fields"] = requested_ip.pop("_custom_field_data", {})
|
|
303
310
|
|
|
304
311
|
# Initialize the serializer with a list or a single object depending on what was requested
|
|
305
312
|
context = {"request": request, "depth": 0}
|
nautobot/ipam/choices.py
CHANGED
|
@@ -102,6 +102,23 @@ class IPAddressTypeChoices(ChoiceSet):
|
|
|
102
102
|
)
|
|
103
103
|
|
|
104
104
|
|
|
105
|
+
#
|
|
106
|
+
# VRFs
|
|
107
|
+
#
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
class VRFStatusChoices(ChoiceSet):
|
|
111
|
+
STATUS_ACTIVE = "active"
|
|
112
|
+
STATUS_DOWN = "down"
|
|
113
|
+
STATUS_DEPRECATED = "deprecated"
|
|
114
|
+
|
|
115
|
+
CHOICES = (
|
|
116
|
+
(STATUS_ACTIVE, "Active"),
|
|
117
|
+
(STATUS_DOWN, "Down"),
|
|
118
|
+
(STATUS_DEPRECATED, "Deprecated"),
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
|
|
105
122
|
#
|
|
106
123
|
# VLANs
|
|
107
124
|
#
|
nautobot/ipam/factory.py
CHANGED
|
@@ -84,6 +84,7 @@ class VRFFactory(PrimaryModelFactory):
|
|
|
84
84
|
model = VRF
|
|
85
85
|
exclude = (
|
|
86
86
|
"has_description",
|
|
87
|
+
"has_status",
|
|
87
88
|
"has_tenant",
|
|
88
89
|
)
|
|
89
90
|
|
|
@@ -103,6 +104,11 @@ class VRFFactory(PrimaryModelFactory):
|
|
|
103
104
|
has_description = NautobotBoolIterator()
|
|
104
105
|
description = factory.Maybe("has_description", factory.Faker("text", max_nb_chars=CHARFIELD_MAX_LENGTH), "")
|
|
105
106
|
|
|
107
|
+
has_status = NautobotBoolIterator()
|
|
108
|
+
status = factory.Maybe(
|
|
109
|
+
"has_status", random_instance(lambda: Status.objects.get_for_model(VRF), allow_null=False), None
|
|
110
|
+
)
|
|
111
|
+
|
|
106
112
|
namespace = random_instance(Namespace, allow_null=False)
|
|
107
113
|
|
|
108
114
|
@factory.post_generation
|
nautobot/ipam/filters.py
CHANGED
|
@@ -66,7 +66,7 @@ class NamespaceFilterSet(NautobotFilterSet):
|
|
|
66
66
|
fields = "__all__"
|
|
67
67
|
|
|
68
68
|
|
|
69
|
-
class VRFFilterSet(NautobotFilterSet, TenancyModelFilterSetMixin):
|
|
69
|
+
class VRFFilterSet(NautobotFilterSet, StatusModelFilterSetMixin, TenancyModelFilterSetMixin):
|
|
70
70
|
q = SearchFilter(
|
|
71
71
|
filter_predicates={
|
|
72
72
|
"name": "icontains",
|
|
@@ -498,7 +498,7 @@ class IPAddressFilterSet(
|
|
|
498
498
|
return queryset.none()
|
|
499
499
|
interface_ids = []
|
|
500
500
|
for device in devices:
|
|
501
|
-
interface_ids.extend(device.
|
|
501
|
+
interface_ids.extend(device.vc_interfaces.values_list("id", flat=True))
|
|
502
502
|
return queryset.filter(interfaces__in=interface_ids)
|
|
503
503
|
|
|
504
504
|
def filter_virtual_machine(self, queryset, name, value):
|
nautobot/ipam/forms.py
CHANGED
|
@@ -125,6 +125,7 @@ class VRFForm(NautobotModelForm, TenancyForm):
|
|
|
125
125
|
"name",
|
|
126
126
|
"rd",
|
|
127
127
|
"namespace",
|
|
128
|
+
"status",
|
|
128
129
|
"description",
|
|
129
130
|
"import_targets",
|
|
130
131
|
"export_targets",
|
|
@@ -140,10 +141,11 @@ class VRFForm(NautobotModelForm, TenancyForm):
|
|
|
140
141
|
}
|
|
141
142
|
help_texts = {
|
|
142
143
|
"rd": "Route distinguisher unique to this Namespace (as defined in RFC 4364)",
|
|
144
|
+
"status": "Operational status of this VRF",
|
|
143
145
|
}
|
|
144
146
|
|
|
145
147
|
|
|
146
|
-
class VRFBulkEditForm(TagsBulkEditFormMixin, NautobotBulkEditForm):
|
|
148
|
+
class VRFBulkEditForm(TagsBulkEditFormMixin, StatusModelBulkEditFormMixin, NautobotBulkEditForm):
|
|
147
149
|
pk = forms.ModelMultipleChoiceField(queryset=VRF.objects.all(), widget=forms.MultipleHiddenInput())
|
|
148
150
|
namespace = DynamicModelChoiceField(queryset=Namespace.objects.all(), required=False)
|
|
149
151
|
tenant = DynamicModelChoiceField(queryset=Tenant.objects.all(), required=False)
|
|
@@ -162,9 +164,9 @@ class VRFBulkEditForm(TagsBulkEditFormMixin, NautobotBulkEditForm):
|
|
|
162
164
|
]
|
|
163
165
|
|
|
164
166
|
|
|
165
|
-
class VRFFilterForm(NautobotFilterForm, TenancyFilterForm):
|
|
167
|
+
class VRFFilterForm(NautobotFilterForm, StatusModelFilterFormMixin, TenancyFilterForm):
|
|
166
168
|
model = VRF
|
|
167
|
-
field_order = ["q", "import_targets", "export_targets", "tenant_group", "tenant"]
|
|
169
|
+
field_order = ["q", "import_targets", "export_targets", "status", "tenant_group", "tenant"]
|
|
168
170
|
q = forms.CharField(required=False, label="Search")
|
|
169
171
|
import_targets = DynamicModelMultipleChoiceField(
|
|
170
172
|
queryset=RouteTarget.objects.all(), to_field_name="name", required=False
|
|
@@ -899,7 +901,7 @@ class ServiceForm(NautobotModelForm):
|
|
|
899
901
|
# Limit IP address choices to those assigned to interfaces of the parent device/VM
|
|
900
902
|
if self.instance.device:
|
|
901
903
|
self.fields["ip_addresses"].queryset = IPAddress.objects.filter(
|
|
902
|
-
interfaces__in=self.instance.device.
|
|
904
|
+
interfaces__in=self.instance.device.vc_interfaces.values_list("id", flat=True)
|
|
903
905
|
)
|
|
904
906
|
elif self.instance.virtual_machine:
|
|
905
907
|
self.fields["ip_addresses"].queryset = IPAddress.objects.filter(
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Generated by Django 4.2.15 on 2024-08-26 17:20
|
|
2
|
+
|
|
3
|
+
from django.db import migrations
|
|
4
|
+
import django.db.models.deletion
|
|
5
|
+
|
|
6
|
+
import nautobot.extras.models.statuses
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class Migration(migrations.Migration):
|
|
10
|
+
dependencies = [
|
|
11
|
+
("extras", "0114_computedfield_grouping"),
|
|
12
|
+
("ipam", "0047_alter_ipaddress_role_alter_ipaddress_status_and_more"),
|
|
13
|
+
]
|
|
14
|
+
|
|
15
|
+
operations = [
|
|
16
|
+
migrations.AddField(
|
|
17
|
+
model_name="vrf",
|
|
18
|
+
name="status",
|
|
19
|
+
field=nautobot.extras.models.statuses.StatusField(
|
|
20
|
+
blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to="extras.status"
|
|
21
|
+
),
|
|
22
|
+
),
|
|
23
|
+
]
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# Generated by Django 4.2.15 on 2024-08-26 18:05
|
|
2
|
+
|
|
3
|
+
from django.db import migrations
|
|
4
|
+
|
|
5
|
+
from nautobot.extras.management import clear_status_choices, populate_status_choices
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def populate_vrf_status_choices(apps, schema_editor):
|
|
9
|
+
"""Create default Status records for the VRF model."""
|
|
10
|
+
populate_status_choices(apps, schema_editor, models=["ipam.VRF"])
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def clear_vrf_status_choices(apps, schema_editor):
|
|
14
|
+
"""Remove default Status records for the VRF model."""
|
|
15
|
+
clear_status_choices(apps, schema_editor, models=["ipam.VRF"])
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class Migration(migrations.Migration):
|
|
19
|
+
dependencies = [
|
|
20
|
+
("ipam", "0048_vrf_status"),
|
|
21
|
+
]
|
|
22
|
+
|
|
23
|
+
operations = [
|
|
24
|
+
migrations.RunPython(populate_vrf_status_choices, clear_vrf_status_choices),
|
|
25
|
+
]
|
nautobot/ipam/models.py
CHANGED
|
@@ -49,7 +49,6 @@ logger = logging.getLogger(__name__)
|
|
|
49
49
|
@extras_features(
|
|
50
50
|
"custom_links",
|
|
51
51
|
"custom_validators",
|
|
52
|
-
"dynamic_groups",
|
|
53
52
|
"export_templates",
|
|
54
53
|
"graphql",
|
|
55
54
|
"locations",
|
|
@@ -98,6 +97,7 @@ def get_default_namespace_pk():
|
|
|
98
97
|
"custom_validators",
|
|
99
98
|
"export_templates",
|
|
100
99
|
"graphql",
|
|
100
|
+
"statuses",
|
|
101
101
|
"webhooks",
|
|
102
102
|
)
|
|
103
103
|
class VRF(PrimaryModel):
|
|
@@ -115,6 +115,7 @@ class VRF(PrimaryModel):
|
|
|
115
115
|
verbose_name="Route distinguisher",
|
|
116
116
|
help_text="Unique route distinguisher (as defined in RFC 4364)",
|
|
117
117
|
)
|
|
118
|
+
status = StatusField(blank=True, null=True)
|
|
118
119
|
namespace = models.ForeignKey(
|
|
119
120
|
"ipam.Namespace",
|
|
120
121
|
on_delete=models.PROTECT,
|
|
@@ -399,7 +400,6 @@ class RIR(OrganizationalModel):
|
|
|
399
400
|
@extras_features(
|
|
400
401
|
"custom_links",
|
|
401
402
|
"custom_validators",
|
|
402
|
-
"dynamic_groups",
|
|
403
403
|
"export_templates",
|
|
404
404
|
"graphql",
|
|
405
405
|
"locations",
|
|
@@ -501,11 +501,6 @@ class Prefix(PrimaryModel):
|
|
|
501
501
|
"type",
|
|
502
502
|
"vlan",
|
|
503
503
|
]
|
|
504
|
-
"""
|
|
505
|
-
dynamic_group_filter_fields = {
|
|
506
|
-
"vrf": "vrf_id", # Duplicate filter fields that will be collapsed in 2.0
|
|
507
|
-
}
|
|
508
|
-
"""
|
|
509
504
|
|
|
510
505
|
class Meta:
|
|
511
506
|
ordering = (
|
|
@@ -986,7 +981,6 @@ class PrefixLocationAssignment(BaseModel):
|
|
|
986
981
|
@extras_features(
|
|
987
982
|
"custom_links",
|
|
988
983
|
"custom_validators",
|
|
989
|
-
"dynamic_groups",
|
|
990
984
|
"export_templates",
|
|
991
985
|
"graphql",
|
|
992
986
|
"statuses",
|
|
@@ -1020,7 +1014,7 @@ class IPAddress(PrimaryModel):
|
|
|
1020
1014
|
parent = models.ForeignKey(
|
|
1021
1015
|
"ipam.Prefix",
|
|
1022
1016
|
blank=True,
|
|
1023
|
-
null=True,
|
|
1017
|
+
null=True, # TODO remove this, it shouldn't be permitted for the database!
|
|
1024
1018
|
related_name="ip_addresses", # `IPAddress` to use `related_name="ip_addresses"`
|
|
1025
1019
|
on_delete=models.PROTECT,
|
|
1026
1020
|
help_text="The parent Prefix of this IPAddress.",
|
|
@@ -1117,7 +1111,7 @@ class IPAddress(PrimaryModel):
|
|
|
1117
1111
|
raise ValidationError({"namespace": "No suitable parent Prefix exists in this Namespace"}) from e
|
|
1118
1112
|
|
|
1119
1113
|
def clean(self):
|
|
1120
|
-
|
|
1114
|
+
self.address = self.address # not a no-op - forces re-calling of self._deconstruct_address()
|
|
1121
1115
|
|
|
1122
1116
|
# Validate that host is not being modified
|
|
1123
1117
|
if self.present_in_database:
|
|
@@ -1131,8 +1125,8 @@ class IPAddress(PrimaryModel):
|
|
|
1131
1125
|
|
|
1132
1126
|
closest_parent = self._get_closest_parent()
|
|
1133
1127
|
# Validate `parent` can be used as the parent for this ipaddress
|
|
1134
|
-
if
|
|
1135
|
-
if self.parent != closest_parent:
|
|
1128
|
+
if closest_parent is not None:
|
|
1129
|
+
if self.parent is not None and self.parent != closest_parent:
|
|
1136
1130
|
raise ValidationError(
|
|
1137
1131
|
{
|
|
1138
1132
|
"parent": (
|
|
@@ -1144,23 +1138,20 @@ class IPAddress(PrimaryModel):
|
|
|
1144
1138
|
self.parent = closest_parent
|
|
1145
1139
|
self._namespace = None
|
|
1146
1140
|
|
|
1147
|
-
def save(self, *args, **kwargs):
|
|
1148
1141
|
# 3.0 TODO: uncomment the below to enforce this constraint
|
|
1149
1142
|
# if self.parent.type != choices.PrefixTypeChoices.TYPE_NETWORK:
|
|
1150
1143
|
# err_msg = f"IP addresses cannot be created in {self.parent.type} prefixes. You must create a network prefix first."
|
|
1151
1144
|
# raise ValidationError({"address": err_msg})
|
|
1152
1145
|
|
|
1153
|
-
self.address = self.address # not a no-op - forces re-calling of self._deconstruct_address()
|
|
1154
|
-
|
|
1155
1146
|
# Force dns_name to lowercase
|
|
1156
1147
|
if not self.dns_name.islower:
|
|
1157
1148
|
self.dns_name = self.dns_name.lower()
|
|
1158
1149
|
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1150
|
+
super().clean()
|
|
1151
|
+
|
|
1152
|
+
def save(self, *args, **kwargs):
|
|
1153
|
+
self.clean() # MUST do data fixup as above
|
|
1154
|
+
|
|
1164
1155
|
super().save(*args, **kwargs)
|
|
1165
1156
|
|
|
1166
1157
|
@property
|
nautobot/ipam/querysets.py
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import re
|
|
2
2
|
|
|
3
3
|
from django.core.exceptions import ValidationError
|
|
4
|
+
from django.core.validators import validate_ipv46_address
|
|
4
5
|
from django.db.models import ProtectedError, Q
|
|
5
6
|
import netaddr
|
|
6
7
|
|
|
@@ -397,6 +398,31 @@ class IPAddressQuerySet(BaseNetworkQuerySet):
|
|
|
397
398
|
"""
|
|
398
399
|
return super().order_by("host")
|
|
399
400
|
|
|
401
|
+
def get_or_create(self, **kwargs):
|
|
402
|
+
from nautobot.ipam.models import get_default_namespace, Prefix
|
|
403
|
+
|
|
404
|
+
parent = kwargs.get("parent")
|
|
405
|
+
namespace = kwargs.pop("namespace", None)
|
|
406
|
+
host = kwargs.get("host")
|
|
407
|
+
mask_length = kwargs.get("mask_length")
|
|
408
|
+
# If `host` or `mask_length` is None skip; then there is no way of getting the closest parent;
|
|
409
|
+
if parent is None and host is not None and mask_length is not None:
|
|
410
|
+
if namespace is None:
|
|
411
|
+
namespace = get_default_namespace()
|
|
412
|
+
cidr = f"{host}/{mask_length}"
|
|
413
|
+
|
|
414
|
+
try:
|
|
415
|
+
validate_ipv46_address(host)
|
|
416
|
+
except ValidationError as err:
|
|
417
|
+
raise ValidationError({"host": err.error_list}) from err
|
|
418
|
+
try:
|
|
419
|
+
netaddr.IPNetwork(cidr)
|
|
420
|
+
except netaddr.AddrFormatError as err:
|
|
421
|
+
raise ValidationError(f"{cidr} does not appear to be an IPv4 or IPv6 network.") from err
|
|
422
|
+
parent = Prefix.objects.filter(namespace=namespace).get_closest_parent(cidr=cidr, include_self=True)
|
|
423
|
+
kwargs["parent"] = parent
|
|
424
|
+
return super().get_or_create(**kwargs)
|
|
425
|
+
|
|
400
426
|
def string_search(self, search):
|
|
401
427
|
"""
|
|
402
428
|
Interpret a search string and return useful results.
|
nautobot/ipam/tables.py
CHANGED
|
@@ -217,7 +217,7 @@ class NamespaceTable(BaseTable):
|
|
|
217
217
|
#
|
|
218
218
|
|
|
219
219
|
|
|
220
|
-
class VRFTable(BaseTable):
|
|
220
|
+
class VRFTable(StatusTableMixin, BaseTable):
|
|
221
221
|
pk = ToggleColumn()
|
|
222
222
|
name = tables.LinkColumn()
|
|
223
223
|
# rd = tables.Column(verbose_name="RD")
|
|
@@ -232,6 +232,7 @@ class VRFTable(BaseTable):
|
|
|
232
232
|
"pk",
|
|
233
233
|
"name",
|
|
234
234
|
# "rd",
|
|
235
|
+
"status",
|
|
235
236
|
"namespace",
|
|
236
237
|
"tenant",
|
|
237
238
|
"description",
|
|
@@ -240,7 +241,7 @@ class VRFTable(BaseTable):
|
|
|
240
241
|
"tags",
|
|
241
242
|
)
|
|
242
243
|
# default_columns = ("pk", "name", "rd", "namespace", "tenant", "description")
|
|
243
|
-
default_columns = ("pk", "name", "namespace", "tenant", "description")
|
|
244
|
+
default_columns = ("pk", "name", "status", "namespace", "tenant", "description")
|
|
244
245
|
|
|
245
246
|
|
|
246
247
|
class VRFDeviceAssignmentTable(BaseTable):
|
|
@@ -355,6 +356,9 @@ class PrefixTable(StatusTableMixin, RoleTableMixin, BaseTable):
|
|
|
355
356
|
location_count = LinkedCountColumn(
|
|
356
357
|
viewname="dcim:location_list", url_params={"prefixes": "pk"}, verbose_name="Locations"
|
|
357
358
|
)
|
|
359
|
+
cloud_networks_count = LinkedCountColumn(
|
|
360
|
+
viewname="cloud:cloudnetwork_list", url_params={"prefixes": "pk"}, verbose_name="Cloud Networks"
|
|
361
|
+
)
|
|
358
362
|
|
|
359
363
|
class Meta(BaseTable.Meta):
|
|
360
364
|
model = Prefix
|
|
@@ -368,6 +372,7 @@ class PrefixTable(StatusTableMixin, RoleTableMixin, BaseTable):
|
|
|
368
372
|
"namespace",
|
|
369
373
|
"tenant",
|
|
370
374
|
"location_count",
|
|
375
|
+
"cloud_networks_count",
|
|
371
376
|
"vlan",
|
|
372
377
|
"role",
|
|
373
378
|
"rir",
|
|
@@ -19,6 +19,10 @@
|
|
|
19
19
|
<td>Tenant</td>
|
|
20
20
|
<td>{{ object.tenant|hyperlinked_object }}</td>
|
|
21
21
|
</tr>
|
|
22
|
+
<tr>
|
|
23
|
+
<td>Status</td>
|
|
24
|
+
<td>{{ object.status|hyperlinked_object_with_color }}</td>
|
|
25
|
+
</tr>
|
|
22
26
|
<tr>
|
|
23
27
|
<td>Description</td>
|
|
24
28
|
<td>{{ object.description|placeholder }}</td>
|