forward-netbox 2.0.2__tar.gz → 2.0.3__tar.gz
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.
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/PKG-INFO +3 -2
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/README.md +2 -1
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/__init__.py +1 -1
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/tests/test_sync.py +32 -538
- forward_netbox-2.0.3/forward_netbox/utilities/fast_bootstrap_executor.py +81 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/utilities/sync.py +7 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/utilities/sync_reporting.py +9 -2
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/pyproject.toml +1 -1
- forward_netbox-2.0.2/forward_netbox/utilities/fast_bootstrap_executor.py +0 -248
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/LICENSE +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/api/__init__.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/api/serializers.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/api/urls.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/api/views.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/choices.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/exceptions.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/filtersets.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/forms.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/jobs.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/management/__init__.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/management/commands/__init__.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/management/commands/forward_apic_cimc_readiness_audit.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/management/commands/forward_blocker_audit.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/management/commands/forward_collection_gap_alert.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/management/commands/forward_device_scope_reconciliation_audit.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/management/commands/forward_module_readiness.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/management/commands/forward_pushdown_profile.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/management/commands/forward_query_diff_coverage_audit.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/management/commands/forward_seed_ui_harness.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/management/commands/forward_validation_org_query_audit.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/migrations/0001_initial.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/migrations/0002_add_coalesce_fields.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/migrations/0003_forwardingestionissue_context_fields.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/migrations/0004_forwardingestion_baseline_fields.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/migrations/0005_validation_and_reporting.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/migrations/0006_alter_forwardnqemap_netbox_model.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/migrations/0007_forwardingestion_persisted_change_counters.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/migrations/0008_alter_forwardnqemap_netbox_model.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/migrations/0009_alter_forwardnqemap_netbox_model.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/migrations/0010_forwardvalidationrun_override_applied_and_more.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/migrations/0011_forwardingestion_change_request_id.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/migrations/0012_forwardnqemap_query_reference.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/migrations/0013_execution_run_step.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/migrations/0014_execution_step_fetch_scope.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/migrations/0015_execution_step_apply_engine.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/migrations/0016_execution_step_query_metrics.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/migrations/0017_execution_step_row_counters.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/migrations/0018_execution_run_reconciliation_events.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/migrations/0019_forwardexecutionstep_query_parameters.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/migrations/0020_execution_step_operation.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/migrations/0021_add_fhrpgroup_nqe_map_choice.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/migrations/0022_alter_forwardnqemap_netbox_model.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/migrations/0023_split_ip_address_maps.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/migrations/0024_forwarddeviceanalysis.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/migrations/0025_device_analysis_netboxmodel.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/migrations/0026_forwarddeviceanalysis_collection_result.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/migrations/0027_alter_forwardexecutionrun_backend.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/migrations/0028_remove_forwardexecutionstep_run_and_more.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/migrations/__init__.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/models.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/navigation.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/queries/__init__.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/queries/forward_aci_apic_cimc_inventory.nqe +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/queries/forward_aci_apic_nodes.nqe +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/queries/forward_aci_app_profiles.nqe +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/queries/forward_aci_bridge_domains.nqe +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/queries/forward_aci_command_inventory.nqe +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/queries/forward_aci_contracts.nqe +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/queries/forward_aci_endpoint_groups.nqe +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/queries/forward_aci_fabrics.nqe +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/queries/forward_aci_filters.nqe +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/queries/forward_aci_l3outs.nqe +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/queries/forward_aci_nodes.nqe +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/queries/forward_aci_pods.nqe +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/queries/forward_aci_static_port_bindings.nqe +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/queries/forward_aci_tenants.nqe +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/queries/forward_aci_vrfs.nqe +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/queries/forward_bgp_address_families.nqe +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/queries/forward_bgp_peer_address_families.nqe +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/queries/forward_bgp_peers.nqe +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/queries/forward_device_analysis.nqe +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/queries/forward_device_feature_tags.nqe +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/queries/forward_device_feature_tags_with_rules.nqe +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/queries/forward_device_models.nqe +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/queries/forward_device_models_with_netbox_aliases.nqe +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/queries/forward_device_types.nqe +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/queries/forward_device_vendors.nqe +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/queries/forward_devices.nqe +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/queries/forward_devices_with_netbox_aliases.nqe +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/queries/forward_hsrp_groups.nqe +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/queries/forward_inferred_interface_cables.nqe +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/queries/forward_interfaces.nqe +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/queries/forward_inventory_items.nqe +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/queries/forward_ip_addresses_ipv4.nqe +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/queries/forward_ip_addresses_ipv6.nqe +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/queries/forward_ip_addresses_unassignable_diagnostics.nqe +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/queries/forward_locations.nqe +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/queries/forward_mac_addresses.nqe +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/queries/forward_modules.nqe +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/queries/forward_ospf_areas.nqe +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/queries/forward_ospf_instances.nqe +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/queries/forward_ospf_interfaces.nqe +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/queries/forward_peering_sessions.nqe +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/queries/forward_platforms.nqe +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/queries/forward_prefixes_ipv4.nqe +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/queries/forward_prefixes_ipv6.nqe +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/queries/forward_routing_import_diagnostics.nqe +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/queries/forward_virtual_chassis.nqe +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/queries/forward_vlans.nqe +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/queries/forward_vrfs.nqe +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/queries/netbox_utilities.nqe +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/signals.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/tables.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/template_content.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/templates/forward_netbox/forwarddriftpolicy.html +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/templates/forward_netbox/forwardingestion.html +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/templates/forward_netbox/forwardnqemap.html +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/templates/forward_netbox/forwardsource.html +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/templates/forward_netbox/forwardsync.html +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/templates/forward_netbox/forwardsync_dependency_preview.html +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/templates/forward_netbox/forwardsync_drift_report.html +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/templates/forward_netbox/forwardsync_health.html +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/templates/forward_netbox/forwardsync_module_readiness.html +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/templates/forward_netbox/forwardsync_scope_reconciliation.html +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/templates/forward_netbox/forwardvalidationrun.html +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/templates/forward_netbox/inc/device_analysis_panel.html +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/templates/forward_netbox/inc/diff.html +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/templates/forward_netbox/inc/execution_insights.html +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/templates/forward_netbox/inc/logs_pending.html +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/templates/forward_netbox/inc/merge_form.html +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/templates/forward_netbox/inc/validation_force_allow_form.html +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/templates/forward_netbox/partials/change_explainability.html +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/templates/forward_netbox/partials/ingestion_all.html +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/templates/forward_netbox/partials/ingestion_merge_button.html +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/templates/forward_netbox/partials/ingestion_progress.html +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/templates/forward_netbox/partials/ingestion_statistics.html +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/templates/forward_netbox/partials/ingestion_status.html +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/templates/forward_netbox/partials/job_logs.html +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/templates/forward_netbox/partials/object_tabs.html +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/templates/forward_netbox/partials/stage_switcher_buttons.html +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/templates/forward_netbox/partials/validation_force_allow_button.html +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/templatetags/__init__.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/templatetags/forward_netbox_helpers.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/tests/__init__.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/tests/fixtures/aci_command_inventory_expected.json +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/tests/fixtures/aci_discovery_expected.json +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/tests/scenarios.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/tests/test_api_usage.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/tests/test_api_views.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/tests/test_apic_cimc_readiness_audit_command.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/tests/test_apply_engine.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/tests/test_branching.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/tests/test_bulk_adapter_parity.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/tests/test_bulk_merge.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/tests/test_bulk_merge_scale.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/tests/test_device_scope_reconciliation_audit_command.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/tests/test_device_scope_tagging.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/tests/test_forms.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/tests/test_forward_api.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/tests/test_health.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/tests/test_ingestion_merge.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/tests/test_interface_naming.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/tests/test_ipaddress_dup_global.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/tests/test_issue_rendering.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/tests/test_job_compat.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/tests/test_job_liveness.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/tests/test_jobs.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/tests/test_log_export.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/tests/test_logging.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/tests/test_models.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/tests/test_module_readiness.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/tests/test_plugin_integrations.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/tests/test_primary_ip.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/tests/test_primary_ip_integration.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/tests/test_query_binding.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/tests/test_query_diff_coverage_audit_command.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/tests/test_query_registry.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/tests/test_release_readiness_audit.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/tests/test_runtime_dependency_check.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/tests/test_scope_matched_tags.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/tests/test_scope_module_ui.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/tests/test_sensitive_content.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/tests/test_stability_hardening.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/tests/test_sync_aci.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/tests/test_sync_facade.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/tests/test_sync_orchestration.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/tests/test_sync_runner_contracts.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/tests/test_sync_state.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/tests/test_synthetic_scenarios.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/tests/test_validation_org_query_audit_command.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/urls.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/utilities/__init__.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/utilities/api_usage.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/utilities/apply_engine.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/utilities/apply_engine_bulk.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/utilities/apply_engine_decision.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/utilities/branch_budget.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/utilities/branching.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/utilities/bulk_merge.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/utilities/change_explainability.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/utilities/density_learning.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/utilities/device_analysis.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/utilities/direct_changes.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/utilities/drift_report.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/utilities/execution_ledger.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/utilities/execution_telemetry.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/utilities/fetch_artifacts.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/utilities/forward_api.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/utilities/forward_api_impl.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/utilities/health.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/utilities/health_apply_fetch.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/utilities/health_checks.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/utilities/health_summary_blocks.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/utilities/ingestion_issues.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/utilities/ingestion_merge.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/utilities/ingestion_presentation.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/utilities/interface_naming.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/utilities/job_compat.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/utilities/job_liveness.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/utilities/json_safe.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/utilities/logging.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/utilities/merge.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/utilities/model_contracts.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/utilities/model_validation.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/utilities/module_readiness.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/utilities/multi_branch_lifecycle.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/utilities/plugin_integrations/__init__.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/utilities/plugin_integrations/registry.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/utilities/primary_ip.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/utilities/query_binding.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/utilities/query_binding_resolution.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/utilities/query_diagnostics.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/utilities/query_fetch.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/utilities/query_fetch_execution.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/utilities/query_registry.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/utilities/runtime_guidance.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/utilities/scope_reconciliation.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/utilities/sensitive_content.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/utilities/single_branch_executor.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/utilities/snapshot_freshness.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/utilities/support_bundle_archive.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/utilities/sync_aci.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/utilities/sync_cable.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/utilities/sync_contracts.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/utilities/sync_core_models.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/utilities/sync_device.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/utilities/sync_events.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/utilities/sync_execution.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/utilities/sync_facade.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/utilities/sync_interface.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/utilities/sync_inventory_module.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/utilities/sync_ipam.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/utilities/sync_orchestration.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/utilities/sync_primitives.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/utilities/sync_routing.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/utilities/sync_routing_impl.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/utilities/sync_runner_adapters.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/utilities/sync_runner_contracts.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/utilities/sync_state.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/utilities/validation.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/utilities/validation_org_query.py +0 -0
- {forward_netbox-2.0.2 → forward_netbox-2.0.3}/forward_netbox/views.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: forward-netbox
|
|
3
|
-
Version: 2.0.
|
|
3
|
+
Version: 2.0.3
|
|
4
4
|
Summary: NetBox plugin to sync Forward data into NetBox via built-in NQE queries
|
|
5
5
|
License: MIT
|
|
6
6
|
License-File: LICENSE
|
|
@@ -31,7 +31,8 @@ Forward 26.6 is the baseline for async NQE.
|
|
|
31
31
|
|
|
32
32
|
| Plugin Release | NetBox Version | Status |
|
|
33
33
|
| --- | --- | --- |
|
|
34
|
-
| `v2.0.
|
|
34
|
+
| `v2.0.3` | `4.6.3` required; needs netbox-branching `1.1.0+` | Current release; Patch: (1) module-sync readiness warnings no longer flood the log — the per-row `module bay does not exist; run forward_module_readiness` skip is capped to a few examples plus a suppressed-count summary (was up to 20 near-identical lines per sync); (2) fixes the release `CI` gate (`CHANGELOG matches README`) that had been red since v1.7.2 — the generator no longer depends on git tag-date timing; (3) removes dead executor code (`ForwardFastBootstrapExecutor.run`) and refreshes stale internal docs. No engine/schema changes; drop-in from `2.0.2` |
|
|
35
|
+
| `v2.0.2` | `4.6.3` required; needs netbox-branching `1.1.0+` | Superseded by `v2.0.3`; Patch: apply_device_scope_tags now works with multiple include tags in `any` match mode — each device is tagged with exactly the include tag(s) it carries (resolved per-device at fetch time), instead of skipping. Also silences the spurious `Skipping untagged VLAN 1` warning (VID 1 is NetBox's implicit access default and is intentionally not imported). No engine/schema changes; drop-in from `2.0.1`, no org republish |
|
|
35
36
|
| `v2.0.1` | `4.6.3` required; needs netbox-branching `1.1.0+` | Superseded by `v2.0.2`; Patch: fixes two 2.0.0 regressions an operator hits immediately — a false `netbox_branching is not installed; syncs will fail` startup warning (the dependency check used the wrong distribution name), and a 500 on the Sync list page (`KeyError: 'available'` from a removed execution-ledger summary). No engine or data changes; drop-in upgrade from `2.0.0` |
|
|
36
37
|
| `v2.0.0` | `4.6.3` required; needs netbox-branching `1.1.0+` | Superseded by `v2.0.1`; Breaking 2.0 — single-branch is the only execution path. Removed the per-shard branching/fast-bootstrap/resumable executor, 10k-change budget sharding, and the execution-ledger run-history; dropped the backend/max-changes/scheduler-overlap selectors |
|
|
37
38
|
| `v1.7.2` | `4.6.3` required (4.5.x dropped); needs netbox-branching `1.1.0+` | Superseded by `v2.0.0`; Collection-gap diagnostics: per-reason backfill breakdown + staleness, growth/trend escalation, per-device collection result, ACI delete safety valve, opt-in auto-tag |
|
|
@@ -8,7 +8,8 @@ Forward 26.6 is the baseline for async NQE.
|
|
|
8
8
|
|
|
9
9
|
| Plugin Release | NetBox Version | Status |
|
|
10
10
|
| --- | --- | --- |
|
|
11
|
-
| `v2.0.
|
|
11
|
+
| `v2.0.3` | `4.6.3` required; needs netbox-branching `1.1.0+` | Current release; Patch: (1) module-sync readiness warnings no longer flood the log — the per-row `module bay does not exist; run forward_module_readiness` skip is capped to a few examples plus a suppressed-count summary (was up to 20 near-identical lines per sync); (2) fixes the release `CI` gate (`CHANGELOG matches README`) that had been red since v1.7.2 — the generator no longer depends on git tag-date timing; (3) removes dead executor code (`ForwardFastBootstrapExecutor.run`) and refreshes stale internal docs. No engine/schema changes; drop-in from `2.0.2` |
|
|
12
|
+
| `v2.0.2` | `4.6.3` required; needs netbox-branching `1.1.0+` | Superseded by `v2.0.3`; Patch: apply_device_scope_tags now works with multiple include tags in `any` match mode — each device is tagged with exactly the include tag(s) it carries (resolved per-device at fetch time), instead of skipping. Also silences the spurious `Skipping untagged VLAN 1` warning (VID 1 is NetBox's implicit access default and is intentionally not imported). No engine/schema changes; drop-in from `2.0.1`, no org republish |
|
|
12
13
|
| `v2.0.1` | `4.6.3` required; needs netbox-branching `1.1.0+` | Superseded by `v2.0.2`; Patch: fixes two 2.0.0 regressions an operator hits immediately — a false `netbox_branching is not installed; syncs will fail` startup warning (the dependency check used the wrong distribution name), and a 500 on the Sync list page (`KeyError: 'available'` from a removed execution-ledger summary). No engine or data changes; drop-in upgrade from `2.0.0` |
|
|
13
14
|
| `v2.0.0` | `4.6.3` required; needs netbox-branching `1.1.0+` | Superseded by `v2.0.1`; Breaking 2.0 — single-branch is the only execution path. Removed the per-shard branching/fast-bootstrap/resumable executor, 10k-change budget sharding, and the execution-ledger run-history; dropped the backend/max-changes/scheduler-overlap selectors |
|
|
14
15
|
| `v1.7.2` | `4.6.3` required (4.5.x dropped); needs netbox-branching `1.1.0+` | Superseded by `v2.0.0`; Collection-gap diagnostics: per-reason backfill breakdown + staleness, growth/trend escalation, per-device collection result, ACI delete safety valve, opt-in auto-tag |
|
|
@@ -8,7 +8,7 @@ class NetboxForwardConfig(PluginConfig):
|
|
|
8
8
|
name = "forward_netbox"
|
|
9
9
|
verbose_name = "NetBox Forward Plugin"
|
|
10
10
|
description = "Sync Forward data into NetBox using built-in NQE queries."
|
|
11
|
-
version = "2.0.
|
|
11
|
+
version = "2.0.3"
|
|
12
12
|
base_url = "forward"
|
|
13
13
|
min_version = "4.6.3"
|
|
14
14
|
|
|
@@ -4,9 +4,7 @@ import tempfile
|
|
|
4
4
|
from unittest.mock import Mock
|
|
5
5
|
from unittest.mock import patch
|
|
6
6
|
|
|
7
|
-
from core.exceptions import SyncError
|
|
8
7
|
from core.models import ObjectChange
|
|
9
|
-
from core.models import ObjectType
|
|
10
8
|
from dcim.models import Cable
|
|
11
9
|
from dcim.models import Device
|
|
12
10
|
from dcim.models import DeviceRole
|
|
@@ -23,7 +21,6 @@ from dcim.models import VirtualChassis
|
|
|
23
21
|
from dcim.models.device_components import ModuleBay
|
|
24
22
|
from dcim.models.modules import ModuleType
|
|
25
23
|
from django.apps import apps
|
|
26
|
-
from django.contrib.auth import get_user_model
|
|
27
24
|
from django.contrib.contenttypes.models import ContentType
|
|
28
25
|
from django.core.exceptions import ValidationError
|
|
29
26
|
from django.db import connection
|
|
@@ -53,7 +50,6 @@ from forward_netbox.models import ForwardIngestion
|
|
|
53
50
|
from forward_netbox.models import ForwardIngestionIssue
|
|
54
51
|
from forward_netbox.models import ForwardSource
|
|
55
52
|
from forward_netbox.models import ForwardSync
|
|
56
|
-
from forward_netbox.models import ForwardValidationRun
|
|
57
53
|
from forward_netbox.signals import seed_builtin_nqe_maps
|
|
58
54
|
from forward_netbox.utilities.apply_engine import ADAPTER_MODELS_WITHOUT_BLOCKER
|
|
59
55
|
from forward_netbox.utilities.apply_engine import ADAPTER_REQUIRED_MODELS
|
|
@@ -79,17 +75,11 @@ from forward_netbox.utilities.branch_budget import shard_fetch_capability_for_mo
|
|
|
79
75
|
from forward_netbox.utilities.branch_budget import shard_fetch_contract
|
|
80
76
|
from forward_netbox.utilities.branch_budget import SHARD_FETCH_MODEL_CONTRACTS
|
|
81
77
|
from forward_netbox.utilities.density_learning import update_density_learning
|
|
82
|
-
from forward_netbox.utilities.direct_changes import object_changes_for_ingestion
|
|
83
78
|
from forward_netbox.utilities.execution_telemetry import build_plan_preview
|
|
84
|
-
from forward_netbox.utilities.fast_bootstrap_executor import (
|
|
85
|
-
ForwardFastBootstrapExecutor,
|
|
86
|
-
)
|
|
87
79
|
from forward_netbox.utilities.forward_api import LATEST_PROCESSED_SNAPSHOT
|
|
88
|
-
from forward_netbox.utilities.logging import SyncLogging
|
|
89
80
|
from forward_netbox.utilities.query_diagnostics import (
|
|
90
81
|
summarize_ipaddress_parent_prefix_rows,
|
|
91
82
|
)
|
|
92
|
-
from forward_netbox.utilities.query_fetch import ForwardModelResult
|
|
93
83
|
from forward_netbox.utilities.query_fetch import ForwardQueryContext
|
|
94
84
|
from forward_netbox.utilities.query_fetch import ForwardQueryFetcher
|
|
95
85
|
from forward_netbox.utilities.query_registry import QuerySpec
|
|
@@ -584,534 +574,6 @@ class ForwardBranchBudgetPlanTest(TestCase):
|
|
|
584
574
|
self.assertEqual(profile["dcim.device"]["sample_count"], 1)
|
|
585
575
|
|
|
586
576
|
|
|
587
|
-
class ForwardFastBootstrapExecutorTest(TestCase):
|
|
588
|
-
SNAPSHOT_ID = "snapshot-1"
|
|
589
|
-
|
|
590
|
-
def setUp(self):
|
|
591
|
-
self.source = ForwardSource.objects.create(
|
|
592
|
-
name="source-fast-bootstrap",
|
|
593
|
-
type="saas",
|
|
594
|
-
url="https://fwd.app",
|
|
595
|
-
parameters={
|
|
596
|
-
"username": "user@example.com",
|
|
597
|
-
"password": "secret",
|
|
598
|
-
"verify": True,
|
|
599
|
-
"timeout": 1200,
|
|
600
|
-
"network_id": "test-network",
|
|
601
|
-
},
|
|
602
|
-
)
|
|
603
|
-
self.sync = ForwardSync.objects.create(
|
|
604
|
-
name="sync-fast-bootstrap",
|
|
605
|
-
source=self.source,
|
|
606
|
-
parameters={
|
|
607
|
-
"snapshot_id": LATEST_PROCESSED_SNAPSHOT,
|
|
608
|
-
"dcim.site": True,
|
|
609
|
-
"enable_bulk_orm": False,
|
|
610
|
-
},
|
|
611
|
-
)
|
|
612
|
-
|
|
613
|
-
@patch("forward_netbox.utilities.fast_bootstrap_executor.ForwardSyncRunner")
|
|
614
|
-
@patch("forward_netbox.utilities.fast_bootstrap_executor.ForwardQueryFetcher")
|
|
615
|
-
def test_run_creates_branchless_baseline_ingestion(
|
|
616
|
-
self,
|
|
617
|
-
mock_fetcher_class,
|
|
618
|
-
mock_runner_class,
|
|
619
|
-
):
|
|
620
|
-
logger = SyncLogging()
|
|
621
|
-
context = ForwardQueryContext(
|
|
622
|
-
network_id="test-network",
|
|
623
|
-
snapshot_selector=LATEST_PROCESSED_SNAPSHOT,
|
|
624
|
-
snapshot_id=self.SNAPSHOT_ID,
|
|
625
|
-
snapshot_info={"state": "PROCESSED"},
|
|
626
|
-
snapshot_metrics={},
|
|
627
|
-
query_parameters={},
|
|
628
|
-
maps=[],
|
|
629
|
-
)
|
|
630
|
-
workload = BranchWorkload(
|
|
631
|
-
model_string="dcim.site",
|
|
632
|
-
label="sites",
|
|
633
|
-
upsert_rows=[{"name": "Site 1", "slug": "site-1"}],
|
|
634
|
-
delete_rows=[{"name": "Old Site", "slug": "old-site"}],
|
|
635
|
-
sync_mode="full",
|
|
636
|
-
coalesce_fields=[["slug"]],
|
|
637
|
-
query_name="Forward Sites",
|
|
638
|
-
execution_mode="query_id",
|
|
639
|
-
execution_value="FQ_sites",
|
|
640
|
-
)
|
|
641
|
-
model_result = ForwardModelResult(
|
|
642
|
-
model_string="dcim.site",
|
|
643
|
-
query_name="Forward Sites",
|
|
644
|
-
execution_mode="query_id",
|
|
645
|
-
execution_value="FQ_sites",
|
|
646
|
-
sync_mode="full",
|
|
647
|
-
row_count=1,
|
|
648
|
-
delete_count=1,
|
|
649
|
-
snapshot_id=self.SNAPSHOT_ID,
|
|
650
|
-
)
|
|
651
|
-
fetcher = mock_fetcher_class.return_value
|
|
652
|
-
fetcher.resolve_context.return_value = context
|
|
653
|
-
fetcher.fetch_workloads.return_value = [workload]
|
|
654
|
-
fetcher.model_results = [model_result]
|
|
655
|
-
runner = mock_runner_class.return_value
|
|
656
|
-
runner._model_coalesce_fields = {}
|
|
657
|
-
|
|
658
|
-
def apply_rows(model_string, rows):
|
|
659
|
-
for _row in rows:
|
|
660
|
-
logger.increment_statistics(model_string)
|
|
661
|
-
|
|
662
|
-
def delete_rows(model_string, rows):
|
|
663
|
-
for _row in rows:
|
|
664
|
-
logger.increment_statistics(model_string)
|
|
665
|
-
|
|
666
|
-
runner._apply_model_rows.side_effect = apply_rows
|
|
667
|
-
runner._delete_model_rows.side_effect = delete_rows
|
|
668
|
-
|
|
669
|
-
ingestions = ForwardFastBootstrapExecutor(
|
|
670
|
-
self.sync,
|
|
671
|
-
Mock(),
|
|
672
|
-
logger,
|
|
673
|
-
user=Mock(),
|
|
674
|
-
).run()
|
|
675
|
-
|
|
676
|
-
self.assertEqual(len(ingestions), 1)
|
|
677
|
-
ingestion = ingestions[0]
|
|
678
|
-
self.assertIsNone(ingestion.branch)
|
|
679
|
-
self.assertTrue(ingestion.baseline_ready)
|
|
680
|
-
self.assertEqual(ingestion.snapshot_id, self.SNAPSHOT_ID)
|
|
681
|
-
self.assertEqual(ingestion.sync_mode, "full")
|
|
682
|
-
self.assertEqual(ingestion.applied_change_count, 2)
|
|
683
|
-
self.assertEqual(ingestion.failed_change_count, 0)
|
|
684
|
-
self.assertEqual(ingestion.model_results, [model_result.as_dict()])
|
|
685
|
-
self.assertEqual(ingestion.model_results[0]["apply_engine"], "adapter")
|
|
686
|
-
self.assertEqual(
|
|
687
|
-
ForwardValidationRun.objects.get(sync=self.sync),
|
|
688
|
-
ingestion.validation_run,
|
|
689
|
-
)
|
|
690
|
-
self.assertIsNotNone(ingestion.change_request_id)
|
|
691
|
-
runner._apply_model_rows.assert_called_once_with(
|
|
692
|
-
"dcim.site",
|
|
693
|
-
workload.upsert_rows,
|
|
694
|
-
)
|
|
695
|
-
runner._delete_model_rows.assert_called_once_with(
|
|
696
|
-
"dcim.site",
|
|
697
|
-
workload.delete_rows,
|
|
698
|
-
)
|
|
699
|
-
|
|
700
|
-
@patch("forward_netbox.utilities.fast_bootstrap_executor.ForwardSyncRunner")
|
|
701
|
-
@patch("forward_netbox.utilities.fast_bootstrap_executor.ForwardQueryFetcher")
|
|
702
|
-
def test_run_skips_preflight_when_source_disables_it(
|
|
703
|
-
self,
|
|
704
|
-
mock_fetcher_class,
|
|
705
|
-
mock_runner_class,
|
|
706
|
-
):
|
|
707
|
-
self.source.parameters["query_preflight_enabled"] = False
|
|
708
|
-
self.source.save(update_fields=["parameters"])
|
|
709
|
-
|
|
710
|
-
logger = SyncLogging()
|
|
711
|
-
context = ForwardQueryContext(
|
|
712
|
-
network_id="test-network",
|
|
713
|
-
snapshot_selector=LATEST_PROCESSED_SNAPSHOT,
|
|
714
|
-
snapshot_id=self.SNAPSHOT_ID,
|
|
715
|
-
snapshot_info={"state": "PROCESSED"},
|
|
716
|
-
snapshot_metrics={},
|
|
717
|
-
query_parameters={},
|
|
718
|
-
maps=[],
|
|
719
|
-
)
|
|
720
|
-
workload = BranchWorkload(
|
|
721
|
-
model_string="dcim.site",
|
|
722
|
-
label="sites",
|
|
723
|
-
upsert_rows=[{"name": "Site 1", "slug": "site-1"}],
|
|
724
|
-
delete_rows=[],
|
|
725
|
-
sync_mode="full",
|
|
726
|
-
coalesce_fields=[["slug"]],
|
|
727
|
-
query_name="Forward Sites",
|
|
728
|
-
execution_mode="query_id",
|
|
729
|
-
execution_value="FQ_sites",
|
|
730
|
-
)
|
|
731
|
-
fetcher = mock_fetcher_class.return_value
|
|
732
|
-
fetcher.resolve_context.return_value = context
|
|
733
|
-
fetcher.fetch_workloads.return_value = [workload]
|
|
734
|
-
fetcher.model_results = []
|
|
735
|
-
runner = mock_runner_class.return_value
|
|
736
|
-
runner._model_coalesce_fields = {}
|
|
737
|
-
|
|
738
|
-
ForwardFastBootstrapExecutor(
|
|
739
|
-
self.sync,
|
|
740
|
-
Mock(),
|
|
741
|
-
logger,
|
|
742
|
-
user=Mock(),
|
|
743
|
-
).run()
|
|
744
|
-
|
|
745
|
-
self.assertFalse(fetcher.run_preflight.called)
|
|
746
|
-
fetcher.fetch_workloads.assert_called_once()
|
|
747
|
-
|
|
748
|
-
@patch("forward_netbox.utilities.fast_bootstrap_executor.ForwardSyncRunner")
|
|
749
|
-
@patch("forward_netbox.utilities.fast_bootstrap_executor.ForwardQueryFetcher")
|
|
750
|
-
def test_run_applies_fast_bootstrap_workloads_in_dependency_order(
|
|
751
|
-
self,
|
|
752
|
-
mock_fetcher_class,
|
|
753
|
-
mock_runner_class,
|
|
754
|
-
):
|
|
755
|
-
logger = SyncLogging()
|
|
756
|
-
context = ForwardQueryContext(
|
|
757
|
-
network_id="test-network",
|
|
758
|
-
snapshot_selector=LATEST_PROCESSED_SNAPSHOT,
|
|
759
|
-
snapshot_id=self.SNAPSHOT_ID,
|
|
760
|
-
snapshot_info={"state": "PROCESSED"},
|
|
761
|
-
snapshot_metrics={},
|
|
762
|
-
query_parameters={},
|
|
763
|
-
maps=[],
|
|
764
|
-
)
|
|
765
|
-
mac_workload = BranchWorkload(
|
|
766
|
-
model_string="dcim.macaddress",
|
|
767
|
-
label="mac addresses",
|
|
768
|
-
upsert_rows=[
|
|
769
|
-
{
|
|
770
|
-
"device": "device-1",
|
|
771
|
-
"interface": "Ethernet1",
|
|
772
|
-
"mac": "00:11:22:33:44:55",
|
|
773
|
-
"mac_address": "00:11:22:33:44:55",
|
|
774
|
-
}
|
|
775
|
-
],
|
|
776
|
-
sync_mode="full",
|
|
777
|
-
coalesce_fields=[["mac_address"]],
|
|
778
|
-
query_name="Forward MAC Addresses",
|
|
779
|
-
execution_mode="query_id",
|
|
780
|
-
execution_value="FQ_macs",
|
|
781
|
-
)
|
|
782
|
-
interface_workload = BranchWorkload(
|
|
783
|
-
model_string="dcim.interface",
|
|
784
|
-
label="interfaces",
|
|
785
|
-
upsert_rows=[
|
|
786
|
-
{
|
|
787
|
-
"device": "device-1",
|
|
788
|
-
"name": "Ethernet1",
|
|
789
|
-
"type": "other",
|
|
790
|
-
"enabled": True,
|
|
791
|
-
}
|
|
792
|
-
],
|
|
793
|
-
sync_mode="full",
|
|
794
|
-
coalesce_fields=[["device", "name"]],
|
|
795
|
-
query_name="Forward Interfaces",
|
|
796
|
-
execution_mode="query_id",
|
|
797
|
-
execution_value="FQ_interfaces",
|
|
798
|
-
)
|
|
799
|
-
fetcher = mock_fetcher_class.return_value
|
|
800
|
-
fetcher.resolve_context.return_value = context
|
|
801
|
-
fetcher.fetch_workloads.return_value = [mac_workload, interface_workload]
|
|
802
|
-
fetcher.model_results = [
|
|
803
|
-
ForwardModelResult(
|
|
804
|
-
model_string="dcim.macaddress",
|
|
805
|
-
query_name="Forward MAC Addresses",
|
|
806
|
-
execution_mode="query_id",
|
|
807
|
-
execution_value="FQ_macs",
|
|
808
|
-
sync_mode="full",
|
|
809
|
-
row_count=1,
|
|
810
|
-
snapshot_id=self.SNAPSHOT_ID,
|
|
811
|
-
),
|
|
812
|
-
ForwardModelResult(
|
|
813
|
-
model_string="dcim.interface",
|
|
814
|
-
query_name="Forward Interfaces",
|
|
815
|
-
execution_mode="query_id",
|
|
816
|
-
execution_value="FQ_interfaces",
|
|
817
|
-
sync_mode="full",
|
|
818
|
-
row_count=1,
|
|
819
|
-
snapshot_id=self.SNAPSHOT_ID,
|
|
820
|
-
),
|
|
821
|
-
]
|
|
822
|
-
runner = mock_runner_class.return_value
|
|
823
|
-
runner._model_coalesce_fields = {}
|
|
824
|
-
|
|
825
|
-
ForwardFastBootstrapExecutor(
|
|
826
|
-
self.sync,
|
|
827
|
-
Mock(),
|
|
828
|
-
logger,
|
|
829
|
-
user=Mock(),
|
|
830
|
-
).run()
|
|
831
|
-
|
|
832
|
-
self.assertEqual(
|
|
833
|
-
[call.args[0] for call in runner._apply_model_rows.call_args_list],
|
|
834
|
-
["dcim.interface", "dcim.macaddress"],
|
|
835
|
-
)
|
|
836
|
-
|
|
837
|
-
@patch("forward_netbox.utilities.fast_bootstrap_executor.ForwardQueryFetcher")
|
|
838
|
-
def test_run_records_direct_netbox_changes_for_fast_bootstrap(
|
|
839
|
-
self,
|
|
840
|
-
mock_fetcher_class,
|
|
841
|
-
):
|
|
842
|
-
logger = SyncLogging()
|
|
843
|
-
context = ForwardQueryContext(
|
|
844
|
-
network_id="test-network",
|
|
845
|
-
snapshot_selector=LATEST_PROCESSED_SNAPSHOT,
|
|
846
|
-
snapshot_id=self.SNAPSHOT_ID,
|
|
847
|
-
snapshot_info={"state": "PROCESSED"},
|
|
848
|
-
snapshot_metrics={},
|
|
849
|
-
query_parameters={},
|
|
850
|
-
maps=[],
|
|
851
|
-
)
|
|
852
|
-
workload = BranchWorkload(
|
|
853
|
-
model_string="dcim.site",
|
|
854
|
-
label="sites",
|
|
855
|
-
upsert_rows=[{"name": "Site 2", "slug": "site-2"}],
|
|
856
|
-
delete_rows=[],
|
|
857
|
-
sync_mode="full",
|
|
858
|
-
coalesce_fields=[["slug"]],
|
|
859
|
-
query_name="Forward Sites",
|
|
860
|
-
execution_mode="query_id",
|
|
861
|
-
execution_value="FQ_sites",
|
|
862
|
-
)
|
|
863
|
-
model_result = ForwardModelResult(
|
|
864
|
-
model_string="dcim.site",
|
|
865
|
-
query_name="Forward Sites",
|
|
866
|
-
execution_mode="query_id",
|
|
867
|
-
execution_value="FQ_sites",
|
|
868
|
-
sync_mode="full",
|
|
869
|
-
row_count=1,
|
|
870
|
-
delete_count=0,
|
|
871
|
-
snapshot_id=self.SNAPSHOT_ID,
|
|
872
|
-
)
|
|
873
|
-
fetcher = mock_fetcher_class.return_value
|
|
874
|
-
fetcher.resolve_context.return_value = context
|
|
875
|
-
fetcher.fetch_workloads.return_value = [workload]
|
|
876
|
-
fetcher.model_results = [model_result]
|
|
877
|
-
user = get_user_model().objects.create_user(username="fast-bootstrap-user")
|
|
878
|
-
|
|
879
|
-
ingestions = ForwardFastBootstrapExecutor(
|
|
880
|
-
self.sync,
|
|
881
|
-
Mock(),
|
|
882
|
-
logger,
|
|
883
|
-
user=user,
|
|
884
|
-
).run()
|
|
885
|
-
|
|
886
|
-
ingestion = ingestions[0]
|
|
887
|
-
ingestion.refresh_from_db()
|
|
888
|
-
site_type = ObjectType.objects.get_for_model(Site)
|
|
889
|
-
self.assertTrue(Site.objects.filter(slug="site-2").exists())
|
|
890
|
-
self.assertTrue(
|
|
891
|
-
ObjectChange.objects.filter(
|
|
892
|
-
request_id=ingestion.change_request_id,
|
|
893
|
-
changed_object_type=site_type,
|
|
894
|
-
action="create",
|
|
895
|
-
).exists()
|
|
896
|
-
)
|
|
897
|
-
self.assertEqual(ingestion.applied_change_count, 1)
|
|
898
|
-
self.assertEqual(ingestion.created_change_count, 1)
|
|
899
|
-
self.assertEqual(ingestion.updated_change_count, 0)
|
|
900
|
-
self.assertEqual(ingestion.deleted_change_count, 0)
|
|
901
|
-
self.assertEqual(object_changes_for_ingestion(ingestion).count(), 1)
|
|
902
|
-
|
|
903
|
-
@patch("forward_netbox.utilities.fast_bootstrap_executor.ForwardSyncRunner")
|
|
904
|
-
@patch("forward_netbox.utilities.fast_bootstrap_executor.ForwardQueryFetcher")
|
|
905
|
-
def test_run_does_not_mark_baseline_ready_when_issues_exist(
|
|
906
|
-
self,
|
|
907
|
-
mock_fetcher_class,
|
|
908
|
-
mock_runner_class,
|
|
909
|
-
):
|
|
910
|
-
logger = SyncLogging()
|
|
911
|
-
context = ForwardQueryContext(
|
|
912
|
-
network_id="test-network",
|
|
913
|
-
snapshot_selector=LATEST_PROCESSED_SNAPSHOT,
|
|
914
|
-
snapshot_id=self.SNAPSHOT_ID,
|
|
915
|
-
snapshot_info={"state": "PROCESSED"},
|
|
916
|
-
snapshot_metrics={},
|
|
917
|
-
query_parameters={},
|
|
918
|
-
maps=[],
|
|
919
|
-
)
|
|
920
|
-
workload = BranchWorkload(
|
|
921
|
-
model_string="dcim.site",
|
|
922
|
-
label="sites",
|
|
923
|
-
upsert_rows=[{"name": "Site 1", "slug": "site-1"}],
|
|
924
|
-
delete_rows=[],
|
|
925
|
-
sync_mode="full",
|
|
926
|
-
coalesce_fields=[["slug"]],
|
|
927
|
-
query_name="Forward Sites",
|
|
928
|
-
execution_mode="query_id",
|
|
929
|
-
execution_value="FQ_sites",
|
|
930
|
-
)
|
|
931
|
-
model_result = ForwardModelResult(
|
|
932
|
-
model_string="dcim.site",
|
|
933
|
-
query_name="Forward Sites",
|
|
934
|
-
execution_mode="query_id",
|
|
935
|
-
execution_value="FQ_sites",
|
|
936
|
-
sync_mode="full",
|
|
937
|
-
row_count=1,
|
|
938
|
-
delete_count=0,
|
|
939
|
-
snapshot_id=self.SNAPSHOT_ID,
|
|
940
|
-
)
|
|
941
|
-
fetcher = mock_fetcher_class.return_value
|
|
942
|
-
fetcher.resolve_context.return_value = context
|
|
943
|
-
fetcher.fetch_workloads.return_value = [workload]
|
|
944
|
-
fetcher.model_results = [model_result]
|
|
945
|
-
runner = mock_runner_class.return_value
|
|
946
|
-
runner._model_coalesce_fields = {}
|
|
947
|
-
|
|
948
|
-
def apply_rows(model_string, _rows):
|
|
949
|
-
ingestion = ForwardIngestion.objects.get(sync=self.sync)
|
|
950
|
-
ingestion.issues.create(
|
|
951
|
-
model=model_string,
|
|
952
|
-
message="Unable to apply site row.",
|
|
953
|
-
exception="validation failed",
|
|
954
|
-
)
|
|
955
|
-
logger.increment_statistics(model_string, outcome="failed")
|
|
956
|
-
|
|
957
|
-
runner._apply_model_rows.side_effect = apply_rows
|
|
958
|
-
|
|
959
|
-
with self.assertRaisesRegex(
|
|
960
|
-
SyncError,
|
|
961
|
-
"Forward fast bootstrap completed with issues",
|
|
962
|
-
):
|
|
963
|
-
ForwardFastBootstrapExecutor(
|
|
964
|
-
self.sync,
|
|
965
|
-
Mock(),
|
|
966
|
-
logger,
|
|
967
|
-
user=Mock(),
|
|
968
|
-
).run()
|
|
969
|
-
|
|
970
|
-
ingestion = ForwardIngestion.objects.get(sync=self.sync)
|
|
971
|
-
self.assertFalse(ingestion.baseline_ready)
|
|
972
|
-
self.assertEqual(ingestion.issues.count(), 1)
|
|
973
|
-
self.assertEqual(ingestion.applied_change_count, 0)
|
|
974
|
-
self.assertEqual(ingestion.failed_change_count, 1)
|
|
975
|
-
|
|
976
|
-
@patch("forward_netbox.utilities.fast_bootstrap_executor.ForwardSyncRunner")
|
|
977
|
-
@patch("forward_netbox.utilities.fast_bootstrap_executor.ForwardQueryFetcher")
|
|
978
|
-
def test_run_marks_baseline_ready_when_only_optional_model_issues_exist(
|
|
979
|
-
self,
|
|
980
|
-
mock_fetcher_class,
|
|
981
|
-
mock_runner_class,
|
|
982
|
-
):
|
|
983
|
-
logger = SyncLogging()
|
|
984
|
-
context = ForwardQueryContext(
|
|
985
|
-
network_id="test-network",
|
|
986
|
-
snapshot_selector=LATEST_PROCESSED_SNAPSHOT,
|
|
987
|
-
snapshot_id=self.SNAPSHOT_ID,
|
|
988
|
-
snapshot_info={"state": "PROCESSED"},
|
|
989
|
-
snapshot_metrics={},
|
|
990
|
-
query_parameters={},
|
|
991
|
-
maps=[],
|
|
992
|
-
)
|
|
993
|
-
workload = BranchWorkload(
|
|
994
|
-
model_string="netbox_routing.bgppeer",
|
|
995
|
-
label="bgp peers",
|
|
996
|
-
upsert_rows=[{"device": "device-1"}],
|
|
997
|
-
delete_rows=[],
|
|
998
|
-
sync_mode="full",
|
|
999
|
-
coalesce_fields=[["device"]],
|
|
1000
|
-
query_name="Forward BGP Peers",
|
|
1001
|
-
execution_mode="query_id",
|
|
1002
|
-
execution_value="FQ_bgp",
|
|
1003
|
-
)
|
|
1004
|
-
model_result = ForwardModelResult(
|
|
1005
|
-
model_string="netbox_routing.bgppeer",
|
|
1006
|
-
query_name="Forward BGP Peers",
|
|
1007
|
-
execution_mode="query_id",
|
|
1008
|
-
execution_value="FQ_bgp",
|
|
1009
|
-
sync_mode="full",
|
|
1010
|
-
row_count=1,
|
|
1011
|
-
delete_count=0,
|
|
1012
|
-
snapshot_id=self.SNAPSHOT_ID,
|
|
1013
|
-
)
|
|
1014
|
-
fetcher = mock_fetcher_class.return_value
|
|
1015
|
-
fetcher.resolve_context.return_value = context
|
|
1016
|
-
fetcher.fetch_workloads.return_value = [workload]
|
|
1017
|
-
fetcher.model_results = [model_result]
|
|
1018
|
-
runner = mock_runner_class.return_value
|
|
1019
|
-
runner._model_coalesce_fields = {}
|
|
1020
|
-
|
|
1021
|
-
def apply_rows(model_string, _rows):
|
|
1022
|
-
ingestion = ForwardIngestion.objects.get(sync=self.sync)
|
|
1023
|
-
ingestion.issues.create(
|
|
1024
|
-
model=model_string,
|
|
1025
|
-
message="Unable to apply optional BGP row.",
|
|
1026
|
-
exception="validation failed",
|
|
1027
|
-
)
|
|
1028
|
-
logger.increment_statistics(model_string, outcome="failed")
|
|
1029
|
-
|
|
1030
|
-
runner._apply_model_rows.side_effect = apply_rows
|
|
1031
|
-
|
|
1032
|
-
ingestions = ForwardFastBootstrapExecutor(
|
|
1033
|
-
self.sync,
|
|
1034
|
-
Mock(),
|
|
1035
|
-
logger,
|
|
1036
|
-
user=Mock(),
|
|
1037
|
-
).run()
|
|
1038
|
-
|
|
1039
|
-
ingestion = ingestions[0]
|
|
1040
|
-
ingestion.refresh_from_db()
|
|
1041
|
-
self.assertTrue(ingestion.baseline_ready)
|
|
1042
|
-
self.assertEqual(ingestion.issues.count(), 1)
|
|
1043
|
-
self.assertEqual(ingestion.failed_change_count, 1)
|
|
1044
|
-
|
|
1045
|
-
@patch("forward_netbox.utilities.fast_bootstrap_executor.ForwardSyncRunner")
|
|
1046
|
-
@patch("forward_netbox.utilities.fast_bootstrap_executor.ForwardQueryFetcher")
|
|
1047
|
-
def test_run_marks_baseline_ready_when_only_dependency_skip_issues_exist(
|
|
1048
|
-
self,
|
|
1049
|
-
mock_fetcher_class,
|
|
1050
|
-
mock_runner_class,
|
|
1051
|
-
):
|
|
1052
|
-
logger = SyncLogging()
|
|
1053
|
-
context = ForwardQueryContext(
|
|
1054
|
-
network_id="test-network",
|
|
1055
|
-
snapshot_selector=LATEST_PROCESSED_SNAPSHOT,
|
|
1056
|
-
snapshot_id=self.SNAPSHOT_ID,
|
|
1057
|
-
snapshot_info={"state": "PROCESSED"},
|
|
1058
|
-
snapshot_metrics={},
|
|
1059
|
-
query_parameters={},
|
|
1060
|
-
maps=[],
|
|
1061
|
-
)
|
|
1062
|
-
workload = BranchWorkload(
|
|
1063
|
-
model_string="ipam.ipaddress",
|
|
1064
|
-
label="ip addresses",
|
|
1065
|
-
upsert_rows=[],
|
|
1066
|
-
delete_rows=[{"address": "192.0.2.1/32"}],
|
|
1067
|
-
sync_mode="full",
|
|
1068
|
-
coalesce_fields=[["address"]],
|
|
1069
|
-
query_name="Forward IP Addresses",
|
|
1070
|
-
execution_mode="query_id",
|
|
1071
|
-
execution_value="FQ_ip",
|
|
1072
|
-
)
|
|
1073
|
-
model_result = ForwardModelResult(
|
|
1074
|
-
model_string="ipam.ipaddress",
|
|
1075
|
-
query_name="Forward IP Addresses",
|
|
1076
|
-
execution_mode="query_id",
|
|
1077
|
-
execution_value="FQ_ip",
|
|
1078
|
-
sync_mode="full",
|
|
1079
|
-
row_count=0,
|
|
1080
|
-
delete_count=1,
|
|
1081
|
-
snapshot_id=self.SNAPSHOT_ID,
|
|
1082
|
-
)
|
|
1083
|
-
fetcher = mock_fetcher_class.return_value
|
|
1084
|
-
fetcher.resolve_context.return_value = context
|
|
1085
|
-
fetcher.fetch_workloads.return_value = [workload]
|
|
1086
|
-
fetcher.model_results = [model_result]
|
|
1087
|
-
runner = mock_runner_class.return_value
|
|
1088
|
-
runner._model_coalesce_fields = {}
|
|
1089
|
-
|
|
1090
|
-
def delete_rows(model_string, _rows):
|
|
1091
|
-
ingestion = ForwardIngestion.objects.get(sync=self.sync)
|
|
1092
|
-
ingestion.issues.create(
|
|
1093
|
-
model=model_string,
|
|
1094
|
-
message="Skipping delete for `ipam.ipaddress` due to protected dependencies.",
|
|
1095
|
-
exception="ForwardDependencySkipError",
|
|
1096
|
-
)
|
|
1097
|
-
logger.increment_statistics(model_string, outcome="skipped")
|
|
1098
|
-
|
|
1099
|
-
runner._delete_model_rows.side_effect = delete_rows
|
|
1100
|
-
|
|
1101
|
-
ingestions = ForwardFastBootstrapExecutor(
|
|
1102
|
-
self.sync,
|
|
1103
|
-
Mock(),
|
|
1104
|
-
logger,
|
|
1105
|
-
user=Mock(),
|
|
1106
|
-
).run()
|
|
1107
|
-
|
|
1108
|
-
ingestion = ingestions[0]
|
|
1109
|
-
ingestion.refresh_from_db()
|
|
1110
|
-
self.assertTrue(ingestion.baseline_ready)
|
|
1111
|
-
self.assertEqual(ingestion.issues.count(), 1)
|
|
1112
|
-
self.assertEqual(ingestion.failed_change_count, 0)
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
577
|
class ForwardSyncRunnerTest(TestCase):
|
|
1116
578
|
def setUp(self):
|
|
1117
579
|
self.source = ForwardSource.objects.create(
|
|
@@ -2492,6 +1954,38 @@ class ForwardSyncRunnerTest(TestCase):
|
|
|
2492
1954
|
"`missing-interface` after the first 20.",
|
|
2493
1955
|
)
|
|
2494
1956
|
|
|
1957
|
+
def test_apply_dcim_module_caps_missing_module_bay_warnings(self):
|
|
1958
|
+
# A systemic readiness gap (module sync enabled before the device-type
|
|
1959
|
+
# module bays exist) skips every module row, so the per-row detail is
|
|
1960
|
+
# capped low (SKIP_WARNING_DETAIL_LIMITS) and the rest are summarized.
|
|
1961
|
+
self._create_device("device-module-readiness")
|
|
1962
|
+
logger = Mock()
|
|
1963
|
+
runner = ForwardSyncRunner(
|
|
1964
|
+
sync=self.sync, ingestion=None, client=None, logger_=logger
|
|
1965
|
+
)
|
|
1966
|
+
limit = ForwardSyncRunner.SKIP_WARNING_DETAIL_LIMITS["missing-module-bay"]
|
|
1967
|
+
rows = [
|
|
1968
|
+
{"device": "device-module-readiness", "module_bay": f"module {index}"}
|
|
1969
|
+
for index in range(limit + 2)
|
|
1970
|
+
]
|
|
1971
|
+
|
|
1972
|
+
runner._apply_model_rows("dcim.module", rows)
|
|
1973
|
+
|
|
1974
|
+
warning_messages = [call.args[0] for call in logger.log_warning.call_args_list]
|
|
1975
|
+
# `limit` per-row detail lines + one suppressed-count summary.
|
|
1976
|
+
self.assertEqual(len(warning_messages), limit + 1)
|
|
1977
|
+
self.assertTrue(
|
|
1978
|
+
all(
|
|
1979
|
+
"forward_module_readiness" in message
|
|
1980
|
+
for message in warning_messages[:limit]
|
|
1981
|
+
)
|
|
1982
|
+
)
|
|
1983
|
+
self.assertEqual(
|
|
1984
|
+
warning_messages[-1],
|
|
1985
|
+
f"Suppressed 2 additional dcim.module skip warnings for "
|
|
1986
|
+
f"`missing-module-bay` after the first {limit}.",
|
|
1987
|
+
)
|
|
1988
|
+
|
|
2495
1989
|
def test_dependency_lookup_cache_primes_only_exact_interface_pairs(self):
|
|
2496
1990
|
device_1 = self._create_device("device-pair-1")
|
|
2497
1991
|
device_2 = self._create_device("device-pair-2")
|