nautobot 3.0.0a3__py3-none-any.whl → 3.0.0rc1__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.
- nautobot/apps/choices.py +4 -0
- nautobot/apps/ui.py +4 -0
- nautobot/apps/utils.py +8 -0
- nautobot/circuits/tests/integration/test_circuits_bulk_operations.py +0 -3
- nautobot/circuits/views.py +6 -2
- nautobot/core/api/serializers.py +1 -1
- nautobot/core/api/urls.py +1 -0
- nautobot/core/api/views.py +4 -0
- nautobot/core/choices.py +1 -1
- nautobot/core/cli/bootstrap_v3_to_v5.py +36 -13
- nautobot/core/cli/migrate_deprecated_templates.py +36 -9
- nautobot/core/filters.py +4 -0
- nautobot/core/forms/__init__.py +2 -0
- nautobot/core/forms/widgets.py +21 -2
- nautobot/core/jobs/__init__.py +56 -0
- nautobot/core/management/commands/generate_test_data.py +3 -3
- nautobot/core/models/__init__.py +11 -0
- nautobot/core/models/utils.py +1 -1
- nautobot/core/settings.py +17 -7
- nautobot/core/settings.yaml +4 -26
- nautobot/core/templates/admin/base.html +1 -2
- nautobot/core/templates/admin/change_list.html +9 -12
- nautobot/core/templates/base_django.html +1 -2
- nautobot/core/templates/components/panel/header_extra_content_table.html +1 -1
- nautobot/core/templates/components/tab/content_wrapper.html +4 -4
- nautobot/core/templates/echarts/echarts.html +21 -8
- nautobot/core/templates/generic/object_bulk_create.html +2 -2
- nautobot/core/templates/generic/object_bulk_delete.html +1 -1
- nautobot/core/templates/generic/object_bulk_edit.html +1 -1
- nautobot/core/templates/generic/object_bulk_import.html +1 -1
- nautobot/core/templates/generic/object_delete.html +1 -1
- nautobot/core/templates/generic/object_detail.html +1 -1
- nautobot/core/templates/generic/object_edit.html +1 -1
- nautobot/core/templates/generic/object_retrieve.html +2 -2
- nautobot/core/templates/graphene/graphiql.html +0 -1
- nautobot/core/templates/inc/footer.html +3 -1
- nautobot/core/templates/inc/header.html +10 -0
- nautobot/core/templates/inc/media.html +14 -0
- nautobot/core/templates/inc/nav_menu.html +1 -8
- nautobot/core/templates/inc/object_details_advanced_panel.html +2 -2
- nautobot/core/templates/nautobot_config.py.j2 +0 -6
- nautobot/core/templates/rest_framework/api.html +103 -2
- nautobot/core/templates/utilities/templatetags/filter_form_drawer.html +33 -0
- nautobot/core/templates/utilities/theme_preview.html +3 -0
- nautobot/core/templates/widgets/number_input_with_choices.html +44 -0
- nautobot/core/templatetags/helpers.py +24 -12
- nautobot/core/testing/integration.py +24 -13
- nautobot/core/testing/utils.py +18 -4
- nautobot/core/testing/views.py +104 -17
- nautobot/core/tests/integration/test_filters.py +48 -11
- nautobot/core/tests/integration/test_theme.py +22 -21
- nautobot/core/tests/nautobot_config.py +3 -0
- nautobot/core/tests/runner.py +1 -2
- nautobot/core/tests/test_breadcrumbs.py +21 -21
- nautobot/core/tests/test_jobs.py +73 -6
- nautobot/core/tests/test_renderers.py +59 -0
- nautobot/core/tests/test_settings_schema.py +1 -0
- nautobot/core/tests/test_templatetags_helpers.py +9 -0
- nautobot/core/tests/test_titles.py +0 -16
- nautobot/core/tests/test_ui.py +122 -3
- nautobot/core/tests/test_utils.py +41 -1
- nautobot/core/ui/breadcrumbs.py +68 -17
- nautobot/core/ui/bulk_buttons.py +1 -1
- nautobot/core/ui/choices.py +49 -65
- nautobot/core/ui/echarts.py +15 -20
- nautobot/core/ui/object_detail.py +54 -46
- nautobot/core/ui/titles.py +3 -6
- nautobot/core/urls.py +8 -8
- nautobot/core/utils/filtering.py +11 -1
- nautobot/core/utils/lookup.py +46 -0
- nautobot/core/views/mixins.py +31 -20
- nautobot/core/views/renderers.py +2 -3
- nautobot/data_validation/migrations/0002_data_migration_from_app.py +3 -2
- nautobot/dcim/api/serializers.py +3 -0
- nautobot/dcim/choices.py +49 -0
- nautobot/dcim/constants.py +7 -0
- nautobot/dcim/factory.py +1 -1
- nautobot/dcim/filters.py +13 -1
- nautobot/dcim/forms.py +89 -3
- nautobot/dcim/migrations/0075_interface_duplex_interface_speed_and_more.py +32 -0
- nautobot/dcim/migrations/{0075_add_deviceclusterassignment.py → 0076_add_deviceclusterassignment.py} +1 -1
- nautobot/dcim/migrations/{0076_device_cluster_to_clusters_data_migration.py → 0077_device_cluster_to_clusters_data_migration.py} +1 -1
- nautobot/dcim/migrations/{0077_remove_device_cluster.py → 0078_remove_device_cluster.py} +1 -1
- nautobot/dcim/migrations/{0078_remove_device_location_tenant_name_uniqueness.py → 0079_remove_device_location_tenant_name_uniqueness.py} +1 -1
- nautobot/dcim/migrations/{0079_device_name_data_migration.py → 0080_device_name_data_migration.py} +1 -1
- nautobot/dcim/migrations/0081_alter_device_device_redundancy_group_priority_and_more.py +25 -0
- nautobot/dcim/models/device_component_templates.py +33 -1
- nautobot/dcim/models/device_components.py +22 -1
- nautobot/dcim/models/devices.py +17 -4
- nautobot/dcim/tables/devices.py +15 -0
- nautobot/dcim/tables/devicetypes.py +8 -1
- nautobot/dcim/tables/racks.py +0 -2
- nautobot/dcim/tables/template_code.py +1 -1
- nautobot/dcim/templates/dcim/cable_trace.html +0 -2
- nautobot/dcim/templates/dcim/consoleport.html +1 -1
- nautobot/dcim/templates/dcim/consoleserverport.html +1 -1
- nautobot/dcim/templates/dcim/devicebay.html +1 -1
- nautobot/dcim/templates/dcim/frontport.html +1 -1
- nautobot/dcim/templates/dcim/inc/devicetype_component_table.html +1 -1
- nautobot/dcim/templates/dcim/inc/moduletype_component_table.html +1 -1
- nautobot/dcim/templates/dcim/inc/rack_elevation.html +1 -1
- nautobot/dcim/templates/dcim/interface.html +9 -1
- nautobot/dcim/templates/dcim/interface_edit.html +2 -0
- nautobot/dcim/templates/dcim/inventoryitem.html +1 -1
- nautobot/dcim/templates/dcim/module_consoleports.html +1 -1
- nautobot/dcim/templates/dcim/module_consoleserverports.html +1 -1
- nautobot/dcim/templates/dcim/module_frontports.html +1 -1
- nautobot/dcim/templates/dcim/module_interfaces.html +1 -1
- nautobot/dcim/templates/dcim/module_modulebays.html +1 -1
- nautobot/dcim/templates/dcim/module_poweroutlets.html +1 -1
- nautobot/dcim/templates/dcim/module_powerports.html +1 -1
- nautobot/dcim/templates/dcim/module_rearports.html +1 -1
- nautobot/dcim/templates/dcim/moduletype_list.html +2 -2
- nautobot/dcim/templates/dcim/poweroutlet.html +1 -1
- nautobot/dcim/templates/dcim/powerport.html +1 -1
- nautobot/dcim/templates/dcim/rack_elevation_list.html +1 -1
- nautobot/dcim/templates/dcim/rack_retrieve.html +0 -11
- nautobot/dcim/templates/dcim/rearport.html +1 -1
- nautobot/dcim/templates/dcim/trace/cable.html +1 -1
- nautobot/dcim/templates/dcim/virtualchassis_update.html +1 -1
- nautobot/dcim/tests/integration/test_controller.py +3 -6
- nautobot/dcim/tests/integration/test_controller_managed_device_group.py +1 -5
- nautobot/dcim/tests/integration/test_create_device.py +0 -2
- nautobot/dcim/tests/integration/test_device_bulk_operations.py +1 -3
- nautobot/dcim/tests/integration/test_fileinputpicker.py +6 -10
- nautobot/dcim/tests/integration/test_location_bulk_operations.py +0 -2
- nautobot/dcim/tests/integration/test_module_bay_position.py +3 -4
- nautobot/dcim/tests/test_api.py +186 -6
- nautobot/dcim/tests/test_filters.py +43 -1
- nautobot/dcim/tests/test_forms.py +110 -8
- nautobot/dcim/tests/test_graphql.py +44 -1
- nautobot/dcim/tests/test_models.py +265 -0
- nautobot/dcim/tests/test_tables.py +160 -0
- nautobot/dcim/tests/test_views.py +69 -7
- nautobot/dcim/views.py +232 -126
- nautobot/extras/api/views.py +51 -44
- nautobot/extras/datasources/git.py +3 -1
- nautobot/extras/filters.py +19 -2
- nautobot/extras/forms/forms.py +9 -2
- nautobot/extras/jobs.py +2 -0
- nautobot/extras/jobs_ui.py +4 -3
- nautobot/extras/management/__init__.py +2 -0
- nautobot/extras/management/commands/refresh_dynamic_group_member_caches.py +4 -1
- nautobot/extras/migrations/0131_configcontext_device_families.py +18 -0
- nautobot/extras/models/approvals.py +11 -1
- nautobot/extras/models/change_logging.py +4 -0
- nautobot/extras/models/jobs.py +1 -3
- nautobot/extras/models/models.py +10 -2
- nautobot/extras/plugins/marketplace_manifest.yml +49 -1
- nautobot/extras/plugins/views.py +0 -5
- nautobot/extras/querysets.py +8 -0
- nautobot/extras/tables.py +12 -0
- nautobot/extras/templates/django_ajax_tables/ajax_wrapper.html +2 -0
- nautobot/extras/templates/extras/configcontext_update.html +1 -0
- nautobot/extras/templates/extras/dynamicgroup_update.html +1 -1
- nautobot/extras/templates/extras/objectchange_retrieve.html +0 -2
- nautobot/extras/templates/extras/plugin_detail.html +3 -3
- nautobot/extras/templates/extras/secret_create.html +1 -1
- nautobot/extras/tests/integration/test_computedfields.py +8 -9
- nautobot/extras/tests/integration/test_customfields.py +1 -3
- nautobot/extras/tests/integration/test_dynamicgroups.py +7 -8
- nautobot/extras/tests/integration/test_relationships.py +0 -2
- nautobot/extras/tests/test_api.py +63 -0
- nautobot/extras/tests/test_changelog.py +24 -2
- nautobot/extras/tests/test_filters.py +36 -3
- nautobot/extras/tests/test_models.py +38 -2
- nautobot/extras/tests/test_utils.py +3 -4
- nautobot/extras/tests/test_views.py +22 -83
- nautobot/extras/urls.py +0 -14
- nautobot/extras/views.py +83 -52
- nautobot/ipam/filters.py +26 -0
- nautobot/ipam/tables.py +6 -0
- nautobot/ipam/templates/ipam/namespace_ip_addresses.html +1 -1
- nautobot/ipam/templates/ipam/namespace_prefixes.html +1 -1
- nautobot/ipam/templates/ipam/namespace_vrfs.html +1 -1
- nautobot/ipam/tests/test_filters.py +26 -1
- nautobot/ipam/tests/test_models.py +1 -1
- nautobot/ipam/views.py +9 -7
- nautobot/load_balancers/__init__.py +0 -0
- nautobot/load_balancers/api/__init__.py +1 -0
- nautobot/load_balancers/api/serializers.py +75 -0
- nautobot/load_balancers/api/urls.py +23 -0
- nautobot/load_balancers/api/views.py +61 -0
- nautobot/load_balancers/apps.py +17 -0
- nautobot/load_balancers/choices.py +167 -0
- nautobot/load_balancers/filters.py +225 -0
- nautobot/load_balancers/forms.py +532 -0
- nautobot/load_balancers/management/commands/__init__.py +0 -0
- nautobot/load_balancers/management/commands/generate_load_balancer_models_test_data.py +38 -0
- nautobot/load_balancers/migrations/0001_initial.py +465 -0
- nautobot/load_balancers/migrations/0002_create_default_statuses_pool_members.py +31 -0
- nautobot/load_balancers/migrations/__init__.py +0 -0
- nautobot/load_balancers/models.py +423 -0
- nautobot/load_balancers/navigation.py +80 -0
- nautobot/load_balancers/tables.py +255 -0
- nautobot/load_balancers/tests/__init__.py +474 -0
- nautobot/load_balancers/tests/test_api.py +353 -0
- nautobot/load_balancers/tests/test_filters.py +134 -0
- nautobot/load_balancers/tests/test_forms.py +266 -0
- nautobot/load_balancers/tests/test_models.py +195 -0
- nautobot/load_balancers/tests/test_views.py +229 -0
- nautobot/load_balancers/urls.py +17 -0
- nautobot/load_balancers/views.py +248 -0
- nautobot/project-static/dist/css/github-dark.min.css +10 -0
- nautobot/project-static/dist/css/github.min.css +10 -0
- nautobot/project-static/dist/css/nautobot.css +1 -11
- nautobot/project-static/dist/css/nautobot.css.map +1 -1
- nautobot/project-static/dist/js/libraries.js +1 -1
- nautobot/project-static/dist/js/libraries.js.map +1 -1
- nautobot/project-static/dist/js/nautobot.js +1 -1
- nautobot/project-static/dist/js/nautobot.js.map +1 -1
- nautobot/project-static/js/forms.js +13 -0
- nautobot/project-static/nautobot-icons/bus-globe.svg +3 -0
- nautobot/project-static/nautobot-icons/bus-shield-check.svg +3 -0
- nautobot/project-static/nautobot-icons/bus-shield.svg +3 -0
- nautobot/ui/package-lock.json +87 -4
- nautobot/ui/package.json +2 -1
- nautobot/ui/src/js/nautobot.js +0 -1
- nautobot/ui/src/js/select2.js +53 -2
- nautobot/ui/src/scss/nautobot.scss +51 -2
- nautobot/ui/webpack.config.js +13 -0
- nautobot/users/templates/users/preferences.html +11 -2
- nautobot/virtualization/filters.py +6 -1
- nautobot/virtualization/tests/test_filters.py +10 -1
- nautobot/virtualization/tests/test_models.py +1 -0
- nautobot/virtualization/views.py +4 -1
- nautobot/vpn/factory.py +25 -15
- nautobot/vpn/filters.py +1 -0
- nautobot/vpn/forms.py +1 -0
- nautobot/vpn/migrations/0001_initial.py +1 -1
- nautobot/vpn/models.py +16 -8
- nautobot/vpn/tables.py +5 -2
- nautobot/vpn/tests/test_api.py +0 -5
- nautobot/vpn/tests/test_forms.py +1 -2
- nautobot/vpn/tests/test_models.py +57 -7
- nautobot/vpn/tests/test_views.py +22 -3
- nautobot/vpn/views.py +78 -20
- {nautobot-3.0.0a3.dist-info → nautobot-3.0.0rc1.dist-info}/METADATA +4 -4
- {nautobot-3.0.0a3.dist-info → nautobot-3.0.0rc1.dist-info}/RECORD +243 -352
- nautobot/circuits/templates/circuits/circuit.html +0 -2
- nautobot/circuits/templates/circuits/circuit_edit.html +0 -2
- nautobot/circuits/templates/circuits/circuit_retrieve.html +0 -2
- nautobot/circuits/templates/circuits/circuit_update.html +0 -1
- nautobot/circuits/templates/circuits/circuittermination.html +0 -2
- nautobot/circuits/templates/circuits/circuittermination_edit.html +0 -2
- nautobot/circuits/templates/circuits/circuittermination_retrieve.html +0 -2
- nautobot/circuits/templates/circuits/circuittermination_update.html +0 -1
- nautobot/circuits/templates/circuits/circuittype.html +0 -2
- nautobot/circuits/templates/circuits/circuittype_retrieve.html +0 -2
- nautobot/circuits/templates/circuits/inc/circuit_termination.html +0 -85
- nautobot/circuits/templates/circuits/provider.html +0 -2
- nautobot/circuits/templates/circuits/provider_edit.html +0 -2
- nautobot/circuits/templates/circuits/provider_retrieve.html +0 -1
- nautobot/circuits/templates/circuits/provider_update.html +0 -1
- nautobot/circuits/templates/circuits/providernetwork.html +0 -2
- nautobot/circuits/templates/circuits/providernetwork_retrieve.html +0 -2
- nautobot/cloud/templates/cloud/cloudaccount_retrieve.html +0 -2
- nautobot/cloud/templates/cloud/cloudnetwork_retrieve.html +0 -2
- nautobot/cloud/templates/cloud/cloudresourcetype_retrieve.html +0 -2
- nautobot/cloud/templates/cloud/cloudservice_retrieve.html +0 -2
- nautobot/core/templates/buttons/import.html +0 -9
- nautobot/data_validation/templates/data_validation/datacompliance_retrieve.html +0 -1
- nautobot/dcim/templates/dcim/cable.html +0 -2
- nautobot/dcim/templates/dcim/cable_edit.html +0 -2
- nautobot/dcim/templates/dcim/controller/base.html +0 -2
- nautobot/dcim/templates/dcim/controller_retrieve.html +0 -2
- nautobot/dcim/templates/dcim/controller_wirelessnetworks.html +0 -2
- nautobot/dcim/templates/dcim/controllermanageddevicegroup_retrieve.html +0 -2
- nautobot/dcim/templates/dcim/device/base.html +0 -2
- nautobot/dcim/templates/dcim/device/consoleports.html +0 -2
- nautobot/dcim/templates/dcim/device/consoleserverports.html +0 -2
- nautobot/dcim/templates/dcim/device/devicebays.html +0 -2
- nautobot/dcim/templates/dcim/device/frontports.html +0 -2
- nautobot/dcim/templates/dcim/device/interfaces.html +0 -2
- nautobot/dcim/templates/dcim/device/inventory.html +0 -2
- nautobot/dcim/templates/dcim/device/modulebays.html +0 -2
- nautobot/dcim/templates/dcim/device/poweroutlets.html +0 -2
- nautobot/dcim/templates/dcim/device/powerports.html +0 -2
- nautobot/dcim/templates/dcim/device/rearports.html +0 -2
- nautobot/dcim/templates/dcim/device/wireless.html +0 -2
- nautobot/dcim/templates/dcim/device_component.html +0 -2
- nautobot/dcim/templates/dcim/device_edit.html +0 -2
- nautobot/dcim/templates/dcim/devicefamily_retrieve.html +0 -2
- nautobot/dcim/templates/dcim/deviceredundancygroup_retrieve.html +0 -2
- nautobot/dcim/templates/dcim/devicetype.html +0 -2
- nautobot/dcim/templates/dcim/devicetype_edit.html +0 -2
- nautobot/dcim/templates/dcim/devicetype_retrieve.html +0 -2
- nautobot/dcim/templates/dcim/inc/device_napalm_tabs.html +0 -1
- nautobot/dcim/templates/dcim/interfaceredundancygroup_retrieve.html +0 -2
- nautobot/dcim/templates/dcim/location.html +0 -2
- nautobot/dcim/templates/dcim/location_edit.html +0 -2
- nautobot/dcim/templates/dcim/location_retrieve.html +0 -2
- nautobot/dcim/templates/dcim/locationtype.html +0 -2
- nautobot/dcim/templates/dcim/locationtype_retrieve.html +0 -2
- nautobot/dcim/templates/dcim/manufacturer.html +0 -2
- nautobot/dcim/templates/dcim/modulebay_retrieve.html +0 -1
- nautobot/dcim/templates/dcim/platform.html +0 -2
- nautobot/dcim/templates/dcim/powerfeed.html +0 -2
- nautobot/dcim/templates/dcim/powerfeed_retrieve.html +0 -2
- nautobot/dcim/templates/dcim/powerpanel.html +0 -2
- nautobot/dcim/templates/dcim/powerpanel_edit.html +0 -2
- nautobot/dcim/templates/dcim/powerpanel_retrieve.html +0 -2
- nautobot/dcim/templates/dcim/rack.html +0 -2
- nautobot/dcim/templates/dcim/rack_edit.html +0 -2
- nautobot/dcim/templates/dcim/rackgroup.html +0 -2
- nautobot/dcim/templates/dcim/rackreservation.html +0 -2
- nautobot/dcim/templates/dcim/softwareimagefile_retrieve.html +0 -2
- nautobot/dcim/templates/dcim/softwareversion_retrieve.html +0 -2
- nautobot/dcim/templates/dcim/virtualchassis.html +0 -2
- nautobot/dcim/templates/dcim/virtualchassis_add.html +0 -2
- nautobot/dcim/templates/dcim/virtualchassis_edit.html +0 -2
- nautobot/dcim/templates/dcim/virtualchassis_retrieve.html +0 -2
- nautobot/dcim/templates/dcim/virtualdevicecontext_retrieve.html +0 -2
- nautobot/dcim/ui.py +0 -29
- nautobot/extras/templates/extras/computedfield.html +0 -2
- nautobot/extras/templates/extras/computedfield_retrieve.html +0 -2
- nautobot/extras/templates/extras/configcontext.html +0 -2
- nautobot/extras/templates/extras/configcontext_edit.html +0 -2
- nautobot/extras/templates/extras/configcontext_retrieve.html +0 -2
- nautobot/extras/templates/extras/configcontextschema.html +0 -2
- nautobot/extras/templates/extras/configcontextschema_edit.html +0 -2
- nautobot/extras/templates/extras/contact_retrieve.html +0 -2
- nautobot/extras/templates/extras/customfield.html +0 -2
- nautobot/extras/templates/extras/customfield_edit.html +0 -2
- nautobot/extras/templates/extras/customfield_retrieve.html +0 -2
- nautobot/extras/templates/extras/customlink.html +0 -2
- nautobot/extras/templates/extras/dynamicgroup.html +0 -2
- nautobot/extras/templates/extras/dynamicgroup_edit.html +0 -2
- nautobot/extras/templates/extras/exporttemplate.html +0 -2
- nautobot/extras/templates/extras/gitrepository.html +0 -2
- nautobot/extras/templates/extras/gitrepository_object_edit.html +0 -2
- nautobot/extras/templates/extras/graphqlquery.html +0 -2
- nautobot/extras/templates/extras/graphqlquery_list.html +0 -1
- nautobot/extras/templates/extras/graphqlquery_retrieve.html +0 -2
- nautobot/extras/templates/extras/job_detail.html +0 -2
- nautobot/extras/templates/extras/jobbutton_retrieve.html +0 -2
- nautobot/extras/templates/extras/jobhook.html +0 -2
- nautobot/extras/templates/extras/jobqueue_retrieve.html +0 -2
- nautobot/extras/templates/extras/jobresult.html +0 -2
- nautobot/extras/templates/extras/metadatatype_retrieve.html +0 -2
- nautobot/extras/templates/extras/note.html +0 -2
- nautobot/extras/templates/extras/note_retrieve.html +0 -1
- nautobot/extras/templates/extras/object_changelog.html +0 -2
- nautobot/extras/templates/extras/object_notes.html +0 -2
- nautobot/extras/templates/extras/objectchange.html +0 -2
- nautobot/extras/templates/extras/objectchange_list.html +0 -3
- nautobot/extras/templates/extras/relationship.html +0 -1
- nautobot/extras/templates/extras/secret.html +0 -1
- nautobot/extras/templates/extras/secret_edit.html +0 -1
- nautobot/extras/templates/extras/secretsgroup.html +0 -2
- nautobot/extras/templates/extras/secretsgroup_edit.html +0 -2
- nautobot/extras/templates/extras/secretsgroup_retrieve.html +0 -2
- nautobot/extras/templates/extras/status.html +0 -2
- nautobot/extras/templates/extras/tag.html +0 -2
- nautobot/extras/templates/extras/tag_edit.html +0 -2
- nautobot/extras/templates/extras/tag_retrieve.html +0 -2
- nautobot/extras/templates/extras/team_retrieve.html +0 -2
- nautobot/ipam/templates/ipam/namespace_retrieve.html +0 -1
- nautobot/ipam/templates/ipam/prefix.html +0 -2
- nautobot/ipam/templates/ipam/prefix_edit.html +0 -1
- nautobot/ipam/templates/ipam/prefix_retrieve.html +0 -2
- nautobot/ipam/templates/ipam/rir.html +0 -2
- nautobot/ipam/templates/ipam/routetarget.html +0 -1
- nautobot/ipam/templates/ipam/service.html +0 -2
- nautobot/ipam/templates/ipam/service_edit.html +0 -2
- nautobot/ipam/templates/ipam/service_retrieve.html +0 -2
- nautobot/ipam/templates/ipam/vlan.html +0 -2
- nautobot/ipam/templates/ipam/vlan_edit.html +0 -2
- nautobot/ipam/templates/ipam/vlan_retrieve.html +0 -2
- nautobot/ipam/templates/ipam/vlangroup.html +0 -2
- nautobot/ipam/templates/ipam/vrf.html +0 -1
- nautobot/tenancy/templates/tenancy/tenant.html +0 -2
- nautobot/tenancy/templates/tenancy/tenant_edit.html +0 -2
- nautobot/tenancy/templates/tenancy/tenantgroup.html +0 -2
- nautobot/tenancy/templates/tenancy/tenantgroup_retrieve.html +0 -1
- nautobot/virtualization/templates/virtualization/clustergroup.html +0 -2
- nautobot/virtualization/templates/virtualization/clustertype.html +0 -2
- nautobot/virtualization/templates/virtualization/virtualmachine.html +0 -2
- nautobot/virtualization/templates/virtualization/virtualmachine_edit.html +0 -2
- nautobot/virtualization/templates/virtualization/virtualmachine_retrieve.html +0 -2
- nautobot/vpn/templates/vpn/vpnprofile.html +0 -2
- nautobot/wireless/templates/wireless/radioprofile_retrieve.html +0 -2
- nautobot/wireless/templates/wireless/supporteddatarate_retrieve.html +0 -2
- nautobot/wireless/templates/wireless/wirelessnetwork_retrieve.html +0 -2
- {nautobot-3.0.0a3.dist-info → nautobot-3.0.0rc1.dist-info}/LICENSE.txt +0 -0
- {nautobot-3.0.0a3.dist-info → nautobot-3.0.0rc1.dist-info}/NOTICE +0 -0
- {nautobot-3.0.0a3.dist-info → nautobot-3.0.0rc1.dist-info}/WHEEL +0 -0
- {nautobot-3.0.0a3.dist-info → nautobot-3.0.0rc1.dist-info}/entry_points.txt +0 -0
nautobot/dcim/filters.py
CHANGED
|
@@ -10,6 +10,7 @@ from nautobot.core.filters import (
|
|
|
10
10
|
ModelMultipleChoiceFilter,
|
|
11
11
|
MultiValueCharFilter,
|
|
12
12
|
MultiValueMACAddressFilter,
|
|
13
|
+
MultiValueNumberFilter,
|
|
13
14
|
MultiValueUUIDFilter,
|
|
14
15
|
NameSearchFilterSet,
|
|
15
16
|
NaturalKeyOrPKMultipleChoiceFilter,
|
|
@@ -22,6 +23,8 @@ from nautobot.dcim.choices import (
|
|
|
22
23
|
CableTypeChoices,
|
|
23
24
|
ConsolePortTypeChoices,
|
|
24
25
|
ControllerCapabilitiesChoices,
|
|
26
|
+
InterfaceDuplexChoices,
|
|
27
|
+
InterfaceSpeedChoices,
|
|
25
28
|
InterfaceTypeChoices,
|
|
26
29
|
PowerOutletTypeChoices,
|
|
27
30
|
PowerPortTypeChoices,
|
|
@@ -102,7 +105,7 @@ from nautobot.extras.filters import (
|
|
|
102
105
|
)
|
|
103
106
|
from nautobot.extras.models import ExternalIntegration, SecretsGroup
|
|
104
107
|
from nautobot.extras.utils import FeatureQuery
|
|
105
|
-
from nautobot.ipam.models import IPAddress, VLAN, VLANGroup
|
|
108
|
+
from nautobot.ipam.models import IPAddress, VLAN, VLANGroup, VRF
|
|
106
109
|
from nautobot.tenancy.filter_mixins import TenancyModelFilterSetMixin
|
|
107
110
|
from nautobot.tenancy.models import Tenant
|
|
108
111
|
from nautobot.virtualization.models import Cluster, VirtualMachine
|
|
@@ -930,6 +933,11 @@ class DeviceFilterSet(
|
|
|
930
933
|
to_field_name="name",
|
|
931
934
|
label="Controller (name or ID)",
|
|
932
935
|
)
|
|
936
|
+
vrfs = NaturalKeyOrPKMultipleChoiceFilter(
|
|
937
|
+
queryset=VRF.objects.all(),
|
|
938
|
+
to_field_name="rd",
|
|
939
|
+
label="VRFs (ID or RD)",
|
|
940
|
+
)
|
|
933
941
|
|
|
934
942
|
def filter_ip_addresses(self, queryset, name, value):
|
|
935
943
|
pk_values = set(item for item in value if is_uuid(item))
|
|
@@ -1129,6 +1137,8 @@ class InterfaceFilterSet(
|
|
|
1129
1137
|
vlan_id = django_filters.CharFilter(method="filter_vlan_id", label="Assigned VLAN")
|
|
1130
1138
|
vlan = django_filters.NumberFilter(method="filter_vlan", label="Assigned VID")
|
|
1131
1139
|
type = django_filters.MultipleChoiceFilter(choices=InterfaceTypeChoices, null_value=None)
|
|
1140
|
+
duplex = django_filters.MultipleChoiceFilter(choices=InterfaceDuplexChoices, null_value=None)
|
|
1141
|
+
speed = MultiValueNumberFilter(lookup_expr="exact", choices=InterfaceSpeedChoices)
|
|
1132
1142
|
interface_redundancy_groups = NaturalKeyOrPKMultipleChoiceFilter(
|
|
1133
1143
|
queryset=InterfaceRedundancyGroup.objects.all(),
|
|
1134
1144
|
to_field_name="name",
|
|
@@ -1161,6 +1171,8 @@ class InterfaceFilterSet(
|
|
|
1161
1171
|
"id",
|
|
1162
1172
|
"name",
|
|
1163
1173
|
"type",
|
|
1174
|
+
"duplex",
|
|
1175
|
+
"speed",
|
|
1164
1176
|
"enabled",
|
|
1165
1177
|
"mtu",
|
|
1166
1178
|
"mgmt_only",
|
nautobot/dcim/forms.py
CHANGED
|
@@ -27,7 +27,9 @@ from nautobot.core.forms import (
|
|
|
27
27
|
form_from_model,
|
|
28
28
|
JSONArrayFormField,
|
|
29
29
|
MultipleContentTypeField,
|
|
30
|
+
MultiValueCharInput,
|
|
30
31
|
NullableDateField,
|
|
32
|
+
NumberWithSelect,
|
|
31
33
|
NumericArrayField,
|
|
32
34
|
SelectWithPK,
|
|
33
35
|
SmallTextarea,
|
|
@@ -37,7 +39,8 @@ from nautobot.core.forms import (
|
|
|
37
39
|
)
|
|
38
40
|
from nautobot.core.forms.constants import BOOLEAN_WITH_BLANK_CHOICES
|
|
39
41
|
from nautobot.core.forms.fields import LaxURLField
|
|
40
|
-
from nautobot.
|
|
42
|
+
from nautobot.core.utils.config import get_settings_or_config
|
|
43
|
+
from nautobot.dcim.constants import RACK_U_HEIGHT_DEFAULT, RACK_U_HEIGHT_MAXIMUM
|
|
41
44
|
from nautobot.dcim.form_mixins import (
|
|
42
45
|
LocatableModelBulkEditFormMixin,
|
|
43
46
|
LocatableModelFilterFormMixin,
|
|
@@ -84,8 +87,10 @@ from .choices import (
|
|
|
84
87
|
ControllerCapabilitiesChoices,
|
|
85
88
|
DeviceFaceChoices,
|
|
86
89
|
DeviceRedundancyGroupFailoverStrategyChoices,
|
|
90
|
+
InterfaceDuplexChoices,
|
|
87
91
|
InterfaceModeChoices,
|
|
88
92
|
InterfaceRedundancyGroupProtocolChoices,
|
|
93
|
+
InterfaceSpeedChoices,
|
|
89
94
|
InterfaceTypeChoices,
|
|
90
95
|
LocationDataToContactActionChoices,
|
|
91
96
|
PortTypeChoices,
|
|
@@ -527,6 +532,17 @@ class RackForm(LocatableModelFormMixin, NautobotModelForm, TenancyForm):
|
|
|
527
532
|
)
|
|
528
533
|
comments = CommentField()
|
|
529
534
|
|
|
535
|
+
def __init__(self, *args, **kwargs):
|
|
536
|
+
super().__init__(*args, **kwargs)
|
|
537
|
+
# Set initial value for u_height from Constance config when creating a new rack
|
|
538
|
+
if not self.instance.present_in_database and not kwargs.get("data"):
|
|
539
|
+
# Only set initial if this is a new form (not submitted data)
|
|
540
|
+
config_default = get_settings_or_config("RACK_DEFAULT_U_HEIGHT", fallback=RACK_U_HEIGHT_DEFAULT)
|
|
541
|
+
self.fields["u_height"].initial = config_default
|
|
542
|
+
# Override the form's initial dict to ensure it displays the Constance config value
|
|
543
|
+
# (unconditionally set it, even if already present from model default)
|
|
544
|
+
self.initial["u_height"] = config_default
|
|
545
|
+
|
|
530
546
|
class Meta:
|
|
531
547
|
model = Rack
|
|
532
548
|
fields = [
|
|
@@ -1460,16 +1476,29 @@ class InterfaceTemplateForm(ModularComponentTemplateForm):
|
|
|
1460
1476
|
"label",
|
|
1461
1477
|
"type",
|
|
1462
1478
|
"mgmt_only",
|
|
1479
|
+
"speed",
|
|
1480
|
+
"duplex",
|
|
1463
1481
|
"description",
|
|
1464
1482
|
]
|
|
1465
1483
|
widgets = {
|
|
1466
1484
|
"type": StaticSelect2(),
|
|
1485
|
+
"speed": NumberWithSelect(choices=InterfaceSpeedChoices),
|
|
1486
|
+
"duplex": StaticSelect2(),
|
|
1487
|
+
}
|
|
1488
|
+
labels = {
|
|
1489
|
+
"speed": "Speed (Kbps)",
|
|
1467
1490
|
}
|
|
1468
1491
|
|
|
1469
1492
|
|
|
1470
1493
|
class InterfaceTemplateCreateForm(ModularComponentTemplateCreateForm):
|
|
1471
1494
|
type = forms.ChoiceField(choices=InterfaceTypeChoices, widget=StaticSelect2())
|
|
1472
1495
|
mgmt_only = forms.BooleanField(required=False, label="Management only")
|
|
1496
|
+
speed = forms.IntegerField(
|
|
1497
|
+
required=False, min_value=0, label="Speed (Kbps)", widget=NumberWithSelect(choices=InterfaceSpeedChoices)
|
|
1498
|
+
)
|
|
1499
|
+
duplex = forms.ChoiceField(
|
|
1500
|
+
choices=add_blank_choice(InterfaceDuplexChoices), required=False, widget=StaticSelect2(), label="Duplex"
|
|
1501
|
+
)
|
|
1473
1502
|
field_order = (
|
|
1474
1503
|
"device_type",
|
|
1475
1504
|
"module_family",
|
|
@@ -1478,6 +1507,8 @@ class InterfaceTemplateCreateForm(ModularComponentTemplateCreateForm):
|
|
|
1478
1507
|
"label_pattern",
|
|
1479
1508
|
"type",
|
|
1480
1509
|
"mgmt_only",
|
|
1510
|
+
"speed",
|
|
1511
|
+
"duplex",
|
|
1481
1512
|
"description",
|
|
1482
1513
|
)
|
|
1483
1514
|
|
|
@@ -1491,10 +1522,16 @@ class InterfaceTemplateBulkEditForm(NautobotBulkEditForm):
|
|
|
1491
1522
|
widget=StaticSelect2(),
|
|
1492
1523
|
)
|
|
1493
1524
|
mgmt_only = forms.NullBooleanField(required=False, widget=BulkEditNullBooleanSelect, label="Management only")
|
|
1525
|
+
speed = forms.IntegerField(
|
|
1526
|
+
required=False, min_value=0, label="Speed (Kbps)", widget=NumberWithSelect(choices=InterfaceSpeedChoices)
|
|
1527
|
+
)
|
|
1528
|
+
duplex = forms.ChoiceField(
|
|
1529
|
+
choices=add_blank_choice(InterfaceDuplexChoices), required=False, widget=StaticSelect2(), label="Duplex"
|
|
1530
|
+
)
|
|
1494
1531
|
description = forms.CharField(required=False)
|
|
1495
1532
|
|
|
1496
1533
|
class Meta:
|
|
1497
|
-
nullable_fields = ["label", "description"]
|
|
1534
|
+
nullable_fields = ["label", "speed", "duplex", "description"]
|
|
1498
1535
|
|
|
1499
1536
|
|
|
1500
1537
|
class FrontPortTemplateForm(ModularComponentTemplateForm):
|
|
@@ -1965,6 +2002,8 @@ class InterfaceTemplateImportForm(ComponentTemplateImportForm):
|
|
|
1965
2002
|
"label",
|
|
1966
2003
|
"type",
|
|
1967
2004
|
"mgmt_only",
|
|
2005
|
+
"speed",
|
|
2006
|
+
"duplex",
|
|
1968
2007
|
]
|
|
1969
2008
|
|
|
1970
2009
|
|
|
@@ -3137,6 +3176,7 @@ class PowerOutletBulkEditForm(
|
|
|
3137
3176
|
class InterfaceFilterForm(ModularDeviceComponentFilterForm, RoleModelFilterFormMixin, StatusModelFilterFormMixin):
|
|
3138
3177
|
model = Interface
|
|
3139
3178
|
type = forms.MultipleChoiceField(choices=InterfaceTypeChoices, required=False, widget=StaticSelect2Multiple())
|
|
3179
|
+
speed = forms.MultipleChoiceField(choices=InterfaceSpeedChoices, required=False, widget=MultiValueCharInput)
|
|
3140
3180
|
enabled = forms.NullBooleanField(required=False, widget=StaticSelect2(choices=BOOLEAN_WITH_BLANK_CHOICES))
|
|
3141
3181
|
mgmt_only = forms.NullBooleanField(required=False, widget=StaticSelect2(choices=BOOLEAN_WITH_BLANK_CHOICES))
|
|
3142
3182
|
mac_address = forms.CharField(required=False, label="MAC address")
|
|
@@ -3221,6 +3261,8 @@ class InterfaceForm(InterfaceCommonForm, ModularComponentEditForm):
|
|
|
3221
3261
|
"bridge",
|
|
3222
3262
|
"lag",
|
|
3223
3263
|
"mac_address",
|
|
3264
|
+
"speed",
|
|
3265
|
+
"duplex",
|
|
3224
3266
|
"ip_addresses",
|
|
3225
3267
|
"virtual_device_contexts",
|
|
3226
3268
|
"mtu",
|
|
@@ -3236,9 +3278,12 @@ class InterfaceForm(InterfaceCommonForm, ModularComponentEditForm):
|
|
|
3236
3278
|
widgets = {
|
|
3237
3279
|
"type": StaticSelect2(),
|
|
3238
3280
|
"mode": StaticSelect2(),
|
|
3281
|
+
"speed": NumberWithSelect(choices=InterfaceSpeedChoices),
|
|
3282
|
+
"duplex": StaticSelect2(),
|
|
3239
3283
|
}
|
|
3240
3284
|
labels = {
|
|
3241
3285
|
"mode": "802.1Q Mode",
|
|
3286
|
+
"speed": "Speed (Kbps)",
|
|
3242
3287
|
}
|
|
3243
3288
|
help_texts = {
|
|
3244
3289
|
"mode": INTERFACE_MODE_HELP_TEXT,
|
|
@@ -3311,6 +3356,12 @@ class InterfaceCreateForm(ModularComponentCreateForm, InterfaceCommonForm, RoleN
|
|
|
3311
3356
|
},
|
|
3312
3357
|
)
|
|
3313
3358
|
mac_address = forms.CharField(required=False, label="MAC Address")
|
|
3359
|
+
speed = forms.IntegerField(
|
|
3360
|
+
required=False, min_value=0, label="Speed (Kbps)", widget=NumberWithSelect(choices=InterfaceSpeedChoices)
|
|
3361
|
+
)
|
|
3362
|
+
duplex = forms.ChoiceField(
|
|
3363
|
+
choices=add_blank_choice(InterfaceDuplexChoices), required=False, widget=StaticSelect2(), label="Duplex"
|
|
3364
|
+
)
|
|
3314
3365
|
mgmt_only = forms.BooleanField(
|
|
3315
3366
|
required=False,
|
|
3316
3367
|
label="Management only",
|
|
@@ -3357,6 +3408,8 @@ class InterfaceCreateForm(ModularComponentCreateForm, InterfaceCommonForm, RoleN
|
|
|
3357
3408
|
"status",
|
|
3358
3409
|
"role",
|
|
3359
3410
|
"type",
|
|
3411
|
+
"speed",
|
|
3412
|
+
"duplex",
|
|
3360
3413
|
"enabled",
|
|
3361
3414
|
"parent_interface",
|
|
3362
3415
|
"bridge",
|
|
@@ -3390,6 +3443,10 @@ class InterfaceBulkCreateForm(
|
|
|
3390
3443
|
queryset=Status.objects.all(),
|
|
3391
3444
|
query_params={"content_types": Interface._meta.label_lower},
|
|
3392
3445
|
)
|
|
3446
|
+
speed = forms.IntegerField(required=False, min_value=0, label="Speed (Kbps)")
|
|
3447
|
+
duplex = forms.ChoiceField(
|
|
3448
|
+
choices=add_blank_choice(InterfaceDuplexChoices), required=False, widget=StaticSelect2(), label="Duplex"
|
|
3449
|
+
)
|
|
3393
3450
|
|
|
3394
3451
|
field_order = (
|
|
3395
3452
|
"name_pattern",
|
|
@@ -3403,6 +3460,8 @@ class InterfaceBulkCreateForm(
|
|
|
3403
3460
|
"mgmt_only",
|
|
3404
3461
|
"description",
|
|
3405
3462
|
"mode",
|
|
3463
|
+
"speed",
|
|
3464
|
+
"duplex",
|
|
3406
3465
|
"tags",
|
|
3407
3466
|
)
|
|
3408
3467
|
|
|
@@ -3422,6 +3481,10 @@ class ModuleInterfaceBulkCreateForm(
|
|
|
3422
3481
|
queryset=Status.objects.all(),
|
|
3423
3482
|
query_params={"content_types": Interface._meta.label_lower},
|
|
3424
3483
|
)
|
|
3484
|
+
speed = forms.IntegerField(required=False, min_value=0, label="Speed (Kbps)")
|
|
3485
|
+
duplex = forms.ChoiceField(
|
|
3486
|
+
choices=add_blank_choice(InterfaceDuplexChoices), required=False, widget=StaticSelect2(), label="Duplex"
|
|
3487
|
+
)
|
|
3425
3488
|
|
|
3426
3489
|
field_order = (
|
|
3427
3490
|
"name_pattern",
|
|
@@ -3435,13 +3498,28 @@ class ModuleInterfaceBulkCreateForm(
|
|
|
3435
3498
|
"mgmt_only",
|
|
3436
3499
|
"description",
|
|
3437
3500
|
"mode",
|
|
3501
|
+
"speed",
|
|
3502
|
+
"duplex",
|
|
3438
3503
|
"tags",
|
|
3439
3504
|
)
|
|
3440
3505
|
|
|
3441
3506
|
|
|
3442
3507
|
class InterfaceBulkEditForm(
|
|
3443
3508
|
form_from_model(
|
|
3444
|
-
Interface,
|
|
3509
|
+
Interface,
|
|
3510
|
+
[
|
|
3511
|
+
"label",
|
|
3512
|
+
"type",
|
|
3513
|
+
"parent_interface",
|
|
3514
|
+
"bridge",
|
|
3515
|
+
"lag",
|
|
3516
|
+
"mac_address",
|
|
3517
|
+
"mtu",
|
|
3518
|
+
"description",
|
|
3519
|
+
"mode",
|
|
3520
|
+
"speed",
|
|
3521
|
+
"duplex",
|
|
3522
|
+
],
|
|
3445
3523
|
),
|
|
3446
3524
|
TagsBulkEditFormMixin,
|
|
3447
3525
|
StatusModelBulkEditFormMixin,
|
|
@@ -3485,6 +3563,12 @@ class InterfaceBulkEditForm(
|
|
|
3485
3563
|
label="VRF",
|
|
3486
3564
|
required=False,
|
|
3487
3565
|
)
|
|
3566
|
+
speed = forms.IntegerField(
|
|
3567
|
+
required=False, min_value=0, label="Speed (Kbps)", widget=NumberWithSelect(choices=InterfaceSpeedChoices)
|
|
3568
|
+
)
|
|
3569
|
+
duplex = forms.ChoiceField(
|
|
3570
|
+
choices=add_blank_choice(InterfaceDuplexChoices), required=False, widget=StaticSelect2(), label="Duplex"
|
|
3571
|
+
)
|
|
3488
3572
|
|
|
3489
3573
|
class Meta:
|
|
3490
3574
|
nullable_fields = [
|
|
@@ -3496,6 +3580,8 @@ class InterfaceBulkEditForm(
|
|
|
3496
3580
|
"mtu",
|
|
3497
3581
|
"description",
|
|
3498
3582
|
"mode",
|
|
3583
|
+
"speed",
|
|
3584
|
+
"duplex",
|
|
3499
3585
|
"untagged_vlan",
|
|
3500
3586
|
"tagged_vlans",
|
|
3501
3587
|
"vrf",
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# Generated by Django 4.2.25 on 2025-11-01 22:09
|
|
2
|
+
|
|
3
|
+
from django.db import migrations, models
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class Migration(migrations.Migration):
|
|
7
|
+
dependencies = [
|
|
8
|
+
("dcim", "0074_alter_rack_u_height"),
|
|
9
|
+
]
|
|
10
|
+
|
|
11
|
+
operations = [
|
|
12
|
+
migrations.AddField(
|
|
13
|
+
model_name="interface",
|
|
14
|
+
name="duplex",
|
|
15
|
+
field=models.CharField(blank=True, default="", max_length=10),
|
|
16
|
+
),
|
|
17
|
+
migrations.AddField(
|
|
18
|
+
model_name="interface",
|
|
19
|
+
name="speed",
|
|
20
|
+
field=models.PositiveIntegerField(blank=True, null=True),
|
|
21
|
+
),
|
|
22
|
+
migrations.AddField(
|
|
23
|
+
model_name="interfacetemplate",
|
|
24
|
+
name="duplex",
|
|
25
|
+
field=models.CharField(blank=True, default="", max_length=10),
|
|
26
|
+
),
|
|
27
|
+
migrations.AddField(
|
|
28
|
+
model_name="interfacetemplate",
|
|
29
|
+
name="speed",
|
|
30
|
+
field=models.PositiveIntegerField(blank=True, null=True),
|
|
31
|
+
),
|
|
32
|
+
]
|
nautobot/dcim/migrations/{0075_add_deviceclusterassignment.py → 0076_add_deviceclusterassignment.py}
RENAMED
|
@@ -6,7 +6,7 @@ import django.db.models.deletion
|
|
|
6
6
|
|
|
7
7
|
class Migration(migrations.Migration):
|
|
8
8
|
dependencies = [
|
|
9
|
-
("dcim", "
|
|
9
|
+
("dcim", "0075_interface_duplex_interface_speed_and_more"),
|
|
10
10
|
("virtualization", "0030_alter_virtualmachine_local_config_context_data_owner_content_type_and_more"),
|
|
11
11
|
]
|
|
12
12
|
|
nautobot/dcim/migrations/{0079_device_name_data_migration.py → 0080_device_name_data_migration.py}
RENAMED
|
@@ -47,7 +47,7 @@ def reverse_migrate_device_uniqueness_setting(apps, schema_editor):
|
|
|
47
47
|
|
|
48
48
|
class Migration(migrations.Migration):
|
|
49
49
|
dependencies = [
|
|
50
|
-
("dcim", "
|
|
50
|
+
("dcim", "0079_remove_device_location_tenant_name_uniqueness"),
|
|
51
51
|
("constance", "0003_drop_pickle"),
|
|
52
52
|
]
|
|
53
53
|
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# Generated by Django 4.2.25 on 2025-11-05 19:42
|
|
2
|
+
|
|
3
|
+
import django.core.validators
|
|
4
|
+
from django.db import migrations, models
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class Migration(migrations.Migration):
|
|
8
|
+
dependencies = [
|
|
9
|
+
("dcim", "0080_device_name_data_migration"),
|
|
10
|
+
]
|
|
11
|
+
|
|
12
|
+
operations = [
|
|
13
|
+
migrations.AlterField(
|
|
14
|
+
model_name="device",
|
|
15
|
+
name="device_redundancy_group_priority",
|
|
16
|
+
field=models.PositiveIntegerField(
|
|
17
|
+
blank=True, null=True, validators=[django.core.validators.MinValueValidator(1)]
|
|
18
|
+
),
|
|
19
|
+
),
|
|
20
|
+
migrations.AlterField(
|
|
21
|
+
model_name="interfaceredundancygroupassociation",
|
|
22
|
+
name="priority",
|
|
23
|
+
field=models.PositiveIntegerField(),
|
|
24
|
+
),
|
|
25
|
+
]
|
|
@@ -11,6 +11,7 @@ from nautobot.core.models.fields import ForeignKeyWithAutoRelatedName, NaturalOr
|
|
|
11
11
|
from nautobot.core.models.ordering import naturalize_interface
|
|
12
12
|
from nautobot.dcim.choices import (
|
|
13
13
|
ConsolePortTypeChoices,
|
|
14
|
+
InterfaceDuplexChoices,
|
|
14
15
|
InterfaceTypeChoices,
|
|
15
16
|
PortTypeChoices,
|
|
16
17
|
PowerOutletFeedLegChoices,
|
|
@@ -18,7 +19,13 @@ from nautobot.dcim.choices import (
|
|
|
18
19
|
PowerPortTypeChoices,
|
|
19
20
|
SubdeviceRoleChoices,
|
|
20
21
|
)
|
|
21
|
-
from nautobot.dcim.constants import
|
|
22
|
+
from nautobot.dcim.constants import (
|
|
23
|
+
COPPER_TWISTED_PAIR_IFACE_TYPES,
|
|
24
|
+
REARPORT_POSITIONS_MAX,
|
|
25
|
+
REARPORT_POSITIONS_MIN,
|
|
26
|
+
VIRTUAL_IFACE_TYPES,
|
|
27
|
+
WIRELESS_IFACE_TYPES,
|
|
28
|
+
)
|
|
22
29
|
from nautobot.extras.models import (
|
|
23
30
|
ChangeLoggedModel,
|
|
24
31
|
ContactMixin,
|
|
@@ -349,6 +356,29 @@ class InterfaceTemplate(ModularComponentTemplateModel):
|
|
|
349
356
|
)
|
|
350
357
|
type = models.CharField(max_length=50, choices=InterfaceTypeChoices)
|
|
351
358
|
mgmt_only = models.BooleanField(default=False, verbose_name="Management only")
|
|
359
|
+
speed = models.PositiveIntegerField(null=True, blank=True)
|
|
360
|
+
duplex = models.CharField(max_length=10, choices=InterfaceDuplexChoices, blank=True, default="")
|
|
361
|
+
|
|
362
|
+
def clean(self):
|
|
363
|
+
super().clean()
|
|
364
|
+
self._validate_speed_and_duplex()
|
|
365
|
+
|
|
366
|
+
def _validate_speed_and_duplex(self):
|
|
367
|
+
"""Validate speed (Kbps) and duplex based on interface type."""
|
|
368
|
+
|
|
369
|
+
is_lag = self.type == InterfaceTypeChoices.TYPE_LAG
|
|
370
|
+
is_virtual = self.type in VIRTUAL_IFACE_TYPES
|
|
371
|
+
is_wireless = self.type in WIRELESS_IFACE_TYPES
|
|
372
|
+
|
|
373
|
+
# Check settings by interface type
|
|
374
|
+
if self.speed and any([is_lag, is_virtual, is_wireless]):
|
|
375
|
+
raise ValidationError({"speed": "Speed is not applicable to this interface type."})
|
|
376
|
+
|
|
377
|
+
if self.duplex and any([is_lag, is_virtual, is_wireless]):
|
|
378
|
+
raise ValidationError({"duplex": "Duplex is not applicable to this interface type."})
|
|
379
|
+
|
|
380
|
+
if self.duplex and self.type not in COPPER_TWISTED_PAIR_IFACE_TYPES:
|
|
381
|
+
raise ValidationError({"duplex": "Duplex is only applicable to copper twisted-pair interfaces."})
|
|
352
382
|
|
|
353
383
|
def instantiate(self, device, module=None):
|
|
354
384
|
try:
|
|
@@ -361,6 +391,8 @@ class InterfaceTemplate(ModularComponentTemplateModel):
|
|
|
361
391
|
module=module,
|
|
362
392
|
type=self.type,
|
|
363
393
|
mgmt_only=self.mgmt_only,
|
|
394
|
+
speed=self.speed,
|
|
395
|
+
duplex=self.duplex,
|
|
364
396
|
status=status,
|
|
365
397
|
)
|
|
366
398
|
|
|
@@ -20,6 +20,7 @@ from nautobot.core.utils.cache import construct_cache_key
|
|
|
20
20
|
from nautobot.core.utils.data import UtilizationData
|
|
21
21
|
from nautobot.dcim.choices import (
|
|
22
22
|
ConsolePortTypeChoices,
|
|
23
|
+
InterfaceDuplexChoices,
|
|
23
24
|
InterfaceModeChoices,
|
|
24
25
|
InterfaceRedundancyGroupProtocolChoices,
|
|
25
26
|
InterfaceStatusChoices,
|
|
@@ -32,6 +33,7 @@ from nautobot.dcim.choices import (
|
|
|
32
33
|
SubdeviceRoleChoices,
|
|
33
34
|
)
|
|
34
35
|
from nautobot.dcim.constants import (
|
|
36
|
+
COPPER_TWISTED_PAIR_IFACE_TYPES,
|
|
35
37
|
NONCONNECTABLE_IFACE_TYPES,
|
|
36
38
|
REARPORT_POSITIONS_MAX,
|
|
37
39
|
REARPORT_POSITIONS_MIN,
|
|
@@ -744,6 +746,9 @@ class Interface(ModularComponentModel, CableTermination, PathEndpoint, BaseInter
|
|
|
744
746
|
blank=True,
|
|
745
747
|
verbose_name="IP Addresses",
|
|
746
748
|
)
|
|
749
|
+
# Operational attributes (distinct from interface type capabilities)
|
|
750
|
+
speed = models.PositiveIntegerField(null=True, blank=True)
|
|
751
|
+
duplex = models.CharField(max_length=10, choices=InterfaceDuplexChoices, blank=True, default="")
|
|
747
752
|
|
|
748
753
|
class Meta(ModularComponentModel.Meta):
|
|
749
754
|
ordering = ("device", "module__id", CollateAsChar("_name")) # Module.ordering is complex; don't order by module
|
|
@@ -878,6 +883,22 @@ class Interface(ModularComponentModel, CableTermination, PathEndpoint, BaseInter
|
|
|
878
883
|
}
|
|
879
884
|
)
|
|
880
885
|
|
|
886
|
+
# Speed/Duplex validation
|
|
887
|
+
self._validate_speed_and_duplex()
|
|
888
|
+
|
|
889
|
+
def _validate_speed_and_duplex(self):
|
|
890
|
+
"""Validate speed (Kbps) and duplex based on interface type."""
|
|
891
|
+
|
|
892
|
+
# Check settings by interface type
|
|
893
|
+
if self.speed and any([self.is_lag, self.is_virtual, self.is_wireless]):
|
|
894
|
+
raise ValidationError({"speed": "Speed is not applicable to this interface type."})
|
|
895
|
+
|
|
896
|
+
if self.duplex and any([self.is_lag, self.is_virtual, self.is_wireless]):
|
|
897
|
+
raise ValidationError({"duplex": "Duplex is not applicable to this interface type."})
|
|
898
|
+
|
|
899
|
+
if self.duplex and self.type not in COPPER_TWISTED_PAIR_IFACE_TYPES:
|
|
900
|
+
raise ValidationError({"duplex": "Duplex is only applicable to copper twisted-pair interfaces."})
|
|
901
|
+
|
|
881
902
|
@property
|
|
882
903
|
def is_connectable(self):
|
|
883
904
|
return self.type not in NONCONNECTABLE_IFACE_TYPES
|
|
@@ -1010,7 +1031,7 @@ class InterfaceRedundancyGroupAssociation(BaseModel, ChangeLoggedModel):
|
|
|
1010
1031
|
on_delete=models.CASCADE,
|
|
1011
1032
|
related_name="interface_redundancy_group_associations",
|
|
1012
1033
|
)
|
|
1013
|
-
priority = models.
|
|
1034
|
+
priority = models.PositiveIntegerField()
|
|
1014
1035
|
is_metadata_associable_model = False
|
|
1015
1036
|
|
|
1016
1037
|
class Meta:
|
nautobot/dcim/models/devices.py
CHANGED
|
@@ -392,6 +392,10 @@ class DeviceType(PrimaryModel):
|
|
|
392
392
|
def display(self):
|
|
393
393
|
return f"{self.manufacturer.name} {self.model}"
|
|
394
394
|
|
|
395
|
+
@property
|
|
396
|
+
def page_title(self):
|
|
397
|
+
return str(self)
|
|
398
|
+
|
|
395
399
|
@property
|
|
396
400
|
def is_parent_device(self):
|
|
397
401
|
return self.subdevice_role == SubdeviceRoleChoices.ROLE_PARENT
|
|
@@ -621,7 +625,7 @@ class Device(PrimaryModel, ConfigContextModel):
|
|
|
621
625
|
null=True,
|
|
622
626
|
verbose_name="Device Redundancy Group",
|
|
623
627
|
)
|
|
624
|
-
device_redundancy_group_priority = models.
|
|
628
|
+
device_redundancy_group_priority = models.PositiveIntegerField(
|
|
625
629
|
blank=True,
|
|
626
630
|
null=True,
|
|
627
631
|
validators=[MinValueValidator(1)],
|
|
@@ -1950,10 +1954,19 @@ class Module(PrimaryModel):
|
|
|
1950
1954
|
def display(self):
|
|
1951
1955
|
if self.location:
|
|
1952
1956
|
return f"{self!s} at location {self.location}"
|
|
1953
|
-
|
|
1957
|
+
if self.parent_module_bay.parent_device is not None:
|
|
1954
1958
|
return f"{self.module_type!s} installed in {self.parent_module_bay.parent_device.display}"
|
|
1955
|
-
|
|
1956
|
-
|
|
1959
|
+
|
|
1960
|
+
return f"{self.module_type!s} installed in {self.parent_module_bay.parent_module.display}"
|
|
1961
|
+
|
|
1962
|
+
@property
|
|
1963
|
+
def page_title(self):
|
|
1964
|
+
if self.location:
|
|
1965
|
+
return f"{self.module_type!s} at location {self.location}"
|
|
1966
|
+
if self.parent_module_bay.parent_device is not None:
|
|
1967
|
+
return f"{self.module_type!s} installed in {self.parent_module_bay.parent_device.display}"
|
|
1968
|
+
|
|
1969
|
+
return f"{self.module_type!s} installed in {self.parent_module_bay.parent_module.module_type!s}"
|
|
1957
1970
|
|
|
1958
1971
|
@property
|
|
1959
1972
|
def device(self):
|
nautobot/dcim/tables/devices.py
CHANGED
|
@@ -11,6 +11,7 @@ from nautobot.core.tables import (
|
|
|
11
11
|
TagColumn,
|
|
12
12
|
ToggleColumn,
|
|
13
13
|
)
|
|
14
|
+
from nautobot.core.templatetags.helpers import humanize_speed
|
|
14
15
|
from nautobot.dcim.models import (
|
|
15
16
|
ConsolePort,
|
|
16
17
|
ConsoleServerPort,
|
|
@@ -728,6 +729,8 @@ class InterfaceTable(ModularDeviceComponentTable, BaseInterfaceTable, PathEndpoi
|
|
|
728
729
|
url_params={"interfaces": "pk"},
|
|
729
730
|
verbose_name="Virtual Device Contexts",
|
|
730
731
|
)
|
|
732
|
+
speed = tables.Column(verbose_name="Speed", accessor="speed", orderable=True)
|
|
733
|
+
duplex = tables.Column(verbose_name="Duplex", accessor="duplex", orderable=True)
|
|
731
734
|
|
|
732
735
|
class Meta(ModularDeviceComponentTable.Meta):
|
|
733
736
|
model = Interface
|
|
@@ -741,6 +744,8 @@ class InterfaceTable(ModularDeviceComponentTable, BaseInterfaceTable, PathEndpoi
|
|
|
741
744
|
"label",
|
|
742
745
|
"enabled",
|
|
743
746
|
"type",
|
|
747
|
+
"speed",
|
|
748
|
+
"duplex",
|
|
744
749
|
"mgmt_only",
|
|
745
750
|
"mtu",
|
|
746
751
|
"vrf",
|
|
@@ -766,9 +771,13 @@ class InterfaceTable(ModularDeviceComponentTable, BaseInterfaceTable, PathEndpoi
|
|
|
766
771
|
"label",
|
|
767
772
|
"enabled",
|
|
768
773
|
"type",
|
|
774
|
+
"speed",
|
|
769
775
|
"description",
|
|
770
776
|
)
|
|
771
777
|
|
|
778
|
+
def render_speed(self, record):
|
|
779
|
+
return humanize_speed(record.speed)
|
|
780
|
+
|
|
772
781
|
|
|
773
782
|
class DeviceModuleInterfaceTable(InterfaceTable):
|
|
774
783
|
name = tables.TemplateColumn(
|
|
@@ -794,6 +803,8 @@ class DeviceModuleInterfaceTable(InterfaceTable):
|
|
|
794
803
|
"module",
|
|
795
804
|
"enabled",
|
|
796
805
|
"type",
|
|
806
|
+
"speed",
|
|
807
|
+
"duplex",
|
|
797
808
|
"parent_interface",
|
|
798
809
|
"bridge",
|
|
799
810
|
"lag",
|
|
@@ -839,6 +850,9 @@ class DeviceModuleInterfaceTable(InterfaceTable):
|
|
|
839
850
|
"data-name": lambda record: record.name,
|
|
840
851
|
}
|
|
841
852
|
|
|
853
|
+
def render_speed(self, record):
|
|
854
|
+
return humanize_speed(record.speed)
|
|
855
|
+
|
|
842
856
|
|
|
843
857
|
class FrontPortTable(ModularDeviceComponentTable, CableTerminationTable):
|
|
844
858
|
rear_port_position = tables.Column(verbose_name="Position")
|
|
@@ -1291,6 +1305,7 @@ class InterfaceRedundancyGroupAssociationTable(BaseTable):
|
|
|
1291
1305
|
"""Table for list view."""
|
|
1292
1306
|
|
|
1293
1307
|
pk = ToggleColumn()
|
|
1308
|
+
interface__enabled = BooleanColumn()
|
|
1294
1309
|
interface_redundancy_group = tables.Column(linkify=True, verbose_name="Group Name")
|
|
1295
1310
|
interface_redundancy_group__virtual_ip = tables.Column(linkify=True, verbose_name="Virtual IP")
|
|
1296
1311
|
interface_redundancy_group__protocol_group_id = tables.Column(verbose_name="Group ID")
|
|
@@ -8,6 +8,7 @@ from nautobot.core.tables import (
|
|
|
8
8
|
TagColumn,
|
|
9
9
|
ToggleColumn,
|
|
10
10
|
)
|
|
11
|
+
from nautobot.core.templatetags.helpers import humanize_speed
|
|
11
12
|
from nautobot.dcim.models import (
|
|
12
13
|
ConsolePortTemplate,
|
|
13
14
|
ConsoleServerPortTemplate,
|
|
@@ -270,6 +271,8 @@ class PowerOutletTemplateTable(ComponentTemplateTable):
|
|
|
270
271
|
|
|
271
272
|
class InterfaceTemplateTable(ComponentTemplateTable):
|
|
272
273
|
mgmt_only = BooleanColumn(verbose_name="Management Only")
|
|
274
|
+
speed = tables.Column(verbose_name="Speed", accessor="speed", orderable=True)
|
|
275
|
+
duplex = tables.Column(verbose_name="Duplex", accessor="duplex", orderable=True)
|
|
273
276
|
actions = ButtonsColumn(
|
|
274
277
|
model=InterfaceTemplate,
|
|
275
278
|
buttons=("edit", "delete"),
|
|
@@ -278,9 +281,13 @@ class InterfaceTemplateTable(ComponentTemplateTable):
|
|
|
278
281
|
|
|
279
282
|
class Meta(BaseTable.Meta):
|
|
280
283
|
model = InterfaceTemplate
|
|
281
|
-
fields = ("pk", "name", "label", "mgmt_only", "type", "description", "actions")
|
|
284
|
+
fields = ("pk", "name", "label", "mgmt_only", "type", "speed", "duplex", "description", "actions")
|
|
285
|
+
default_columns = ("pk", "name", "label", "mgmt_only", "type", "speed", "description", "actions")
|
|
282
286
|
empty_text = "None"
|
|
283
287
|
|
|
288
|
+
def render_speed(self, record):
|
|
289
|
+
return humanize_speed(record.speed)
|
|
290
|
+
|
|
284
291
|
|
|
285
292
|
class FrontPortTemplateTable(ComponentTemplateTable):
|
|
286
293
|
rear_port_position = tables.Column(verbose_name="Position")
|