mirror of
https://github.com/dtzp555-max/aci-sim.git
synced 2026-07-23 14:05:11 +00:00
Initial public release — aci-sim v0.16.0
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>
This commit is contained in:
@@ -0,0 +1,94 @@
|
||||
"""build/cabling.py — fabricLink, lldpAdjEp, cdpAdjEp derived from the cabling graph.
|
||||
|
||||
fabricLink DN (verified against autoACI/backend/routers/topology.py lines 381-388):
|
||||
topology/pod-{pod}/lnk-{n1}-{s1}-{p1}-to-{n2}-{s2}-{p2}
|
||||
where "lnk-{n1}-{s1}-{p1}-to-...".split("-") = [n1, s1, p1, ...]
|
||||
→ source_port = f"eth{s1}/{p1}" (spc[1], spc[2])
|
||||
n1/n2 attributes carry the plain node IDs.
|
||||
|
||||
Port assignment (auto mode):
|
||||
Spines: uplinks eth1/1, eth1/2, ... (one per downlink, in order)
|
||||
Leaves/border-leaves: uplinks eth1/49, eth1/50, ... (one per spine, in order)
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
from aci_sim.build.fabric import oob_ip
|
||||
from aci_sim.build.neighbors import add_switch_adjacency
|
||||
from aci_sim.mit.mo import MO
|
||||
from aci_sim.mit.store import MITStore
|
||||
from aci_sim.topology.schema import Node, Site, Topology
|
||||
|
||||
|
||||
def cabling_links(site: Site) -> list[tuple[int, int, int, int, int, int]]:
|
||||
"""Return (n1_id, slot1, port1, n2_id, slot2, port2) for every fabric link.
|
||||
|
||||
Convention: n1=spine, n2=leaf/border-leaf.
|
||||
Spine port: eth1/{leaf_idx+1}
|
||||
Leaf uplink: eth1/{49+spine_idx}
|
||||
"""
|
||||
spines = site.spine_nodes()
|
||||
downlinks = site.leaf_nodes() + site.border_leaf_nodes()
|
||||
links: list[tuple[int, int, int, int, int, int]] = []
|
||||
for l_idx, leaf in enumerate(downlinks):
|
||||
for s_idx, spine in enumerate(spines):
|
||||
links.append((
|
||||
spine.id, 1, l_idx + 1, # spine eth1/(leaf_idx+1)
|
||||
leaf.id, 1, 49 + s_idx, # leaf eth1/(49+spine_idx)
|
||||
))
|
||||
return links
|
||||
|
||||
|
||||
def build(topo: Topology, site: Site, store: MITStore) -> None:
|
||||
"""Emit fabricLink + lldpAdjEp + cdpAdjEp derived from the cabling graph."""
|
||||
pod = site.pod
|
||||
|
||||
# Build a lookup: node_id -> Node (for name/loopback lookups)
|
||||
node_map: dict[int, Node] = {n.id: n for n in site.all_nodes()}
|
||||
|
||||
for n1, s1, p1, n2, s2, p2 in cabling_links(site):
|
||||
lnk_dn = (
|
||||
f"topology/pod-{pod}"
|
||||
f"/lnk-{n1}-{s1}-{p1}-to-{n2}-{s2}-{p2}"
|
||||
)
|
||||
store.add(MO(
|
||||
"fabricLink",
|
||||
dn=lnk_dn,
|
||||
n1=str(n1),
|
||||
n2=str(n2),
|
||||
operSt="up",
|
||||
operSpeed="100G",
|
||||
linkType="leaf",
|
||||
))
|
||||
|
||||
# --- LLDP & CDP adjacencies on BOTH endpoints ---
|
||||
node1 = node_map.get(n1)
|
||||
node2 = node_map.get(n2)
|
||||
if node1 is None or node2 is None:
|
||||
continue
|
||||
|
||||
port1 = f"eth{s1}/{p1}"
|
||||
port2 = f"eth{s2}/{p2}"
|
||||
oob1 = oob_ip(pod, n1)
|
||||
oob2 = oob_ip(pod, n2)
|
||||
|
||||
# Node1 sees Node2 as neighbor on port1 (Node2's own port is port2)
|
||||
add_switch_adjacency(
|
||||
store,
|
||||
pod=pod,
|
||||
local_node_id=n1,
|
||||
local_port=port1,
|
||||
remote_port=port2,
|
||||
neighbor=node2,
|
||||
neighbor_mgmt_ip=oob2,
|
||||
)
|
||||
|
||||
# Node2 sees Node1 as neighbor on port2 (Node1's own port is port1)
|
||||
add_switch_adjacency(
|
||||
store,
|
||||
pod=pod,
|
||||
local_node_id=n2,
|
||||
local_port=port2,
|
||||
remote_port=port1,
|
||||
neighbor=node1,
|
||||
neighbor_mgmt_ip=oob1,
|
||||
)
|
||||
Reference in New Issue
Block a user