"""In-memory state shared between STAGE 1 collection/loading and STAGE 3/4. Replaces the bash original's `declare -gA` global associative-array soup with one explicit, typed object. Populated either by audit.collect() (real OpenStack/Sprut queries) or audit.load_from_audit_json() (parsing a previously written audit file) -- both paths produce the same shape so STAGE 3/4 don't need to know which one ran. """ from __future__ import annotations from dataclasses import dataclass, field @dataclass class MigrationState: neutron_to_adv_router: dict[str, str] = field(default_factory=dict) subnet_id_to_subnet_address: dict[str, str] = field(default_factory=dict) # STEP 2: full Neutron router objects (id -> raw dict), so a router # whose advanced_router_id is blank in the CSV can be auto-created in # Sprut using this router's own name/description, without a second # per-item show call. neutron_router_by_id: dict[str, dict] = field(default_factory=dict) # STEP 1: optional availability_zone/flavor CSV columns (3rd/4th), # keyed by neutron_router_id, only present for rows whose # advanced_router_id was blank. router_creation_hints: dict[str, dict] = field(default_factory=dict) # STEP 3 (collect()) or --from-audit load: resolved name/description/ # availability_zone/flavor for routers still awaiting DC Router # creation. Populated either freshly (collect()) or from a previously # written audit.json's "pending_dc_router" block (--from-audit). pending_dc_router_by_neutron_id: dict[str, dict] = field(default_factory=dict) neutron_ike_policy_by_id: dict[str, dict] = field(default_factory=dict) neutron_ipsec_policy_by_id: dict[str, dict] = field(default_factory=dict) neutron_endpoint_group_by_id: dict[str, dict] = field(default_factory=dict) # STEP 8: filtered to in-scope (CSV) routers only. router_id_to_vpn_service_id: dict[str, str] = field(default_factory=dict) # STEP 8: reverse map, deliberately NOT filtered -- stays project-wide # because STEP 9 needs it to resolve every connection's owning router # before in-scope narrowing happens. Do not filter this one. vpn_service_id_to_router_id: dict[str, str] = field(default_factory=dict) neutron_vpn_service_by_id: dict[str, dict] = field(default_factory=dict) # STEP 9: router id -> list of ipsec site connection ids it owns. neutron_router_to_ipsec_ids: dict[str, list[str]] = field(default_factory=dict) neutron_connection_by_id: dict[str, dict] = field(default_factory=dict) in_scope_connection_ids: set[str] = field(default_factory=set) in_scope_ike_policy_ids: set[str] = field(default_factory=set) in_scope_ipsec_policy_ids: set[str] = field(default_factory=set) in_scope_endpoint_group_ids: set[str] = field(default_factory=set)