nautobot 3.0.0a3__py3-none-any.whl → 3.0.0rc1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- nautobot/apps/choices.py +4 -0
- nautobot/apps/ui.py +4 -0
- nautobot/apps/utils.py +8 -0
- nautobot/circuits/tests/integration/test_circuits_bulk_operations.py +0 -3
- nautobot/circuits/views.py +6 -2
- nautobot/core/api/serializers.py +1 -1
- nautobot/core/api/urls.py +1 -0
- nautobot/core/api/views.py +4 -0
- nautobot/core/choices.py +1 -1
- nautobot/core/cli/bootstrap_v3_to_v5.py +36 -13
- nautobot/core/cli/migrate_deprecated_templates.py +36 -9
- nautobot/core/filters.py +4 -0
- nautobot/core/forms/__init__.py +2 -0
- nautobot/core/forms/widgets.py +21 -2
- nautobot/core/jobs/__init__.py +56 -0
- nautobot/core/management/commands/generate_test_data.py +3 -3
- nautobot/core/models/__init__.py +11 -0
- nautobot/core/models/utils.py +1 -1
- nautobot/core/settings.py +17 -7
- nautobot/core/settings.yaml +4 -26
- nautobot/core/templates/admin/base.html +1 -2
- nautobot/core/templates/admin/change_list.html +9 -12
- nautobot/core/templates/base_django.html +1 -2
- nautobot/core/templates/components/panel/header_extra_content_table.html +1 -1
- nautobot/core/templates/components/tab/content_wrapper.html +4 -4
- nautobot/core/templates/echarts/echarts.html +21 -8
- nautobot/core/templates/generic/object_bulk_create.html +2 -2
- nautobot/core/templates/generic/object_bulk_delete.html +1 -1
- nautobot/core/templates/generic/object_bulk_edit.html +1 -1
- nautobot/core/templates/generic/object_bulk_import.html +1 -1
- nautobot/core/templates/generic/object_delete.html +1 -1
- nautobot/core/templates/generic/object_detail.html +1 -1
- nautobot/core/templates/generic/object_edit.html +1 -1
- nautobot/core/templates/generic/object_retrieve.html +2 -2
- nautobot/core/templates/graphene/graphiql.html +0 -1
- nautobot/core/templates/inc/footer.html +3 -1
- nautobot/core/templates/inc/header.html +10 -0
- nautobot/core/templates/inc/media.html +14 -0
- nautobot/core/templates/inc/nav_menu.html +1 -8
- nautobot/core/templates/inc/object_details_advanced_panel.html +2 -2
- nautobot/core/templates/nautobot_config.py.j2 +0 -6
- nautobot/core/templates/rest_framework/api.html +103 -2
- nautobot/core/templates/utilities/templatetags/filter_form_drawer.html +33 -0
- nautobot/core/templates/utilities/theme_preview.html +3 -0
- nautobot/core/templates/widgets/number_input_with_choices.html +44 -0
- nautobot/core/templatetags/helpers.py +24 -12
- nautobot/core/testing/integration.py +24 -13
- nautobot/core/testing/utils.py +18 -4
- nautobot/core/testing/views.py +104 -17
- nautobot/core/tests/integration/test_filters.py +48 -11
- nautobot/core/tests/integration/test_theme.py +22 -21
- nautobot/core/tests/nautobot_config.py +3 -0
- nautobot/core/tests/runner.py +1 -2
- nautobot/core/tests/test_breadcrumbs.py +21 -21
- nautobot/core/tests/test_jobs.py +73 -6
- nautobot/core/tests/test_renderers.py +59 -0
- nautobot/core/tests/test_settings_schema.py +1 -0
- nautobot/core/tests/test_templatetags_helpers.py +9 -0
- nautobot/core/tests/test_titles.py +0 -16
- nautobot/core/tests/test_ui.py +122 -3
- nautobot/core/tests/test_utils.py +41 -1
- nautobot/core/ui/breadcrumbs.py +68 -17
- nautobot/core/ui/bulk_buttons.py +1 -1
- nautobot/core/ui/choices.py +49 -65
- nautobot/core/ui/echarts.py +15 -20
- nautobot/core/ui/object_detail.py +54 -46
- nautobot/core/ui/titles.py +3 -6
- nautobot/core/urls.py +8 -8
- nautobot/core/utils/filtering.py +11 -1
- nautobot/core/utils/lookup.py +46 -0
- nautobot/core/views/mixins.py +31 -20
- nautobot/core/views/renderers.py +2 -3
- nautobot/data_validation/migrations/0002_data_migration_from_app.py +3 -2
- nautobot/dcim/api/serializers.py +3 -0
- nautobot/dcim/choices.py +49 -0
- nautobot/dcim/constants.py +7 -0
- nautobot/dcim/factory.py +1 -1
- nautobot/dcim/filters.py +13 -1
- nautobot/dcim/forms.py +89 -3
- nautobot/dcim/migrations/0075_interface_duplex_interface_speed_and_more.py +32 -0
- nautobot/dcim/migrations/{0075_add_deviceclusterassignment.py → 0076_add_deviceclusterassignment.py} +1 -1
- nautobot/dcim/migrations/{0076_device_cluster_to_clusters_data_migration.py → 0077_device_cluster_to_clusters_data_migration.py} +1 -1
- nautobot/dcim/migrations/{0077_remove_device_cluster.py → 0078_remove_device_cluster.py} +1 -1
- nautobot/dcim/migrations/{0078_remove_device_location_tenant_name_uniqueness.py → 0079_remove_device_location_tenant_name_uniqueness.py} +1 -1
- nautobot/dcim/migrations/{0079_device_name_data_migration.py → 0080_device_name_data_migration.py} +1 -1
- nautobot/dcim/migrations/0081_alter_device_device_redundancy_group_priority_and_more.py +25 -0
- nautobot/dcim/models/device_component_templates.py +33 -1
- nautobot/dcim/models/device_components.py +22 -1
- nautobot/dcim/models/devices.py +17 -4
- nautobot/dcim/tables/devices.py +15 -0
- nautobot/dcim/tables/devicetypes.py +8 -1
- nautobot/dcim/tables/racks.py +0 -2
- nautobot/dcim/tables/template_code.py +1 -1
- nautobot/dcim/templates/dcim/cable_trace.html +0 -2
- nautobot/dcim/templates/dcim/consoleport.html +1 -1
- nautobot/dcim/templates/dcim/consoleserverport.html +1 -1
- nautobot/dcim/templates/dcim/devicebay.html +1 -1
- nautobot/dcim/templates/dcim/frontport.html +1 -1
- nautobot/dcim/templates/dcim/inc/devicetype_component_table.html +1 -1
- nautobot/dcim/templates/dcim/inc/moduletype_component_table.html +1 -1
- nautobot/dcim/templates/dcim/inc/rack_elevation.html +1 -1
- nautobot/dcim/templates/dcim/interface.html +9 -1
- nautobot/dcim/templates/dcim/interface_edit.html +2 -0
- nautobot/dcim/templates/dcim/inventoryitem.html +1 -1
- nautobot/dcim/templates/dcim/module_consoleports.html +1 -1
- nautobot/dcim/templates/dcim/module_consoleserverports.html +1 -1
- nautobot/dcim/templates/dcim/module_frontports.html +1 -1
- nautobot/dcim/templates/dcim/module_interfaces.html +1 -1
- nautobot/dcim/templates/dcim/module_modulebays.html +1 -1
- nautobot/dcim/templates/dcim/module_poweroutlets.html +1 -1
- nautobot/dcim/templates/dcim/module_powerports.html +1 -1
- nautobot/dcim/templates/dcim/module_rearports.html +1 -1
- nautobot/dcim/templates/dcim/moduletype_list.html +2 -2
- nautobot/dcim/templates/dcim/poweroutlet.html +1 -1
- nautobot/dcim/templates/dcim/powerport.html +1 -1
- nautobot/dcim/templates/dcim/rack_elevation_list.html +1 -1
- nautobot/dcim/templates/dcim/rack_retrieve.html +0 -11
- nautobot/dcim/templates/dcim/rearport.html +1 -1
- nautobot/dcim/templates/dcim/trace/cable.html +1 -1
- nautobot/dcim/templates/dcim/virtualchassis_update.html +1 -1
- nautobot/dcim/tests/integration/test_controller.py +3 -6
- nautobot/dcim/tests/integration/test_controller_managed_device_group.py +1 -5
- nautobot/dcim/tests/integration/test_create_device.py +0 -2
- nautobot/dcim/tests/integration/test_device_bulk_operations.py +1 -3
- nautobot/dcim/tests/integration/test_fileinputpicker.py +6 -10
- nautobot/dcim/tests/integration/test_location_bulk_operations.py +0 -2
- nautobot/dcim/tests/integration/test_module_bay_position.py +3 -4
- nautobot/dcim/tests/test_api.py +186 -6
- nautobot/dcim/tests/test_filters.py +43 -1
- nautobot/dcim/tests/test_forms.py +110 -8
- nautobot/dcim/tests/test_graphql.py +44 -1
- nautobot/dcim/tests/test_models.py +265 -0
- nautobot/dcim/tests/test_tables.py +160 -0
- nautobot/dcim/tests/test_views.py +69 -7
- nautobot/dcim/views.py +232 -126
- nautobot/extras/api/views.py +51 -44
- nautobot/extras/datasources/git.py +3 -1
- nautobot/extras/filters.py +19 -2
- nautobot/extras/forms/forms.py +9 -2
- nautobot/extras/jobs.py +2 -0
- nautobot/extras/jobs_ui.py +4 -3
- nautobot/extras/management/__init__.py +2 -0
- nautobot/extras/management/commands/refresh_dynamic_group_member_caches.py +4 -1
- nautobot/extras/migrations/0131_configcontext_device_families.py +18 -0
- nautobot/extras/models/approvals.py +11 -1
- nautobot/extras/models/change_logging.py +4 -0
- nautobot/extras/models/jobs.py +1 -3
- nautobot/extras/models/models.py +10 -2
- nautobot/extras/plugins/marketplace_manifest.yml +49 -1
- nautobot/extras/plugins/views.py +0 -5
- nautobot/extras/querysets.py +8 -0
- nautobot/extras/tables.py +12 -0
- nautobot/extras/templates/django_ajax_tables/ajax_wrapper.html +2 -0
- nautobot/extras/templates/extras/configcontext_update.html +1 -0
- nautobot/extras/templates/extras/dynamicgroup_update.html +1 -1
- nautobot/extras/templates/extras/objectchange_retrieve.html +0 -2
- nautobot/extras/templates/extras/plugin_detail.html +3 -3
- nautobot/extras/templates/extras/secret_create.html +1 -1
- nautobot/extras/tests/integration/test_computedfields.py +8 -9
- nautobot/extras/tests/integration/test_customfields.py +1 -3
- nautobot/extras/tests/integration/test_dynamicgroups.py +7 -8
- nautobot/extras/tests/integration/test_relationships.py +0 -2
- nautobot/extras/tests/test_api.py +63 -0
- nautobot/extras/tests/test_changelog.py +24 -2
- nautobot/extras/tests/test_filters.py +36 -3
- nautobot/extras/tests/test_models.py +38 -2
- nautobot/extras/tests/test_utils.py +3 -4
- nautobot/extras/tests/test_views.py +22 -83
- nautobot/extras/urls.py +0 -14
- nautobot/extras/views.py +83 -52
- nautobot/ipam/filters.py +26 -0
- nautobot/ipam/tables.py +6 -0
- nautobot/ipam/templates/ipam/namespace_ip_addresses.html +1 -1
- nautobot/ipam/templates/ipam/namespace_prefixes.html +1 -1
- nautobot/ipam/templates/ipam/namespace_vrfs.html +1 -1
- nautobot/ipam/tests/test_filters.py +26 -1
- nautobot/ipam/tests/test_models.py +1 -1
- nautobot/ipam/views.py +9 -7
- nautobot/load_balancers/__init__.py +0 -0
- nautobot/load_balancers/api/__init__.py +1 -0
- nautobot/load_balancers/api/serializers.py +75 -0
- nautobot/load_balancers/api/urls.py +23 -0
- nautobot/load_balancers/api/views.py +61 -0
- nautobot/load_balancers/apps.py +17 -0
- nautobot/load_balancers/choices.py +167 -0
- nautobot/load_balancers/filters.py +225 -0
- nautobot/load_balancers/forms.py +532 -0
- nautobot/load_balancers/management/commands/__init__.py +0 -0
- nautobot/load_balancers/management/commands/generate_load_balancer_models_test_data.py +38 -0
- nautobot/load_balancers/migrations/0001_initial.py +465 -0
- nautobot/load_balancers/migrations/0002_create_default_statuses_pool_members.py +31 -0
- nautobot/load_balancers/migrations/__init__.py +0 -0
- nautobot/load_balancers/models.py +423 -0
- nautobot/load_balancers/navigation.py +80 -0
- nautobot/load_balancers/tables.py +255 -0
- nautobot/load_balancers/tests/__init__.py +474 -0
- nautobot/load_balancers/tests/test_api.py +353 -0
- nautobot/load_balancers/tests/test_filters.py +134 -0
- nautobot/load_balancers/tests/test_forms.py +266 -0
- nautobot/load_balancers/tests/test_models.py +195 -0
- nautobot/load_balancers/tests/test_views.py +229 -0
- nautobot/load_balancers/urls.py +17 -0
- nautobot/load_balancers/views.py +248 -0
- nautobot/project-static/dist/css/github-dark.min.css +10 -0
- nautobot/project-static/dist/css/github.min.css +10 -0
- nautobot/project-static/dist/css/nautobot.css +1 -11
- nautobot/project-static/dist/css/nautobot.css.map +1 -1
- nautobot/project-static/dist/js/libraries.js +1 -1
- nautobot/project-static/dist/js/libraries.js.map +1 -1
- nautobot/project-static/dist/js/nautobot.js +1 -1
- nautobot/project-static/dist/js/nautobot.js.map +1 -1
- nautobot/project-static/js/forms.js +13 -0
- nautobot/project-static/nautobot-icons/bus-globe.svg +3 -0
- nautobot/project-static/nautobot-icons/bus-shield-check.svg +3 -0
- nautobot/project-static/nautobot-icons/bus-shield.svg +3 -0
- nautobot/ui/package-lock.json +87 -4
- nautobot/ui/package.json +2 -1
- nautobot/ui/src/js/nautobot.js +0 -1
- nautobot/ui/src/js/select2.js +53 -2
- nautobot/ui/src/scss/nautobot.scss +51 -2
- nautobot/ui/webpack.config.js +13 -0
- nautobot/users/templates/users/preferences.html +11 -2
- nautobot/virtualization/filters.py +6 -1
- nautobot/virtualization/tests/test_filters.py +10 -1
- nautobot/virtualization/tests/test_models.py +1 -0
- nautobot/virtualization/views.py +4 -1
- nautobot/vpn/factory.py +25 -15
- nautobot/vpn/filters.py +1 -0
- nautobot/vpn/forms.py +1 -0
- nautobot/vpn/migrations/0001_initial.py +1 -1
- nautobot/vpn/models.py +16 -8
- nautobot/vpn/tables.py +5 -2
- nautobot/vpn/tests/test_api.py +0 -5
- nautobot/vpn/tests/test_forms.py +1 -2
- nautobot/vpn/tests/test_models.py +57 -7
- nautobot/vpn/tests/test_views.py +22 -3
- nautobot/vpn/views.py +78 -20
- {nautobot-3.0.0a3.dist-info → nautobot-3.0.0rc1.dist-info}/METADATA +4 -4
- {nautobot-3.0.0a3.dist-info → nautobot-3.0.0rc1.dist-info}/RECORD +243 -352
- nautobot/circuits/templates/circuits/circuit.html +0 -2
- nautobot/circuits/templates/circuits/circuit_edit.html +0 -2
- nautobot/circuits/templates/circuits/circuit_retrieve.html +0 -2
- nautobot/circuits/templates/circuits/circuit_update.html +0 -1
- nautobot/circuits/templates/circuits/circuittermination.html +0 -2
- nautobot/circuits/templates/circuits/circuittermination_edit.html +0 -2
- nautobot/circuits/templates/circuits/circuittermination_retrieve.html +0 -2
- nautobot/circuits/templates/circuits/circuittermination_update.html +0 -1
- nautobot/circuits/templates/circuits/circuittype.html +0 -2
- nautobot/circuits/templates/circuits/circuittype_retrieve.html +0 -2
- nautobot/circuits/templates/circuits/inc/circuit_termination.html +0 -85
- nautobot/circuits/templates/circuits/provider.html +0 -2
- nautobot/circuits/templates/circuits/provider_edit.html +0 -2
- nautobot/circuits/templates/circuits/provider_retrieve.html +0 -1
- nautobot/circuits/templates/circuits/provider_update.html +0 -1
- nautobot/circuits/templates/circuits/providernetwork.html +0 -2
- nautobot/circuits/templates/circuits/providernetwork_retrieve.html +0 -2
- nautobot/cloud/templates/cloud/cloudaccount_retrieve.html +0 -2
- nautobot/cloud/templates/cloud/cloudnetwork_retrieve.html +0 -2
- nautobot/cloud/templates/cloud/cloudresourcetype_retrieve.html +0 -2
- nautobot/cloud/templates/cloud/cloudservice_retrieve.html +0 -2
- nautobot/core/templates/buttons/import.html +0 -9
- nautobot/data_validation/templates/data_validation/datacompliance_retrieve.html +0 -1
- nautobot/dcim/templates/dcim/cable.html +0 -2
- nautobot/dcim/templates/dcim/cable_edit.html +0 -2
- nautobot/dcim/templates/dcim/controller/base.html +0 -2
- nautobot/dcim/templates/dcim/controller_retrieve.html +0 -2
- nautobot/dcim/templates/dcim/controller_wirelessnetworks.html +0 -2
- nautobot/dcim/templates/dcim/controllermanageddevicegroup_retrieve.html +0 -2
- nautobot/dcim/templates/dcim/device/base.html +0 -2
- nautobot/dcim/templates/dcim/device/consoleports.html +0 -2
- nautobot/dcim/templates/dcim/device/consoleserverports.html +0 -2
- nautobot/dcim/templates/dcim/device/devicebays.html +0 -2
- nautobot/dcim/templates/dcim/device/frontports.html +0 -2
- nautobot/dcim/templates/dcim/device/interfaces.html +0 -2
- nautobot/dcim/templates/dcim/device/inventory.html +0 -2
- nautobot/dcim/templates/dcim/device/modulebays.html +0 -2
- nautobot/dcim/templates/dcim/device/poweroutlets.html +0 -2
- nautobot/dcim/templates/dcim/device/powerports.html +0 -2
- nautobot/dcim/templates/dcim/device/rearports.html +0 -2
- nautobot/dcim/templates/dcim/device/wireless.html +0 -2
- nautobot/dcim/templates/dcim/device_component.html +0 -2
- nautobot/dcim/templates/dcim/device_edit.html +0 -2
- nautobot/dcim/templates/dcim/devicefamily_retrieve.html +0 -2
- nautobot/dcim/templates/dcim/deviceredundancygroup_retrieve.html +0 -2
- nautobot/dcim/templates/dcim/devicetype.html +0 -2
- nautobot/dcim/templates/dcim/devicetype_edit.html +0 -2
- nautobot/dcim/templates/dcim/devicetype_retrieve.html +0 -2
- nautobot/dcim/templates/dcim/inc/device_napalm_tabs.html +0 -1
- nautobot/dcim/templates/dcim/interfaceredundancygroup_retrieve.html +0 -2
- nautobot/dcim/templates/dcim/location.html +0 -2
- nautobot/dcim/templates/dcim/location_edit.html +0 -2
- nautobot/dcim/templates/dcim/location_retrieve.html +0 -2
- nautobot/dcim/templates/dcim/locationtype.html +0 -2
- nautobot/dcim/templates/dcim/locationtype_retrieve.html +0 -2
- nautobot/dcim/templates/dcim/manufacturer.html +0 -2
- nautobot/dcim/templates/dcim/modulebay_retrieve.html +0 -1
- nautobot/dcim/templates/dcim/platform.html +0 -2
- nautobot/dcim/templates/dcim/powerfeed.html +0 -2
- nautobot/dcim/templates/dcim/powerfeed_retrieve.html +0 -2
- nautobot/dcim/templates/dcim/powerpanel.html +0 -2
- nautobot/dcim/templates/dcim/powerpanel_edit.html +0 -2
- nautobot/dcim/templates/dcim/powerpanel_retrieve.html +0 -2
- nautobot/dcim/templates/dcim/rack.html +0 -2
- nautobot/dcim/templates/dcim/rack_edit.html +0 -2
- nautobot/dcim/templates/dcim/rackgroup.html +0 -2
- nautobot/dcim/templates/dcim/rackreservation.html +0 -2
- nautobot/dcim/templates/dcim/softwareimagefile_retrieve.html +0 -2
- nautobot/dcim/templates/dcim/softwareversion_retrieve.html +0 -2
- nautobot/dcim/templates/dcim/virtualchassis.html +0 -2
- nautobot/dcim/templates/dcim/virtualchassis_add.html +0 -2
- nautobot/dcim/templates/dcim/virtualchassis_edit.html +0 -2
- nautobot/dcim/templates/dcim/virtualchassis_retrieve.html +0 -2
- nautobot/dcim/templates/dcim/virtualdevicecontext_retrieve.html +0 -2
- nautobot/dcim/ui.py +0 -29
- nautobot/extras/templates/extras/computedfield.html +0 -2
- nautobot/extras/templates/extras/computedfield_retrieve.html +0 -2
- nautobot/extras/templates/extras/configcontext.html +0 -2
- nautobot/extras/templates/extras/configcontext_edit.html +0 -2
- nautobot/extras/templates/extras/configcontext_retrieve.html +0 -2
- nautobot/extras/templates/extras/configcontextschema.html +0 -2
- nautobot/extras/templates/extras/configcontextschema_edit.html +0 -2
- nautobot/extras/templates/extras/contact_retrieve.html +0 -2
- nautobot/extras/templates/extras/customfield.html +0 -2
- nautobot/extras/templates/extras/customfield_edit.html +0 -2
- nautobot/extras/templates/extras/customfield_retrieve.html +0 -2
- nautobot/extras/templates/extras/customlink.html +0 -2
- nautobot/extras/templates/extras/dynamicgroup.html +0 -2
- nautobot/extras/templates/extras/dynamicgroup_edit.html +0 -2
- nautobot/extras/templates/extras/exporttemplate.html +0 -2
- nautobot/extras/templates/extras/gitrepository.html +0 -2
- nautobot/extras/templates/extras/gitrepository_object_edit.html +0 -2
- nautobot/extras/templates/extras/graphqlquery.html +0 -2
- nautobot/extras/templates/extras/graphqlquery_list.html +0 -1
- nautobot/extras/templates/extras/graphqlquery_retrieve.html +0 -2
- nautobot/extras/templates/extras/job_detail.html +0 -2
- nautobot/extras/templates/extras/jobbutton_retrieve.html +0 -2
- nautobot/extras/templates/extras/jobhook.html +0 -2
- nautobot/extras/templates/extras/jobqueue_retrieve.html +0 -2
- nautobot/extras/templates/extras/jobresult.html +0 -2
- nautobot/extras/templates/extras/metadatatype_retrieve.html +0 -2
- nautobot/extras/templates/extras/note.html +0 -2
- nautobot/extras/templates/extras/note_retrieve.html +0 -1
- nautobot/extras/templates/extras/object_changelog.html +0 -2
- nautobot/extras/templates/extras/object_notes.html +0 -2
- nautobot/extras/templates/extras/objectchange.html +0 -2
- nautobot/extras/templates/extras/objectchange_list.html +0 -3
- nautobot/extras/templates/extras/relationship.html +0 -1
- nautobot/extras/templates/extras/secret.html +0 -1
- nautobot/extras/templates/extras/secret_edit.html +0 -1
- nautobot/extras/templates/extras/secretsgroup.html +0 -2
- nautobot/extras/templates/extras/secretsgroup_edit.html +0 -2
- nautobot/extras/templates/extras/secretsgroup_retrieve.html +0 -2
- nautobot/extras/templates/extras/status.html +0 -2
- nautobot/extras/templates/extras/tag.html +0 -2
- nautobot/extras/templates/extras/tag_edit.html +0 -2
- nautobot/extras/templates/extras/tag_retrieve.html +0 -2
- nautobot/extras/templates/extras/team_retrieve.html +0 -2
- nautobot/ipam/templates/ipam/namespace_retrieve.html +0 -1
- nautobot/ipam/templates/ipam/prefix.html +0 -2
- nautobot/ipam/templates/ipam/prefix_edit.html +0 -1
- nautobot/ipam/templates/ipam/prefix_retrieve.html +0 -2
- nautobot/ipam/templates/ipam/rir.html +0 -2
- nautobot/ipam/templates/ipam/routetarget.html +0 -1
- nautobot/ipam/templates/ipam/service.html +0 -2
- nautobot/ipam/templates/ipam/service_edit.html +0 -2
- nautobot/ipam/templates/ipam/service_retrieve.html +0 -2
- nautobot/ipam/templates/ipam/vlan.html +0 -2
- nautobot/ipam/templates/ipam/vlan_edit.html +0 -2
- nautobot/ipam/templates/ipam/vlan_retrieve.html +0 -2
- nautobot/ipam/templates/ipam/vlangroup.html +0 -2
- nautobot/ipam/templates/ipam/vrf.html +0 -1
- nautobot/tenancy/templates/tenancy/tenant.html +0 -2
- nautobot/tenancy/templates/tenancy/tenant_edit.html +0 -2
- nautobot/tenancy/templates/tenancy/tenantgroup.html +0 -2
- nautobot/tenancy/templates/tenancy/tenantgroup_retrieve.html +0 -1
- nautobot/virtualization/templates/virtualization/clustergroup.html +0 -2
- nautobot/virtualization/templates/virtualization/clustertype.html +0 -2
- nautobot/virtualization/templates/virtualization/virtualmachine.html +0 -2
- nautobot/virtualization/templates/virtualization/virtualmachine_edit.html +0 -2
- nautobot/virtualization/templates/virtualization/virtualmachine_retrieve.html +0 -2
- nautobot/vpn/templates/vpn/vpnprofile.html +0 -2
- nautobot/wireless/templates/wireless/radioprofile_retrieve.html +0 -2
- nautobot/wireless/templates/wireless/supporteddatarate_retrieve.html +0 -2
- nautobot/wireless/templates/wireless/wirelessnetwork_retrieve.html +0 -2
- {nautobot-3.0.0a3.dist-info → nautobot-3.0.0rc1.dist-info}/LICENSE.txt +0 -0
- {nautobot-3.0.0a3.dist-info → nautobot-3.0.0rc1.dist-info}/NOTICE +0 -0
- {nautobot-3.0.0a3.dist-info → nautobot-3.0.0rc1.dist-info}/WHEEL +0 -0
- {nautobot-3.0.0a3.dist-info → nautobot-3.0.0rc1.dist-info}/entry_points.txt +0 -0
nautobot/extras/api/views.py
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
from django.conf import settings
|
|
2
2
|
from django.contrib.contenttypes.models import ContentType
|
|
3
|
+
from django.db import transaction
|
|
3
4
|
from django.db.models import ProtectedError
|
|
4
5
|
from django.forms import ValidationError as FormsValidationError
|
|
5
6
|
from django.http import FileResponse, Http404
|
|
@@ -897,55 +898,61 @@ class JobViewSetBase(
|
|
|
897
898
|
if schedule_data is None:
|
|
898
899
|
schedule_data = {"interval": JobExecutionType.TYPE_IMMEDIATELY, "start_time": timezone.now()}
|
|
899
900
|
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
request.user,
|
|
903
|
-
name=schedule_data.get("name"),
|
|
904
|
-
start_time=schedule_data.get("start_time"),
|
|
905
|
-
interval=schedule_data.get("interval"),
|
|
906
|
-
crontab=schedule_data.get("crontab", ""),
|
|
907
|
-
job_queue=job_queue,
|
|
908
|
-
validated_save=False,
|
|
909
|
-
**job_class.serialize_data(cleaned_data),
|
|
910
|
-
)
|
|
911
|
-
|
|
912
|
-
scheduled_job_has_approval_workflow = schedule.has_approval_workflow_definition()
|
|
913
|
-
if job_model.has_sensitive_variables:
|
|
914
|
-
if (
|
|
915
|
-
"schedule" in request.data
|
|
916
|
-
and "interval" in request.data["schedule"]
|
|
917
|
-
and request.data["schedule"]["interval"] != JobExecutionType.TYPE_IMMEDIATELY
|
|
918
|
-
):
|
|
919
|
-
raise ValidationError(
|
|
920
|
-
{"schedule": {"interval": ["Unable to schedule job: Job may have sensitive input variables"]}}
|
|
921
|
-
)
|
|
922
|
-
# check approval_required pointer
|
|
923
|
-
if scheduled_job_has_approval_workflow:
|
|
924
|
-
raise ValidationError(
|
|
925
|
-
"Unable to run or schedule job: "
|
|
926
|
-
"This job is flagged as possibly having sensitive variables but also has an applicable approval workflow definition."
|
|
927
|
-
"Modify or remove the approval workflow definition or modify the job to set `has_sensitive_variables` to False."
|
|
928
|
-
)
|
|
929
|
-
|
|
930
|
-
# Approval is not required for dryrun
|
|
931
|
-
# TODO: remove this once we have the ability to configure an approval workflow to ignore jobs with specific parameters(including `dryrun`)
|
|
932
|
-
dryrun = data.get("dryrun", False) if job_class.supports_dryrun else False
|
|
933
|
-
|
|
934
|
-
if (not dryrun and scheduled_job_has_approval_workflow) or schedule_data[
|
|
935
|
-
"interval"
|
|
936
|
-
] in JobExecutionType.SCHEDULE_CHOICES:
|
|
937
|
-
schedule.validated_save()
|
|
938
|
-
serializer = serializers.ScheduledJobSerializer(schedule, context={"request": request})
|
|
939
|
-
return Response({"scheduled_job": serializer.data, "job_result": None}, status=status.HTTP_201_CREATED)
|
|
940
|
-
else:
|
|
941
|
-
job_result = JobResult.enqueue_job(
|
|
901
|
+
with transaction.atomic():
|
|
902
|
+
schedule = ScheduledJob.create_schedule(
|
|
942
903
|
job_model,
|
|
943
904
|
request.user,
|
|
905
|
+
name=schedule_data.get("name"),
|
|
906
|
+
start_time=schedule_data.get("start_time"),
|
|
907
|
+
interval=schedule_data.get("interval"),
|
|
908
|
+
crontab=schedule_data.get("crontab", ""),
|
|
944
909
|
job_queue=job_queue,
|
|
945
910
|
**job_class.serialize_data(cleaned_data),
|
|
946
911
|
)
|
|
947
|
-
|
|
948
|
-
|
|
912
|
+
|
|
913
|
+
scheduled_job_has_approval_workflow = schedule.has_approval_workflow_definition()
|
|
914
|
+
if job_model.has_sensitive_variables:
|
|
915
|
+
if (
|
|
916
|
+
"schedule" in request.data
|
|
917
|
+
and "interval" in request.data["schedule"]
|
|
918
|
+
and request.data["schedule"]["interval"] != JobExecutionType.TYPE_IMMEDIATELY
|
|
919
|
+
):
|
|
920
|
+
schedule.delete()
|
|
921
|
+
schedule = None
|
|
922
|
+
raise ValidationError(
|
|
923
|
+
{"schedule": {"interval": ["Unable to schedule job: Job may have sensitive input variables"]}}
|
|
924
|
+
)
|
|
925
|
+
# check approval_required pointer
|
|
926
|
+
if scheduled_job_has_approval_workflow:
|
|
927
|
+
schedule.delete()
|
|
928
|
+
schedule = None
|
|
929
|
+
raise ValidationError(
|
|
930
|
+
"Unable to run or schedule job: "
|
|
931
|
+
"This job is flagged as possibly having sensitive variables but also has an applicable approval workflow definition."
|
|
932
|
+
"Modify or remove the approval workflow definition or modify the job to set `has_sensitive_variables` to False."
|
|
933
|
+
)
|
|
934
|
+
|
|
935
|
+
# Approval is not required for dryrun
|
|
936
|
+
# TODO: remove this once we have the ability to configure an approval workflow to ignore jobs with specific parameters(including `dryrun`)
|
|
937
|
+
dryrun = data.get("dryrun", False) if job_class.supports_dryrun else False
|
|
938
|
+
|
|
939
|
+
if (not dryrun and scheduled_job_has_approval_workflow) or schedule_data[
|
|
940
|
+
"interval"
|
|
941
|
+
] in JobExecutionType.SCHEDULE_CHOICES:
|
|
942
|
+
serializer = serializers.ScheduledJobSerializer(schedule, context={"request": request})
|
|
943
|
+
return Response({"scheduled_job": serializer.data, "job_result": None}, status=status.HTTP_201_CREATED)
|
|
944
|
+
|
|
945
|
+
schedule.delete()
|
|
946
|
+
schedule = None
|
|
947
|
+
|
|
948
|
+
job_result = JobResult.enqueue_job(
|
|
949
|
+
job_model,
|
|
950
|
+
request.user,
|
|
951
|
+
job_queue=job_queue,
|
|
952
|
+
**job_class.serialize_data(cleaned_data),
|
|
953
|
+
)
|
|
954
|
+
serializer = serializers.JobResultSerializer(job_result, context={"request": request})
|
|
955
|
+
return Response({"scheduled_job": None, "job_result": serializer.data}, status=status.HTTP_201_CREATED)
|
|
949
956
|
|
|
950
957
|
|
|
951
958
|
class JobViewSet(
|
|
@@ -18,7 +18,7 @@ import yaml
|
|
|
18
18
|
|
|
19
19
|
from nautobot.core.utils.git import GitRepo
|
|
20
20
|
from nautobot.core.utils.module_loading import check_name_safe_to_import_privately, import_modules_privately
|
|
21
|
-
from nautobot.dcim.models import Device, DeviceRedundancyGroup, DeviceType, Location, Platform
|
|
21
|
+
from nautobot.dcim.models import Device, DeviceFamily, DeviceRedundancyGroup, DeviceType, Location, Platform
|
|
22
22
|
from nautobot.extras.choices import (
|
|
23
23
|
LogLevelChoices,
|
|
24
24
|
SecretsGroupAccessTypeChoices,
|
|
@@ -274,6 +274,7 @@ def update_git_config_contexts(repository_record, job_result):
|
|
|
274
274
|
for filter_type in (
|
|
275
275
|
"locations",
|
|
276
276
|
"device_types",
|
|
277
|
+
"device_families",
|
|
277
278
|
"roles",
|
|
278
279
|
"platforms",
|
|
279
280
|
"cluster_groups",
|
|
@@ -408,6 +409,7 @@ def import_config_context(context_data, repository_record, job_result):
|
|
|
408
409
|
for key, model_class in [
|
|
409
410
|
("locations", Location),
|
|
410
411
|
("device_types", DeviceType),
|
|
412
|
+
("device_families", DeviceFamily),
|
|
411
413
|
("roles", Role),
|
|
412
414
|
("platforms", Platform),
|
|
413
415
|
("cluster_groups", ClusterGroup),
|
nautobot/extras/filters.py
CHANGED
|
@@ -23,8 +23,9 @@ from nautobot.core.filters import (
|
|
|
23
23
|
RelatedMembershipBooleanFilter,
|
|
24
24
|
SearchFilter,
|
|
25
25
|
)
|
|
26
|
-
from nautobot.dcim.models import DeviceRedundancyGroup, DeviceType, Location, Platform
|
|
26
|
+
from nautobot.dcim.models import DeviceFamily, DeviceRedundancyGroup, DeviceType, Location, Platform
|
|
27
27
|
from nautobot.extras.choices import (
|
|
28
|
+
ApprovalWorkflowStateChoices,
|
|
28
29
|
JobQueueTypeChoices,
|
|
29
30
|
JobResultStatusChoices,
|
|
30
31
|
MetadataTypeDataTypeChoices,
|
|
@@ -386,6 +387,12 @@ class ConfigContextFilterSet(BaseFilterSet):
|
|
|
386
387
|
to_field_name="model",
|
|
387
388
|
label="Device Type (model or ID)",
|
|
388
389
|
)
|
|
390
|
+
device_family = NaturalKeyOrPKMultipleChoiceFilter(
|
|
391
|
+
field_name="device_families",
|
|
392
|
+
queryset=DeviceFamily.objects.all(),
|
|
393
|
+
to_field_name="name",
|
|
394
|
+
label="Device Family (name or ID)",
|
|
395
|
+
)
|
|
389
396
|
platform_id = ModelMultipleChoiceFilter(
|
|
390
397
|
field_name="platforms",
|
|
391
398
|
queryset=Platform.objects.all(),
|
|
@@ -1208,10 +1215,15 @@ class ScheduledJobFilterSet(BaseFilterSet):
|
|
|
1208
1215
|
label="Time zone",
|
|
1209
1216
|
null_value="",
|
|
1210
1217
|
)
|
|
1218
|
+
approval_state = django_filters.MultipleChoiceFilter(
|
|
1219
|
+
field_name="associated_approval_workflows__current_state",
|
|
1220
|
+
label="Approval state",
|
|
1221
|
+
choices=ApprovalWorkflowStateChoices,
|
|
1222
|
+
)
|
|
1211
1223
|
|
|
1212
1224
|
class Meta:
|
|
1213
1225
|
model = ScheduledJob
|
|
1214
|
-
fields = ["id", "name", "total_run_count", "start_time", "last_run_at", "time_zone"]
|
|
1226
|
+
fields = ["id", "name", "enabled", "total_run_count", "start_time", "last_run_at", "time_zone"]
|
|
1215
1227
|
|
|
1216
1228
|
|
|
1217
1229
|
#
|
|
@@ -1471,6 +1483,11 @@ class SecretFilterSet(
|
|
|
1471
1483
|
"name": "icontains",
|
|
1472
1484
|
},
|
|
1473
1485
|
)
|
|
1486
|
+
secrets_groups = NaturalKeyOrPKMultipleChoiceFilter(
|
|
1487
|
+
queryset=SecretsGroup.objects.all(),
|
|
1488
|
+
label="Groups (ID or name)",
|
|
1489
|
+
to_field_name="name",
|
|
1490
|
+
)
|
|
1474
1491
|
# TODO(Glenn): dynamic choices needed. The issue being that secrets providers are Python
|
|
1475
1492
|
# classes, not database models.
|
|
1476
1493
|
# provider = django_filters.MultipleChoiceFilter(choices=..., null_value=None)
|
nautobot/extras/forms/forms.py
CHANGED
|
@@ -42,7 +42,7 @@ from nautobot.core.forms.constants import BOOLEAN_WITH_BLANK_CHOICES
|
|
|
42
42
|
from nautobot.core.forms.fields import MultiValueCharField
|
|
43
43
|
from nautobot.core.forms.forms import ConfirmationForm
|
|
44
44
|
from nautobot.core.forms.widgets import ClearableFileInput
|
|
45
|
-
from nautobot.dcim.models import Device, DeviceRedundancyGroup, DeviceType, Location, Platform
|
|
45
|
+
from nautobot.dcim.models import Device, DeviceFamily, DeviceRedundancyGroup, DeviceType, Location, Platform
|
|
46
46
|
from nautobot.extras.choices import (
|
|
47
47
|
ApprovalWorkflowStateChoices,
|
|
48
48
|
ButtonClassChoices,
|
|
@@ -544,6 +544,7 @@ class ConfigContextForm(BootstrapMixin, NoteModelFormMixin, forms.ModelForm):
|
|
|
544
544
|
required=False,
|
|
545
545
|
)
|
|
546
546
|
device_types = DynamicModelMultipleChoiceField(queryset=DeviceType.objects.all(), required=False)
|
|
547
|
+
device_families = DynamicModelMultipleChoiceField(queryset=DeviceFamily.objects.all(), required=False)
|
|
547
548
|
platforms = DynamicModelMultipleChoiceField(queryset=Platform.objects.all(), required=False)
|
|
548
549
|
cluster_groups = DynamicModelMultipleChoiceField(queryset=ClusterGroup.objects.all(), required=False)
|
|
549
550
|
clusters = DynamicModelMultipleChoiceField(queryset=Cluster.objects.all(), required=False)
|
|
@@ -576,6 +577,7 @@ class ConfigContextForm(BootstrapMixin, NoteModelFormMixin, forms.ModelForm):
|
|
|
576
577
|
"locations",
|
|
577
578
|
"roles",
|
|
578
579
|
"device_types",
|
|
580
|
+
"device_families",
|
|
579
581
|
"platforms",
|
|
580
582
|
"cluster_groups",
|
|
581
583
|
"clusters",
|
|
@@ -609,7 +611,12 @@ class ConfigContextFilterForm(BootstrapMixin, forms.Form):
|
|
|
609
611
|
role = DynamicModelMultipleChoiceField(
|
|
610
612
|
queryset=Role.objects.get_for_models([Device, VirtualMachine]), to_field_name="name", required=False
|
|
611
613
|
)
|
|
612
|
-
|
|
614
|
+
device_type = DynamicModelMultipleChoiceField(
|
|
615
|
+
queryset=DeviceType.objects.all(), to_field_name="model", required=False
|
|
616
|
+
)
|
|
617
|
+
device_family = DynamicModelMultipleChoiceField(
|
|
618
|
+
queryset=DeviceFamily.objects.all(), to_field_name="name", required=False
|
|
619
|
+
)
|
|
613
620
|
platform = DynamicModelMultipleChoiceField(queryset=Platform.objects.all(), to_field_name="name", required=False)
|
|
614
621
|
cluster_group = DynamicModelMultipleChoiceField(
|
|
615
622
|
queryset=ClusterGroup.objects.all(), to_field_name="name", required=False
|
nautobot/extras/jobs.py
CHANGED
|
@@ -468,6 +468,7 @@ class BaseJob:
|
|
|
468
468
|
label="Profile job execution",
|
|
469
469
|
help_text="Profiles the job execution using cProfile and outputs a report to /tmp/",
|
|
470
470
|
)
|
|
471
|
+
form.fields["_profile"].widget.attrs["class"] = "form-check-input"
|
|
471
472
|
# If the class already exists there may be overrides, so we have to check this.
|
|
472
473
|
try:
|
|
473
474
|
job_model = JobModel.objects.get(module_name=cls.__module__, job_class_name=cls.__name__)
|
|
@@ -484,6 +485,7 @@ class BaseJob:
|
|
|
484
485
|
label="Ignore singleton lock",
|
|
485
486
|
help_text="Allow this singleton job to run even when another instance is already running",
|
|
486
487
|
)
|
|
488
|
+
form.fields["_ignore_singleton_lock"].widget.attrs["class"] = "form-check-input"
|
|
487
489
|
|
|
488
490
|
if job_model is not None:
|
|
489
491
|
job_queue_queryset = JobQueue.objects.filter(jobs=job_model)
|
nautobot/extras/jobs_ui.py
CHANGED
|
@@ -165,10 +165,11 @@ class JobKeyValueOverrideValueTablePanel(KeyValueTablePanel):
|
|
|
165
165
|
else:
|
|
166
166
|
value_tag = format_html(
|
|
167
167
|
"""
|
|
168
|
-
<span
|
|
168
|
+
<span>
|
|
169
169
|
<span id="{unique_id}_value_{key}">{value}</span>
|
|
170
|
-
<button class="btn btn-
|
|
171
|
-
<span class="mdi mdi-content-copy"></span>
|
|
170
|
+
<button class="btn btn-secondary nb-btn-inline-hover" data-clipboard-target="#{unique_id}_value_{key}">
|
|
171
|
+
<span aria-hidden="true" class="mdi mdi-content-copy"></span>
|
|
172
|
+
<span class="visually-hidden">Copy</span>
|
|
172
173
|
</button>
|
|
173
174
|
</span>
|
|
174
175
|
""",
|
|
@@ -10,6 +10,7 @@ from nautobot.core.choices import ColorChoices
|
|
|
10
10
|
from nautobot.dcim import choices as dcim_choices
|
|
11
11
|
from nautobot.extras import choices as extras_choices
|
|
12
12
|
from nautobot.ipam import choices as ipam_choices
|
|
13
|
+
from nautobot.load_balancers import choices as load_balancer_choices
|
|
13
14
|
from nautobot.virtualization import choices as vm_choices
|
|
14
15
|
from nautobot.vpn import choices as vpn_choices
|
|
15
16
|
|
|
@@ -35,6 +36,7 @@ STATUS_CHOICESET_MAP = {
|
|
|
35
36
|
"ipam.Prefix": ipam_choices.PrefixStatusChoices,
|
|
36
37
|
"ipam.VLAN": ipam_choices.VLANStatusChoices,
|
|
37
38
|
"ipam.VRF": ipam_choices.VRFStatusChoices,
|
|
39
|
+
"load_balancers.LoadBalancerPoolMember": load_balancer_choices.LoadBalancerPoolMemberStatusChoices,
|
|
38
40
|
"virtualization.VirtualMachine": vm_choices.VirtualMachineStatusChoices,
|
|
39
41
|
"virtualization.VMInterface": vm_choices.VMInterfaceStatusChoices,
|
|
40
42
|
"vpn.VPNTunnel": vpn_choices.VPNTunnelStatusChoices,
|
|
@@ -14,4 +14,7 @@ class Command(BaseCommand):
|
|
|
14
14
|
dynamic_groups = DynamicGroup.objects.all()
|
|
15
15
|
|
|
16
16
|
for dynamic_group in dynamic_groups:
|
|
17
|
-
|
|
17
|
+
try:
|
|
18
|
+
dynamic_group.update_cached_members()
|
|
19
|
+
except Exception as err:
|
|
20
|
+
self.stderr.write(self.style.ERROR(f"Error while refreshing {dynamic_group}: {err}"))
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# Generated by Django 4.2.24 on 2025-09-26 19:15
|
|
2
|
+
|
|
3
|
+
from django.db import migrations, models
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class Migration(migrations.Migration):
|
|
7
|
+
dependencies = [
|
|
8
|
+
("dcim", "0074_alter_rack_u_height"),
|
|
9
|
+
("extras", "0130_jobresult_generate_log_entry_counts"),
|
|
10
|
+
]
|
|
11
|
+
|
|
12
|
+
operations = [
|
|
13
|
+
migrations.AddField(
|
|
14
|
+
model_name="configcontext",
|
|
15
|
+
name="device_families",
|
|
16
|
+
field=models.ManyToManyField(blank=True, related_name="+", to="dcim.devicefamily"),
|
|
17
|
+
),
|
|
18
|
+
]
|
|
@@ -4,7 +4,7 @@ from django.conf import settings
|
|
|
4
4
|
from django.contrib.auth.models import Group
|
|
5
5
|
from django.contrib.contenttypes.fields import GenericForeignKey
|
|
6
6
|
from django.contrib.contenttypes.models import ContentType
|
|
7
|
-
from django.core.exceptions import ValidationError
|
|
7
|
+
from django.core.exceptions import FieldError, ValidationError
|
|
8
8
|
from django.db import models
|
|
9
9
|
from django.utils import timezone
|
|
10
10
|
|
|
@@ -97,6 +97,16 @@ class ApprovalWorkflowDefinition(PrimaryModel):
|
|
|
97
97
|
"""Stringify instance."""
|
|
98
98
|
return self.name
|
|
99
99
|
|
|
100
|
+
def clean(self):
|
|
101
|
+
super().clean()
|
|
102
|
+
model_class = self.model_content_type.model_class()
|
|
103
|
+
if model_class is None:
|
|
104
|
+
raise ValidationError({"model_content_type": "Couldn't find corresponding model class. Is it installed?"})
|
|
105
|
+
try:
|
|
106
|
+
model_class.objects.filter(**self.model_constraints)
|
|
107
|
+
except (FieldError, AttributeError) as exc:
|
|
108
|
+
raise ValidationError({"model_constraints": f"Invalid query filter: {exc}"})
|
|
109
|
+
|
|
100
110
|
|
|
101
111
|
@extras_features(
|
|
102
112
|
"custom_links",
|
|
@@ -154,6 +154,10 @@ class ObjectChange(BaseModel):
|
|
|
154
154
|
def __str__(self):
|
|
155
155
|
return f"{self.changed_object_type} {self.object_repr} {self.get_action_display().lower()} by {self.user_name}"
|
|
156
156
|
|
|
157
|
+
@property
|
|
158
|
+
def page_title(self):
|
|
159
|
+
return f"{self.object_repr} - {self.time.strftime('%Y-%m-%d %H:%M')}"
|
|
160
|
+
|
|
157
161
|
def save(self, *args, **kwargs):
|
|
158
162
|
# Record the user's name and the object's representation as static strings
|
|
159
163
|
if not self.user_name:
|
nautobot/extras/models/jobs.py
CHANGED
|
@@ -1413,7 +1413,6 @@ class ScheduledJob(ApprovableModelMixin, BaseModel):
|
|
|
1413
1413
|
job_queue: Optional[JobQueue] = None,
|
|
1414
1414
|
task_queue: Optional[str] = None, # deprecated!
|
|
1415
1415
|
ignore_singleton_lock: bool = False,
|
|
1416
|
-
validated_save: bool = True,
|
|
1417
1416
|
**job_kwargs,
|
|
1418
1417
|
):
|
|
1419
1418
|
"""
|
|
@@ -1503,8 +1502,7 @@ class ScheduledJob(ApprovableModelMixin, BaseModel):
|
|
|
1503
1502
|
crontab=crontab,
|
|
1504
1503
|
job_queue=job_queue,
|
|
1505
1504
|
)
|
|
1506
|
-
|
|
1507
|
-
scheduled_job.validated_save()
|
|
1505
|
+
scheduled_job.validated_save()
|
|
1508
1506
|
return scheduled_job
|
|
1509
1507
|
|
|
1510
1508
|
create_schedule.__func__.alters_data = True
|
nautobot/extras/models/models.py
CHANGED
|
@@ -31,7 +31,13 @@ from nautobot.extras.choices import (
|
|
|
31
31
|
)
|
|
32
32
|
from nautobot.extras.constants import HTTP_CONTENT_TYPE_JSON
|
|
33
33
|
from nautobot.extras.models import ChangeLoggedModel
|
|
34
|
-
from nautobot.extras.models.mixins import
|
|
34
|
+
from nautobot.extras.models.mixins import (
|
|
35
|
+
ContactMixin,
|
|
36
|
+
DataComplianceModelMixin,
|
|
37
|
+
DynamicGroupsModelMixin,
|
|
38
|
+
NotesMixin,
|
|
39
|
+
SavedViewMixin,
|
|
40
|
+
)
|
|
35
41
|
from nautobot.extras.models.relationships import RelationshipModel
|
|
36
42
|
from nautobot.extras.querysets import ConfigContextQuerySet, NotesQuerySet
|
|
37
43
|
from nautobot.extras.utils import extras_features, FeatureQuery, image_upload
|
|
@@ -127,6 +133,7 @@ class ConfigContext(
|
|
|
127
133
|
tenant_groups = models.ManyToManyField(to="tenancy.TenantGroup", related_name="+", blank=True)
|
|
128
134
|
tenants = models.ManyToManyField(to="tenancy.Tenant", related_name="+", blank=True)
|
|
129
135
|
tags = models.ManyToManyField(to="extras.Tag", related_name="+", blank=True)
|
|
136
|
+
device_families = models.ManyToManyField("dcim.DeviceFamily", related_name="+", blank=True)
|
|
130
137
|
|
|
131
138
|
# Due to feature flag CONFIG_CONTEXT_DYNAMIC_GROUPS_ENABLED this field will remain empty unless set to True.
|
|
132
139
|
dynamic_groups = models.ManyToManyField(
|
|
@@ -687,6 +694,7 @@ class FileProxy(BaseModel):
|
|
|
687
694
|
class GraphQLQuery(
|
|
688
695
|
ChangeLoggedModel,
|
|
689
696
|
ContactMixin,
|
|
697
|
+
DataComplianceModelMixin,
|
|
690
698
|
DynamicGroupsModelMixin,
|
|
691
699
|
NotesMixin,
|
|
692
700
|
SavedViewMixin,
|
|
@@ -827,7 +835,7 @@ class ImageAttachment(BaseModel):
|
|
|
827
835
|
|
|
828
836
|
|
|
829
837
|
@extras_features("graphql", "webhooks")
|
|
830
|
-
class Note(ChangeLoggedModel, BaseModel):
|
|
838
|
+
class Note(ChangeLoggedModel, DataComplianceModelMixin, BaseModel):
|
|
831
839
|
"""
|
|
832
840
|
Notes allow anyone with proper permissions to add a note to an object.
|
|
833
841
|
"""
|
|
@@ -1,5 +1,29 @@
|
|
|
1
1
|
---
|
|
2
2
|
"apps":
|
|
3
|
+
- "name": "Ansible Automation"
|
|
4
|
+
"use_cases":
|
|
5
|
+
- "Network Automation"
|
|
6
|
+
- "Ansible Playbook Execution"
|
|
7
|
+
"requires": []
|
|
8
|
+
"docs": "https://docs.nautobot.com/projects/ansible-automation/en/stable/"
|
|
9
|
+
"headline": >-
|
|
10
|
+
Execute and monitor automation workflows from Redhat Ansible Automation Platform seamlessly without leaving
|
|
11
|
+
Nautobot.
|
|
12
|
+
"description": >-
|
|
13
|
+
Nautobot Ansible Automation seamlessly integrates automation workflows from Redhat Ansible Automation Platform
|
|
14
|
+
as Nautobot Jobs, allowing its users to run and visualize the output of such workflows directly within Nautobot.
|
|
15
|
+
The Nautobot App connects with Redhat AAP/AWX platforms in order to selectively import Job Templates and Workflows
|
|
16
|
+
so they can be triggered to run from Nautobot. Other features include: historical result synchronization, support
|
|
17
|
+
for input customization using surveys, and deeper integration using Nautobot inventory data.
|
|
18
|
+
"package_name": "nautobot_ansible_automation"
|
|
19
|
+
"author": "Network to Code (NTC)"
|
|
20
|
+
"display":
|
|
21
|
+
"cloud": true
|
|
22
|
+
"oss": true
|
|
23
|
+
"enterprise": true
|
|
24
|
+
"availability": "NTC License"
|
|
25
|
+
"icon": >-
|
|
26
|
+
data:image/png;base64,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
|
|
3
27
|
- "name": "BGP Models"
|
|
4
28
|
"use_cases":
|
|
5
29
|
- "Routing"
|
|
@@ -112,7 +136,6 @@
|
|
|
112
136
|
"availability": "Open Source"
|
|
113
137
|
"icon": >-
|
|
114
138
|
data:image/png;base64,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
|
|
115
|
-
# TODO: remove data_validation_engine from marketplace repo so it doesn't get reintroduced here by accident
|
|
116
139
|
- "name": "Design Builder"
|
|
117
140
|
"use_cases":
|
|
118
141
|
- "Network Design"
|
|
@@ -430,6 +453,31 @@
|
|
|
430
453
|
"availability": "Open Source"
|
|
431
454
|
"icon": >-
|
|
432
455
|
data:image/png;base64,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
|
|
456
|
+
- "name": "Version Control"
|
|
457
|
+
"use_cases":
|
|
458
|
+
- "Enterprise Governance"
|
|
459
|
+
- "Branching"
|
|
460
|
+
- "Approvals"
|
|
461
|
+
- "Data Management"
|
|
462
|
+
"requires": []
|
|
463
|
+
"docs": "https://docs.nautobot.com/projects/version-control/en/latest/"
|
|
464
|
+
"headline": >-
|
|
465
|
+
Allows users to have change (workflow) management with approvals when managing data within Nautobot ensuring
|
|
466
|
+
Enterprise can maintain governance of their data.
|
|
467
|
+
"description": >-
|
|
468
|
+
Version Control allows users to stage changes and have them reviewed by others before committing them. It offers
|
|
469
|
+
Git semantics when working with Nautobot using branch, commit, merge, and pull request concepts allowing users
|
|
470
|
+
to stage changes in a branch and have it be later merged after someone approves it in the UI or API. This app
|
|
471
|
+
requires a Dolt database.
|
|
472
|
+
"package_name": "nautobot_version_control"
|
|
473
|
+
"author": "Network to Code (NTC)"
|
|
474
|
+
"display":
|
|
475
|
+
"cloud": true
|
|
476
|
+
"oss": false
|
|
477
|
+
"enterprise": false
|
|
478
|
+
"availability": "NTC License"
|
|
479
|
+
"icon": >-
|
|
480
|
+
data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAMAAACdt4HsAAABoVBMVEUAAACvr6+wsLCxsbEAff8AfP8Ae/+BosVYlti1sq61sa7geAbmeADgeAe8oYPIlFvheAbheAiysrKvr6+wsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCvr6+wsLAAfP8AfP8Aff8Aff8Abf+xsbEAff8Aff8Cfv5Xlti7s6oAfP8AfP8kh++orrQAfP8jh++xsLACfv68tKsAef+wsLCwsLCwsLCvr6+xsbGwsLCvsLCxsLCvsLGrr7LCtqgPgfgAdP8Aff8Aff8AfP/CtagAdf8Aff/BtagAff8Aff+rrrL0eADueADfeAfgeAfgeAfuaADgeAbgeAfgeAffeQnIlFqss7vgeAbhdwTWgymyrajhdwSwsLHfeQnJlFqttLzjdQCwsLCwsLCwsLDfeAbheAawsLCwsLCwsLDheQawsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLBnm9FLkjVQAAAAiXRSTlMAAAAAAAAAAAAAAAAAAAAAAAAAAgkCeMLBhg72xfOVDRL8ls+eFggMCIcCCXjCAgL2xcQSCRLC88W/88LFCQmIwHoDA5oNlf6aDJoM+5YNDAz8DAINmgIJAnjCAgn2xcQSCRLC88W/wsUSCQn+Hd0CAk3X+AKM8EGTyAsza/2Qx+/cA6qLTKlqMjF60isAAAL+SURBVFjD7ZfbWxJBGMZlliV1tSgOu8ECghoJ0kpm2ZEsFEMp07IkpDLtqGVaeOhg2XH9q5uZZQ+4s7tDV174Xu3Dw/vb+Wa+eWe2peVQB0YuYCkXFQAAn5+oACUB+II8ScLJEB0B+PmwaPaLETkaoyJAgNhlLqBLkOMJKgIE8H7zBPqF7h46ggIg/Cr0RqkIlgD+VDJBQ7AG+EGMhmAHoCLYAmgIdgCGhmA/AgCSTmthCai31+nenngUdrUDwM02yGNocKFblvsCTgCWTaU1pVjWuMUEISL4HQGp/oym/jNHAJAM+0LknQHpzEBWsWcHzg6egzafvi94KkB2SClg6PyFYTTyoFo3LSCTViYwffHS8GVeDGumpgGZK4NXjXU3XUI2c63VaKIF6JMIx9I8oGEZU/8BaGgkNwngsjgqLDrRBIB+H/GosCtBeaf6HMrlSEeF5STi3QjfCf8hijidZJm0sUnLiADXI3A3iiOwHcGNkZGbKFnyeVI0EBrJCJAgAEgSGIXJlCTGtBVAKUGCJTAw2UbHCuO32nDA7Q8XqxLUSWTQ+sUShb3ihKcVJPNyLgCa60Tsj48XJ0u3Pe0IIIGmOlHxJ+5Mle6WJqYT5nxUG2lGb6QZQyfW/bE29l5psngfTyJDAHAdsw80zXZwKsClnQxudqq4V4ia/HVA58O5sqa5R0f1/q/7AWifHi+Mmf3qCCrl+apir84/fvJUCRSjHz0R3m8AVBcqWAvPFpd4JdL2+RMkvw4oVzisyvPFpRcoVCWGxk8AlF++eq00YYjCTyihWn5zDLsCueV80slPmkQ4FtwBK29lBWDnVwHvjMu46sVX2PfhtXVktPWrgM7ViqYPHIcBH2sbm/omZmxD9biX0+Xl8AhCW1vJ7c31eowwTV40oT7VcmB7Y01ejtr5La66MAvB5y9f+3a+hb/nbP3kyzbKwt0fcry28/PXimTrJ1/3URYGgr///I3VU8n2gyNA+NqQUB/tYvcJh7syikyS0M8u5vCT8KDrH3bO2ltvf7BdAAAAAElFTkSuQmCC
|
|
433
481
|
- "name": "Welcome Wizard"
|
|
434
482
|
"use_cases":
|
|
435
483
|
- "Onboarding"
|
nautobot/extras/plugins/views.py
CHANGED
|
@@ -141,11 +141,6 @@ class InstalledAppDetailView(GenericView):
|
|
|
141
141
|
items={
|
|
142
142
|
"*": [
|
|
143
143
|
ViewNameBreadcrumbItem(view_name="apps:apps_list", label="Installed Apps"),
|
|
144
|
-
ViewNameBreadcrumbItem(
|
|
145
|
-
view_name="apps:app_detail",
|
|
146
|
-
reverse_kwargs=lambda context: {"app": context["app_data"]["package"]},
|
|
147
|
-
label=lambda context: context["app_data"]["name"],
|
|
148
|
-
),
|
|
149
144
|
]
|
|
150
145
|
}
|
|
151
146
|
)
|
nautobot/extras/querysets.py
CHANGED
|
@@ -19,6 +19,9 @@ class ConfigContextQuerySet(RestrictedQuerySet):
|
|
|
19
19
|
# `device_type` for Device; `type` for VirtualMachine
|
|
20
20
|
device_type = getattr(obj, "device_type", None)
|
|
21
21
|
|
|
22
|
+
# `device_family` for Device;
|
|
23
|
+
device_family = getattr(device_type, "device_family", None)
|
|
24
|
+
|
|
22
25
|
device_redundancy_group = getattr(obj, "device_redundancy_group", None)
|
|
23
26
|
|
|
24
27
|
# Get the group of the assigned tenant, if any
|
|
@@ -40,6 +43,7 @@ class ConfigContextQuerySet(RestrictedQuerySet):
|
|
|
40
43
|
Q(locations__in=locations) | Q(locations=None),
|
|
41
44
|
Q(roles=role) | Q(roles=None),
|
|
42
45
|
Q(device_types=device_type) | Q(device_types=None),
|
|
46
|
+
Q(device_families=device_family) | Q(device_families=None),
|
|
43
47
|
Q(platforms=obj.platform) | Q(platforms=None),
|
|
44
48
|
Q(device_redundancy_groups=device_redundancy_group) | Q(device_redundancy_groups=None),
|
|
45
49
|
Q(tenant_groups__in=tenant_groups) | Q(tenant_groups=None),
|
|
@@ -136,6 +140,7 @@ class ConfigContextModelQuerySet(RestrictedQuerySet):
|
|
|
136
140
|
if self.model._meta.model_name == "device":
|
|
137
141
|
location_query_string = "location"
|
|
138
142
|
base_query.add((Q(device_types=OuterRef("device_type")) | Q(device_types=None)), Q.AND)
|
|
143
|
+
base_query.add((Q(device_families=OuterRef("device_type__device_family")) | Q(device_families=None)), Q.AND)
|
|
139
144
|
base_query.add(
|
|
140
145
|
(Q(device_redundancy_groups=OuterRef("device_redundancy_group")) | Q(device_redundancy_groups=None)),
|
|
141
146
|
Q.AND,
|
|
@@ -145,6 +150,9 @@ class ConfigContextModelQuerySet(RestrictedQuerySet):
|
|
|
145
150
|
base_query.add((Q(cluster_groups=OuterRef("clusters__cluster_group")) | Q(cluster_groups=None)), Q.AND)
|
|
146
151
|
else:
|
|
147
152
|
location_query_string = "cluster__location"
|
|
153
|
+
base_query.add(Q(device_types=None), Q.AND)
|
|
154
|
+
base_query.add(Q(device_families=None), Q.AND)
|
|
155
|
+
base_query.add(Q(device_redundancy_groups=None), Q.AND)
|
|
148
156
|
# For virtual machines, handle cluster as ForeignKey relationship
|
|
149
157
|
base_query.add((Q(clusters=OuterRef("cluster")) | Q(clusters=None)), Q.AND)
|
|
150
158
|
base_query.add((Q(cluster_groups=OuterRef("cluster__cluster_group")) | Q(cluster_groups=None)), Q.AND)
|
nautobot/extras/tables.py
CHANGED
|
@@ -1161,6 +1161,7 @@ class JobTable(BaseTable):
|
|
|
1161
1161
|
|
|
1162
1162
|
class JobHookTable(BaseTable):
|
|
1163
1163
|
pk = ToggleColumn()
|
|
1164
|
+
enabled = BooleanColumn()
|
|
1164
1165
|
name = tables.Column(linkify=True)
|
|
1165
1166
|
content_types = tables.TemplateColumn(WEBHOOK_CONTENT_TYPES)
|
|
1166
1167
|
job = tables.Column(linkify=True)
|
|
@@ -1478,12 +1479,20 @@ class ScheduledJobTable(BaseTable):
|
|
|
1478
1479
|
pk = ToggleColumn()
|
|
1479
1480
|
name = tables.Column(linkify=True)
|
|
1480
1481
|
job_model = tables.Column(verbose_name="Job", linkify=True)
|
|
1482
|
+
enabled = BooleanColumn()
|
|
1481
1483
|
interval = tables.Column(verbose_name="Execution Type")
|
|
1482
1484
|
start_time = tables.DateTimeColumn(verbose_name="First Run", format=settings.SHORT_DATETIME_FORMAT)
|
|
1483
1485
|
last_run_at = tables.DateTimeColumn(verbose_name="Most Recent Run", format=settings.SHORT_DATETIME_FORMAT)
|
|
1484
1486
|
crontab = tables.Column()
|
|
1485
1487
|
total_run_count = tables.Column(verbose_name="Total Run Count")
|
|
1486
1488
|
actions = ButtonsColumn(ScheduledJob, buttons=("delete",), prepend_template=SCHEDULED_JOB_BUTTONS)
|
|
1489
|
+
approval_state = tables.Column(empty_values=[], orderable=False)
|
|
1490
|
+
|
|
1491
|
+
def render_approval_state(self, record):
|
|
1492
|
+
workflow = record.associated_approval_workflows.first()
|
|
1493
|
+
if workflow is not None:
|
|
1494
|
+
return format_html('<a href="{}">{}</a>', record.get_approval_workflow_url(), workflow.current_state)
|
|
1495
|
+
return HTML_NONE
|
|
1487
1496
|
|
|
1488
1497
|
class Meta(BaseTable.Meta):
|
|
1489
1498
|
model = ScheduledJob
|
|
@@ -1492,6 +1501,7 @@ class ScheduledJobTable(BaseTable):
|
|
|
1492
1501
|
"name",
|
|
1493
1502
|
"total_run_count",
|
|
1494
1503
|
"job_model",
|
|
1504
|
+
"approval_state",
|
|
1495
1505
|
"interval",
|
|
1496
1506
|
"start_time",
|
|
1497
1507
|
"last_run_at",
|
|
@@ -1503,6 +1513,8 @@ class ScheduledJobTable(BaseTable):
|
|
|
1503
1513
|
"pk",
|
|
1504
1514
|
"name",
|
|
1505
1515
|
"job_model",
|
|
1516
|
+
"enabled",
|
|
1517
|
+
"approval_state",
|
|
1506
1518
|
"interval",
|
|
1507
1519
|
"last_run_at",
|
|
1508
1520
|
"actions",
|
|
@@ -38,6 +38,8 @@ Ref: https://github.com/nautobot/nautobot/issues/1289
|
|
|
38
38
|
|
|
39
39
|
_replace_links_{{ ajax_divname }}(url, div.getElementsByTagName('TH'));
|
|
40
40
|
_replace_links_{{ ajax_divname }}(url, div.getElementsByClassName('pagination'));
|
|
41
|
+
/* Hook back up the JS for the "per_page" dropdown, if present for this table */
|
|
42
|
+
initializeResultPerPageSelection(div);
|
|
41
43
|
}
|
|
42
44
|
}
|
|
43
45
|
};
|