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
|
@@ -12,14 +12,10 @@ from django.urls import get_resolver, URLPattern
|
|
|
12
12
|
|
|
13
13
|
from nautobot.core.apps import (
|
|
14
14
|
NautobotConfig,
|
|
15
|
-
NavMenuButton,
|
|
16
|
-
NavMenuGroup,
|
|
17
|
-
NavMenuItem,
|
|
18
15
|
NavMenuTab,
|
|
19
16
|
register_menu_items,
|
|
20
17
|
register_homepage_panels,
|
|
21
18
|
)
|
|
22
|
-
from nautobot.core.choices import ButtonColorChoices
|
|
23
19
|
from nautobot.core.utils.deprecation import class_deprecated_in_favor_of
|
|
24
20
|
from nautobot.core.signals import nautobot_database_ready
|
|
25
21
|
from nautobot.extras.choices import BannerClassChoices
|
|
@@ -76,11 +72,6 @@ class NautobotAppConfig(NautobotConfig):
|
|
|
76
72
|
# along with the plugin.
|
|
77
73
|
installed_apps = []
|
|
78
74
|
|
|
79
|
-
# Cacheops configuration. Cache all operations by default.
|
|
80
|
-
caching_config = {
|
|
81
|
-
"*": {"ops": "all"},
|
|
82
|
-
}
|
|
83
|
-
|
|
84
75
|
# Default constance configuration parameters
|
|
85
76
|
constance_config = {}
|
|
86
77
|
|
|
@@ -244,7 +235,6 @@ class NautobotAppConfig(NautobotConfig):
|
|
|
244
235
|
# TODO(jathan): This is fine for now, but as we expand the functionality
|
|
245
236
|
# of plugins, we'll need to consider something like pydantic or attrs.
|
|
246
237
|
setting_validations = {
|
|
247
|
-
"caching_config": dict,
|
|
248
238
|
"default_settings": dict,
|
|
249
239
|
"installed_apps": list,
|
|
250
240
|
"middleware": list,
|
|
@@ -515,124 +505,17 @@ def register_filter_extensions(filter_extensions, plugin_name):
|
|
|
515
505
|
#
|
|
516
506
|
|
|
517
507
|
|
|
518
|
-
# 2.2 TODO: remove in favor of NavMenuItem
|
|
519
|
-
@class_deprecated_in_favor_of(NavMenuItem)
|
|
520
|
-
class PluginMenuItem:
|
|
521
|
-
"""
|
|
522
|
-
This class represents a navigation menu item. This constitutes primary link and its text, but also allows for
|
|
523
|
-
specifying additional link buttons that appear to the right of the item in the van menu.
|
|
524
|
-
|
|
525
|
-
Links are specified as Django reverse URL strings.
|
|
526
|
-
Buttons are each specified as a list of PluginMenuButton instances.
|
|
527
|
-
"""
|
|
528
|
-
|
|
529
|
-
permissions = []
|
|
530
|
-
buttons = []
|
|
531
|
-
|
|
532
|
-
def __init__(self, link, link_text, permissions=None, buttons=None):
|
|
533
|
-
self.link = link
|
|
534
|
-
self.link_text = link_text
|
|
535
|
-
if permissions is not None:
|
|
536
|
-
if not isinstance(permissions, (list, tuple)):
|
|
537
|
-
raise TypeError("Permissions must be passed as a tuple or list.")
|
|
538
|
-
self.permissions = permissions
|
|
539
|
-
if buttons is not None:
|
|
540
|
-
if not isinstance(buttons, (list, tuple)):
|
|
541
|
-
raise TypeError("Buttons must be passed as a tuple or list.")
|
|
542
|
-
self.buttons = buttons
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
# 2.2 TODO: remove in favor of NavMenuButton
|
|
546
|
-
@class_deprecated_in_favor_of(NavMenuButton)
|
|
547
|
-
class PluginMenuButton:
|
|
548
|
-
"""
|
|
549
|
-
This class represents a button within a PluginMenuItem. Note that button colors should come from
|
|
550
|
-
ButtonColorChoices.
|
|
551
|
-
"""
|
|
552
|
-
|
|
553
|
-
color = ButtonColorChoices.DEFAULT
|
|
554
|
-
permissions = []
|
|
555
|
-
|
|
556
|
-
def __init__(self, link, title, icon_class, color=None, permissions=None):
|
|
557
|
-
self.link = link
|
|
558
|
-
self.title = title
|
|
559
|
-
self.icon_class = icon_class
|
|
560
|
-
if permissions is not None:
|
|
561
|
-
if not isinstance(permissions, (list, tuple)):
|
|
562
|
-
raise TypeError("Permissions must be passed as a tuple or list.")
|
|
563
|
-
self.permissions = permissions
|
|
564
|
-
if color is not None:
|
|
565
|
-
if color not in ButtonColorChoices.values():
|
|
566
|
-
raise ValueError("Button color must be a choice within ButtonColorChoices.")
|
|
567
|
-
self.color = color
|
|
568
|
-
|
|
569
|
-
|
|
570
508
|
def register_plugin_menu_items(section_name, menu_items):
|
|
571
509
|
"""
|
|
572
|
-
Register a list of
|
|
510
|
+
Register a list of NavMenuTab instances for a given menu section (e.g. plugin name)
|
|
573
511
|
"""
|
|
574
|
-
new_menu_items = []
|
|
575
|
-
new_menu_item_weight = 100
|
|
576
|
-
|
|
577
512
|
nav_menu_items = set()
|
|
578
513
|
|
|
579
|
-
permissions = set()
|
|
580
|
-
|
|
581
514
|
for menu_item in menu_items:
|
|
582
|
-
if isinstance(menu_item,
|
|
583
|
-
# translate old-style plugin menu definitions into the new nav-menu items and buttons
|
|
584
|
-
|
|
585
|
-
new_menu_button_weight = 100
|
|
586
|
-
new_menu_buttons = []
|
|
587
|
-
for button in menu_item.buttons:
|
|
588
|
-
new_menu_buttons.append(
|
|
589
|
-
NavMenuButton(
|
|
590
|
-
link=button.link,
|
|
591
|
-
title=button.title,
|
|
592
|
-
icon_class=button.icon_class,
|
|
593
|
-
button_class=button.color,
|
|
594
|
-
permissions=button.permissions,
|
|
595
|
-
weight=new_menu_button_weight,
|
|
596
|
-
)
|
|
597
|
-
)
|
|
598
|
-
new_menu_button_weight += 100
|
|
599
|
-
|
|
600
|
-
new_menu_items.append(
|
|
601
|
-
NavMenuItem(
|
|
602
|
-
link=menu_item.link,
|
|
603
|
-
name=menu_item.link_text,
|
|
604
|
-
permissions=menu_item.permissions,
|
|
605
|
-
weight=new_menu_item_weight,
|
|
606
|
-
buttons=new_menu_buttons,
|
|
607
|
-
)
|
|
608
|
-
)
|
|
609
|
-
new_menu_item_weight += 100
|
|
610
|
-
permissions = permissions.union(menu_item.permissions)
|
|
611
|
-
elif isinstance(menu_item, NavMenuTab):
|
|
515
|
+
if isinstance(menu_item, NavMenuTab):
|
|
612
516
|
nav_menu_items.add(menu_item)
|
|
613
517
|
else:
|
|
614
|
-
raise TypeError("Top level objects need to be an instance of NavMenuTab
|
|
615
|
-
|
|
616
|
-
if new_menu_items:
|
|
617
|
-
# wrap bare item/button list into the default "Plugins" menu tab and appropriate grouping
|
|
618
|
-
if registry["nav_menu"]["tabs"].get("Plugins"):
|
|
619
|
-
weight = (
|
|
620
|
-
registry["nav_menu"]["tabs"]["Plugins"]["groups"][
|
|
621
|
-
list(registry["nav_menu"]["tabs"]["Plugins"]["groups"])[-1]
|
|
622
|
-
]["weight"]
|
|
623
|
-
+ 100
|
|
624
|
-
)
|
|
625
|
-
else:
|
|
626
|
-
weight = 100
|
|
627
|
-
nav_menu_items.add(
|
|
628
|
-
NavMenuTab(
|
|
629
|
-
name="Plugins",
|
|
630
|
-
weight=5000,
|
|
631
|
-
# Permissions cast to tuple to match development pattern.
|
|
632
|
-
permissions=tuple(permissions),
|
|
633
|
-
groups=(NavMenuGroup(name=section_name, weight=weight, items=new_menu_items),),
|
|
634
|
-
),
|
|
635
|
-
)
|
|
518
|
+
raise TypeError(f"Top level objects need to be an instance of NavMenuTab: {menu_item}")
|
|
636
519
|
|
|
637
520
|
register_menu_items(nav_menu_items)
|
|
638
521
|
|
nautobot/extras/plugins/utils.py
CHANGED
|
@@ -103,9 +103,6 @@ def load_plugin(plugin_name, settings):
|
|
|
103
103
|
if middleware not in settings.MIDDLEWARE:
|
|
104
104
|
settings.MIDDLEWARE.append(middleware)
|
|
105
105
|
|
|
106
|
-
# Update caching configg
|
|
107
|
-
settings.CACHEOPS.update({f"{plugin_name}.{key}": value for key, value in plugin_config.caching_config.items()})
|
|
108
|
-
|
|
109
106
|
# Update Constance Config and Constance Fieldset
|
|
110
107
|
if plugin_config.constance_config:
|
|
111
108
|
app_config = {}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
from functools import wraps
|
|
2
2
|
|
|
3
|
-
from django.
|
|
3
|
+
from django.apps import apps
|
|
4
4
|
|
|
5
5
|
from nautobot.extras.plugins import CustomValidator
|
|
6
6
|
from nautobot.extras.registry import registry
|
|
@@ -40,6 +40,7 @@ def wrap_model_clean_methods():
|
|
|
40
40
|
"""
|
|
41
41
|
Helper function that wraps plugin model validator registered clean methods for all applicable models
|
|
42
42
|
"""
|
|
43
|
-
for
|
|
44
|
-
|
|
45
|
-
|
|
43
|
+
for app_label, models in FeatureQuery("custom_validators").as_dict():
|
|
44
|
+
for model in models:
|
|
45
|
+
model_class = apps.get_model(app_label=app_label, model_name=model)
|
|
46
|
+
model_class.clean = custom_validator_clean(model_class.clean)
|
nautobot/extras/plugins/views.py
CHANGED
|
@@ -88,7 +88,7 @@ class InstalledPluginDetailView(LoginRequiredMixin, View):
|
|
|
88
88
|
|
|
89
89
|
class InstalledPluginsAPIView(NautobotAPIVersionMixin, APIView):
|
|
90
90
|
"""
|
|
91
|
-
API view for listing all installed
|
|
91
|
+
API view for listing all installed non-core Apps.
|
|
92
92
|
"""
|
|
93
93
|
|
|
94
94
|
permission_classes = [permissions.IsAdminUser]
|
|
@@ -99,15 +99,28 @@ class InstalledPluginsAPIView(NautobotAPIVersionMixin, APIView):
|
|
|
99
99
|
|
|
100
100
|
@staticmethod
|
|
101
101
|
def _get_plugin_data(plugin_app_config):
|
|
102
|
+
try:
|
|
103
|
+
home_url = reverse(plugin_app_config.home_view_name)
|
|
104
|
+
except NoReverseMatch:
|
|
105
|
+
home_url = None
|
|
106
|
+
try:
|
|
107
|
+
config_url = reverse(plugin_app_config.config_view_name)
|
|
108
|
+
except NoReverseMatch:
|
|
109
|
+
config_url = None
|
|
110
|
+
try:
|
|
111
|
+
docs_url = reverse(plugin_app_config.docs_view_name)
|
|
112
|
+
except NoReverseMatch:
|
|
113
|
+
docs_url = None
|
|
102
114
|
return {
|
|
103
115
|
"name": plugin_app_config.verbose_name,
|
|
104
116
|
"package": plugin_app_config.name,
|
|
105
117
|
"author": plugin_app_config.author,
|
|
106
118
|
"author_email": plugin_app_config.author_email,
|
|
107
119
|
"description": plugin_app_config.description,
|
|
108
|
-
# 2.0 TODO: Remove verison key/value when bumping to major revision
|
|
109
|
-
"verison": plugin_app_config.version,
|
|
110
120
|
"version": plugin_app_config.version,
|
|
121
|
+
"home_url": home_url,
|
|
122
|
+
"config_url": config_url,
|
|
123
|
+
"docs_url": docs_url,
|
|
111
124
|
}
|
|
112
125
|
|
|
113
126
|
@extend_schema(exclude=True)
|
nautobot/extras/querysets.py
CHANGED
|
@@ -185,18 +185,12 @@ class JobQuerySet(RestrictedQuerySet):
|
|
|
185
185
|
|
|
186
186
|
def get_for_class_path(self, class_path):
|
|
187
187
|
try:
|
|
188
|
-
|
|
189
|
-
repository_slug = None
|
|
190
|
-
if source.startswith("git."):
|
|
191
|
-
repository_slug = source[4:]
|
|
192
|
-
source = "git"
|
|
188
|
+
module_name, job_class_name = class_path.rsplit(".", 1)
|
|
193
189
|
except ValueError: # not a class_path perhaps?
|
|
194
190
|
raise self.model.DoesNotExist()
|
|
195
191
|
return self.get(
|
|
196
|
-
source=source,
|
|
197
192
|
module_name=module_name,
|
|
198
193
|
job_class_name=job_class_name,
|
|
199
|
-
git_repository__slug=repository_slug,
|
|
200
194
|
)
|
|
201
195
|
|
|
202
196
|
|
nautobot/extras/registry.py
CHANGED
nautobot/extras/signals.py
CHANGED
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
import os
|
|
2
2
|
import random
|
|
3
3
|
import shutil
|
|
4
|
-
import uuid
|
|
5
4
|
import logging
|
|
6
5
|
from datetime import timedelta
|
|
7
6
|
|
|
8
|
-
from cacheops.signals import cache_invalidated, cache_read
|
|
9
7
|
from django.contrib.contenttypes.models import ContentType
|
|
10
8
|
from django.core.exceptions import ValidationError
|
|
11
9
|
from django.db import transaction
|
|
@@ -13,8 +11,8 @@ from django.db.models.signals import m2m_changed, pre_delete, pre_save
|
|
|
13
11
|
from django.dispatch import receiver
|
|
14
12
|
from django.utils import timezone
|
|
15
13
|
from django_prometheus.models import model_deletes, model_inserts, model_updates
|
|
16
|
-
from prometheus_client import Counter
|
|
17
14
|
|
|
15
|
+
from nautobot.core.celery import app, import_jobs_as_celery_tasks
|
|
18
16
|
from nautobot.core.utils.config import get_settings_or_config
|
|
19
17
|
from nautobot.extras.tasks import delete_custom_field_data, provision_field
|
|
20
18
|
from nautobot.extras.utils import refresh_job_model_from_job_class
|
|
@@ -155,30 +153,6 @@ def handle_cf_removed_obj_types(instance, action, pk_set, **kwargs):
|
|
|
155
153
|
m2m_changed.connect(handle_cf_removed_obj_types, sender=CustomField.content_types.through)
|
|
156
154
|
|
|
157
155
|
|
|
158
|
-
#
|
|
159
|
-
# Caching
|
|
160
|
-
#
|
|
161
|
-
|
|
162
|
-
cacheops_cache_hit = Counter("cacheops_cache_hit", "Number of cache hits")
|
|
163
|
-
cacheops_cache_miss = Counter("cacheops_cache_miss", "Number of cache misses")
|
|
164
|
-
cacheops_cache_invalidated = Counter("cacheops_cache_invalidated", "Number of cache invalidations")
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
def cache_read_collector(sender, func, hit, **kwargs):
|
|
168
|
-
if hit:
|
|
169
|
-
cacheops_cache_hit.inc()
|
|
170
|
-
else:
|
|
171
|
-
cacheops_cache_miss.inc()
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
def cache_invalidated_collector(sender, obj_dict, **kwargs):
|
|
175
|
-
cacheops_cache_invalidated.inc()
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
cache_read.connect(cache_read_collector)
|
|
179
|
-
cache_invalidated.connect(cache_invalidated_collector)
|
|
180
|
-
|
|
181
|
-
|
|
182
156
|
#
|
|
183
157
|
# Datasources
|
|
184
158
|
#
|
|
@@ -195,11 +169,12 @@ def git_repository_pre_delete(instance, **kwargs):
|
|
|
195
169
|
"""
|
|
196
170
|
from nautobot.extras.datasources import refresh_datasource_content
|
|
197
171
|
|
|
172
|
+
# FIXME(jathan): In light of jobs overhaul and Git syncs as jobs, we need to rethink this. We
|
|
173
|
+
# might instead make "delete" another Job class and call it here, but also think about how
|
|
174
|
+
# worker events will be such as firing the worker event here.
|
|
198
175
|
job_result = JobResult.objects.create(
|
|
199
176
|
name=instance.name,
|
|
200
|
-
obj_type=ContentType.objects.get_for_model(instance),
|
|
201
177
|
user=None,
|
|
202
|
-
task_id=uuid.uuid4(),
|
|
203
178
|
status=JobResultStatusChoices.STATUS_STARTED,
|
|
204
179
|
)
|
|
205
180
|
|
|
@@ -210,13 +185,13 @@ def git_repository_pre_delete(instance, **kwargs):
|
|
|
210
185
|
|
|
211
186
|
refresh_datasource_content("extras.gitrepository", instance, None, job_result, delete=True)
|
|
212
187
|
|
|
213
|
-
|
|
214
|
-
job_result.set_status(JobResultStatusChoices.STATUS_SUCCESS)
|
|
215
|
-
job_result.save()
|
|
216
|
-
|
|
217
|
-
# TODO(Glenn): In a distributed Nautobot deployment, each Django instance and/or worker instance may have its own clone
|
|
188
|
+
# In a distributed Nautobot deployment, each Django instance and/or worker instance may have its own clone
|
|
218
189
|
# of this repository; we need some way to ensure that all such clones are deleted.
|
|
219
|
-
#
|
|
190
|
+
# In the Celery worker case, we can broadcast a control message to all workers to do so:
|
|
191
|
+
app.control.broadcast("discard_git_repository", repository_slug=instance.slug)
|
|
192
|
+
# But we don't have an equivalent way to broadcast to any other Django instances.
|
|
193
|
+
# For now we just delete the one that we have locally and rely on other methods,
|
|
194
|
+
# such as the import_jobs_as_celery_tasks() signal that runs on server startup,
|
|
220
195
|
# to clean up other clones as they're encountered.
|
|
221
196
|
if os.path.isdir(instance.filesystem_path):
|
|
222
197
|
shutil.rmtree(instance.filesystem_path)
|
|
@@ -262,40 +237,31 @@ def refresh_job_models(sender, *, apps, **kwargs):
|
|
|
262
237
|
"""
|
|
263
238
|
Callback for the nautobot_database_ready signal; updates Jobs in the database based on Job source file availability.
|
|
264
239
|
"""
|
|
240
|
+
from nautobot.extras.jobs import Job as JobClass # avoid circular import
|
|
241
|
+
|
|
265
242
|
Job = apps.get_model("extras", "Job")
|
|
266
|
-
GitRepository = apps.get_model("extras", "GitRepository") # pylint: disable=redefined-outer-name
|
|
267
243
|
|
|
268
244
|
# To make reverse migrations safe
|
|
269
|
-
if not hasattr(Job, "job_class_name")
|
|
245
|
+
if not hasattr(Job, "job_class_name"):
|
|
270
246
|
logger.info("Skipping refresh_job_models() as it appears Job model has not yet been migrated to latest.")
|
|
271
247
|
return
|
|
272
248
|
|
|
273
|
-
|
|
249
|
+
import_jobs_as_celery_tasks(app)
|
|
274
250
|
|
|
275
|
-
# TODO(Glenn): eventually this should be inverted so that get_jobs() relies on the database models...
|
|
276
|
-
job_classes = get_jobs()
|
|
277
251
|
job_models = []
|
|
278
|
-
for
|
|
279
|
-
|
|
280
|
-
if
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
job_model, _ = refresh_job_model_from_job_class(Job, source, job_class, git_repository=git_repository)
|
|
290
|
-
if job_model is not None:
|
|
291
|
-
job_models.append(job_model)
|
|
292
|
-
|
|
293
|
-
for job_model in Job.objects.all():
|
|
294
|
-
if job_model.installed and job_model not in job_models:
|
|
252
|
+
for task in app.tasks.values():
|
|
253
|
+
# Skip Celery tasks that aren't Jobs
|
|
254
|
+
if not isinstance(task, JobClass):
|
|
255
|
+
continue
|
|
256
|
+
|
|
257
|
+
job_model, _ = refresh_job_model_from_job_class(Job, task.__class__)
|
|
258
|
+
if job_model is not None:
|
|
259
|
+
job_models.append(job_model)
|
|
260
|
+
|
|
261
|
+
for job_model in Job.objects.filter(installed=True):
|
|
262
|
+
if job_model not in job_models:
|
|
295
263
|
logger.info(
|
|
296
|
-
"Job %s
|
|
297
|
-
job_model.source,
|
|
298
|
-
f"/{job_model.git_repository.slug}" if job_model.git_repository is not None else "",
|
|
264
|
+
"Job %s/%s is no longer installed",
|
|
299
265
|
job_model.module_name,
|
|
300
266
|
job_model.job_class_name,
|
|
301
267
|
)
|
nautobot/extras/tables.py
CHANGED
|
@@ -69,11 +69,11 @@ class="label label-{% if entry.content_identifier in record.provided_contents %}
|
|
|
69
69
|
"""
|
|
70
70
|
|
|
71
71
|
GITREPOSITORY_BUTTONS = """
|
|
72
|
-
<button data-url="{% url 'extras:gitrepository_sync'
|
|
72
|
+
<button data-url="{% url 'extras:gitrepository_sync' pk=record.pk %}" type="submit" class="btn btn-primary btn-xs sync-repository" title="Sync" {% if not perms.extras.change_gitrepository %}disabled="disabled"{% endif %}><i class="mdi mdi-source-branch-sync" aria-hidden="true"></i></button>
|
|
73
73
|
"""
|
|
74
74
|
|
|
75
75
|
JOB_BUTTONS = """
|
|
76
|
-
<a href="{% url 'extras:job_run'
|
|
76
|
+
<a href="{% url 'extras:job_run' pk=record.pk %}" class="btn btn-primary btn-xs" title="Run/Schedule" {% if not perms.extras.run_job or not record.runnable %}disabled="disabled"{% endif %}><i class="mdi mdi-play" aria-hidden="true"></i></a>
|
|
77
77
|
"""
|
|
78
78
|
|
|
79
79
|
OBJECTCHANGE_OBJECT = """
|
|
@@ -97,7 +97,7 @@ SCHEDULED_JOB_APPROVAL_QUEUE_BUTTONS = """
|
|
|
97
97
|
<button type="button"
|
|
98
98
|
onClick="handleDetailPostAction('{% url 'extras:scheduledjob_approval_request_view' pk=record.pk %}', '_dry_run')"
|
|
99
99
|
title="Dry Run"
|
|
100
|
-
class="btn btn-primary btn-xs"{% if not perms.extras.run_job %} disabled="disabled"{% endif %}>
|
|
100
|
+
class="btn btn-primary btn-xs"{% if not perms.extras.run_job or not record.job_model.supports_dryrun %} disabled="disabled"{% endif %}>
|
|
101
101
|
<i class="mdi mdi-play"></i>
|
|
102
102
|
</button>
|
|
103
103
|
<button type="button"
|
|
@@ -124,7 +124,7 @@ class ComputedFieldTable(BaseTable):
|
|
|
124
124
|
fields = (
|
|
125
125
|
"pk",
|
|
126
126
|
"label",
|
|
127
|
-
"
|
|
127
|
+
"key",
|
|
128
128
|
"content_type",
|
|
129
129
|
"description",
|
|
130
130
|
"weight",
|
|
@@ -132,7 +132,7 @@ class ComputedFieldTable(BaseTable):
|
|
|
132
132
|
default_columns = (
|
|
133
133
|
"pk",
|
|
134
134
|
"label",
|
|
135
|
-
"
|
|
135
|
+
"key",
|
|
136
136
|
"content_type",
|
|
137
137
|
"description",
|
|
138
138
|
)
|
|
@@ -169,7 +169,7 @@ class ConfigContextSchemaTable(BaseTable):
|
|
|
169
169
|
pk = ToggleColumn()
|
|
170
170
|
name = tables.LinkColumn()
|
|
171
171
|
owner = tables.LinkColumn()
|
|
172
|
-
actions = ButtonsColumn(ConfigContextSchema
|
|
172
|
+
actions = ButtonsColumn(ConfigContextSchema)
|
|
173
173
|
|
|
174
174
|
class Meta(BaseTable.Meta):
|
|
175
175
|
model = ConfigContextSchema
|
|
@@ -298,7 +298,7 @@ class DynamicGroupMembershipTable(DynamicGroupTable):
|
|
|
298
298
|
"""Hybrid table for displaying info for both group and membership."""
|
|
299
299
|
|
|
300
300
|
description = tables.Column(accessor="group.description")
|
|
301
|
-
actions = ButtonsColumn(DynamicGroup, pk_field="
|
|
301
|
+
actions = ButtonsColumn(DynamicGroup, pk_field="pk", buttons=("edit",))
|
|
302
302
|
|
|
303
303
|
class Meta(BaseTable.Meta):
|
|
304
304
|
model = DynamicGroupMembership
|
|
@@ -421,15 +421,15 @@ class GitRepositoryTable(BaseTable):
|
|
|
421
421
|
|
|
422
422
|
class JobResultColumn(tables.TemplateColumn):
|
|
423
423
|
def render(self, record, table, value, bound_column, **kwargs):
|
|
424
|
-
if record.
|
|
425
|
-
table.context.update({"result": table.context["job_results"][record.
|
|
424
|
+
if str(record.pk) in table.context.get("job_results", {}):
|
|
425
|
+
table.context.update({"result": table.context["job_results"][str(record.pk)]})
|
|
426
426
|
else:
|
|
427
427
|
table.context.update({"result": None})
|
|
428
428
|
return super().render(record, table, value, bound_column, **kwargs)
|
|
429
429
|
|
|
430
430
|
last_sync_status = JobResultColumn(template_name="extras/inc/job_label.html", verbose_name="Sync Status")
|
|
431
431
|
provides = tables.TemplateColumn(GITREPOSITORY_PROVIDES)
|
|
432
|
-
actions = ButtonsColumn(GitRepository,
|
|
432
|
+
actions = ButtonsColumn(GitRepository, prepend_template=GITREPOSITORY_BUTTONS)
|
|
433
433
|
|
|
434
434
|
class Meta(BaseTable.Meta):
|
|
435
435
|
model = GitRepository
|
|
@@ -518,15 +518,16 @@ class JobTable(BaseTable):
|
|
|
518
518
|
enabled = BooleanColumn()
|
|
519
519
|
has_sensitive_variables = BooleanColumn()
|
|
520
520
|
description = tables.Column(accessor="description_first_line")
|
|
521
|
-
|
|
521
|
+
dryrun_default = BooleanColumn()
|
|
522
522
|
hidden = BooleanColumn()
|
|
523
523
|
read_only = BooleanColumn()
|
|
524
524
|
approval_required = BooleanColumn()
|
|
525
525
|
is_job_hook_receiver = BooleanColumn()
|
|
526
526
|
is_job_button_receiver = BooleanColumn()
|
|
527
|
+
supports_dryrun = BooleanColumn()
|
|
527
528
|
soft_time_limit = tables.Column()
|
|
528
529
|
time_limit = tables.Column()
|
|
529
|
-
actions = ButtonsColumn(JobModel,
|
|
530
|
+
actions = ButtonsColumn(JobModel, prepend_template=JOB_BUTTONS)
|
|
530
531
|
last_run = tables.TemplateColumn(
|
|
531
532
|
accessor="latest_result",
|
|
532
533
|
template_code="""
|
|
@@ -556,12 +557,13 @@ class JobTable(BaseTable):
|
|
|
556
557
|
"enabled",
|
|
557
558
|
"has_sensitive_variables",
|
|
558
559
|
"description",
|
|
559
|
-
"
|
|
560
|
+
"dryrun_default",
|
|
560
561
|
"hidden",
|
|
561
562
|
"read_only",
|
|
562
563
|
"is_job_hook_receiver",
|
|
563
564
|
"is_job_button_receiver",
|
|
564
565
|
"approval_required",
|
|
566
|
+
"supports_dryrun",
|
|
565
567
|
"soft_time_limit",
|
|
566
568
|
"time_limit",
|
|
567
569
|
"last_run",
|
|
@@ -621,8 +623,10 @@ class JobLogEntryTable(BaseTable):
|
|
|
621
623
|
def render_log_level(self, value):
|
|
622
624
|
log_level = value.lower()
|
|
623
625
|
# The css is label-danger for failure items.
|
|
624
|
-
if log_level
|
|
626
|
+
if log_level in ["error", "critical"]:
|
|
625
627
|
log_level = "danger"
|
|
628
|
+
elif log_level == "debug":
|
|
629
|
+
log_level = "default"
|
|
626
630
|
|
|
627
631
|
return format_html('<label class="label label-{}">{}</label>', log_level, value)
|
|
628
632
|
|
|
@@ -644,8 +648,7 @@ class JobLogEntryTable(BaseTable):
|
|
|
644
648
|
|
|
645
649
|
class JobResultTable(BaseTable):
|
|
646
650
|
pk = ToggleColumn()
|
|
647
|
-
|
|
648
|
-
name = tables.Column()
|
|
651
|
+
job_model = tables.Column(linkify=True)
|
|
649
652
|
date_created = tables.DateTimeColumn(linkify=True, format=settings.SHORT_DATETIME_FORMAT)
|
|
650
653
|
status = tables.TemplateColumn(
|
|
651
654
|
template_code="{% include 'extras/inc/job_label.html' with result=record %}",
|
|
@@ -661,12 +664,12 @@ class JobResultTable(BaseTable):
|
|
|
661
664
|
{% load helpers %}
|
|
662
665
|
{% if perms.extras.run_job %}
|
|
663
666
|
{% if record.job_model and record.task_kwargs %}
|
|
664
|
-
<a href="{% url 'extras:job_run'
|
|
667
|
+
<a href="{% url 'extras:job_run' pk=record.job_model.pk %}?kwargs_from_job_result={{ record.pk }}"
|
|
665
668
|
class="btn btn-xs btn-success" title="Re-run job with same arguments.">
|
|
666
669
|
<i class="mdi mdi-repeat"></i>
|
|
667
670
|
</a>
|
|
668
671
|
{% elif record.job_model is not None %}
|
|
669
|
-
<a href="{% url 'extras:job_run'
|
|
672
|
+
<a href="{% url 'extras:job_run' pk=record.job_model.pk %}" class="btn btn-primary btn-xs"
|
|
670
673
|
title="Run job">
|
|
671
674
|
<i class="mdi mdi-play"></i>
|
|
672
675
|
</a>
|
|
@@ -683,33 +686,24 @@ class JobResultTable(BaseTable):
|
|
|
683
686
|
"""
|
|
684
687
|
)
|
|
685
688
|
|
|
686
|
-
def order_linked_record(self, queryset, is_descending):
|
|
687
|
-
return (
|
|
688
|
-
queryset.order_by(
|
|
689
|
-
("-" if is_descending else "") + "job_model__name",
|
|
690
|
-
("-" if is_descending else "") + "name",
|
|
691
|
-
),
|
|
692
|
-
True,
|
|
693
|
-
)
|
|
694
|
-
|
|
695
689
|
def render_summary(self, record):
|
|
696
690
|
"""
|
|
697
691
|
Define custom rendering for the summary column.
|
|
698
692
|
"""
|
|
699
693
|
log_objects = record.job_log_entries.all()
|
|
700
|
-
|
|
694
|
+
debug = log_objects.filter(log_level=LogLevelChoices.LOG_DEBUG).count()
|
|
701
695
|
info = log_objects.filter(log_level=LogLevelChoices.LOG_INFO).count()
|
|
702
696
|
warning = log_objects.filter(log_level=LogLevelChoices.LOG_WARNING).count()
|
|
703
|
-
|
|
697
|
+
error = log_objects.filter(log_level__in=[LogLevelChoices.LOG_ERROR, LogLevelChoices.LOG_CRITICAL]).count()
|
|
704
698
|
return format_html(
|
|
705
|
-
"""<label class="label label-
|
|
699
|
+
"""<label class="label label-default">{}</label>
|
|
706
700
|
<label class="label label-info">{}</label>
|
|
707
701
|
<label class="label label-warning">{}</label>
|
|
708
702
|
<label class="label label-danger">{}</label>""",
|
|
709
|
-
|
|
703
|
+
debug,
|
|
710
704
|
info,
|
|
711
705
|
warning,
|
|
712
|
-
|
|
706
|
+
error,
|
|
713
707
|
)
|
|
714
708
|
|
|
715
709
|
class Meta(BaseTable.Meta):
|
|
@@ -718,7 +712,7 @@ class JobResultTable(BaseTable):
|
|
|
718
712
|
"pk",
|
|
719
713
|
"date_created",
|
|
720
714
|
"name",
|
|
721
|
-
"
|
|
715
|
+
"job_model",
|
|
722
716
|
"duration",
|
|
723
717
|
"date_done",
|
|
724
718
|
"user",
|
|
@@ -726,7 +720,7 @@ class JobResultTable(BaseTable):
|
|
|
726
720
|
"summary",
|
|
727
721
|
"actions",
|
|
728
722
|
)
|
|
729
|
-
default_columns = ("pk", "date_created", "name", "
|
|
723
|
+
default_columns = ("pk", "date_created", "name", "job_model", "user", "status", "summary", "actions")
|
|
730
724
|
|
|
731
725
|
|
|
732
726
|
class JobButtonTable(BaseTable):
|
|
@@ -766,7 +760,7 @@ class JobButtonTable(BaseTable):
|
|
|
766
760
|
|
|
767
761
|
|
|
768
762
|
class NoteTable(BaseTable):
|
|
769
|
-
actions = ButtonsColumn(Note
|
|
763
|
+
actions = ButtonsColumn(Note)
|
|
770
764
|
|
|
771
765
|
class Meta(BaseTable.Meta):
|
|
772
766
|
model = Note
|
|
@@ -834,14 +828,14 @@ class ObjectChangeTable(BaseTable):
|
|
|
834
828
|
|
|
835
829
|
class RelationshipTable(BaseTable):
|
|
836
830
|
pk = ToggleColumn()
|
|
837
|
-
|
|
838
|
-
actions = ButtonsColumn(Relationship,
|
|
831
|
+
label = tables.Column(linkify=True)
|
|
832
|
+
actions = ButtonsColumn(Relationship, buttons=("edit", "delete"))
|
|
839
833
|
|
|
840
834
|
class Meta(BaseTable.Meta):
|
|
841
835
|
model = Relationship
|
|
842
836
|
fields = (
|
|
843
837
|
"pk",
|
|
844
|
-
"
|
|
838
|
+
"label",
|
|
845
839
|
"description",
|
|
846
840
|
"type",
|
|
847
841
|
"source_type",
|
|
@@ -973,10 +967,10 @@ class StatusTableMixin(BaseTable):
|
|
|
973
967
|
|
|
974
968
|
class TagTable(BaseTable):
|
|
975
969
|
pk = ToggleColumn()
|
|
976
|
-
name = tables.LinkColumn(viewname="extras:tag", args=[Accessor("
|
|
970
|
+
name = tables.LinkColumn(viewname="extras:tag", args=[Accessor("pk")])
|
|
977
971
|
color = ColorColumn()
|
|
978
972
|
content_types = ContentTypesColumn(truncate_words=15)
|
|
979
|
-
actions = ButtonsColumn(Tag
|
|
973
|
+
actions = ButtonsColumn(Tag)
|
|
980
974
|
|
|
981
975
|
class Meta(BaseTable.Meta):
|
|
982
976
|
model = Tag
|
nautobot/extras/tasks.py
CHANGED
|
@@ -171,15 +171,3 @@ def process_webhook(webhook_pk, data, model_name, event, timestamp, username, re
|
|
|
171
171
|
raise requests.exceptions.RequestException(
|
|
172
172
|
f"Status {response.status_code} returned with content '{response.content}', webhook FAILED to process."
|
|
173
173
|
)
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
# TODO(jathan): Delete these two functions before we ship this. These are handy
|
|
177
|
-
# for Jobs v2 testing for now.
|
|
178
|
-
@nautobot_task
|
|
179
|
-
def add(x, y):
|
|
180
|
-
return x + y
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
@nautobot_task
|
|
184
|
-
def fail():
|
|
185
|
-
raise Exception("You have failed.") # pylint: disable=broad-exception-raised
|