mirror of
https://github.com/dtzp555-max/aci-sim.git
synced 2026-07-21 21:15:12 +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>
114 lines
4.0 KiB
Python
114 lines
4.0 KiB
Python
"""build/health_faults.py — healthInst, faultInst, coopPol/coopInst, configExportP.
|
|
|
|
healthInst DN (read by topology.py line 160-163):
|
|
topology/pod-{pod}/node-{id}/sys/health
|
|
→ connector.query_dn(dn) → item.get("healthInst", {}).get("attributes", {})
|
|
|
|
faultInst DNs must:
|
|
1. Start with topology/pod-{pod}/node-{id}/ (for node-scoped queries)
|
|
2. Contain /node-{id}/ (for topology.py line 196 grouping regex)
|
|
Required attrs: severity, code, lc, type, subject, descr, created, lastTransition
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
from aci_sim.mit.mo import MO
|
|
from aci_sim.mit.store import MITStore
|
|
from aci_sim.topology.schema import Site, Topology
|
|
|
|
_CREATED_TS = "2026-01-01T00:00:00.000+00:00"
|
|
|
|
|
|
def build(topo: Topology, site: Site, store: MITStore) -> None:
|
|
"""Emit health/fault/coop/config MOs for *site*."""
|
|
pod = site.pod
|
|
faults_cfg = topo.faults
|
|
hd = faults_cfg.health_defaults
|
|
|
|
# ---- Per-node healthInst --------------------------------------------------
|
|
for node in site.all_nodes():
|
|
store.add(MO(
|
|
"healthInst",
|
|
dn=f"topology/pod-{pod}/node-{node.id}/sys/health",
|
|
cur=str(hd.node),
|
|
min=str(hd.node),
|
|
max="100",
|
|
prev=str(hd.node),
|
|
))
|
|
|
|
# ---- Per-controller healthInst --------------------------------------------
|
|
# Real APIC exposes controller (role=controller, node IDs 1..N) health at
|
|
# the same .../sys/health DN shape as switch nodes; fabric.py already
|
|
# builds a topSystem at topology/pod-{pod}/node-{cid}/sys for each
|
|
# controller, so this just adds the matching healthInst there too.
|
|
for cid in range(1, site.controllers + 1):
|
|
store.add(MO(
|
|
"healthInst",
|
|
dn=f"topology/pod-{pod}/node-{cid}/sys/health",
|
|
cur=str(hd.node),
|
|
min=str(hd.node),
|
|
max="100",
|
|
prev=str(hd.node),
|
|
))
|
|
|
|
# ---- Per-tenant healthInst (for tenants deployed in this site) -----------
|
|
for tenant in topo.tenants:
|
|
if site.name not in tenant.sites:
|
|
continue
|
|
store.add(MO(
|
|
"healthInst",
|
|
dn=f"uni/tn-{tenant.name}/health",
|
|
cur=str(hd.tenant),
|
|
min=str(hd.tenant),
|
|
max="100",
|
|
prev=str(hd.tenant),
|
|
))
|
|
|
|
# ---- Seeded faultInst (node-local DNs for node-scoped query support) -----
|
|
# Map node_id → pod for this site
|
|
site_node_pods: dict[int, int] = {n.id: pod for n in site.all_nodes()}
|
|
|
|
for seed in faults_cfg.seed:
|
|
node_pod = site_node_pods.get(seed.node)
|
|
if node_pod is None:
|
|
continue # this fault belongs to a different site's node
|
|
# seed.code already carries the full ACI fault code (e.g. "F0532") —
|
|
# do NOT prepend another "F" (that produced invalid "FF0532").
|
|
fault_dn = (
|
|
f"topology/pod-{node_pod}/node-{seed.node}"
|
|
f"/local/svc-policyelem-id-0/uni/fault-{seed.code}"
|
|
)
|
|
store.add(MO(
|
|
"faultInst",
|
|
dn=fault_dn,
|
|
severity=seed.severity,
|
|
code=seed.code,
|
|
descr=seed.descr,
|
|
created=_CREATED_TS,
|
|
lastTransition=_CREATED_TS,
|
|
lc="raised",
|
|
type="operational",
|
|
subject="node",
|
|
))
|
|
|
|
# ---- coopPol + coopInst --------------------------------------------------
|
|
store.add(MO("coopPol", dn="uni/fabric/pol-coop", name="coop"))
|
|
for node in site.all_nodes():
|
|
store.add(MO(
|
|
"coopInst",
|
|
dn=f"topology/pod-{pod}/node-{node.id}/local/svc-coop-id-0/uni/epp/fv-[coop]/node-{node.id}",
|
|
operSt="formed",
|
|
))
|
|
|
|
# ---- configExportP + configJob (backup/export stubs) ---------------------
|
|
store.add(MO(
|
|
"configExportP",
|
|
dn="uni/fabric/configexp-defaultOneTime",
|
|
name="defaultOneTime",
|
|
))
|
|
store.add(MO(
|
|
"configJob",
|
|
dn="uni/fabric/configexp-defaultOneTime/job-defaultOneTime",
|
|
operSt="success",
|
|
executeTime=_CREATED_TS,
|
|
))
|