nautobot 2.0.0a3__py3-none-any.whl → 2.0.0b1__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/api.py +6 -8
- nautobot/apps/forms.py +0 -2
- nautobot/apps/ui.py +0 -8
- nautobot/circuits/api/serializers.py +9 -117
- nautobot/circuits/api/urls.py +1 -1
- nautobot/circuits/api/views.py +0 -1
- nautobot/circuits/forms.py +0 -65
- nautobot/circuits/migrations/0014_related_name_changes.py +1 -1
- nautobot/circuits/migrations/0016_tagsfield.py +34 -0
- nautobot/circuits/migrations/0017_fixup_null_statuses.py +22 -0
- nautobot/circuits/migrations/0018_status_nonnullable.py +22 -0
- nautobot/circuits/models.py +3 -87
- nautobot/circuits/navigation.py +14 -69
- nautobot/circuits/signals.py +0 -2
- nautobot/circuits/tables.py +39 -1
- nautobot/circuits/tests/integration/test_relationships.py +9 -9
- nautobot/circuits/tests/test_api.py +4 -8
- nautobot/circuits/tests/test_filters.py +10 -4
- nautobot/circuits/tests/test_models.py +5 -1
- nautobot/circuits/tests/test_views.py +27 -5
- nautobot/circuits/views.py +18 -10
- nautobot/core/api/__init__.py +8 -2
- nautobot/core/api/fields.py +15 -6
- nautobot/core/api/filter_backends.py +3 -2
- nautobot/core/api/metadata.py +237 -30
- nautobot/core/api/mixins.py +94 -0
- nautobot/core/api/pagination.py +4 -0
- nautobot/core/api/parsers.py +154 -0
- nautobot/core/api/renderers.py +153 -2
- nautobot/core/api/schema.py +46 -2
- nautobot/core/api/serializers.py +377 -35
- nautobot/core/api/urls.py +11 -3
- nautobot/core/api/utils.py +174 -2
- nautobot/core/api/versioning.py +32 -10
- nautobot/core/api/views.py +266 -72
- nautobot/core/apps/__init__.py +138 -220
- nautobot/core/celery/__init__.py +112 -41
- nautobot/core/celery/backends.py +19 -12
- nautobot/core/celery/control.py +46 -0
- nautobot/core/celery/encoders.py +53 -0
- nautobot/core/celery/log.py +38 -0
- nautobot/core/celery/schedulers.py +23 -4
- nautobot/core/celery/task.py +1 -16
- nautobot/core/checks.py +0 -27
- nautobot/core/choices.py +0 -113
- nautobot/core/{cli.py → cli/__init__.py} +1 -1
- nautobot/core/cli/__main__.py +3 -0
- nautobot/core/constants.py +0 -24
- nautobot/core/context_processors.py +12 -0
- nautobot/core/filters.py +2 -2
- nautobot/core/forms/__init__.py +0 -4
- nautobot/core/forms/fields.py +38 -65
- nautobot/core/forms/forms.py +4 -1
- nautobot/core/forms/utils.py +0 -52
- nautobot/core/graphql/schema.py +4 -27
- nautobot/core/jobs/__init__.py +75 -0
- nautobot/core/management/commands/build_ui.py +255 -0
- nautobot/core/management/commands/generate_test_data.py +3 -2
- nautobot/core/management/commands/post_upgrade.py +24 -24
- nautobot/core/models/__init__.py +26 -1
- nautobot/core/models/fields.py +24 -5
- nautobot/core/models/generics.py +2 -42
- nautobot/core/models/managers.py +5 -0
- nautobot/core/models/name_color_content_types.py +0 -14
- nautobot/core/models/tree_queries.py +14 -4
- nautobot/core/models/utils.py +5 -6
- nautobot/core/models/validators.py +17 -8
- nautobot/core/releases.py +8 -10
- nautobot/core/settings.py +80 -42
- nautobot/core/tables.py +5 -5
- nautobot/core/tasks.py +4 -7
- nautobot/core/templates/base.html +1 -49
- nautobot/core/templates/base_django.html +49 -0
- nautobot/core/templates/base_react.html +55 -0
- nautobot/core/templates/buttons/export.html +6 -4
- nautobot/core/templates/generic/object_bulk_create.html +10 -21
- nautobot/core/templates/generic/object_list.html +3 -1
- nautobot/core/templates/generic/object_retrieve_plugin_full_width.html +3 -0
- nautobot/core/templates/inc/footer.html +1 -0
- nautobot/core/templates/inc/javascript.html +0 -14
- nautobot/core/templates/inc/nav_menu.html +28 -33
- nautobot/core/templates/inc/object_details_advanced_panel.html +13 -0
- nautobot/core/templates/inc/relationships_table_rows.html +2 -2
- nautobot/core/templates/nautobot_config.py.j2 +8 -20
- nautobot/core/templates/plugin_template/__init__.py-tpl +1 -2
- nautobot/core/templates/rest_framework/api.html +8 -0
- nautobot/core/templatetags/buttons.py +32 -28
- nautobot/core/testing/__init__.py +47 -44
- nautobot/core/testing/api.py +362 -47
- nautobot/core/testing/filters.py +1 -1
- nautobot/core/testing/migrations.py +2 -0
- nautobot/core/testing/mixins.py +22 -9
- nautobot/core/testing/schema.py +2 -1
- nautobot/core/testing/views.py +21 -46
- nautobot/core/tests/integration/test_filters.py +17 -8
- nautobot/core/tests/integration/test_navbar.py +11 -34
- nautobot/core/tests/integration/test_plugin_navbar.py +9 -103
- nautobot/core/tests/nautobot_config.py +2 -3
- nautobot/core/tests/test_api.py +290 -21
- nautobot/core/tests/test_checks.py +0 -7
- nautobot/core/tests/test_filters.py +107 -59
- nautobot/core/tests/test_forms.py +26 -92
- nautobot/core/tests/test_graphql.py +110 -77
- nautobot/core/tests/test_logging.py +4 -0
- nautobot/core/tests/test_managers.py +3 -1
- nautobot/core/tests/test_models.py +2 -0
- nautobot/core/tests/test_paginator.py +3 -1
- nautobot/core/tests/test_releases.py +12 -12
- nautobot/core/tests/test_templatetags_helpers.py +4 -4
- nautobot/core/tests/test_utils.py +32 -68
- nautobot/core/tests/test_views.py +12 -15
- nautobot/core/utils/data.py +17 -0
- nautobot/core/utils/deprecation.py +9 -6
- nautobot/core/utils/filtering.py +8 -3
- nautobot/core/utils/git.py +12 -4
- nautobot/core/utils/lookup.py +3 -1
- nautobot/core/utils/requests.py +1 -104
- nautobot/core/views/__init__.py +1 -0
- nautobot/core/views/generic.py +75 -110
- nautobot/core/views/mixins.py +52 -61
- nautobot/core/views/renderers.py +6 -7
- nautobot/core/views/utils.py +80 -0
- nautobot/dcim/api/serializers.py +160 -667
- nautobot/dcim/api/urls.py +1 -1
- nautobot/dcim/api/views.py +7 -44
- nautobot/dcim/choices.py +2 -0
- nautobot/dcim/filters/__init__.py +21 -0
- nautobot/dcim/form_mixins.py +1 -27
- nautobot/dcim/forms.py +19 -765
- nautobot/dcim/migrations/0024_alter_device_and_rack_role_add_new_role.py +2 -1
- nautobot/dcim/migrations/0025_device_and_rack_roles_data_migrations.py +19 -13
- nautobot/dcim/migrations/0027_remove_device_role_and_rack_role.py +1 -1
- nautobot/dcim/migrations/0028_rename_foreignkey_fields.py +1 -1
- nautobot/dcim/migrations/0030_migrate_region_and_site_data_to_locations.py +2 -2
- nautobot/dcim/migrations/0035_related_name_changes.py +1 -1
- nautobot/dcim/migrations/0036_remove_region_and_site.py +1 -1
- nautobot/dcim/migrations/0040_tagsfield.py +109 -0
- nautobot/dcim/migrations/{0040_ipam__namespaces.py → 0041_ipam__namespaces.py} +1 -1
- nautobot/dcim/migrations/0042_fixup_null_statuses.py +51 -0
- nautobot/dcim/migrations/0043_status_nonnullable.py +72 -0
- nautobot/dcim/models/cables.py +3 -33
- nautobot/dcim/models/device_component_templates.py +6 -0
- nautobot/dcim/models/device_components.py +12 -198
- nautobot/dcim/models/devices.py +30 -143
- nautobot/dcim/models/locations.py +3 -64
- nautobot/dcim/models/power.py +3 -50
- nautobot/dcim/models/racks.py +7 -84
- nautobot/dcim/navigation.py +141 -467
- nautobot/dcim/signals.py +0 -2
- nautobot/dcim/tables/locations.py +2 -2
- nautobot/dcim/tables/power.py +1 -2
- nautobot/dcim/templates/dcim/console_port_connection_list.html +7 -0
- nautobot/dcim/templates/dcim/devicetype.html +2 -2
- nautobot/dcim/templates/dcim/interface_connection_list.html +7 -0
- nautobot/dcim/templates/dcim/location.html +16 -1
- nautobot/dcim/templates/dcim/locationtype.html +15 -0
- nautobot/dcim/templates/dcim/power_port_connection_list.html +7 -0
- nautobot/dcim/templates/dcim/rackgroup.html +0 -12
- nautobot/dcim/tests/test_api.py +166 -81
- nautobot/dcim/tests/test_cablepaths.py +41 -35
- nautobot/dcim/tests/test_filters.py +67 -23
- nautobot/dcim/tests/test_forms.py +5 -205
- nautobot/dcim/tests/test_graphql.py +7 -2
- nautobot/dcim/tests/test_migrations.py +6 -11
- nautobot/dcim/tests/test_models.py +182 -110
- nautobot/dcim/tests/test_natural_ordering.py +11 -8
- nautobot/dcim/tests/test_signals.py +6 -3
- nautobot/dcim/tests/test_views.py +197 -175
- nautobot/dcim/urls.py +11 -16
- nautobot/dcim/views.py +7 -134
- nautobot/docs/additional-features/caching.md +6 -87
- nautobot/docs/additional-features/job-scheduling-and-approvals.md +3 -0
- nautobot/docs/additional-features/jobs.md +177 -195
- nautobot/docs/administration/nautobot-server.md +6 -21
- nautobot/docs/administration/replicating-nautobot.md +0 -10
- nautobot/docs/configuration/optional-settings.md +32 -41
- nautobot/docs/configuration/required-settings.md +11 -52
- nautobot/docs/development/application-registry.md +2 -13
- nautobot/docs/development/extending-models.md +15 -17
- nautobot/docs/development/generic-views.md +0 -2
- nautobot/docs/development/getting-started.md +55 -5
- nautobot/docs/development/navigation-menu.md +22 -93
- nautobot/docs/development/react-ui.md +105 -0
- nautobot/docs/development/role-internals.md +1 -3
- nautobot/docs/development/style-guide.md +6 -4
- nautobot/docs/index.md +3 -2
- nautobot/docs/installation/migrating-from-netbox.md +11 -42
- nautobot/docs/installation/nautobot.md +1 -1
- nautobot/docs/installation/tables/v2-api-behavior-changes.yaml +70 -0
- nautobot/docs/installation/tables/v2-api-removed-fields.yaml +142 -0
- nautobot/docs/installation/tables/v2-api-renamed-fields.yaml +124 -0
- nautobot/docs/installation/tables/v2-code-location-changes.yaml +241 -0
- nautobot/docs/installation/tables/v2-code-removals.yaml +67 -0
- nautobot/docs/installation/tables/v2-database-behavior-changes.yaml +37 -0
- nautobot/docs/installation/tables/v2-database-removed-fields.yaml +166 -0
- nautobot/docs/installation/tables/v2-database-renamed-fields.yaml +340 -0
- nautobot/docs/installation/tables/v2-filters-corrected-fields.yaml +28 -0
- nautobot/docs/installation/tables/v2-filters-enhanced-fields.yaml +241 -0
- nautobot/docs/installation/tables/v2-filters-removed-fields.yaml +553 -0
- nautobot/docs/installation/tables/v2-filters-renamed-fields.yaml +223 -0
- nautobot/docs/installation/tables/v2-logging-renamed-loggers.yaml +23 -0
- nautobot/docs/installation/upgrading-from-nautobot-v1.md +170 -747
- nautobot/docs/models/dcim/device.md +3 -0
- nautobot/docs/models/dcim/deviceredundancygroup.md +3 -3
- nautobot/docs/models/extras/computedfield.md +4 -4
- nautobot/docs/models/extras/gitrepository.md +3 -0
- nautobot/docs/models/extras/job.md +1 -0
- nautobot/docs/models/extras/jobbutton.md +18 -13
- nautobot/docs/models/extras/jobhook.md +7 -4
- nautobot/docs/models/extras/jobresult.md +6 -2
- nautobot/docs/models/extras/relationship.md +2 -2
- nautobot/docs/models/extras/status.md +6 -19
- nautobot/docs/models/ipam/ipaddress.md +3 -0
- nautobot/docs/models/virtualization/virtualmachine.md +3 -0
- nautobot/docs/plugins/development.md +83 -21
- nautobot/docs/release-notes/version-1.5.md +53 -0
- nautobot/docs/release-notes/version-2.0.md +180 -0
- nautobot/docs/requirements.txt +1 -0
- nautobot/docs/rest-api/overview.md +384 -215
- nautobot/docs/rest-api/ui-related-endpoints.md +9 -0
- nautobot/extras/admin.py +3 -5
- nautobot/extras/api/customfields.py +15 -39
- nautobot/extras/api/fields.py +0 -11
- nautobot/extras/api/mixins.py +45 -0
- nautobot/extras/api/relationships.py +63 -158
- nautobot/extras/api/serializers.py +165 -700
- nautobot/extras/api/urls.py +1 -1
- nautobot/extras/api/views.py +294 -280
- nautobot/extras/apps.py +4 -7
- nautobot/extras/choices.py +11 -9
- nautobot/extras/constants.py +9 -3
- nautobot/extras/datasources/__init__.py +2 -0
- nautobot/extras/datasources/git.py +135 -186
- nautobot/extras/datasources/registry.py +25 -35
- nautobot/extras/filters/__init__.py +20 -19
- nautobot/extras/filters/mixins.py +4 -4
- nautobot/extras/forms/forms.py +63 -127
- nautobot/extras/forms/mixins.py +23 -51
- nautobot/extras/health_checks.py +0 -33
- nautobot/extras/jobs.py +387 -565
- nautobot/extras/management/commands/runjob.py +24 -62
- nautobot/extras/managers.py +30 -7
- nautobot/extras/migrations/0058_jobresult_add_time_status_idxs.py +38 -0
- nautobot/extras/migrations/{0058_joblogentry_scheduledjob_webhook_data_migration.py → 0059_joblogentry_scheduledjob_webhook_data_migration.py} +1 -1
- nautobot/extras/migrations/{0059_alter_joblogentry_scheduledjob_webhook_fields.py → 0060_alter_joblogentry_scheduledjob_webhook_fields.py} +1 -1
- nautobot/extras/migrations/{0060_role_and_alter_status.py → 0061_role_and_alter_status.py} +1 -7
- nautobot/extras/migrations/{0061_collect_roles_from_related_apps_roles.py → 0062_collect_roles_from_related_apps_roles.py} +33 -32
- nautobot/extras/migrations/{0062_alter_role_options.py → 0063_alter_role_options.py} +1 -1
- nautobot/extras/migrations/{0063_alter_configcontext_and_add_new_role.py → 0064_alter_configcontext_and_add_new_role.py} +1 -1
- nautobot/extras/migrations/0065_configcontext_data_migrations.py +44 -0
- nautobot/extras/migrations/{0065_rename_configcontext_role.py → 0066_rename_configcontext_role.py} +1 -1
- nautobot/extras/migrations/{0066_jobresult__add_celery_fields.py → 0067_jobresult__add_celery_fields.py} +36 -2
- nautobot/extras/migrations/{0067_created_datetime.py → 0068_created_datetime.py} +1 -1
- nautobot/extras/migrations/{0068_remove_site_and_region_attributes_from_config_context.py → 0069_remove_site_and_region_attributes_from_config_context.py} +1 -1
- nautobot/extras/migrations/{0069_replace_related_names.py → 0070_replace_related_names.py} +1 -1
- nautobot/extras/migrations/{0070_rename_model_fields.py → 0071_rename_model_fields.py} +1 -1
- nautobot/extras/migrations/0072_job__unique_name_data_migration.py +86 -0
- nautobot/extras/migrations/{0072_job__unique_name.py → 0073_job__unique_name.py} +13 -9
- nautobot/extras/migrations/{0073_remove_gitrepository_fields.py → 0074_remove_gitrepository_fields.py} +1 -1
- nautobot/extras/migrations/{0074_rename_slug_to_key_for_custom_field.py → 0075_rename_slug_to_key_for_custom_field.py} +1 -1
- nautobot/extras/migrations/{0075_migrate_custom_field_data.py → 0076_migrate_custom_field_data.py} +1 -1
- nautobot/extras/migrations/{0076_remove_name_field_and_make_label_field_non_nullable.py → 0077_remove_name_field_and_make_label_field_non_nullable.py} +1 -1
- nautobot/extras/migrations/{0077_remove_slug.py → 0078_remove_slug.py} +1 -5
- nautobot/extras/migrations/0079_tagsfield.py +28 -0
- nautobot/extras/migrations/0080_rename_relationship_slug_to_key.py +17 -0
- nautobot/extras/migrations/0081_rename_relationship_name_to_label.py +29 -0
- nautobot/extras/migrations/0082_ensure_relationship_keys_are_unique.py +43 -0
- nautobot/extras/migrations/0083_rename_computed_field_slug_to_key.py +21 -0
- nautobot/extras/migrations/0084_taggeditem_cleanup.py +43 -0
- nautobot/extras/migrations/0085_taggeditem_uniqueness.py +22 -0
- nautobot/extras/migrations/0086_job__celery_task_fields__dryrun_support.py +81 -0
- nautobot/extras/migrations/0087_job__commit_default_data_migration.py +26 -0
- nautobot/extras/migrations/0088_joblogentry__log_level_default.py +17 -0
- nautobot/extras/migrations/0089_joblogentry__log_level_data_migration.py +34 -0
- nautobot/extras/migrations/0090_scheduledjob__data_migration.py +57 -0
- nautobot/extras/models/__init__.py +2 -3
- nautobot/extras/models/change_logging.py +0 -36
- nautobot/extras/models/customfields.py +39 -33
- nautobot/extras/models/datasources.py +48 -50
- nautobot/extras/models/groups.py +5 -6
- nautobot/extras/models/jobs.py +189 -321
- nautobot/extras/models/mixins.py +0 -71
- nautobot/extras/models/models.py +0 -19
- nautobot/extras/models/relationships.py +19 -13
- nautobot/extras/models/roles.py +0 -34
- nautobot/extras/models/secrets.py +2 -26
- nautobot/extras/models/statuses.py +6 -5
- nautobot/extras/models/tags.py +2 -17
- nautobot/extras/navigation.py +89 -307
- nautobot/extras/plugins/__init__.py +3 -120
- nautobot/extras/plugins/utils.py +0 -3
- nautobot/extras/plugins/validators.py +5 -4
- nautobot/extras/plugins/views.py +16 -3
- nautobot/extras/querysets.py +1 -7
- nautobot/extras/registry.py +3 -0
- nautobot/extras/signals.py +26 -60
- nautobot/extras/tables.py +34 -40
- nautobot/extras/tasks.py +0 -12
- nautobot/extras/templates/extras/configcontext.html +1 -1
- nautobot/extras/templates/extras/configcontextschema.html +16 -1
- nautobot/extras/templates/extras/customfield.html +0 -13
- nautobot/extras/templates/extras/gitrepository.html +3 -3
- nautobot/extras/templates/extras/inc/jobresult.html +10 -0
- nautobot/extras/templates/extras/inc/panel_jobhistory.html +1 -1
- nautobot/extras/templates/extras/job.html +35 -25
- nautobot/extras/templates/extras/job_approval_request.html +15 -30
- nautobot/extras/templates/extras/job_detail.html +13 -31
- nautobot/extras/templates/extras/job_edit.html +15 -17
- nautobot/extras/templates/extras/jobresult.html +24 -6
- nautobot/extras/templates/extras/scheduledjob.html +2 -2
- nautobot/extras/templates/extras/secret.html +28 -0
- nautobot/extras/templatetags/job_buttons.py +1 -0
- nautobot/extras/{tests/example_jobs → test_jobs}/api_test_job.py +13 -6
- nautobot/extras/test_jobs/atomic_transaction.py +53 -0
- nautobot/extras/test_jobs/dry_run.py +29 -0
- nautobot/extras/{tests/example_jobs/test_duplicate_name.py → test_jobs/duplicate_name.py} +4 -0
- nautobot/extras/test_jobs/duplicate_name2.py +9 -0
- nautobot/extras/test_jobs/fail.py +23 -0
- nautobot/extras/{tests/example_jobs/test_field_default.py → test_jobs/field_default.py} +4 -0
- nautobot/extras/{tests/example_jobs/test_field_order.py → test_jobs/field_order.py} +4 -0
- nautobot/extras/{tests/example_jobs/test_file_upload_fail.py → test_jobs/file_upload_fail.py} +11 -6
- nautobot/extras/test_jobs/file_upload_pass.py +25 -0
- nautobot/extras/test_jobs/has_sensitive_variables.py +25 -0
- nautobot/extras/test_jobs/ipaddress_vars.py +66 -0
- nautobot/extras/test_jobs/job_button_receiver.py +28 -0
- nautobot/extras/test_jobs/job_hook_receiver.py +29 -0
- nautobot/extras/test_jobs/job_variables.py +88 -0
- nautobot/extras/test_jobs/location_with_custom_field.py +45 -0
- nautobot/extras/test_jobs/log_redaction.py +20 -0
- nautobot/extras/test_jobs/log_skip_db_logging.py +17 -0
- nautobot/extras/test_jobs/modify_db.py +25 -0
- nautobot/extras/{tests/example_jobs/test_no_field_order.py → test_jobs/no_field_order.py} +4 -0
- nautobot/extras/test_jobs/object_var_optional.py +21 -0
- nautobot/extras/test_jobs/object_var_required.py +21 -0
- nautobot/extras/test_jobs/object_vars.py +26 -0
- nautobot/extras/test_jobs/pass.py +25 -0
- nautobot/extras/test_jobs/profiling.py +32 -0
- nautobot/extras/test_jobs/read_only_job.py +15 -0
- nautobot/extras/{tests/example_jobs/test_required_args.py → test_jobs/required_args.py} +4 -0
- nautobot/extras/{tests/example_jobs/test_soft_time_limit_greater_than_time_limit.py → test_jobs/soft_time_limit_greater_than_time_limit.py} +5 -1
- nautobot/extras/{tests/example_jobs/test_task_queues.py → test_jobs/task_queues.py} +5 -1
- nautobot/extras/tests/integration/test_computedfields.py +1 -1
- nautobot/extras/tests/integration/test_configcontextschema.py +5 -3
- nautobot/extras/tests/integration/test_customfields.py +4 -2
- nautobot/extras/tests/integration/test_dynamicgroups.py +1 -1
- nautobot/extras/tests/integration/test_jobs.py +25 -27
- nautobot/extras/tests/integration/test_notes.py +8 -4
- nautobot/extras/tests/integration/test_relationships.py +2 -2
- nautobot/extras/tests/test_api.py +649 -642
- nautobot/extras/tests/test_changelog.py +3 -3
- nautobot/extras/tests/test_context_managers.py +5 -3
- nautobot/extras/tests/test_customfields.py +92 -50
- nautobot/extras/tests/test_datasources.py +189 -112
- nautobot/extras/tests/test_dynamicgroups.py +7 -8
- nautobot/extras/tests/test_filters.py +137 -89
- nautobot/extras/tests/test_forms.py +73 -75
- nautobot/extras/tests/{test_scripts.py → test_job_variables.py} +43 -49
- nautobot/extras/tests/test_jobs.py +262 -263
- nautobot/extras/tests/test_migrations.py +4 -3
- nautobot/extras/tests/test_models.py +116 -161
- nautobot/extras/tests/test_plugins.py +38 -60
- nautobot/extras/tests/test_relationships.py +167 -120
- nautobot/extras/tests/test_tags.py +6 -11
- nautobot/extras/tests/test_utils.py +31 -1
- nautobot/extras/tests/test_views.py +201 -145
- nautobot/extras/tests/test_webhooks.py +6 -2
- nautobot/extras/urls.py +42 -42
- nautobot/extras/utils.py +137 -163
- nautobot/extras/views.py +78 -152
- nautobot/ipam/api/fields.py +17 -0
- nautobot/ipam/api/serializers.py +58 -164
- nautobot/ipam/api/urls.py +1 -1
- nautobot/ipam/api/views.py +3 -2
- nautobot/ipam/apps.py +1 -2
- nautobot/ipam/filters.py +1 -10
- nautobot/ipam/forms.py +4 -177
- nautobot/ipam/lookups.py +1 -0
- nautobot/ipam/management/commands/__init__.py +0 -0
- nautobot/ipam/management/commands/fix_prefix_broadcast.py +17 -0
- nautobot/ipam/migrations/0010_alter_ipam_role_add_new_role.py +1 -1
- nautobot/ipam/migrations/0011_migrate_ipam_role_data.py +32 -38
- nautobot/ipam/migrations/0020_related_name_changes.py +1 -1
- nautobot/ipam/migrations/0022_aggregate_to_prefix_data_migration.py +2 -2
- nautobot/ipam/migrations/0028_tagsfield.py +44 -0
- nautobot/ipam/migrations/0029_ip_address_to_interface_uniqueness_constraints.py +18 -0
- nautobot/ipam/migrations/{0028_ipam__namespaces.py → 0030_ipam__namespaces.py} +77 -28
- nautobot/ipam/migrations/0031_ipam__prefix__add_parent.py +58 -0
- nautobot/ipam/migrations/0032_ipam__namespaces_finish.py +63 -0
- nautobot/ipam/migrations/0033_fixup_null_statuses.py +26 -0
- nautobot/ipam/migrations/0034_status_nonnullable.py +36 -0
- nautobot/ipam/models.py +100 -236
- nautobot/ipam/navigation.py +36 -181
- nautobot/ipam/querysets.py +20 -25
- nautobot/ipam/signals.py +49 -6
- nautobot/ipam/tables.py +10 -3
- nautobot/ipam/templates/ipam/namespace_ipaddresses.html +11 -0
- nautobot/ipam/templates/ipam/namespace_prefixes.html +11 -0
- nautobot/ipam/templates/ipam/namespace_retrieve.html +17 -4
- nautobot/ipam/templates/ipam/namespace_vrfs.html +11 -0
- nautobot/ipam/templates/ipam/prefix.html +1 -1
- nautobot/ipam/templates/ipam/vlangroup.html +0 -13
- nautobot/ipam/templates/ipam/vrf_edit.html +6 -0
- nautobot/ipam/tests/integration/test_prefixes.py +3 -26
- nautobot/ipam/tests/test_api.py +22 -19
- nautobot/ipam/tests/test_filters.py +59 -23
- nautobot/ipam/tests/test_migrations.py +6 -10
- nautobot/ipam/tests/test_models.py +323 -198
- nautobot/ipam/tests/test_ordering.py +2 -2
- nautobot/ipam/tests/test_querysets.py +44 -24
- nautobot/ipam/tests/test_views.py +73 -26
- nautobot/ipam/urls.py +16 -0
- nautobot/ipam/{utils.py → utils/__init__.py} +2 -2
- nautobot/ipam/utils/migrations.py +713 -0
- nautobot/ipam/views.py +137 -20
- nautobot/project-static/docs/404.html +1178 -10
- nautobot/project-static/docs/additional-features/caching.html +1224 -159
- nautobot/project-static/docs/additional-features/change-logging.html +1180 -12
- nautobot/project-static/docs/additional-features/config-contexts.html +1180 -12
- nautobot/project-static/docs/additional-features/graphql.html +1179 -11
- nautobot/project-static/docs/additional-features/healthcheck.html +1180 -12
- nautobot/project-static/docs/additional-features/job-scheduling-and-approvals.html +1184 -12
- nautobot/project-static/docs/additional-features/jobs.html +1514 -328
- nautobot/project-static/docs/additional-features/napalm.html +1180 -12
- nautobot/project-static/docs/additional-features/prometheus-metrics.html +1180 -12
- nautobot/project-static/docs/additional-features/template-filters.html +1180 -12
- nautobot/project-static/docs/administration/celery-queues.html +1178 -10
- nautobot/project-static/docs/administration/nautobot-server.html +1451 -304
- nautobot/project-static/docs/administration/nautobot-shell.html +1178 -10
- nautobot/project-static/docs/administration/permissions.html +1178 -10
- nautobot/project-static/docs/administration/replicating-nautobot.html +1262 -113
- nautobot/project-static/docs/apps/index.html +1178 -10
- nautobot/project-static/docs/apps/nautobot-apps.html +1178 -10
- nautobot/project-static/docs/code-reference/nautobot/apps/__init__.html +1580 -426
- nautobot/project-static/docs/code-reference/nautobot/apps/admin.html +1178 -10
- nautobot/project-static/docs/code-reference/nautobot/apps/api.html +3481 -1838
- nautobot/project-static/docs/code-reference/nautobot/apps/choices.html +1178 -10
- nautobot/project-static/docs/code-reference/nautobot/apps/config.html +1178 -10
- nautobot/project-static/docs/code-reference/nautobot/apps/datasources.html +1185 -11
- nautobot/project-static/docs/code-reference/nautobot/apps/filters.html +1719 -551
- nautobot/project-static/docs/code-reference/nautobot/apps/forms.html +2062 -930
- nautobot/project-static/docs/code-reference/nautobot/apps/models.html +1946 -659
- nautobot/project-static/docs/code-reference/nautobot/apps/secrets.html +1180 -12
- nautobot/project-static/docs/code-reference/nautobot/apps/tables.html +1189 -21
- nautobot/project-static/docs/code-reference/nautobot/apps/testing.html +9283 -6218
- nautobot/project-static/docs/code-reference/nautobot/apps/ui.html +2734 -2122
- nautobot/project-static/docs/code-reference/nautobot/apps/urls.html +1178 -10
- nautobot/project-static/docs/code-reference/nautobot/apps/views.html +2337 -1300
- nautobot/project-static/docs/configuration/authentication/ldap.html +1178 -10
- nautobot/project-static/docs/configuration/authentication/remote.html +1178 -10
- nautobot/project-static/docs/configuration/authentication/sso.html +1178 -10
- nautobot/project-static/docs/configuration/index.html +1178 -10
- nautobot/project-static/docs/configuration/optional-settings.html +1311 -160
- nautobot/project-static/docs/configuration/required-settings.html +1312 -211
- nautobot/project-static/docs/core-functionality/circuits.html +1178 -10
- nautobot/project-static/docs/core-functionality/device-types.html +1178 -10
- nautobot/project-static/docs/core-functionality/devices.html +1182 -10
- nautobot/project-static/docs/core-functionality/ipam.html +1182 -10
- nautobot/project-static/docs/core-functionality/power.html +1178 -10
- nautobot/project-static/docs/core-functionality/secrets.html +1178 -10
- nautobot/project-static/docs/core-functionality/services.html +1178 -10
- nautobot/project-static/docs/core-functionality/sites-and-racks.html +1178 -10
- nautobot/project-static/docs/core-functionality/tenancy.html +1178 -10
- nautobot/project-static/docs/core-functionality/virtualization.html +1182 -10
- nautobot/project-static/docs/core-functionality/vlans.html +1179 -11
- nautobot/project-static/docs/development/application-registry.html +1190 -42
- nautobot/project-static/docs/development/best-practices.html +1178 -10
- nautobot/project-static/docs/development/docker-compose-advanced-use-cases.html +1178 -10
- nautobot/project-static/docs/development/extending-models.html +1238 -83
- nautobot/project-static/docs/development/generic-views.html +1180 -14
- nautobot/project-static/docs/development/getting-started.html +1365 -90
- nautobot/project-static/docs/development/homepage.html +1178 -10
- nautobot/project-static/docs/development/index.html +1178 -10
- nautobot/project-static/docs/development/model-features.html +1178 -10
- nautobot/project-static/docs/development/natural-keys.html +1178 -10
- nautobot/project-static/docs/development/navigation-menu.html +1215 -125
- nautobot/project-static/docs/development/react-ui.html +4199 -0
- nautobot/project-static/docs/development/release-checklist.html +1178 -10
- nautobot/project-static/docs/development/role-internals.html +1179 -12
- nautobot/project-static/docs/development/style-guide.html +1188 -19
- nautobot/project-static/docs/development/templates.html +1178 -10
- nautobot/project-static/docs/development/testing.html +1178 -10
- nautobot/project-static/docs/development/user-preferences.html +1178 -10
- nautobot/project-static/docs/docker/index.html +1178 -10
- nautobot/project-static/docs/index.html +1183 -12
- nautobot/project-static/docs/installation/centos.html +1178 -10
- nautobot/project-static/docs/installation/external-authentication.html +1178 -10
- nautobot/project-static/docs/installation/http-server.html +1178 -10
- nautobot/project-static/docs/installation/index.html +1178 -10
- nautobot/project-static/docs/installation/migrating-from-netbox.html +1305 -189
- nautobot/project-static/docs/installation/migrating-from-postgresql.html +1178 -10
- nautobot/project-static/docs/installation/nautobot.html +1179 -11
- nautobot/project-static/docs/installation/region-and-site-data-migration-guide.html +1178 -10
- nautobot/project-static/docs/installation/selinux-troubleshooting.html +1178 -10
- nautobot/project-static/docs/installation/services.html +1178 -10
- nautobot/project-static/docs/installation/tables/v2-api-behavior-changes.yaml +70 -0
- nautobot/project-static/docs/installation/tables/v2-api-removed-fields.yaml +142 -0
- nautobot/project-static/docs/installation/tables/v2-api-renamed-fields.yaml +124 -0
- nautobot/project-static/docs/installation/tables/v2-code-location-changes.yaml +241 -0
- nautobot/project-static/docs/installation/tables/v2-code-removals.yaml +67 -0
- nautobot/project-static/docs/installation/tables/v2-database-behavior-changes.yaml +37 -0
- nautobot/project-static/docs/installation/tables/v2-database-removed-fields.yaml +166 -0
- nautobot/project-static/docs/installation/tables/v2-database-renamed-fields.yaml +340 -0
- nautobot/project-static/docs/installation/tables/v2-filters-corrected-fields.yaml +28 -0
- nautobot/project-static/docs/installation/tables/v2-filters-enhanced-fields.yaml +241 -0
- nautobot/project-static/docs/installation/tables/v2-filters-removed-fields.yaml +553 -0
- nautobot/project-static/docs/installation/tables/v2-filters-renamed-fields.yaml +223 -0
- nautobot/project-static/docs/installation/tables/v2-logging-renamed-loggers.yaml +23 -0
- nautobot/project-static/docs/installation/ubuntu.html +1178 -10
- nautobot/project-static/docs/installation/upgrading-from-nautobot-v1.html +3823 -2152
- nautobot/project-static/docs/installation/upgrading.html +1178 -10
- nautobot/project-static/docs/models/circuits/circuit.html +1293 -103
- nautobot/project-static/docs/models/circuits/circuittermination.html +1293 -103
- nautobot/project-static/docs/models/circuits/circuittype.html +1293 -103
- nautobot/project-static/docs/models/circuits/provider.html +1293 -103
- nautobot/project-static/docs/models/circuits/providernetwork.html +1293 -103
- nautobot/project-static/docs/models/dcim/cable.html +1324 -103
- nautobot/project-static/docs/models/dcim/consoleport.html +1293 -103
- nautobot/project-static/docs/models/dcim/consoleporttemplate.html +1293 -103
- nautobot/project-static/docs/models/dcim/consoleserverport.html +1293 -103
- nautobot/project-static/docs/models/dcim/consoleserverporttemplate.html +1293 -103
- nautobot/project-static/docs/models/dcim/device.html +1326 -132
- nautobot/project-static/docs/models/dcim/devicebay.html +1293 -103
- nautobot/project-static/docs/models/dcim/devicebaytemplate.html +1293 -103
- nautobot/project-static/docs/models/dcim/deviceredundancygroup.html +1379 -97
- nautobot/project-static/docs/models/dcim/devicetype.html +1293 -103
- nautobot/project-static/docs/models/dcim/frontport.html +1293 -103
- nautobot/project-static/docs/models/dcim/frontporttemplate.html +1293 -103
- nautobot/project-static/docs/models/dcim/interface.html +1293 -103
- nautobot/project-static/docs/models/dcim/interfacetemplate.html +1293 -103
- nautobot/project-static/docs/models/dcim/inventoryitem.html +1293 -103
- nautobot/project-static/docs/models/dcim/location.html +1293 -103
- nautobot/project-static/docs/models/dcim/locationtype.html +1293 -103
- nautobot/project-static/docs/models/dcim/manufacturer.html +1292 -102
- nautobot/project-static/docs/models/dcim/platform.html +1272 -82
- nautobot/project-static/docs/models/dcim/powerfeed.html +1270 -80
- nautobot/project-static/docs/models/dcim/poweroutlet.html +1272 -82
- nautobot/project-static/docs/models/dcim/poweroutlettemplate.html +1272 -82
- nautobot/project-static/docs/models/dcim/powerpanel.html +1270 -80
- nautobot/project-static/docs/models/dcim/powerport.html +1272 -82
- nautobot/project-static/docs/models/dcim/powerporttemplate.html +1272 -82
- nautobot/project-static/docs/models/dcim/rack.html +1272 -82
- nautobot/project-static/docs/models/dcim/rackgroup.html +1272 -82
- nautobot/project-static/docs/models/dcim/rackreservation.html +1272 -82
- nautobot/project-static/docs/models/dcim/rearport.html +1286 -96
- nautobot/project-static/docs/models/dcim/rearporttemplate.html +1286 -96
- nautobot/project-static/docs/models/dcim/region.html +1178 -10
- nautobot/project-static/docs/models/dcim/site.html +1178 -10
- nautobot/project-static/docs/models/dcim/virtualchassis.html +1284 -94
- nautobot/project-static/docs/models/extras/computedfield.html +1184 -16
- nautobot/project-static/docs/models/extras/configcontext.html +1314 -86
- nautobot/project-static/docs/models/extras/configcontextschema.html +1276 -86
- nautobot/project-static/docs/models/extras/customfield.html +1180 -12
- nautobot/project-static/docs/models/extras/customlink.html +1180 -12
- nautobot/project-static/docs/models/extras/dynamicgroup.html +1180 -12
- nautobot/project-static/docs/models/extras/exporttemplate.html +1180 -12
- nautobot/project-static/docs/models/extras/gitrepository.html +1184 -12
- nautobot/project-static/docs/models/extras/graphqlquery.html +1321 -86
- nautobot/project-static/docs/models/extras/imageattachment.html +1276 -86
- nautobot/project-static/docs/models/extras/job.html +1277 -86
- nautobot/project-static/docs/models/extras/jobbutton.html +1201 -29
- nautobot/project-static/docs/models/extras/jobhook.html +1188 -16
- nautobot/project-static/docs/models/extras/joblogentry.html +1274 -84
- nautobot/project-static/docs/models/extras/jobresult.html +1364 -169
- nautobot/project-static/docs/models/extras/note.html +1180 -12
- nautobot/project-static/docs/models/extras/relationship.html +1182 -14
- nautobot/project-static/docs/models/extras/role.html +1320 -86
- nautobot/project-static/docs/models/extras/secret.html +1314 -86
- nautobot/project-static/docs/models/extras/secretsgroup.html +1276 -86
- nautobot/project-static/docs/models/extras/status.html +1188 -59
- nautobot/project-static/docs/models/extras/tag.html +1180 -12
- nautobot/project-static/docs/models/extras/webhook.html +1180 -12
- nautobot/project-static/docs/models/ipam/ipaddress.html +1327 -102
- nautobot/project-static/docs/models/ipam/prefix.html +1276 -86
- nautobot/project-static/docs/models/ipam/rir.html +1276 -86
- nautobot/project-static/docs/models/ipam/routetarget.html +1276 -86
- nautobot/project-static/docs/models/ipam/service.html +1276 -86
- nautobot/project-static/docs/models/ipam/vlan.html +1276 -86
- nautobot/project-static/docs/models/ipam/vlangroup.html +1276 -86
- nautobot/project-static/docs/models/ipam/vrf.html +1276 -86
- nautobot/project-static/docs/models/tenancy/tenant.html +1276 -86
- nautobot/project-static/docs/models/tenancy/tenantgroup.html +1276 -86
- nautobot/project-static/docs/models/users/objectpermission.html +1314 -86
- nautobot/project-static/docs/models/users/token.html +1276 -86
- nautobot/project-static/docs/models/virtualization/cluster.html +1276 -86
- nautobot/project-static/docs/models/virtualization/clustergroup.html +1276 -86
- nautobot/project-static/docs/models/virtualization/clustertype.html +1276 -86
- nautobot/project-static/docs/models/virtualization/virtualmachine.html +1321 -127
- nautobot/project-static/docs/models/virtualization/vminterface.html +1276 -86
- nautobot/project-static/docs/objects.inv +0 -0
- nautobot/project-static/docs/plugins/development.html +1726 -495
- nautobot/project-static/docs/plugins/index.html +1178 -10
- nautobot/project-static/docs/plugins/porting-from-netbox.html +1178 -10
- nautobot/project-static/docs/release-notes/index.html +1178 -10
- nautobot/project-static/docs/release-notes/version-1.0.html +1178 -10
- nautobot/project-static/docs/release-notes/version-1.1.html +1178 -10
- nautobot/project-static/docs/release-notes/version-1.2.html +1178 -10
- nautobot/project-static/docs/release-notes/version-1.3.html +1178 -10
- nautobot/project-static/docs/release-notes/version-1.4.html +1178 -10
- nautobot/project-static/docs/release-notes/version-1.5.html +1608 -225
- nautobot/project-static/docs/release-notes/version-2.0.html +1547 -47
- nautobot/project-static/docs/requirements.txt +1 -0
- nautobot/project-static/docs/rest-api/authentication.html +1179 -11
- nautobot/project-static/docs/rest-api/filtering.html +1178 -10
- nautobot/project-static/docs/rest-api/overview.html +1841 -446
- nautobot/project-static/docs/rest-api/ui-related-endpoints.html +4057 -0
- nautobot/project-static/docs/search/search_index.json +1 -1
- nautobot/project-static/docs/sitemap.xml +197 -187
- nautobot/project-static/docs/sitemap.xml.gz +0 -0
- nautobot/project-static/docs/user-guides/custom-fields.html +1178 -10
- nautobot/project-static/docs/user-guides/getting-started/creating-devices.html +1178 -10
- nautobot/project-static/docs/user-guides/getting-started/index.html +1178 -10
- nautobot/project-static/docs/user-guides/getting-started/interfaces.html +1178 -10
- nautobot/project-static/docs/user-guides/getting-started/ipam.html +1178 -10
- nautobot/project-static/docs/user-guides/getting-started/platforms.html +1178 -10
- nautobot/project-static/docs/user-guides/getting-started/regions.html +1178 -10
- nautobot/project-static/docs/user-guides/getting-started/search-bar.html +1178 -10
- nautobot/project-static/docs/user-guides/getting-started/tenants.html +1178 -10
- nautobot/project-static/docs/user-guides/getting-started/vlans-and-vlan-groups.html +1178 -10
- nautobot/project-static/docs/user-guides/git-data-source.html +1178 -10
- nautobot/project-static/docs/user-guides/graphql.html +1178 -10
- nautobot/project-static/docs/user-guides/relationships.html +1178 -10
- nautobot/project-static/docs/user-guides/s3-django-storage.html +1178 -10
- nautobot/project-static/js/forms.js +16 -9
- nautobot/project-static/js/theme.js +5 -0
- nautobot/tenancy/api/serializers.py +4 -32
- nautobot/tenancy/api/urls.py +1 -1
- nautobot/tenancy/forms.py +0 -28
- nautobot/tenancy/migrations/0008_tagsfield.py +19 -0
- nautobot/tenancy/models.py +0 -25
- nautobot/tenancy/navigation.py +6 -39
- nautobot/tenancy/templates/tenancy/tenant.html +12 -12
- nautobot/tenancy/templates/tenancy/tenantgroup.html +1 -1
- nautobot/tenancy/tests/test_api.py +1 -3
- nautobot/tenancy/tests/test_filters.py +10 -5
- nautobot/tenancy/views.py +0 -2
- nautobot/ui/.eslintignore +6 -0
- nautobot/ui/.gitignore +10 -0
- nautobot/ui/.prettierignore +9 -0
- nautobot/ui/.prettierrc +4 -0
- nautobot/ui/README.md +33 -0
- nautobot/ui/app_imports.js.j2 +7 -0
- nautobot/ui/craco.config.js +46 -0
- nautobot/ui/jsconfig-base.json +11 -0
- nautobot/ui/jsconfig.json +5 -0
- nautobot/ui/lib/nautobot-craco-alias-plugin.js +40 -0
- nautobot/ui/package-lock.json +21451 -0
- nautobot/ui/package.json +70 -0
- nautobot/ui/public/index.html +47 -0
- nautobot/ui/public/logo192.png +0 -0
- nautobot/ui/public/logo512.png +0 -0
- nautobot/ui/public/manifest.json +25 -0
- nautobot/ui/public/nautobot_logo.svg +131 -0
- nautobot/ui/public/robots.txt +3 -0
- nautobot/ui/src/App.js +71 -0
- nautobot/ui/src/components/AppFullWidthComponents.js +8 -0
- nautobot/ui/src/components/AppTab.js +40 -0
- nautobot/ui/src/components/Apps.js +60 -0
- nautobot/ui/src/components/HomeChangelogPanel.js +98 -0
- nautobot/ui/src/components/HomePanel.js +58 -0
- nautobot/ui/src/components/JobHistoryTable.js +78 -0
- nautobot/ui/src/components/Layout.js +53 -0
- nautobot/ui/src/components/LoadingWidget.js +25 -0
- nautobot/ui/src/components/Navbar.js +116 -0
- nautobot/ui/src/components/NotificationPopover.js +27 -0
- nautobot/ui/src/components/ObjectListTable.js +209 -0
- nautobot/ui/src/components/ReferenceDataTag.js +35 -0
- nautobot/ui/src/components/RouterButton.js +10 -0
- nautobot/ui/src/components/RouterLink.js +10 -0
- nautobot/ui/src/components/SidebarNav.js +147 -0
- nautobot/ui/src/components/Table.js +48 -0
- nautobot/ui/src/components/TableItem.js +71 -0
- nautobot/ui/src/components/__tests__/AppFullWidthComponents.test.js +16 -0
- nautobot/ui/src/components/__tests__/AppTab.test.js +21 -0
- nautobot/ui/src/components/__tests__/Apps.test.js +14 -0
- nautobot/ui/src/components/__tests__/Layout.test.js +33 -0
- nautobot/ui/src/components/__tests__/Table.test.js +36 -0
- nautobot/ui/src/components/__tests__/TableItem.test.js +37 -0
- nautobot/ui/src/components/__tests__/paginator.test.js +43 -0
- nautobot/ui/src/components/__tests__/paginator_form.test.js +13 -0
- nautobot/ui/src/components/pagination.js +93 -0
- nautobot/ui/src/components/paginator.js +79 -0
- nautobot/ui/src/components/paginator_form.js +43 -0
- nautobot/ui/src/components/usePagination.js +57 -0
- nautobot/ui/src/constants/apiPath.js +10 -0
- nautobot/ui/src/constants/icons.js +15 -0
- nautobot/ui/src/constants/size.js +15 -0
- nautobot/ui/src/index.js +65 -0
- nautobot/ui/src/reportWebVitals.js +15 -0
- nautobot/ui/src/router.js +77 -0
- nautobot/ui/src/utils/api.js +131 -0
- nautobot/ui/src/utils/app-import.js +15 -0
- nautobot/ui/src/utils/color.js +15 -0
- nautobot/ui/src/utils/date.js +14 -0
- nautobot/ui/src/utils/index.js +15 -0
- nautobot/ui/src/utils/navigation.js +32 -0
- nautobot/ui/src/utils/session.js +64 -0
- nautobot/ui/src/utils/store.js +242 -0
- nautobot/ui/src/utils/string.js +6 -0
- nautobot/ui/src/utils/url.js +4 -0
- nautobot/ui/src/views/Home.js +138 -0
- nautobot/ui/src/views/InstalledApps.js +80 -0
- nautobot/ui/src/views/Login.js +48 -0
- nautobot/ui/src/views/Logout.js +20 -0
- nautobot/ui/src/views/__tests__/BSCreateViewTemplate.test.js +11 -0
- nautobot/ui/src/views/__tests__/BSListViewTemplate.test.js +107 -0
- nautobot/ui/src/views/__tests__/Login.test.js +15 -0
- nautobot/ui/src/views/generic/GenericView.js +142 -0
- nautobot/ui/src/views/generic/ObjectCreate.js +96 -0
- nautobot/ui/src/views/generic/ObjectList.js +127 -0
- nautobot/ui/src/views/generic/ObjectRetrieve.js +551 -0
- nautobot/users/admin.py +1 -1
- nautobot/users/api/serializers.py +51 -61
- nautobot/users/api/urls.py +1 -1
- nautobot/users/api/views.py +53 -2
- nautobot/users/tests/test_api.py +110 -25
- nautobot/virtualization/api/serializers.py +18 -130
- nautobot/virtualization/api/urls.py +1 -1
- nautobot/virtualization/api/views.py +1 -22
- nautobot/virtualization/forms.py +13 -99
- nautobot/virtualization/migrations/0012_alter_virtualmachine_role_add_new_role.py +1 -1
- nautobot/virtualization/migrations/0013_migrate_virtualmachine_role_data.py +18 -11
- nautobot/virtualization/migrations/0015_rename_foreignkey_fields.py +1 -1
- nautobot/virtualization/migrations/0018_related_name_changes.py +1 -1
- nautobot/virtualization/migrations/0021_tagsfield_and_vminterface_to_primarymodel.py +39 -0
- nautobot/virtualization/migrations/0022_vminterface_timestamps_data_migration.py +17 -0
- nautobot/virtualization/migrations/{0021_ipam__namespaces.py → 0023_ipam__namespaces.py} +2 -2
- nautobot/virtualization/migrations/0024_fixup_null_statuses.py +25 -0
- nautobot/virtualization/migrations/0025_status_nonnullable.py +29 -0
- nautobot/virtualization/models.py +31 -123
- nautobot/virtualization/navigation.py +18 -99
- nautobot/virtualization/templates/virtualization/virtualmachine.html +2 -1
- nautobot/virtualization/templates/virtualization/virtualmachine_edit.html +6 -0
- nautobot/virtualization/tests/test_api.py +25 -26
- nautobot/virtualization/tests/test_filters.py +41 -15
- nautobot/virtualization/tests/test_models.py +31 -7
- nautobot/virtualization/tests/test_views.py +42 -25
- nautobot/virtualization/views.py +7 -6
- {nautobot-2.0.0a3.dist-info → nautobot-2.0.0b1.dist-info}/METADATA +3 -7
- {nautobot-2.0.0a3.dist-info → nautobot-2.0.0b1.dist-info}/RECORD +744 -602
- {nautobot-2.0.0a3.dist-info → nautobot-2.0.0b1.dist-info}/WHEEL +1 -1
- nautobot/circuits/api/nested_serializers.py +0 -69
- nautobot/core/templates/plugin_template/navigation.py-tpl +0 -22
- nautobot/dcim/api/nested_serializers.py +0 -356
- nautobot/dcim/templates/dcim/device_import.html +0 -5
- nautobot/dcim/templates/dcim/device_import_child.html +0 -5
- nautobot/dcim/templates/dcim/inc/device_import_header.html +0 -4
- nautobot/extras/api/nested_serializers.py +0 -353
- nautobot/extras/migrations/0064_configcontext_data_migrations.py +0 -41
- nautobot/extras/migrations/0071_job__unique_name_data_migration.py +0 -46
- nautobot/extras/reports.py +0 -60
- nautobot/extras/scripts.py +0 -72
- nautobot/extras/tests/example_jobs/script_variables.py +0 -67
- nautobot/extras/tests/example_jobs/test_duplicate_name2.py +0 -5
- nautobot/extras/tests/example_jobs/test_fail.py +0 -16
- nautobot/extras/tests/example_jobs/test_file_upload_pass.py +0 -20
- nautobot/extras/tests/example_jobs/test_ipaddress_vars.py +0 -52
- nautobot/extras/tests/example_jobs/test_job_button_receiver.py +0 -21
- nautobot/extras/tests/example_jobs/test_job_hook_receiver.py +0 -20
- nautobot/extras/tests/example_jobs/test_location_with_custom_field.py +0 -35
- nautobot/extras/tests/example_jobs/test_log_redaction.py +0 -14
- nautobot/extras/tests/example_jobs/test_modify_db.py +0 -18
- nautobot/extras/tests/example_jobs/test_object_var_optional.py +0 -14
- nautobot/extras/tests/example_jobs/test_object_var_required.py +0 -14
- nautobot/extras/tests/example_jobs/test_object_vars.py +0 -29
- nautobot/extras/tests/example_jobs/test_pass.py +0 -19
- nautobot/extras/tests/example_jobs/test_read_only_fail.py +0 -24
- nautobot/extras/tests/example_jobs/test_read_only_no_commit_field.py +0 -10
- nautobot/extras/tests/example_jobs/test_read_only_pass.py +0 -22
- nautobot/ipam/api/nested_serializers.py +0 -159
- nautobot/ipam/migrations/0029_ipam__prefix__add_parent.py +0 -31
- nautobot/ipam/migrations/0030_ipam__prefix__data_migration.py +0 -13
- nautobot/ipam/migrations/0031_ipam__ipaddress__add_parent.py +0 -41
- nautobot/ipam/migrations/0032_ipam__ipaddress__data_migration.py +0 -11
- nautobot/tenancy/api/nested_serializers.py +0 -31
- nautobot/users/api/nested_serializers.py +0 -67
- nautobot/virtualization/api/nested_serializers.py +0 -65
- /nautobot/extras/{tests/example_jobs → test_jobs}/__init__.py +0 -0
- /nautobot/{dcim/models/sites.py → ipam/management/__init__.py} +0 -0
- {nautobot-2.0.0a3.dist-info → nautobot-2.0.0b1.dist-info}/LICENSE.txt +0 -0
- {nautobot-2.0.0a3.dist-info → nautobot-2.0.0b1.dist-info}/entry_points.txt +0 -0
nautobot/extras/views.py
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import inspect
|
|
2
1
|
from datetime import timedelta
|
|
3
2
|
import logging
|
|
4
3
|
|
|
@@ -26,16 +25,16 @@ from nautobot.core.models.querysets import count_related
|
|
|
26
25
|
from nautobot.core.models.utils import pretty_print_query
|
|
27
26
|
from nautobot.core.tables import ButtonsColumn
|
|
28
27
|
from nautobot.core.utils.lookup import get_table_for_model
|
|
29
|
-
from nautobot.core.utils.requests import
|
|
28
|
+
from nautobot.core.utils.requests import normalize_querydict
|
|
30
29
|
from nautobot.core.views import generic, viewsets
|
|
31
30
|
from nautobot.core.views.viewsets import NautobotUIViewSet
|
|
32
31
|
from nautobot.core.views.mixins import ObjectPermissionRequiredMixin
|
|
33
32
|
from nautobot.core.views.paginator import EnhancedPaginator, get_paginate_count
|
|
34
|
-
from nautobot.core.views.utils import
|
|
33
|
+
from nautobot.core.views.utils import prepare_cloned_fields
|
|
35
34
|
from nautobot.dcim.models import Device
|
|
36
35
|
from nautobot.dcim.tables import DeviceTable
|
|
37
36
|
from nautobot.extras.tasks import delete_custom_field_data
|
|
38
|
-
from nautobot.extras.utils import get_base_template,
|
|
37
|
+
from nautobot.extras.utils import get_base_template, get_worker_count
|
|
39
38
|
from nautobot.ipam.tables import IPAddressTable, PrefixTable, VLANTable
|
|
40
39
|
from nautobot.virtualization.models import VirtualMachine
|
|
41
40
|
from nautobot.virtualization.tables import VirtualMachineTable
|
|
@@ -49,9 +48,8 @@ from .datasources import (
|
|
|
49
48
|
get_datasource_contents,
|
|
50
49
|
)
|
|
51
50
|
from .filters import RoleFilterSet
|
|
52
|
-
from .forms import RoleBulkEditForm,
|
|
53
|
-
from .jobs import
|
|
54
|
-
from .jobs import get_job, run_job
|
|
51
|
+
from .forms import RoleBulkEditForm, RoleForm
|
|
52
|
+
from .jobs import get_job
|
|
55
53
|
from .models import (
|
|
56
54
|
ComputedField,
|
|
57
55
|
ConfigContext,
|
|
@@ -65,7 +63,6 @@ from .models import (
|
|
|
65
63
|
ImageAttachment,
|
|
66
64
|
JobButton,
|
|
67
65
|
JobHook,
|
|
68
|
-
JobLogEntry,
|
|
69
66
|
JobResult,
|
|
70
67
|
Note,
|
|
71
68
|
ObjectChange,
|
|
@@ -796,12 +793,12 @@ class GitRepositoryListView(generic.ObjectListView):
|
|
|
796
793
|
template_name = "extras/gitrepository_list.html"
|
|
797
794
|
|
|
798
795
|
def extra_context(self):
|
|
799
|
-
git_repository_content_type = ContentType.objects.get(app_label="extras", model="gitrepository")
|
|
800
796
|
# Get the newest results for each repository name
|
|
801
797
|
results = {
|
|
802
|
-
r.
|
|
798
|
+
r.task_kwargs["repository"]: r
|
|
803
799
|
for r in JobResult.objects.filter(
|
|
804
|
-
|
|
800
|
+
task_name__startswith="nautobot.core.jobs.GitRepository",
|
|
801
|
+
task_kwargs__repository__isnull=False,
|
|
805
802
|
status__in=JobResultStatusChoices.READY_STATES,
|
|
806
803
|
)
|
|
807
804
|
.order_by("date_done")
|
|
@@ -827,14 +824,17 @@ class GitRepositoryEditView(generic.ObjectEditView):
|
|
|
827
824
|
model_form = forms.GitRepositoryForm
|
|
828
825
|
template_name = "extras/gitrepository_object_edit.html"
|
|
829
826
|
|
|
827
|
+
# TODO(jathan): Align with changes for v2 where we're not stashing the user on the instance for
|
|
828
|
+
# magical calls and instead discretely calling `repo.sync(user=user, dry_run=dry_run)`, but
|
|
829
|
+
# again, this will be moved to the API calls, so just something to keep in mind.
|
|
830
830
|
def alter_obj(self, obj, request, url_args, url_kwargs):
|
|
831
831
|
# A GitRepository needs to know the originating request when it's saved so that it can enqueue using it
|
|
832
|
-
obj.
|
|
832
|
+
obj.user = request.user
|
|
833
833
|
return super().alter_obj(obj, request, url_args, url_kwargs)
|
|
834
834
|
|
|
835
835
|
def get_return_url(self, request, obj):
|
|
836
836
|
if request.method == "POST":
|
|
837
|
-
return reverse("extras:gitrepository_result", kwargs={"
|
|
837
|
+
return reverse("extras:gitrepository_result", kwargs={"pk": obj.pk})
|
|
838
838
|
return super().get_return_url(request, obj)
|
|
839
839
|
|
|
840
840
|
|
|
@@ -844,17 +844,8 @@ class GitRepositoryDeleteView(generic.ObjectDeleteView):
|
|
|
844
844
|
|
|
845
845
|
class GitRepositoryBulkImportView(generic.BulkImportView):
|
|
846
846
|
queryset = GitRepository.objects.all()
|
|
847
|
-
model_form = forms.GitRepositoryCSVForm
|
|
848
847
|
table = tables.GitRepositoryBulkTable
|
|
849
848
|
|
|
850
|
-
def _save_obj(self, obj_form, request):
|
|
851
|
-
"""Each GitRepository needs to know the originating request when it's saved so that it can enqueue using it."""
|
|
852
|
-
instance = obj_form.save(commit=False)
|
|
853
|
-
instance.request = request
|
|
854
|
-
instance.save()
|
|
855
|
-
|
|
856
|
-
return instance
|
|
857
|
-
|
|
858
849
|
|
|
859
850
|
class GitRepositoryBulkEditView(generic.BulkEditView):
|
|
860
851
|
queryset = GitRepository.objects.select_related("secrets_group")
|
|
@@ -883,11 +874,11 @@ class GitRepositoryBulkDeleteView(generic.BulkDeleteView):
|
|
|
883
874
|
}
|
|
884
875
|
|
|
885
876
|
|
|
886
|
-
def check_and_call_git_repository_function(request,
|
|
877
|
+
def check_and_call_git_repository_function(request, pk, func):
|
|
887
878
|
"""Helper for checking Git permissions and worker availability, then calling provided function if all is well
|
|
888
879
|
Args:
|
|
889
880
|
request: request object.
|
|
890
|
-
|
|
881
|
+
pk (UUID): GitRepository pk value.
|
|
891
882
|
func (function): Enqueue git repo function.
|
|
892
883
|
Returns:
|
|
893
884
|
HttpResponseForbidden or a redirect
|
|
@@ -899,20 +890,20 @@ def check_and_call_git_repository_function(request, slug, func):
|
|
|
899
890
|
if not get_worker_count():
|
|
900
891
|
messages.error(request, "Unable to run job: Celery worker process not running.")
|
|
901
892
|
else:
|
|
902
|
-
repository = get_object_or_404(GitRepository,
|
|
903
|
-
func(repository, request)
|
|
893
|
+
repository = get_object_or_404(GitRepository, pk=pk)
|
|
894
|
+
job_result = func(repository, request.user)
|
|
904
895
|
|
|
905
|
-
return redirect(
|
|
896
|
+
return redirect(job_result.get_absolute_url())
|
|
906
897
|
|
|
907
898
|
|
|
908
899
|
class GitRepositorySyncView(View):
|
|
909
|
-
def post(self, request,
|
|
910
|
-
return check_and_call_git_repository_function(request,
|
|
900
|
+
def post(self, request, pk):
|
|
901
|
+
return check_and_call_git_repository_function(request, pk, enqueue_pull_git_repository_and_refresh_data)
|
|
911
902
|
|
|
912
903
|
|
|
913
904
|
class GitRepositoryDryRunView(View):
|
|
914
|
-
def post(self, request,
|
|
915
|
-
return check_and_call_git_repository_function(request,
|
|
905
|
+
def post(self, request, pk):
|
|
906
|
+
return check_and_call_git_repository_function(request, pk, enqueue_git_repository_diff_origin_and_local)
|
|
916
907
|
|
|
917
908
|
|
|
918
909
|
class GitRepositoryResultView(generic.ObjectView):
|
|
@@ -927,12 +918,7 @@ class GitRepositoryResultView(generic.ObjectView):
|
|
|
927
918
|
return "extras.view_gitrepository"
|
|
928
919
|
|
|
929
920
|
def get_extra_context(self, request, instance):
|
|
930
|
-
|
|
931
|
-
job_result = (
|
|
932
|
-
JobResult.objects.filter(obj_type=git_repository_content_type, name=instance.name)
|
|
933
|
-
.order_by("-date_created")
|
|
934
|
-
.first()
|
|
935
|
-
)
|
|
921
|
+
job_result = instance.get_latest_sync()
|
|
936
922
|
|
|
937
923
|
return {
|
|
938
924
|
"result": job_result,
|
|
@@ -1065,7 +1051,7 @@ class JobView(ObjectPermissionRequiredMixin, View):
|
|
|
1065
1051
|
def get_required_permission(self):
|
|
1066
1052
|
return "extras.run_job"
|
|
1067
1053
|
|
|
1068
|
-
def _get_job_model_or_404(self, class_path=None,
|
|
1054
|
+
def _get_job_model_or_404(self, class_path=None, pk=None):
|
|
1069
1055
|
"""Helper function for get() and post()."""
|
|
1070
1056
|
if class_path:
|
|
1071
1057
|
try:
|
|
@@ -1073,30 +1059,32 @@ class JobView(ObjectPermissionRequiredMixin, View):
|
|
|
1073
1059
|
except JobModel.DoesNotExist:
|
|
1074
1060
|
raise Http404
|
|
1075
1061
|
else:
|
|
1076
|
-
job_model = get_object_or_404(self.queryset,
|
|
1062
|
+
job_model = get_object_or_404(self.queryset, pk=pk)
|
|
1077
1063
|
|
|
1078
1064
|
return job_model
|
|
1079
1065
|
|
|
1080
|
-
def get(self, request, class_path=None,
|
|
1081
|
-
job_model = self._get_job_model_or_404(class_path,
|
|
1066
|
+
def get(self, request, class_path=None, pk=None):
|
|
1067
|
+
job_model = self._get_job_model_or_404(class_path, pk)
|
|
1082
1068
|
|
|
1083
1069
|
try:
|
|
1084
|
-
|
|
1085
|
-
|
|
1070
|
+
try:
|
|
1071
|
+
job_instance = job_model.job_class()
|
|
1072
|
+
except TypeError as exc:
|
|
1073
|
+
# job_class may be None
|
|
1074
|
+
raise RuntimeError("Job code for this job is not currently installed or loadable") from exc
|
|
1075
|
+
initial = normalize_querydict(request.GET, form_class=job_instance.as_form_class())
|
|
1086
1076
|
if "kwargs_from_job_result" in initial:
|
|
1087
1077
|
job_result_pk = initial.pop("kwargs_from_job_result")
|
|
1088
1078
|
try:
|
|
1089
|
-
job_result = job_model.
|
|
1090
|
-
# Allow explicitly specified arg values in request.GET to take precedence over the saved
|
|
1091
|
-
# for example "?kwargs_from_job_result=<UUID>&integervar=22
|
|
1079
|
+
job_result = job_model.job_results.get(pk=job_result_pk)
|
|
1080
|
+
# Allow explicitly specified arg values in request.GET to take precedence over the saved task_kwargs,
|
|
1081
|
+
# for example "?kwargs_from_job_result=<UUID>&integervar=22"
|
|
1092
1082
|
explicit_initial = initial
|
|
1093
|
-
initial = job_result.
|
|
1094
|
-
|
|
1095
|
-
if commit is not None:
|
|
1096
|
-
initial.setdefault("_commit", commit)
|
|
1097
|
-
task_queue = job_result.job_kwargs.get("task_queue")
|
|
1083
|
+
initial = job_result.task_kwargs.copy()
|
|
1084
|
+
task_queue = job_result.celery_kwargs.get("queue", None)
|
|
1098
1085
|
if task_queue is not None:
|
|
1099
|
-
initial
|
|
1086
|
+
initial["_task_queue"] = task_queue
|
|
1087
|
+
initial["_profile"] = job_result.celery_kwargs.get("nautobot_job_profile", False)
|
|
1100
1088
|
initial.update(explicit_initial)
|
|
1101
1089
|
except JobResult.DoesNotExist:
|
|
1102
1090
|
messages.warning(
|
|
@@ -1105,11 +1093,11 @@ class JobView(ObjectPermissionRequiredMixin, View):
|
|
|
1105
1093
|
)
|
|
1106
1094
|
|
|
1107
1095
|
template_name = "extras/job.html"
|
|
1108
|
-
job_form =
|
|
1109
|
-
if hasattr(
|
|
1096
|
+
job_form = job_instance.as_form(initial=initial)
|
|
1097
|
+
if hasattr(job_instance, "template_name"):
|
|
1110
1098
|
try:
|
|
1111
|
-
get_template(
|
|
1112
|
-
template_name =
|
|
1099
|
+
get_template(job_instance.template_name)
|
|
1100
|
+
template_name = job_instance.template_name
|
|
1113
1101
|
except TemplateDoesNotExist as err:
|
|
1114
1102
|
messages.error(request, f'Unable to render requested custom job template "{template_name}": {err}')
|
|
1115
1103
|
except RuntimeError as err:
|
|
@@ -1128,8 +1116,8 @@ class JobView(ObjectPermissionRequiredMixin, View):
|
|
|
1128
1116
|
},
|
|
1129
1117
|
)
|
|
1130
1118
|
|
|
1131
|
-
def post(self, request, class_path=None,
|
|
1132
|
-
job_model = self._get_job_model_or_404(class_path,
|
|
1119
|
+
def post(self, request, class_path=None, pk=None):
|
|
1120
|
+
job_model = self._get_job_model_or_404(class_path, pk)
|
|
1133
1121
|
|
|
1134
1122
|
job_form = (
|
|
1135
1123
|
job_model.job_class().as_form(request.POST, request.FILES) if job_model.job_class is not None else None
|
|
@@ -1154,11 +1142,13 @@ class JobView(ObjectPermissionRequiredMixin, View):
|
|
|
1154
1142
|
"One of these two flags must be removed before this job can be scheduled or run.",
|
|
1155
1143
|
)
|
|
1156
1144
|
elif job_form is not None and job_form.is_valid() and schedule_form.is_valid():
|
|
1145
|
+
task_queue = job_form.cleaned_data.pop("_task_queue", None)
|
|
1146
|
+
dryrun = job_form.cleaned_data.get("dryrun", False)
|
|
1157
1147
|
# Run the job. A new JobResult is created.
|
|
1158
|
-
|
|
1148
|
+
profile = job_form.cleaned_data.pop("_profile")
|
|
1159
1149
|
schedule_type = schedule_form.cleaned_data["_schedule_type"]
|
|
1160
1150
|
|
|
1161
|
-
if job_model.approval_required or schedule_type in JobExecutionType.SCHEDULE_CHOICES:
|
|
1151
|
+
if (not dryrun and job_model.approval_required) or schedule_type in JobExecutionType.SCHEDULE_CHOICES:
|
|
1162
1152
|
crontab = ""
|
|
1163
1153
|
|
|
1164
1154
|
if schedule_type == JobExecutionType.TYPE_IMMEDIATELY:
|
|
@@ -1184,25 +1174,16 @@ class JobView(ObjectPermissionRequiredMixin, View):
|
|
|
1184
1174
|
else:
|
|
1185
1175
|
schedule_datetime = schedule_form.cleaned_data["_schedule_start_time"]
|
|
1186
1176
|
|
|
1187
|
-
|
|
1188
|
-
"data": job_model.job_class.serialize_data(job_form.cleaned_data),
|
|
1189
|
-
"request": copy_safe_request(request),
|
|
1190
|
-
"user": request.user.pk,
|
|
1191
|
-
"commit": commit,
|
|
1192
|
-
"name": job_model.class_path,
|
|
1193
|
-
"task_queue": job_form.cleaned_data.get("_task_queue", None),
|
|
1194
|
-
}
|
|
1195
|
-
if task_queue:
|
|
1196
|
-
task_kwargs["celery_kwargs"] = {"queue": task_queue}
|
|
1197
|
-
|
|
1177
|
+
celery_kwargs = {"nautobot_job_profile": profile, "queue": task_queue}
|
|
1198
1178
|
scheduled_job = ScheduledJob(
|
|
1199
1179
|
name=schedule_name,
|
|
1200
|
-
task=
|
|
1180
|
+
task=job_model.job_class.registered_name,
|
|
1201
1181
|
job_class=job_model.class_path,
|
|
1202
1182
|
job_model=job_model,
|
|
1203
1183
|
start_time=schedule_datetime,
|
|
1204
1184
|
description=f"Nautobot job {schedule_name} scheduled by {request.user} for {schedule_datetime}",
|
|
1205
|
-
kwargs=
|
|
1185
|
+
kwargs=job_model.job_class.serialize_data(job_form.cleaned_data),
|
|
1186
|
+
celery_kwargs=celery_kwargs,
|
|
1206
1187
|
interval=schedule_type,
|
|
1207
1188
|
one_off=schedule_type == JobExecutionType.TYPE_FUTURE,
|
|
1208
1189
|
queue=task_queue,
|
|
@@ -1221,17 +1202,13 @@ class JobView(ObjectPermissionRequiredMixin, View):
|
|
|
1221
1202
|
|
|
1222
1203
|
else:
|
|
1223
1204
|
# Enqueue job for immediate execution
|
|
1224
|
-
|
|
1205
|
+
job_kwargs = job_model.job_class.prepare_job_kwargs(job_form.cleaned_data)
|
|
1225
1206
|
job_result = JobResult.enqueue_job(
|
|
1226
|
-
|
|
1227
|
-
job_model.class_path,
|
|
1228
|
-
job_content_type,
|
|
1207
|
+
job_model,
|
|
1229
1208
|
request.user,
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
commit=commit,
|
|
1234
|
-
task_queue=job_form.cleaned_data.get("_task_queue", None),
|
|
1209
|
+
profile=profile,
|
|
1210
|
+
task_queue=task_queue,
|
|
1211
|
+
**job_model.job_class.serialize_data(job_kwargs),
|
|
1235
1212
|
)
|
|
1236
1213
|
|
|
1237
1214
|
return redirect("extras:jobresult", pk=job_result.pk)
|
|
@@ -1279,7 +1256,7 @@ class JobApprovalRequestView(generic.ObjectView):
|
|
|
1279
1256
|
job's execution, rather than initial job form input.
|
|
1280
1257
|
"""
|
|
1281
1258
|
|
|
1282
|
-
queryset = ScheduledJob.objects.
|
|
1259
|
+
queryset = ScheduledJob.objects.needs_approved()
|
|
1283
1260
|
template_name = "extras/job_approval_request.html"
|
|
1284
1261
|
additional_permissions = ("extras.view_job",)
|
|
1285
1262
|
|
|
@@ -1298,8 +1275,9 @@ class JobApprovalRequestView(generic.ObjectView):
|
|
|
1298
1275
|
|
|
1299
1276
|
if job_class is not None:
|
|
1300
1277
|
# Render the form with all fields disabled
|
|
1301
|
-
initial = instance.kwargs
|
|
1302
|
-
initial["
|
|
1278
|
+
initial = instance.kwargs
|
|
1279
|
+
initial["_task_queue"] = instance.queue
|
|
1280
|
+
initial["_profile"] = instance.celery_kwargs.get("profile", False)
|
|
1303
1281
|
job_form = job_class().as_form(initial=initial, approval_view=True)
|
|
1304
1282
|
else:
|
|
1305
1283
|
job_form = None
|
|
@@ -1335,22 +1313,17 @@ class JobApprovalRequestView(generic.ObjectView):
|
|
|
1335
1313
|
messages.error(request, "This job cannot be run at this time")
|
|
1336
1314
|
elif not JobModel.objects.check_perms(self.request.user, instance=job_model, action="run"):
|
|
1337
1315
|
messages.error(request, "You do not have permission to run this job")
|
|
1316
|
+
elif not job_model.supports_dryrun:
|
|
1317
|
+
messages.error(request, "This job does not support dryrun")
|
|
1338
1318
|
else:
|
|
1339
|
-
# Immediately enqueue the job
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
initial["_commit"] = False
|
|
1343
|
-
celery_kwargs = scheduled_job.kwargs.get("celery_kwargs", {})
|
|
1319
|
+
# Immediately enqueue the job and send the user to the normal JobResult view
|
|
1320
|
+
job_kwargs = job_model.job_class.prepare_job_kwargs(scheduled_job.kwargs or {})
|
|
1321
|
+
job_kwargs["dryrun"] = True
|
|
1344
1322
|
job_result = JobResult.enqueue_job(
|
|
1345
|
-
|
|
1346
|
-
job_model.job_class.class_path,
|
|
1347
|
-
job_content_type,
|
|
1323
|
+
job_model,
|
|
1348
1324
|
request.user,
|
|
1349
|
-
celery_kwargs=celery_kwargs,
|
|
1350
|
-
|
|
1351
|
-
request=copy_safe_request(request),
|
|
1352
|
-
commit=False, # force a dry-run
|
|
1353
|
-
task_queue=scheduled_job.kwargs.get("task_queue", None),
|
|
1325
|
+
celery_kwargs=scheduled_job.celery_kwargs,
|
|
1326
|
+
**job_model.job_class.serialize_data(job_kwargs),
|
|
1354
1327
|
)
|
|
1355
1328
|
|
|
1356
1329
|
return redirect("extras:jobresult", pk=job_result.pk)
|
|
@@ -1405,7 +1378,7 @@ class JobApprovalRequestView(generic.ObjectView):
|
|
|
1405
1378
|
|
|
1406
1379
|
|
|
1407
1380
|
class ScheduledJobListView(generic.ObjectListView):
|
|
1408
|
-
queryset = ScheduledJob.objects.
|
|
1381
|
+
queryset = ScheduledJob.objects.enabled()
|
|
1409
1382
|
table = tables.ScheduledJobTable
|
|
1410
1383
|
filterset = filters.ScheduledJobFilterSet
|
|
1411
1384
|
filterset_form = forms.ScheduledJobFilterForm
|
|
@@ -1419,7 +1392,7 @@ class ScheduledJobBulkDeleteView(generic.BulkDeleteView):
|
|
|
1419
1392
|
|
|
1420
1393
|
|
|
1421
1394
|
class ScheduledJobApprovalQueueListView(generic.ObjectListView):
|
|
1422
|
-
queryset = ScheduledJob.objects.
|
|
1395
|
+
queryset = ScheduledJob.objects.needs_approved()
|
|
1423
1396
|
table = tables.ScheduledJobApprovalQueueTable
|
|
1424
1397
|
filterset = filters.ScheduledJobFilterSet
|
|
1425
1398
|
filterset_form = forms.ScheduledJobFilterForm
|
|
@@ -1491,7 +1464,7 @@ class JobResultListView(generic.ObjectListView):
|
|
|
1491
1464
|
List JobResults
|
|
1492
1465
|
"""
|
|
1493
1466
|
|
|
1494
|
-
queryset = JobResult.objects.select_related("job_model", "
|
|
1467
|
+
queryset = JobResult.objects.select_related("job_model", "user").prefetch_related("logs")
|
|
1495
1468
|
filterset = filters.JobResultFilterSet
|
|
1496
1469
|
filterset_form = forms.JobResultFilterForm
|
|
1497
1470
|
table = tables.JobResultTable
|
|
@@ -1512,49 +1485,14 @@ class JobResultView(generic.ObjectView):
|
|
|
1512
1485
|
Display a JobResult and its Job data.
|
|
1513
1486
|
"""
|
|
1514
1487
|
|
|
1515
|
-
queryset = JobResult.objects.prefetch_related("job_model", "
|
|
1488
|
+
queryset = JobResult.objects.prefetch_related("job_model", "user")
|
|
1516
1489
|
template_name = "extras/jobresult.html"
|
|
1517
1490
|
|
|
1518
|
-
def instance_to_csv(self, instance):
|
|
1519
|
-
"""Format instance to csv."""
|
|
1520
|
-
csv_data = []
|
|
1521
|
-
headers = JobLogEntry.csv_headers.copy()
|
|
1522
|
-
csv_data.append(",".join(headers))
|
|
1523
|
-
|
|
1524
|
-
for log_entry in instance.job_log_entries.all():
|
|
1525
|
-
data = log_entry.to_csv()
|
|
1526
|
-
csv_data.append(csv_format(data))
|
|
1527
|
-
|
|
1528
|
-
return "\n".join(csv_data)
|
|
1529
|
-
|
|
1530
|
-
def get(self, request, *args, **kwargs):
|
|
1531
|
-
"""
|
|
1532
|
-
Generic GET handler for accessing an object by PK or slug
|
|
1533
|
-
"""
|
|
1534
|
-
instance = get_object_or_404(self.queryset, **kwargs)
|
|
1535
|
-
|
|
1536
|
-
if "export" in request.GET:
|
|
1537
|
-
response = HttpResponse(self.instance_to_csv(instance), content_type="text/csv")
|
|
1538
|
-
underscore_filename = f"{instance.job_model.slug.replace('-', '_')}"
|
|
1539
|
-
formated_completion_time = instance.date_done.strftime("%Y-%m-%d_%H_%M")
|
|
1540
|
-
filename = f"{underscore_filename}_{formated_completion_time}_logs.csv"
|
|
1541
|
-
response["Content-Disposition"] = f"attachment; filename={filename}"
|
|
1542
|
-
return response
|
|
1543
|
-
|
|
1544
|
-
return super().get(request, *args, **kwargs)
|
|
1545
|
-
|
|
1546
1491
|
def get_extra_context(self, request, instance):
|
|
1547
1492
|
associated_record = None
|
|
1548
1493
|
job_class = None
|
|
1549
1494
|
if instance.job_model is not None:
|
|
1550
1495
|
job_class = instance.job_model.job_class
|
|
1551
|
-
# 2.0 TODO: remove JobResult.related_object entirely
|
|
1552
|
-
related_object = instance.related_object
|
|
1553
|
-
if inspect.isclass(related_object) and issubclass(related_object, JobClass):
|
|
1554
|
-
if job_class is None:
|
|
1555
|
-
job_class = related_object
|
|
1556
|
-
elif related_object:
|
|
1557
|
-
associated_record = related_object
|
|
1558
1496
|
|
|
1559
1497
|
return {
|
|
1560
1498
|
"job": job_class,
|
|
@@ -1587,7 +1525,6 @@ class JobButtonUIViewSet(NautobotUIViewSet):
|
|
|
1587
1525
|
filterset_class = filters.JobButtonFilterSet
|
|
1588
1526
|
filterset_form_class = forms.JobButtonFilterForm
|
|
1589
1527
|
form_class = forms.JobButtonForm
|
|
1590
|
-
lookup_field = "pk"
|
|
1591
1528
|
queryset = JobButton.objects.all()
|
|
1592
1529
|
serializer_class = serializers.JobButtonSerializer
|
|
1593
1530
|
table_class = tables.JobButtonTable
|
|
@@ -1608,16 +1545,10 @@ class JobButtonRunView(ObjectPermissionRequiredMixin, View):
|
|
|
1608
1545
|
job_button = JobButton.objects.get(pk=pk)
|
|
1609
1546
|
job_model = job_button.job
|
|
1610
1547
|
result = JobResult.enqueue_job(
|
|
1611
|
-
|
|
1612
|
-
name=job_model.class_path,
|
|
1613
|
-
obj_type=get_job_content_type(),
|
|
1548
|
+
job_model=job_model,
|
|
1614
1549
|
user=request.user,
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
"object_model_name": post_data["object_model_name"],
|
|
1618
|
-
},
|
|
1619
|
-
request=copy_safe_request(request),
|
|
1620
|
-
commit=True,
|
|
1550
|
+
object_pk=post_data["object_pk"],
|
|
1551
|
+
object_model_name=post_data["object_model_name"],
|
|
1621
1552
|
)
|
|
1622
1553
|
msg = f'Job enqueued. <a href="{result.get_absolute_url()}">Click here for the results.</a>'
|
|
1623
1554
|
messages.info(request=request, message=mark_safe(msg))
|
|
@@ -1852,13 +1783,11 @@ class RoleUIViewSet(viewsets.NautobotUIViewSet):
|
|
|
1852
1783
|
"""`Roles` UIViewSet."""
|
|
1853
1784
|
|
|
1854
1785
|
queryset = Role.objects.all()
|
|
1855
|
-
bulk_create_form_class = RoleCSVForm
|
|
1856
1786
|
bulk_update_form_class = RoleBulkEditForm
|
|
1857
1787
|
filterset_class = RoleFilterSet
|
|
1858
1788
|
form_class = RoleForm
|
|
1859
1789
|
serializer_class = serializers.RoleSerializer
|
|
1860
1790
|
table_class = RoleTable
|
|
1861
|
-
lookup_field = "pk"
|
|
1862
1791
|
|
|
1863
1792
|
def get_extra_context(self, request, instance):
|
|
1864
1793
|
context = super().get_extra_context(request, instance)
|
|
@@ -1999,7 +1928,6 @@ class SecretDeleteView(generic.ObjectDeleteView):
|
|
|
1999
1928
|
|
|
2000
1929
|
class SecretBulkImportView(generic.BulkImportView):
|
|
2001
1930
|
queryset = Secret.objects.all()
|
|
2002
|
-
model_form = forms.SecretCSVForm
|
|
2003
1931
|
table = tables.SecretTable
|
|
2004
1932
|
|
|
2005
1933
|
|
|
@@ -2174,7 +2102,6 @@ class StatusBulkImportView(generic.BulkImportView):
|
|
|
2174
2102
|
"""Bulk CSV import of multiple `Status` objects."""
|
|
2175
2103
|
|
|
2176
2104
|
queryset = Status.objects.all()
|
|
2177
|
-
model_form = forms.StatusCSVForm
|
|
2178
2105
|
table = tables.StatusTable
|
|
2179
2106
|
|
|
2180
2107
|
|
|
@@ -2235,7 +2162,6 @@ class TagDeleteView(generic.ObjectDeleteView):
|
|
|
2235
2162
|
|
|
2236
2163
|
class TagBulkImportView(generic.BulkImportView):
|
|
2237
2164
|
queryset = Tag.objects.all()
|
|
2238
|
-
model_form = forms.TagCSVForm
|
|
2239
2165
|
table = tables.TagTable
|
|
2240
2166
|
|
|
2241
2167
|
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import netaddr
|
|
2
|
+
from rest_framework import serializers
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class IPFieldSerializer(serializers.CharField):
|
|
6
|
+
def to_representation(self, value):
|
|
7
|
+
"""Convert internal (IPNetwork) representation to API (string) representation."""
|
|
8
|
+
return str(value)
|
|
9
|
+
|
|
10
|
+
def to_internal_value(self, value):
|
|
11
|
+
"""Convert API (string) representation to internal (IPNetwork) representation."""
|
|
12
|
+
try:
|
|
13
|
+
return netaddr.IPNetwork(value)
|
|
14
|
+
except netaddr.AddrFormatError:
|
|
15
|
+
raise serializers.ValidationError(f"Invalid IP address format: {value}")
|
|
16
|
+
except (TypeError, ValueError) as e:
|
|
17
|
+
raise serializers.ValidationError(e)
|