nautobot 2.4.21__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 +2 -2
- nautobot/apps/filters.py +9 -9
- nautobot/apps/forms.py +2 -0
- nautobot/apps/models.py +7 -2
- nautobot/apps/ui.py +20 -1
- nautobot/apps/utils.py +2 -3
- nautobot/apps/views.py +7 -1
- nautobot/circuits/filters.py +8 -23
- nautobot/circuits/navigation.py +3 -1
- nautobot/circuits/templates/circuits/circuit_create.html +9 -9
- nautobot/circuits/templates/circuits/circuit_terminations_swap.html +2 -2
- nautobot/circuits/templates/circuits/circuittermination_create.html +24 -33
- nautobot/circuits/templates/circuits/inc/circuit_termination.html +10 -10
- nautobot/circuits/templates/circuits/inc/circuit_termination_cable_fragment.html +13 -13
- nautobot/circuits/templates/circuits/inc/circuit_termination_header_extra_content.html +6 -6
- nautobot/circuits/templates/circuits/inc/circuit_termination_speed_fragment.html +3 -3
- nautobot/circuits/templates/circuits/inc/speed_widget.html +13 -13
- nautobot/circuits/templates/circuits/provider_create.html +9 -9
- nautobot/circuits/tests/integration/test_circuit.py +19 -19
- nautobot/circuits/tests/integration/test_circuits_bulk_operations.py +3 -0
- nautobot/circuits/tests/integration/test_relationships.py +4 -12
- nautobot/circuits/views.py +0 -2
- nautobot/cloud/filters.py +1 -13
- nautobot/cloud/navigation.py +3 -1
- nautobot/cloud/templates/cloud/cloudnetwork_update.html +9 -9
- nautobot/cloud/templates/cloud/cloudservice_update.html +6 -6
- nautobot/core/api/fields.py +30 -2
- nautobot/core/api/schema.py +1 -1
- nautobot/core/api/serializers.py +9 -2
- nautobot/core/api/urls.py +2 -0
- nautobot/core/api/views.py +58 -37
- nautobot/core/apps/__init__.py +6 -12
- nautobot/core/branching.py +83 -0
- nautobot/core/celery/__init__.py +11 -6
- nautobot/core/celery/backends.py +2 -0
- nautobot/core/celery/encoders.py +7 -0
- nautobot/core/celery/task.py +44 -0
- nautobot/core/checks.py +60 -0
- nautobot/core/cli/bootstrap_v3_to_v5.py +776 -0
- nautobot/core/constants.py +9 -0
- nautobot/core/context_processors.py +84 -0
- nautobot/core/filters.py +131 -2
- nautobot/core/forms/__init__.py +4 -2
- nautobot/core/forms/fields.py +10 -8
- nautobot/core/forms/forms.py +21 -9
- nautobot/core/forms/search.py +0 -15
- nautobot/core/forms/widgets.py +3 -2
- nautobot/core/graphql/__init__.py +8 -26
- nautobot/core/graphql/generators.py +16 -6
- nautobot/core/graphql/schema.py +1 -1
- nautobot/core/graphql/schema_init.py +1 -2
- nautobot/core/graphql/utils.py +7 -9
- nautobot/core/jobs/__init__.py +158 -0
- nautobot/core/management/commands/generate_test_data.py +28 -9
- nautobot/core/models/__init__.py +17 -2
- nautobot/core/models/fields.py +3 -2
- nautobot/core/models/generics.py +9 -1
- nautobot/core/models/name_color_content_types.py +1 -1
- nautobot/core/models/ordering.py +7 -5
- nautobot/core/models/querysets.py +77 -2
- nautobot/core/models/tree_queries.py +6 -4
- nautobot/core/settings.py +30 -16
- nautobot/core/settings.yaml +13 -7
- nautobot/core/tables.py +114 -44
- nautobot/core/templates/403.html +1 -1
- nautobot/core/templates/403_csrf_failure.html +1 -1
- nautobot/core/templates/404.html +1 -1
- nautobot/core/templates/40x.html +8 -8
- nautobot/core/templates/500.html +10 -10
- nautobot/core/templates/about.html +13 -12
- nautobot/core/templates/admin/actions.html +1 -1
- nautobot/core/templates/admin/app_index.html +3 -3
- nautobot/core/templates/admin/base.html +45 -52
- nautobot/core/templates/admin/base_site.html +0 -9
- nautobot/core/templates/admin/change_form.html +5 -5
- nautobot/core/templates/admin/change_list.html +8 -12
- nautobot/core/templates/admin/change_list_results.html +3 -3
- nautobot/core/templates/admin/config/config.html +24 -24
- nautobot/core/templates/admin/delete_confirmation.html +5 -5
- nautobot/core/templates/admin/edit_inline/stacked.html +5 -5
- nautobot/core/templates/admin/edit_inline/tabular.html +3 -3
- nautobot/core/templates/admin/includes/fieldset.html +15 -15
- nautobot/core/templates/admin/index.html +8 -8
- nautobot/core/templates/admin/submit_line.html +5 -5
- nautobot/core/templates/base_django.html +36 -32
- nautobot/core/templates/buttons/add.html +1 -1
- nautobot/core/templates/buttons/consolidated_detail_view_action_buttons.html +2 -2
- nautobot/core/templates/buttons/export.html +17 -18
- nautobot/core/templates/buttons/job_import.html +2 -2
- nautobot/core/templates/components/breadcrumbs.html +19 -17
- nautobot/core/templates/components/button/dropdown.html +7 -5
- nautobot/core/templates/components/echarts.html +2 -0
- nautobot/core/templates/components/layout/one_over_two.html +3 -3
- nautobot/core/templates/components/layout/two_over_one.html +3 -3
- nautobot/core/templates/components/panel/body_content_data_table.html +2 -2
- nautobot/core/templates/components/panel/body_content_tags.html +1 -1
- nautobot/core/templates/components/panel/body_wrapper_generic.html +4 -2
- nautobot/core/templates/components/panel/body_wrapper_generic_table.html +1 -1
- nautobot/core/templates/components/panel/body_wrapper_key_value_table.html +5 -3
- nautobot/core/templates/components/panel/body_wrapper_table.html +4 -2
- nautobot/core/templates/components/panel/footer_contacts_table.html +4 -4
- nautobot/core/templates/components/panel/footer_content_table.html +3 -3
- nautobot/core/templates/components/panel/grouping_toggle.html +12 -11
- nautobot/core/templates/components/panel/header_extra_content_table.html +2 -11
- nautobot/core/templates/components/panel/panel.html +6 -3
- nautobot/core/templates/components/panel/stats_panel_body.html +9 -7
- nautobot/core/templates/components/tab/content_wrapper.html +29 -1
- nautobot/core/templates/components/tab/label_wrapper.html +10 -2
- nautobot/core/templates/components/tab/label_wrapper_distinct_view.html +11 -4
- nautobot/core/templates/echarts/echarts.html +20 -0
- nautobot/core/templates/exceptions/import_error.html +2 -2
- nautobot/core/templates/exceptions/permission_error.html +1 -1
- nautobot/core/templates/exceptions/programming_error.html +2 -2
- nautobot/core/templates/generic/object_bulk_add_component.html +29 -20
- nautobot/core/templates/generic/object_bulk_create.html +87 -75
- nautobot/core/templates/generic/object_bulk_destroy.html +35 -37
- nautobot/core/templates/generic/object_bulk_remove.html +30 -26
- nautobot/core/templates/generic/object_bulk_rename.html +53 -40
- nautobot/core/templates/generic/object_bulk_update.html +36 -29
- nautobot/core/templates/generic/object_create.html +40 -27
- nautobot/core/templates/generic/object_import.html +36 -24
- nautobot/core/templates/generic/object_list.html +279 -215
- nautobot/core/templates/generic/object_notes.html +21 -11
- nautobot/core/templates/generic/object_retrieve.html +161 -213
- nautobot/core/templates/graphene/graphiql.html +113 -60
- nautobot/core/templates/home.html +164 -87
- nautobot/core/templates/import_success.html +3 -2
- nautobot/core/templates/inc/ajax_loader.html +1 -1
- nautobot/core/templates/inc/computed_fields/panel_data.html +25 -13
- nautobot/core/templates/inc/created_updated.html +12 -7
- nautobot/core/templates/inc/custom_fields/panel_data.html +28 -16
- nautobot/core/templates/inc/custom_fields_panel.html +3 -3
- nautobot/core/templates/inc/dynamic_groups_panel.html +3 -3
- nautobot/core/templates/inc/extras_features_edit_form_fields.html +15 -15
- nautobot/core/templates/inc/footer.html +90 -40
- nautobot/core/templates/inc/form_static_field.html +6 -0
- nautobot/core/templates/inc/header.html +75 -0
- nautobot/core/templates/inc/header_banners.html +17 -0
- nautobot/core/templates/inc/header_messages.html +6 -0
- nautobot/core/templates/inc/image_attachments.html +9 -9
- nautobot/core/templates/inc/javascript.html +7 -24
- nautobot/core/templates/inc/media.html +4 -29
- nautobot/core/templates/inc/modal.html +2 -2
- nautobot/core/templates/inc/nav_favorites.html +27 -0
- nautobot/core/templates/inc/nav_menu.html +150 -108
- nautobot/core/templates/inc/object_details_advanced_panel.html +84 -71
- nautobot/core/templates/inc/page_title.html +23 -0
- nautobot/core/templates/inc/paginator.html +39 -28
- nautobot/core/templates/inc/relationships/panel_override.html +3 -3
- nautobot/core/templates/inc/relationships_panel.html +3 -3
- nautobot/core/templates/inc/relationships_table_rows.html +1 -1
- nautobot/core/templates/inc/search_panel.html +22 -16
- nautobot/core/templates/inc/table.html +61 -36
- nautobot/core/templates/inc/tenancy_form_panel.html +3 -3
- nautobot/core/templates/login.html +17 -59
- nautobot/core/templates/modals/modal_theme.html +12 -23
- nautobot/core/templates/nautobot_config.py.j2 +6 -5
- nautobot/core/templates/panel_table.html +8 -12
- nautobot/core/templates/redoc_ui.html +80 -0
- nautobot/core/templates/rest_framework/api.html +43 -21
- nautobot/core/templates/search.html +12 -13
- nautobot/core/templates/swagger_ui.html +19 -4
- nautobot/core/templates/system_jobs/import_objects.html +70 -58
- nautobot/core/templates/template.css +0 -6
- nautobot/core/templates/utilities/comment_form.html +34 -0
- nautobot/core/templates/utilities/confirmation_form.html +17 -9
- nautobot/core/templates/utilities/obj_table.html +19 -11
- nautobot/core/templates/utilities/render_field.html +27 -21
- nautobot/core/templates/utilities/render_jinja2.html +22 -25
- nautobot/core/templates/utilities/templatetags/advanced_filter_indicator.html +8 -0
- nautobot/core/templates/utilities/templatetags/badge.html +1 -1
- nautobot/core/templates/utilities/templatetags/dynamic_group_assignment_modal.html +2 -3
- nautobot/core/templates/utilities/templatetags/filter_form_drawer.html +482 -0
- nautobot/core/templates/utilities/templatetags/modal_form_as_dialog.html +14 -18
- nautobot/core/templates/utilities/templatetags/saved_view_modal.html +11 -11
- nautobot/core/templates/utilities/templatetags/table_config_form.html +51 -24
- nautobot/core/templates/utilities/templatetags/tag.html +1 -1
- nautobot/core/templates/utilities/templatetags/utilization_graph.html +3 -3
- nautobot/core/templates/utilities/theme_preview.html +829 -566
- nautobot/core/templates/utilities/worker_status.html +42 -41
- nautobot/core/templates/widgets/selectwithdisabled_option.html +3 -1
- nautobot/core/templates/widgets/sluginput.html +2 -2
- nautobot/core/templatetags/buttons.py +38 -40
- nautobot/core/templatetags/helpers.py +105 -28
- nautobot/core/templatetags/ui_framework.py +17 -0
- nautobot/core/testing/api.py +76 -12
- nautobot/core/testing/filters.py +11 -27
- nautobot/core/testing/integration.py +128 -10
- nautobot/core/testing/mixins.py +7 -4
- nautobot/core/testing/utils.py +28 -5
- nautobot/core/testing/views.py +125 -27
- nautobot/core/tests/integration/test_app_home.py +39 -35
- nautobot/core/tests/integration/test_app_navbar.py +60 -67
- nautobot/core/tests/integration/test_filters.py +123 -55
- nautobot/core/tests/integration/test_general_functionality.py +1 -1
- nautobot/core/tests/integration/test_home.py +10 -18
- nautobot/core/tests/integration/test_import_objects_ui.py +2 -9
- nautobot/core/tests/integration/test_navbar.py +41 -16
- nautobot/core/tests/integration/test_swagger.py +1 -7
- nautobot/core/tests/integration/test_theme.py +3 -0
- nautobot/core/tests/nautobot_config_without_example_apps.py +4 -0
- nautobot/core/tests/runner.py +6 -1
- nautobot/core/tests/test_api.py +5 -3
- nautobot/core/tests/test_branching.py +154 -0
- nautobot/core/tests/test_breadcrumbs.py +7 -8
- nautobot/core/tests/test_checks.py +28 -0
- nautobot/core/tests/test_commands.py +0 -41
- nautobot/core/tests/test_config.py +2 -1
- nautobot/core/tests/test_csv.py +4 -7
- nautobot/core/tests/test_filters.py +326 -318
- nautobot/core/tests/test_forms.py +19 -30
- nautobot/core/tests/test_graphql.py +67 -57
- nautobot/core/tests/test_models.py +1 -1
- nautobot/core/tests/test_nautobot_server.py +2 -0
- nautobot/core/tests/test_navigations.py +78 -10
- nautobot/core/tests/test_tables.py +3 -1
- nautobot/core/tests/test_templatetags_helpers.py +61 -21
- nautobot/core/tests/test_templatetags_ui_framework.py +36 -18
- nautobot/core/tests/test_ui.py +207 -2
- nautobot/core/tests/test_utils.py +147 -2
- nautobot/core/tests/test_views.py +201 -64
- nautobot/core/tests/test_views_utils.py +1 -1
- nautobot/core/ui/breadcrumbs.py +2 -12
- nautobot/core/ui/choices.py +190 -0
- nautobot/core/ui/constants.py +86 -0
- nautobot/core/ui/echarts.py +474 -0
- nautobot/core/ui/nav.py +5 -1
- nautobot/core/ui/object_detail.py +180 -16
- nautobot/core/urls.py +13 -1
- nautobot/core/utils/cache.py +71 -0
- nautobot/core/utils/data.py +8 -5
- nautobot/core/utils/filtering.py +8 -2
- nautobot/core/utils/git.py +3 -3
- nautobot/core/utils/lookup.py +87 -13
- nautobot/core/utils/migrations.py +22 -0
- nautobot/core/utils/module_loading.py +26 -0
- nautobot/core/utils/permissions.py +9 -5
- nautobot/core/views/__init__.py +114 -63
- nautobot/core/views/generic.py +34 -27
- nautobot/core/views/mixins.py +49 -27
- nautobot/core/views/renderers.py +3 -5
- nautobot/core/views/utils.py +10 -5
- nautobot/core/views/viewsets.py +2 -1
- nautobot/data_validation/__init__.py +0 -0
- nautobot/data_validation/api/__init__.py +1 -0
- nautobot/data_validation/api/serializers.py +80 -0
- nautobot/data_validation/api/urls.py +20 -0
- nautobot/data_validation/api/views.py +44 -0
- nautobot/data_validation/apps.py +18 -0
- nautobot/data_validation/custom_validators.py +330 -0
- nautobot/data_validation/filters.py +133 -0
- nautobot/data_validation/form_mixin.py +25 -0
- nautobot/data_validation/forms.py +342 -0
- nautobot/data_validation/migrations/0001_initial.py +224 -0
- nautobot/data_validation/migrations/0002_data_migration_from_app.py +324 -0
- nautobot/data_validation/migrations/__init__.py +0 -0
- nautobot/data_validation/models.py +361 -0
- nautobot/data_validation/navigation.py +74 -0
- nautobot/data_validation/signals.py +30 -0
- nautobot/data_validation/tables.py +259 -0
- nautobot/data_validation/templates/data_validation/datacompliance_retrieve.html +1 -0
- nautobot/data_validation/templates/data_validation/datacompliance_tab.html +11 -0
- nautobot/data_validation/templates/data_validation/device_constraints.html +61 -0
- nautobot/data_validation/tests/__init__.py +20 -0
- nautobot/data_validation/tests/migrations/__init__.py +0 -0
- nautobot/data_validation/tests/migrations/test_migrations.py +489 -0
- nautobot/data_validation/tests/test_api.py +238 -0
- nautobot/data_validation/tests/test_custom_validators.py +423 -0
- nautobot/data_validation/tests/test_data_compliance_rules.py +85 -0
- nautobot/data_validation/tests/test_filters.py +240 -0
- nautobot/data_validation/tests/test_form_mixin.py +115 -0
- nautobot/data_validation/tests/test_models.py +393 -0
- nautobot/data_validation/tests/test_views.py +435 -0
- nautobot/data_validation/urls.py +21 -0
- nautobot/data_validation/views.py +227 -0
- nautobot/dcim/api/serializers.py +10 -13
- nautobot/dcim/api/urls.py +2 -0
- nautobot/dcim/api/views.py +7 -0
- 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} +70 -157
- nautobot/dcim/forms.py +12 -6
- nautobot/dcim/graphql/types.py +1 -0
- nautobot/dcim/migrations/0075_add_deviceclusterassignment.py +52 -0
- nautobot/dcim/migrations/0076_device_cluster_to_clusters_data_migration.py +40 -0
- nautobot/dcim/migrations/0077_remove_device_cluster.py +14 -0
- 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/__init__.py +2 -0
- nautobot/dcim/models/device_components.py +3 -1
- nautobot/dcim/models/devices.py +115 -51
- nautobot/dcim/navigation.py +7 -3
- nautobot/dcim/querysets.py +6 -0
- nautobot/dcim/signals.py +19 -0
- nautobot/dcim/tables/devices.py +9 -5
- nautobot/dcim/tables/template_code.py +191 -102
- nautobot/dcim/templates/dcim/cable.html +1 -1
- nautobot/dcim/templates/dcim/cable_connect.html +62 -146
- nautobot/dcim/templates/dcim/cable_retrieve.html +10 -10
- nautobot/dcim/templates/dcim/cable_trace.html +15 -17
- nautobot/dcim/templates/dcim/console_port_connection_list.html +2 -2
- nautobot/dcim/templates/dcim/consoleport.html +18 -17
- nautobot/dcim/templates/dcim/consoleserverport.html +18 -17
- nautobot/dcim/templates/dcim/controller_create.html +12 -8
- nautobot/dcim/templates/dcim/controller_wirelessnetworks.html +1 -1
- nautobot/dcim/templates/dcim/controllermanageddevicegroup_create.html +6 -6
- nautobot/dcim/templates/dcim/controllermanageddevicegroup_retrieve.html +1 -1
- nautobot/dcim/templates/dcim/device/config.html +17 -19
- nautobot/dcim/templates/dcim/device/lldp_neighbors.html +4 -4
- nautobot/dcim/templates/dcim/device/status.html +20 -20
- nautobot/dcim/templates/dcim/device_component_add.html +24 -15
- nautobot/dcim/templates/dcim/device_create.html +120 -120
- nautobot/dcim/templates/dcim/device_list.html +75 -12
- nautobot/dcim/templates/dcim/devicebay.html +7 -7
- nautobot/dcim/templates/dcim/devicebay_populate.html +29 -23
- nautobot/dcim/templates/dcim/deviceredundancygroup_create.html +6 -6
- nautobot/dcim/templates/dcim/devicetype.html +1 -1
- nautobot/dcim/templates/dcim/devicetype_component_add.html +25 -19
- nautobot/dcim/templates/dcim/devicetype_list.html +4 -4
- nautobot/dcim/templates/dcim/devicetype_update.html +9 -9
- nautobot/dcim/templates/dcim/footer_convert_to_contact_or_team_record.html +3 -3
- nautobot/dcim/templates/dcim/frontport.html +21 -20
- nautobot/dcim/templates/dcim/inc/cable_form.html +7 -7
- nautobot/dcim/templates/dcim/inc/cable_termination.html +1 -1
- nautobot/dcim/templates/dcim/inc/cable_toggle_buttons.html +18 -9
- nautobot/dcim/templates/dcim/inc/detail_softwareversion_softwareimagefile_rows.html +1 -1
- nautobot/dcim/templates/dcim/inc/device_interface_filter.html +1 -1
- nautobot/dcim/templates/dcim/inc/devicetype_component_table.html +10 -10
- nautobot/dcim/templates/dcim/inc/edit_form_softwareversion_js.html +2 -2
- nautobot/dcim/templates/dcim/inc/homepage_connections.html +2 -2
- nautobot/dcim/templates/dcim/inc/moduletype_component_table.html +10 -10
- nautobot/dcim/templates/dcim/inc/rack_elevation.html +2 -2
- nautobot/dcim/templates/dcim/interface.html +42 -22
- nautobot/dcim/templates/dcim/interface_connection_list.html +2 -2
- nautobot/dcim/templates/dcim/interface_edit.html +26 -11
- nautobot/dcim/templates/dcim/interfaceredundancygroupassociation_create.html +3 -3
- nautobot/dcim/templates/dcim/inventoryitem.html +3 -3
- nautobot/dcim/templates/dcim/inventoryitem_add.html +21 -10
- nautobot/dcim/templates/dcim/inventoryitem_bulk_delete.html +1 -1
- nautobot/dcim/templates/dcim/inventoryitem_edit.html +6 -4
- nautobot/dcim/templates/dcim/location.html +1 -1
- nautobot/dcim/templates/dcim/location_migrate_data_to_contact.html +24 -18
- nautobot/dcim/templates/dcim/location_retrieve.html +1 -1
- nautobot/dcim/templates/dcim/location_update.html +9 -9
- nautobot/dcim/templates/dcim/locationtype.html +0 -1
- nautobot/dcim/templates/dcim/module/base.html +67 -27
- nautobot/dcim/templates/dcim/module_consoleports.html +13 -15
- nautobot/dcim/templates/dcim/module_consoleserverports.html +13 -15
- nautobot/dcim/templates/dcim/module_frontports.html +13 -15
- nautobot/dcim/templates/dcim/module_interfaces.html +14 -16
- nautobot/dcim/templates/dcim/module_list.html +59 -10
- nautobot/dcim/templates/dcim/module_modulebays.html +12 -14
- nautobot/dcim/templates/dcim/module_poweroutlets.html +13 -15
- nautobot/dcim/templates/dcim/module_powerports.html +13 -15
- nautobot/dcim/templates/dcim/module_rearports.html +13 -15
- nautobot/dcim/templates/dcim/module_retrieve.html +3 -3
- nautobot/dcim/templates/dcim/module_update.html +15 -9
- nautobot/dcim/templates/dcim/modulebay_retrieve.html +0 -93
- nautobot/dcim/templates/dcim/modulefamily_retrieve.html +7 -7
- nautobot/dcim/templates/dcim/moduletype_list.html +2 -2
- nautobot/dcim/templates/dcim/moduletype_retrieve.html +74 -35
- nautobot/dcim/templates/dcim/platform_create.html +9 -9
- nautobot/dcim/templates/dcim/power_port_connection_list.html +3 -3
- nautobot/dcim/templates/dcim/powerfeed.html +1 -1
- nautobot/dcim/templates/dcim/powerfeed_edit.html +15 -15
- nautobot/dcim/templates/dcim/poweroutlet.html +13 -13
- nautobot/dcim/templates/dcim/powerpanel.html +1 -1
- nautobot/dcim/templates/dcim/powerport.html +17 -16
- nautobot/dcim/templates/dcim/rack.html +1 -1
- nautobot/dcim/templates/dcim/rack_elevation.html +2 -2
- nautobot/dcim/templates/dcim/rack_elevation_list.html +21 -9
- nautobot/dcim/templates/dcim/rack_retrieve.html +75 -57
- nautobot/dcim/templates/dcim/rack_update.html +14 -14
- nautobot/dcim/templates/dcim/rackreservation.html +1 -1
- nautobot/dcim/templates/dcim/rackreservation_edit.html +6 -6
- nautobot/dcim/templates/dcim/rearport.html +19 -18
- nautobot/dcim/templates/dcim/trace/cable.html +1 -1
- nautobot/dcim/templates/dcim/trace/circuit.html +1 -1
- nautobot/dcim/templates/dcim/trace/device.html +1 -1
- nautobot/dcim/templates/dcim/trace/powerpanel.html +1 -1
- nautobot/dcim/templates/dcim/trace/termination.html +1 -1
- nautobot/dcim/templates/dcim/virtualchassis.html +1 -1
- nautobot/dcim/templates/dcim/virtualchassis_add_member.html +25 -16
- nautobot/dcim/templates/dcim/virtualchassis_create.html +6 -6
- nautobot/dcim/templates/dcim/virtualchassis_edit.html +1 -1
- nautobot/dcim/templates/dcim/virtualchassis_retrieve.html +1 -1
- nautobot/dcim/templates/dcim/virtualchassis_update.html +36 -22
- nautobot/dcim/templates/dcim/virtualdevicecontext_update.html +9 -9
- nautobot/dcim/tests/integration/test_controller.py +6 -6
- nautobot/dcim/tests/integration/test_controller_managed_device_group.py +7 -7
- nautobot/dcim/tests/integration/test_create_device.py +9 -9
- nautobot/dcim/tests/integration/test_device_bulk_operations.py +7 -2
- nautobot/dcim/tests/integration/test_fileinputpicker.py +5 -7
- nautobot/dcim/tests/integration/test_location_bulk_operations.py +2 -0
- nautobot/dcim/tests/integration/test_module_bay_position.py +4 -1
- nautobot/dcim/tests/test_api.py +86 -6
- nautobot/dcim/tests/test_custom_validators.py +229 -0
- nautobot/dcim/tests/test_filters.py +159 -110
- nautobot/dcim/tests/test_graphql.py +32 -36
- nautobot/dcim/tests/test_jobs.py +1 -1
- nautobot/dcim/tests/test_models.py +229 -1
- nautobot/dcim/tests/test_views.py +31 -20
- nautobot/dcim/utils.py +3 -3
- nautobot/dcim/views.py +77 -41
- nautobot/extras/api/serializers.py +83 -19
- nautobot/extras/api/urls.py +7 -0
- nautobot/extras/api/views.py +243 -140
- nautobot/extras/choices.py +34 -13
- nautobot/extras/constants.py +1 -1
- nautobot/extras/context_managers.py +26 -26
- nautobot/extras/datasources/git.py +22 -0
- nautobot/extras/datasources/registry.py +3 -0
- nautobot/extras/exceptions.py +5 -0
- nautobot/extras/factory.py +11 -1
- nautobot/extras/{filters/mixins.py → filter_mixins.py} +4 -3
- nautobot/extras/{filters/__init__.py → filters.py} +203 -58
- nautobot/extras/forms/base.py +2 -1
- nautobot/extras/forms/forms.py +225 -20
- nautobot/extras/forms/mixins.py +0 -41
- nautobot/extras/homepage.py +21 -2
- nautobot/extras/jobs.py +2 -8
- nautobot/extras/jobs_ui.py +2 -2
- nautobot/extras/management/__init__.py +9 -0
- nautobot/extras/managers.py +31 -22
- nautobot/extras/migrations/0126_approval_workflow_pre_check.py +58 -0
- nautobot/extras/migrations/0127_approval_workflow_models.py +266 -0
- nautobot/extras/migrations/0128_remove_job_approval_required_and_more.py +29 -0
- 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 +14 -3
- nautobot/extras/models/approvals.py +556 -0
- nautobot/extras/models/change_logging.py +1 -0
- nautobot/extras/models/contacts.py +2 -0
- nautobot/extras/models/customfields.py +57 -22
- nautobot/extras/models/datasources.py +21 -0
- nautobot/extras/models/groups.py +2 -0
- nautobot/extras/models/jobs.py +122 -39
- nautobot/extras/models/metadata.py +2 -3
- nautobot/extras/models/mixins.py +129 -1
- nautobot/extras/models/models.py +22 -14
- nautobot/extras/models/relationships.py +47 -10
- nautobot/extras/models/secrets.py +1 -0
- nautobot/extras/models/statuses.py +0 -15
- nautobot/extras/models/tags.py +1 -1
- nautobot/extras/navigation.py +42 -15
- nautobot/extras/plugins/__init__.py +33 -55
- nautobot/extras/plugins/marketplace_manifest.yml +1 -23
- nautobot/extras/plugins/tables.py +8 -6
- nautobot/extras/plugins/urls.py +2 -21
- nautobot/extras/plugins/utils.py +1 -33
- nautobot/extras/plugins/validators.py +10 -10
- nautobot/extras/plugins/views.py +1 -5
- nautobot/extras/querysets.py +17 -21
- nautobot/extras/signals.py +23 -8
- nautobot/extras/tables.py +420 -99
- nautobot/extras/templates/extras/approval_dashboard.html +15 -0
- nautobot/extras/templates/extras/approval_workflow/approve.html +11 -0
- nautobot/extras/templates/extras/approval_workflow/comment.html +9 -0
- nautobot/extras/templates/extras/approval_workflow/deny.html +10 -0
- nautobot/extras/templates/extras/approvalworkflowdefinition_update.html +77 -0
- nautobot/extras/templates/extras/approvalworkflowstage_retrieve.html +29 -0
- nautobot/extras/templates/extras/configcontext_update.html +12 -12
- nautobot/extras/templates/extras/configcontextschema.html +1 -1
- nautobot/extras/templates/extras/configcontextschema_retrieve.html +9 -9
- nautobot/extras/templates/extras/configcontextschema_update.html +6 -6
- nautobot/extras/templates/extras/configcontextschema_validation.html +2 -2
- nautobot/extras/templates/extras/customfield_update.html +12 -12
- nautobot/extras/templates/extras/dynamicgroup.html +1 -1
- nautobot/extras/templates/extras/dynamicgroup_edit.html +1 -1
- nautobot/extras/templates/extras/dynamicgroup_retrieve.html +17 -17
- nautobot/extras/templates/extras/dynamicgroup_update.html +24 -24
- nautobot/extras/templates/extras/externalintegration_update.html +6 -6
- nautobot/extras/templates/extras/gitrepository.html +1 -1
- nautobot/extras/templates/extras/gitrepository_object_edit.html +1 -1
- nautobot/extras/templates/extras/gitrepository_result.html +1 -1
- nautobot/extras/templates/extras/gitrepository_retrieve.html +12 -12
- nautobot/extras/templates/extras/gitrepository_update.html +25 -7
- nautobot/extras/templates/extras/graphqlquery_retrieve.html +1 -1
- nautobot/extras/templates/extras/inc/approval_buttons_column.html +38 -0
- nautobot/extras/templates/extras/inc/bulk_edit_overridable_field.html +14 -13
- nautobot/extras/templates/extras/inc/configcontext_format.html +11 -4
- nautobot/extras/templates/extras/inc/graphqlquery_execute.html +7 -7
- nautobot/extras/templates/extras/inc/job_label.html +5 -5
- nautobot/extras/templates/extras/inc/job_table.html +23 -10
- nautobot/extras/templates/extras/inc/job_tiles.html +33 -21
- nautobot/extras/templates/extras/inc/jobresult.html +6 -6
- nautobot/extras/templates/extras/inc/json_format.html +11 -4
- nautobot/extras/templates/extras/inc/object_contact_header.html +6 -6
- nautobot/extras/templates/extras/inc/overridable_field.html +16 -15
- nautobot/extras/templates/extras/inc/panel_approvalworkflowstage.html +34 -0
- nautobot/extras/templates/extras/inc/panel_changelog.html +9 -9
- nautobot/extras/templates/extras/inc/panel_jobhistory.html +8 -6
- nautobot/extras/templates/extras/inc/tags_panel.html +3 -3
- nautobot/extras/templates/extras/job.html +154 -155
- nautobot/extras/templates/extras/job_approval_confirmation.html +4 -27
- nautobot/extras/templates/extras/job_bulk_edit.html +18 -1
- nautobot/extras/templates/extras/job_detail.html +1 -1
- nautobot/extras/templates/extras/job_edit.html +69 -64
- nautobot/extras/templates/extras/job_list.html +37 -60
- nautobot/extras/templates/extras/jobresult.html +1 -1
- nautobot/extras/templates/extras/jobresult_retrieve.html +17 -17
- nautobot/extras/templates/extras/marketplace.html +62 -71
- nautobot/extras/templates/extras/metadatatype_create.html +9 -9
- nautobot/extras/templates/extras/note.html +1 -1
- nautobot/extras/templates/extras/object_approvalworkflow.html +36 -0
- nautobot/extras/templates/extras/object_assign_contact_or_team.html +16 -7
- nautobot/extras/templates/extras/object_configcontext.html +20 -20
- nautobot/extras/templates/extras/object_new_contact.html +6 -6
- nautobot/extras/templates/extras/object_new_team.html +6 -6
- nautobot/extras/templates/extras/objectchange.html +1 -1
- nautobot/extras/templates/extras/objectchange_retrieve.html +37 -56
- nautobot/extras/templates/extras/plugin_detail.html +40 -41
- nautobot/extras/templates/extras/plugins_list.html +23 -38
- nautobot/extras/templates/extras/plugins_tiles.html +28 -28
- nautobot/extras/templates/extras/role_retrieve.html +112 -48
- nautobot/extras/templates/extras/scheduledjob.html +25 -28
- nautobot/extras/templates/extras/secret_create.html +11 -11
- nautobot/extras/templates/extras/secretsgroup_update.html +6 -6
- nautobot/extras/templates/extras/staticgroupassociation_retrieve.html +3 -3
- nautobot/extras/templates/extras/status.html +1 -1
- nautobot/extras/templates/extras/tag.html +1 -1
- nautobot/extras/templates/extras/tag_update.html +3 -3
- nautobot/extras/templates/extras/templatetags/log_level.html +1 -1
- nautobot/extras/templates/extras/templatetags/plugin_object_detail_tabs.html +2 -2
- nautobot/extras/templates/extras/webhook.html +12 -12
- nautobot/extras/templatetags/approvals.py +19 -0
- 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_computedfields.py +5 -8
- nautobot/extras/tests/integration/test_configcontextschema.py +43 -48
- nautobot/extras/tests/integration/test_customfields.py +33 -33
- nautobot/extras/tests/integration/test_dynamicgroups.py +5 -10
- nautobot/extras/tests/integration/test_jobs.py +2 -4
- nautobot/extras/tests/integration/test_notes.py +3 -9
- nautobot/extras/tests/integration/test_plugin_banner.py +3 -0
- nautobot/extras/tests/integration/test_plugins.py +35 -27
- nautobot/extras/tests/integration/test_relationships.py +7 -11
- nautobot/extras/tests/integration/test_tagfilter.py +3 -11
- nautobot/extras/tests/test_api.py +786 -242
- nautobot/extras/tests/test_approvals.py +715 -0
- nautobot/extras/tests/test_changelog.py +18 -14
- nautobot/extras/tests/test_customfields.py +14 -13
- nautobot/extras/tests/test_datasources.py +1 -1
- nautobot/extras/tests/test_dynamicgroups.py +9 -4
- nautobot/extras/tests/test_filters.py +443 -13
- nautobot/extras/tests/test_forms.py +18 -57
- nautobot/extras/tests/test_jobs.py +25 -4
- nautobot/extras/tests/test_migrations.py +81 -1
- nautobot/extras/tests/test_models.py +378 -47
- nautobot/extras/tests/test_plugins.py +47 -13
- nautobot/extras/tests/test_relationships.py +7 -2
- nautobot/extras/tests/test_utils.py +2 -0
- nautobot/extras/tests/test_views.py +780 -493
- nautobot/extras/urls.py +36 -12
- nautobot/extras/utils.py +58 -12
- nautobot/extras/views.py +668 -209
- nautobot/ipam/factory.py +7 -0
- nautobot/ipam/filter_mixins.py +38 -0
- nautobot/ipam/filters.py +35 -71
- 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 -1
- nautobot/ipam/querysets.py +1 -2
- nautobot/ipam/tables.py +26 -17
- nautobot/ipam/templates/ipam/inc/ipadress_edit_header.html +6 -6
- nautobot/ipam/templates/ipam/inc/service.html +8 -8
- nautobot/ipam/templates/ipam/inc/toggle_available.html +10 -10
- nautobot/ipam/templates/ipam/inc/vlangroup_header.html +3 -2
- nautobot/ipam/templates/ipam/ipaddress.html +27 -13
- nautobot/ipam/templates/ipam/ipaddress_assign.html +31 -24
- nautobot/ipam/templates/ipam/ipaddress_bulk_add.html +3 -3
- nautobot/ipam/templates/ipam/ipaddress_edit.html +9 -9
- nautobot/ipam/templates/ipam/ipaddress_interfaces.html +7 -9
- nautobot/ipam/templates/ipam/ipaddress_merge.html +195 -186
- nautobot/ipam/templates/ipam/ipaddress_vm_interfaces.html +7 -9
- nautobot/ipam/templates/ipam/ipaddresstointerface_retrieve.html +7 -5
- nautobot/ipam/templates/ipam/namespace_ip_addresses.html +1 -1
- nautobot/ipam/templates/ipam/namespace_prefixes.html +1 -1
- nautobot/ipam/templates/ipam/namespace_update.html +15 -0
- nautobot/ipam/templates/ipam/namespace_vrfs.html +1 -1
- nautobot/ipam/templates/ipam/prefix_create.html +9 -9
- nautobot/ipam/templates/ipam/prefix_list.html +15 -14
- nautobot/ipam/templates/ipam/prefix_retrieve.html +0 -1
- nautobot/ipam/templates/ipam/vlan.html +1 -1
- nautobot/ipam/templates/ipam/vlan_interfaces.html +1 -1
- nautobot/ipam/templates/ipam/vlan_update.html +6 -6
- nautobot/ipam/templates/ipam/vlan_vminterfaces.html +1 -1
- nautobot/ipam/templates/ipam/vrf_edit.html +15 -15
- nautobot/ipam/tests/integration/test_prefixes.py +5 -13
- nautobot/ipam/tests/migration/test_migrations.py +89 -0
- nautobot/ipam/tests/test_api.py +20 -7
- nautobot/ipam/tests/test_filters.py +10 -0
- nautobot/ipam/tests/test_forms.py +1 -1
- nautobot/ipam/tests/test_models.py +1 -1
- nautobot/ipam/tests/test_tables.py +1 -2
- nautobot/ipam/tests/test_utils.py +1 -1
- nautobot/ipam/tests/test_views.py +24 -21
- nautobot/ipam/ui.py +0 -17
- nautobot/ipam/utils/migrations.py +16 -2
- nautobot/ipam/utils/testing.py +9 -3
- nautobot/ipam/views.py +49 -7
- nautobot/project-static/dist/css/graphql-libraries.css +655 -0
- nautobot/project-static/dist/css/graphql-libraries.css.map +1 -0
- nautobot/project-static/dist/css/materialdesignicons.css +3 -0
- nautobot/project-static/dist/css/materialdesignicons.css.map +1 -0
- nautobot/project-static/dist/css/nautobot.css +13 -0
- nautobot/project-static/dist/css/nautobot.css.map +1 -0
- nautobot/project-static/dist/js/graphql-libraries.js +3 -0
- nautobot/project-static/dist/js/graphql-libraries.js.LICENSE.txt +62 -0
- nautobot/project-static/dist/js/graphql-libraries.js.map +1 -0
- nautobot/project-static/dist/js/libraries.js +3 -0
- nautobot/project-static/dist/js/libraries.js.LICENSE.txt +65 -0
- nautobot/project-static/dist/js/libraries.js.map +1 -0
- nautobot/project-static/dist/js/materialdesignicons.js +0 -0
- nautobot/project-static/dist/js/nautobot-graphiql.js +2 -0
- nautobot/project-static/dist/js/nautobot-graphiql.js.map +1 -0
- nautobot/project-static/dist/js/nautobot.js +2 -0
- nautobot/project-static/dist/js/nautobot.js.map +1 -0
- nautobot/project-static/fonts/Montserrat-v30-Bold.woff2 +0 -0
- nautobot/project-static/fonts/Montserrat-v30-Light.woff2 +0 -0
- nautobot/project-static/fonts/Montserrat-v30-Regular.woff2 +0 -0
- nautobot/project-static/fonts/Roboto-v48-Bold.woff2 +0 -0
- nautobot/project-static/fonts/Roboto-v48-Light.woff2 +0 -0
- nautobot/project-static/fonts/Roboto-v48-Regular.woff2 +0 -0
- nautobot/project-static/img/jinja_logo.svg +21 -92
- nautobot/project-static/js/cabletrace.js +1 -1
- nautobot/project-static/js/editor.js +4 -4
- nautobot/project-static/js/forms.js +67 -717
- nautobot/project-static/js/job_result.js +2 -2
- nautobot/project-static/nautobot-icons/360-degrees.svg +3 -0
- nautobot/project-static/nautobot-icons/arrow-decision.svg +3 -0
- nautobot/project-static/nautobot-icons/arrows-expand-rec.svg +3 -0
- nautobot/project-static/nautobot-icons/arrows-move-2-rec.svg +3 -0
- nautobot/project-static/nautobot-icons/arrows-move-rec.svg +3 -0
- nautobot/project-static/nautobot-icons/atom.svg +3 -0
- nautobot/project-static/nautobot-icons/battery-3.svg +3 -0
- nautobot/project-static/nautobot-icons/branch.svg +3 -0
- nautobot/project-static/nautobot-icons/briefcase-2.svg +3 -0
- nautobot/project-static/nautobot-icons/cable-data-2.svg +3 -0
- nautobot/project-static/nautobot-icons/cable-data.svg +3 -0
- nautobot/project-static/nautobot-icons/cast.svg +3 -0
- nautobot/project-static/nautobot-icons/check-circle.svg +3 -0
- nautobot/project-static/nautobot-icons/checkbox-circle.svg +3 -0
- nautobot/project-static/nautobot-icons/checkbox-rec.svg +3 -0
- nautobot/project-static/nautobot-icons/cloud-check.svg +3 -0
- nautobot/project-static/nautobot-icons/cloud-lightning.svg +3 -0
- nautobot/project-static/nautobot-icons/cloud-upload.svg +3 -0
- nautobot/project-static/nautobot-icons/cloud.svg +3 -0
- nautobot/project-static/nautobot-icons/compass.svg +3 -0
- nautobot/project-static/nautobot-icons/control-panel.svg +3 -0
- nautobot/project-static/nautobot-icons/credit-card.svg +3 -0
- nautobot/project-static/nautobot-icons/device-lifecycle.svg +3 -0
- nautobot/project-static/nautobot-icons/direction.svg +3 -0
- nautobot/project-static/nautobot-icons/elements.svg +3 -0
- nautobot/project-static/nautobot-icons/extensibility.svg +3 -0
- nautobot/project-static/nautobot-icons/globe-2.svg +3 -0
- nautobot/project-static/nautobot-icons/globe.svg +3 -0
- nautobot/project-static/nautobot-icons/hammer.svg +3 -0
- nautobot/project-static/nautobot-icons/history.svg +3 -0
- nautobot/project-static/nautobot-icons/ip.svg +3 -0
- nautobot/project-static/nautobot-icons/laptop.svg +3 -0
- nautobot/project-static/nautobot-icons/lightning.svg +3 -0
- nautobot/project-static/nautobot-icons/list-unordered.svg +3 -0
- nautobot/project-static/nautobot-icons/map-view.svg +3 -0
- nautobot/project-static/nautobot-icons/organization.svg +3 -0
- nautobot/project-static/nautobot-icons/pin-2.svg +3 -0
- nautobot/project-static/nautobot-icons/pin-3.svg +3 -0
- nautobot/project-static/nautobot-icons/plug.svg +3 -0
- nautobot/project-static/nautobot-icons/refresh-cw.svg +3 -0
- nautobot/project-static/nautobot-icons/rocket-2.svg +3 -0
- nautobot/project-static/nautobot-icons/rotate-cw.svg +3 -0
- nautobot/project-static/nautobot-icons/route.svg +3 -0
- nautobot/project-static/nautobot-icons/secrets.svg +3 -0
- nautobot/project-static/nautobot-icons/security.svg +3 -0
- nautobot/project-static/nautobot-icons/server-2.svg +3 -0
- nautobot/project-static/nautobot-icons/server.svg +3 -0
- nautobot/project-static/nautobot-icons/share.svg +3 -0
- nautobot/project-static/nautobot-icons/shield-check.svg +3 -0
- nautobot/project-static/nautobot-icons/sitemap-outline.svg +3 -0
- nautobot/project-static/nautobot-icons/sliders-vert-2.svg +3 -0
- nautobot/project-static/nautobot-icons/sliders-vert.svg +3 -0
- nautobot/project-static/nautobot-icons/star-filled.svg +3 -0
- nautobot/project-static/nautobot-icons/star.svg +3 -0
- nautobot/project-static/nautobot-icons/transform.svg +3 -0
- nautobot/project-static/nautobot-icons/wifi.svg +3 -0
- 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/templates/tenancy/tenant_create.html +6 -6
- nautobot/tenancy/tests/test_filters.py +0 -2
- nautobot/tenancy/views.py +2 -1
- nautobot/ui/.gitignore +137 -0
- nautobot/ui/.node-version +1 -0
- nautobot/ui/.prettierignore +3 -0
- nautobot/ui/eslint.config.js +33 -0
- nautobot/ui/package-lock.json +6594 -0
- nautobot/ui/package.json +67 -0
- nautobot/ui/prettier.config.js +9 -0
- nautobot/ui/src/js/collapse.js +69 -0
- nautobot/ui/src/js/cookie.js +31 -0
- nautobot/ui/src/js/draggable.js +101 -0
- nautobot/ui/src/js/drawer.js +106 -0
- nautobot/ui/src/js/form.js +23 -0
- nautobot/ui/src/js/history.js +51 -0
- nautobot/ui/src/js/nautobot-graphiql.js +19 -0
- nautobot/ui/src/js/nautobot.js +128 -0
- nautobot/ui/src/js/search.js +274 -0
- nautobot/ui/src/js/select2.js +318 -0
- nautobot/ui/src/js/sidenav.js +87 -0
- nautobot/ui/src/js/tabs.js +139 -0
- nautobot/ui/src/js/theme.js +104 -0
- nautobot/ui/src/js/utils.js +54 -0
- nautobot/ui/src/scss/colors.scss +58 -0
- nautobot/ui/src/scss/nautobot.scss +2471 -0
- nautobot/ui/webpack.config.js +148 -0
- nautobot/users/apps.py +3 -0
- nautobot/users/filters.py +7 -11
- nautobot/users/forms.py +10 -0
- nautobot/users/models.py +8 -0
- nautobot/users/templates/users/advanced_settings_edit.html +31 -21
- nautobot/users/templates/users/api_tokens.html +61 -51
- nautobot/users/templates/users/base.html +23 -31
- nautobot/users/templates/users/change_password.html +29 -19
- nautobot/users/templates/users/preferences.html +55 -45
- nautobot/users/templates/users/profile.html +45 -14
- nautobot/users/tests/test_api.py +4 -0
- nautobot/users/urls.py +2 -0
- nautobot/users/views.py +70 -2
- nautobot/virtualization/api/views.py +1 -1
- nautobot/virtualization/filters.py +18 -32
- nautobot/virtualization/forms.py +22 -59
- nautobot/virtualization/models.py +1 -19
- nautobot/virtualization/navigation.py +3 -1
- nautobot/virtualization/tables.py +10 -6
- nautobot/virtualization/templates/virtualization/cluster.html +13 -13
- nautobot/virtualization/templates/virtualization/cluster_edit.html +6 -6
- nautobot/virtualization/templates/virtualization/inc/virtualmachine_vminterface_filter.html +1 -1
- nautobot/virtualization/templates/virtualization/virtualmachine.html +1 -1
- nautobot/virtualization/templates/virtualization/virtualmachine_component_add.html +24 -16
- nautobot/virtualization/templates/virtualization/virtualmachine_edit.html +1 -1
- nautobot/virtualization/templates/virtualization/virtualmachine_list.html +4 -4
- nautobot/virtualization/templates/virtualization/virtualmachine_update.html +27 -25
- nautobot/virtualization/templates/virtualization/vminterface.html +5 -5
- nautobot/virtualization/templates/virtualization/vminterface_edit.html +27 -11
- nautobot/virtualization/tests/test_api.py +3 -0
- nautobot/virtualization/tests/test_models.py +20 -5
- nautobot/virtualization/tests/test_views.py +3 -5
- nautobot/virtualization/urls.py +0 -11
- nautobot/virtualization/views.py +5 -122
- 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/filters.py +0 -8
- nautobot/wireless/navigation.py +3 -1
- nautobot/wireless/templates/wireless/wirelessnetwork_create.html +6 -6
- nautobot/wireless/tests/integration/test_radio_profile.py +3 -7
- nautobot/wireless/tests/test_api.py +1 -1
- {nautobot-2.4.21.dist-info → nautobot-3.0.0a3.dist-info}/METADATA +5 -4
- {nautobot-2.4.21.dist-info → nautobot-3.0.0a3.dist-info}/RECORD +802 -707
- {nautobot-2.4.21.dist-info → nautobot-3.0.0a3.dist-info}/entry_points.txt +1 -0
- nautobot/core/management/commands/check_job_approval_status.py +0 -47
- nautobot/core/templates/search_form.html +0 -9
- nautobot/core/templates/utilities/templatetags/filter_form_modal.html +0 -87
- nautobot/dcim/filters/mixins.py +0 -354
- nautobot/extras/templates/extras/job_approval_request.html +0 -134
- nautobot/extras/templates/extras/scheduled_jobs_approval_queue_list.html +0 -28
- nautobot/ipam/mixins.py +0 -32
- nautobot/ipam/templates/ipam/inc/prefix_header_extra_content_table.html +0 -4
- nautobot/project-static/bootstrap-3.4.1-dist/css/bootstrap-theme.css +0 -587
- nautobot/project-static/bootstrap-3.4.1-dist/css/bootstrap-theme.css.map +0 -1
- nautobot/project-static/bootstrap-3.4.1-dist/css/bootstrap-theme.min.css +0 -6
- nautobot/project-static/bootstrap-3.4.1-dist/css/bootstrap-theme.min.css.map +0 -1
- nautobot/project-static/bootstrap-3.4.1-dist/css/bootstrap.css +0 -6865
- nautobot/project-static/bootstrap-3.4.1-dist/css/bootstrap.css.map +0 -1
- nautobot/project-static/bootstrap-3.4.1-dist/css/bootstrap.min.css +0 -6
- nautobot/project-static/bootstrap-3.4.1-dist/css/bootstrap.min.css.map +0 -1
- nautobot/project-static/bootstrap-3.4.1-dist/fonts/glyphicons-halflings-regular.eot +0 -0
- nautobot/project-static/bootstrap-3.4.1-dist/fonts/glyphicons-halflings-regular.svg +0 -288
- nautobot/project-static/bootstrap-3.4.1-dist/fonts/glyphicons-halflings-regular.ttf +0 -0
- nautobot/project-static/bootstrap-3.4.1-dist/fonts/glyphicons-halflings-regular.woff +0 -0
- nautobot/project-static/bootstrap-3.4.1-dist/fonts/glyphicons-halflings-regular.woff2 +0 -0
- nautobot/project-static/bootstrap-3.4.1-dist/js/bootstrap.js +0 -2580
- nautobot/project-static/bootstrap-3.4.1-dist/js/bootstrap.min.js +0 -6
- nautobot/project-static/bootstrap-3.4.1-dist/js/npm.js +0 -13
- nautobot/project-static/clipboard.js-2.0.9/clipboard.min.js +0 -7
- nautobot/project-static/css/base.css +0 -1040
- nautobot/project-static/css/dark.css +0 -282
- nautobot/project-static/flatpickr-4.6.9/flatpickr.min.js +0 -2
- nautobot/project-static/flatpickr-4.6.9/themes/light.min.css +0 -1
- nautobot/project-static/graphiql-1.5.16/graphiql.min.css +0 -12
- nautobot/project-static/graphiql-1.5.16/graphiql.min.js +0 -11
- nautobot/project-static/highlight.js-11.9.0/github-dark.min.css +0 -10
- nautobot/project-static/highlight.js-11.9.0/github.min.css +0 -10
- nautobot/project-static/highlight.js-11.9.0/highlight.min.js +0 -378
- nautobot/project-static/jquery/jquery-3.7.1.min.js +0 -2
- nautobot/project-static/jquery-ui-1.13.2/images/ui-icons_444444_256x240.png +0 -0
- nautobot/project-static/jquery-ui-1.13.2/images/ui-icons_555555_256x240.png +0 -0
- nautobot/project-static/jquery-ui-1.13.2/images/ui-icons_777620_256x240.png +0 -0
- nautobot/project-static/jquery-ui-1.13.2/images/ui-icons_777777_256x240.png +0 -0
- nautobot/project-static/jquery-ui-1.13.2/images/ui-icons_cc0000_256x240.png +0 -0
- nautobot/project-static/jquery-ui-1.13.2/images/ui-icons_ffffff_256x240.png +0 -0
- nautobot/project-static/jquery-ui-1.13.2/jquery-ui.min.css +0 -7
- nautobot/project-static/jquery-ui-1.13.2/jquery-ui.min.js +0 -6
- nautobot/project-static/jquery-ui-1.13.2/jquery-ui.structure.min.css +0 -5
- nautobot/project-static/jquery-ui-1.13.2/jquery-ui.theme.min.css +0 -5
- nautobot/project-static/js/homepage_layout.js +0 -182
- nautobot/project-static/js/nav_menu.js +0 -250
- nautobot/project-static/js/theme.js +0 -133
- nautobot/project-static/materialdesignicons-7.4.47/LICENSE +0 -20
- nautobot/project-static/materialdesignicons-7.4.47/css/materialdesignicons.min.css +0 -3
- nautobot/project-static/react-16.14.0/react.production.min.js +0 -32
- nautobot/project-static/react-dom-16.14.0/react-dom.production.min.js +0 -239
- nautobot/project-static/select2-4.0.13/i18n/af.js +0 -3
- nautobot/project-static/select2-4.0.13/i18n/ar.js +0 -3
- nautobot/project-static/select2-4.0.13/i18n/az.js +0 -3
- nautobot/project-static/select2-4.0.13/i18n/bg.js +0 -3
- nautobot/project-static/select2-4.0.13/i18n/bn.js +0 -3
- nautobot/project-static/select2-4.0.13/i18n/bs.js +0 -3
- nautobot/project-static/select2-4.0.13/i18n/ca.js +0 -3
- nautobot/project-static/select2-4.0.13/i18n/cs.js +0 -3
- nautobot/project-static/select2-4.0.13/i18n/da.js +0 -3
- nautobot/project-static/select2-4.0.13/i18n/de.js +0 -3
- nautobot/project-static/select2-4.0.13/i18n/dsb.js +0 -3
- nautobot/project-static/select2-4.0.13/i18n/el.js +0 -3
- nautobot/project-static/select2-4.0.13/i18n/en.js +0 -3
- nautobot/project-static/select2-4.0.13/i18n/es.js +0 -3
- nautobot/project-static/select2-4.0.13/i18n/et.js +0 -3
- nautobot/project-static/select2-4.0.13/i18n/eu.js +0 -3
- nautobot/project-static/select2-4.0.13/i18n/fa.js +0 -3
- nautobot/project-static/select2-4.0.13/i18n/fi.js +0 -3
- nautobot/project-static/select2-4.0.13/i18n/fr.js +0 -3
- nautobot/project-static/select2-4.0.13/i18n/gl.js +0 -3
- nautobot/project-static/select2-4.0.13/i18n/he.js +0 -3
- nautobot/project-static/select2-4.0.13/i18n/hi.js +0 -3
- nautobot/project-static/select2-4.0.13/i18n/hr.js +0 -3
- nautobot/project-static/select2-4.0.13/i18n/hsb.js +0 -3
- nautobot/project-static/select2-4.0.13/i18n/hu.js +0 -3
- nautobot/project-static/select2-4.0.13/i18n/hy.js +0 -3
- nautobot/project-static/select2-4.0.13/i18n/id.js +0 -3
- nautobot/project-static/select2-4.0.13/i18n/is.js +0 -3
- nautobot/project-static/select2-4.0.13/i18n/it.js +0 -3
- nautobot/project-static/select2-4.0.13/i18n/ja.js +0 -3
- nautobot/project-static/select2-4.0.13/i18n/ka.js +0 -3
- nautobot/project-static/select2-4.0.13/i18n/km.js +0 -3
- nautobot/project-static/select2-4.0.13/i18n/ko.js +0 -3
- nautobot/project-static/select2-4.0.13/i18n/lt.js +0 -3
- nautobot/project-static/select2-4.0.13/i18n/lv.js +0 -3
- nautobot/project-static/select2-4.0.13/i18n/mk.js +0 -3
- nautobot/project-static/select2-4.0.13/i18n/ms.js +0 -3
- nautobot/project-static/select2-4.0.13/i18n/nb.js +0 -3
- nautobot/project-static/select2-4.0.13/i18n/ne.js +0 -3
- nautobot/project-static/select2-4.0.13/i18n/nl.js +0 -3
- nautobot/project-static/select2-4.0.13/i18n/pl.js +0 -3
- nautobot/project-static/select2-4.0.13/i18n/ps.js +0 -3
- nautobot/project-static/select2-4.0.13/i18n/pt-BR.js +0 -3
- nautobot/project-static/select2-4.0.13/i18n/pt.js +0 -3
- nautobot/project-static/select2-4.0.13/i18n/ro.js +0 -3
- nautobot/project-static/select2-4.0.13/i18n/ru.js +0 -3
- nautobot/project-static/select2-4.0.13/i18n/sk.js +0 -3
- nautobot/project-static/select2-4.0.13/i18n/sl.js +0 -3
- nautobot/project-static/select2-4.0.13/i18n/sq.js +0 -3
- nautobot/project-static/select2-4.0.13/i18n/sr-Cyrl.js +0 -3
- nautobot/project-static/select2-4.0.13/i18n/sr.js +0 -3
- nautobot/project-static/select2-4.0.13/i18n/sv.js +0 -3
- nautobot/project-static/select2-4.0.13/i18n/th.js +0 -3
- nautobot/project-static/select2-4.0.13/i18n/tk.js +0 -3
- nautobot/project-static/select2-4.0.13/i18n/tr.js +0 -3
- nautobot/project-static/select2-4.0.13/i18n/uk.js +0 -3
- nautobot/project-static/select2-4.0.13/i18n/vi.js +0 -3
- nautobot/project-static/select2-4.0.13/i18n/zh-CN.js +0 -3
- nautobot/project-static/select2-4.0.13/i18n/zh-TW.js +0 -3
- nautobot/project-static/select2-4.0.13/select2.min.css +0 -1
- nautobot/project-static/select2-4.0.13/select2.min.js +0 -2
- nautobot/project-static/select2-bootstrap-0.1.0-beta.10/select2-bootstrap.min.css +0 -7
- nautobot/project-static/subscriptions-transport-ws-0.9.18/client.min.js +0 -8
- nautobot/project-static/whatwg-fetch-3.6.2/fetch.umd.min.js +0 -8
- nautobot/virtualization/templates/virtualization/cluster_add_devices.html +0 -37
- /nautobot/extras/{filters/customfields.py → filter_mixins_customfields.py} +0 -0
- /nautobot/project-static/{materialdesignicons-7.4.47/fonts/materialdesignicons-webfont.ttf → dist/1fcc36272ea3e53d0031.ttf} +0 -0
- /nautobot/project-static/{materialdesignicons-7.4.47/fonts/materialdesignicons-webfont.eot → dist/2146c3c82b553977abc7.eot} +0 -0
- /nautobot/project-static/{materialdesignicons-7.4.47/fonts/materialdesignicons-webfont.woff → dist/e55a20c80650829ec5fd.woff} +0 -0
- /nautobot/project-static/{materialdesignicons-7.4.47/fonts/materialdesignicons-webfont.woff2 → dist/ec024da790d2972da002.woff2} +0 -0
- /nautobot/tenancy/{filters/mixins.py → filter_mixins.py} +0 -0
- {nautobot-2.4.21.dist-info → nautobot-3.0.0a3.dist-info}/LICENSE.txt +0 -0
- {nautobot-2.4.21.dist-info → nautobot-3.0.0a3.dist-info}/NOTICE +0 -0
- {nautobot-2.4.21.dist-info → nautobot-3.0.0a3.dist-info}/WHEEL +0 -0
nautobot/core/api/views.py
CHANGED
|
@@ -23,10 +23,11 @@ from drf_spectacular.utils import extend_schema
|
|
|
23
23
|
from drf_spectacular.views import SpectacularAPIView, SpectacularRedocView, SpectacularSwaggerView
|
|
24
24
|
from graphene_django.settings import graphene_settings
|
|
25
25
|
from graphene_django.views import GraphQLView, HttpError, instantiate_middleware
|
|
26
|
-
from graphql import
|
|
26
|
+
from graphql import execute, get_operation_ast, OperationType, parse, validate_schema
|
|
27
27
|
from graphql.execution import ExecutionResult
|
|
28
28
|
from graphql.execution.middleware import MiddlewareManager
|
|
29
29
|
from graphql.type.schema import GraphQLSchema
|
|
30
|
+
from graphql.validation import validate
|
|
30
31
|
import redis.exceptions
|
|
31
32
|
from rest_framework import routers, serializers as drf_serializers, status
|
|
32
33
|
from rest_framework.exceptions import APIException, ParseError, PermissionDenied
|
|
@@ -440,6 +441,10 @@ class APIRootView(AuthenticatedAPIRootView):
|
|
|
440
441
|
"cloud",
|
|
441
442
|
reverse("cloud-api:api-root", request=request, format=format),
|
|
442
443
|
),
|
|
444
|
+
(
|
|
445
|
+
"data-validation",
|
|
446
|
+
reverse("data_validation-api:api-root", request=request, format=format),
|
|
447
|
+
),
|
|
443
448
|
(
|
|
444
449
|
"dcim",
|
|
445
450
|
reverse("dcim-api:api-root", request=request, format=format),
|
|
@@ -474,6 +479,14 @@ class APIRootView(AuthenticatedAPIRootView):
|
|
|
474
479
|
format=format,
|
|
475
480
|
),
|
|
476
481
|
),
|
|
482
|
+
(
|
|
483
|
+
"vpn",
|
|
484
|
+
reverse(
|
|
485
|
+
"vpn-api:api-root",
|
|
486
|
+
request=request,
|
|
487
|
+
format=format,
|
|
488
|
+
),
|
|
489
|
+
),
|
|
477
490
|
(
|
|
478
491
|
"wireless",
|
|
479
492
|
reverse(
|
|
@@ -606,12 +619,15 @@ class NautobotSpectacularSwaggerView(APIVersioningGetSchemaURLMixin, Spectacular
|
|
|
606
619
|
|
|
607
620
|
# Add additional data so drf-spectacular will use the Token keyword in authorization header.
|
|
608
621
|
response.data["schema_auth_names"] = ["tokenAuth"]
|
|
622
|
+
|
|
609
623
|
return response
|
|
610
624
|
|
|
611
625
|
|
|
612
626
|
class NautobotSpectacularRedocView(APIVersioningGetSchemaURLMixin, SpectacularRedocView):
|
|
613
627
|
"""Extend SpectacularRedocView to support Nautobot's ?api_version=<version> query parameter."""
|
|
614
628
|
|
|
629
|
+
template_name = "redoc_ui.html"
|
|
630
|
+
|
|
615
631
|
|
|
616
632
|
@method_decorator(gzip_page, name="dispatch")
|
|
617
633
|
class NautobotSpectacularAPIView(SpectacularAPIView):
|
|
@@ -662,18 +678,25 @@ class GraphQLDRFAPIView(NautobotAPIVersionMixin, APIView):
|
|
|
662
678
|
# https://github.com/graphql-python/graphene-django/blob/main/graphene_django/views.py#L57
|
|
663
679
|
|
|
664
680
|
permission_classes = [IsAuthenticated]
|
|
665
|
-
|
|
666
|
-
executor = None
|
|
667
|
-
backend = None
|
|
681
|
+
execution_context_class = None
|
|
668
682
|
middleware = None
|
|
669
683
|
root_value = None
|
|
670
|
-
|
|
671
|
-
|
|
684
|
+
validation_rules = None
|
|
685
|
+
|
|
686
|
+
def __init__(
|
|
687
|
+
self,
|
|
688
|
+
schema=None,
|
|
689
|
+
execution_context_class=None,
|
|
690
|
+
middleware=None,
|
|
691
|
+
root_value=None,
|
|
692
|
+
validation_rules=None,
|
|
693
|
+
**kwargs,
|
|
694
|
+
):
|
|
672
695
|
self.schema = schema
|
|
673
|
-
self.
|
|
696
|
+
self.execution_context_class = execution_context_class
|
|
674
697
|
self.middleware = middleware
|
|
675
698
|
self.root_value = root_value
|
|
676
|
-
self.
|
|
699
|
+
self.validation_rules = validation_rules
|
|
677
700
|
super().__init__(**kwargs)
|
|
678
701
|
|
|
679
702
|
def get_root_value(self, request):
|
|
@@ -685,9 +708,6 @@ class GraphQLDRFAPIView(NautobotAPIVersionMixin, APIView):
|
|
|
685
708
|
def get_context(self, request):
|
|
686
709
|
return request
|
|
687
710
|
|
|
688
|
-
def get_backend(self, request):
|
|
689
|
-
return self.backend
|
|
690
|
-
|
|
691
711
|
@extend_schema(
|
|
692
712
|
request=serializers.GraphQLAPISerializer,
|
|
693
713
|
description="Query the database using a GraphQL query",
|
|
@@ -719,21 +739,16 @@ class GraphQLDRFAPIView(NautobotAPIVersionMixin, APIView):
|
|
|
719
739
|
if not self.schema:
|
|
720
740
|
self.schema = graphene_settings.SCHEMA
|
|
721
741
|
|
|
722
|
-
if self.backend is None:
|
|
723
|
-
self.backend = get_default_backend()
|
|
724
|
-
|
|
725
|
-
self.graphql_schema = self.graphql_schema or self.schema
|
|
726
|
-
|
|
727
742
|
if self.middleware is not None:
|
|
728
743
|
if isinstance(self.middleware, MiddlewareManager):
|
|
729
744
|
self.middleware = graphene_settings.MIDDLEWARE
|
|
730
745
|
else:
|
|
731
746
|
self.middleware = list(instantiate_middleware(self.middleware))
|
|
732
747
|
|
|
733
|
-
self.
|
|
748
|
+
self.execution_context_class = self.execution_context_class
|
|
734
749
|
self.root_value = self.root_value
|
|
735
750
|
|
|
736
|
-
if not isinstance(self.graphql_schema, GraphQLSchema):
|
|
751
|
+
if not isinstance(self.schema.graphql_schema, GraphQLSchema):
|
|
737
752
|
raise ValueError("A Schema is required to be provided to GraphQLAPIView.")
|
|
738
753
|
|
|
739
754
|
def get_response(self, request, data):
|
|
@@ -757,7 +772,7 @@ class GraphQLDRFAPIView(NautobotAPIVersionMixin, APIView):
|
|
|
757
772
|
if execution_result.errors:
|
|
758
773
|
response["errors"] = [GraphQLView.format_error(e) for e in execution_result.errors]
|
|
759
774
|
|
|
760
|
-
if execution_result.
|
|
775
|
+
if execution_result.errors and any(not getattr(e, "path", None) for e in execution_result.errors):
|
|
761
776
|
status_code = 400
|
|
762
777
|
else:
|
|
763
778
|
response["data"] = execution_result.data
|
|
@@ -809,38 +824,44 @@ class GraphQLDRFAPIView(NautobotAPIVersionMixin, APIView):
|
|
|
809
824
|
if not query:
|
|
810
825
|
raise HttpError(HttpResponseBadRequest("Must provide query string."))
|
|
811
826
|
|
|
827
|
+
schema = self.schema.graphql_schema
|
|
828
|
+
|
|
829
|
+
schema_validation_errors = validate_schema(schema)
|
|
830
|
+
if schema_validation_errors:
|
|
831
|
+
return ExecutionResult(data=None, errors=schema_validation_errors)
|
|
832
|
+
|
|
812
833
|
try:
|
|
813
|
-
|
|
814
|
-
document = backend.document_from_string(self.graphql_schema, query)
|
|
834
|
+
document = parse(query)
|
|
815
835
|
except Exception as e:
|
|
816
|
-
return ExecutionResult(errors=[e]
|
|
836
|
+
return ExecutionResult(errors=[e])
|
|
837
|
+
|
|
838
|
+
operation_ast = get_operation_ast(document, operation_name)
|
|
817
839
|
|
|
818
|
-
|
|
819
|
-
if operation_type and operation_type != "query":
|
|
840
|
+
if operation_ast is not None and operation_ast.operation != OperationType.QUERY:
|
|
820
841
|
raise HttpError(
|
|
821
|
-
HttpResponseBadRequest(
|
|
842
|
+
HttpResponseBadRequest(
|
|
843
|
+
f"'{operation_ast.operation}' is not a supported operation, Only query are supported."
|
|
844
|
+
)
|
|
822
845
|
)
|
|
823
846
|
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
# We only include it optionally since
|
|
828
|
-
# executor is not a valid argument in all backends
|
|
829
|
-
extra_options["executor"] = self.executor
|
|
847
|
+
validation_errors = validate(schema, document, self.validation_rules, graphene_settings.MAX_VALIDATION_ERRORS)
|
|
848
|
+
if validation_errors:
|
|
849
|
+
return ExecutionResult(data=None, errors=validation_errors)
|
|
830
850
|
|
|
831
|
-
|
|
851
|
+
try:
|
|
852
|
+
execute_options = {
|
|
832
853
|
"root_value": self.get_root_value(request),
|
|
854
|
+
"context_value": self.get_context(request),
|
|
833
855
|
"variable_values": variables,
|
|
834
856
|
"operation_name": operation_name,
|
|
835
|
-
"context_value": self.get_context(request),
|
|
836
857
|
"middleware": self.get_middleware(request),
|
|
837
858
|
}
|
|
838
|
-
|
|
859
|
+
if self.execution_context_class:
|
|
860
|
+
execute_options["execution_context_class"] = self.execution_context_class
|
|
839
861
|
|
|
840
|
-
|
|
841
|
-
return document.execute(**options)
|
|
862
|
+
return execute(schema=schema, document=document, **execute_options)
|
|
842
863
|
except Exception as e:
|
|
843
|
-
return ExecutionResult(errors=[e]
|
|
864
|
+
return ExecutionResult(errors=[e])
|
|
844
865
|
|
|
845
866
|
|
|
846
867
|
#
|
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,6 +30,7 @@ from nautobot.core.ui.nav import ( # isort: skip # noqa: F401
|
|
|
31
30
|
NavMenuTab,
|
|
32
31
|
NAV_CONTEXT_NAMES,
|
|
33
32
|
)
|
|
33
|
+
from nautobot.core.utils.module_loading import import_string_optional
|
|
34
34
|
from nautobot.core.utils.patch_social_django import patch_django_storage
|
|
35
35
|
from nautobot.extras.registry import registry
|
|
36
36
|
|
|
@@ -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):
|
|
@@ -334,9 +328,9 @@ class CoreConfig(NautobotConfig):
|
|
|
334
328
|
# Register in django_jinja
|
|
335
329
|
library.filter(name=name, fn=func)
|
|
336
330
|
|
|
331
|
+
from graphene.types.scalars import BigInt
|
|
337
332
|
from graphene_django.converter import convert_django_field
|
|
338
333
|
|
|
339
|
-
from nautobot.core.graphql import BigInteger
|
|
340
334
|
import nautobot.core.jobs # noqa: F401 # unused-import -- but this import registers the system jobs
|
|
341
335
|
|
|
342
336
|
@convert_django_field.register(JSONField)
|
|
@@ -351,8 +345,8 @@ class CoreConfig(NautobotConfig):
|
|
|
351
345
|
|
|
352
346
|
@convert_django_field.register(BigIntegerField)
|
|
353
347
|
def convert_biginteger(field, registry=None): # pylint: disable=redefined-outer-name
|
|
354
|
-
"""Convert BigIntegerField to
|
|
355
|
-
return
|
|
348
|
+
"""Convert BigIntegerField to BigInt scalar."""
|
|
349
|
+
return BigInt()
|
|
356
350
|
|
|
357
351
|
from django.conf import settings
|
|
358
352
|
from django.contrib.auth.models import update_last_login
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
|
|
3
|
+
from django.conf import settings
|
|
4
|
+
from django.db import connections
|
|
5
|
+
|
|
6
|
+
LOGGER = logging.getLogger(__name__)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class BranchContext:
|
|
10
|
+
def __init__(self, branch_name=None, using=None, user=None, autocommit=True):
|
|
11
|
+
"""
|
|
12
|
+
Instantiate a BranchContext context manager.
|
|
13
|
+
|
|
14
|
+
Example:
|
|
15
|
+
with BranchContext(branch_name="my-branch", user=request.user):
|
|
16
|
+
...
|
|
17
|
+
|
|
18
|
+
Args:
|
|
19
|
+
branch_name (str): The Dolt branch name (if any) to potentially switch to.
|
|
20
|
+
If left as the default `None`, this context manager does nothing, allowing it to be safely used in
|
|
21
|
+
code that can execute in a non-version-controlled Nautobot deployment as well.
|
|
22
|
+
using (str, list[str]): The database connection alias(es) to potentially switch to the specified branch.
|
|
23
|
+
Note it can be a *list* of connections, or a single connection alias string like most Django built-ins.
|
|
24
|
+
If omitted, only the `"default"` connection will be used.
|
|
25
|
+
user (User): The user account to associate with any Dolt Commit created when using `autocommit=True`.
|
|
26
|
+
autocommit (bool): Whether to create an automatic Dolt Commit record when exiting this context.
|
|
27
|
+
"""
|
|
28
|
+
self.branch_name = branch_name
|
|
29
|
+
if not using:
|
|
30
|
+
self.using = ["default"]
|
|
31
|
+
elif isinstance(using, str):
|
|
32
|
+
self.using = [using]
|
|
33
|
+
else:
|
|
34
|
+
self.using = using
|
|
35
|
+
self.user = user
|
|
36
|
+
self.autocommit = autocommit
|
|
37
|
+
|
|
38
|
+
self.cursors = {}
|
|
39
|
+
self.original_branches = {}
|
|
40
|
+
self.auto_dolt_commit = None
|
|
41
|
+
|
|
42
|
+
def __enter__(self):
|
|
43
|
+
if self.branch_name is None or "nautobot_version_control" not in settings.PLUGINS:
|
|
44
|
+
if self.branch_name is not None:
|
|
45
|
+
LOGGER.warning(
|
|
46
|
+
"nautobot_version_control is not installed, ignoring requested branch %s", self.branch_name
|
|
47
|
+
)
|
|
48
|
+
return
|
|
49
|
+
|
|
50
|
+
from nautobot_version_control.utils import active_branch, checkout_branch # pylint: disable=import-error
|
|
51
|
+
|
|
52
|
+
for using in self.using:
|
|
53
|
+
self.cursors[using] = connections[using].cursor()
|
|
54
|
+
self.cursors[using].__enter__()
|
|
55
|
+
self.original_branches[using] = active_branch(using=using)
|
|
56
|
+
|
|
57
|
+
if self.branch_name != self.original_branches[using]:
|
|
58
|
+
LOGGER.info("Switching connection %r to branch %r", using, self.branch_name)
|
|
59
|
+
|
|
60
|
+
checkout_branch(self.branch_name, using=using)
|
|
61
|
+
|
|
62
|
+
if self.autocommit:
|
|
63
|
+
from nautobot_version_control.middleware import AutoDoltCommit # pylint: disable=import-error
|
|
64
|
+
|
|
65
|
+
self.auto_dolt_commit = AutoDoltCommit(user=self.user)
|
|
66
|
+
self.auto_dolt_commit.__enter__()
|
|
67
|
+
|
|
68
|
+
def __exit__(self, exc_type, exc_value, traceback):
|
|
69
|
+
if self.branch_name is None or "nautobot_version_control" not in settings.PLUGINS:
|
|
70
|
+
return
|
|
71
|
+
|
|
72
|
+
if self.autocommit:
|
|
73
|
+
self.auto_dolt_commit.__exit__(exc_type, exc_value, traceback)
|
|
74
|
+
|
|
75
|
+
for using in self.using:
|
|
76
|
+
if self.branch_name != self.original_branches[using]:
|
|
77
|
+
from nautobot_version_control.utils import checkout_branch # pylint: disable=import-error
|
|
78
|
+
|
|
79
|
+
checkout_branch(self.original_branches[using], using=using)
|
|
80
|
+
|
|
81
|
+
LOGGER.info("Returned connection %r to branch %r", using, self.original_branches[using])
|
|
82
|
+
|
|
83
|
+
self.cursors[using].__exit__(exc_type, exc_value, traceback)
|
nautobot/core/celery/__init__.py
CHANGED
|
@@ -12,16 +12,15 @@ 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
|
|
|
19
18
|
from nautobot import add_failure_logger, add_success_logger
|
|
19
|
+
from nautobot.core.branching import BranchContext
|
|
20
20
|
from nautobot.core.celery.control import discard_git_repository, refresh_git_repository # noqa: F401 # unused-import
|
|
21
21
|
from nautobot.core.celery.encoders import NautobotKombuJSONEncoder
|
|
22
22
|
from nautobot.core.celery.log import NautobotDatabaseHandler
|
|
23
|
-
from nautobot.core.utils.module_loading import import_modules_privately
|
|
24
|
-
from nautobot.extras.plugins.utils import import_object
|
|
23
|
+
from nautobot.core.utils.module_loading import import_modules_privately, import_string_optional
|
|
25
24
|
from nautobot.extras.registry import registry
|
|
26
25
|
|
|
27
26
|
logger = logging.getLogger(__name__)
|
|
@@ -139,7 +138,7 @@ def _import_dynamic_jobs_from_apps():
|
|
|
139
138
|
del sys.modules[job.__module__]
|
|
140
139
|
|
|
141
140
|
# Load app jobs
|
|
142
|
-
app_config.features["jobs"] =
|
|
141
|
+
app_config.features["jobs"] = import_string_optional(f"{app_config.__module__}.{app_config.jobs}")
|
|
143
142
|
|
|
144
143
|
|
|
145
144
|
def add_nautobot_log_handler(logger_instance, log_format=None):
|
|
@@ -217,10 +216,16 @@ def nautobot_kombu_json_loads_hook(data):
|
|
|
217
216
|
"""
|
|
218
217
|
if "__nautobot_type__" in data:
|
|
219
218
|
qual_name = data.pop("__nautobot_type__")
|
|
219
|
+
branch_name = data.pop("__nautobot_branch__", None)
|
|
220
220
|
logger.debug("Performing nautobot deserialization for type %s", qual_name)
|
|
221
|
-
cls =
|
|
221
|
+
cls = import_string_optional(qual_name) # fully qualified dotted import path
|
|
222
222
|
if cls:
|
|
223
|
-
|
|
223
|
+
|
|
224
|
+
def get_object():
|
|
225
|
+
with BranchContext(branch_name=branch_name, autocommit=False):
|
|
226
|
+
return cls.objects.get(id=data["id"])
|
|
227
|
+
|
|
228
|
+
return SimpleLazyObject(get_object)
|
|
224
229
|
else:
|
|
225
230
|
raise TypeError(f"Unable to import {qual_name} during nautobot deserialization")
|
|
226
231
|
else:
|
nautobot/core/celery/backends.py
CHANGED
|
@@ -29,6 +29,7 @@ class NautobotDatabaseBackend(DatabaseBackend):
|
|
|
29
29
|
"task_args": None,
|
|
30
30
|
"task_kwargs": None,
|
|
31
31
|
"celery_kwargs": None,
|
|
32
|
+
"branch_name": None,
|
|
32
33
|
"job_model_id": None,
|
|
33
34
|
"scheduled_job_id": None,
|
|
34
35
|
"task_name": None,
|
|
@@ -67,6 +68,7 @@ class NautobotDatabaseBackend(DatabaseBackend):
|
|
|
67
68
|
"task_args": task_args,
|
|
68
69
|
"task_kwargs": task_kwargs,
|
|
69
70
|
"celery_kwargs": celery_kwargs,
|
|
71
|
+
"branch_name": properties.get("nautobot_job_branch_name", None),
|
|
70
72
|
"job_model_id": properties.get("nautobot_job_job_model_id", None),
|
|
71
73
|
"scheduled_job_id": properties.get("nautobot_job_scheduled_job_id", None),
|
|
72
74
|
"task_name": task_name,
|
nautobot/core/celery/encoders.py
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import logging
|
|
2
2
|
from zoneinfo import ZoneInfo
|
|
3
3
|
|
|
4
|
+
from django.conf import settings
|
|
4
5
|
from django.db import models
|
|
5
6
|
from rest_framework.utils.encoders import JSONEncoder
|
|
6
7
|
|
|
@@ -41,6 +42,12 @@ class NautobotKombuJSONEncoder(JSONEncoder):
|
|
|
41
42
|
# TODO: change to natural key to provide additional context if object is deleted from the db
|
|
42
43
|
"display": getattr(obj, "display", str(obj)),
|
|
43
44
|
}
|
|
45
|
+
|
|
46
|
+
if "nautobot_version_control" in settings.PLUGINS:
|
|
47
|
+
from nautobot_version_control.utils import active_branch # pylint: disable=import-error
|
|
48
|
+
|
|
49
|
+
data["__nautobot_branch__"] = active_branch()
|
|
50
|
+
|
|
44
51
|
return data
|
|
45
52
|
|
|
46
53
|
elif isinstance(obj, set):
|
nautobot/core/celery/task.py
CHANGED
|
@@ -4,12 +4,51 @@ from celery.exceptions import Retry
|
|
|
4
4
|
from celery.result import EagerResult
|
|
5
5
|
from celery.utils.functional import maybe_list
|
|
6
6
|
from celery.utils.nodenames import gethostname
|
|
7
|
+
from django.conf import settings
|
|
8
|
+
from django.contrib.auth import get_user_model
|
|
7
9
|
from kombu.utils.uuid import uuid
|
|
8
10
|
|
|
11
|
+
from nautobot.core.branching import BranchContext
|
|
12
|
+
from nautobot.extras.models.jobs import JOB_LOGS
|
|
13
|
+
|
|
9
14
|
|
|
10
15
|
class NautobotTask(Task):
|
|
11
16
|
"""Nautobot extensions to tasks for integrating with Job machinery."""
|
|
12
17
|
|
|
18
|
+
def before_start(self, task_id, args, kwargs):
|
|
19
|
+
super().before_start(task_id, args, kwargs)
|
|
20
|
+
User = get_user_model()
|
|
21
|
+
user_id = self.request.properties.get("nautobot_job_user_id", None)
|
|
22
|
+
self._nautobot_branch_context = BranchContext(
|
|
23
|
+
branch_name=self.request.properties.get("nautobot_job_branch_name", None),
|
|
24
|
+
user=User.objects.get(id=user_id) if user_id else None,
|
|
25
|
+
using=["default", JOB_LOGS],
|
|
26
|
+
)
|
|
27
|
+
self._nautobot_branch_context.__enter__()
|
|
28
|
+
|
|
29
|
+
def after_return(self, status, retval, task_id, args, kwargs, einfo):
|
|
30
|
+
self._nautobot_branch_context.__exit__(None, None, None) # TODO: good enough?
|
|
31
|
+
delattr(self, "_nautobot_branch_context")
|
|
32
|
+
super().after_return(status, retval, task_id, args, kwargs, einfo)
|
|
33
|
+
|
|
34
|
+
def apply_async(
|
|
35
|
+
self,
|
|
36
|
+
args=None,
|
|
37
|
+
kwargs=None,
|
|
38
|
+
task_id=None,
|
|
39
|
+
producer=None,
|
|
40
|
+
link=None,
|
|
41
|
+
link_error=None,
|
|
42
|
+
shadow=None,
|
|
43
|
+
**options,
|
|
44
|
+
):
|
|
45
|
+
if "nautobot_version_control" in settings.PLUGINS and "nautobot_job_branch_name" not in options:
|
|
46
|
+
from nautobot_version_control.utils import active_branch # pylint: disable=import-error
|
|
47
|
+
|
|
48
|
+
options["nautobot_job_branch_name"] = active_branch()
|
|
49
|
+
|
|
50
|
+
return super().apply_async(args, kwargs, task_id, producer, link, link_error, shadow, **options)
|
|
51
|
+
|
|
13
52
|
def apply(
|
|
14
53
|
self,
|
|
15
54
|
args=None,
|
|
@@ -39,6 +78,11 @@ class NautobotTask(Task):
|
|
|
39
78
|
# Make sure we get the task instance, not class.
|
|
40
79
|
task = app._tasks[self.name]
|
|
41
80
|
|
|
81
|
+
if "nautobot_version_control" in settings.PLUGINS and "nautobot_job_branch_name" not in options:
|
|
82
|
+
from nautobot_version_control.utils import active_branch # pylint: disable=import-error
|
|
83
|
+
|
|
84
|
+
options["nautobot_job_branch_name"] = active_branch()
|
|
85
|
+
|
|
42
86
|
request = {
|
|
43
87
|
"id": task_id,
|
|
44
88
|
"retries": retries,
|
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",
|
|
@@ -30,12 +33,31 @@ E005 = Error(
|
|
|
30
33
|
obj=settings,
|
|
31
34
|
)
|
|
32
35
|
|
|
36
|
+
E006 = Error(
|
|
37
|
+
"The Data Validation Engine app has been moved directly into Nautobot Core. Please remove 'nautobot_data_validation_engine' from PLUGINS and PLUGINS_CONFIG in your nautobot_config.py. After running Nautobot migrations successfully, you can then also uninstall 'nautobot-data-validation-engine' from the Python environment.",
|
|
38
|
+
id="nautobot.core.E006",
|
|
39
|
+
obj=settings,
|
|
40
|
+
)
|
|
41
|
+
|
|
33
42
|
W005 = Warning(
|
|
34
43
|
"STORAGE_CONFIG has been set but STORAGE_BACKEND is not defined. STORAGE_CONFIG will be ignored.",
|
|
35
44
|
id="nautobot.core.W005",
|
|
36
45
|
obj=settings,
|
|
37
46
|
)
|
|
38
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
|
+
|
|
39
61
|
MIN_POSTGRESQL_MAJOR_VERSION = 12
|
|
40
62
|
MIN_POSTGRESQL_MINOR_VERSION = 0
|
|
41
63
|
|
|
@@ -139,3 +161,41 @@ def check_sanitizer_patterns(app_configs, **kwargs):
|
|
|
139
161
|
)
|
|
140
162
|
|
|
141
163
|
return errors
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
@register(Tags.compatibility)
|
|
167
|
+
def check_data_validation_engine_installed(app_configs, **kwargs):
|
|
168
|
+
app_name = "nautobot_data_validation_engine"
|
|
169
|
+
if app_name in settings.PLUGINS or app_name in settings.PLUGINS_CONFIG:
|
|
170
|
+
return [E006]
|
|
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 []
|