nautobot 2.4.0b1__py3-none-any.whl → 2.4.1__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/apps/__init__.py +1 -1
- nautobot/apps/api.py +8 -8
- nautobot/apps/change_logging.py +2 -2
- nautobot/apps/choices.py +4 -4
- nautobot/apps/events.py +3 -3
- nautobot/apps/factory.py +2 -2
- nautobot/apps/filters.py +1 -1
- nautobot/apps/forms.py +20 -20
- nautobot/apps/graphql.py +2 -2
- nautobot/apps/jobs.py +8 -8
- nautobot/apps/models.py +19 -19
- nautobot/apps/tables.py +1 -1
- nautobot/apps/testing.py +10 -10
- nautobot/apps/ui.py +2 -2
- nautobot/apps/utils.py +7 -7
- nautobot/apps/views.py +7 -7
- nautobot/circuits/api/serializers.py +1 -0
- nautobot/circuits/api/views.py +4 -8
- nautobot/circuits/tables.py +2 -1
- nautobot/circuits/templates/circuits/circuit_create.html +1 -7
- nautobot/circuits/views.py +3 -3
- nautobot/cloud/api/views.py +6 -10
- nautobot/cloud/models.py +1 -1
- nautobot/cloud/views.py +0 -16
- nautobot/core/api/constants.py +11 -0
- nautobot/core/api/fields.py +5 -5
- nautobot/core/api/filter_backends.py +3 -9
- nautobot/core/api/schema.py +13 -2
- nautobot/core/api/serializers.py +40 -34
- nautobot/core/api/views.py +56 -4
- nautobot/core/celery/log.py +4 -4
- nautobot/core/celery/schedulers.py +2 -2
- nautobot/core/choices.py +2 -2
- nautobot/core/events/__init__.py +3 -3
- nautobot/core/filters.py +67 -35
- nautobot/core/forms/__init__.py +19 -19
- nautobot/core/forms/fields.py +14 -11
- nautobot/core/forms/forms.py +33 -2
- nautobot/core/graphql/types.py +1 -1
- nautobot/core/jobs/__init__.py +28 -7
- nautobot/core/jobs/bulk_actions.py +285 -0
- nautobot/core/jobs/cleanup.py +48 -12
- nautobot/core/jobs/groups.py +1 -1
- nautobot/core/management/commands/validate_models.py +1 -1
- nautobot/core/models/__init__.py +3 -1
- nautobot/core/models/query_functions.py +2 -2
- nautobot/core/models/tree_queries.py +6 -3
- nautobot/core/settings.py +29 -2
- nautobot/core/settings.yaml +21 -0
- nautobot/core/tables.py +79 -61
- nautobot/core/templates/about.html +67 -0
- nautobot/core/templates/inc/media.html +3 -0
- nautobot/core/templates/inc/nav_menu.html +1 -0
- nautobot/core/templates/inc/tenancy_form_panel.html +9 -0
- nautobot/core/templates/inc/tenant_table_row.html +11 -0
- nautobot/core/templates/nautobot_config.py.j2 +13 -0
- nautobot/core/templates/search.html +7 -0
- nautobot/core/templates/utilities/render_jinja2.html +1 -1
- nautobot/core/templates/utilities/templatetags/tag.html +1 -1
- nautobot/core/templates/utilities/theme_preview.html +7 -0
- nautobot/core/templatetags/helpers.py +11 -2
- nautobot/core/testing/__init__.py +8 -8
- nautobot/core/testing/api.py +170 -15
- nautobot/core/testing/filters.py +45 -10
- nautobot/core/testing/forms.py +2 -0
- nautobot/core/testing/integration.py +86 -4
- nautobot/core/testing/mixins.py +7 -2
- nautobot/core/testing/views.py +44 -29
- nautobot/core/tests/integration/test_app_home.py +0 -1
- nautobot/core/tests/integration/test_app_navbar.py +0 -1
- nautobot/core/tests/integration/test_filters.py +0 -2
- nautobot/core/tests/integration/test_home.py +0 -1
- nautobot/core/tests/integration/test_navbar.py +0 -1
- nautobot/core/tests/integration/test_view_authentication.py +1 -0
- nautobot/core/tests/runner.py +1 -1
- nautobot/core/tests/test_api.py +98 -1
- nautobot/core/tests/test_csv.py +25 -3
- nautobot/core/tests/test_filters.py +209 -246
- nautobot/core/tests/test_forms.py +1 -0
- nautobot/core/tests/test_jobs.py +460 -1
- nautobot/core/tests/test_models.py +9 -0
- nautobot/core/tests/test_settings_schema.py +7 -0
- nautobot/core/tests/test_tables.py +100 -0
- nautobot/core/tests/test_utils.py +63 -1
- nautobot/core/tests/test_views.py +30 -3
- nautobot/core/ui/nav.py +1 -0
- nautobot/core/ui/object_detail.py +15 -1
- nautobot/core/urls.py +11 -0
- nautobot/core/utils/lookup.py +11 -8
- nautobot/core/utils/querysets.py +64 -0
- nautobot/core/utils/requests.py +24 -9
- nautobot/core/views/__init__.py +42 -0
- nautobot/core/views/generic.py +131 -197
- nautobot/core/views/mixins.py +126 -38
- nautobot/core/views/renderers.py +6 -6
- nautobot/dcim/api/serializers.py +56 -64
- nautobot/dcim/api/views.py +47 -113
- nautobot/dcim/constants.py +6 -13
- nautobot/dcim/factory.py +6 -1
- nautobot/dcim/filters/__init__.py +31 -2
- nautobot/dcim/forms.py +36 -17
- nautobot/dcim/graphql/types.py +2 -2
- nautobot/dcim/migrations/0067_controllermanageddevicegroup_tenant.py +25 -0
- nautobot/dcim/models/__init__.py +1 -1
- nautobot/dcim/models/device_component_templates.py +2 -2
- nautobot/dcim/models/device_components.py +22 -20
- nautobot/dcim/models/devices.py +10 -1
- nautobot/dcim/models/locations.py +3 -3
- nautobot/dcim/models/power.py +6 -5
- nautobot/dcim/models/racks.py +4 -4
- nautobot/dcim/tables/__init__.py +3 -3
- nautobot/dcim/tables/devices.py +7 -5
- nautobot/dcim/tables/devicetypes.py +2 -2
- nautobot/dcim/tables/racks.py +1 -1
- nautobot/dcim/templates/dcim/controller_create.html +1 -7
- nautobot/dcim/templates/dcim/controller_retrieve.html +1 -9
- nautobot/dcim/templates/dcim/controllermanageddevicegroup_create.html +2 -0
- nautobot/dcim/templates/dcim/controllermanageddevicegroup_retrieve.html +5 -0
- nautobot/dcim/templates/dcim/device.html +1 -9
- nautobot/dcim/templates/dcim/device_edit.html +36 -37
- nautobot/dcim/templates/dcim/location.html +1 -9
- nautobot/dcim/templates/dcim/location_edit.html +1 -7
- nautobot/dcim/templates/dcim/rack.html +1 -9
- nautobot/dcim/templates/dcim/rack_edit.html +1 -7
- nautobot/dcim/templates/dcim/rackreservation.html +1 -9
- nautobot/dcim/templates/dcim/virtualdevicecontext_retrieve.html +1 -9
- nautobot/dcim/templates/dcim/virtualdevicecontext_update.html +1 -7
- nautobot/dcim/tests/integration/test_controller.py +62 -0
- nautobot/dcim/tests/integration/test_controller_managed_device_group.py +71 -0
- nautobot/dcim/tests/integration/test_device_bulk_delete.py +189 -0
- nautobot/dcim/tests/integration/test_device_bulk_edit.py +181 -0
- nautobot/dcim/tests/test_api.py +16 -5
- nautobot/dcim/tests/test_filters.py +33 -0
- nautobot/dcim/tests/test_forms.py +51 -2
- nautobot/dcim/tests/test_graphql.py +52 -0
- nautobot/dcim/tests/test_jobs.py +118 -0
- nautobot/dcim/tests/test_models.py +52 -9
- nautobot/dcim/tests/test_views.py +21 -83
- nautobot/dcim/views.py +1 -13
- nautobot/extras/api/customfields.py +2 -2
- nautobot/extras/api/serializers.py +90 -85
- nautobot/extras/api/views.py +22 -27
- nautobot/extras/constants.py +2 -0
- nautobot/extras/filters/__init__.py +8 -6
- nautobot/extras/forms/base.py +2 -2
- nautobot/extras/forms/forms.py +139 -31
- nautobot/extras/forms/mixins.py +14 -6
- nautobot/extras/group_sync.py +3 -3
- nautobot/extras/health_checks.py +1 -2
- nautobot/extras/jobs.py +85 -18
- nautobot/extras/managers.py +3 -1
- nautobot/extras/migrations/0018_joblog_data_migration.py +7 -9
- nautobot/extras/migrations/0120_job_is_singleton_job_is_singleton_override.py +22 -0
- nautobot/extras/migrations/0121_alter_team_contacts.py +17 -0
- nautobot/extras/models/__init__.py +1 -1
- nautobot/extras/models/contacts.py +1 -1
- nautobot/extras/models/customfields.py +12 -11
- nautobot/extras/models/groups.py +11 -9
- nautobot/extras/models/jobs.py +23 -4
- nautobot/extras/models/models.py +2 -2
- nautobot/extras/plugins/__init__.py +13 -2
- nautobot/extras/plugins/marketplace_manifest.yml +84 -79
- nautobot/extras/plugins/tables.py +16 -14
- nautobot/extras/plugins/views.py +65 -69
- nautobot/extras/registry.py +1 -1
- nautobot/extras/secrets/__init__.py +2 -2
- nautobot/extras/tables.py +7 -5
- nautobot/extras/templates/extras/dynamicgroup.html +1 -9
- nautobot/extras/templates/extras/job_detail.html +16 -0
- nautobot/extras/templates/extras/job_edit.html +1 -0
- nautobot/extras/templates/extras/jobqueue_retrieve.html +1 -9
- nautobot/extras/templates/extras/marketplace.html +29 -11
- nautobot/extras/templates/extras/plugin_detail.html +32 -15
- nautobot/extras/templates/extras/plugins_tiles.html +21 -10
- nautobot/extras/templatetags/job_buttons.py +4 -4
- nautobot/extras/test_jobs/api_test_job.py +1 -1
- nautobot/extras/test_jobs/atomic_transaction.py +2 -2
- nautobot/extras/test_jobs/dry_run.py +1 -1
- nautobot/extras/test_jobs/fail.py +5 -5
- nautobot/extras/test_jobs/file_output.py +1 -1
- nautobot/extras/test_jobs/file_upload_fail.py +1 -1
- nautobot/extras/test_jobs/file_upload_pass.py +1 -1
- nautobot/extras/test_jobs/ipaddress_vars.py +3 -1
- nautobot/extras/test_jobs/jobs_module/jobs_submodule/jobs.py +1 -1
- nautobot/extras/test_jobs/location_with_custom_field.py +1 -1
- nautobot/extras/test_jobs/log_redaction.py +1 -1
- nautobot/extras/test_jobs/log_skip_db_logging.py +1 -1
- nautobot/extras/test_jobs/modify_db.py +1 -1
- nautobot/extras/test_jobs/object_var_optional.py +1 -1
- nautobot/extras/test_jobs/object_var_required.py +1 -1
- nautobot/extras/test_jobs/object_vars.py +1 -1
- nautobot/extras/test_jobs/pass.py +3 -3
- nautobot/extras/test_jobs/profiling.py +1 -1
- nautobot/extras/test_jobs/relative_import.py +3 -3
- nautobot/extras/test_jobs/singleton.py +16 -0
- nautobot/extras/test_jobs/soft_time_limit_greater_than_time_limit.py +1 -1
- nautobot/extras/test_jobs/task_queues.py +1 -1
- nautobot/extras/tests/integration/test_plugin_banner.py +0 -2
- nautobot/extras/tests/test_api.py +13 -13
- nautobot/extras/tests/test_customfields.py +1 -1
- nautobot/extras/tests/test_datasources.py +2 -1
- nautobot/extras/tests/test_dynamicgroups.py +1 -1
- nautobot/extras/tests/test_filters.py +6 -6
- nautobot/extras/tests/test_forms.py +33 -1
- nautobot/extras/tests/test_jobs.py +178 -32
- nautobot/extras/tests/test_models.py +16 -10
- nautobot/extras/tests/test_plugins.py +62 -9
- nautobot/extras/tests/test_relationships.py +120 -9
- nautobot/extras/tests/test_views.py +56 -194
- nautobot/extras/utils.py +3 -2
- nautobot/extras/views.py +30 -98
- nautobot/ipam/api/fields.py +3 -3
- nautobot/ipam/api/serializers.py +41 -33
- nautobot/ipam/api/views.py +68 -117
- nautobot/ipam/factory.py +1 -1
- nautobot/ipam/filters.py +3 -2
- nautobot/ipam/lookups.py +101 -62
- nautobot/ipam/models.py +66 -16
- nautobot/ipam/querysets.py +2 -2
- nautobot/ipam/tables.py +23 -7
- nautobot/ipam/templates/ipam/ipaddress.html +1 -9
- nautobot/ipam/templates/ipam/ipaddress_bulk_add.html +1 -7
- nautobot/ipam/templates/ipam/ipaddress_edit.html +1 -7
- nautobot/ipam/templates/ipam/prefix.html +1 -9
- nautobot/ipam/templates/ipam/prefix_edit.html +1 -7
- nautobot/ipam/templates/ipam/vlan.html +1 -9
- nautobot/ipam/templates/ipam/vlan_edit.html +1 -7
- nautobot/ipam/templates/ipam/vrf_edit.html +1 -7
- nautobot/ipam/tests/test_api.py +436 -3
- nautobot/ipam/tests/test_forms.py +49 -47
- nautobot/ipam/tests/test_migrations.py +30 -30
- nautobot/ipam/tests/test_models.py +95 -34
- nautobot/ipam/tests/test_querysets.py +63 -1
- nautobot/ipam/tests/test_views.py +3 -0
- nautobot/ipam/utils/__init__.py +36 -6
- nautobot/ipam/views.py +61 -87
- nautobot/project-static/bootstrap-3.4.1-dist/css/bootstrap-theme.css.map +1 -1
- nautobot/project-static/bootstrap-3.4.1-dist/css/bootstrap-theme.min.css.map +1 -1
- nautobot/project-static/bootstrap-3.4.1-dist/css/bootstrap.css +40 -2
- nautobot/project-static/bootstrap-3.4.1-dist/css/bootstrap.css.map +1 -1
- nautobot/project-static/bootstrap-3.4.1-dist/css/bootstrap.min.css +1 -1
- nautobot/project-static/bootstrap-3.4.1-dist/css/bootstrap.min.css.map +1 -1
- nautobot/project-static/docs/404.html +46 -4
- nautobot/project-static/docs/apps/index.html +46 -4
- nautobot/project-static/docs/apps/nautobot-apps.html +47 -6
- nautobot/project-static/docs/assets/_mkdocstrings.css +25 -1
- nautobot/project-static/docs/assets/javascripts/{bundle.83f73b43.min.js → bundle.88dd0f4e.min.js} +2 -2
- nautobot/project-static/docs/assets/javascripts/{bundle.83f73b43.min.js.map → bundle.88dd0f4e.min.js.map} +2 -2
- nautobot/project-static/docs/code-reference/nautobot/apps/__init__.html +62 -10
- nautobot/project-static/docs/code-reference/nautobot/apps/admin.html +59 -7
- nautobot/project-static/docs/code-reference/nautobot/apps/api.html +374 -122
- nautobot/project-static/docs/code-reference/nautobot/apps/change_logging.html +90 -18
- nautobot/project-static/docs/code-reference/nautobot/apps/choices.html +95 -21
- nautobot/project-static/docs/code-reference/nautobot/apps/config.html +53 -6
- nautobot/project-static/docs/code-reference/nautobot/apps/constants.html +52 -5
- nautobot/project-static/docs/code-reference/nautobot/apps/datasources.html +79 -17
- nautobot/project-static/docs/code-reference/nautobot/apps/events.html +102 -28
- nautobot/project-static/docs/code-reference/nautobot/apps/exceptions.html +108 -21
- nautobot/project-static/docs/code-reference/nautobot/apps/factory.html +131 -38
- nautobot/project-static/docs/code-reference/nautobot/apps/filters.html +239 -65
- nautobot/project-static/docs/code-reference/nautobot/apps/forms.html +581 -165
- nautobot/project-static/docs/code-reference/nautobot/apps/graphql.html +109 -36
- nautobot/project-static/docs/code-reference/nautobot/apps/jobs.html +453 -167
- nautobot/project-static/docs/code-reference/nautobot/apps/models.html +493 -211
- nautobot/project-static/docs/code-reference/nautobot/apps/querysets.html +60 -8
- nautobot/project-static/docs/code-reference/nautobot/apps/secrets.html +71 -15
- nautobot/project-static/docs/code-reference/nautobot/apps/tables.html +407 -55
- nautobot/project-static/docs/code-reference/nautobot/apps/testing.html +620 -205
- nautobot/project-static/docs/code-reference/nautobot/apps/ui.html +858 -412
- nautobot/project-static/docs/code-reference/nautobot/apps/urls.html +59 -7
- nautobot/project-static/docs/code-reference/nautobot/apps/utils.html +448 -186
- nautobot/project-static/docs/code-reference/nautobot/apps/views.html +365 -147
- nautobot/project-static/docs/development/apps/api/configuration-view.html +46 -4
- nautobot/project-static/docs/development/apps/api/database-backend-config.html +46 -4
- nautobot/project-static/docs/development/apps/api/models/django-admin.html +46 -4
- nautobot/project-static/docs/development/apps/api/models/global-search.html +46 -4
- nautobot/project-static/docs/development/apps/api/models/graphql.html +46 -4
- nautobot/project-static/docs/development/apps/api/models/index.html +46 -4
- nautobot/project-static/docs/development/apps/api/nautobot-app-config.html +46 -4
- nautobot/project-static/docs/development/apps/api/platform-features/custom-validators.html +46 -4
- nautobot/project-static/docs/development/apps/api/platform-features/filter-extensions.html +46 -4
- nautobot/project-static/docs/development/apps/api/platform-features/git-repository-content.html +46 -4
- nautobot/project-static/docs/development/apps/api/platform-features/index.html +46 -4
- nautobot/project-static/docs/development/apps/api/platform-features/jinja2-filters.html +46 -4
- nautobot/project-static/docs/development/apps/api/platform-features/jobs.html +46 -4
- nautobot/project-static/docs/development/apps/api/platform-features/populating-extensibility-features.html +46 -4
- nautobot/project-static/docs/development/apps/api/platform-features/secrets-providers.html +46 -4
- nautobot/project-static/docs/development/apps/api/platform-features/table-extensions.html +68 -7
- nautobot/project-static/docs/development/apps/api/platform-features/uniquely-identify-objects.html +46 -4
- nautobot/project-static/docs/development/apps/api/prometheus.html +46 -4
- nautobot/project-static/docs/development/apps/api/setup.html +46 -4
- nautobot/project-static/docs/development/apps/api/testing.html +46 -4
- nautobot/project-static/docs/development/apps/api/ui-extensions/banners.html +46 -4
- nautobot/project-static/docs/development/apps/api/ui-extensions/home-page.html +46 -4
- nautobot/project-static/docs/development/apps/api/ui-extensions/index.html +46 -4
- nautobot/project-static/docs/development/apps/api/ui-extensions/navigation.html +46 -4
- nautobot/project-static/docs/development/apps/api/ui-extensions/object-views.html +46 -4
- nautobot/project-static/docs/development/apps/api/views/base-template.html +46 -4
- nautobot/project-static/docs/development/apps/api/views/core-view-overrides.html +46 -4
- nautobot/project-static/docs/development/apps/api/views/django-generic-views.html +46 -4
- nautobot/project-static/docs/development/apps/api/views/help-documentation.html +46 -4
- nautobot/project-static/docs/development/apps/api/views/index.html +46 -4
- nautobot/project-static/docs/development/apps/api/views/nautobot-generic-views.html +46 -4
- nautobot/project-static/docs/development/apps/api/views/nautobotuiviewset.html +46 -4
- nautobot/project-static/docs/development/apps/api/views/nautobotuiviewsetrouter.html +46 -4
- nautobot/project-static/docs/development/apps/api/views/notes.html +46 -4
- nautobot/project-static/docs/development/apps/api/views/rest-api.html +52 -6
- nautobot/project-static/docs/development/apps/api/views/urls.html +46 -4
- nautobot/project-static/docs/development/apps/index.html +46 -4
- nautobot/project-static/docs/development/apps/migration/code-updates.html +46 -4
- nautobot/project-static/docs/development/apps/migration/dependency-updates.html +46 -4
- nautobot/project-static/docs/development/apps/migration/from-v1.html +46 -4
- nautobot/project-static/docs/development/apps/migration/model-updates/dcim.html +46 -4
- nautobot/project-static/docs/development/apps/migration/model-updates/extras.html +46 -4
- nautobot/project-static/docs/development/apps/migration/model-updates/global.html +46 -4
- nautobot/project-static/docs/development/apps/migration/model-updates/ipam.html +46 -4
- nautobot/project-static/docs/development/apps/migration/ui-component-framework/best-practices.html +50 -8
- nautobot/project-static/docs/development/apps/migration/ui-component-framework/custom-content.html +46 -4
- nautobot/project-static/docs/development/apps/migration/ui-component-framework/index.html +211 -14
- nautobot/project-static/docs/development/apps/migration/ui-component-framework/migration-steps.html +46 -4
- nautobot/project-static/docs/development/apps/porting-from-netbox.html +46 -4
- nautobot/project-static/docs/development/core/application-registry.html +46 -4
- nautobot/project-static/docs/development/core/best-practices.html +46 -4
- nautobot/project-static/docs/development/core/bootstrap-ui.html +46 -4
- nautobot/project-static/docs/development/core/caching.html +46 -4
- nautobot/project-static/docs/development/core/controllers.html +46 -4
- nautobot/project-static/docs/development/core/docker-compose-advanced-use-cases.html +73 -74
- nautobot/project-static/docs/development/core/generic-views.html +46 -4
- nautobot/project-static/docs/development/core/getting-started.html +249 -224
- nautobot/project-static/docs/development/core/homepage.html +49 -7
- nautobot/project-static/docs/development/core/index.html +46 -4
- nautobot/project-static/docs/development/core/{local-k8s.html → minikube-dev-environment-for-k8s-jobs.html} +469 -168
- nautobot/project-static/docs/development/core/model-checklist.html +56 -12
- nautobot/project-static/docs/development/core/model-features.html +46 -4
- nautobot/project-static/docs/development/core/natural-keys.html +46 -4
- nautobot/project-static/docs/development/core/navigation-menu.html +46 -4
- nautobot/project-static/docs/development/core/release-checklist.html +49 -7
- nautobot/project-static/docs/development/core/role-internals.html +46 -4
- nautobot/project-static/docs/development/core/settings.html +46 -4
- nautobot/project-static/docs/development/core/style-guide.html +49 -7
- nautobot/project-static/docs/development/core/templates.html +46 -4
- nautobot/project-static/docs/development/core/testing.html +46 -4
- nautobot/project-static/docs/development/core/ui-component-framework.html +369 -273
- nautobot/project-static/docs/development/core/user-preferences.html +46 -4
- nautobot/project-static/docs/development/index.html +46 -4
- nautobot/project-static/docs/development/jobs/index.html +216 -122
- nautobot/project-static/docs/development/jobs/migration/from-v1.html +46 -4
- nautobot/project-static/docs/index.html +54 -23
- nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_edit.png +0 -0
- nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_edit_button.png +0 -0
- nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_list_nav.png +0 -0
- nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_list_view.png +0 -0
- nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_queue.png +0 -0
- nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_queue_add.png +0 -0
- nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_queue_config.png +0 -0
- nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_result_completed.png +0 -0
- nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_result_nav.png +0 -0
- nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_result_pending.png +0 -0
- nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_run_form.png +0 -0
- nautobot/project-static/docs/media/development/core/kubernetes/k8s_nautobot_login.png +0 -0
- nautobot/project-static/docs/media/development/core/kubernetes/k8s_run_job.png +0 -0
- nautobot/project-static/docs/media/development/core/kubernetes/k8s_run_scheduled_job_form.png +0 -0
- nautobot/project-static/docs/media/development/core/kubernetes/k8s_scheduled_job_result.png +0 -0
- nautobot/project-static/docs/media/development/core/ui-component-framework/buttons-example.png +0 -0
- nautobot/project-static/docs/media/development/core/ui-component-framework/cluster-type-before-after-example.png +0 -0
- nautobot/project-static/docs/media/development/core/ui-component-framework/object-fields-panel-example_2.png +0 -0
- nautobot/project-static/docs/media/development/core/ui-component-framework/stats-panel-example-code.png +0 -0
- nautobot/project-static/docs/objects.inv +0 -0
- nautobot/project-static/docs/overview/application_stack.html +47 -7
- nautobot/project-static/docs/overview/design_philosophy.html +46 -4
- nautobot/project-static/docs/release-notes/index.html +52 -12
- nautobot/project-static/docs/release-notes/version-1.0.html +234 -193
- nautobot/project-static/docs/release-notes/version-1.1.html +231 -190
- nautobot/project-static/docs/release-notes/version-1.2.html +306 -265
- nautobot/project-static/docs/release-notes/version-1.3.html +332 -291
- nautobot/project-static/docs/release-notes/version-1.4.html +417 -377
- nautobot/project-static/docs/release-notes/version-1.5.html +605 -566
- nautobot/project-static/docs/release-notes/version-1.6.html +904 -447
- nautobot/project-static/docs/release-notes/version-2.0.html +528 -489
- nautobot/project-static/docs/release-notes/version-2.1.html +363 -324
- nautobot/project-static/docs/release-notes/version-2.2.html +356 -317
- nautobot/project-static/docs/release-notes/version-2.3.html +997 -352
- nautobot/project-static/docs/release-notes/version-2.4.html +525 -101
- nautobot/project-static/docs/requirements.txt +2 -2
- nautobot/project-static/docs/search/search_index.json +1 -1
- nautobot/project-static/docs/sitemap.xml +295 -287
- nautobot/project-static/docs/sitemap.xml.gz +0 -0
- nautobot/project-static/docs/user-guide/administration/configuration/authentication/ldap.html +46 -4
- nautobot/project-static/docs/user-guide/administration/configuration/authentication/remote.html +46 -4
- nautobot/project-static/docs/user-guide/administration/configuration/authentication/sso.html +48 -6
- nautobot/project-static/docs/user-guide/administration/configuration/index.html +46 -4
- nautobot/project-static/docs/user-guide/administration/configuration/redis.html +46 -4
- nautobot/project-static/docs/user-guide/administration/configuration/settings.html +110 -8
- nautobot/project-static/docs/user-guide/administration/configuration/time-zones.html +46 -4
- nautobot/project-static/docs/user-guide/administration/guides/celery-queues.html +46 -4
- nautobot/project-static/docs/user-guide/administration/guides/docker.html +46 -4
- nautobot/project-static/docs/user-guide/administration/guides/health-checks.html +46 -4
- nautobot/project-static/docs/user-guide/administration/guides/permissions.html +46 -4
- nautobot/project-static/docs/user-guide/administration/guides/prometheus-metrics.html +46 -4
- nautobot/project-static/docs/user-guide/administration/guides/replicating-nautobot.html +46 -4
- nautobot/project-static/docs/user-guide/administration/guides/request-profiling.html +46 -4
- nautobot/project-static/docs/user-guide/administration/guides/s3-django-storage.html +48 -6
- nautobot/project-static/docs/user-guide/administration/guides/selinux-troubleshooting.html +46 -4
- nautobot/project-static/docs/user-guide/administration/installation/app-install.html +46 -4
- nautobot/project-static/docs/user-guide/administration/installation/external-authentication.html +46 -4
- nautobot/project-static/docs/user-guide/administration/installation/http-server.html +66 -8
- nautobot/project-static/docs/user-guide/administration/installation/index.html +46 -4
- nautobot/project-static/docs/user-guide/administration/installation/install_system.html +47 -5
- nautobot/project-static/docs/user-guide/administration/installation/nautobot.html +46 -4
- nautobot/project-static/docs/user-guide/administration/installation/services.html +46 -4
- nautobot/project-static/docs/user-guide/administration/migration/migrating-from-netbox.html +46 -4
- nautobot/project-static/docs/user-guide/administration/migration/migrating-from-postgresql.html +46 -4
- nautobot/project-static/docs/user-guide/administration/tools/nautobot-server.html +46 -4
- nautobot/project-static/docs/user-guide/administration/tools/nautobot-shell.html +46 -4
- nautobot/project-static/docs/user-guide/administration/upgrading/database-backup.html +46 -4
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/after-you-upgrade.html +46 -4
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/before-you-upgrade.html +46 -4
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/for-developers.html +46 -4
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/index.html +46 -4
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/whats-changed.html +49 -8
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/region-and-site-data-migration-guide.html +46 -4
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/upgrading-from-nautobot-v1.html +46 -4
- nautobot/project-static/docs/user-guide/administration/upgrading/upgrading.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/circuits/circuit.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittermination.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittype.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/circuits/provider.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/circuits/providernetwork.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloud.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudaccount.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudnetwork.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudnetworkprefixassignment.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudresourcetype.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudservice.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudservicenetworkassignment.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/dcim/cable.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleport.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleporttemplate.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverport.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverporttemplate.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/dcim/controller.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/dcim/controllermanageddevicegroup.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/dcim/device.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebay.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebaytemplate.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicefamily.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/dcim/deviceredundancygroup.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicetype.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/dcim/frontport.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/dcim/frontporttemplate.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/dcim/interface.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/dcim/interfaceredundancygroup.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/dcim/interfacetemplate.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/dcim/inventoryitem.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/dcim/location.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/dcim/locationtype.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/dcim/manufacturer.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/dcim/module.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/dcim/modulebay.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/dcim/modulebaytemplate.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/dcim/moduletype.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/dcim/platform.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerfeed.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlet.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlettemplate.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerpanel.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerport.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerporttemplate.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rack.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rackgroup.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rackreservation.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rearport.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rearporttemplate.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareimagefile.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareversion.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/dcim/virtualchassis.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/dcim/virtualdevicecontext.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/extras/configcontext.html +50 -12
- nautobot/project-static/docs/user-guide/core-data-model/extras/configcontextschema.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/extras/contact.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/extras/team.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/ipam/ipaddress.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/ipam/namespace.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/ipam/prefix.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/ipam/rir.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/ipam/routetarget.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/ipam/service.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/ipam/vlan.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/ipam/vlangroup.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/ipam/vrf.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/overview/introduction.html +49 -7
- nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenant.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenantgroup.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/cluster.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustergroup.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustertype.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/virtualmachine.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/vminterface.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/wireless/index.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/wireless/radioprofile.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/wireless/supporteddatarate.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/wireless/wirelessnetwork.html +46 -4
- nautobot/project-static/docs/user-guide/feature-guides/contacts-and-teams.html +46 -4
- nautobot/project-static/docs/user-guide/feature-guides/custom-fields.html +46 -4
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-devices.html +46 -4
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-location-types-and-locations.html +46 -4
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/index.html +46 -4
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/interfaces.html +46 -4
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/ipam.html +46 -4
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/platforms.html +46 -4
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/search-bar.html +46 -4
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/tenants.html +46 -4
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/vlans-and-vlan-groups.html +46 -4
- nautobot/project-static/docs/user-guide/feature-guides/git-data-source.html +51 -7
- nautobot/project-static/docs/user-guide/feature-guides/graphql.html +46 -4
- nautobot/project-static/docs/user-guide/feature-guides/images/wireless/central-mode.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/wireless/device-group-add.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/wireless/device-group-create-1.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/wireless/device-group-create-2.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/wireless/radio-profile-add.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/wireless/radio-profile-create.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/wireless/supported-data-rate-add.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/wireless/supported-data-rate-create.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/wireless/wireless-controller-add.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/wireless/wireless-controller-create-1.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/wireless/wireless-controller-create-2.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/wireless/wireless-network-add.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/wireless/wireless-network-create.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/ip-address-merge-tool.html +46 -4
- nautobot/project-static/docs/user-guide/feature-guides/relationships.html +46 -4
- nautobot/project-static/docs/user-guide/feature-guides/software-image-files-and-versions.html +49 -7
- nautobot/project-static/docs/user-guide/feature-guides/wireless-networks-and-controllers.html +9444 -0
- nautobot/project-static/docs/user-guide/index.html +46 -4
- nautobot/project-static/docs/user-guide/platform-functionality/change-logging.html +46 -4
- nautobot/project-static/docs/user-guide/platform-functionality/computedfield.html +50 -8
- nautobot/project-static/docs/user-guide/platform-functionality/customfield.html +46 -4
- nautobot/project-static/docs/user-guide/platform-functionality/customlink.html +46 -4
- nautobot/project-static/docs/user-guide/platform-functionality/dynamicgroup.html +46 -4
- nautobot/project-static/docs/user-guide/platform-functionality/events.html +46 -4
- nautobot/project-static/docs/user-guide/platform-functionality/exporttemplate.html +46 -4
- nautobot/project-static/docs/user-guide/platform-functionality/externalintegration.html +46 -4
- nautobot/project-static/docs/user-guide/platform-functionality/gitrepository.html +46 -4
- nautobot/project-static/docs/user-guide/platform-functionality/graphql.html +46 -4
- nautobot/project-static/docs/user-guide/platform-functionality/graphqlquery.html +46 -4
- nautobot/project-static/docs/user-guide/platform-functionality/imageattachment.html +46 -4
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/index.html +50 -7
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/job-scheduling-and-approvals.html +46 -4
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobbutton.html +49 -7
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobhook.html +46 -4
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobqueue.html +46 -4
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/kubernetes-job-support.html +9722 -0
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/models.html +46 -4
- nautobot/project-static/docs/user-guide/platform-functionality/napalm.html +46 -4
- nautobot/project-static/docs/user-guide/platform-functionality/note.html +46 -4
- nautobot/project-static/docs/user-guide/platform-functionality/objectmetadata.html +46 -4
- nautobot/project-static/docs/user-guide/platform-functionality/relationship.html +47 -5
- nautobot/project-static/docs/user-guide/platform-functionality/rendering-jinja-templates.html +46 -4
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/authentication.html +46 -4
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/filtering.html +94 -25
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/overview.html +74 -5
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/ui-related-endpoints.html +46 -4
- nautobot/project-static/docs/user-guide/platform-functionality/role.html +46 -4
- nautobot/project-static/docs/user-guide/platform-functionality/savedview.html +46 -4
- nautobot/project-static/docs/user-guide/platform-functionality/secret.html +46 -4
- nautobot/project-static/docs/user-guide/platform-functionality/staticgroupassociation.html +46 -4
- nautobot/project-static/docs/user-guide/platform-functionality/status.html +46 -4
- nautobot/project-static/docs/user-guide/platform-functionality/tag.html +46 -4
- nautobot/project-static/docs/user-guide/platform-functionality/template-filters.html +46 -4
- nautobot/project-static/docs/user-guide/platform-functionality/users/objectpermission.html +46 -4
- nautobot/project-static/docs/user-guide/platform-functionality/users/token.html +46 -4
- nautobot/project-static/docs/user-guide/platform-functionality/webhook.html +46 -4
- nautobot/project-static/js/forms.js +1 -1
- nautobot/tenancy/api/views.py +9 -13
- nautobot/tenancy/views.py +4 -2
- nautobot/users/admin.py +1 -1
- nautobot/users/api/serializers.py +5 -4
- nautobot/users/api/views.py +3 -3
- nautobot/virtualization/api/serializers.py +4 -4
- nautobot/virtualization/api/views.py +5 -24
- nautobot/virtualization/filters.py +20 -3
- nautobot/virtualization/models.py +1 -1
- nautobot/virtualization/tables.py +2 -2
- nautobot/virtualization/templates/virtualization/cluster_edit.html +1 -7
- nautobot/virtualization/templates/virtualization/virtualmachine.html +1 -9
- nautobot/virtualization/templates/virtualization/virtualmachine_edit.html +2 -8
- nautobot/virtualization/tests/test_filters.py +17 -0
- nautobot/wireless/filters.py +2 -2
- nautobot/wireless/forms.py +1 -1
- nautobot/wireless/templates/wireless/wirelessnetwork_retrieve.html +1 -9
- nautobot/wireless/tests/integration/__init__.py +0 -0
- nautobot/wireless/tests/integration/test_radio_profile.py +42 -0
- nautobot/wireless/tests/test_filters.py +29 -1
- nautobot/wireless/tests/test_views.py +22 -1
- nautobot/wireless/views.py +0 -10
- {nautobot-2.4.0b1.dist-info → nautobot-2.4.1.dist-info}/METADATA +6 -6
- {nautobot-2.4.0b1.dist-info → nautobot-2.4.1.dist-info}/RECORD +600 -550
- {nautobot-2.4.0b1.dist-info → nautobot-2.4.1.dist-info}/WHEEL +1 -1
- nautobot/core/fixtures/user-data.json +0 -59
- {nautobot-2.4.0b1.dist-info → nautobot-2.4.1.dist-info}/LICENSE.txt +0 -0
- {nautobot-2.4.0b1.dist-info → nautobot-2.4.1.dist-info}/NOTICE +0 -0
- {nautobot-2.4.0b1.dist-info → nautobot-2.4.1.dist-info}/entry_points.txt +0 -0
nautobot/dcim/forms.py
CHANGED
|
@@ -588,7 +588,7 @@ class RackBulkEditForm(
|
|
|
588
588
|
required=False,
|
|
589
589
|
widget=StaticSelect2(),
|
|
590
590
|
)
|
|
591
|
-
u_height = forms.IntegerField(required=False, label="Height (U)")
|
|
591
|
+
u_height = forms.IntegerField(required=False, label="Height (U)", min_value=1, max_value=100)
|
|
592
592
|
desc_units = forms.NullBooleanField(required=False, widget=BulkEditNullBooleanSelect, label="Descending units")
|
|
593
593
|
outer_width = forms.IntegerField(required=False, min_value=1)
|
|
594
594
|
outer_depth = forms.IntegerField(required=False, min_value=1)
|
|
@@ -796,7 +796,7 @@ class DeviceFamilyFilterForm(NautobotFilterForm):
|
|
|
796
796
|
tags = TagFilterField(model)
|
|
797
797
|
|
|
798
798
|
|
|
799
|
-
class DeviceFamilyBulkEditForm(
|
|
799
|
+
class DeviceFamilyBulkEditForm(TagsBulkEditFormMixin, NautobotBulkEditForm):
|
|
800
800
|
pk = forms.ModelMultipleChoiceField(queryset=DeviceFamily.objects.all(), widget=forms.MultipleHiddenInput())
|
|
801
801
|
description = forms.CharField(required=False)
|
|
802
802
|
|
|
@@ -878,7 +878,7 @@ class DeviceTypeBulkEditForm(TagsBulkEditFormMixin, NautobotBulkEditForm):
|
|
|
878
878
|
manufacturer = DynamicModelChoiceField(queryset=Manufacturer.objects.all(), required=False)
|
|
879
879
|
device_family = DynamicModelChoiceField(queryset=DeviceFamily.objects.all(), required=False)
|
|
880
880
|
software_image_files = DynamicModelMultipleChoiceField(queryset=SoftwareImageFile.objects.all(), required=False)
|
|
881
|
-
u_height = forms.IntegerField(required=False)
|
|
881
|
+
u_height = forms.IntegerField(required=False, min_value=0)
|
|
882
882
|
is_full_depth = forms.NullBooleanField(required=False, widget=BulkEditNullBooleanSelect(), label="Is full depth")
|
|
883
883
|
comments = CommentField(label="Comments", required=False)
|
|
884
884
|
|
|
@@ -1655,6 +1655,8 @@ class ComponentTemplateImportForm(BootstrapMixin, CustomFieldModelCSVForm):
|
|
|
1655
1655
|
netbox-community/devicetype-library repository.
|
|
1656
1656
|
"""
|
|
1657
1657
|
|
|
1658
|
+
Meta: type # to be defined by concrete subclasses
|
|
1659
|
+
|
|
1658
1660
|
def __init__(self, data=None, *args, **kwargs):
|
|
1659
1661
|
super().__init__(data, *args, **kwargs)
|
|
1660
1662
|
|
|
@@ -2127,6 +2129,8 @@ class DeviceBulkEditForm(
|
|
|
2127
2129
|
rack_group = DynamicModelChoiceField(
|
|
2128
2130
|
queryset=RackGroup.objects.all(), required=False, query_params={"location": "$location"}
|
|
2129
2131
|
)
|
|
2132
|
+
cluster = DynamicModelChoiceField(queryset=Cluster.objects.all(), required=False)
|
|
2133
|
+
comments = CommentField(widget=SmallTextarea, label="Comments")
|
|
2130
2134
|
tenant = DynamicModelChoiceField(queryset=Tenant.objects.all(), required=False)
|
|
2131
2135
|
platform = DynamicModelChoiceField(queryset=Platform.objects.all(), required=False)
|
|
2132
2136
|
serial = forms.CharField(max_length=CHARFIELD_MAX_LENGTH, required=False, label="Serial Number")
|
|
@@ -2150,6 +2154,8 @@ class DeviceBulkEditForm(
|
|
|
2150
2154
|
"position",
|
|
2151
2155
|
"face",
|
|
2152
2156
|
"rack_group",
|
|
2157
|
+
"cluster",
|
|
2158
|
+
"comments",
|
|
2153
2159
|
"secrets_group",
|
|
2154
2160
|
"device_redundancy_group",
|
|
2155
2161
|
"device_redundancy_group_priority",
|
|
@@ -3214,9 +3220,6 @@ class InterfaceBulkEditForm(
|
|
|
3214
3220
|
untagged_vlan = DynamicModelChoiceField(
|
|
3215
3221
|
queryset=VLAN.objects.all(),
|
|
3216
3222
|
required=False,
|
|
3217
|
-
query_params={
|
|
3218
|
-
"locations": "null",
|
|
3219
|
-
},
|
|
3220
3223
|
)
|
|
3221
3224
|
tagged_vlans = DynamicModelMultipleChoiceField(
|
|
3222
3225
|
queryset=VLAN.objects.all(),
|
|
@@ -3266,8 +3269,12 @@ class InterfaceBulkEditForm(
|
|
|
3266
3269
|
# Limit VLAN choices by Location
|
|
3267
3270
|
if locations.count() == 1:
|
|
3268
3271
|
location = locations.first()
|
|
3269
|
-
|
|
3272
|
+
# In the case of a single location, use the available_on_device query param to limit untagged VLAN choices
|
|
3273
|
+
# to those available on the devices in that location and in the ancestors of the location.
|
|
3274
|
+
self.fields["untagged_vlan"].widget.add_query_param("available_on_device", device.pk)
|
|
3270
3275
|
self.fields["tagged_vlans"].widget.add_query_param("locations", location.pk)
|
|
3276
|
+
else:
|
|
3277
|
+
self.fields["tagged_vlans"].widget.add_query_param("locations", "null")
|
|
3271
3278
|
|
|
3272
3279
|
# Restrict parent/bridge/LAG interface assignment by device (or VC master)
|
|
3273
3280
|
if device_count == 1:
|
|
@@ -4982,10 +4989,6 @@ class ControllerForm(LocatableModelFormMixin, NautobotModelForm, TenancyForm):
|
|
|
4982
4989
|
queryset=Platform.objects.all(),
|
|
4983
4990
|
required=False,
|
|
4984
4991
|
)
|
|
4985
|
-
tenant = DynamicModelChoiceField(
|
|
4986
|
-
queryset=Tenant.objects.all(),
|
|
4987
|
-
required=False,
|
|
4988
|
-
)
|
|
4989
4992
|
external_integration = DynamicModelChoiceField(
|
|
4990
4993
|
queryset=ExternalIntegration.objects.all(),
|
|
4991
4994
|
required=False,
|
|
@@ -5007,6 +5010,7 @@ class ControllerForm(LocatableModelFormMixin, NautobotModelForm, TenancyForm):
|
|
|
5007
5010
|
"role",
|
|
5008
5011
|
"description",
|
|
5009
5012
|
"platform",
|
|
5013
|
+
"tenant_group",
|
|
5010
5014
|
"tenant",
|
|
5011
5015
|
"location",
|
|
5012
5016
|
"capabilities",
|
|
@@ -5059,6 +5063,7 @@ class ControllerFilterForm(
|
|
|
5059
5063
|
"description",
|
|
5060
5064
|
"location",
|
|
5061
5065
|
"platform",
|
|
5066
|
+
"tenant_group",
|
|
5062
5067
|
"tenant",
|
|
5063
5068
|
"external_integration",
|
|
5064
5069
|
"controller_device",
|
|
@@ -5085,7 +5090,7 @@ class ControllerBulkEditForm(
|
|
|
5085
5090
|
required=False,
|
|
5086
5091
|
)
|
|
5087
5092
|
capabilities = JSONArrayFormField(
|
|
5088
|
-
choices=
|
|
5093
|
+
choices=ControllerCapabilitiesChoices,
|
|
5089
5094
|
base_field=forms.CharField(),
|
|
5090
5095
|
required=False,
|
|
5091
5096
|
)
|
|
@@ -5114,15 +5119,18 @@ class ControllerBulkEditForm(
|
|
|
5114
5119
|
"description",
|
|
5115
5120
|
"location",
|
|
5116
5121
|
"platform",
|
|
5117
|
-
"tenant",
|
|
5118
5122
|
"external_integration",
|
|
5119
5123
|
"controller_device",
|
|
5120
5124
|
"controller_device_redundancy_group",
|
|
5121
5125
|
"tags",
|
|
5122
5126
|
)
|
|
5127
|
+
nullable_fields = (
|
|
5128
|
+
"tenant",
|
|
5129
|
+
"capabilities",
|
|
5130
|
+
)
|
|
5123
5131
|
|
|
5124
5132
|
|
|
5125
|
-
class ControllerManagedDeviceGroupForm(NautobotModelForm):
|
|
5133
|
+
class ControllerManagedDeviceGroupForm(NautobotModelForm, TenancyForm):
|
|
5126
5134
|
"""ControllerManagedDeviceGroup create/edit form."""
|
|
5127
5135
|
|
|
5128
5136
|
controller = DynamicModelChoiceField(queryset=Controller.objects.all(), required=True)
|
|
@@ -5139,12 +5147,15 @@ class ControllerManagedDeviceGroupForm(NautobotModelForm):
|
|
|
5139
5147
|
fields = (
|
|
5140
5148
|
"controller",
|
|
5141
5149
|
"name",
|
|
5150
|
+
"description",
|
|
5142
5151
|
"devices",
|
|
5143
5152
|
"parent",
|
|
5144
5153
|
"capabilities",
|
|
5145
5154
|
"weight",
|
|
5146
5155
|
"radio_profiles",
|
|
5147
5156
|
"tags",
|
|
5157
|
+
"tenant_group",
|
|
5158
|
+
"tenant",
|
|
5148
5159
|
)
|
|
5149
5160
|
|
|
5150
5161
|
def __init__(self, *args, **kwargs):
|
|
@@ -5159,12 +5170,13 @@ class ControllerManagedDeviceGroupForm(NautobotModelForm):
|
|
|
5159
5170
|
return instance
|
|
5160
5171
|
|
|
5161
5172
|
|
|
5162
|
-
class ControllerManagedDeviceGroupFilterForm(NautobotFilterForm):
|
|
5173
|
+
class ControllerManagedDeviceGroupFilterForm(NautobotFilterForm, TenancyFilterForm):
|
|
5163
5174
|
"""ControllerManagedDeviceGroup basic filter form."""
|
|
5164
5175
|
|
|
5165
5176
|
model = ControllerManagedDeviceGroup
|
|
5166
5177
|
q = forms.CharField(required=False, label="Search")
|
|
5167
5178
|
name = forms.CharField(required=False, label="Name")
|
|
5179
|
+
description = forms.CharField(required=False, label="Description")
|
|
5168
5180
|
controller = DynamicModelChoiceField(
|
|
5169
5181
|
queryset=Controller.objects.all(),
|
|
5170
5182
|
required=False,
|
|
@@ -5185,11 +5197,14 @@ class ControllerManagedDeviceGroupFilterForm(NautobotFilterForm):
|
|
|
5185
5197
|
field_order = (
|
|
5186
5198
|
"q",
|
|
5187
5199
|
"name",
|
|
5200
|
+
"description",
|
|
5188
5201
|
"controller",
|
|
5189
5202
|
"parent",
|
|
5190
5203
|
"weight",
|
|
5191
5204
|
"subtree",
|
|
5192
5205
|
"tags",
|
|
5206
|
+
"tenant",
|
|
5207
|
+
"tenant_group",
|
|
5193
5208
|
)
|
|
5194
5209
|
|
|
5195
5210
|
|
|
@@ -5214,10 +5229,11 @@ class ControllerManagedDeviceGroupBulkEditForm(TagsBulkEditFormMixin, NautobotBu
|
|
|
5214
5229
|
label="Remove Radio Profiles",
|
|
5215
5230
|
)
|
|
5216
5231
|
capabilities = JSONArrayFormField(
|
|
5217
|
-
choices=
|
|
5232
|
+
choices=ControllerCapabilitiesChoices,
|
|
5218
5233
|
base_field=forms.CharField(),
|
|
5219
5234
|
required=False,
|
|
5220
5235
|
)
|
|
5236
|
+
tenant = DynamicModelChoiceField(queryset=Tenant.objects.all(), required=False)
|
|
5221
5237
|
|
|
5222
5238
|
class Meta:
|
|
5223
5239
|
model = ControllerManagedDeviceGroup
|
|
@@ -5225,9 +5241,12 @@ class ControllerManagedDeviceGroupBulkEditForm(TagsBulkEditFormMixin, NautobotBu
|
|
|
5225
5241
|
"controller",
|
|
5226
5242
|
"parent",
|
|
5227
5243
|
"weight",
|
|
5228
|
-
"capabilities",
|
|
5229
5244
|
"tags",
|
|
5230
5245
|
)
|
|
5246
|
+
nullable_fields = (
|
|
5247
|
+
"tenant",
|
|
5248
|
+
"capabilities",
|
|
5249
|
+
)
|
|
5231
5250
|
|
|
5232
5251
|
|
|
5233
5252
|
#
|
nautobot/dcim/graphql/types.py
CHANGED
|
@@ -98,13 +98,13 @@ class CableType(OptimizedNautobotObjectType):
|
|
|
98
98
|
|
|
99
99
|
def resolve_termination_a_type(self, args):
|
|
100
100
|
if self.termination_a_type:
|
|
101
|
-
model = self.termination_a_type.model_class()
|
|
101
|
+
model = self.termination_a_type.model_class() # pylint: disable=no-member
|
|
102
102
|
return f"{model._meta.app_label}.{model._meta.model_name}"
|
|
103
103
|
return None
|
|
104
104
|
|
|
105
105
|
def resolve_termination_b_type(self, args):
|
|
106
106
|
if self.termination_b_type:
|
|
107
|
-
model = self.termination_b_type.model_class()
|
|
107
|
+
model = self.termination_b_type.model_class() # pylint: disable=no-member
|
|
108
108
|
return f"{model._meta.app_label}.{model._meta.model_name}"
|
|
109
109
|
return None
|
|
110
110
|
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# Generated by Django 4.2.16 on 2024-11-21 12:35
|
|
2
|
+
|
|
3
|
+
from django.db import migrations, models
|
|
4
|
+
import django.db.models.deletion
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class Migration(migrations.Migration):
|
|
8
|
+
dependencies = [
|
|
9
|
+
("tenancy", "0009_update_all_charfields_max_length_to_255"),
|
|
10
|
+
("dcim", "0066_controllermanageddevicegroup_radio_profiles_and_more"),
|
|
11
|
+
]
|
|
12
|
+
|
|
13
|
+
operations = [
|
|
14
|
+
migrations.AddField(
|
|
15
|
+
model_name="controllermanageddevicegroup",
|
|
16
|
+
name="tenant",
|
|
17
|
+
field=models.ForeignKey(
|
|
18
|
+
blank=True,
|
|
19
|
+
null=True,
|
|
20
|
+
on_delete=django.db.models.deletion.PROTECT,
|
|
21
|
+
related_name="controller_managed_device_groups",
|
|
22
|
+
to="tenancy.tenant",
|
|
23
|
+
),
|
|
24
|
+
),
|
|
25
|
+
]
|
nautobot/dcim/models/__init__.py
CHANGED
|
@@ -63,12 +63,12 @@ __all__ = (
|
|
|
63
63
|
"Device",
|
|
64
64
|
"DeviceBay",
|
|
65
65
|
"DeviceBayTemplate",
|
|
66
|
+
"DeviceFamily",
|
|
66
67
|
"DeviceRedundancyGroup",
|
|
67
68
|
"DeviceType",
|
|
68
69
|
"DeviceTypeToSoftwareImageFile",
|
|
69
70
|
"FrontPort",
|
|
70
71
|
"FrontPortTemplate",
|
|
71
|
-
"DeviceFamily",
|
|
72
72
|
"Interface",
|
|
73
73
|
"InterfaceRedundancyGroup",
|
|
74
74
|
"InterfaceRedundancyGroupAssociation",
|
|
@@ -100,7 +100,7 @@ class ComponentTemplateModel(
|
|
|
100
100
|
def get_absolute_url(self, api=False):
|
|
101
101
|
# TODO: in the new UI, this should be able to link directly to the object, instead of the device-type.
|
|
102
102
|
if not api:
|
|
103
|
-
return self.device_type.get_absolute_url(api=api)
|
|
103
|
+
return self.device_type.get_absolute_url(api=api) # pylint: disable=no-member
|
|
104
104
|
return super().get_absolute_url(api=api)
|
|
105
105
|
|
|
106
106
|
def instantiate_model(self, model, device, **kwargs):
|
|
@@ -460,7 +460,7 @@ class DeviceBayTemplate(ComponentTemplateModel):
|
|
|
460
460
|
return self.instantiate_model(model=DeviceBay, device=device)
|
|
461
461
|
|
|
462
462
|
def clean(self):
|
|
463
|
-
if self.device_type and self.device_type.subdevice_role != SubdeviceRoleChoices.ROLE_PARENT:
|
|
463
|
+
if self.device_type and self.device_type.subdevice_role != SubdeviceRoleChoices.ROLE_PARENT: # pylint: disable=no-member
|
|
464
464
|
raise ValidationError(
|
|
465
465
|
f'Subdevice role of device type ({self.device_type}) must be set to "parent" to allow device bays.'
|
|
466
466
|
)
|
|
@@ -138,7 +138,7 @@ class ModularComponentModel(ComponentModel):
|
|
|
138
138
|
@property
|
|
139
139
|
def parent(self):
|
|
140
140
|
"""Device that this component belongs to, walking up module inheritance if necessary."""
|
|
141
|
-
return self.module.device if self.module else self.device
|
|
141
|
+
return self.module.device if self.module else self.device # pylint: disable=no-member
|
|
142
142
|
|
|
143
143
|
def render_name_template(self, save=False):
|
|
144
144
|
"""
|
|
@@ -161,9 +161,9 @@ class ModularComponentModel(ComponentModel):
|
|
|
161
161
|
|
|
162
162
|
The deeply nested interface would be named "A{module.parent}" after calling this method.
|
|
163
163
|
"""
|
|
164
|
-
if self.module and self.module.parent_module_bay and "{module" in self.name:
|
|
164
|
+
if self.module and self.module.parent_module_bay and "{module" in self.name: # pylint: disable=no-member
|
|
165
165
|
name = ""
|
|
166
|
-
module_bay = self.module.parent_module_bay
|
|
166
|
+
module_bay = self.module.parent_module_bay # pylint: disable=no-member
|
|
167
167
|
positions = []
|
|
168
168
|
while module_bay is not None:
|
|
169
169
|
position = getattr(module_bay, "position", None)
|
|
@@ -291,11 +291,11 @@ class PathEndpoint(models.Model):
|
|
|
291
291
|
return []
|
|
292
292
|
|
|
293
293
|
# Construct the complete path
|
|
294
|
-
path = [self, *self._path.get_path()]
|
|
294
|
+
path = [self, *self._path.get_path()] # pylint: disable=no-member
|
|
295
295
|
while (len(path) + 1) % 3:
|
|
296
296
|
# Pad to ensure we have complete three-tuples (e.g. for paths that end at a RearPort)
|
|
297
297
|
path.append(None)
|
|
298
|
-
path.append(self._path.destination)
|
|
298
|
+
path.append(self._path.destination) # pylint: disable=no-member
|
|
299
299
|
|
|
300
300
|
# Return the path as a list of three-tuples (A termination, cable, B termination)
|
|
301
301
|
return list(zip(*[iter(path)] * 3))
|
|
@@ -555,7 +555,7 @@ class BaseInterface(RelationshipModel):
|
|
|
555
555
|
|
|
556
556
|
def clean(self):
|
|
557
557
|
# Remove untagged VLAN assignment for non-802.1Q interfaces
|
|
558
|
-
if not self.mode and self.untagged_vlan is not None:
|
|
558
|
+
if not self.mode and self.untagged_vlan is not None: # pylint: disable=no-member # Intf/VMIntf both have untagged_vlan
|
|
559
559
|
raise ValidationError({"untagged_vlan": "Mode must be set when specifying untagged_vlan"})
|
|
560
560
|
|
|
561
561
|
def save(self, *args, **kwargs):
|
|
@@ -569,8 +569,8 @@ class BaseInterface(RelationshipModel):
|
|
|
569
569
|
self.status = status
|
|
570
570
|
|
|
571
571
|
# Only "tagged" interfaces may have tagged VLANs assigned. ("tagged all" implies all VLANs are assigned.)
|
|
572
|
-
if self.present_in_database and self.mode != InterfaceModeChoices.MODE_TAGGED:
|
|
573
|
-
self.tagged_vlans.clear()
|
|
572
|
+
if self.present_in_database and self.mode != InterfaceModeChoices.MODE_TAGGED: # pylint: disable=no-member
|
|
573
|
+
self.tagged_vlans.clear() # pylint: disable=no-member # Intf/VMIntf both have tagged_vlans
|
|
574
574
|
|
|
575
575
|
return super().save(*args, **kwargs)
|
|
576
576
|
|
|
@@ -710,18 +710,19 @@ class Interface(ModularComponentModel, CableTermination, PathEndpoint, BaseInter
|
|
|
710
710
|
)
|
|
711
711
|
|
|
712
712
|
# An interface's parent must belong to the same device or virtual chassis
|
|
713
|
-
if self.parent and self.parent_interface.parent != self.parent:
|
|
713
|
+
if self.parent and self.parent_interface.parent != self.parent: # pylint: disable=no-member
|
|
714
714
|
if getattr(self.parent, "virtual_chassis", None) is None:
|
|
715
715
|
raise ValidationError(
|
|
716
|
-
{
|
|
717
|
-
"parent_interface": f"The selected parent interface ({self.parent_interface}) belongs
|
|
718
|
-
f"({self.parent_interface.parent})."
|
|
716
|
+
{ # pylint: disable=no-member # false positive on parent_interface.parent
|
|
717
|
+
"parent_interface": f"The selected parent interface ({self.parent_interface}) belongs "
|
|
718
|
+
f"to a different device ({self.parent_interface.parent})."
|
|
719
719
|
}
|
|
720
720
|
)
|
|
721
|
-
elif self.parent_interface.parent.virtual_chassis != self.parent.virtual_chassis:
|
|
721
|
+
elif self.parent_interface.parent.virtual_chassis != self.parent.virtual_chassis: # pylint: disable=no-member
|
|
722
722
|
raise ValidationError(
|
|
723
|
-
{
|
|
724
|
-
"parent_interface": f"The selected parent interface ({self.parent_interface}) belongs
|
|
723
|
+
{ # pylint: disable=no-member # false positive on parent_interface.parent
|
|
724
|
+
"parent_interface": f"The selected parent interface ({self.parent_interface}) belongs "
|
|
725
|
+
f"to {self.parent_interface.parent}, which "
|
|
725
726
|
f"is not part of virtual chassis {self.parent.virtual_chassis}."
|
|
726
727
|
}
|
|
727
728
|
)
|
|
@@ -754,21 +755,22 @@ class Interface(ModularComponentModel, CableTermination, PathEndpoint, BaseInter
|
|
|
754
755
|
raise ValidationError({"bridge": "An interface cannot be bridged to itself."})
|
|
755
756
|
|
|
756
757
|
# A bridged interface belong to the same device or virtual chassis
|
|
757
|
-
if self.parent and self.bridge.parent != self.parent:
|
|
758
|
+
if self.parent and self.bridge.parent != self.parent: # pylint: disable=no-member
|
|
758
759
|
if getattr(self.parent, "virtual_chassis", None) is None:
|
|
759
760
|
raise ValidationError(
|
|
760
761
|
{
|
|
761
762
|
"bridge": (
|
|
763
|
+
# pylint: disable=no-member # false positive on bridge.parent
|
|
762
764
|
f"The selected bridge interface ({self.bridge}) belongs to a different device "
|
|
763
765
|
f"({self.bridge.parent})."
|
|
764
766
|
)
|
|
765
767
|
}
|
|
766
768
|
)
|
|
767
|
-
elif self.bridge.parent.virtual_chassis_id != self.parent.virtual_chassis_id:
|
|
769
|
+
elif self.bridge.parent.virtual_chassis_id != self.parent.virtual_chassis_id: # pylint: disable=no-member
|
|
768
770
|
raise ValidationError(
|
|
769
771
|
{
|
|
770
772
|
"bridge": (
|
|
771
|
-
f"The selected bridge interface ({self.bridge}) belongs to {self.bridge.parent}, which "
|
|
773
|
+
f"The selected bridge interface ({self.bridge}) belongs to {self.bridge.parent}, which " # pylint: disable=no-member
|
|
772
774
|
f"is not part of virtual chassis {self.parent.virtual_chassis}."
|
|
773
775
|
)
|
|
774
776
|
}
|
|
@@ -1084,8 +1086,8 @@ class DeviceBay(ComponentModel):
|
|
|
1084
1086
|
super().clean()
|
|
1085
1087
|
|
|
1086
1088
|
# Validate that the parent Device can have DeviceBays
|
|
1087
|
-
if not self.device.device_type.is_parent_device:
|
|
1088
|
-
raise ValidationError(f"This type of device ({self.device.device_type}) does not support device bays.")
|
|
1089
|
+
if not self.device.device_type.is_parent_device: # pylint: disable=no-member
|
|
1090
|
+
raise ValidationError(f"This type of device ({self.device.device_type}) does not support device bays.") # pylint: disable=no-member
|
|
1089
1091
|
|
|
1090
1092
|
# Cannot install a device into itself, obviously
|
|
1091
1093
|
if self.device == self.installed_device:
|
nautobot/dcim/models/devices.py
CHANGED
|
@@ -48,6 +48,7 @@ __all__ = (
|
|
|
48
48
|
"Controller",
|
|
49
49
|
"ControllerManagedDeviceGroup",
|
|
50
50
|
"Device",
|
|
51
|
+
"DeviceFamily",
|
|
51
52
|
"DeviceRedundancyGroup",
|
|
52
53
|
"DeviceType",
|
|
53
54
|
"InterfaceVDCAssignment",
|
|
@@ -823,6 +824,7 @@ class Device(PrimaryModel, ConfigContextModel):
|
|
|
823
824
|
|
|
824
825
|
# If any software image file is specified, validate that
|
|
825
826
|
# each of the software image files belongs to the device's device type or is a default image
|
|
827
|
+
# TODO: this is incorrect as we cannot validate a ManyToMany during clean() - nautobot/nautobot#6344
|
|
826
828
|
for image_file in self.software_image_files.all():
|
|
827
829
|
if not image_file.default_image and self.device_type not in image_file.device_types.all():
|
|
828
830
|
raise ValidationError(
|
|
@@ -1481,6 +1483,13 @@ class ControllerManagedDeviceGroup(TreeModel, PrimaryModel):
|
|
|
1481
1483
|
null=True,
|
|
1482
1484
|
help_text="List of capabilities supported by the controller device group, these capabilities are used to enhance views in Nautobot.",
|
|
1483
1485
|
)
|
|
1486
|
+
tenant = models.ForeignKey(
|
|
1487
|
+
to="tenancy.Tenant",
|
|
1488
|
+
on_delete=models.PROTECT,
|
|
1489
|
+
related_name="controller_managed_device_groups",
|
|
1490
|
+
blank=True,
|
|
1491
|
+
null=True,
|
|
1492
|
+
)
|
|
1484
1493
|
|
|
1485
1494
|
class Meta:
|
|
1486
1495
|
ordering = ("weight",)
|
|
@@ -1500,7 +1509,7 @@ class ControllerManagedDeviceGroup(TreeModel, PrimaryModel):
|
|
|
1500
1509
|
if self.controller == self._original_controller and self.parent == self._original_parent:
|
|
1501
1510
|
return
|
|
1502
1511
|
|
|
1503
|
-
if self.parent and self.controller and self.controller != self.parent.controller:
|
|
1512
|
+
if self.parent and self.controller and self.controller != self.parent.controller: # pylint: disable=no-member
|
|
1504
1513
|
raise ValidationError(
|
|
1505
1514
|
{"controller": "Controller device group must have the same controller as the parent group."}
|
|
1506
1515
|
)
|
|
@@ -283,7 +283,7 @@ class Location(TreeModel, PrimaryModel):
|
|
|
283
283
|
# We shouldn't have a parent, *unless* our own location type is permitted to be nested.
|
|
284
284
|
if self.parent is not None:
|
|
285
285
|
if self.location_type.nestable:
|
|
286
|
-
if self.parent.location_type != self.location_type:
|
|
286
|
+
if self.parent.location_type != self.location_type: # pylint: disable=no-member
|
|
287
287
|
raise ValidationError(
|
|
288
288
|
{
|
|
289
289
|
"parent": f"A Location of type {self.location_type} may only have "
|
|
@@ -304,7 +304,7 @@ class Location(TreeModel, PrimaryModel):
|
|
|
304
304
|
|
|
305
305
|
# Is the parent location of a correct type?
|
|
306
306
|
if self.location_type.nestable:
|
|
307
|
-
if self.parent.location_type not in (self.location_type, self.location_type.parent):
|
|
307
|
+
if self.parent.location_type not in (self.location_type, self.location_type.parent): # pylint: disable=no-member
|
|
308
308
|
raise ValidationError(
|
|
309
309
|
{
|
|
310
310
|
"parent": f"A Location of type {self.location_type} can only have a Location "
|
|
@@ -312,7 +312,7 @@ class Location(TreeModel, PrimaryModel):
|
|
|
312
312
|
}
|
|
313
313
|
)
|
|
314
314
|
else:
|
|
315
|
-
if self.parent.location_type != self.location_type.parent:
|
|
315
|
+
if self.parent.location_type != self.location_type.parent: # pylint: disable=no-member
|
|
316
316
|
raise ValidationError(
|
|
317
317
|
{
|
|
318
318
|
"parent": f"A Location of type {self.location_type} can only have a Location "
|
nautobot/dcim/models/power.py
CHANGED
|
@@ -73,11 +73,11 @@ class PowerPanel(PrimaryModel):
|
|
|
73
73
|
if self.rack_group:
|
|
74
74
|
if (
|
|
75
75
|
self.location is not None
|
|
76
|
-
and self.rack_group.location is not None
|
|
77
|
-
and self.rack_group.location not in self.location.ancestors(include_self=True)
|
|
76
|
+
and self.rack_group.location is not None # pylint: disable=no-member
|
|
77
|
+
and self.rack_group.location not in self.location.ancestors(include_self=True) # pylint: disable=no-member
|
|
78
78
|
):
|
|
79
79
|
raise ValidationError(
|
|
80
|
-
{
|
|
80
|
+
{ # pylint: disable=no-member # false positive on rack_group.location
|
|
81
81
|
"rack_group": f'Rack group "{self.rack_group}" belongs to a location '
|
|
82
82
|
f'("{self.rack_group.location}") that does not contain "{self.location}".'
|
|
83
83
|
}
|
|
@@ -151,9 +151,10 @@ class PowerFeed(PrimaryModel, PathEndpoint, CableTermination):
|
|
|
151
151
|
super().clean()
|
|
152
152
|
|
|
153
153
|
# Rack must belong to same Location as PowerPanel
|
|
154
|
-
if self.rack and self.rack.location != self.power_panel.location:
|
|
154
|
+
if self.rack and self.rack.location != self.power_panel.location: # pylint: disable=no-member
|
|
155
155
|
raise ValidationError(
|
|
156
|
-
f"Rack {self.rack} ({self.rack.location}) and
|
|
156
|
+
f"Rack {self.rack} ({self.rack.location}) and " # pylint: disable=no-member
|
|
157
|
+
f"power panel {self.power_panel} ({self.power_panel.location}) are in different locations"
|
|
157
158
|
)
|
|
158
159
|
|
|
159
160
|
# AC voltage cannot be negative
|
nautobot/dcim/models/racks.py
CHANGED
|
@@ -77,11 +77,11 @@ class RackGroup(TreeModel, OrganizationalModel):
|
|
|
77
77
|
# Parent RackGroup (if any) must belong to the same or ancestor Location
|
|
78
78
|
if (
|
|
79
79
|
self.parent is not None
|
|
80
|
-
and self.parent.location is not None
|
|
81
|
-
and self.parent.location not in self.location.ancestors(include_self=True)
|
|
80
|
+
and self.parent.location is not None # pylint: disable=no-member
|
|
81
|
+
and self.parent.location not in self.location.ancestors(include_self=True) # pylint: disable=no-member
|
|
82
82
|
):
|
|
83
83
|
raise ValidationError(
|
|
84
|
-
{
|
|
84
|
+
{ # pylint: disable=no-member # false positive on parent.location
|
|
85
85
|
"location": f'Location "{self.location}" is not descended from '
|
|
86
86
|
f'parent rack group "{self.parent}" location "{self.parent.location}".'
|
|
87
87
|
}
|
|
@@ -296,7 +296,7 @@ class Rack(PrimaryModel):
|
|
|
296
296
|
# Determine which devices the user has permission to view
|
|
297
297
|
permitted_device_ids = []
|
|
298
298
|
if user is not None:
|
|
299
|
-
permitted_device_ids = self.devices.restrict(user, "view").values_list("pk", flat=True)
|
|
299
|
+
permitted_device_ids = self.devices.restrict(user, "view").values_list("pk", flat=True) # pylint: disable=no-member
|
|
300
300
|
|
|
301
301
|
for device in queryset:
|
|
302
302
|
if expand_devices:
|
nautobot/dcim/tables/__init__.py
CHANGED
|
@@ -145,7 +145,7 @@ class ConsoleConnectionTable(BaseTable):
|
|
|
145
145
|
linkify=True,
|
|
146
146
|
verbose_name="Port",
|
|
147
147
|
)
|
|
148
|
-
device = tables.Column(linkify=True, accessor="parent")
|
|
148
|
+
device = tables.Column(linkify=True, accessor="parent", orderable=False)
|
|
149
149
|
name = tables.Column(linkify=True, verbose_name="Console Port")
|
|
150
150
|
reachable = BooleanColumn(accessor=Accessor("_path__is_active"), verbose_name="Reachable")
|
|
151
151
|
|
|
@@ -173,7 +173,7 @@ class PowerConnectionTable(BaseTable):
|
|
|
173
173
|
linkify=True,
|
|
174
174
|
verbose_name="Outlet",
|
|
175
175
|
)
|
|
176
|
-
device = tables.Column(linkify=True, accessor="parent")
|
|
176
|
+
device = tables.Column(linkify=True, accessor="parent", orderable=False)
|
|
177
177
|
name = tables.Column(linkify=True, verbose_name="Power Port")
|
|
178
178
|
reachable = BooleanColumn(accessor=Accessor("_path__is_active"), verbose_name="Reachable")
|
|
179
179
|
|
|
@@ -183,7 +183,7 @@ class PowerConnectionTable(BaseTable):
|
|
|
183
183
|
|
|
184
184
|
|
|
185
185
|
class InterfaceConnectionTable(BaseTable):
|
|
186
|
-
device_a = tables.Column(accessor=Accessor("parent"), linkify=True, verbose_name="Device A")
|
|
186
|
+
device_a = tables.Column(accessor=Accessor("parent"), linkify=True, verbose_name="Device A", orderable=False)
|
|
187
187
|
interface_a = tables.Column(accessor=Accessor("name"), linkify=True, verbose_name="Interface A")
|
|
188
188
|
device_b = tables.Column(
|
|
189
189
|
accessor=Accessor("_path__destination__parent"),
|
nautobot/dcim/tables/devices.py
CHANGED
|
@@ -64,8 +64,8 @@ from .template_code import (
|
|
|
64
64
|
__all__ = (
|
|
65
65
|
"ConsolePortTable",
|
|
66
66
|
"ConsoleServerPortTable",
|
|
67
|
-
"ControllerTable",
|
|
68
67
|
"ControllerManagedDeviceGroupTable",
|
|
68
|
+
"ControllerTable",
|
|
69
69
|
"DeviceBayTable",
|
|
70
70
|
"DeviceDeviceBayTable",
|
|
71
71
|
"DeviceImportTable",
|
|
@@ -75,19 +75,19 @@ __all__ = (
|
|
|
75
75
|
"DeviceModuleConsoleServerPortTable",
|
|
76
76
|
"DeviceModuleFrontPortTable",
|
|
77
77
|
"DeviceModuleInterfaceTable",
|
|
78
|
-
"DeviceModulePowerPortTable",
|
|
79
78
|
"DeviceModulePowerOutletTable",
|
|
79
|
+
"DeviceModulePowerPortTable",
|
|
80
80
|
"DeviceModuleRearPortTable",
|
|
81
81
|
"DeviceRedundancyGroupTable",
|
|
82
82
|
"DeviceTable",
|
|
83
83
|
"FrontPortTable",
|
|
84
|
-
"InterfaceTable",
|
|
85
|
-
"InterfaceRedundancyGroupTable",
|
|
86
84
|
"InterfaceRedundancyGroupAssociationTable",
|
|
85
|
+
"InterfaceRedundancyGroupTable",
|
|
86
|
+
"InterfaceTable",
|
|
87
87
|
"InventoryItemTable",
|
|
88
|
-
"ModuleTable",
|
|
89
88
|
"ModuleBayTable",
|
|
90
89
|
"ModuleModuleBayTable",
|
|
90
|
+
"ModuleTable",
|
|
91
91
|
"PlatformTable",
|
|
92
92
|
"PowerOutletTable",
|
|
93
93
|
"PowerPortTable",
|
|
@@ -1409,6 +1409,7 @@ class ControllerManagedDeviceGroupTable(BaseTable):
|
|
|
1409
1409
|
name = tables.TemplateColumn(template_code=TREE_LINK, attrs={"td": {"class": "text-nowrap"}})
|
|
1410
1410
|
weight = tables.Column()
|
|
1411
1411
|
controller = tables.Column(linkify=True)
|
|
1412
|
+
tenant = TenantColumn()
|
|
1412
1413
|
capabilities = tables.Column()
|
|
1413
1414
|
tags = TagColumn(url_name="dcim:controllermanageddevicegroup_list")
|
|
1414
1415
|
actions = ButtonsColumn(ControllerManagedDeviceGroup)
|
|
@@ -1440,6 +1441,7 @@ class ControllerManagedDeviceGroupTable(BaseTable):
|
|
|
1440
1441
|
"wireless_networks_count",
|
|
1441
1442
|
"controller",
|
|
1442
1443
|
"weight",
|
|
1444
|
+
"tenant",
|
|
1443
1445
|
"capabilities",
|
|
1444
1446
|
"tags",
|
|
1445
1447
|
"actions",
|
|
@@ -253,7 +253,7 @@ class PowerOutletTemplateTable(ComponentTemplateTable):
|
|
|
253
253
|
"name",
|
|
254
254
|
"label",
|
|
255
255
|
"type",
|
|
256
|
-
"
|
|
256
|
+
"power_port_template",
|
|
257
257
|
"feed_leg",
|
|
258
258
|
"description",
|
|
259
259
|
"actions",
|
|
@@ -290,7 +290,7 @@ class FrontPortTemplateTable(ComponentTemplateTable):
|
|
|
290
290
|
"name",
|
|
291
291
|
"label",
|
|
292
292
|
"type",
|
|
293
|
-
"
|
|
293
|
+
"rear_port_template",
|
|
294
294
|
"rear_port_position",
|
|
295
295
|
"description",
|
|
296
296
|
"actions",
|
nautobot/dcim/tables/racks.py
CHANGED
|
@@ -15,10 +15,10 @@ from nautobot.tenancy.tables import TenantColumn
|
|
|
15
15
|
from .template_code import RACKGROUP_ELEVATIONS, TREE_LINK, UTILIZATION_GRAPH
|
|
16
16
|
|
|
17
17
|
__all__ = (
|
|
18
|
-
"RackTable",
|
|
19
18
|
"RackDetailTable",
|
|
20
19
|
"RackGroupTable",
|
|
21
20
|
"RackReservationTable",
|
|
21
|
+
"RackTable",
|
|
22
22
|
)
|
|
23
23
|
|
|
24
24
|
|
|
@@ -34,13 +34,7 @@
|
|
|
34
34
|
{% endwith %}
|
|
35
35
|
</div>
|
|
36
36
|
</div>
|
|
37
|
-
|
|
38
|
-
<div class="panel-heading"><strong>Tenancy</strong></div>
|
|
39
|
-
<div class="panel-body">
|
|
40
|
-
{% render_field form.tenant_group %}
|
|
41
|
-
{% render_field form.tenant %}
|
|
42
|
-
</div>
|
|
43
|
-
</div>
|
|
37
|
+
{% include 'inc/tenancy_form_panel.html' %}
|
|
44
38
|
{% include 'inc/extras_features_edit_form_fields.html' %}
|
|
45
39
|
{% endblock form %}
|
|
46
40
|
|
|
@@ -34,15 +34,7 @@
|
|
|
34
34
|
<td>Platform</td>
|
|
35
35
|
<td>{{ object.platform|hyperlinked_object }}</td>
|
|
36
36
|
</tr>
|
|
37
|
-
|
|
38
|
-
<td>Tenant</td>
|
|
39
|
-
<td>
|
|
40
|
-
{% if object.tenant and object.tenant.tenant_group %}
|
|
41
|
-
{{ object.tenant.tenant_group|hyperlinked_object }} /
|
|
42
|
-
{% endif %}
|
|
43
|
-
{{ object.tenant|hyperlinked_object }}
|
|
44
|
-
</td>
|
|
45
|
-
</tr>
|
|
37
|
+
{% include 'inc/tenant_table_row.html' %}
|
|
46
38
|
<tr>
|
|
47
39
|
<td>Description</td>
|
|
48
40
|
<td>{{ object.description|placeholder }}</td>
|