nautobot 3.0.0a2__py3-none-any.whl → 3.0.0a3__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/choices.py +0 -2
- nautobot/apps/filters.py +7 -9
- nautobot/apps/models.py +2 -2
- nautobot/apps/ui.py +9 -1
- nautobot/circuits/filters.py +3 -2
- nautobot/circuits/navigation.py +3 -2
- nautobot/circuits/templates/circuits/circuit.html +1 -1
- nautobot/circuits/templates/circuits/circuit_create.html +3 -3
- nautobot/circuits/templates/circuits/circuittermination.html +1 -1
- nautobot/circuits/templates/circuits/circuittermination_create.html +9 -24
- nautobot/circuits/templates/circuits/circuittype.html +1 -1
- nautobot/circuits/templates/circuits/inc/circuit_termination_cable_fragment.html +6 -6
- nautobot/circuits/templates/circuits/inc/speed_widget.html +12 -12
- nautobot/circuits/templates/circuits/providernetwork.html +1 -1
- nautobot/circuits/tests/integration/test_circuit.py +10 -13
- nautobot/cloud/filters.py +1 -1
- nautobot/cloud/navigation.py +3 -2
- nautobot/core/api/schema.py +1 -1
- nautobot/core/api/serializers.py +6 -1
- nautobot/core/api/urls.py +1 -0
- nautobot/core/api/views.py +8 -0
- nautobot/core/apps/__init__.py +11 -10
- nautobot/core/celery/__init__.py +3 -5
- nautobot/core/checks.py +46 -0
- nautobot/core/cli/bootstrap_v3_to_v5.py +70 -1
- nautobot/core/cli/migrate_deprecated_templates.py +200 -0
- nautobot/core/constants.py +3 -0
- nautobot/core/context_processors.py +9 -1
- nautobot/core/forms/forms.py +1 -1
- nautobot/core/jobs/__init__.py +6 -3
- nautobot/core/jobs/groups.py +31 -1
- nautobot/core/management/commands/generate_test_data.py +28 -9
- nautobot/core/models/generics.py +9 -1
- nautobot/core/models/tree_queries.py +10 -5
- nautobot/core/settings.py +18 -12
- nautobot/core/settings.yaml +13 -7
- nautobot/core/signals.py +12 -1
- nautobot/core/tables.py +13 -6
- nautobot/core/templates/40x.html +1 -1
- nautobot/core/templates/500.html +2 -2
- nautobot/core/templates/admin/config/config.html +12 -12
- nautobot/core/templates/admin/index.html +3 -3
- nautobot/core/templates/buttons/export.html +1 -1
- nautobot/core/templates/components/button/dropdown.html +5 -3
- nautobot/core/templates/components/panel/body_wrapper_generic_table.html +1 -1
- nautobot/core/templates/components/panel/panel.html +3 -3
- nautobot/core/templates/components/tab/content_wrapper.html +2 -3
- nautobot/core/templates/components/tab/label_wrapper_distinct_view.html +1 -1
- nautobot/core/templates/echarts/echarts.html +1 -1
- nautobot/core/templates/generic/object_bulk_add_component.html +2 -1
- nautobot/core/templates/generic/object_bulk_create.html +4 -3
- nautobot/core/templates/generic/object_bulk_destroy.html +3 -3
- nautobot/core/templates/generic/object_bulk_remove.html +2 -2
- nautobot/core/templates/generic/object_bulk_update.html +5 -4
- nautobot/core/templates/generic/object_create.html +5 -4
- nautobot/core/templates/generic/object_import.html +2 -1
- nautobot/core/templates/generic/object_list.html +12 -4
- nautobot/core/templates/generic/object_notes.html +5 -3
- nautobot/core/templates/generic/object_retrieve.html +2 -3
- nautobot/core/templates/graphene/graphiql.html +7 -7
- nautobot/core/templates/home.html +1 -1
- nautobot/core/templates/import_success.html +2 -1
- nautobot/core/templates/inc/computed_fields/panel_data.html +1 -1
- nautobot/core/templates/inc/created_updated.html +7 -3
- nautobot/core/templates/inc/custom_fields/panel_data.html +1 -1
- nautobot/core/templates/inc/form_static_field.html +6 -0
- nautobot/core/templates/inc/header.html +1 -1
- nautobot/core/templates/inc/image_attachments.html +2 -1
- nautobot/core/templates/inc/nav_menu.html +2 -1
- nautobot/core/templates/inc/search_panel.html +4 -4
- nautobot/core/templates/login.html +4 -2
- nautobot/core/templates/nautobot_config.py.j2 +6 -5
- nautobot/core/templates/redoc_ui.html +7 -0
- nautobot/core/templates/search.html +1 -1
- nautobot/core/templates/swagger_ui.html +17 -3
- nautobot/core/templates/system_jobs/import_objects.html +1 -2
- nautobot/core/templates/utilities/confirmation_form.html +2 -2
- nautobot/core/templates/utilities/obj_table.html +10 -2
- nautobot/core/templates/utilities/render_field.html +7 -7
- nautobot/core/templates/utilities/render_jinja2.html +2 -2
- nautobot/core/templates/utilities/templatetags/filter_form_drawer.html +4 -4
- nautobot/core/templates/utilities/theme_preview.html +16 -3
- nautobot/core/templates/widgets/selectwithdisabled_option.html +3 -1
- nautobot/core/templatetags/helpers.py +52 -6
- nautobot/core/testing/api.py +68 -9
- nautobot/core/testing/filters.py +0 -23
- nautobot/core/testing/integration.py +23 -10
- nautobot/core/testing/mixins.py +2 -0
- nautobot/core/testing/views.py +4 -0
- nautobot/core/tests/integration/test_app_home.py +34 -30
- nautobot/core/tests/integration/test_app_navbar.py +3 -0
- nautobot/core/tests/nautobot_config_without_example_apps.py +4 -0
- nautobot/core/tests/runner.py +9 -1
- nautobot/core/tests/test_api.py +5 -3
- nautobot/core/tests/test_breadcrumbs.py +6 -7
- nautobot/core/tests/test_checks.py +28 -0
- nautobot/core/tests/test_cli.py +40 -0
- nautobot/core/tests/test_config.py +2 -1
- nautobot/core/tests/test_forms.py +55 -13
- nautobot/core/tests/test_jobs.py +75 -1
- nautobot/core/tests/test_nautobot_server.py +2 -0
- nautobot/core/tests/test_navigations.py +76 -1
- nautobot/core/tests/test_patch_social_django.py +42 -0
- nautobot/core/tests/test_tables.py +3 -1
- nautobot/core/tests/test_templatetags_helpers.py +53 -13
- nautobot/core/tests/test_templatetags_ui_framework.py +4 -4
- nautobot/core/tests/test_tree_queries.py +14 -1
- nautobot/core/tests/test_ui.py +1 -1
- nautobot/core/tests/test_utils.py +31 -4
- nautobot/core/tests/test_views.py +159 -31
- nautobot/core/ui/breadcrumbs.py +2 -12
- nautobot/core/ui/choices.py +142 -10
- nautobot/core/ui/constants.py +76 -12
- nautobot/core/ui/object_detail.py +92 -12
- nautobot/core/urls.py +12 -1
- nautobot/core/utils/cache.py +2 -1
- nautobot/core/utils/filtering.py +17 -17
- nautobot/core/utils/lookup.py +3 -8
- nautobot/core/utils/module_loading.py +21 -0
- nautobot/core/utils/patch_social_django.py +128 -0
- nautobot/core/views/__init__.py +38 -1
- nautobot/core/views/generic.py +3 -3
- nautobot/core/views/mixins.py +15 -3
- nautobot/core/views/renderers.py +2 -0
- nautobot/core/views/viewsets.py +2 -1
- nautobot/data_validation/apps.py +1 -5
- nautobot/data_validation/custom_validators.py +4 -4
- nautobot/data_validation/filters.py +1 -1
- nautobot/data_validation/forms.py +40 -0
- nautobot/data_validation/migrations/0001_initial.py +0 -7
- nautobot/data_validation/migrations/0002_data_migration_from_app.py +0 -12
- nautobot/data_validation/models.py +16 -7
- nautobot/data_validation/navigation.py +8 -1
- nautobot/data_validation/tables.py +12 -5
- nautobot/data_validation/templates/data_validation/datacompliance_tab.html +1 -0
- nautobot/data_validation/templates/data_validation/device_constraints.html +61 -0
- nautobot/data_validation/tests/__init__.py +2 -2
- nautobot/data_validation/tests/migrations/test_migrations.py +83 -3
- nautobot/data_validation/tests/test_data_compliance_rules.py +12 -7
- nautobot/data_validation/tests/test_filters.py +8 -6
- nautobot/data_validation/tests/test_models.py +15 -0
- nautobot/data_validation/tests/test_views.py +190 -32
- nautobot/data_validation/urls.py +2 -5
- nautobot/data_validation/views.py +73 -40
- nautobot/dcim/api/serializers.py +0 -13
- nautobot/dcim/apps.py +4 -0
- nautobot/dcim/choices.py +16 -0
- nautobot/dcim/custom_validators.py +84 -0
- nautobot/dcim/filter_mixins.py +353 -4
- nautobot/dcim/{filters/__init__.py → filters.py} +2 -35
- nautobot/dcim/forms.py +1 -1
- nautobot/dcim/migrations/0078_remove_device_location_tenant_name_uniqueness.py +16 -0
- nautobot/dcim/migrations/0079_device_name_data_migration.py +59 -0
- nautobot/dcim/models/device_components.py +81 -68
- nautobot/dcim/models/devices.py +13 -16
- nautobot/dcim/navigation.py +7 -6
- nautobot/dcim/tables/devices.py +3 -0
- nautobot/dcim/tables/template_code.py +14 -14
- nautobot/dcim/templates/dcim/cable.html +2 -61
- nautobot/dcim/templates/dcim/cable_connect.html +28 -112
- nautobot/dcim/templates/dcim/cable_edit.html +2 -5
- nautobot/dcim/templates/dcim/cable_retrieve.html +61 -0
- nautobot/dcim/templates/dcim/cable_trace.html +1 -3
- nautobot/dcim/templates/dcim/cable_update.html +5 -0
- nautobot/dcim/templates/dcim/consoleport.html +6 -5
- nautobot/dcim/templates/dcim/consoleserverport.html +6 -5
- nautobot/dcim/templates/dcim/device/config.html +2 -2
- nautobot/dcim/templates/dcim/device/consoleports.html +1 -1
- nautobot/dcim/templates/dcim/device/consoleserverports.html +1 -1
- nautobot/dcim/templates/dcim/device/devicebays.html +1 -1
- nautobot/dcim/templates/dcim/device/frontports.html +1 -1
- nautobot/dcim/templates/dcim/device/interfaces.html +1 -1
- nautobot/dcim/templates/dcim/device/inventory.html +1 -1
- nautobot/dcim/templates/dcim/device/lldp_neighbors.html +1 -1
- nautobot/dcim/templates/dcim/device/modulebays.html +1 -1
- nautobot/dcim/templates/dcim/device/poweroutlets.html +1 -1
- nautobot/dcim/templates/dcim/device/powerports.html +1 -1
- nautobot/dcim/templates/dcim/device/rearports.html +1 -1
- nautobot/dcim/templates/dcim/device/status.html +8 -8
- nautobot/dcim/templates/dcim/device/wireless.html +1 -1
- nautobot/dcim/templates/dcim/device.html +1 -1
- nautobot/dcim/templates/dcim/device_component_add.html +2 -2
- nautobot/dcim/templates/dcim/device_create.html +5 -3
- nautobot/dcim/templates/dcim/device_interface_delete.html +1 -1
- nautobot/dcim/templates/dcim/device_list.html +73 -10
- nautobot/dcim/templates/dcim/devicebay_populate.html +2 -2
- nautobot/dcim/templates/dcim/devicetype.html +1 -1
- nautobot/dcim/templates/dcim/devicetype_component_add.html +2 -2
- nautobot/dcim/templates/dcim/footer_convert_to_contact_or_team_record.html +14 -0
- nautobot/dcim/templates/dcim/frontport.html +9 -8
- nautobot/dcim/templates/dcim/inc/edit_form_softwareversion_js.html +2 -2
- nautobot/dcim/templates/dcim/interface.html +26 -6
- nautobot/dcim/templates/dcim/interface_bulk_delete.html +1 -1
- nautobot/dcim/templates/dcim/inventoryitem_add.html +3 -1
- nautobot/dcim/templates/dcim/inventoryitem_bulk_delete.html +1 -1
- nautobot/dcim/templates/dcim/inventoryitem_edit.html +3 -1
- nautobot/dcim/templates/dcim/location_retrieve.html +1 -242
- nautobot/dcim/templates/dcim/module/base.html +49 -9
- nautobot/dcim/templates/dcim/module_list.html +57 -8
- nautobot/dcim/templates/dcim/modulefamily_retrieve.html +1 -1
- nautobot/dcim/templates/dcim/moduletype_retrieve.html +49 -9
- nautobot/dcim/templates/dcim/platform_create.html +1 -1
- nautobot/dcim/templates/dcim/powerfeed.html +1 -1
- nautobot/dcim/templates/dcim/powerpanel.html +1 -1
- nautobot/dcim/templates/dcim/powerport.html +5 -4
- nautobot/dcim/templates/dcim/rack_elevation_list.html +16 -4
- nautobot/dcim/templates/dcim/rack_retrieve.html +33 -15
- nautobot/dcim/templates/dcim/rearport.html +7 -6
- nautobot/dcim/templates/dcim/virtualchassis.html +1 -1
- nautobot/dcim/templates/dcim/virtualchassis_add_member.html +16 -14
- nautobot/dcim/templates/dcim/virtualchassis_update.html +14 -6
- nautobot/dcim/tests/integration/test_controller.py +1 -0
- nautobot/dcim/tests/test_api.py +8 -0
- nautobot/dcim/tests/test_custom_validators.py +229 -0
- nautobot/dcim/tests/test_filters.py +12 -6
- nautobot/dcim/tests/test_models.py +63 -4
- nautobot/dcim/tests/test_views.py +63 -22
- nautobot/dcim/urls.py +64 -21
- nautobot/dcim/utils.py +3 -3
- nautobot/dcim/views.py +547 -273
- nautobot/extras/api/views.py +9 -1
- nautobot/extras/choices.py +2 -13
- nautobot/extras/{filters/mixins.py → filter_mixins.py} +1 -1
- nautobot/extras/{filters/customfields.py → filter_mixins_customfields.py} +42 -6
- nautobot/extras/{filters/__init__.py → filters.py} +14 -46
- nautobot/extras/forms/forms.py +5 -13
- nautobot/extras/forms/mixins.py +0 -41
- nautobot/extras/management/__init__.py +9 -0
- nautobot/extras/migrations/0127_approval_workflow_models.py +6 -6
- nautobot/extras/migrations/0129_jobresult_debug_log_count_jobresult_error_log_count_and_more.py +37 -0
- nautobot/extras/migrations/0130_jobresult_generate_log_entry_counts.py +42 -0
- nautobot/extras/models/__init__.py +1 -2
- nautobot/extras/models/approvals.py +22 -13
- nautobot/extras/models/contacts.py +2 -0
- nautobot/extras/models/groups.py +44 -5
- nautobot/extras/models/jobs.py +59 -1
- nautobot/extras/models/mixins.py +28 -0
- nautobot/extras/models/models.py +13 -0
- nautobot/extras/models/secrets.py +1 -0
- nautobot/extras/models/statuses.py +0 -15
- nautobot/extras/navigation.py +13 -9
- nautobot/extras/plugins/__init__.py +33 -55
- nautobot/extras/plugins/tables.py +3 -3
- nautobot/extras/plugins/urls.py +2 -21
- nautobot/extras/plugins/utils.py +1 -33
- nautobot/extras/plugins/views.py +0 -4
- nautobot/extras/signals.py +20 -19
- nautobot/extras/tables.py +52 -68
- nautobot/extras/templates/extras/approval_dashboard.html +7 -5
- nautobot/extras/templates/extras/approvalworkflowdefinition_update.html +4 -2
- nautobot/extras/templates/extras/approvalworkflowstage_retrieve.html +20 -12
- nautobot/extras/templates/extras/computedfield.html +1 -1
- nautobot/extras/templates/extras/configcontext.html +1 -1
- nautobot/extras/templates/extras/configcontextschema_validation.html +2 -2
- nautobot/extras/templates/extras/customfield.html +1 -1
- nautobot/extras/templates/extras/dynamicgroup_retrieve.html +11 -5
- nautobot/extras/templates/extras/dynamicgroup_update.html +1 -1
- nautobot/extras/templates/extras/gitrepository_result.html +0 -2
- nautobot/extras/templates/extras/graphqlquery_retrieve.html +1 -96
- nautobot/extras/templates/extras/inc/approval_buttons_column.html +20 -6
- nautobot/extras/templates/extras/inc/bulk_edit_overridable_field.html +8 -7
- nautobot/extras/templates/extras/inc/configcontext_format.html +10 -3
- nautobot/extras/templates/extras/inc/graphqlquery_execute.html +71 -0
- nautobot/extras/templates/extras/inc/job_tiles.html +15 -3
- nautobot/extras/templates/extras/inc/json_format.html +10 -3
- nautobot/extras/templates/extras/inc/overridable_field.html +13 -12
- nautobot/extras/templates/extras/job.html +29 -12
- nautobot/extras/templates/extras/job_bulk_edit.html +18 -0
- nautobot/extras/templates/extras/job_edit.html +52 -46
- nautobot/extras/templates/extras/job_list.html +29 -25
- nautobot/extras/templates/extras/marketplace.html +5 -9
- nautobot/extras/templates/extras/object_configcontext.html +1 -1
- nautobot/extras/templates/extras/object_dynamicgroups.html +2 -2
- nautobot/extras/templates/extras/objectchange_retrieve.html +19 -37
- nautobot/extras/templates/extras/plugin_detail.html +26 -21
- nautobot/extras/templates/extras/plugins_list.html +16 -26
- nautobot/extras/templates/extras/role_retrieve.html +64 -0
- nautobot/extras/templates/extras/scheduledjob.html +4 -2
- nautobot/extras/templates/extras/secretsgroup.html +1 -1
- nautobot/extras/templates/extras/tag.html +1 -1
- nautobot/extras/templatetags/custom_links.py +12 -12
- nautobot/extras/templatetags/job_buttons.py +14 -12
- nautobot/extras/test_jobs/invalid_import.py +9 -0
- nautobot/extras/test_jobs/log_counts_by_level.py +23 -0
- nautobot/extras/test_jobs/missing_import.py +11 -0
- nautobot/extras/tests/integration/test_configcontextschema.py +27 -26
- nautobot/extras/tests/integration/test_customfields.py +8 -7
- nautobot/extras/tests/integration/test_dynamicgroups.py +5 -1
- nautobot/extras/tests/integration/test_plugin_banner.py +3 -0
- nautobot/extras/tests/integration/test_plugins.py +18 -6
- nautobot/extras/tests/test_api.py +27 -18
- nautobot/extras/tests/test_approvals.py +38 -38
- nautobot/extras/tests/test_changelog.py +35 -3
- nautobot/extras/tests/test_customfields.py +22 -13
- nautobot/extras/tests/test_customfields_filters.py +479 -0
- nautobot/extras/tests/test_dynamicgroups.py +39 -1
- nautobot/extras/tests/test_filters.py +21 -19
- nautobot/extras/tests/test_forms.py +18 -21
- nautobot/extras/tests/test_jobs.py +25 -4
- nautobot/extras/tests/test_migrations.py +1 -0
- nautobot/extras/tests/test_models.py +13 -31
- nautobot/extras/tests/test_plugins.py +36 -10
- nautobot/extras/tests/test_views.py +31 -30
- nautobot/extras/views.py +81 -19
- nautobot/ipam/factory.py +7 -0
- nautobot/ipam/filter_mixins.py +38 -0
- nautobot/ipam/filters.py +27 -38
- nautobot/ipam/formfields.py +1 -1
- nautobot/ipam/forms.py +6 -3
- nautobot/ipam/migrations/0030_ipam__namespaces.py +13 -0
- nautobot/ipam/migrations/0031_ipam___data_migrations.py +4 -1
- nautobot/ipam/migrations/0054_namespace_tenant.py +25 -0
- nautobot/ipam/models.py +29 -2
- nautobot/ipam/navigation.py +3 -2
- nautobot/ipam/signals.py +71 -0
- nautobot/ipam/tables.py +13 -6
- nautobot/ipam/templates/ipam/inc/toggle_available.html +10 -10
- nautobot/ipam/templates/ipam/inc/vlangroup_header.html +1 -0
- nautobot/ipam/templates/ipam/ipaddress.html +14 -0
- nautobot/ipam/templates/ipam/ipaddress_merge.html +3 -3
- nautobot/ipam/templates/ipam/ipaddresstointerface_retrieve.html +1 -0
- nautobot/ipam/templates/ipam/namespace_update.html +15 -0
- nautobot/ipam/templates/ipam/prefix_delete.html +1 -1
- nautobot/ipam/templates/ipam/prefix_list.html +14 -13
- nautobot/ipam/templates/ipam/service.html +1 -1
- nautobot/ipam/templates/ipam/vlan.html +1 -1
- nautobot/ipam/templates/ipam/vlan_interfaces.html +1 -1
- nautobot/ipam/templates/ipam/vlan_vminterfaces.html +1 -1
- nautobot/ipam/tests/migration/test_migrations.py +89 -0
- nautobot/ipam/tests/test_api.py +13 -6
- nautobot/ipam/tests/test_filters.py +10 -0
- nautobot/ipam/tests/test_forms.py +1 -1
- nautobot/ipam/tests/test_models.py +43 -1
- nautobot/ipam/tests/test_tables.py +1 -2
- nautobot/ipam/tests/test_utils.py +1 -1
- nautobot/ipam/tests/test_views.py +13 -14
- nautobot/ipam/ui.py +0 -17
- nautobot/ipam/utils/migrations.py +16 -2
- nautobot/ipam/utils/testing.py +9 -3
- nautobot/ipam/views.py +46 -6
- nautobot/project-static/dist/css/nautobot.css +1 -1
- nautobot/project-static/dist/css/nautobot.css.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/cabletrace.js +1 -1
- nautobot/project-static/js/interface_filtering.js +20 -16
- nautobot/project-static/nautobot-icons/battery-3.svg +3 -0
- nautobot/project-static/nautobot-icons/cloud.svg +1 -1
- nautobot/project-static/nautobot-icons/control-panel.svg +1 -1
- nautobot/project-static/nautobot-icons/device-lifecycle.svg +1 -1
- nautobot/project-static/nautobot-icons/elements.svg +1 -1
- nautobot/project-static/nautobot-icons/extensibility.svg +3 -0
- nautobot/project-static/nautobot-icons/hammer.svg +1 -1
- nautobot/project-static/nautobot-icons/organization.svg +3 -0
- nautobot/project-static/nautobot-icons/secrets.svg +1 -1
- nautobot/project-static/nautobot-icons/security.svg +3 -0
- nautobot/project-static/nautobot-icons/server.svg +1 -1
- nautobot/project-static/nautobot-icons/star-filled.svg +1 -1
- nautobot/project-static/nautobot-icons/star.svg +1 -1
- nautobot/tenancy/api/serializers.py +1 -0
- nautobot/tenancy/api/views.py +2 -1
- nautobot/tenancy/{filters/__init__.py → filters.py} +2 -10
- nautobot/tenancy/navigation.py +3 -1
- nautobot/tenancy/tests/test_filters.py +0 -2
- nautobot/tenancy/views.py +2 -1
- nautobot/ui/src/js/collapse.js +3 -3
- nautobot/ui/src/js/nautobot.js +16 -0
- nautobot/ui/src/scss/colors.scss +1 -1
- nautobot/ui/src/scss/nautobot.scss +61 -28
- nautobot/users/templates/users/profile.html +45 -12
- nautobot/users/templates/users/sessionkey_delete.html +1 -1
- nautobot/users/tests/test_api.py +4 -0
- nautobot/users/views.py +4 -2
- nautobot/virtualization/models.py +1 -68
- nautobot/virtualization/navigation.py +3 -2
- nautobot/virtualization/templates/virtualization/virtual_machine_vminterface_delete.html +1 -1
- nautobot/virtualization/templates/virtualization/virtualmachine.html +1 -1
- nautobot/virtualization/templates/virtualization/virtualmachine_list.html +2 -2
- nautobot/virtualization/templates/virtualization/virtualmachine_update.html +3 -1
- nautobot/virtualization/tests/test_api.py +3 -0
- nautobot/virtualization/tests/test_models.py +44 -4
- nautobot/vpn/__init__.py +0 -0
- nautobot/vpn/api/serializers.py +113 -0
- nautobot/vpn/api/urls.py +19 -0
- nautobot/vpn/api/views.py +70 -0
- nautobot/vpn/apps.py +8 -0
- nautobot/vpn/choices.py +171 -0
- nautobot/vpn/factory.py +209 -0
- nautobot/vpn/filters.py +233 -0
- nautobot/vpn/forms.py +486 -0
- nautobot/vpn/homepage.py +19 -0
- nautobot/vpn/migrations/0001_initial.py +541 -0
- nautobot/vpn/migrations/0002_populate_defaults.py +199 -0
- nautobot/vpn/migrations/__init__.py +0 -0
- nautobot/vpn/models.py +527 -0
- nautobot/vpn/navigation.py +98 -0
- nautobot/vpn/tables.py +380 -0
- nautobot/vpn/templates/vpn/vpnprofile.html +2 -0
- nautobot/vpn/templates/vpn/vpnprofile_create.html +150 -0
- nautobot/vpn/tests/__init__.py +0 -0
- nautobot/vpn/tests/test_api.py +341 -0
- nautobot/vpn/tests/test_filters.py +139 -0
- nautobot/vpn/tests/test_forms.py +294 -0
- nautobot/vpn/tests/test_models.py +97 -0
- nautobot/vpn/tests/test_views.py +281 -0
- nautobot/vpn/urls.py +16 -0
- nautobot/vpn/views.py +437 -0
- nautobot/wireless/navigation.py +3 -2
- nautobot/wireless/tests/integration/test_radio_profile.py +1 -5
- nautobot/wireless/tests/test_api.py +1 -1
- {nautobot-3.0.0a2.dist-info → nautobot-3.0.0a3.dist-info}/METADATA +14 -14
- {nautobot-3.0.0a2.dist-info → nautobot-3.0.0a3.dist-info}/RECORD +417 -366
- {nautobot-3.0.0a2.dist-info → nautobot-3.0.0a3.dist-info}/entry_points.txt +1 -0
- nautobot/data_validation/template_content.py +0 -42
- nautobot/dcim/filters/mixins.py +0 -354
- nautobot/ipam/templates/ipam/inc/prefix_header_extra_content_table.html +0 -4
- /nautobot/tenancy/{filters/mixins.py → filter_mixins.py} +0 -0
- {nautobot-3.0.0a2.dist-info → nautobot-3.0.0a3.dist-info}/LICENSE.txt +0 -0
- {nautobot-3.0.0a2.dist-info → nautobot-3.0.0a3.dist-info}/NOTICE +0 -0
- {nautobot-3.0.0a2.dist-info → nautobot-3.0.0a3.dist-info}/WHEEL +0 -0
nautobot/apps/choices.py
CHANGED
|
@@ -43,7 +43,6 @@ from nautobot.extras.choices import (
|
|
|
43
43
|
ButtonClassChoices,
|
|
44
44
|
CustomFieldFilterLogicChoices,
|
|
45
45
|
CustomFieldTypeChoices,
|
|
46
|
-
CustomLinkButtonClassChoices,
|
|
47
46
|
DynamicGroupOperatorChoices,
|
|
48
47
|
JobExecutionType,
|
|
49
48
|
JobResultStatusChoices,
|
|
@@ -79,7 +78,6 @@ __all__ = (
|
|
|
79
78
|
"ConsolePortTypeChoices",
|
|
80
79
|
"CustomFieldFilterLogicChoices",
|
|
81
80
|
"CustomFieldTypeChoices",
|
|
82
|
-
"CustomLinkButtonClassChoices",
|
|
83
81
|
"DeviceFaceChoices",
|
|
84
82
|
"DeviceRedundancyGroupFailoverStrategyChoices",
|
|
85
83
|
"DynamicGroupOperatorChoices",
|
nautobot/apps/filters.py
CHANGED
|
@@ -28,24 +28,22 @@ from nautobot.core.filters import (
|
|
|
28
28
|
TagFilter,
|
|
29
29
|
TreeNodeMultipleChoiceFilter,
|
|
30
30
|
)
|
|
31
|
-
from nautobot.extras.
|
|
31
|
+
from nautobot.extras.filter_mixins import (
|
|
32
|
+
ConfigContextRoleFilter,
|
|
32
33
|
CreatedUpdatedModelFilterSetMixin,
|
|
33
34
|
CustomFieldModelFilterSetMixin,
|
|
34
|
-
NautobotFilterSet,
|
|
35
|
-
RelationshipModelFilterSetMixin,
|
|
36
|
-
StatusModelFilterSetMixin,
|
|
37
|
-
)
|
|
38
|
-
from nautobot.extras.filters.mixins import (
|
|
39
|
-
ConfigContextRoleFilter,
|
|
40
35
|
LocalContextModelFilterSetMixin,
|
|
41
36
|
RelationshipFilter,
|
|
37
|
+
RelationshipModelFilterSetMixin,
|
|
42
38
|
RoleFilter,
|
|
43
39
|
RoleModelFilterSetMixin,
|
|
44
40
|
StatusFilter,
|
|
41
|
+
StatusModelFilterSetMixin,
|
|
45
42
|
)
|
|
43
|
+
from nautobot.extras.filters import NautobotFilterSet
|
|
46
44
|
from nautobot.extras.plugins import FilterExtension
|
|
47
|
-
from nautobot.ipam.
|
|
48
|
-
from nautobot.tenancy.
|
|
45
|
+
from nautobot.ipam.filter_mixins import PrefixFilter
|
|
46
|
+
from nautobot.tenancy.filter_mixins import TenancyModelFilterSetMixin
|
|
49
47
|
|
|
50
48
|
__all__ = (
|
|
51
49
|
"BaseFilterSet",
|
nautobot/apps/models.py
CHANGED
|
@@ -43,11 +43,11 @@ from nautobot.extras.models import (
|
|
|
43
43
|
CustomFieldModel,
|
|
44
44
|
RelationshipModel,
|
|
45
45
|
StatusField,
|
|
46
|
-
StatusModel,
|
|
47
46
|
)
|
|
48
47
|
from nautobot.extras.models.mixins import (
|
|
49
48
|
ApprovableModelMixin,
|
|
50
49
|
ContactMixin,
|
|
50
|
+
DataComplianceModelMixin,
|
|
51
51
|
DynamicGroupMixin,
|
|
52
52
|
DynamicGroupsModelMixin,
|
|
53
53
|
NotesMixin,
|
|
@@ -76,6 +76,7 @@ __all__ = (
|
|
|
76
76
|
"ContentTypeRelatedQuerySet",
|
|
77
77
|
"CustomFieldModel",
|
|
78
78
|
"CustomValidator",
|
|
79
|
+
"DataComplianceModelMixin",
|
|
79
80
|
"DataComplianceRule",
|
|
80
81
|
"DynamicGroupMixin",
|
|
81
82
|
"DynamicGroupsModelMixin",
|
|
@@ -97,7 +98,6 @@ __all__ = (
|
|
|
97
98
|
"RestrictedQuerySet",
|
|
98
99
|
"SavedViewMixin",
|
|
99
100
|
"StatusField",
|
|
100
|
-
"StatusModel",
|
|
101
101
|
"TagsField",
|
|
102
102
|
"TagsManager",
|
|
103
103
|
"TreeManager",
|
nautobot/apps/ui.py
CHANGED
|
@@ -12,7 +12,13 @@ from nautobot.core.ui.breadcrumbs import (
|
|
|
12
12
|
ModelBreadcrumbItem,
|
|
13
13
|
ViewNameBreadcrumbItem,
|
|
14
14
|
)
|
|
15
|
-
from nautobot.core.ui.choices import
|
|
15
|
+
from nautobot.core.ui.choices import (
|
|
16
|
+
EChartsTypeChoices,
|
|
17
|
+
LayoutChoices,
|
|
18
|
+
NavigationIconChoices,
|
|
19
|
+
NavigationWeightChoices,
|
|
20
|
+
SectionChoices,
|
|
21
|
+
)
|
|
16
22
|
from nautobot.core.ui.echarts import (
|
|
17
23
|
EChartsBase,
|
|
18
24
|
queryset_to_nested_dict_keys_as_series,
|
|
@@ -90,6 +96,8 @@ __all__ = (
|
|
|
90
96
|
"NavMenuImportButton",
|
|
91
97
|
"NavMenuItem",
|
|
92
98
|
"NavMenuTab",
|
|
99
|
+
"NavigationIconChoices",
|
|
100
|
+
"NavigationWeightChoices",
|
|
93
101
|
"ObjectDetailContent",
|
|
94
102
|
"ObjectFieldsPanel",
|
|
95
103
|
"ObjectTextPanel",
|
nautobot/circuits/filters.py
CHANGED
|
@@ -13,8 +13,9 @@ from nautobot.dcim.filters import (
|
|
|
13
13
|
PathEndpointModelFilterSetMixin,
|
|
14
14
|
)
|
|
15
15
|
from nautobot.dcim.models import Location
|
|
16
|
-
from nautobot.extras.
|
|
17
|
-
from nautobot.
|
|
16
|
+
from nautobot.extras.filter_mixins import StatusModelFilterSetMixin
|
|
17
|
+
from nautobot.extras.filters import NautobotFilterSet
|
|
18
|
+
from nautobot.tenancy.filter_mixins import TenancyModelFilterSetMixin
|
|
18
19
|
|
|
19
20
|
from .models import Circuit, CircuitTermination, CircuitType, Provider, ProviderNetwork
|
|
20
21
|
|
nautobot/circuits/navigation.py
CHANGED
|
@@ -4,12 +4,13 @@ from nautobot.core.apps import (
|
|
|
4
4
|
NavMenuItem,
|
|
5
5
|
NavMenuTab,
|
|
6
6
|
)
|
|
7
|
+
from nautobot.core.ui.choices import NavigationIconChoices, NavigationWeightChoices
|
|
7
8
|
|
|
8
9
|
menu_items = (
|
|
9
10
|
NavMenuTab(
|
|
10
11
|
name="Circuits",
|
|
11
|
-
icon=
|
|
12
|
-
weight=
|
|
12
|
+
icon=NavigationIconChoices.CIRCUITS,
|
|
13
|
+
weight=NavigationWeightChoices.CIRCUITS,
|
|
13
14
|
groups=(
|
|
14
15
|
NavMenuGroup(
|
|
15
16
|
name="Circuits",
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
{% extends '
|
|
1
|
+
{% extends 'generic/object_retrieve.html' %}
|
|
2
2
|
{% comment %}2.0 TODO: remove this template, which only exists for backward compatibility with 1.3 and earlier{% endcomment %}
|
|
@@ -10,9 +10,9 @@
|
|
|
10
10
|
{% render_field form.circuit_type %}
|
|
11
11
|
{% render_field form.status %}
|
|
12
12
|
{% render_field form.install_date %}
|
|
13
|
-
<div class="mb-10 d-flex justify-content-center">
|
|
14
|
-
<label class="col-
|
|
15
|
-
<div class="col-
|
|
13
|
+
<div class="mb-10 d-md-flex justify-content-center">
|
|
14
|
+
<label class="col-md-3 col-form-label" for="id_commit_rate">{{ form.commit_rate.label }}</label>
|
|
15
|
+
<div class="col-md-9">
|
|
16
16
|
<div class="input-group">
|
|
17
17
|
{{ form.commit_rate }}
|
|
18
18
|
{% include 'circuits/inc/speed_widget.html' with target_field='commit_rate' %}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
{% extends '
|
|
1
|
+
{% extends 'generic/object_retrieve.html' %}
|
|
2
2
|
{% comment %}2.0 TODO: remove this template, which only exists for backward compatibility with 1.3 and earlier{% endcomment %}
|
|
@@ -7,24 +7,9 @@
|
|
|
7
7
|
<div class="card">
|
|
8
8
|
<div class="card-header"><strong>Termination</strong></div>
|
|
9
9
|
<div class="card-body">
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
<p class="form-control-plaintext">{{ obj.circuit.provider }}</p>
|
|
14
|
-
</div>
|
|
15
|
-
</div>
|
|
16
|
-
<div class="mb-10 d-flex justify-content-center">
|
|
17
|
-
<label class="col-lg-3 col-form-label">Circuit</label>
|
|
18
|
-
<div class="col-lg-9">
|
|
19
|
-
<p class="form-control-plaintext">{{ obj.circuit.cid }}</p>
|
|
20
|
-
</div>
|
|
21
|
-
</div>
|
|
22
|
-
<div class="mb-10 d-flex justify-content-center">
|
|
23
|
-
<label class="col-lg-3 col-form-label">Termination</label>
|
|
24
|
-
<div class="col-lg-9">
|
|
25
|
-
<p class="form-control-plaintext">{{ form.term_side.value }}</p>
|
|
26
|
-
</div>
|
|
27
|
-
</div>
|
|
10
|
+
{% include "inc/form_static_field.html" with label="Provider" value=obj.circuit.provider %}
|
|
11
|
+
{% include "inc/form_static_field.html" with label="Circuit" value=obj.circuit.cid %}
|
|
12
|
+
{% include "inc/form_static_field.html" with label="Termination" value=form.term_side.value %}
|
|
28
13
|
{% with location_tab_active=form.initial.location %}
|
|
29
14
|
{% with providernetwork_tab_active=form.initial.provider_network %}
|
|
30
15
|
{% with cloudnetwork_tab_active=form.initial.cloud_network %}
|
|
@@ -58,9 +43,9 @@
|
|
|
58
43
|
<div class="card">
|
|
59
44
|
<div class="card-header"><strong>Termination Details</strong></div>
|
|
60
45
|
<div class="card-body">
|
|
61
|
-
<div class="mb-10 d-flex justify-content-center">
|
|
62
|
-
<label class="col-
|
|
63
|
-
<div class="col-
|
|
46
|
+
<div class="mb-10 d-md-flex justify-content-center">
|
|
47
|
+
<label class="col-md-3 col-form-label" for="id_port_speed">{{ form.port_speed.label }}</label>
|
|
48
|
+
<div class="col-md-9">
|
|
64
49
|
<div class="input-group">
|
|
65
50
|
{{ form.port_speed }}
|
|
66
51
|
{% include 'circuits/inc/speed_widget.html' with target_field='port_speed' %}
|
|
@@ -68,9 +53,9 @@
|
|
|
68
53
|
<span class="form-text">{{ form.port_speed.help_text }}</span>
|
|
69
54
|
</div>
|
|
70
55
|
</div>
|
|
71
|
-
<div class="mb-10 d-flex justify-content-center">
|
|
72
|
-
<label class="col-
|
|
73
|
-
<div class="col-
|
|
56
|
+
<div class="mb-10 d-md-flex justify-content-center">
|
|
57
|
+
<label class="col-md-3 col-form-label" for="id_upstream_speed">{{ form.upstream_speed.label }}</label>
|
|
58
|
+
<div class="col-md-9">
|
|
74
59
|
<div class="input-group">
|
|
75
60
|
{{ form.upstream_speed }}
|
|
76
61
|
{% include 'circuits/inc/speed_widget.html' with target_field='upstream_speed' %}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
{% extends '
|
|
1
|
+
{% extends 'generic/object_retrieve.html' %}
|
|
2
2
|
{% comment %}3.0 TODO: remove this template, which only exists for backward compatibility with 2.4 and earlier{% endcomment %}
|
|
@@ -24,14 +24,14 @@
|
|
|
24
24
|
{% if perms.dcim.add_cable %}
|
|
25
25
|
<div class="float-end">
|
|
26
26
|
<span class="dropdown">
|
|
27
|
-
<button type="button" class="btn btn-success btn-sm dropdown-toggle" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
|
27
|
+
<button type="button" class="btn btn-success btn-sm dropdown-toggle" data-bs-toggle="dropdown" data-bs-popper-config='{"strategy": "fixed"}' aria-haspopup="true" aria-expanded="false">
|
|
28
28
|
<span class="mdi mdi-ethernet-cable" aria-hidden="true"></span> Connect
|
|
29
29
|
</button>
|
|
30
|
-
<ul class="dropdown-menu dropdown-menu-
|
|
31
|
-
<li><a href="{% url 'circuits:circuittermination_connect' termination_a_id=termination.pk termination_b_type='interface' %}?termination_b_location={{ termination.location.pk }}&return_url={{ object.get_absolute_url }}">Interface</a></li>
|
|
32
|
-
<li><a href="{% url 'circuits:circuittermination_connect' termination_a_id=termination.pk termination_b_type='front-port' %}?termination_b_location={{ termination.location.pk }}&return_url={{ object.get_absolute_url }}">Front Port</a></li>
|
|
33
|
-
<li><a href="{% url 'circuits:circuittermination_connect' termination_a_id=termination.pk termination_b_type='rear-port' %}?termination_b_location={{ termination.location.pk }}&return_url={{ object.get_absolute_url }}">Rear Port</a></li>
|
|
34
|
-
<li><a href="{% url 'circuits:circuittermination_connect' termination_a_id=termination.pk termination_b_type='circuit-termination' %}?termination_b_location={{ termination.location.pk }}&return_url={{ object.get_absolute_url }}">Circuit Termination</a></li>
|
|
30
|
+
<ul class="dropdown-menu dropdown-menu-end">
|
|
31
|
+
<li><a class="dropdown-item" href="{% url 'circuits:circuittermination_connect' termination_a_id=termination.pk termination_b_type='interface' %}?termination_b_location={{ termination.location.pk }}&return_url={{ object.get_absolute_url }}">Interface</a></li>
|
|
32
|
+
<li><a class="dropdown-item" href="{% url 'circuits:circuittermination_connect' termination_a_id=termination.pk termination_b_type='front-port' %}?termination_b_location={{ termination.location.pk }}&return_url={{ object.get_absolute_url }}">Front Port</a></li>
|
|
33
|
+
<li><a class="dropdown-item" href="{% url 'circuits:circuittermination_connect' termination_a_id=termination.pk termination_b_type='rear-port' %}?termination_b_location={{ termination.location.pk }}&return_url={{ object.get_absolute_url }}">Rear Port</a></li>
|
|
34
|
+
<li><a class="dropdown-item" href="{% url 'circuits:circuittermination_connect' termination_a_id=termination.pk termination_b_type='circuit-termination' %}?termination_b_location={{ termination.location.pk }}&return_url={{ object.get_absolute_url }}">Circuit Termination</a></li>
|
|
35
35
|
</ul>
|
|
36
36
|
</span>
|
|
37
37
|
</div>
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
<span class="input-group-btn">
|
|
2
|
-
<button type="button" class="btn btn-secondary dropdown-toggle" data-bs-toggle="dropdown">
|
|
2
|
+
<button type="button" class="btn btn-secondary dropdown-toggle" data-bs-toggle="dropdown" data-bs-popper-config='{"strategy": "fixed"}'>
|
|
3
3
|
<span class="mdi mdi-chevron-down"></span>
|
|
4
4
|
</button>
|
|
5
|
-
<ul class="dropdown-menu dropdown-menu-
|
|
6
|
-
<li><a href="#" target="{{ target_field }}" data="10000" class="set_speed">10 Mbps</a></li>
|
|
7
|
-
<li><a href="#" target="{{ target_field }}" data="100000" class="set_speed">100 Mbps</a></li>
|
|
8
|
-
<li><a href="#" target="{{ target_field }}" data="1000000" class="set_speed">1 Gbps</a></li>
|
|
9
|
-
<li><a href="#" target="{{ target_field }}" data="10000000" class="set_speed">10 Gbps</a></li>
|
|
10
|
-
<li><a href="#" target="{{ target_field }}" data="25000000" class="set_speed">25 Gbps</a></li>
|
|
11
|
-
<li><a href="#" target="{{ target_field }}" data="40000000" class="set_speed">40 Gbps</a></li>
|
|
12
|
-
<li><a href="#" target="{{ target_field }}" data="100000000" class="set_speed">100 Gbps</a></li>
|
|
13
|
-
<li class="divider"></li>
|
|
14
|
-
<li><a href="#" target="{{ target_field }}" data="1544" class="set_speed">T1 (1.544 Mbps)</a></li>
|
|
15
|
-
<li><a href="#" target="{{ target_field }}" data="2048" class="set_speed">E1 (2.048 Mbps)</a></li>
|
|
5
|
+
<ul class="dropdown-menu dropdown-menu-end">
|
|
6
|
+
<li><a href="#" target="{{ target_field }}" data="10000" class="set_speed dropdown-item">10 Mbps</a></li>
|
|
7
|
+
<li><a href="#" target="{{ target_field }}" data="100000" class="set_speed dropdown-item">100 Mbps</a></li>
|
|
8
|
+
<li><a href="#" target="{{ target_field }}" data="1000000" class="set_speed dropdown-item">1 Gbps</a></li>
|
|
9
|
+
<li><a href="#" target="{{ target_field }}" data="10000000" class="set_speed dropdown-item">10 Gbps</a></li>
|
|
10
|
+
<li><a href="#" target="{{ target_field }}" data="25000000" class="set_speed dropdown-item">25 Gbps</a></li>
|
|
11
|
+
<li><a href="#" target="{{ target_field }}" data="40000000" class="set_speed dropdown-item">40 Gbps</a></li>
|
|
12
|
+
<li><a href="#" target="{{ target_field }}" data="100000000" class="set_speed dropdown-item">100 Gbps</a></li>
|
|
13
|
+
<li><hr class="dropdown-divider"></li>
|
|
14
|
+
<li><a href="#" target="{{ target_field }}" data="1544" class="set_speed dropdown-item">T1 (1.544 Mbps)</a></li>
|
|
15
|
+
<li><a href="#" target="{{ target_field }}" data="2048" class="set_speed dropdown-item">E1 (2.048 Mbps)</a></li>
|
|
16
16
|
</ul>
|
|
17
17
|
</span>
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
{% extends '
|
|
1
|
+
{% extends 'generic/object_retrieve.html' %}
|
|
2
2
|
{% comment %}3.0 TODO: remove this template, which only exists for backward compatibility with 2.4 and earlier{% endcomment %}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
from django.contrib.contenttypes.models import ContentType
|
|
2
|
-
from django.test import tag
|
|
3
2
|
from django.urls import reverse
|
|
4
3
|
|
|
5
4
|
from nautobot.circuits.models import Circuit, CircuitTermination, CircuitType, Provider
|
|
@@ -48,7 +47,6 @@ class CircuitTestCase(SeleniumTestCase, ObjectsListMixin, ObjectDetailsMixin):
|
|
|
48
47
|
)
|
|
49
48
|
return circuit
|
|
50
49
|
|
|
51
|
-
@tag("fix_in_v3")
|
|
52
50
|
def test_circuit_create(self):
|
|
53
51
|
cid = "Circuit-test-abc123"
|
|
54
52
|
description = "My Precious Circuit"
|
|
@@ -87,16 +85,15 @@ class CircuitTestCase(SeleniumTestCase, ObjectsListMixin, ObjectDetailsMixin):
|
|
|
87
85
|
circuit = Circuit.objects.get(cid=cid)
|
|
88
86
|
self.assertIn(self.live_server_url + reverse("circuits:circuit", kwargs={"pk": circuit.pk}), self.browser.url)
|
|
89
87
|
|
|
90
|
-
self.assertPanelValue("
|
|
91
|
-
self.assertPanelValue("
|
|
92
|
-
self.assertPanelValue("
|
|
93
|
-
self.assertPanelValue("
|
|
94
|
-
self.assertPanelValue("
|
|
95
|
-
self.assertPanelValue("
|
|
96
|
-
self.assertPanelValue("
|
|
97
|
-
self.assertPanelValue("
|
|
88
|
+
self.assertPanelValue("CIRCUIT", "Circuit ID", cid)
|
|
89
|
+
self.assertPanelValue("CIRCUIT", "Status", "Active")
|
|
90
|
+
self.assertPanelValue("CIRCUIT", "Provider", self.provider.name)
|
|
91
|
+
self.assertPanelValue("CIRCUIT", "Circuit Type", self.circuit_type.name)
|
|
92
|
+
self.assertPanelValue("CIRCUIT", "Tenant", self.tenant.name)
|
|
93
|
+
self.assertPanelValue("CIRCUIT", "Date Installed", "Jan. 1, 2025")
|
|
94
|
+
self.assertPanelValue("CIRCUIT", "Commit Rate (Kbps)", "192")
|
|
95
|
+
self.assertPanelValue("CIRCUIT", "Description", description)
|
|
98
96
|
|
|
99
|
-
@tag("fix_in_v3")
|
|
100
97
|
def test_circuit_create_termination(self):
|
|
101
98
|
circuit = self.create_circuit("Circuit-test-termination")
|
|
102
99
|
sides = ["A", "Z"]
|
|
@@ -108,7 +105,7 @@ class CircuitTestCase(SeleniumTestCase, ObjectsListMixin, ObjectDetailsMixin):
|
|
|
108
105
|
self.assertIn(details_url, self.browser.url)
|
|
109
106
|
|
|
110
107
|
# Find and click add termination button
|
|
111
|
-
termination_panel_xpath = f'//*[@id="main"]//div[@class
|
|
108
|
+
termination_panel_xpath = f'//*[@id="main"]//div[contains(@class, "card-header") and contains(normalize-space(), "TERMINATION - {side} SIDE")]'
|
|
112
109
|
self.browser.find_by_xpath(f'{termination_panel_xpath}//a[normalize-space()="Add"]').click()
|
|
113
110
|
|
|
114
111
|
port_speed = ord(side)
|
|
@@ -129,7 +126,7 @@ class CircuitTestCase(SeleniumTestCase, ObjectsListMixin, ObjectDetailsMixin):
|
|
|
129
126
|
self.assertTrue(self.browser.is_text_present(f"Created circuit termination Termination {side}"))
|
|
130
127
|
|
|
131
128
|
# Assert that value are properly set
|
|
132
|
-
panel_label = f"
|
|
129
|
+
panel_label = f"TERMINATION - {side} SIDE"
|
|
133
130
|
self.assertPanelValue(panel_label, "Location", self.location.name)
|
|
134
131
|
self.assertPanelValue(panel_label, "Speed", port_speed)
|
|
135
132
|
self.assertPanelValue(panel_label, "Speed", upstream_speed)
|
nautobot/cloud/filters.py
CHANGED
|
@@ -9,7 +9,7 @@ from nautobot.dcim.models import Manufacturer
|
|
|
9
9
|
from nautobot.extras.filters import NautobotFilterSet
|
|
10
10
|
from nautobot.extras.models import SecretsGroup
|
|
11
11
|
from nautobot.extras.utils import FeatureQuery
|
|
12
|
-
from nautobot.ipam.
|
|
12
|
+
from nautobot.ipam.filter_mixins import PrefixFilter
|
|
13
13
|
|
|
14
14
|
|
|
15
15
|
class CloudAccountFilterSet(NautobotFilterSet):
|
nautobot/cloud/navigation.py
CHANGED
|
@@ -4,12 +4,13 @@ from nautobot.core.apps import (
|
|
|
4
4
|
NavMenuItem,
|
|
5
5
|
NavMenuTab,
|
|
6
6
|
)
|
|
7
|
+
from nautobot.core.ui.choices import NavigationIconChoices, NavigationWeightChoices
|
|
7
8
|
|
|
8
9
|
menu_items = (
|
|
9
10
|
NavMenuTab(
|
|
10
11
|
name="Cloud",
|
|
11
|
-
icon=
|
|
12
|
-
weight=
|
|
12
|
+
icon=NavigationIconChoices.CLOUD,
|
|
13
|
+
weight=NavigationWeightChoices.CLOUD,
|
|
13
14
|
groups=(
|
|
14
15
|
NavMenuGroup(
|
|
15
16
|
name="Cloud",
|
nautobot/core/api/schema.py
CHANGED
|
@@ -143,7 +143,7 @@ class NautobotAutoSchema(AutoSchema):
|
|
|
143
143
|
"name": "exclude_m2m",
|
|
144
144
|
"required": False,
|
|
145
145
|
"description": "Exclude many-to-many fields from the response",
|
|
146
|
-
"schema": {"type": "boolean"
|
|
146
|
+
"schema": {"type": "boolean"},
|
|
147
147
|
}
|
|
148
148
|
)
|
|
149
149
|
# TODO: add "include" parameter to the schema where relevant - nautobot/nautobot#685
|
nautobot/core/api/serializers.py
CHANGED
|
@@ -64,6 +64,7 @@ class OptInFieldsMixin:
|
|
|
64
64
|
- Removes all serializer fields specified in `Meta.opt_in_fields` list that aren't specified in the
|
|
65
65
|
`include` query parameter. (applies to GET requests only)
|
|
66
66
|
- If the `exclude_m2m` query parameter is truthy, remove all many-to-many serializer fields for performance.
|
|
67
|
+
If `exclude_m2m` is not provided, only `tags`, `content_types`, and `object_types` are included by default.
|
|
67
68
|
|
|
68
69
|
As an example, if the serializer specifies that `opt_in_fields = ["computed_fields"]`
|
|
69
70
|
but `computed_fields` is not specified in the `?include` query parameter, `computed_fields` will be popped
|
|
@@ -102,9 +103,13 @@ class OptInFieldsMixin:
|
|
|
102
103
|
|
|
103
104
|
# If exclude_m2m is present and truthy, mark any many-to-many fields as write-only so they
|
|
104
105
|
# don't get included in the response.
|
|
105
|
-
|
|
106
|
+
# If exclude_m2m is not present, we include a subset of many-to-many fields by default.
|
|
107
|
+
exclude_m2m = params.get("exclude_m2m")
|
|
108
|
+
if exclude_m2m is None or is_truthy(exclude_m2m):
|
|
106
109
|
for field_instance in fields.values():
|
|
107
110
|
if isinstance(field_instance, (serializers.ManyRelatedField, serializers.ListSerializer)):
|
|
111
|
+
if exclude_m2m is None and field_instance.source in constants.DEFAULT_M2M_FIELDS:
|
|
112
|
+
continue
|
|
108
113
|
field_instance.write_only = True
|
|
109
114
|
|
|
110
115
|
self.__pruned_fields = fields
|
nautobot/core/api/urls.py
CHANGED
|
@@ -51,6 +51,7 @@ urlpatterns = [
|
|
|
51
51
|
path("tenancy/", include("nautobot.tenancy.api.urls")),
|
|
52
52
|
path("users/", include("nautobot.users.api.urls")),
|
|
53
53
|
path("virtualization/", include("nautobot.virtualization.api.urls")),
|
|
54
|
+
path("vpn/", include("nautobot.vpn.api.urls")),
|
|
54
55
|
path("wireless/", include("nautobot.wireless.api.urls")),
|
|
55
56
|
path("status/", StatusView.as_view(), name="api-status"),
|
|
56
57
|
path("docs/", NautobotSpectacularSwaggerView.as_view(url_name="schema"), name="api_docs"),
|
nautobot/core/api/views.py
CHANGED
nautobot/core/apps/__init__.py
CHANGED
|
@@ -9,7 +9,6 @@ from django.db.models.signals import post_migrate
|
|
|
9
9
|
from django.urls import reverse
|
|
10
10
|
from django.urls.exceptions import NoReverseMatch
|
|
11
11
|
from django.utils.http import urlencode
|
|
12
|
-
from django.utils.module_loading import import_string
|
|
13
12
|
from graphene.types import generic, String
|
|
14
13
|
|
|
15
14
|
from nautobot.core.signals import nautobot_database_ready
|
|
@@ -31,7 +30,8 @@ from nautobot.core.ui.nav import ( # isort: skip # noqa: F401
|
|
|
31
30
|
NavMenuTab,
|
|
32
31
|
NAV_CONTEXT_NAMES,
|
|
33
32
|
)
|
|
34
|
-
|
|
33
|
+
from nautobot.core.utils.module_loading import import_string_optional
|
|
34
|
+
from nautobot.core.utils.patch_social_django import patch_django_storage
|
|
35
35
|
from nautobot.extras.registry import registry
|
|
36
36
|
|
|
37
37
|
logger = logging.getLogger(__name__)
|
|
@@ -60,17 +60,11 @@ class NautobotConfig(AppConfig):
|
|
|
60
60
|
"""
|
|
61
61
|
Ready function initiates the import application.
|
|
62
62
|
"""
|
|
63
|
-
|
|
64
|
-
homepage_layout = import_string(f"{self.name}.{self.homepage_layout}")
|
|
63
|
+
if homepage_layout := import_string_optional(f"{self.name}.{self.homepage_layout}"):
|
|
65
64
|
register_homepage_panels(self.path, self.label, homepage_layout)
|
|
66
|
-
except ImportError:
|
|
67
|
-
pass
|
|
68
65
|
|
|
69
|
-
|
|
70
|
-
menu_items = import_string(f"{self.name}.{self.menu_tabs}")
|
|
66
|
+
if menu_items := import_string_optional(f"{self.name}.{self.menu_tabs}"):
|
|
71
67
|
register_menu_items(menu_items)
|
|
72
|
-
except ImportError:
|
|
73
|
-
pass
|
|
74
68
|
|
|
75
69
|
|
|
76
70
|
def create_or_check_entry(grouping, record, key, path):
|
|
@@ -364,6 +358,13 @@ class CoreConfig(NautobotConfig):
|
|
|
364
358
|
logger.warning("Maintenance mode enabled: disabling update of most recent login time")
|
|
365
359
|
user_logged_in.disconnect(update_last_login, dispatch_uid="update_last_login")
|
|
366
360
|
|
|
361
|
+
# SECURITY
|
|
362
|
+
# Patch social_django to prevent account takeover vulnerability
|
|
363
|
+
from social_django.models import DjangoStorage
|
|
364
|
+
|
|
365
|
+
# TODO: When upgrading to 5.6.0 or later, remove the patch
|
|
366
|
+
patch_django_storage(DjangoStorage)
|
|
367
|
+
|
|
367
368
|
post_migrate.connect(post_migrate_send_nautobot_database_ready, sender=self)
|
|
368
369
|
|
|
369
370
|
super().ready()
|
nautobot/core/celery/__init__.py
CHANGED
|
@@ -12,7 +12,6 @@ from django.apps import apps
|
|
|
12
12
|
from django.conf import settings
|
|
13
13
|
from django.db.utils import OperationalError, ProgrammingError
|
|
14
14
|
from django.utils.functional import SimpleLazyObject
|
|
15
|
-
from django.utils.module_loading import import_string
|
|
16
15
|
from kombu.serialization import register
|
|
17
16
|
from prometheus_client import CollectorRegistry, multiprocess, start_http_server
|
|
18
17
|
|
|
@@ -21,8 +20,7 @@ from nautobot.core.branching import BranchContext
|
|
|
21
20
|
from nautobot.core.celery.control import discard_git_repository, refresh_git_repository # noqa: F401 # unused-import
|
|
22
21
|
from nautobot.core.celery.encoders import NautobotKombuJSONEncoder
|
|
23
22
|
from nautobot.core.celery.log import NautobotDatabaseHandler
|
|
24
|
-
from nautobot.core.utils.module_loading import import_modules_privately
|
|
25
|
-
from nautobot.extras.plugins.utils import import_object
|
|
23
|
+
from nautobot.core.utils.module_loading import import_modules_privately, import_string_optional
|
|
26
24
|
from nautobot.extras.registry import registry
|
|
27
25
|
|
|
28
26
|
logger = logging.getLogger(__name__)
|
|
@@ -140,7 +138,7 @@ def _import_dynamic_jobs_from_apps():
|
|
|
140
138
|
del sys.modules[job.__module__]
|
|
141
139
|
|
|
142
140
|
# Load app jobs
|
|
143
|
-
app_config.features["jobs"] =
|
|
141
|
+
app_config.features["jobs"] = import_string_optional(f"{app_config.__module__}.{app_config.jobs}")
|
|
144
142
|
|
|
145
143
|
|
|
146
144
|
def add_nautobot_log_handler(logger_instance, log_format=None):
|
|
@@ -220,7 +218,7 @@ def nautobot_kombu_json_loads_hook(data):
|
|
|
220
218
|
qual_name = data.pop("__nautobot_type__")
|
|
221
219
|
branch_name = data.pop("__nautobot_branch__", None)
|
|
222
220
|
logger.debug("Performing nautobot deserialization for type %s", qual_name)
|
|
223
|
-
cls =
|
|
221
|
+
cls = import_string_optional(qual_name) # fully qualified dotted import path
|
|
224
222
|
if cls:
|
|
225
223
|
|
|
226
224
|
def get_object():
|
nautobot/core/checks.py
CHANGED
|
@@ -6,6 +6,9 @@ from django.core.exceptions import ValidationError
|
|
|
6
6
|
from django.core.validators import URLValidator
|
|
7
7
|
from django.db import connections
|
|
8
8
|
|
|
9
|
+
from nautobot.core.utils.config import get_settings_or_config
|
|
10
|
+
from nautobot.dcim.choices import DeviceUniquenessChoices
|
|
11
|
+
|
|
9
12
|
E002 = Error(
|
|
10
13
|
"'nautobot.core.authentication.ObjectPermissionBackend' must be included in AUTHENTICATION_BACKENDS",
|
|
11
14
|
id="nautobot.core.E002",
|
|
@@ -42,6 +45,19 @@ W005 = Warning(
|
|
|
42
45
|
obj=settings,
|
|
43
46
|
)
|
|
44
47
|
|
|
48
|
+
W006 = Warning(
|
|
49
|
+
"The deprecated setting DEVICE_NAME_AS_NATURAL_KEY is still defined.",
|
|
50
|
+
hint="This setting has been superseded by DEVICE_UNIQUENESS (see Device Constraints).",
|
|
51
|
+
id="nautobot.core.W006",
|
|
52
|
+
obj=settings,
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
W007 = Warning(
|
|
56
|
+
"Invalid DEVICE_UNIQUENESS configuration value.",
|
|
57
|
+
hint=f"DEVICE_UNIQUENESS must be one of: {', '.join(DeviceUniquenessChoices.values())}.",
|
|
58
|
+
id="nautobot.core.W007",
|
|
59
|
+
)
|
|
60
|
+
|
|
45
61
|
MIN_POSTGRESQL_MAJOR_VERSION = 12
|
|
46
62
|
MIN_POSTGRESQL_MINOR_VERSION = 0
|
|
47
63
|
|
|
@@ -153,3 +169,33 @@ def check_data_validation_engine_installed(app_configs, **kwargs):
|
|
|
153
169
|
if app_name in settings.PLUGINS or app_name in settings.PLUGINS_CONFIG:
|
|
154
170
|
return [E006]
|
|
155
171
|
return []
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
@register(Tags.compatibility)
|
|
175
|
+
def check_deprecated_device_name_as_natural_key(app_configs, **kwargs):
|
|
176
|
+
"""
|
|
177
|
+
Warn if the deprecated DEVICE_NAME_AS_NATURAL_KEY setting is still defined.
|
|
178
|
+
|
|
179
|
+
This setting existed prior to 3.0 and has been replaced by the
|
|
180
|
+
DEVICE_UNIQUENESS Constance configuration.
|
|
181
|
+
"""
|
|
182
|
+
try:
|
|
183
|
+
get_settings_or_config("DEVICE_NAME_AS_NATURAL_KEY")
|
|
184
|
+
return [W006]
|
|
185
|
+
except AttributeError:
|
|
186
|
+
pass
|
|
187
|
+
return []
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
@register(Tags.compatibility)
|
|
191
|
+
def check_valid_value_for_device_uniqueness(app_configs, **kwargs):
|
|
192
|
+
"""
|
|
193
|
+
Warn if the invalid value for DEVICE_UNIQUENESS is set.
|
|
194
|
+
"""
|
|
195
|
+
try:
|
|
196
|
+
device_uniqueness = get_settings_or_config("DEVICE_UNIQUENESS")
|
|
197
|
+
if device_uniqueness not in DeviceUniquenessChoices.values():
|
|
198
|
+
return [W007]
|
|
199
|
+
except AttributeError:
|
|
200
|
+
return [W007]
|
|
201
|
+
return []
|