mirror of
https://github.com/dtzp555-max/aci-sim.git
synced 2026-07-19 09:46:33 +00:00
aci-sim is a stateful REST simulator of a 2-site Cisco ACI fabric (per-site APIC + ND/NDO management planes) — for testing ACI automation (Ansible cisco.aci / cisco.mso, aci-py, custom REST clients) and CI gates without real hardware. Highlights: APIC + NDO REST surface served from one in-memory MIT built from a declarative topology.yaml; port mode + sandbox (real per-device IPs on :443) run modes; LLDP/CDP neighbor visibility; NDO->APIC deploy mirror (multi-site templates materialize onto the target sites' APIC stores); real-APIC fvBD default attributes; file-backed state save/restore; an `aci-sim` CLI (validate/show/graph/run/new/init/lldp); and an 888-test suite. History squashed for the public release. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
90 lines
3.2 KiB
Python
90 lines
3.2 KiB
Python
"""Orchestrator — assemble a full per-site MITStore from the topology.
|
|
|
|
Every sub-builder is a pure function of (topology, site) that only ADDS MOs and
|
|
never reads another builder's output, so the order below is for readability only.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from aci_sim.build import (
|
|
access,
|
|
cabling,
|
|
endpoints,
|
|
fabric,
|
|
health_faults,
|
|
interfaces,
|
|
l3out,
|
|
mgmt,
|
|
overlay,
|
|
routing,
|
|
tenants,
|
|
underlay,
|
|
userprofile,
|
|
zoning,
|
|
)
|
|
from aci_sim.mit.store import MITStore
|
|
from aci_sim.topology.schema import Site, Topology
|
|
|
|
# fabric first (nodes), then wiring/underlay/overlay, then tenant config,
|
|
# then L3Out (needs border leaves), endpoints, and finally health/faults.
|
|
#
|
|
# Batch-1 note: `endpoints` now runs BEFORE `tenants` (moved from after
|
|
# `l3out`) so tenants.py's fvRsPathAtt (static binding) can read back the
|
|
# real fvCEp/fabricPathDn each EPG's endpoints already got from the store,
|
|
# instead of re-deriving port assignment logic independently (which risked
|
|
# silently drifting out of sync with endpoints.py). Every other builder
|
|
# remains a pure "only ADDS MOs, never reads another builder's output"
|
|
# function per the orchestrator's original contract — endpoints.py itself
|
|
# still only adds and doesn't read from tenants/access/l3out, so moving it
|
|
# earlier is safe (its only cross-module dependency, _HOST_PORTS, comes from
|
|
# `interfaces`, which still runs first).
|
|
#
|
|
# Batch-2 note: `zoning` runs AFTER both `tenants` (needs fvAEPg.pcTag/
|
|
# fvCtx.scope, and reuses tenants.py's pctag_for/scope_id_for helpers) and
|
|
# `endpoints` (needs fvCEp to know which leaves host each EPG's local
|
|
# endpoints) — same read-back pattern as tenants.py's fvRsPathAtt, so zoning
|
|
# is placed right after tenants in the list (endpoints already ran earlier).
|
|
# `overlay.build_vpn_routes` (bgpVpnRoute/bgpPath) has the same fvRsBd/fvCEp
|
|
# read-back dependency, so it also runs post-tenants/endpoints — as a SECOND
|
|
# call into the `overlay` module, alongside (not instead of) its early
|
|
# `overlay.build` call which only needs fabric/topology data and stays in
|
|
# its original early slot for BGP peer setup.
|
|
#
|
|
# OOB-gateway PR: `mgmt` builds the mgmt-tenant OOB scaffolding
|
|
# (fvTenant(mgmt)/mgmtMgmtP/mgmtOoB/mgmtRsOoBStNode) that carries
|
|
# site.oob_gateway on a real MO. It only needs topology data (site.all_nodes(),
|
|
# oob_ip(), site.controller_oob_ips()) — no read-back from another builder's
|
|
# store output — so, like every other builder here, it is placed for
|
|
# readability only; it is grouped right after `fabric` since both build
|
|
# node-identity/OOB data.
|
|
_BUILDERS = [
|
|
fabric,
|
|
mgmt,
|
|
cabling,
|
|
underlay,
|
|
overlay,
|
|
interfaces,
|
|
endpoints,
|
|
tenants,
|
|
zoning,
|
|
access,
|
|
l3out,
|
|
routing,
|
|
health_faults,
|
|
userprofile,
|
|
]
|
|
|
|
|
|
def build_site(topo: Topology, site: Site) -> MITStore:
|
|
"""Build and return a fully-populated MITStore for one site."""
|
|
store = MITStore()
|
|
for mod in _BUILDERS:
|
|
mod.build(topo, site, store)
|
|
overlay.build_vpn_routes(topo, site, store)
|
|
return store
|
|
|
|
|
|
def build_all(topo: Topology) -> dict[str, MITStore]:
|
|
"""Build every site → ``{site_name: MITStore}``."""
|
|
return {site.name: build_site(topo, site) for site in topo.sites}
|