nautobot 2.0.0a3__py3-none-any.whl → 2.0.0b1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- nautobot/apps/api.py +6 -8
- nautobot/apps/forms.py +0 -2
- nautobot/apps/ui.py +0 -8
- nautobot/circuits/api/serializers.py +9 -117
- nautobot/circuits/api/urls.py +1 -1
- nautobot/circuits/api/views.py +0 -1
- nautobot/circuits/forms.py +0 -65
- nautobot/circuits/migrations/0014_related_name_changes.py +1 -1
- nautobot/circuits/migrations/0016_tagsfield.py +34 -0
- nautobot/circuits/migrations/0017_fixup_null_statuses.py +22 -0
- nautobot/circuits/migrations/0018_status_nonnullable.py +22 -0
- nautobot/circuits/models.py +3 -87
- nautobot/circuits/navigation.py +14 -69
- nautobot/circuits/signals.py +0 -2
- nautobot/circuits/tables.py +39 -1
- nautobot/circuits/tests/integration/test_relationships.py +9 -9
- nautobot/circuits/tests/test_api.py +4 -8
- nautobot/circuits/tests/test_filters.py +10 -4
- nautobot/circuits/tests/test_models.py +5 -1
- nautobot/circuits/tests/test_views.py +27 -5
- nautobot/circuits/views.py +18 -10
- nautobot/core/api/__init__.py +8 -2
- nautobot/core/api/fields.py +15 -6
- nautobot/core/api/filter_backends.py +3 -2
- nautobot/core/api/metadata.py +237 -30
- nautobot/core/api/mixins.py +94 -0
- nautobot/core/api/pagination.py +4 -0
- nautobot/core/api/parsers.py +154 -0
- nautobot/core/api/renderers.py +153 -2
- nautobot/core/api/schema.py +46 -2
- nautobot/core/api/serializers.py +377 -35
- nautobot/core/api/urls.py +11 -3
- nautobot/core/api/utils.py +174 -2
- nautobot/core/api/versioning.py +32 -10
- nautobot/core/api/views.py +266 -72
- nautobot/core/apps/__init__.py +138 -220
- nautobot/core/celery/__init__.py +112 -41
- nautobot/core/celery/backends.py +19 -12
- nautobot/core/celery/control.py +46 -0
- nautobot/core/celery/encoders.py +53 -0
- nautobot/core/celery/log.py +38 -0
- nautobot/core/celery/schedulers.py +23 -4
- nautobot/core/celery/task.py +1 -16
- nautobot/core/checks.py +0 -27
- nautobot/core/choices.py +0 -113
- nautobot/core/{cli.py → cli/__init__.py} +1 -1
- nautobot/core/cli/__main__.py +3 -0
- nautobot/core/constants.py +0 -24
- nautobot/core/context_processors.py +12 -0
- nautobot/core/filters.py +2 -2
- nautobot/core/forms/__init__.py +0 -4
- nautobot/core/forms/fields.py +38 -65
- nautobot/core/forms/forms.py +4 -1
- nautobot/core/forms/utils.py +0 -52
- nautobot/core/graphql/schema.py +4 -27
- nautobot/core/jobs/__init__.py +75 -0
- nautobot/core/management/commands/build_ui.py +255 -0
- nautobot/core/management/commands/generate_test_data.py +3 -2
- nautobot/core/management/commands/post_upgrade.py +24 -24
- nautobot/core/models/__init__.py +26 -1
- nautobot/core/models/fields.py +24 -5
- nautobot/core/models/generics.py +2 -42
- nautobot/core/models/managers.py +5 -0
- nautobot/core/models/name_color_content_types.py +0 -14
- nautobot/core/models/tree_queries.py +14 -4
- nautobot/core/models/utils.py +5 -6
- nautobot/core/models/validators.py +17 -8
- nautobot/core/releases.py +8 -10
- nautobot/core/settings.py +80 -42
- nautobot/core/tables.py +5 -5
- nautobot/core/tasks.py +4 -7
- nautobot/core/templates/base.html +1 -49
- nautobot/core/templates/base_django.html +49 -0
- nautobot/core/templates/base_react.html +55 -0
- nautobot/core/templates/buttons/export.html +6 -4
- nautobot/core/templates/generic/object_bulk_create.html +10 -21
- nautobot/core/templates/generic/object_list.html +3 -1
- nautobot/core/templates/generic/object_retrieve_plugin_full_width.html +3 -0
- nautobot/core/templates/inc/footer.html +1 -0
- nautobot/core/templates/inc/javascript.html +0 -14
- nautobot/core/templates/inc/nav_menu.html +28 -33
- nautobot/core/templates/inc/object_details_advanced_panel.html +13 -0
- nautobot/core/templates/inc/relationships_table_rows.html +2 -2
- nautobot/core/templates/nautobot_config.py.j2 +8 -20
- nautobot/core/templates/plugin_template/__init__.py-tpl +1 -2
- nautobot/core/templates/rest_framework/api.html +8 -0
- nautobot/core/templatetags/buttons.py +32 -28
- nautobot/core/testing/__init__.py +47 -44
- nautobot/core/testing/api.py +362 -47
- nautobot/core/testing/filters.py +1 -1
- nautobot/core/testing/migrations.py +2 -0
- nautobot/core/testing/mixins.py +22 -9
- nautobot/core/testing/schema.py +2 -1
- nautobot/core/testing/views.py +21 -46
- nautobot/core/tests/integration/test_filters.py +17 -8
- nautobot/core/tests/integration/test_navbar.py +11 -34
- nautobot/core/tests/integration/test_plugin_navbar.py +9 -103
- nautobot/core/tests/nautobot_config.py +2 -3
- nautobot/core/tests/test_api.py +290 -21
- nautobot/core/tests/test_checks.py +0 -7
- nautobot/core/tests/test_filters.py +107 -59
- nautobot/core/tests/test_forms.py +26 -92
- nautobot/core/tests/test_graphql.py +110 -77
- nautobot/core/tests/test_logging.py +4 -0
- nautobot/core/tests/test_managers.py +3 -1
- nautobot/core/tests/test_models.py +2 -0
- nautobot/core/tests/test_paginator.py +3 -1
- nautobot/core/tests/test_releases.py +12 -12
- nautobot/core/tests/test_templatetags_helpers.py +4 -4
- nautobot/core/tests/test_utils.py +32 -68
- nautobot/core/tests/test_views.py +12 -15
- nautobot/core/utils/data.py +17 -0
- nautobot/core/utils/deprecation.py +9 -6
- nautobot/core/utils/filtering.py +8 -3
- nautobot/core/utils/git.py +12 -4
- nautobot/core/utils/lookup.py +3 -1
- nautobot/core/utils/requests.py +1 -104
- nautobot/core/views/__init__.py +1 -0
- nautobot/core/views/generic.py +75 -110
- nautobot/core/views/mixins.py +52 -61
- nautobot/core/views/renderers.py +6 -7
- nautobot/core/views/utils.py +80 -0
- nautobot/dcim/api/serializers.py +160 -667
- nautobot/dcim/api/urls.py +1 -1
- nautobot/dcim/api/views.py +7 -44
- nautobot/dcim/choices.py +2 -0
- nautobot/dcim/filters/__init__.py +21 -0
- nautobot/dcim/form_mixins.py +1 -27
- nautobot/dcim/forms.py +19 -765
- nautobot/dcim/migrations/0024_alter_device_and_rack_role_add_new_role.py +2 -1
- nautobot/dcim/migrations/0025_device_and_rack_roles_data_migrations.py +19 -13
- nautobot/dcim/migrations/0027_remove_device_role_and_rack_role.py +1 -1
- nautobot/dcim/migrations/0028_rename_foreignkey_fields.py +1 -1
- nautobot/dcim/migrations/0030_migrate_region_and_site_data_to_locations.py +2 -2
- nautobot/dcim/migrations/0035_related_name_changes.py +1 -1
- nautobot/dcim/migrations/0036_remove_region_and_site.py +1 -1
- nautobot/dcim/migrations/0040_tagsfield.py +109 -0
- nautobot/dcim/migrations/{0040_ipam__namespaces.py → 0041_ipam__namespaces.py} +1 -1
- nautobot/dcim/migrations/0042_fixup_null_statuses.py +51 -0
- nautobot/dcim/migrations/0043_status_nonnullable.py +72 -0
- nautobot/dcim/models/cables.py +3 -33
- nautobot/dcim/models/device_component_templates.py +6 -0
- nautobot/dcim/models/device_components.py +12 -198
- nautobot/dcim/models/devices.py +30 -143
- nautobot/dcim/models/locations.py +3 -64
- nautobot/dcim/models/power.py +3 -50
- nautobot/dcim/models/racks.py +7 -84
- nautobot/dcim/navigation.py +141 -467
- nautobot/dcim/signals.py +0 -2
- nautobot/dcim/tables/locations.py +2 -2
- nautobot/dcim/tables/power.py +1 -2
- nautobot/dcim/templates/dcim/console_port_connection_list.html +7 -0
- nautobot/dcim/templates/dcim/devicetype.html +2 -2
- nautobot/dcim/templates/dcim/interface_connection_list.html +7 -0
- nautobot/dcim/templates/dcim/location.html +16 -1
- nautobot/dcim/templates/dcim/locationtype.html +15 -0
- nautobot/dcim/templates/dcim/power_port_connection_list.html +7 -0
- nautobot/dcim/templates/dcim/rackgroup.html +0 -12
- nautobot/dcim/tests/test_api.py +166 -81
- nautobot/dcim/tests/test_cablepaths.py +41 -35
- nautobot/dcim/tests/test_filters.py +67 -23
- nautobot/dcim/tests/test_forms.py +5 -205
- nautobot/dcim/tests/test_graphql.py +7 -2
- nautobot/dcim/tests/test_migrations.py +6 -11
- nautobot/dcim/tests/test_models.py +182 -110
- nautobot/dcim/tests/test_natural_ordering.py +11 -8
- nautobot/dcim/tests/test_signals.py +6 -3
- nautobot/dcim/tests/test_views.py +197 -175
- nautobot/dcim/urls.py +11 -16
- nautobot/dcim/views.py +7 -134
- nautobot/docs/additional-features/caching.md +6 -87
- nautobot/docs/additional-features/job-scheduling-and-approvals.md +3 -0
- nautobot/docs/additional-features/jobs.md +177 -195
- nautobot/docs/administration/nautobot-server.md +6 -21
- nautobot/docs/administration/replicating-nautobot.md +0 -10
- nautobot/docs/configuration/optional-settings.md +32 -41
- nautobot/docs/configuration/required-settings.md +11 -52
- nautobot/docs/development/application-registry.md +2 -13
- nautobot/docs/development/extending-models.md +15 -17
- nautobot/docs/development/generic-views.md +0 -2
- nautobot/docs/development/getting-started.md +55 -5
- nautobot/docs/development/navigation-menu.md +22 -93
- nautobot/docs/development/react-ui.md +105 -0
- nautobot/docs/development/role-internals.md +1 -3
- nautobot/docs/development/style-guide.md +6 -4
- nautobot/docs/index.md +3 -2
- nautobot/docs/installation/migrating-from-netbox.md +11 -42
- nautobot/docs/installation/nautobot.md +1 -1
- nautobot/docs/installation/tables/v2-api-behavior-changes.yaml +70 -0
- nautobot/docs/installation/tables/v2-api-removed-fields.yaml +142 -0
- nautobot/docs/installation/tables/v2-api-renamed-fields.yaml +124 -0
- nautobot/docs/installation/tables/v2-code-location-changes.yaml +241 -0
- nautobot/docs/installation/tables/v2-code-removals.yaml +67 -0
- nautobot/docs/installation/tables/v2-database-behavior-changes.yaml +37 -0
- nautobot/docs/installation/tables/v2-database-removed-fields.yaml +166 -0
- nautobot/docs/installation/tables/v2-database-renamed-fields.yaml +340 -0
- nautobot/docs/installation/tables/v2-filters-corrected-fields.yaml +28 -0
- nautobot/docs/installation/tables/v2-filters-enhanced-fields.yaml +241 -0
- nautobot/docs/installation/tables/v2-filters-removed-fields.yaml +553 -0
- nautobot/docs/installation/tables/v2-filters-renamed-fields.yaml +223 -0
- nautobot/docs/installation/tables/v2-logging-renamed-loggers.yaml +23 -0
- nautobot/docs/installation/upgrading-from-nautobot-v1.md +170 -747
- nautobot/docs/models/dcim/device.md +3 -0
- nautobot/docs/models/dcim/deviceredundancygroup.md +3 -3
- nautobot/docs/models/extras/computedfield.md +4 -4
- nautobot/docs/models/extras/gitrepository.md +3 -0
- nautobot/docs/models/extras/job.md +1 -0
- nautobot/docs/models/extras/jobbutton.md +18 -13
- nautobot/docs/models/extras/jobhook.md +7 -4
- nautobot/docs/models/extras/jobresult.md +6 -2
- nautobot/docs/models/extras/relationship.md +2 -2
- nautobot/docs/models/extras/status.md +6 -19
- nautobot/docs/models/ipam/ipaddress.md +3 -0
- nautobot/docs/models/virtualization/virtualmachine.md +3 -0
- nautobot/docs/plugins/development.md +83 -21
- nautobot/docs/release-notes/version-1.5.md +53 -0
- nautobot/docs/release-notes/version-2.0.md +180 -0
- nautobot/docs/requirements.txt +1 -0
- nautobot/docs/rest-api/overview.md +384 -215
- nautobot/docs/rest-api/ui-related-endpoints.md +9 -0
- nautobot/extras/admin.py +3 -5
- nautobot/extras/api/customfields.py +15 -39
- nautobot/extras/api/fields.py +0 -11
- nautobot/extras/api/mixins.py +45 -0
- nautobot/extras/api/relationships.py +63 -158
- nautobot/extras/api/serializers.py +165 -700
- nautobot/extras/api/urls.py +1 -1
- nautobot/extras/api/views.py +294 -280
- nautobot/extras/apps.py +4 -7
- nautobot/extras/choices.py +11 -9
- nautobot/extras/constants.py +9 -3
- nautobot/extras/datasources/__init__.py +2 -0
- nautobot/extras/datasources/git.py +135 -186
- nautobot/extras/datasources/registry.py +25 -35
- nautobot/extras/filters/__init__.py +20 -19
- nautobot/extras/filters/mixins.py +4 -4
- nautobot/extras/forms/forms.py +63 -127
- nautobot/extras/forms/mixins.py +23 -51
- nautobot/extras/health_checks.py +0 -33
- nautobot/extras/jobs.py +387 -565
- nautobot/extras/management/commands/runjob.py +24 -62
- nautobot/extras/managers.py +30 -7
- nautobot/extras/migrations/0058_jobresult_add_time_status_idxs.py +38 -0
- nautobot/extras/migrations/{0058_joblogentry_scheduledjob_webhook_data_migration.py → 0059_joblogentry_scheduledjob_webhook_data_migration.py} +1 -1
- nautobot/extras/migrations/{0059_alter_joblogentry_scheduledjob_webhook_fields.py → 0060_alter_joblogentry_scheduledjob_webhook_fields.py} +1 -1
- nautobot/extras/migrations/{0060_role_and_alter_status.py → 0061_role_and_alter_status.py} +1 -7
- nautobot/extras/migrations/{0061_collect_roles_from_related_apps_roles.py → 0062_collect_roles_from_related_apps_roles.py} +33 -32
- nautobot/extras/migrations/{0062_alter_role_options.py → 0063_alter_role_options.py} +1 -1
- nautobot/extras/migrations/{0063_alter_configcontext_and_add_new_role.py → 0064_alter_configcontext_and_add_new_role.py} +1 -1
- nautobot/extras/migrations/0065_configcontext_data_migrations.py +44 -0
- nautobot/extras/migrations/{0065_rename_configcontext_role.py → 0066_rename_configcontext_role.py} +1 -1
- nautobot/extras/migrations/{0066_jobresult__add_celery_fields.py → 0067_jobresult__add_celery_fields.py} +36 -2
- nautobot/extras/migrations/{0067_created_datetime.py → 0068_created_datetime.py} +1 -1
- nautobot/extras/migrations/{0068_remove_site_and_region_attributes_from_config_context.py → 0069_remove_site_and_region_attributes_from_config_context.py} +1 -1
- nautobot/extras/migrations/{0069_replace_related_names.py → 0070_replace_related_names.py} +1 -1
- nautobot/extras/migrations/{0070_rename_model_fields.py → 0071_rename_model_fields.py} +1 -1
- nautobot/extras/migrations/0072_job__unique_name_data_migration.py +86 -0
- nautobot/extras/migrations/{0072_job__unique_name.py → 0073_job__unique_name.py} +13 -9
- nautobot/extras/migrations/{0073_remove_gitrepository_fields.py → 0074_remove_gitrepository_fields.py} +1 -1
- nautobot/extras/migrations/{0074_rename_slug_to_key_for_custom_field.py → 0075_rename_slug_to_key_for_custom_field.py} +1 -1
- nautobot/extras/migrations/{0075_migrate_custom_field_data.py → 0076_migrate_custom_field_data.py} +1 -1
- nautobot/extras/migrations/{0076_remove_name_field_and_make_label_field_non_nullable.py → 0077_remove_name_field_and_make_label_field_non_nullable.py} +1 -1
- nautobot/extras/migrations/{0077_remove_slug.py → 0078_remove_slug.py} +1 -5
- nautobot/extras/migrations/0079_tagsfield.py +28 -0
- nautobot/extras/migrations/0080_rename_relationship_slug_to_key.py +17 -0
- nautobot/extras/migrations/0081_rename_relationship_name_to_label.py +29 -0
- nautobot/extras/migrations/0082_ensure_relationship_keys_are_unique.py +43 -0
- nautobot/extras/migrations/0083_rename_computed_field_slug_to_key.py +21 -0
- nautobot/extras/migrations/0084_taggeditem_cleanup.py +43 -0
- nautobot/extras/migrations/0085_taggeditem_uniqueness.py +22 -0
- nautobot/extras/migrations/0086_job__celery_task_fields__dryrun_support.py +81 -0
- nautobot/extras/migrations/0087_job__commit_default_data_migration.py +26 -0
- nautobot/extras/migrations/0088_joblogentry__log_level_default.py +17 -0
- nautobot/extras/migrations/0089_joblogentry__log_level_data_migration.py +34 -0
- nautobot/extras/migrations/0090_scheduledjob__data_migration.py +57 -0
- nautobot/extras/models/__init__.py +2 -3
- nautobot/extras/models/change_logging.py +0 -36
- nautobot/extras/models/customfields.py +39 -33
- nautobot/extras/models/datasources.py +48 -50
- nautobot/extras/models/groups.py +5 -6
- nautobot/extras/models/jobs.py +189 -321
- nautobot/extras/models/mixins.py +0 -71
- nautobot/extras/models/models.py +0 -19
- nautobot/extras/models/relationships.py +19 -13
- nautobot/extras/models/roles.py +0 -34
- nautobot/extras/models/secrets.py +2 -26
- nautobot/extras/models/statuses.py +6 -5
- nautobot/extras/models/tags.py +2 -17
- nautobot/extras/navigation.py +89 -307
- nautobot/extras/plugins/__init__.py +3 -120
- nautobot/extras/plugins/utils.py +0 -3
- nautobot/extras/plugins/validators.py +5 -4
- nautobot/extras/plugins/views.py +16 -3
- nautobot/extras/querysets.py +1 -7
- nautobot/extras/registry.py +3 -0
- nautobot/extras/signals.py +26 -60
- nautobot/extras/tables.py +34 -40
- nautobot/extras/tasks.py +0 -12
- nautobot/extras/templates/extras/configcontext.html +1 -1
- nautobot/extras/templates/extras/configcontextschema.html +16 -1
- nautobot/extras/templates/extras/customfield.html +0 -13
- nautobot/extras/templates/extras/gitrepository.html +3 -3
- nautobot/extras/templates/extras/inc/jobresult.html +10 -0
- nautobot/extras/templates/extras/inc/panel_jobhistory.html +1 -1
- nautobot/extras/templates/extras/job.html +35 -25
- nautobot/extras/templates/extras/job_approval_request.html +15 -30
- nautobot/extras/templates/extras/job_detail.html +13 -31
- nautobot/extras/templates/extras/job_edit.html +15 -17
- nautobot/extras/templates/extras/jobresult.html +24 -6
- nautobot/extras/templates/extras/scheduledjob.html +2 -2
- nautobot/extras/templates/extras/secret.html +28 -0
- nautobot/extras/templatetags/job_buttons.py +1 -0
- nautobot/extras/{tests/example_jobs → test_jobs}/api_test_job.py +13 -6
- nautobot/extras/test_jobs/atomic_transaction.py +53 -0
- nautobot/extras/test_jobs/dry_run.py +29 -0
- nautobot/extras/{tests/example_jobs/test_duplicate_name.py → test_jobs/duplicate_name.py} +4 -0
- nautobot/extras/test_jobs/duplicate_name2.py +9 -0
- nautobot/extras/test_jobs/fail.py +23 -0
- nautobot/extras/{tests/example_jobs/test_field_default.py → test_jobs/field_default.py} +4 -0
- nautobot/extras/{tests/example_jobs/test_field_order.py → test_jobs/field_order.py} +4 -0
- nautobot/extras/{tests/example_jobs/test_file_upload_fail.py → test_jobs/file_upload_fail.py} +11 -6
- nautobot/extras/test_jobs/file_upload_pass.py +25 -0
- nautobot/extras/test_jobs/has_sensitive_variables.py +25 -0
- nautobot/extras/test_jobs/ipaddress_vars.py +66 -0
- nautobot/extras/test_jobs/job_button_receiver.py +28 -0
- nautobot/extras/test_jobs/job_hook_receiver.py +29 -0
- nautobot/extras/test_jobs/job_variables.py +88 -0
- nautobot/extras/test_jobs/location_with_custom_field.py +45 -0
- nautobot/extras/test_jobs/log_redaction.py +20 -0
- nautobot/extras/test_jobs/log_skip_db_logging.py +17 -0
- nautobot/extras/test_jobs/modify_db.py +25 -0
- nautobot/extras/{tests/example_jobs/test_no_field_order.py → test_jobs/no_field_order.py} +4 -0
- nautobot/extras/test_jobs/object_var_optional.py +21 -0
- nautobot/extras/test_jobs/object_var_required.py +21 -0
- nautobot/extras/test_jobs/object_vars.py +26 -0
- nautobot/extras/test_jobs/pass.py +25 -0
- nautobot/extras/test_jobs/profiling.py +32 -0
- nautobot/extras/test_jobs/read_only_job.py +15 -0
- nautobot/extras/{tests/example_jobs/test_required_args.py → test_jobs/required_args.py} +4 -0
- nautobot/extras/{tests/example_jobs/test_soft_time_limit_greater_than_time_limit.py → test_jobs/soft_time_limit_greater_than_time_limit.py} +5 -1
- nautobot/extras/{tests/example_jobs/test_task_queues.py → test_jobs/task_queues.py} +5 -1
- nautobot/extras/tests/integration/test_computedfields.py +1 -1
- nautobot/extras/tests/integration/test_configcontextschema.py +5 -3
- nautobot/extras/tests/integration/test_customfields.py +4 -2
- nautobot/extras/tests/integration/test_dynamicgroups.py +1 -1
- nautobot/extras/tests/integration/test_jobs.py +25 -27
- nautobot/extras/tests/integration/test_notes.py +8 -4
- nautobot/extras/tests/integration/test_relationships.py +2 -2
- nautobot/extras/tests/test_api.py +649 -642
- nautobot/extras/tests/test_changelog.py +3 -3
- nautobot/extras/tests/test_context_managers.py +5 -3
- nautobot/extras/tests/test_customfields.py +92 -50
- nautobot/extras/tests/test_datasources.py +189 -112
- nautobot/extras/tests/test_dynamicgroups.py +7 -8
- nautobot/extras/tests/test_filters.py +137 -89
- nautobot/extras/tests/test_forms.py +73 -75
- nautobot/extras/tests/{test_scripts.py → test_job_variables.py} +43 -49
- nautobot/extras/tests/test_jobs.py +262 -263
- nautobot/extras/tests/test_migrations.py +4 -3
- nautobot/extras/tests/test_models.py +116 -161
- nautobot/extras/tests/test_plugins.py +38 -60
- nautobot/extras/tests/test_relationships.py +167 -120
- nautobot/extras/tests/test_tags.py +6 -11
- nautobot/extras/tests/test_utils.py +31 -1
- nautobot/extras/tests/test_views.py +201 -145
- nautobot/extras/tests/test_webhooks.py +6 -2
- nautobot/extras/urls.py +42 -42
- nautobot/extras/utils.py +137 -163
- nautobot/extras/views.py +78 -152
- nautobot/ipam/api/fields.py +17 -0
- nautobot/ipam/api/serializers.py +58 -164
- nautobot/ipam/api/urls.py +1 -1
- nautobot/ipam/api/views.py +3 -2
- nautobot/ipam/apps.py +1 -2
- nautobot/ipam/filters.py +1 -10
- nautobot/ipam/forms.py +4 -177
- nautobot/ipam/lookups.py +1 -0
- nautobot/ipam/management/commands/__init__.py +0 -0
- nautobot/ipam/management/commands/fix_prefix_broadcast.py +17 -0
- nautobot/ipam/migrations/0010_alter_ipam_role_add_new_role.py +1 -1
- nautobot/ipam/migrations/0011_migrate_ipam_role_data.py +32 -38
- nautobot/ipam/migrations/0020_related_name_changes.py +1 -1
- nautobot/ipam/migrations/0022_aggregate_to_prefix_data_migration.py +2 -2
- nautobot/ipam/migrations/0028_tagsfield.py +44 -0
- nautobot/ipam/migrations/0029_ip_address_to_interface_uniqueness_constraints.py +18 -0
- nautobot/ipam/migrations/{0028_ipam__namespaces.py → 0030_ipam__namespaces.py} +77 -28
- nautobot/ipam/migrations/0031_ipam__prefix__add_parent.py +58 -0
- nautobot/ipam/migrations/0032_ipam__namespaces_finish.py +63 -0
- nautobot/ipam/migrations/0033_fixup_null_statuses.py +26 -0
- nautobot/ipam/migrations/0034_status_nonnullable.py +36 -0
- nautobot/ipam/models.py +100 -236
- nautobot/ipam/navigation.py +36 -181
- nautobot/ipam/querysets.py +20 -25
- nautobot/ipam/signals.py +49 -6
- nautobot/ipam/tables.py +10 -3
- nautobot/ipam/templates/ipam/namespace_ipaddresses.html +11 -0
- nautobot/ipam/templates/ipam/namespace_prefixes.html +11 -0
- nautobot/ipam/templates/ipam/namespace_retrieve.html +17 -4
- nautobot/ipam/templates/ipam/namespace_vrfs.html +11 -0
- nautobot/ipam/templates/ipam/prefix.html +1 -1
- nautobot/ipam/templates/ipam/vlangroup.html +0 -13
- nautobot/ipam/templates/ipam/vrf_edit.html +6 -0
- nautobot/ipam/tests/integration/test_prefixes.py +3 -26
- nautobot/ipam/tests/test_api.py +22 -19
- nautobot/ipam/tests/test_filters.py +59 -23
- nautobot/ipam/tests/test_migrations.py +6 -10
- nautobot/ipam/tests/test_models.py +323 -198
- nautobot/ipam/tests/test_ordering.py +2 -2
- nautobot/ipam/tests/test_querysets.py +44 -24
- nautobot/ipam/tests/test_views.py +73 -26
- nautobot/ipam/urls.py +16 -0
- nautobot/ipam/{utils.py → utils/__init__.py} +2 -2
- nautobot/ipam/utils/migrations.py +713 -0
- nautobot/ipam/views.py +137 -20
- nautobot/project-static/docs/404.html +1178 -10
- nautobot/project-static/docs/additional-features/caching.html +1224 -159
- nautobot/project-static/docs/additional-features/change-logging.html +1180 -12
- nautobot/project-static/docs/additional-features/config-contexts.html +1180 -12
- nautobot/project-static/docs/additional-features/graphql.html +1179 -11
- nautobot/project-static/docs/additional-features/healthcheck.html +1180 -12
- nautobot/project-static/docs/additional-features/job-scheduling-and-approvals.html +1184 -12
- nautobot/project-static/docs/additional-features/jobs.html +1514 -328
- nautobot/project-static/docs/additional-features/napalm.html +1180 -12
- nautobot/project-static/docs/additional-features/prometheus-metrics.html +1180 -12
- nautobot/project-static/docs/additional-features/template-filters.html +1180 -12
- nautobot/project-static/docs/administration/celery-queues.html +1178 -10
- nautobot/project-static/docs/administration/nautobot-server.html +1451 -304
- nautobot/project-static/docs/administration/nautobot-shell.html +1178 -10
- nautobot/project-static/docs/administration/permissions.html +1178 -10
- nautobot/project-static/docs/administration/replicating-nautobot.html +1262 -113
- nautobot/project-static/docs/apps/index.html +1178 -10
- nautobot/project-static/docs/apps/nautobot-apps.html +1178 -10
- nautobot/project-static/docs/code-reference/nautobot/apps/__init__.html +1580 -426
- nautobot/project-static/docs/code-reference/nautobot/apps/admin.html +1178 -10
- nautobot/project-static/docs/code-reference/nautobot/apps/api.html +3481 -1838
- nautobot/project-static/docs/code-reference/nautobot/apps/choices.html +1178 -10
- nautobot/project-static/docs/code-reference/nautobot/apps/config.html +1178 -10
- nautobot/project-static/docs/code-reference/nautobot/apps/datasources.html +1185 -11
- nautobot/project-static/docs/code-reference/nautobot/apps/filters.html +1719 -551
- nautobot/project-static/docs/code-reference/nautobot/apps/forms.html +2062 -930
- nautobot/project-static/docs/code-reference/nautobot/apps/models.html +1946 -659
- nautobot/project-static/docs/code-reference/nautobot/apps/secrets.html +1180 -12
- nautobot/project-static/docs/code-reference/nautobot/apps/tables.html +1189 -21
- nautobot/project-static/docs/code-reference/nautobot/apps/testing.html +9283 -6218
- nautobot/project-static/docs/code-reference/nautobot/apps/ui.html +2734 -2122
- nautobot/project-static/docs/code-reference/nautobot/apps/urls.html +1178 -10
- nautobot/project-static/docs/code-reference/nautobot/apps/views.html +2337 -1300
- nautobot/project-static/docs/configuration/authentication/ldap.html +1178 -10
- nautobot/project-static/docs/configuration/authentication/remote.html +1178 -10
- nautobot/project-static/docs/configuration/authentication/sso.html +1178 -10
- nautobot/project-static/docs/configuration/index.html +1178 -10
- nautobot/project-static/docs/configuration/optional-settings.html +1311 -160
- nautobot/project-static/docs/configuration/required-settings.html +1312 -211
- nautobot/project-static/docs/core-functionality/circuits.html +1178 -10
- nautobot/project-static/docs/core-functionality/device-types.html +1178 -10
- nautobot/project-static/docs/core-functionality/devices.html +1182 -10
- nautobot/project-static/docs/core-functionality/ipam.html +1182 -10
- nautobot/project-static/docs/core-functionality/power.html +1178 -10
- nautobot/project-static/docs/core-functionality/secrets.html +1178 -10
- nautobot/project-static/docs/core-functionality/services.html +1178 -10
- nautobot/project-static/docs/core-functionality/sites-and-racks.html +1178 -10
- nautobot/project-static/docs/core-functionality/tenancy.html +1178 -10
- nautobot/project-static/docs/core-functionality/virtualization.html +1182 -10
- nautobot/project-static/docs/core-functionality/vlans.html +1179 -11
- nautobot/project-static/docs/development/application-registry.html +1190 -42
- nautobot/project-static/docs/development/best-practices.html +1178 -10
- nautobot/project-static/docs/development/docker-compose-advanced-use-cases.html +1178 -10
- nautobot/project-static/docs/development/extending-models.html +1238 -83
- nautobot/project-static/docs/development/generic-views.html +1180 -14
- nautobot/project-static/docs/development/getting-started.html +1365 -90
- nautobot/project-static/docs/development/homepage.html +1178 -10
- nautobot/project-static/docs/development/index.html +1178 -10
- nautobot/project-static/docs/development/model-features.html +1178 -10
- nautobot/project-static/docs/development/natural-keys.html +1178 -10
- nautobot/project-static/docs/development/navigation-menu.html +1215 -125
- nautobot/project-static/docs/development/react-ui.html +4199 -0
- nautobot/project-static/docs/development/release-checklist.html +1178 -10
- nautobot/project-static/docs/development/role-internals.html +1179 -12
- nautobot/project-static/docs/development/style-guide.html +1188 -19
- nautobot/project-static/docs/development/templates.html +1178 -10
- nautobot/project-static/docs/development/testing.html +1178 -10
- nautobot/project-static/docs/development/user-preferences.html +1178 -10
- nautobot/project-static/docs/docker/index.html +1178 -10
- nautobot/project-static/docs/index.html +1183 -12
- nautobot/project-static/docs/installation/centos.html +1178 -10
- nautobot/project-static/docs/installation/external-authentication.html +1178 -10
- nautobot/project-static/docs/installation/http-server.html +1178 -10
- nautobot/project-static/docs/installation/index.html +1178 -10
- nautobot/project-static/docs/installation/migrating-from-netbox.html +1305 -189
- nautobot/project-static/docs/installation/migrating-from-postgresql.html +1178 -10
- nautobot/project-static/docs/installation/nautobot.html +1179 -11
- nautobot/project-static/docs/installation/region-and-site-data-migration-guide.html +1178 -10
- nautobot/project-static/docs/installation/selinux-troubleshooting.html +1178 -10
- nautobot/project-static/docs/installation/services.html +1178 -10
- nautobot/project-static/docs/installation/tables/v2-api-behavior-changes.yaml +70 -0
- nautobot/project-static/docs/installation/tables/v2-api-removed-fields.yaml +142 -0
- nautobot/project-static/docs/installation/tables/v2-api-renamed-fields.yaml +124 -0
- nautobot/project-static/docs/installation/tables/v2-code-location-changes.yaml +241 -0
- nautobot/project-static/docs/installation/tables/v2-code-removals.yaml +67 -0
- nautobot/project-static/docs/installation/tables/v2-database-behavior-changes.yaml +37 -0
- nautobot/project-static/docs/installation/tables/v2-database-removed-fields.yaml +166 -0
- nautobot/project-static/docs/installation/tables/v2-database-renamed-fields.yaml +340 -0
- nautobot/project-static/docs/installation/tables/v2-filters-corrected-fields.yaml +28 -0
- nautobot/project-static/docs/installation/tables/v2-filters-enhanced-fields.yaml +241 -0
- nautobot/project-static/docs/installation/tables/v2-filters-removed-fields.yaml +553 -0
- nautobot/project-static/docs/installation/tables/v2-filters-renamed-fields.yaml +223 -0
- nautobot/project-static/docs/installation/tables/v2-logging-renamed-loggers.yaml +23 -0
- nautobot/project-static/docs/installation/ubuntu.html +1178 -10
- nautobot/project-static/docs/installation/upgrading-from-nautobot-v1.html +3823 -2152
- nautobot/project-static/docs/installation/upgrading.html +1178 -10
- nautobot/project-static/docs/models/circuits/circuit.html +1293 -103
- nautobot/project-static/docs/models/circuits/circuittermination.html +1293 -103
- nautobot/project-static/docs/models/circuits/circuittype.html +1293 -103
- nautobot/project-static/docs/models/circuits/provider.html +1293 -103
- nautobot/project-static/docs/models/circuits/providernetwork.html +1293 -103
- nautobot/project-static/docs/models/dcim/cable.html +1324 -103
- nautobot/project-static/docs/models/dcim/consoleport.html +1293 -103
- nautobot/project-static/docs/models/dcim/consoleporttemplate.html +1293 -103
- nautobot/project-static/docs/models/dcim/consoleserverport.html +1293 -103
- nautobot/project-static/docs/models/dcim/consoleserverporttemplate.html +1293 -103
- nautobot/project-static/docs/models/dcim/device.html +1326 -132
- nautobot/project-static/docs/models/dcim/devicebay.html +1293 -103
- nautobot/project-static/docs/models/dcim/devicebaytemplate.html +1293 -103
- nautobot/project-static/docs/models/dcim/deviceredundancygroup.html +1379 -97
- nautobot/project-static/docs/models/dcim/devicetype.html +1293 -103
- nautobot/project-static/docs/models/dcim/frontport.html +1293 -103
- nautobot/project-static/docs/models/dcim/frontporttemplate.html +1293 -103
- nautobot/project-static/docs/models/dcim/interface.html +1293 -103
- nautobot/project-static/docs/models/dcim/interfacetemplate.html +1293 -103
- nautobot/project-static/docs/models/dcim/inventoryitem.html +1293 -103
- nautobot/project-static/docs/models/dcim/location.html +1293 -103
- nautobot/project-static/docs/models/dcim/locationtype.html +1293 -103
- nautobot/project-static/docs/models/dcim/manufacturer.html +1292 -102
- nautobot/project-static/docs/models/dcim/platform.html +1272 -82
- nautobot/project-static/docs/models/dcim/powerfeed.html +1270 -80
- nautobot/project-static/docs/models/dcim/poweroutlet.html +1272 -82
- nautobot/project-static/docs/models/dcim/poweroutlettemplate.html +1272 -82
- nautobot/project-static/docs/models/dcim/powerpanel.html +1270 -80
- nautobot/project-static/docs/models/dcim/powerport.html +1272 -82
- nautobot/project-static/docs/models/dcim/powerporttemplate.html +1272 -82
- nautobot/project-static/docs/models/dcim/rack.html +1272 -82
- nautobot/project-static/docs/models/dcim/rackgroup.html +1272 -82
- nautobot/project-static/docs/models/dcim/rackreservation.html +1272 -82
- nautobot/project-static/docs/models/dcim/rearport.html +1286 -96
- nautobot/project-static/docs/models/dcim/rearporttemplate.html +1286 -96
- nautobot/project-static/docs/models/dcim/region.html +1178 -10
- nautobot/project-static/docs/models/dcim/site.html +1178 -10
- nautobot/project-static/docs/models/dcim/virtualchassis.html +1284 -94
- nautobot/project-static/docs/models/extras/computedfield.html +1184 -16
- nautobot/project-static/docs/models/extras/configcontext.html +1314 -86
- nautobot/project-static/docs/models/extras/configcontextschema.html +1276 -86
- nautobot/project-static/docs/models/extras/customfield.html +1180 -12
- nautobot/project-static/docs/models/extras/customlink.html +1180 -12
- nautobot/project-static/docs/models/extras/dynamicgroup.html +1180 -12
- nautobot/project-static/docs/models/extras/exporttemplate.html +1180 -12
- nautobot/project-static/docs/models/extras/gitrepository.html +1184 -12
- nautobot/project-static/docs/models/extras/graphqlquery.html +1321 -86
- nautobot/project-static/docs/models/extras/imageattachment.html +1276 -86
- nautobot/project-static/docs/models/extras/job.html +1277 -86
- nautobot/project-static/docs/models/extras/jobbutton.html +1201 -29
- nautobot/project-static/docs/models/extras/jobhook.html +1188 -16
- nautobot/project-static/docs/models/extras/joblogentry.html +1274 -84
- nautobot/project-static/docs/models/extras/jobresult.html +1364 -169
- nautobot/project-static/docs/models/extras/note.html +1180 -12
- nautobot/project-static/docs/models/extras/relationship.html +1182 -14
- nautobot/project-static/docs/models/extras/role.html +1320 -86
- nautobot/project-static/docs/models/extras/secret.html +1314 -86
- nautobot/project-static/docs/models/extras/secretsgroup.html +1276 -86
- nautobot/project-static/docs/models/extras/status.html +1188 -59
- nautobot/project-static/docs/models/extras/tag.html +1180 -12
- nautobot/project-static/docs/models/extras/webhook.html +1180 -12
- nautobot/project-static/docs/models/ipam/ipaddress.html +1327 -102
- nautobot/project-static/docs/models/ipam/prefix.html +1276 -86
- nautobot/project-static/docs/models/ipam/rir.html +1276 -86
- nautobot/project-static/docs/models/ipam/routetarget.html +1276 -86
- nautobot/project-static/docs/models/ipam/service.html +1276 -86
- nautobot/project-static/docs/models/ipam/vlan.html +1276 -86
- nautobot/project-static/docs/models/ipam/vlangroup.html +1276 -86
- nautobot/project-static/docs/models/ipam/vrf.html +1276 -86
- nautobot/project-static/docs/models/tenancy/tenant.html +1276 -86
- nautobot/project-static/docs/models/tenancy/tenantgroup.html +1276 -86
- nautobot/project-static/docs/models/users/objectpermission.html +1314 -86
- nautobot/project-static/docs/models/users/token.html +1276 -86
- nautobot/project-static/docs/models/virtualization/cluster.html +1276 -86
- nautobot/project-static/docs/models/virtualization/clustergroup.html +1276 -86
- nautobot/project-static/docs/models/virtualization/clustertype.html +1276 -86
- nautobot/project-static/docs/models/virtualization/virtualmachine.html +1321 -127
- nautobot/project-static/docs/models/virtualization/vminterface.html +1276 -86
- nautobot/project-static/docs/objects.inv +0 -0
- nautobot/project-static/docs/plugins/development.html +1726 -495
- nautobot/project-static/docs/plugins/index.html +1178 -10
- nautobot/project-static/docs/plugins/porting-from-netbox.html +1178 -10
- nautobot/project-static/docs/release-notes/index.html +1178 -10
- nautobot/project-static/docs/release-notes/version-1.0.html +1178 -10
- nautobot/project-static/docs/release-notes/version-1.1.html +1178 -10
- nautobot/project-static/docs/release-notes/version-1.2.html +1178 -10
- nautobot/project-static/docs/release-notes/version-1.3.html +1178 -10
- nautobot/project-static/docs/release-notes/version-1.4.html +1178 -10
- nautobot/project-static/docs/release-notes/version-1.5.html +1608 -225
- nautobot/project-static/docs/release-notes/version-2.0.html +1547 -47
- nautobot/project-static/docs/requirements.txt +1 -0
- nautobot/project-static/docs/rest-api/authentication.html +1179 -11
- nautobot/project-static/docs/rest-api/filtering.html +1178 -10
- nautobot/project-static/docs/rest-api/overview.html +1841 -446
- nautobot/project-static/docs/rest-api/ui-related-endpoints.html +4057 -0
- nautobot/project-static/docs/search/search_index.json +1 -1
- nautobot/project-static/docs/sitemap.xml +197 -187
- nautobot/project-static/docs/sitemap.xml.gz +0 -0
- nautobot/project-static/docs/user-guides/custom-fields.html +1178 -10
- nautobot/project-static/docs/user-guides/getting-started/creating-devices.html +1178 -10
- nautobot/project-static/docs/user-guides/getting-started/index.html +1178 -10
- nautobot/project-static/docs/user-guides/getting-started/interfaces.html +1178 -10
- nautobot/project-static/docs/user-guides/getting-started/ipam.html +1178 -10
- nautobot/project-static/docs/user-guides/getting-started/platforms.html +1178 -10
- nautobot/project-static/docs/user-guides/getting-started/regions.html +1178 -10
- nautobot/project-static/docs/user-guides/getting-started/search-bar.html +1178 -10
- nautobot/project-static/docs/user-guides/getting-started/tenants.html +1178 -10
- nautobot/project-static/docs/user-guides/getting-started/vlans-and-vlan-groups.html +1178 -10
- nautobot/project-static/docs/user-guides/git-data-source.html +1178 -10
- nautobot/project-static/docs/user-guides/graphql.html +1178 -10
- nautobot/project-static/docs/user-guides/relationships.html +1178 -10
- nautobot/project-static/docs/user-guides/s3-django-storage.html +1178 -10
- nautobot/project-static/js/forms.js +16 -9
- nautobot/project-static/js/theme.js +5 -0
- nautobot/tenancy/api/serializers.py +4 -32
- nautobot/tenancy/api/urls.py +1 -1
- nautobot/tenancy/forms.py +0 -28
- nautobot/tenancy/migrations/0008_tagsfield.py +19 -0
- nautobot/tenancy/models.py +0 -25
- nautobot/tenancy/navigation.py +6 -39
- nautobot/tenancy/templates/tenancy/tenant.html +12 -12
- nautobot/tenancy/templates/tenancy/tenantgroup.html +1 -1
- nautobot/tenancy/tests/test_api.py +1 -3
- nautobot/tenancy/tests/test_filters.py +10 -5
- nautobot/tenancy/views.py +0 -2
- nautobot/ui/.eslintignore +6 -0
- nautobot/ui/.gitignore +10 -0
- nautobot/ui/.prettierignore +9 -0
- nautobot/ui/.prettierrc +4 -0
- nautobot/ui/README.md +33 -0
- nautobot/ui/app_imports.js.j2 +7 -0
- nautobot/ui/craco.config.js +46 -0
- nautobot/ui/jsconfig-base.json +11 -0
- nautobot/ui/jsconfig.json +5 -0
- nautobot/ui/lib/nautobot-craco-alias-plugin.js +40 -0
- nautobot/ui/package-lock.json +21451 -0
- nautobot/ui/package.json +70 -0
- nautobot/ui/public/index.html +47 -0
- nautobot/ui/public/logo192.png +0 -0
- nautobot/ui/public/logo512.png +0 -0
- nautobot/ui/public/manifest.json +25 -0
- nautobot/ui/public/nautobot_logo.svg +131 -0
- nautobot/ui/public/robots.txt +3 -0
- nautobot/ui/src/App.js +71 -0
- nautobot/ui/src/components/AppFullWidthComponents.js +8 -0
- nautobot/ui/src/components/AppTab.js +40 -0
- nautobot/ui/src/components/Apps.js +60 -0
- nautobot/ui/src/components/HomeChangelogPanel.js +98 -0
- nautobot/ui/src/components/HomePanel.js +58 -0
- nautobot/ui/src/components/JobHistoryTable.js +78 -0
- nautobot/ui/src/components/Layout.js +53 -0
- nautobot/ui/src/components/LoadingWidget.js +25 -0
- nautobot/ui/src/components/Navbar.js +116 -0
- nautobot/ui/src/components/NotificationPopover.js +27 -0
- nautobot/ui/src/components/ObjectListTable.js +209 -0
- nautobot/ui/src/components/ReferenceDataTag.js +35 -0
- nautobot/ui/src/components/RouterButton.js +10 -0
- nautobot/ui/src/components/RouterLink.js +10 -0
- nautobot/ui/src/components/SidebarNav.js +147 -0
- nautobot/ui/src/components/Table.js +48 -0
- nautobot/ui/src/components/TableItem.js +71 -0
- nautobot/ui/src/components/__tests__/AppFullWidthComponents.test.js +16 -0
- nautobot/ui/src/components/__tests__/AppTab.test.js +21 -0
- nautobot/ui/src/components/__tests__/Apps.test.js +14 -0
- nautobot/ui/src/components/__tests__/Layout.test.js +33 -0
- nautobot/ui/src/components/__tests__/Table.test.js +36 -0
- nautobot/ui/src/components/__tests__/TableItem.test.js +37 -0
- nautobot/ui/src/components/__tests__/paginator.test.js +43 -0
- nautobot/ui/src/components/__tests__/paginator_form.test.js +13 -0
- nautobot/ui/src/components/pagination.js +93 -0
- nautobot/ui/src/components/paginator.js +79 -0
- nautobot/ui/src/components/paginator_form.js +43 -0
- nautobot/ui/src/components/usePagination.js +57 -0
- nautobot/ui/src/constants/apiPath.js +10 -0
- nautobot/ui/src/constants/icons.js +15 -0
- nautobot/ui/src/constants/size.js +15 -0
- nautobot/ui/src/index.js +65 -0
- nautobot/ui/src/reportWebVitals.js +15 -0
- nautobot/ui/src/router.js +77 -0
- nautobot/ui/src/utils/api.js +131 -0
- nautobot/ui/src/utils/app-import.js +15 -0
- nautobot/ui/src/utils/color.js +15 -0
- nautobot/ui/src/utils/date.js +14 -0
- nautobot/ui/src/utils/index.js +15 -0
- nautobot/ui/src/utils/navigation.js +32 -0
- nautobot/ui/src/utils/session.js +64 -0
- nautobot/ui/src/utils/store.js +242 -0
- nautobot/ui/src/utils/string.js +6 -0
- nautobot/ui/src/utils/url.js +4 -0
- nautobot/ui/src/views/Home.js +138 -0
- nautobot/ui/src/views/InstalledApps.js +80 -0
- nautobot/ui/src/views/Login.js +48 -0
- nautobot/ui/src/views/Logout.js +20 -0
- nautobot/ui/src/views/__tests__/BSCreateViewTemplate.test.js +11 -0
- nautobot/ui/src/views/__tests__/BSListViewTemplate.test.js +107 -0
- nautobot/ui/src/views/__tests__/Login.test.js +15 -0
- nautobot/ui/src/views/generic/GenericView.js +142 -0
- nautobot/ui/src/views/generic/ObjectCreate.js +96 -0
- nautobot/ui/src/views/generic/ObjectList.js +127 -0
- nautobot/ui/src/views/generic/ObjectRetrieve.js +551 -0
- nautobot/users/admin.py +1 -1
- nautobot/users/api/serializers.py +51 -61
- nautobot/users/api/urls.py +1 -1
- nautobot/users/api/views.py +53 -2
- nautobot/users/tests/test_api.py +110 -25
- nautobot/virtualization/api/serializers.py +18 -130
- nautobot/virtualization/api/urls.py +1 -1
- nautobot/virtualization/api/views.py +1 -22
- nautobot/virtualization/forms.py +13 -99
- nautobot/virtualization/migrations/0012_alter_virtualmachine_role_add_new_role.py +1 -1
- nautobot/virtualization/migrations/0013_migrate_virtualmachine_role_data.py +18 -11
- nautobot/virtualization/migrations/0015_rename_foreignkey_fields.py +1 -1
- nautobot/virtualization/migrations/0018_related_name_changes.py +1 -1
- nautobot/virtualization/migrations/0021_tagsfield_and_vminterface_to_primarymodel.py +39 -0
- nautobot/virtualization/migrations/0022_vminterface_timestamps_data_migration.py +17 -0
- nautobot/virtualization/migrations/{0021_ipam__namespaces.py → 0023_ipam__namespaces.py} +2 -2
- nautobot/virtualization/migrations/0024_fixup_null_statuses.py +25 -0
- nautobot/virtualization/migrations/0025_status_nonnullable.py +29 -0
- nautobot/virtualization/models.py +31 -123
- nautobot/virtualization/navigation.py +18 -99
- nautobot/virtualization/templates/virtualization/virtualmachine.html +2 -1
- nautobot/virtualization/templates/virtualization/virtualmachine_edit.html +6 -0
- nautobot/virtualization/tests/test_api.py +25 -26
- nautobot/virtualization/tests/test_filters.py +41 -15
- nautobot/virtualization/tests/test_models.py +31 -7
- nautobot/virtualization/tests/test_views.py +42 -25
- nautobot/virtualization/views.py +7 -6
- {nautobot-2.0.0a3.dist-info → nautobot-2.0.0b1.dist-info}/METADATA +3 -7
- {nautobot-2.0.0a3.dist-info → nautobot-2.0.0b1.dist-info}/RECORD +744 -602
- {nautobot-2.0.0a3.dist-info → nautobot-2.0.0b1.dist-info}/WHEEL +1 -1
- nautobot/circuits/api/nested_serializers.py +0 -69
- nautobot/core/templates/plugin_template/navigation.py-tpl +0 -22
- nautobot/dcim/api/nested_serializers.py +0 -356
- nautobot/dcim/templates/dcim/device_import.html +0 -5
- nautobot/dcim/templates/dcim/device_import_child.html +0 -5
- nautobot/dcim/templates/dcim/inc/device_import_header.html +0 -4
- nautobot/extras/api/nested_serializers.py +0 -353
- nautobot/extras/migrations/0064_configcontext_data_migrations.py +0 -41
- nautobot/extras/migrations/0071_job__unique_name_data_migration.py +0 -46
- nautobot/extras/reports.py +0 -60
- nautobot/extras/scripts.py +0 -72
- nautobot/extras/tests/example_jobs/script_variables.py +0 -67
- nautobot/extras/tests/example_jobs/test_duplicate_name2.py +0 -5
- nautobot/extras/tests/example_jobs/test_fail.py +0 -16
- nautobot/extras/tests/example_jobs/test_file_upload_pass.py +0 -20
- nautobot/extras/tests/example_jobs/test_ipaddress_vars.py +0 -52
- nautobot/extras/tests/example_jobs/test_job_button_receiver.py +0 -21
- nautobot/extras/tests/example_jobs/test_job_hook_receiver.py +0 -20
- nautobot/extras/tests/example_jobs/test_location_with_custom_field.py +0 -35
- nautobot/extras/tests/example_jobs/test_log_redaction.py +0 -14
- nautobot/extras/tests/example_jobs/test_modify_db.py +0 -18
- nautobot/extras/tests/example_jobs/test_object_var_optional.py +0 -14
- nautobot/extras/tests/example_jobs/test_object_var_required.py +0 -14
- nautobot/extras/tests/example_jobs/test_object_vars.py +0 -29
- nautobot/extras/tests/example_jobs/test_pass.py +0 -19
- nautobot/extras/tests/example_jobs/test_read_only_fail.py +0 -24
- nautobot/extras/tests/example_jobs/test_read_only_no_commit_field.py +0 -10
- nautobot/extras/tests/example_jobs/test_read_only_pass.py +0 -22
- nautobot/ipam/api/nested_serializers.py +0 -159
- nautobot/ipam/migrations/0029_ipam__prefix__add_parent.py +0 -31
- nautobot/ipam/migrations/0030_ipam__prefix__data_migration.py +0 -13
- nautobot/ipam/migrations/0031_ipam__ipaddress__add_parent.py +0 -41
- nautobot/ipam/migrations/0032_ipam__ipaddress__data_migration.py +0 -11
- nautobot/tenancy/api/nested_serializers.py +0 -31
- nautobot/users/api/nested_serializers.py +0 -67
- nautobot/virtualization/api/nested_serializers.py +0 -65
- /nautobot/extras/{tests/example_jobs → test_jobs}/__init__.py +0 -0
- /nautobot/{dcim/models/sites.py → ipam/management/__init__.py} +0 -0
- {nautobot-2.0.0a3.dist-info → nautobot-2.0.0b1.dist-info}/LICENSE.txt +0 -0
- {nautobot-2.0.0a3.dist-info → nautobot-2.0.0b1.dist-info}/entry_points.txt +0 -0
nautobot/core/celery/__init__.py
CHANGED
|
@@ -2,17 +2,26 @@ import json
|
|
|
2
2
|
import logging
|
|
3
3
|
import os
|
|
4
4
|
from pathlib import Path
|
|
5
|
+
import pkgutil
|
|
6
|
+
import shutil
|
|
7
|
+
import sys
|
|
5
8
|
|
|
6
9
|
from celery import Celery, shared_task, signals
|
|
10
|
+
from celery.app.log import TaskFormatter
|
|
7
11
|
from celery.fixups.django import DjangoFixup
|
|
12
|
+
from celery.utils.log import get_logger
|
|
8
13
|
from django.conf import settings
|
|
9
|
-
from django.
|
|
14
|
+
from django.utils.functional import SimpleLazyObject
|
|
10
15
|
from django.utils.module_loading import import_string
|
|
11
16
|
from kombu.serialization import register
|
|
12
17
|
from prometheus_client import CollectorRegistry, multiprocess, start_http_server
|
|
13
18
|
|
|
14
|
-
|
|
19
|
+
from nautobot.core.celery.control import discard_git_repository, refresh_git_repository # noqa: F401
|
|
20
|
+
from nautobot.core.celery.encoders import NautobotKombuJSONEncoder
|
|
21
|
+
from nautobot.core.celery.log import NautobotDatabaseHandler
|
|
22
|
+
|
|
15
23
|
|
|
24
|
+
logger = logging.getLogger(__name__)
|
|
16
25
|
# The Celery documentation tells us to call setup on the app to initialize
|
|
17
26
|
# settings, but we will NOT be doing that because of a chicken-and-egg problem
|
|
18
27
|
# when bootstrapping the Django settings with `nautobot-server`.
|
|
@@ -25,7 +34,22 @@ logger = logging.getLogger(__name__)
|
|
|
25
34
|
# NOT need to be called here.
|
|
26
35
|
# nautobot.setup()
|
|
27
36
|
|
|
28
|
-
|
|
37
|
+
|
|
38
|
+
class NautobotCelery(Celery):
|
|
39
|
+
task_cls = "nautobot.core.celery.task:NautobotTask"
|
|
40
|
+
|
|
41
|
+
def register_task(self, task, **options):
|
|
42
|
+
"""Override the default task name for job classes to allow app provided jobs to use the full module path."""
|
|
43
|
+
from nautobot.extras.jobs import Job
|
|
44
|
+
|
|
45
|
+
if issubclass(task, Job):
|
|
46
|
+
task = task()
|
|
47
|
+
task.name = task.registered_name
|
|
48
|
+
|
|
49
|
+
return super().register_task(task, **options)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
app = NautobotCelery("nautobot")
|
|
29
53
|
|
|
30
54
|
# Using a string here means the worker doesn't have to serialize
|
|
31
55
|
# the configuration object to child processes. Again, this is possible
|
|
@@ -43,7 +67,83 @@ DjangoFixup(app).install()
|
|
|
43
67
|
app.autodiscover_tasks()
|
|
44
68
|
|
|
45
69
|
|
|
46
|
-
@signals.
|
|
70
|
+
@signals.import_modules.connect
|
|
71
|
+
def import_jobs_as_celery_tasks(sender, database_ready=True, **kwargs):
|
|
72
|
+
"""
|
|
73
|
+
Import system Jobs into Celery as well as Jobs from JOBS_ROOT and GIT_ROOT.
|
|
74
|
+
|
|
75
|
+
Note that app-provided Jobs are automatically imported at startup time via NautobotAppConfig.ready()
|
|
76
|
+
"""
|
|
77
|
+
logger.debug("Importing system Jobs")
|
|
78
|
+
sender.loader.import_task_module("nautobot.core.jobs")
|
|
79
|
+
|
|
80
|
+
jobs_root = settings.JOBS_ROOT
|
|
81
|
+
if jobs_root and os.path.exists(jobs_root):
|
|
82
|
+
if jobs_root not in sys.path:
|
|
83
|
+
sys.path.append(jobs_root)
|
|
84
|
+
for _, module_name, _ in pkgutil.iter_modules([jobs_root]):
|
|
85
|
+
try:
|
|
86
|
+
logger.debug("Importing Jobs from %s in JOBS_ROOT", module_name)
|
|
87
|
+
sender.loader.import_task_module(module_name)
|
|
88
|
+
except Exception as exc:
|
|
89
|
+
# logger.error(f"Unable to load module '{module_name}' from {jobs_root}: {exc:}")
|
|
90
|
+
logger.exception(exc)
|
|
91
|
+
|
|
92
|
+
git_root = settings.GIT_ROOT
|
|
93
|
+
if git_root and os.path.exists(git_root):
|
|
94
|
+
if git_root not in sys.path:
|
|
95
|
+
sys.path.append(git_root)
|
|
96
|
+
|
|
97
|
+
# We can't detect which Git directories we're *supposed* to auto-load Jobs from if we can't read GitRepository
|
|
98
|
+
# records from the DB, unfortunately.
|
|
99
|
+
# We work around this in JobModel.job_task to try later loading Git jobs on-the-fly if needed.
|
|
100
|
+
if database_ready:
|
|
101
|
+
from nautobot.extras.models import GitRepository
|
|
102
|
+
|
|
103
|
+
# Make sure there are no git clones in GIT_ROOT that *aren't* tracked by a GitRepository;
|
|
104
|
+
# for example, maybe a GitRepository was deleted while this worker process wasn't running?
|
|
105
|
+
for filename in os.listdir(git_root):
|
|
106
|
+
filepath = os.path.join(git_root, filename)
|
|
107
|
+
if (
|
|
108
|
+
os.path.isdir(filepath)
|
|
109
|
+
and os.path.isdir(os.path.join(filepath, ".git"))
|
|
110
|
+
and not GitRepository.objects.filter(slug=filename).exists()
|
|
111
|
+
):
|
|
112
|
+
logger.warning("Deleting unmanaged (leftover?) Git repository clone at %s", filepath)
|
|
113
|
+
shutil.rmtree(filepath)
|
|
114
|
+
|
|
115
|
+
# Make sure all GitRepository records that include Jobs have up-to-date git clones, and load their jobs
|
|
116
|
+
for repo in GitRepository.objects.all():
|
|
117
|
+
refresh_git_repository(state=None, repository_pk=repo.pk, head=repo.current_head)
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def add_nautobot_log_handler(logger_instance, log_format=None):
|
|
121
|
+
"""Add NautobotDatabaseHandler to logger and update logger level filtering to send all log levels to our handler."""
|
|
122
|
+
if any(isinstance(h, NautobotDatabaseHandler) for h in logger_instance.handlers):
|
|
123
|
+
return
|
|
124
|
+
if logger_instance.level not in (logging.NOTSET, logging.DEBUG):
|
|
125
|
+
for handler in logger_instance.handlers:
|
|
126
|
+
handler.setLevel(logger_instance.level)
|
|
127
|
+
logger_instance.setLevel(logging.DEBUG)
|
|
128
|
+
|
|
129
|
+
if log_format is None:
|
|
130
|
+
log_format = app.conf.worker_task_log_format
|
|
131
|
+
handler = NautobotDatabaseHandler()
|
|
132
|
+
handler.setFormatter(TaskFormatter(log_format, use_color=False))
|
|
133
|
+
logger_instance.addHandler(handler)
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
@signals.celeryd_after_setup.connect
|
|
137
|
+
def setup_nautobot_job_logging(sender, instance, conf, **kwargs):
|
|
138
|
+
"""Add nautobot database logging handler to celery stdout/stderr redirect logger and celery task logger."""
|
|
139
|
+
task_logger = get_logger("celery.task")
|
|
140
|
+
add_nautobot_log_handler(task_logger)
|
|
141
|
+
if conf.worker_redirect_stdouts:
|
|
142
|
+
redirect_logger = get_logger("celery.redirected")
|
|
143
|
+
add_nautobot_log_handler(redirect_logger)
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
@signals.worker_ready.connect
|
|
47
147
|
def setup_prometheus(**kwargs):
|
|
48
148
|
"""This sets up an HTTP server to serve prometheus metrics from the celery workers."""
|
|
49
149
|
# Don't set up the server if the port is undefined
|
|
@@ -71,42 +171,6 @@ def setup_prometheus(**kwargs):
|
|
|
71
171
|
logger.warning("Cannot export Prometheus metrics from worker, no available ports in range.")
|
|
72
172
|
|
|
73
173
|
|
|
74
|
-
class NautobotKombuJSONEncoder(DjangoJSONEncoder):
|
|
75
|
-
"""
|
|
76
|
-
Custom json encoder based on DjangoJSONEncoder that serializes objects that implement
|
|
77
|
-
the `nautobot_serialize()` method via the `__nautobot_type__` interface. This is useful
|
|
78
|
-
in passing special objects to and from Celery tasks.
|
|
79
|
-
|
|
80
|
-
This pattern should generally be avoided by passing pointers to persisted objects to the
|
|
81
|
-
Celery tasks and retrieving them from within the task execution. While this is always possible
|
|
82
|
-
for model instances (which covers 99% of use cases), for rare instances where it does not,
|
|
83
|
-
and the actual object must be passed, this pattern allows for encoding and decoding
|
|
84
|
-
of such objects.
|
|
85
|
-
|
|
86
|
-
It requires a conforming class to implement the instance method `nautobot_serialize()` which
|
|
87
|
-
returns a json serializable dictionary of the object representation. The class must also implement
|
|
88
|
-
the `nautobot_deserialize()` class method which takes the dictionary representation and returns
|
|
89
|
-
an actual instance of the class.
|
|
90
|
-
"""
|
|
91
|
-
|
|
92
|
-
def default(self, obj):
|
|
93
|
-
if hasattr(obj, "nautobot_serialize"):
|
|
94
|
-
cls = obj.__class__
|
|
95
|
-
module = cls.__module__
|
|
96
|
-
qual_name = ".".join([module, cls.__qualname__]) # fully qualified dotted import path
|
|
97
|
-
logger.debug("Performing nautobot serialization on %s for type %s", obj, qual_name)
|
|
98
|
-
data = {"__nautobot_type__": qual_name}
|
|
99
|
-
data.update(obj.nautobot_serialize())
|
|
100
|
-
return data
|
|
101
|
-
|
|
102
|
-
elif isinstance(obj, set):
|
|
103
|
-
# Convert a set to a list for passing to and from a task
|
|
104
|
-
return list(obj)
|
|
105
|
-
|
|
106
|
-
else:
|
|
107
|
-
return DjangoJSONEncoder.default(self, obj)
|
|
108
|
-
|
|
109
|
-
|
|
110
174
|
def nautobot_kombu_json_loads_hook(data):
|
|
111
175
|
"""
|
|
112
176
|
In concert with the NautobotKombuJSONEncoder json encoder, this object hook method decodes
|
|
@@ -117,7 +181,7 @@ def nautobot_kombu_json_loads_hook(data):
|
|
|
117
181
|
logger.debug("Performing nautobot deserialization for type %s", qual_name)
|
|
118
182
|
cls = import_string(qual_name) # fully qualified dotted import path
|
|
119
183
|
if cls:
|
|
120
|
-
return cls.
|
|
184
|
+
return SimpleLazyObject(lambda: cls.objects.get(id=data["id"]))
|
|
121
185
|
else:
|
|
122
186
|
raise TypeError(f"Unable to import {qual_name} during nautobot deserialization")
|
|
123
187
|
else:
|
|
@@ -148,3 +212,10 @@ register("nautobot_json", _dumps, _loads, content_type="application/x-nautobot-j
|
|
|
148
212
|
#
|
|
149
213
|
|
|
150
214
|
nautobot_task = shared_task
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
def register_jobs(*jobs):
|
|
218
|
+
"""Helper method to register jobs with Celery"""
|
|
219
|
+
for job in jobs:
|
|
220
|
+
logger.debug("Registering job %s.%s", job.__module__, job.__name__)
|
|
221
|
+
app.register_task(job)
|
nautobot/core/celery/backends.py
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
from django_celery_results.backends import DatabaseBackend
|
|
2
2
|
|
|
3
|
+
from nautobot.extras.constants import JOB_RESULT_CUSTOM_CELERY_KWARGS
|
|
3
4
|
from nautobot.extras.models import JobResult
|
|
4
5
|
|
|
5
6
|
|
|
@@ -20,38 +21,44 @@ class NautobotDatabaseBackend(DatabaseBackend):
|
|
|
20
21
|
|
|
21
22
|
def _get_extended_properties(self, request, traceback):
|
|
22
23
|
"""
|
|
23
|
-
Overload default so that `argsrepr` and `kwargsrepr` aren't used to construct `args` and
|
|
24
|
-
|
|
24
|
+
Overload default so that `argsrepr` and `kwargsrepr` aren't used to construct `args` and `kwargs`.
|
|
25
|
+
Also adds custom kwargs passed in on `apply_async` calls to track user, job model, scheduled job, etc.
|
|
25
26
|
"""
|
|
26
27
|
extended_props = {
|
|
27
|
-
"periodic_task_name": None,
|
|
28
28
|
"task_args": None,
|
|
29
29
|
"task_kwargs": None,
|
|
30
|
+
"celery_kwargs": None,
|
|
31
|
+
"job_model_id": None,
|
|
32
|
+
"scheduled_job_id": None,
|
|
30
33
|
"task_name": None,
|
|
31
34
|
"traceback": None,
|
|
35
|
+
"user_id": None,
|
|
32
36
|
"worker": None,
|
|
33
37
|
}
|
|
34
38
|
if request and self.app.conf.find_value_for_key("extended", "result"):
|
|
35
|
-
#
|
|
39
|
+
# do not encode args/kwargs as we store these in a JSONField instead of TextField
|
|
36
40
|
task_args = getattr(request, "args", None)
|
|
37
41
|
task_kwargs = getattr(request, "kwargs", None)
|
|
38
42
|
|
|
39
|
-
|
|
40
|
-
if task_args is not None:
|
|
41
|
-
_, _, task_args = self.encode_content(task_args)
|
|
43
|
+
properties = getattr(request, "properties", {}) or {}
|
|
42
44
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
+
# retrieve original "queue" kwarg from the request, celery stores it in delivery_info.routing_key
|
|
46
|
+
celery_kwargs = {"queue": request.delivery_info.get("routing_key", None)}
|
|
47
|
+
|
|
48
|
+
for kwarg_name in JOB_RESULT_CUSTOM_CELERY_KWARGS:
|
|
49
|
+
if kwarg_name in properties:
|
|
50
|
+
celery_kwargs[kwarg_name] = properties[kwarg_name]
|
|
45
51
|
|
|
46
|
-
properties = getattr(request, "properties", {}) or {}
|
|
47
|
-
periodic_task_name = properties.get("periodic_task_name", None)
|
|
48
52
|
extended_props.update(
|
|
49
53
|
{
|
|
50
|
-
"periodic_task_name": periodic_task_name,
|
|
51
54
|
"task_args": task_args,
|
|
52
55
|
"task_kwargs": task_kwargs,
|
|
56
|
+
"celery_kwargs": celery_kwargs,
|
|
57
|
+
"job_model_id": properties.get("nautobot_job_job_model_id", None),
|
|
58
|
+
"scheduled_job_id": properties.get("nautobot_job_scheduled_job_id", None),
|
|
53
59
|
"task_name": getattr(request, "task", None),
|
|
54
60
|
"traceback": traceback,
|
|
61
|
+
"user_id": properties.get("nautobot_job_user_id", None),
|
|
55
62
|
"worker": getattr(request, "hostname", None),
|
|
56
63
|
}
|
|
57
64
|
)
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
import os
|
|
3
|
+
import shutil
|
|
4
|
+
|
|
5
|
+
from celery.worker.control import control_command
|
|
6
|
+
|
|
7
|
+
from django.conf import settings
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
logger = logging.getLogger(__name__)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@control_command(args=[("repository_pk", str), ("head", str)])
|
|
14
|
+
def refresh_git_repository(state, repository_pk, head):
|
|
15
|
+
"""
|
|
16
|
+
Celery worker control event to ensure that all active workers have the correct head for a given Git repository.
|
|
17
|
+
"""
|
|
18
|
+
from nautobot.extras.datasources.git import ensure_git_repository, refresh_code_from_repository
|
|
19
|
+
from nautobot.extras.models import GitRepository
|
|
20
|
+
|
|
21
|
+
try:
|
|
22
|
+
repository = GitRepository.objects.get(pk=repository_pk)
|
|
23
|
+
# Refresh the repository on disk
|
|
24
|
+
ensure_git_repository(repository, head=head, logger=logger)
|
|
25
|
+
refresh_code_from_repository(repository.slug, consumer=state.consumer if state is not None else None)
|
|
26
|
+
|
|
27
|
+
return {"ok": {"head": repository.current_head}}
|
|
28
|
+
except Exception as exc:
|
|
29
|
+
logger.error("%s", exc)
|
|
30
|
+
return {"error": str(exc)}
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
@control_command(args=["repository_slug", str])
|
|
34
|
+
def discard_git_repository(state, repository_slug):
|
|
35
|
+
"""
|
|
36
|
+
Celery worker control even to ensure that all active workers unload a given Git repository and delete it from disk.
|
|
37
|
+
"""
|
|
38
|
+
from nautobot.extras.datasources.git import refresh_code_from_repository
|
|
39
|
+
|
|
40
|
+
filesystem_path = os.path.join(settings.GIT_ROOT, repository_slug)
|
|
41
|
+
if os.path.isdir(filesystem_path):
|
|
42
|
+
shutil.rmtree(filesystem_path)
|
|
43
|
+
# Unload any code from this repository
|
|
44
|
+
refresh_code_from_repository(
|
|
45
|
+
repository_slug, consumer=state.consumer if state is not None else None, skip_reimport=True
|
|
46
|
+
)
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
|
|
3
|
+
from rest_framework.utils.encoders import JSONEncoder
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
logger = logging.getLogger(__name__)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class NautobotKombuJSONEncoder(JSONEncoder):
|
|
10
|
+
"""
|
|
11
|
+
Custom json encoder based on restframework's JSONEncoder that serializes objects that implement
|
|
12
|
+
the `nautobot_serialize()` method via the `__nautobot_type__` interface. This is useful
|
|
13
|
+
in passing special objects to and from Celery tasks.
|
|
14
|
+
|
|
15
|
+
This pattern should generally be avoided by passing pointers to persisted objects to the
|
|
16
|
+
Celery tasks and retrieving them from within the task execution. While this is always possible
|
|
17
|
+
for model instances (which covers 99% of use cases), for rare instances where it does not,
|
|
18
|
+
and the actual object must be passed, this pattern allows for encoding and decoding
|
|
19
|
+
of such objects.
|
|
20
|
+
|
|
21
|
+
It requires a conforming class to implement the instance method `nautobot_serialize()` which
|
|
22
|
+
returns a json serializable dictionary of the object representation. The class must also implement
|
|
23
|
+
the `nautobot_deserialize()` class method which takes the dictionary representation and returns
|
|
24
|
+
an actual instance of the class.
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
def default(self, obj):
|
|
28
|
+
# Import here to avoid django.core.exceptions.ImproperlyConfigured Error.
|
|
29
|
+
# Core App is not set up yet if we import this at the top of the file.
|
|
30
|
+
from nautobot.core.models import BaseModel
|
|
31
|
+
from nautobot.core.models.managers import TagsManager
|
|
32
|
+
|
|
33
|
+
if isinstance(obj, BaseModel):
|
|
34
|
+
cls = obj.__class__
|
|
35
|
+
module = cls.__module__
|
|
36
|
+
qual_name = ".".join([module, cls.__qualname__]) # fully qualified dotted import path
|
|
37
|
+
logger.debug("Performing nautobot serialization on %s for type %s", obj, qual_name)
|
|
38
|
+
data = {
|
|
39
|
+
"id": obj.id,
|
|
40
|
+
"__nautobot_type__": qual_name,
|
|
41
|
+
# TODO: change to natural key to provide additional context if object is deleted from the db
|
|
42
|
+
"display": getattr(obj, "display", str(obj)),
|
|
43
|
+
}
|
|
44
|
+
return data
|
|
45
|
+
|
|
46
|
+
elif isinstance(obj, set):
|
|
47
|
+
# Convert a set to a list for passing to and from a task
|
|
48
|
+
return list(obj)
|
|
49
|
+
elif isinstance(obj, TagsManager):
|
|
50
|
+
obj = obj.values_list("id", flat=True)
|
|
51
|
+
return obj
|
|
52
|
+
else:
|
|
53
|
+
return super().default(obj)
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
|
|
3
|
+
from celery import current_task
|
|
4
|
+
from django.core.exceptions import ValidationError
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class NautobotDatabaseHandler(logging.Handler):
|
|
8
|
+
"""Custom logging handler to log messages to JobLogEntry database entries."""
|
|
9
|
+
|
|
10
|
+
def emit(self, record):
|
|
11
|
+
if current_task is None:
|
|
12
|
+
return
|
|
13
|
+
|
|
14
|
+
from nautobot.extras.models.jobs import JobResult
|
|
15
|
+
|
|
16
|
+
try:
|
|
17
|
+
self.format(record)
|
|
18
|
+
|
|
19
|
+
try:
|
|
20
|
+
job_result = JobResult.objects.get(id=record.task_id)
|
|
21
|
+
except (ValidationError, JobResult.DoesNotExist):
|
|
22
|
+
# Both of these cases are very rare
|
|
23
|
+
# ValidationError - because the task_id might not a valid UUID
|
|
24
|
+
# JobResult.DoesNotExist - because we might not have a JobResult with that ID
|
|
25
|
+
return
|
|
26
|
+
|
|
27
|
+
# Skip recording the log entry if it has been marked as such
|
|
28
|
+
if getattr(record, "skip_db_logging", False):
|
|
29
|
+
return
|
|
30
|
+
|
|
31
|
+
job_result.log(
|
|
32
|
+
message=record.message,
|
|
33
|
+
level_choice=record.levelname.lower(),
|
|
34
|
+
obj=getattr(record, "object", None),
|
|
35
|
+
grouping=getattr(record, "grouping", record.funcName),
|
|
36
|
+
)
|
|
37
|
+
except Exception:
|
|
38
|
+
self.handleError(record)
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
from collections.abc import Mapping
|
|
1
2
|
import logging
|
|
2
3
|
|
|
3
4
|
from celery import current_app
|
|
@@ -38,11 +39,29 @@ class NautobotScheduleEntry(ModelEntry):
|
|
|
38
39
|
)
|
|
39
40
|
self._disable(model)
|
|
40
41
|
|
|
41
|
-
self.options = {}
|
|
42
|
-
|
|
43
|
-
|
|
42
|
+
self.options = {"nautobot_job_scheduled_job_id": model.id, "headers": {}}
|
|
43
|
+
|
|
44
|
+
if model.user:
|
|
45
|
+
self.options["nautobot_job_user_id"] = model.user.id
|
|
46
|
+
else:
|
|
47
|
+
logger.error(
|
|
48
|
+
"Disabling schedule %s with missing user",
|
|
49
|
+
self.name,
|
|
50
|
+
)
|
|
51
|
+
self._disable(model)
|
|
52
|
+
|
|
53
|
+
if model.job_model:
|
|
54
|
+
self.options["nautobot_job_job_model_id"] = model.job_model.id
|
|
55
|
+
else:
|
|
56
|
+
logger.error(
|
|
57
|
+
"Disabling schedule %s with missing job model",
|
|
58
|
+
self.name,
|
|
59
|
+
)
|
|
60
|
+
self._disable(model)
|
|
61
|
+
|
|
62
|
+
if isinstance(model.celery_kwargs, Mapping):
|
|
63
|
+
self.options.update(model.celery_kwargs)
|
|
44
64
|
|
|
45
|
-
self.options["headers"] = {}
|
|
46
65
|
self.total_run_count = model.total_run_count
|
|
47
66
|
self.model = model
|
|
48
67
|
|
nautobot/core/celery/task.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
from celery.utils.log import get_task_logger
|
|
2
1
|
from celery import Task
|
|
3
2
|
|
|
3
|
+
from nautobot.extras.jobs import get_task_logger
|
|
4
4
|
|
|
5
5
|
logger = get_task_logger(__name__)
|
|
6
6
|
|
|
@@ -10,18 +10,3 @@ class NautobotTask(Task):
|
|
|
10
10
|
|
|
11
11
|
|
|
12
12
|
Task = NautobotTask # noqa: So that the class path resolves.
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
# TODO(jathan): Remove this once this body of work is done. This is just useful for debugging but it
|
|
16
|
-
# results int a lot of noise and slows things down.
|
|
17
|
-
# from celery import signals
|
|
18
|
-
# @signals.task_prerun.connect
|
|
19
|
-
def debug_task_prerun(sender, task_id, task, args, kwargs, **extra):
|
|
20
|
-
logger.error(">>> SENDER = %s", sender)
|
|
21
|
-
logger.error(">>> TASK = %s", task)
|
|
22
|
-
logger.error(">>> REQUEST = %s", task.request)
|
|
23
|
-
logger.error(">>> TASK_NAME = %s", task.request.task)
|
|
24
|
-
logger.error(">>> TASK_ID = %s", task_id)
|
|
25
|
-
logger.error(">>> ARGS = %s", args)
|
|
26
|
-
logger.error(">>> KWARGS = %s", kwargs)
|
|
27
|
-
logger.error(">>> EXTRA = %s", extra)
|
nautobot/core/checks.py
CHANGED
|
@@ -6,12 +6,6 @@ from django.core.exceptions import ValidationError
|
|
|
6
6
|
from django.core.validators import URLValidator
|
|
7
7
|
|
|
8
8
|
|
|
9
|
-
E001 = Error(
|
|
10
|
-
"CACHEOPS_DEFAULTS['timeout'] value cannot be 0. To disable caching set CACHEOPS_ENABLED=False.",
|
|
11
|
-
id="nautobot.core.E001",
|
|
12
|
-
obj=settings,
|
|
13
|
-
)
|
|
14
|
-
|
|
15
9
|
E002 = Error(
|
|
16
10
|
"'nautobot.core.authentication.ObjectPermissionBackend' must be included in AUTHENTICATION_BACKENDS",
|
|
17
11
|
id="nautobot.core.E002",
|
|
@@ -42,20 +36,6 @@ W005 = Warning(
|
|
|
42
36
|
obj=settings,
|
|
43
37
|
)
|
|
44
38
|
|
|
45
|
-
W006 = Warning(
|
|
46
|
-
"CACHEOPS_ENABLED is set to True but cacheops is no longer recommended in v1.5. It can still be used but may lead to "
|
|
47
|
-
"inaccurate data responses. Cacheops will be removed in a later release.",
|
|
48
|
-
id="nautobot.core.W006",
|
|
49
|
-
obj=settings,
|
|
50
|
-
)
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
@register(Tags.caches)
|
|
54
|
-
def check_cache_timeout(app_configs, **kwargs):
|
|
55
|
-
if settings.CACHEOPS_DEFAULTS.get("timeout") == 0:
|
|
56
|
-
return [E001]
|
|
57
|
-
return []
|
|
58
|
-
|
|
59
39
|
|
|
60
40
|
@register(Tags.security)
|
|
61
41
|
def check_object_permissions_backend(app_configs, **kwargs):
|
|
@@ -96,13 +76,6 @@ def check_maintenance_mode(app_configs, **kwargs):
|
|
|
96
76
|
return []
|
|
97
77
|
|
|
98
78
|
|
|
99
|
-
@register(Tags.compatibility)
|
|
100
|
-
def check_cacheops_enabled(app_configs, **kwargs):
|
|
101
|
-
if settings.CACHEOPS_ENABLED:
|
|
102
|
-
return [W006]
|
|
103
|
-
return []
|
|
104
|
-
|
|
105
|
-
|
|
106
79
|
@register(Tags.security)
|
|
107
80
|
def check_sanitizer_patterns(app_configs, **kwargs):
|
|
108
81
|
errors = []
|
nautobot/core/choices.py
CHANGED
|
@@ -167,116 +167,3 @@ class ColorChoices(ChoiceSet):
|
|
|
167
167
|
(COLOR_BLACK, "Black"),
|
|
168
168
|
(COLOR_WHITE, "White"),
|
|
169
169
|
)
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
#
|
|
173
|
-
# Button color choices
|
|
174
|
-
#
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
class ButtonColorChoices(ChoiceSet):
|
|
178
|
-
"""
|
|
179
|
-
Map standard button color choices to Bootstrap color classes
|
|
180
|
-
"""
|
|
181
|
-
|
|
182
|
-
DEFAULT = "default"
|
|
183
|
-
BLUE = "primary"
|
|
184
|
-
GREY = "secondary"
|
|
185
|
-
GREEN = "success"
|
|
186
|
-
RED = "danger"
|
|
187
|
-
YELLOW = "warning"
|
|
188
|
-
BLACK = "dark"
|
|
189
|
-
|
|
190
|
-
CHOICES = (
|
|
191
|
-
(DEFAULT, "Default"),
|
|
192
|
-
(BLUE, "Blue"),
|
|
193
|
-
(GREY, "Grey"),
|
|
194
|
-
(GREEN, "Green"),
|
|
195
|
-
(RED, "Red"),
|
|
196
|
-
(YELLOW, "Yellow"),
|
|
197
|
-
(BLACK, "Black"),
|
|
198
|
-
)
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
class ButtonActionColorChoices(ChoiceSet):
|
|
202
|
-
"""
|
|
203
|
-
Map standard button actions to Bootstrap color classes.
|
|
204
|
-
"""
|
|
205
|
-
|
|
206
|
-
ADD = "success"
|
|
207
|
-
CANCEL = "default"
|
|
208
|
-
CLONE = "success"
|
|
209
|
-
CONFIGURE = "default"
|
|
210
|
-
CONNECT = "success"
|
|
211
|
-
DEFAULT = "default"
|
|
212
|
-
DELETE = "danger"
|
|
213
|
-
DISCONNECT = "info"
|
|
214
|
-
EDIT = "warning"
|
|
215
|
-
EXPORT = "success"
|
|
216
|
-
IMPORT = "primary"
|
|
217
|
-
INFO = "info"
|
|
218
|
-
SUBMIT = "primary"
|
|
219
|
-
SWAP = "primary"
|
|
220
|
-
|
|
221
|
-
CHOICES = (
|
|
222
|
-
(ADD, "Add"),
|
|
223
|
-
(CANCEL, "Cancel"),
|
|
224
|
-
(CLONE, "Clone"),
|
|
225
|
-
(CONFIGURE, "Configure"),
|
|
226
|
-
(CONNECT, "Connect"),
|
|
227
|
-
(DEFAULT, "Default"),
|
|
228
|
-
(DELETE, "Delete"),
|
|
229
|
-
(DISCONNECT, "Disconnect"),
|
|
230
|
-
(EDIT, "Edit"),
|
|
231
|
-
(EXPORT, "Export"),
|
|
232
|
-
(IMPORT, "Import"),
|
|
233
|
-
(INFO, "Info"),
|
|
234
|
-
(SUBMIT, "Submit"),
|
|
235
|
-
(SWAP, "Swap"),
|
|
236
|
-
)
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
class ButtonActionIconChoices(ChoiceSet):
|
|
240
|
-
"""
|
|
241
|
-
Map standard button actions to Material Design Icons classes.
|
|
242
|
-
"""
|
|
243
|
-
|
|
244
|
-
ADD = "mdi-plus-thick"
|
|
245
|
-
ALERT = "mdi-alert"
|
|
246
|
-
ARROW_DOWN = "mdi-arrow-down-bold"
|
|
247
|
-
ARROW_UP = "mdi-arrow-up-bold"
|
|
248
|
-
CONFIGURE = "mdi-cogs"
|
|
249
|
-
CONNECT = "mdi-ethernet-cable"
|
|
250
|
-
DELETE = "mdi-trash-can-outline"
|
|
251
|
-
DISCONNECT = "mdi-ethernet-cable-off"
|
|
252
|
-
EDIT = "mdi-pencil"
|
|
253
|
-
EXPORT = "mdi-database-export-outline"
|
|
254
|
-
HELP = "mdi-help-circle"
|
|
255
|
-
INFO = "mdi-help-circle"
|
|
256
|
-
IMPORT = "mdi-database-import-outline"
|
|
257
|
-
LOCK = "mdi-lock"
|
|
258
|
-
MAGNIFY = "mdi-magnify"
|
|
259
|
-
NOTE = "mdi-note-text"
|
|
260
|
-
SWAP = "mdi-swap-vertical"
|
|
261
|
-
TRASH = "mdi-trash-can-outline"
|
|
262
|
-
|
|
263
|
-
CHOICES = (
|
|
264
|
-
(ADD, "Add"),
|
|
265
|
-
(ALERT, "Alert"),
|
|
266
|
-
(ARROW_DOWN, "Arrow Down"),
|
|
267
|
-
(ARROW_UP, "Arrow Up"),
|
|
268
|
-
(CONFIGURE, "Configure"),
|
|
269
|
-
(CONNECT, "Connect"),
|
|
270
|
-
(DELETE, "Delete"),
|
|
271
|
-
(DISCONNECT, "Disconnect"),
|
|
272
|
-
(EDIT, "Edit"),
|
|
273
|
-
(EXPORT, "Export"),
|
|
274
|
-
(HELP, "Help"),
|
|
275
|
-
(INFO, "Info"),
|
|
276
|
-
(IMPORT, "Import"),
|
|
277
|
-
(LOCK, "Lock"),
|
|
278
|
-
(MAGNIFY, "Magnify"),
|
|
279
|
-
(NOTE, "Note"),
|
|
280
|
-
(SWAP, "Swap"),
|
|
281
|
-
(TRASH, "Trash"),
|
|
282
|
-
)
|
|
@@ -27,7 +27,7 @@ SETTINGS_ENVVAR = "NAUTOBOT_CONFIG"
|
|
|
27
27
|
BASE_DIR = os.path.dirname(__file__)
|
|
28
28
|
|
|
29
29
|
# File path of template used to generate config emitted by `init`
|
|
30
|
-
CONFIG_TEMPLATE = os.path.join(BASE_DIR, "templates/nautobot_config.py.j2")
|
|
30
|
+
CONFIG_TEMPLATE = os.path.join(BASE_DIR, "../templates/nautobot_config.py.j2")
|
|
31
31
|
|
|
32
32
|
DESCRIPTION = """
|
|
33
33
|
Nautobot server management utility.
|
nautobot/core/constants.py
CHANGED
|
@@ -32,30 +32,6 @@ FILTER_NUMERIC_BASED_LOOKUP_MAP = {
|
|
|
32
32
|
|
|
33
33
|
FILTER_NEGATION_LOOKUP_MAP = {"n": "exact"}
|
|
34
34
|
|
|
35
|
-
|
|
36
|
-
#
|
|
37
|
-
# HTTP Request META safe copy
|
|
38
|
-
#
|
|
39
|
-
|
|
40
|
-
HTTP_REQUEST_META_SAFE_COPY = [
|
|
41
|
-
"CONTENT_LENGTH",
|
|
42
|
-
"CONTENT_TYPE",
|
|
43
|
-
"HTTP_ACCEPT",
|
|
44
|
-
"HTTP_ACCEPT_ENCODING",
|
|
45
|
-
"HTTP_ACCEPT_LANGUAGE",
|
|
46
|
-
"HTTP_HOST",
|
|
47
|
-
"HTTP_REFERER",
|
|
48
|
-
"HTTP_USER_AGENT",
|
|
49
|
-
"QUERY_STRING",
|
|
50
|
-
"REMOTE_ADDR",
|
|
51
|
-
"REMOTE_HOST",
|
|
52
|
-
"REMOTE_USER",
|
|
53
|
-
"REQUEST_METHOD",
|
|
54
|
-
"SERVER_NAME",
|
|
55
|
-
"SERVER_PORT",
|
|
56
|
-
]
|
|
57
|
-
|
|
58
|
-
|
|
59
35
|
#
|
|
60
36
|
# Factory defaults
|
|
61
37
|
#
|