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/ipam/tests/test_api.py
CHANGED
|
@@ -40,6 +40,7 @@ from nautobot.ipam.models import (
|
|
|
40
40
|
VRFDeviceAssignment,
|
|
41
41
|
VRFPrefixAssignment,
|
|
42
42
|
)
|
|
43
|
+
from nautobot.tenancy.models import Tenant
|
|
43
44
|
from nautobot.virtualization.models import Cluster, ClusterType, VirtualMachine, VMInterface
|
|
44
45
|
|
|
45
46
|
|
|
@@ -57,22 +58,28 @@ class NamespaceTest(APIViewTestCases.APIViewTestCase):
|
|
|
57
58
|
@classmethod
|
|
58
59
|
def setUpTestData(cls):
|
|
59
60
|
location = Location.objects.first()
|
|
61
|
+
tenant = Tenant.objects.first()
|
|
60
62
|
cls.create_data = [
|
|
61
63
|
{
|
|
62
64
|
"name": "Purple Monkey Namespace 1",
|
|
63
|
-
"description": "A
|
|
65
|
+
"description": "A namespace with a tenant and location.",
|
|
64
66
|
"location": location.pk,
|
|
67
|
+
"tenant": tenant.pk,
|
|
65
68
|
},
|
|
66
69
|
{
|
|
67
70
|
"name": "Purple Monkey Namespace 2",
|
|
68
|
-
"description": "A
|
|
69
|
-
"
|
|
71
|
+
"description": "A namespace with a tenant and no location.",
|
|
72
|
+
"tenant": tenant.pk,
|
|
70
73
|
},
|
|
71
74
|
{
|
|
72
75
|
"name": "Purple Monkey Namespace 3",
|
|
73
|
-
"description": "A
|
|
76
|
+
"description": "A namespace with no tenant but with a location.",
|
|
74
77
|
"location": location.pk,
|
|
75
78
|
},
|
|
79
|
+
{
|
|
80
|
+
"name": "Purple Monkey Namespace 4",
|
|
81
|
+
"description": "A namespace with no tenant and no location.",
|
|
82
|
+
},
|
|
76
83
|
]
|
|
77
84
|
cls.bulk_update_data = {
|
|
78
85
|
"description": "A perfectly new description.",
|
|
@@ -194,7 +201,7 @@ class VRFDeviceAssignmentTest(APIViewTestCases.APIViewTestCase):
|
|
|
194
201
|
},
|
|
195
202
|
{
|
|
196
203
|
"vrf": cls.vrfs[4].pk,
|
|
197
|
-
"virtual_device_context": cls.vdcs[
|
|
204
|
+
"virtual_device_context": cls.vdcs[1].pk,
|
|
198
205
|
},
|
|
199
206
|
]
|
|
200
207
|
cls.bulk_update_data = {
|
|
@@ -1619,7 +1626,7 @@ class IPAddressTest(APIViewTestCases.APIViewTestCase):
|
|
|
1619
1626
|
self.assertHttpStatus(ip2, status.HTTP_201_CREATED)
|
|
1620
1627
|
|
|
1621
1628
|
response = self.client.get(
|
|
1622
|
-
self._get_detail_url(nat_inside) + "?depth=1",
|
|
1629
|
+
self._get_detail_url(nat_inside) + "?depth=1&exclude_m2m=false",
|
|
1623
1630
|
**self.header,
|
|
1624
1631
|
)
|
|
1625
1632
|
self.assertHttpStatus(response, status.HTTP_200_OK)
|
|
@@ -17,6 +17,7 @@ from nautobot.ipam.choices import PrefixTypeChoices, ServiceProtocolChoices
|
|
|
17
17
|
from nautobot.ipam.filters import (
|
|
18
18
|
IPAddressFilterSet,
|
|
19
19
|
IPAddressToInterfaceFilterSet,
|
|
20
|
+
NamespaceFilterSet,
|
|
20
21
|
PrefixFilterSet,
|
|
21
22
|
PrefixLocationAssignmentFilterSet,
|
|
22
23
|
RIRFilterSet,
|
|
@@ -54,6 +55,15 @@ from nautobot.virtualization.models import (
|
|
|
54
55
|
)
|
|
55
56
|
|
|
56
57
|
|
|
58
|
+
class NamespaceTestCase(FilterTestCases.FilterTestCase, FilterTestCases.TenancyFilterTestCaseMixin):
|
|
59
|
+
"""Namespace FilterSet tests"""
|
|
60
|
+
|
|
61
|
+
queryset = Namespace.objects.all()
|
|
62
|
+
filterset = NamespaceFilterSet
|
|
63
|
+
tenancy_related_name = "namespaces"
|
|
64
|
+
generic_filter_tests = (("name",),)
|
|
65
|
+
|
|
66
|
+
|
|
57
67
|
class VRFTestCase(FilterTestCases.FilterTestCase, FilterTestCases.TenancyFilterTestCaseMixin):
|
|
58
68
|
"""VRF Filterset tests
|
|
59
69
|
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
"""Test IPAM forms."""
|
|
2
2
|
|
|
3
3
|
from django.forms import Form
|
|
4
|
-
from django.test import TestCase
|
|
5
4
|
|
|
5
|
+
from nautobot.core.testing import TestCase
|
|
6
6
|
from nautobot.core.testing.forms import FormTestCases
|
|
7
7
|
from nautobot.extras.models import Status
|
|
8
8
|
from nautobot.ipam import forms, models
|
|
@@ -5,9 +5,9 @@ from django.contrib.contenttypes.models import ContentType
|
|
|
5
5
|
from django.core.exceptions import ValidationError
|
|
6
6
|
from django.db import connection, IntegrityError
|
|
7
7
|
from django.db.models import ProtectedError
|
|
8
|
-
from django.test import TestCase
|
|
9
8
|
import netaddr
|
|
10
9
|
|
|
10
|
+
from nautobot.core.testing import TestCase
|
|
11
11
|
from nautobot.core.testing.models import ModelTestCases
|
|
12
12
|
from nautobot.dcim import choices as dcim_choices
|
|
13
13
|
from nautobot.dcim.models import Device, DeviceType, Interface, Location, LocationType, Module, ModuleBay, ModuleType
|
|
@@ -172,6 +172,48 @@ class IPAddressToInterfaceTest(TestCase):
|
|
|
172
172
|
IPAddressToInterface.objects.create(vm_interface=None, interface=None, ip_address=ip_addr)
|
|
173
173
|
self.assertIn("Must associate to either an Interface or a VMInterface.", str(cm.exception))
|
|
174
174
|
|
|
175
|
+
def test_m2m_save_signal_prevents_iface_ipaddress_and_vminterface_through_defaults(self):
|
|
176
|
+
"""Test that the m2m save signal prevents a VMInterface from using the same IPAddressToInterface instance as an Interface."""
|
|
177
|
+
ip_addr = IPAddress.objects.create(address="192.0.2.1/24", status=self.status, namespace=self.namespace)
|
|
178
|
+
with self.assertRaises(ValidationError) as cm:
|
|
179
|
+
self.test_int1.ip_addresses.add(ip_addr, through_defaults={"vm_interface": self.test_vmint1})
|
|
180
|
+
|
|
181
|
+
self.assertIn(
|
|
182
|
+
"Cannot use a single instance to associate to both an Interface and a VMInterface.", str(cm.exception)
|
|
183
|
+
)
|
|
184
|
+
|
|
185
|
+
def test_m2m_save_signal_prevents_vminterface_ipaddress_and_interface_through_defaults(self):
|
|
186
|
+
"""Test that the m2m save signal prevents an Interface from using the same IPAddressToInterface instance as a VMInterface."""
|
|
187
|
+
ip_addr = IPAddress.objects.create(address="192.0.2.1/24", status=self.status, namespace=self.namespace)
|
|
188
|
+
with self.assertRaises(ValidationError) as cm:
|
|
189
|
+
self.test_vmint1.ip_addresses.add(ip_addr, through_defaults={"interface": self.test_int1})
|
|
190
|
+
|
|
191
|
+
self.assertIn(
|
|
192
|
+
"Cannot use a single instance to associate to both an Interface and a VMInterface.", str(cm.exception)
|
|
193
|
+
)
|
|
194
|
+
|
|
195
|
+
def test_m2m_save_signal_prevents_ipaddress_interface_and_vminterface_through_defaults(self):
|
|
196
|
+
"""Test that the m2m save signal prevents an Interface being added to an IPAddress with a VMInterface through_defaults."""
|
|
197
|
+
ip_addr = IPAddress.objects.create(address="192.0.2.1/24", status=self.status, namespace=self.namespace)
|
|
198
|
+
|
|
199
|
+
with self.assertRaises(ValidationError) as cm:
|
|
200
|
+
ip_addr.interfaces.add(self.test_int1, through_defaults={"vm_interface": self.test_vmint1})
|
|
201
|
+
|
|
202
|
+
self.assertIn(
|
|
203
|
+
"Cannot use a single instance to associate to both an Interface and a VMInterface.", str(cm.exception)
|
|
204
|
+
)
|
|
205
|
+
|
|
206
|
+
def test_m2m_save_signal_prevents_ipaddress_vminterface_and_interface_through_defaults(self):
|
|
207
|
+
"""Test that the m2m save signal prevents a VMInterface being added to an IPAddress with an Interface through_defaults."""
|
|
208
|
+
ip_addr = IPAddress.objects.create(address="192.0.2.1/24", status=self.status, namespace=self.namespace)
|
|
209
|
+
|
|
210
|
+
with self.assertRaises(ValidationError) as cm:
|
|
211
|
+
ip_addr.vm_interfaces.add(self.test_vmint1, through_defaults={"interface": self.test_int1})
|
|
212
|
+
|
|
213
|
+
self.assertIn(
|
|
214
|
+
"Cannot use a single instance to associate to both an Interface and a VMInterface.", str(cm.exception)
|
|
215
|
+
)
|
|
216
|
+
|
|
175
217
|
def test_primary_ip_retained_when_deleted_from_device_or_module_interface(self):
|
|
176
218
|
"""Test primary_ip4 remains set when the same IP is assigned to multiple interfaces and deleted from one."""
|
|
177
219
|
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
from django.test import TestCase
|
|
2
|
-
|
|
3
1
|
from nautobot.core.models.querysets import count_related
|
|
2
|
+
from nautobot.core.testing import TestCase
|
|
4
3
|
from nautobot.dcim.models.locations import Location
|
|
5
4
|
from nautobot.ipam.models import Prefix
|
|
6
5
|
from nautobot.ipam.tables import PrefixTable
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
from django.test import TestCase
|
|
2
1
|
import netaddr
|
|
3
2
|
|
|
4
3
|
from nautobot.core.forms.utils import parse_numeric_range
|
|
4
|
+
from nautobot.core.testing import TestCase
|
|
5
5
|
from nautobot.extras.models import Status
|
|
6
6
|
from nautobot.ipam.models import IPAddress, Namespace, Prefix, VLAN, VLANGroup
|
|
7
7
|
from nautobot.ipam.utils import add_available_ipaddresses, add_available_vlans
|
|
@@ -51,17 +51,7 @@ from nautobot.users.models import ObjectPermission
|
|
|
51
51
|
from nautobot.virtualization.models import Cluster, ClusterType, VirtualMachine
|
|
52
52
|
|
|
53
53
|
|
|
54
|
-
class NamespaceTestCase(
|
|
55
|
-
ViewTestCases.GetObjectViewTestCase,
|
|
56
|
-
ViewTestCases.GetObjectChangelogViewTestCase,
|
|
57
|
-
ViewTestCases.GetObjectNotesViewTestCase,
|
|
58
|
-
ViewTestCases.CreateObjectViewTestCase,
|
|
59
|
-
ViewTestCases.EditObjectViewTestCase,
|
|
60
|
-
ViewTestCases.DeleteObjectViewTestCase,
|
|
61
|
-
ViewTestCases.ListObjectsViewTestCase,
|
|
62
|
-
ViewTestCases.BulkEditObjectsViewTestCase,
|
|
63
|
-
ViewTestCases.BulkDeleteObjectsViewTestCase,
|
|
64
|
-
):
|
|
54
|
+
class NamespaceTestCase(ViewTestCases.PrimaryObjectViewTestCase):
|
|
65
55
|
model = Namespace
|
|
66
56
|
custom_action_required_permissions = {
|
|
67
57
|
"ipam:namespace_vrfs": ["ipam.view_namespace", "ipam.view_vrf"],
|
|
@@ -72,11 +62,18 @@ class NamespaceTestCase(
|
|
|
72
62
|
@classmethod
|
|
73
63
|
def setUpTestData(cls):
|
|
74
64
|
locations = Location.objects.get_for_model(Namespace)
|
|
65
|
+
tenants = Tenant.objects.all()[:2]
|
|
75
66
|
|
|
76
|
-
cls.form_data = {
|
|
67
|
+
cls.form_data = {
|
|
68
|
+
"name": "Namespace X",
|
|
69
|
+
"location": locations[0].pk,
|
|
70
|
+
"tenant": tenants[0].pk,
|
|
71
|
+
"description": "A new Namespace",
|
|
72
|
+
}
|
|
77
73
|
|
|
78
74
|
cls.bulk_edit_data = {
|
|
79
75
|
"description": "New description",
|
|
76
|
+
"tenant": tenants[1].pk,
|
|
80
77
|
"location": locations[1].pk,
|
|
81
78
|
}
|
|
82
79
|
|
|
@@ -165,7 +162,7 @@ class RIRTestCase(ViewTestCases.OrganizationalObjectViewTestCase):
|
|
|
165
162
|
if count > 1:
|
|
166
163
|
self.assertBodyContains(
|
|
167
164
|
response,
|
|
168
|
-
f'<a href="{prefix_list_url}?{urlencode({"rir": rir.name})}" class="badge">{count}</a>',
|
|
165
|
+
f'<a href="{prefix_list_url}?{urlencode({"rir": rir.name})}" class="badge bg-primary">{count}</a>',
|
|
169
166
|
)
|
|
170
167
|
elif count == 1:
|
|
171
168
|
self.assertBodyContains(response, hyperlinked_object(rir.prefixes.first()))
|
|
@@ -250,7 +247,8 @@ class PrefixTestCase(ViewTestCases.PrimaryObjectViewTestCase, ViewTestCases.List
|
|
|
250
247
|
count = prefix.locations.count()
|
|
251
248
|
if count > 1:
|
|
252
249
|
self.assertBodyContains(
|
|
253
|
-
response,
|
|
250
|
+
response,
|
|
251
|
+
f'<a href="{locations_list_url}?prefixes={prefix.pk}" class="badge bg-primary">{count}</a>',
|
|
254
252
|
)
|
|
255
253
|
elif count == 1:
|
|
256
254
|
self.assertBodyContains(response, hyperlinked_object(prefix.locations.first(), "name"))
|
|
@@ -756,6 +754,7 @@ class IPAddressMergeTestCase(ModelViewTestCase):
|
|
|
756
754
|
self.add_permissions("ipam.change_ipaddress")
|
|
757
755
|
num_ips_before = IPAddress.objects.all().count()
|
|
758
756
|
ips = IPAddress.objects.all().exclude(pk__in=[self.dup_ip_1.pk, self.dup_ip_2.pk, self.dup_ip_3.pk])
|
|
757
|
+
self.assertGreaterEqual(len(ips), 6)
|
|
759
758
|
ip_ct = ContentType.objects.get_for_model(IPAddress)
|
|
760
759
|
locations = Location.objects.all()
|
|
761
760
|
location_ct = ContentType.objects.get_for_model(Location)
|
nautobot/ipam/ui.py
CHANGED
|
@@ -10,29 +10,12 @@ from nautobot.core.ui.object_detail import (
|
|
|
10
10
|
Button,
|
|
11
11
|
KeyValueTablePanel,
|
|
12
12
|
ObjectFieldsPanel,
|
|
13
|
-
ObjectsTablePanel,
|
|
14
13
|
)
|
|
15
14
|
from nautobot.core.views.utils import get_obj_from_context
|
|
16
15
|
|
|
17
16
|
logger = logging.getLogger(__name__)
|
|
18
17
|
|
|
19
18
|
|
|
20
|
-
# TODO: can be removed as a part of NAUTOBOT-1051
|
|
21
|
-
class PrefixChildTablePanel(ObjectsTablePanel):
|
|
22
|
-
def should_render(self, context: Context):
|
|
23
|
-
if not super().should_render(context):
|
|
24
|
-
return False
|
|
25
|
-
return context.get("active_tab") == "prefixes"
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
# TODO: can be removed as a part of NAUTOBOT-1051
|
|
29
|
-
class IPAddressTablePanel(ObjectsTablePanel):
|
|
30
|
-
def should_render(self, context: Context):
|
|
31
|
-
if not super().should_render(context):
|
|
32
|
-
return False
|
|
33
|
-
return context.get("active_tab") == "ip-addresses"
|
|
34
|
-
|
|
35
|
-
|
|
36
19
|
class AddChildPrefixButton(Button):
|
|
37
20
|
"""Custom button to add a child prefix inside a Prefix detail view."""
|
|
38
21
|
|
|
@@ -146,7 +146,9 @@ def process_vrfs(apps):
|
|
|
146
146
|
Namespace = apps.get_model("ipam", "Namespace")
|
|
147
147
|
VRF = apps.get_model("ipam", "VRF")
|
|
148
148
|
|
|
149
|
-
global_ns = Namespace.objects.
|
|
149
|
+
global_ns, _ = Namespace.objects.get_or_create(
|
|
150
|
+
name=GLOBAL_NS, defaults={"description": "Default Global namespace. Created by Nautobot."}
|
|
151
|
+
)
|
|
150
152
|
vrfs = VRF.objects.all().order_by("name", "rd")
|
|
151
153
|
unique_non_empty_vrfs = vrfs.filter(enforce_unique=True).exclude(ip_addresses__isnull=True, prefixes__isnull=True)
|
|
152
154
|
# At the point in the migration where we iterate through vrfs in global_ns_vrfs, every vrf that
|
|
@@ -257,6 +259,11 @@ def process_ip_addresses(apps):
|
|
|
257
259
|
broadcast = new_parent_cidr[-1]
|
|
258
260
|
# This can result in duplicate Prefixes being created in the global_ns but that will be
|
|
259
261
|
# cleaned up subsequently in `process_prefix_duplicates`.
|
|
262
|
+
if orphaned_ip.vrf and orphaned_ip.vrf.namespace:
|
|
263
|
+
prefix_namespace = orphaned_ip.vrf.namespace
|
|
264
|
+
else:
|
|
265
|
+
prefix_namespace = global_ns
|
|
266
|
+
|
|
260
267
|
new_parent = Prefix.objects.create(
|
|
261
268
|
ip_version=orphaned_ip.ip_version,
|
|
262
269
|
network=network,
|
|
@@ -264,7 +271,7 @@ def process_ip_addresses(apps):
|
|
|
264
271
|
tenant=orphaned_ip.tenant,
|
|
265
272
|
vrf=orphaned_ip.vrf,
|
|
266
273
|
prefix_length=prefix_length,
|
|
267
|
-
namespace=
|
|
274
|
+
namespace=prefix_namespace,
|
|
268
275
|
description=DESCRIPTION,
|
|
269
276
|
)
|
|
270
277
|
orphaned_ip.parent = new_parent
|
|
@@ -296,6 +303,13 @@ def process_prefix_duplicates(apps):
|
|
|
296
303
|
Prefix = apps.get_model("ipam", "Prefix")
|
|
297
304
|
global_namespace = Namespace.objects.get(name=GLOBAL_NS)
|
|
298
305
|
|
|
306
|
+
# First, assign any remaining prefixes with null namespace to Global namespace
|
|
307
|
+
null_namespace_prefixes = Prefix.objects.filter(namespace__isnull=True)
|
|
308
|
+
if null_namespace_prefixes.exists():
|
|
309
|
+
if "test" not in sys.argv:
|
|
310
|
+
print(f">>> Assigning {null_namespace_prefixes.count()} prefixes with null namespace to Global namespace")
|
|
311
|
+
null_namespace_prefixes.update(namespace=global_namespace)
|
|
312
|
+
|
|
299
313
|
namespaces = list(Namespace.objects.all())
|
|
300
314
|
# Always start with the Global Namespace.
|
|
301
315
|
namespaces.remove(global_namespace)
|
nautobot/ipam/utils/testing.py
CHANGED
|
@@ -5,8 +5,6 @@ import random
|
|
|
5
5
|
from django.apps import apps
|
|
6
6
|
from netaddr import IPNetwork
|
|
7
7
|
|
|
8
|
-
from nautobot.ipam.models import get_default_namespace_pk
|
|
9
|
-
|
|
10
8
|
# Calculate the probabilities to use for the maybe_subdivide() function defined below.
|
|
11
9
|
|
|
12
10
|
# Frequency of IPv4 (leaf, network) Prefixes by each given mask length in a "realistic" data set.
|
|
@@ -129,7 +127,15 @@ def create_prefixes_and_ips(initial_subnet: str, apps=apps, seed="Nautobot"): #
|
|
|
129
127
|
|
|
130
128
|
all_tenants = list(Tenant.objects.all())
|
|
131
129
|
if hasattr(VRF, "namespace"):
|
|
132
|
-
|
|
130
|
+
# Simulate mid-migration state: create Global namespace and assign all VRFs to it
|
|
131
|
+
# This creates more realistic test conditions for namespace-aware migration logic
|
|
132
|
+
Namespace = apps.get_model("ipam", "Namespace")
|
|
133
|
+
global_ns, _ = Namespace.objects.get_or_create(
|
|
134
|
+
name="Global", defaults={"description": "Default Global namespace. Created by Nautobot."}
|
|
135
|
+
)
|
|
136
|
+
# Pre-assign all VRFs to Global namespace to simulate early migration state
|
|
137
|
+
VRF.objects.all().update(namespace=global_ns)
|
|
138
|
+
all_vrfs = list(VRF.objects.filter(namespace_id=global_ns.pk))
|
|
133
139
|
else:
|
|
134
140
|
all_vrfs = list(VRF.objects.all())
|
|
135
141
|
|
nautobot/ipam/views.py
CHANGED
|
@@ -44,6 +44,7 @@ from nautobot.extras.models import Role, SavedView, Status, Tag
|
|
|
44
44
|
from nautobot.ipam.api import serializers
|
|
45
45
|
from nautobot.tenancy.models import Tenant
|
|
46
46
|
from nautobot.virtualization.models import VirtualMachine, VMInterface
|
|
47
|
+
from nautobot.vpn.tables import VPNTunnelEndpointTable
|
|
47
48
|
|
|
48
49
|
from . import filters, forms, tables, ui
|
|
49
50
|
from .models import (
|
|
@@ -423,6 +424,25 @@ class PrefixUIViewSet(NautobotUIViewSet):
|
|
|
423
424
|
paginate=False,
|
|
424
425
|
show_table_config_button=False,
|
|
425
426
|
),
|
|
427
|
+
object_detail.ObjectsTablePanel(
|
|
428
|
+
section=SectionChoices.RIGHT_HALF,
|
|
429
|
+
weight=300,
|
|
430
|
+
table_class=VPNTunnelEndpointTable,
|
|
431
|
+
table_attribute="vpn_tunnel_endpoints",
|
|
432
|
+
table_title="VPN Tunnel Endpoints",
|
|
433
|
+
exclude_columns=[
|
|
434
|
+
"vpn_profile",
|
|
435
|
+
"destination_ipaddress",
|
|
436
|
+
"destination_fqdn",
|
|
437
|
+
"protected_prefixes_dg_count",
|
|
438
|
+
"protected_prefixes_count",
|
|
439
|
+
"actions",
|
|
440
|
+
],
|
|
441
|
+
related_field_name="vpn_tunnel_endpoints",
|
|
442
|
+
add_button_route=None,
|
|
443
|
+
paginate=False,
|
|
444
|
+
show_table_config_button=False,
|
|
445
|
+
),
|
|
426
446
|
],
|
|
427
447
|
extra_tabs=[
|
|
428
448
|
object_detail.DistinctViewTab(
|
|
@@ -432,13 +452,13 @@ class PrefixUIViewSet(NautobotUIViewSet):
|
|
|
432
452
|
related_object_attribute="default_descendants",
|
|
433
453
|
url_name="ipam:prefix_prefixes",
|
|
434
454
|
panels=(
|
|
435
|
-
|
|
455
|
+
object_detail.ObjectsTablePanel(
|
|
436
456
|
section=SectionChoices.FULL_WIDTH,
|
|
437
457
|
weight=100,
|
|
438
458
|
context_table_key="prefix_table",
|
|
439
459
|
add_button_route=None,
|
|
440
460
|
include_paginator=True,
|
|
441
|
-
|
|
461
|
+
related_field_name="within",
|
|
442
462
|
),
|
|
443
463
|
),
|
|
444
464
|
),
|
|
@@ -449,18 +469,24 @@ class PrefixUIViewSet(NautobotUIViewSet):
|
|
|
449
469
|
related_object_attribute="all_ips",
|
|
450
470
|
url_name="ipam:prefix_ipaddresses",
|
|
451
471
|
panels=[
|
|
452
|
-
|
|
472
|
+
object_detail.ObjectsTablePanel(
|
|
453
473
|
section=SectionChoices.FULL_WIDTH,
|
|
454
474
|
weight=100,
|
|
455
475
|
context_table_key="ip_table",
|
|
456
476
|
add_button_route=None,
|
|
457
477
|
include_paginator=True,
|
|
458
|
-
|
|
478
|
+
related_field_name="prefix",
|
|
459
479
|
),
|
|
460
480
|
],
|
|
461
481
|
),
|
|
462
482
|
],
|
|
463
483
|
extra_buttons=[
|
|
484
|
+
object_detail.Button(
|
|
485
|
+
weight=100,
|
|
486
|
+
label="Available",
|
|
487
|
+
render_on_tab_id="prefixes",
|
|
488
|
+
template_path="ipam/inc/toggle_available.html",
|
|
489
|
+
),
|
|
464
490
|
ui.AddChildPrefixButton(
|
|
465
491
|
weight=200,
|
|
466
492
|
label="Add Child Prefix",
|
|
@@ -470,8 +496,14 @@ class PrefixUIViewSet(NautobotUIViewSet):
|
|
|
470
496
|
required_permissions=["ipam.add_prefix"],
|
|
471
497
|
render_on_tab_id="prefixes",
|
|
472
498
|
),
|
|
499
|
+
object_detail.Button(
|
|
500
|
+
weight=100,
|
|
501
|
+
label="Available",
|
|
502
|
+
render_on_tab_id="ip-addresses",
|
|
503
|
+
template_path="ipam/inc/toggle_available.html",
|
|
504
|
+
),
|
|
473
505
|
ui.AddIPAddressButton(
|
|
474
|
-
weight=
|
|
506
|
+
weight=200,
|
|
475
507
|
label="Add an IP Address",
|
|
476
508
|
link_name="ipam:ipaddress_add",
|
|
477
509
|
color=ButtonActionColorChoices.SUBMIT,
|
|
@@ -516,7 +548,9 @@ class PrefixUIViewSet(NautobotUIViewSet):
|
|
|
516
548
|
|
|
517
549
|
prefix_table = tables.PrefixDetailTable(
|
|
518
550
|
child_prefixes,
|
|
551
|
+
configurable=True,
|
|
519
552
|
exclude=["namespace"],
|
|
553
|
+
user=request.user,
|
|
520
554
|
data_transform_callback=data_transform_callback,
|
|
521
555
|
)
|
|
522
556
|
if request.user.has_perm("ipam.change_prefix") or request.user.has_perm("ipam.delete_prefix"):
|
|
@@ -547,6 +581,7 @@ class PrefixUIViewSet(NautobotUIViewSet):
|
|
|
547
581
|
"active_tab": "prefixes",
|
|
548
582
|
"view_action": "prefixes",
|
|
549
583
|
"show_available": request.GET.get("show_available", "true") == "true",
|
|
584
|
+
"badge_count_override": child_prefixes.count(),
|
|
550
585
|
}
|
|
551
586
|
)
|
|
552
587
|
|
|
@@ -568,7 +603,11 @@ class PrefixUIViewSet(NautobotUIViewSet):
|
|
|
568
603
|
)
|
|
569
604
|
|
|
570
605
|
ip_table = tables.IPAddressTable(
|
|
571
|
-
ipaddresses,
|
|
606
|
+
ipaddresses,
|
|
607
|
+
configurable=True,
|
|
608
|
+
exclude=["parent__namespace"],
|
|
609
|
+
user=request.user,
|
|
610
|
+
data_transform_callback=data_transform_callback,
|
|
572
611
|
)
|
|
573
612
|
if request.user.has_perm("ipam.change_ipaddress") or request.user.has_perm("ipam.delete_ipaddress"):
|
|
574
613
|
ip_table.columns.show("pk")
|
|
@@ -597,6 +636,7 @@ class PrefixUIViewSet(NautobotUIViewSet):
|
|
|
597
636
|
"active_tab": "ip-addresses",
|
|
598
637
|
"view_action": "ip_addresses",
|
|
599
638
|
"show_available": request.GET.get("show_available", "true") == "true",
|
|
639
|
+
"badge_count_override": ipaddresses.count(),
|
|
600
640
|
}
|
|
601
641
|
)
|
|
602
642
|
|