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
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
import
|
|
1
|
+
import uuid
|
|
2
2
|
|
|
3
3
|
from django import forms as django_forms
|
|
4
4
|
from django.contrib.auth.models import Group
|
|
5
5
|
from django.contrib.contenttypes.models import ContentType
|
|
6
6
|
from django.db.models import Q
|
|
7
7
|
from django.http import QueryDict
|
|
8
|
-
from django.test import
|
|
8
|
+
from django.test import TestCase
|
|
9
9
|
|
|
10
10
|
from example_plugin.models import ExampleModel
|
|
11
11
|
|
|
12
12
|
from nautobot.circuits import models as circuits_models
|
|
13
|
-
from nautobot.core import
|
|
13
|
+
from nautobot.core import exceptions, forms, settings_funcs
|
|
14
14
|
from nautobot.core.api import utils as api_utils
|
|
15
15
|
from nautobot.core.models import fields as core_fields, utils as models_utils
|
|
16
16
|
from nautobot.core.utils import data as data_utils, filtering, lookup, requests
|
|
@@ -595,76 +595,20 @@ class LookupRelatedFunctionTest(TestCase):
|
|
|
595
595
|
self.assertEqual(err.exception.code, 404)
|
|
596
596
|
|
|
597
597
|
|
|
598
|
-
class NautobotFakeRequestTest(testing.TestCase):
|
|
599
|
-
"""Test the NautobotFakeRequest class."""
|
|
600
|
-
|
|
601
|
-
def setUp(self):
|
|
602
|
-
"""Create the RequestFactory."""
|
|
603
|
-
super().setUp()
|
|
604
|
-
self.factory = RequestFactory()
|
|
605
|
-
|
|
606
|
-
def get_with_user(self, url):
|
|
607
|
-
"""RequestFactory() doesn't run middleware, so simulate it."""
|
|
608
|
-
request = self.factory.get(url)
|
|
609
|
-
request.user = self.user
|
|
610
|
-
return request
|
|
611
|
-
|
|
612
|
-
def test_copy_safe_request(self):
|
|
613
|
-
"""Test that copy_safe_request() produces a realistic looking NautobotFakeRequest."""
|
|
614
|
-
real_request = self.get_with_user("/")
|
|
615
|
-
fake_request = requests.copy_safe_request(real_request)
|
|
616
|
-
self.assertEqual(real_request.POST, fake_request.POST)
|
|
617
|
-
self.assertEqual(real_request.GET, fake_request.GET)
|
|
618
|
-
self.assertEqual(real_request.user, fake_request.user)
|
|
619
|
-
self.assertEqual(real_request.path, fake_request.path)
|
|
620
|
-
for key in fake_request.META.keys():
|
|
621
|
-
self.assertIn(key, constants.HTTP_REQUEST_META_SAFE_COPY)
|
|
622
|
-
self.assertEqual(real_request.META[key], fake_request.META[key])
|
|
623
|
-
self.assertEqual(fake_request.user, self.user)
|
|
624
|
-
|
|
625
|
-
def test_fake_request_json_no_extra_db_access(self):
|
|
626
|
-
"""Verify that serializing and deserializing a NautobotFakeRequest as JSON doesn't unnecessarily access the DB."""
|
|
627
|
-
real_request = self.get_with_user("/")
|
|
628
|
-
fake_request = requests.copy_safe_request(real_request)
|
|
629
|
-
with self.assertNumQueries(0):
|
|
630
|
-
new_fake_request = requests.NautobotFakeRequest.nautobot_deserialize(fake_request.nautobot_serialize())
|
|
631
|
-
# After creating the new instance, its `user` is a lazy attribute, which should evaluate on demand:
|
|
632
|
-
with self.assertNumQueries(1):
|
|
633
|
-
new_fake_request.user
|
|
634
|
-
self.assertEqual(new_fake_request.user, self.user)
|
|
635
|
-
# It should then be cached and not require re-lookup from the DB
|
|
636
|
-
with self.assertNumQueries(0):
|
|
637
|
-
new_fake_request.user
|
|
638
|
-
|
|
639
|
-
def test_fake_request_pickle_no_extra_db_access(self):
|
|
640
|
-
"""Verify that pickling and unpickling a NautobotFakeRequest doesn't unnecessarily access the DB."""
|
|
641
|
-
real_request = self.get_with_user("/")
|
|
642
|
-
fake_request = requests.copy_safe_request(real_request)
|
|
643
|
-
with self.assertNumQueries(0):
|
|
644
|
-
new_fake_request = pickle.loads(pickle.dumps(fake_request))
|
|
645
|
-
# After creating the new instance, its `user` is a lazy attribute, which should evaluate on demand:
|
|
646
|
-
with self.assertNumQueries(1):
|
|
647
|
-
new_fake_request.user
|
|
648
|
-
self.assertEqual(new_fake_request.user, self.user)
|
|
649
|
-
# It should then be cached and not require re-lookup from the DB
|
|
650
|
-
with self.assertNumQueries(0):
|
|
651
|
-
new_fake_request.user
|
|
652
|
-
|
|
653
|
-
|
|
654
598
|
class GetFilterFieldLabelTest(TestCase):
|
|
655
599
|
@classmethod
|
|
656
600
|
def setUpTestData(cls):
|
|
657
601
|
device_ct = ContentType.objects.get_for_model(dcim_models.Device)
|
|
658
602
|
cls.peer_relationship = extras_models.Relationship(
|
|
659
|
-
|
|
660
|
-
|
|
603
|
+
label="HA Device Peer",
|
|
604
|
+
key="ha_device_peer",
|
|
661
605
|
source_type=device_ct,
|
|
662
606
|
destination_type=device_ct,
|
|
663
607
|
source_label="Peer",
|
|
664
608
|
destination_label="Peer",
|
|
665
609
|
type=RelationshipTypeChoices.TYPE_ONE_TO_ONE_SYMMETRIC,
|
|
666
610
|
)
|
|
667
|
-
|
|
611
|
+
cls.peer_relationship.validated_save()
|
|
668
612
|
|
|
669
613
|
cls.custom_field = extras_models.CustomField(key="labeled_custom_field", label="Moo!", type="text")
|
|
670
614
|
cls.custom_field.validated_save()
|
|
@@ -683,12 +627,11 @@ class GetFilterFieldLabelTest(TestCase):
|
|
|
683
627
|
filtering.get_filter_field_label(device_filter_set_filters["has_interfaces"]), "Has interfaces"
|
|
684
628
|
)
|
|
685
629
|
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
# )
|
|
630
|
+
with self.subTest("Relationship field name"):
|
|
631
|
+
self.assertEqual(
|
|
632
|
+
filtering.get_filter_field_label(device_filter_set_filters[f"cr_{self.peer_relationship.key}__peer"]),
|
|
633
|
+
self.peer_relationship.source_label,
|
|
634
|
+
)
|
|
692
635
|
|
|
693
636
|
with self.subTest("Custom field with label"):
|
|
694
637
|
self.assertEqual(
|
|
@@ -714,3 +657,24 @@ class FieldNameToDisplayTest(TestCase):
|
|
|
714
657
|
# This shouldn't ever be an input because get_filter_field_label
|
|
715
658
|
# will use the label from the custom field instead of the field name
|
|
716
659
|
self.assertEqual(filtering._field_name_to_display("cr_sister_sites__peer"), "Cr_sister_sites peer")
|
|
660
|
+
|
|
661
|
+
|
|
662
|
+
class IsFooTest(TestCase):
|
|
663
|
+
def test_is_url(self):
|
|
664
|
+
"""Validate the operation of `is_url()`."""
|
|
665
|
+
with self.subTest("Test a valid URL."):
|
|
666
|
+
self.assertTrue(
|
|
667
|
+
data_utils.is_url("http://localhost:3000/api/extras/statuses/3256ead7-0745-432a-a031-3928c9b7d075/")
|
|
668
|
+
)
|
|
669
|
+
with self.subTest("Test an nvalid URL."):
|
|
670
|
+
self.assertFalse(data_utils.is_url("pizza"))
|
|
671
|
+
|
|
672
|
+
def test_is_uuid(self):
|
|
673
|
+
"""Validate the operation of `is_uuid()`."""
|
|
674
|
+
with self.subTest("Test valid UUID."):
|
|
675
|
+
self.assertTrue(data_utils.is_uuid(uuid.uuid4()))
|
|
676
|
+
self.assertTrue(data_utils.is_uuid(str(uuid.uuid4())))
|
|
677
|
+
with self.subTest("Test invalid UUID."):
|
|
678
|
+
self.assertFalse(data_utils.is_uuid(None))
|
|
679
|
+
self.assertFalse(data_utils.is_uuid(1))
|
|
680
|
+
self.assertFalse(data_utils.is_uuid("abc123"))
|
|
@@ -187,8 +187,8 @@ class NavRestrictedUI(TestCase):
|
|
|
187
187
|
return response.content.decode(response.charset)
|
|
188
188
|
|
|
189
189
|
@override_settings(HIDE_RESTRICTED_UI=True)
|
|
190
|
-
def
|
|
191
|
-
"""The "Installed
|
|
190
|
+
def test_installed_apps_visible_to_staff_with_hide_restricted_ui_true(self):
|
|
191
|
+
"""The "Installed Apps" menu item should be available to is_staff user regardless of HIDE_RESTRICTED_UI."""
|
|
192
192
|
# Make user admin
|
|
193
193
|
self.user.is_staff = True
|
|
194
194
|
self.user.save()
|
|
@@ -197,16 +197,15 @@ class NavRestrictedUI(TestCase):
|
|
|
197
197
|
self.assertInHTML(
|
|
198
198
|
f"""
|
|
199
199
|
<li>
|
|
200
|
-
<
|
|
201
|
-
<a href="{self.url}" data-item-weight="{self.item_weight}">Installed Plugins</a>
|
|
200
|
+
<a href="{self.url}" data-item-weight="{self.item_weight}">Installed Apps</a>
|
|
202
201
|
</li>
|
|
203
202
|
""",
|
|
204
203
|
response_content,
|
|
205
204
|
)
|
|
206
205
|
|
|
207
206
|
@override_settings(HIDE_RESTRICTED_UI=False)
|
|
208
|
-
def
|
|
209
|
-
"""The "Installed
|
|
207
|
+
def test_installed_apps_visible_to_staff_with_hide_restricted_ui_false(self):
|
|
208
|
+
"""The "Installed Apps" menu item should be available to is_staff user regardless of HIDE_RESTRICTED_UI."""
|
|
210
209
|
# Make user admin
|
|
211
210
|
self.user.is_staff = True
|
|
212
211
|
self.user.save()
|
|
@@ -215,30 +214,28 @@ class NavRestrictedUI(TestCase):
|
|
|
215
214
|
self.assertInHTML(
|
|
216
215
|
f"""
|
|
217
216
|
<li>
|
|
218
|
-
<
|
|
219
|
-
<a href="{self.url}" data-item-weight="{self.item_weight}">Installed Plugins</a>
|
|
217
|
+
<a href="{self.url}" data-item-weight="{self.item_weight}">Installed Apps</a>
|
|
220
218
|
</li>
|
|
221
219
|
""",
|
|
222
220
|
response_content,
|
|
223
221
|
)
|
|
224
222
|
|
|
225
223
|
@override_settings(HIDE_RESTRICTED_UI=True)
|
|
226
|
-
def
|
|
227
|
-
"""The "Installed
|
|
224
|
+
def test_installed_apps_not_visible_to_non_staff_user_with_hide_restricted_ui_true(self):
|
|
225
|
+
"""The "Installed Apps" menu item should be hidden from a non-staff user when HIDE_RESTRICTED_UI=True."""
|
|
228
226
|
response_content = self.make_request()
|
|
229
227
|
|
|
230
|
-
self.assertNotRegex(response_content, r"Installed\s+
|
|
228
|
+
self.assertNotRegex(response_content, r"Installed\s+Apps")
|
|
231
229
|
|
|
232
230
|
@override_settings(HIDE_RESTRICTED_UI=False)
|
|
233
|
-
def
|
|
234
|
-
"""The "Installed
|
|
231
|
+
def test_installed_apps_disabled_to_non_staff_user_with_hide_restricted_ui_false(self):
|
|
232
|
+
"""The "Installed Apps" menu item should be disabled for a non-staff user when HIDE_RESTRICTED_UI=False."""
|
|
235
233
|
response_content = self.make_request()
|
|
236
234
|
|
|
237
235
|
self.assertInHTML(
|
|
238
236
|
f"""
|
|
239
237
|
<li class="disabled">
|
|
240
|
-
<
|
|
241
|
-
<a href="{self.url}" data-item-weight="{self.item_weight}">Installed Plugins</a>
|
|
238
|
+
<a href="{self.url}" data-item-weight="{self.item_weight}">Installed Apps</a>
|
|
242
239
|
</li>
|
|
243
240
|
""",
|
|
244
241
|
response_content,
|
nautobot/core/utils/data.py
CHANGED
|
@@ -2,6 +2,7 @@ from collections import OrderedDict, namedtuple
|
|
|
2
2
|
from decimal import Decimal
|
|
3
3
|
import uuid
|
|
4
4
|
|
|
5
|
+
from django.core import validators
|
|
5
6
|
from django.template import engines
|
|
6
7
|
|
|
7
8
|
from nautobot.dcim import choices # TODO move dcim.choices.CableLengthUnitChoices into core
|
|
@@ -66,6 +67,22 @@ def is_uuid(value):
|
|
|
66
67
|
return False
|
|
67
68
|
|
|
68
69
|
|
|
70
|
+
def is_url(value):
|
|
71
|
+
"""
|
|
72
|
+
Validate whether a value is a URL.
|
|
73
|
+
|
|
74
|
+
Args:
|
|
75
|
+
value (str): String to validate.
|
|
76
|
+
|
|
77
|
+
Returns:
|
|
78
|
+
bool
|
|
79
|
+
"""
|
|
80
|
+
try:
|
|
81
|
+
return validators.URLValidator()(value) is None
|
|
82
|
+
except validators.ValidationError:
|
|
83
|
+
return False
|
|
84
|
+
|
|
85
|
+
|
|
69
86
|
def render_jinja2(template_code, context):
|
|
70
87
|
"""
|
|
71
88
|
Render a Jinja2 template with the provided context. Return the rendered content.
|
|
@@ -9,8 +9,8 @@ from nautobot.core.settings import LOG_DEPRECATION_WARNINGS
|
|
|
9
9
|
logger = logging.getLogger(__name__)
|
|
10
10
|
|
|
11
11
|
|
|
12
|
-
def
|
|
13
|
-
"""Decorator to mark a class as deprecated
|
|
12
|
+
def class_deprecated(message):
|
|
13
|
+
"""Decorator to mark a class as deprecated with a custom message about what to do instead of subclassing it."""
|
|
14
14
|
|
|
15
15
|
def decorate(cls):
|
|
16
16
|
def init_subclass(new_subclass):
|
|
@@ -24,8 +24,7 @@ def class_deprecated_in_favor_of(replacement_class):
|
|
|
24
24
|
stacklevel = 1
|
|
25
25
|
warnings.warn(
|
|
26
26
|
f"Class {cls.__name__} is deprecated, and will be removed in a future Nautobot release. "
|
|
27
|
-
f"Instead of deriving {new_subclass.__name__} from {cls.__name__}, "
|
|
28
|
-
f"please migrate your code to inherit from class {replacement_class.__name__} instead.",
|
|
27
|
+
f"Instead of deriving {new_subclass.__name__} from {cls.__name__}, {message}.",
|
|
29
28
|
DeprecationWarning,
|
|
30
29
|
stacklevel=stacklevel,
|
|
31
30
|
)
|
|
@@ -33,8 +32,7 @@ def class_deprecated_in_favor_of(replacement_class):
|
|
|
33
32
|
# Since DeprecationWarnings are silenced by default, also log a traditional warning.
|
|
34
33
|
logger.warning(
|
|
35
34
|
f"Class {cls.__name__} is deprecated, and will be removed in a future Nautobot release. "
|
|
36
|
-
f"Instead of deriving {new_subclass.__name__} from {cls.__name__}, "
|
|
37
|
-
f"please migrate your code to inherit from class {replacement_class.__name__} instead.",
|
|
35
|
+
f"Instead of deriving {new_subclass.__name__} from {cls.__name__}, {message}.",
|
|
38
36
|
stacklevel=stacklevel,
|
|
39
37
|
)
|
|
40
38
|
|
|
@@ -42,3 +40,8 @@ def class_deprecated_in_favor_of(replacement_class):
|
|
|
42
40
|
return cls
|
|
43
41
|
|
|
44
42
|
return decorate
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def class_deprecated_in_favor_of(replacement_class):
|
|
46
|
+
"""Decorator to mark a class as deprecated and suggest a replacement class if it is subclassed from."""
|
|
47
|
+
return class_deprecated(f"please migrate your code to inherit from class {replacement_class.__name__} instead")
|
nautobot/core/utils/filtering.py
CHANGED
|
@@ -123,8 +123,13 @@ def get_filterset_parameter_form_field(model, parameter, filterset=None):
|
|
|
123
123
|
form_attr["query_params"] = {"content_types": model._meta.label_lower}
|
|
124
124
|
|
|
125
125
|
form_field = DynamicModelMultipleChoiceField(**form_attr)
|
|
126
|
-
elif isinstance(
|
|
127
|
-
|
|
126
|
+
elif isinstance(
|
|
127
|
+
field, ContentTypeMultipleChoiceFilter
|
|
128
|
+
): # While there are other objects using `ContentTypeMultipleChoiceFilter`, the case where
|
|
129
|
+
# models that have sucha filter and the `verbose_name_plural` has multiple words is ony one: "dynamic groups".
|
|
130
|
+
from nautobot.core.models.fields import slugify_dashes_to_underscores # Avoid circular import
|
|
131
|
+
|
|
132
|
+
plural_name = slugify_dashes_to_underscores(model._meta.verbose_name_plural)
|
|
128
133
|
try:
|
|
129
134
|
form_field = MultipleContentTypeField(choices_as_strings=True, feature=plural_name)
|
|
130
135
|
except KeyError:
|
|
@@ -133,7 +138,7 @@ def get_filterset_parameter_form_field(model, parameter, filterset=None):
|
|
|
133
138
|
# In this case use queryset
|
|
134
139
|
queryset_map = {
|
|
135
140
|
"tags": TaggableClassesQuery,
|
|
136
|
-
"
|
|
141
|
+
"job_hooks": ChangeLoggedModelsQuery,
|
|
137
142
|
"roles": RoleModelsQuery,
|
|
138
143
|
}
|
|
139
144
|
form_field = MultipleContentTypeField(
|
nautobot/core/utils/git.py
CHANGED
|
@@ -69,17 +69,25 @@ class GitRepo:
|
|
|
69
69
|
if url not in self.repo.remotes.origin.urls:
|
|
70
70
|
self.repo.remotes.origin.set_url(url)
|
|
71
71
|
|
|
72
|
+
@property
|
|
73
|
+
def head(self):
|
|
74
|
+
"""Current checked out repository head commit."""
|
|
75
|
+
return self.repo.head.commit.hexsha
|
|
76
|
+
|
|
72
77
|
def fetch(self):
|
|
73
78
|
self.repo.remotes.origin.fetch()
|
|
74
79
|
|
|
75
80
|
def checkout(self, branch, commit_hexsha=None):
|
|
76
81
|
"""
|
|
77
82
|
Check out the given branch, and optionally the specified commit within that branch.
|
|
83
|
+
|
|
84
|
+
Returns:
|
|
85
|
+
(str, bool): commit_hexsha the repo contains now, whether any change occurred
|
|
78
86
|
"""
|
|
79
87
|
# Short-circuit logic - do we already have this commit checked out?
|
|
80
|
-
if commit_hexsha and commit_hexsha == self.
|
|
88
|
+
if commit_hexsha and commit_hexsha == self.head:
|
|
81
89
|
logger.debug(f"Commit {commit_hexsha} is already checked out.")
|
|
82
|
-
return commit_hexsha
|
|
90
|
+
return (commit_hexsha, False)
|
|
83
91
|
|
|
84
92
|
self.fetch()
|
|
85
93
|
if commit_hexsha:
|
|
@@ -92,7 +100,7 @@ class GitRepo:
|
|
|
92
100
|
raise RuntimeError(f"Requested to check out commit `{commit_hexsha}`, but it's not in branch {branch}!")
|
|
93
101
|
logger.info(f"Checking out commit `{commit_hexsha}` on branch `{branch}`...")
|
|
94
102
|
self.repo.git.checkout(commit_hexsha)
|
|
95
|
-
return commit_hexsha
|
|
103
|
+
return (commit_hexsha, True)
|
|
96
104
|
|
|
97
105
|
if branch in self.repo.heads:
|
|
98
106
|
branch_head = self.repo.heads[branch]
|
|
@@ -117,7 +125,7 @@ class GitRepo:
|
|
|
117
125
|
self.repo.head.reset(f"origin/{branch}", index=True, working_tree=True)
|
|
118
126
|
commit_hexsha = self.repo.head.reference.commit.hexsha
|
|
119
127
|
logger.info(f"Latest commit on branch `{branch}` is `{commit_hexsha}`")
|
|
120
|
-
return commit_hexsha
|
|
128
|
+
return (commit_hexsha, True)
|
|
121
129
|
|
|
122
130
|
def diff_remote(self, branch):
|
|
123
131
|
logger.debug("Fetching from remote.")
|
nautobot/core/utils/lookup.py
CHANGED
|
@@ -85,7 +85,9 @@ def get_route_for_model(model, action, api=False):
|
|
|
85
85
|
else:
|
|
86
86
|
app_label = model._meta.app_label
|
|
87
87
|
prefix = f"{app_label}{suffix}:{model._meta.model_name}"
|
|
88
|
-
sep = "
|
|
88
|
+
sep = ""
|
|
89
|
+
if action != "":
|
|
90
|
+
sep = "_" if not api else "-"
|
|
89
91
|
viewname = f"{prefix}{sep}{action}"
|
|
90
92
|
|
|
91
93
|
if model._meta.app_label in settings.PLUGINS:
|
nautobot/core/utils/requests.py
CHANGED
|
@@ -1,118 +1,15 @@
|
|
|
1
|
-
import copy
|
|
2
1
|
import re
|
|
3
2
|
|
|
4
3
|
from django import forms
|
|
5
|
-
from django.contrib.auth import get_user_model
|
|
6
4
|
from django.contrib.contenttypes.models import ContentType
|
|
7
5
|
from django.core.exceptions import ValidationError
|
|
8
6
|
from django.http import QueryDict
|
|
9
|
-
from django.utils.functional import SimpleLazyObject
|
|
10
7
|
import django_filters
|
|
11
8
|
|
|
12
|
-
from nautobot.core import
|
|
9
|
+
from nautobot.core import exceptions
|
|
13
10
|
from nautobot.core.utils.filtering import get_filterset_field
|
|
14
11
|
|
|
15
12
|
|
|
16
|
-
#
|
|
17
|
-
# Fake request object
|
|
18
|
-
#
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
class NautobotFakeRequest:
|
|
22
|
-
"""
|
|
23
|
-
A fake request object which is explicitly defined at the module level so it is able to be pickled. It simply
|
|
24
|
-
takes what is passed to it as kwargs on init and sets them as instance variables.
|
|
25
|
-
"""
|
|
26
|
-
|
|
27
|
-
def __init__(self, _dict):
|
|
28
|
-
self.__dict__ = _dict
|
|
29
|
-
|
|
30
|
-
def _get_user(self):
|
|
31
|
-
"""Lazy lookup function for self.user."""
|
|
32
|
-
if not self._cached_user:
|
|
33
|
-
User = get_user_model()
|
|
34
|
-
self._cached_user = User.objects.get(pk=self._user_pk)
|
|
35
|
-
return self._cached_user
|
|
36
|
-
|
|
37
|
-
def _init_user(self):
|
|
38
|
-
"""Set up self.user as a lazy attribute, similar to a real Django Request object."""
|
|
39
|
-
self._cached_user = None
|
|
40
|
-
self.user = SimpleLazyObject(self._get_user)
|
|
41
|
-
|
|
42
|
-
def nautobot_serialize(self):
|
|
43
|
-
"""
|
|
44
|
-
Serialize a JSON representation that is safe to pass to Celery.
|
|
45
|
-
|
|
46
|
-
This function is called from nautobot.core.celery.NautobotKombuJSONEncoder.
|
|
47
|
-
"""
|
|
48
|
-
data = copy.deepcopy(self.__dict__)
|
|
49
|
-
# We don't want to try to pickle/unpickle or serialize/deserialize the actual User object,
|
|
50
|
-
# but make sure we do store its PK so that we can look it up on-demand after being deserialized.
|
|
51
|
-
user = data.pop("user")
|
|
52
|
-
data.pop("_cached_user", None)
|
|
53
|
-
if "_user_pk" not in data:
|
|
54
|
-
# We have a user but haven't stored its PK yet, so look it up and store it
|
|
55
|
-
data["_user_pk"] = user.pk
|
|
56
|
-
return data
|
|
57
|
-
|
|
58
|
-
@classmethod
|
|
59
|
-
def nautobot_deserialize(cls, data):
|
|
60
|
-
"""
|
|
61
|
-
Deserialize a JSON representation that is safe to pass to Celery and return a NautobotFakeRequest instance.
|
|
62
|
-
|
|
63
|
-
This function is registered for usage by Celery in nautobot/core/celery/__init__.py
|
|
64
|
-
"""
|
|
65
|
-
obj = cls(data)
|
|
66
|
-
obj._init_user()
|
|
67
|
-
return obj
|
|
68
|
-
|
|
69
|
-
def __getstate__(self):
|
|
70
|
-
"""
|
|
71
|
-
Implement `pickle` serialization API.
|
|
72
|
-
|
|
73
|
-
It turns out that Celery uses pickle internally in apply_async()/send_job() even if we have configured Celery
|
|
74
|
-
to use JSON for all I/O (and we do, see settings.py), so we need to support pickle and JSON both.
|
|
75
|
-
"""
|
|
76
|
-
return self.nautobot_serialize()
|
|
77
|
-
|
|
78
|
-
def __setstate__(self, state):
|
|
79
|
-
"""
|
|
80
|
-
Implement `pickle` deserialization API.
|
|
81
|
-
|
|
82
|
-
It turns out that Celery uses pickle internally in apply_async()/send_job() even if we have configured Celery
|
|
83
|
-
to use JSON for all I/O (and we do, see settings.py), so we need to support pickle and JSON both.
|
|
84
|
-
"""
|
|
85
|
-
# Generic __setstate__ behavior
|
|
86
|
-
self.__dict__.update(state)
|
|
87
|
-
# Set up lazy `self.user` attribute based on `state["_user_pk"]`
|
|
88
|
-
self._init_user()
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
def copy_safe_request(request):
|
|
92
|
-
"""
|
|
93
|
-
Copy selected attributes from a request object into a new fake request object. This is needed in places where
|
|
94
|
-
thread safe pickling of the useful request data is needed.
|
|
95
|
-
|
|
96
|
-
Note that `request.FILES` is explicitly omitted because they cannot be uniformly serialized.
|
|
97
|
-
"""
|
|
98
|
-
meta = {
|
|
99
|
-
k: request.META[k]
|
|
100
|
-
for k in constants.HTTP_REQUEST_META_SAFE_COPY
|
|
101
|
-
if k in request.META and isinstance(request.META[k], str)
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
return NautobotFakeRequest(
|
|
105
|
-
{
|
|
106
|
-
"META": meta,
|
|
107
|
-
"POST": request.POST,
|
|
108
|
-
"GET": request.GET,
|
|
109
|
-
"user": request.user,
|
|
110
|
-
"path": request.path,
|
|
111
|
-
"id": getattr(request, "id", None), # UUID assigned by middleware
|
|
112
|
-
}
|
|
113
|
-
)
|
|
114
|
-
|
|
115
|
-
|
|
116
13
|
def convert_querydict_to_factory_formset_acceptable_querydict(request_querydict, filterset):
|
|
117
14
|
"""
|
|
118
15
|
Convert request QueryDict/GET into an acceptable factory formset QueryDict
|
nautobot/core/views/__init__.py
CHANGED
|
@@ -34,6 +34,7 @@ from nautobot.extras.forms import GraphQLQueryForm
|
|
|
34
34
|
|
|
35
35
|
class HomeView(AccessMixin, TemplateView):
|
|
36
36
|
template_name = "home.html"
|
|
37
|
+
use_new_ui = True
|
|
37
38
|
|
|
38
39
|
def render_additional_content(self, request, context, details):
|
|
39
40
|
# Collect all custom data using callback functions.
|