Files
taodengandClaude Fable 5 7e9a175ce6 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>
2026-07-05 20:06:36 +10:00

2.0 KiB

CI gate example — fail a PR before it reaches real hardware

Pattern: run your network automation (Ansible / Terraform / Python / aci-py) against a running aci-sim, then assert the MIT reached the expected end state. A failed assertion fails the build. No hardware, deterministic, resettable.

Files

  • assert_mit.py — the gate. Logs into the sim (or a real APIC) and checks that the objects your change was supposed to create/modify are present. Exit code = number of failed checks, so CI can gate on it.
  • github-actions-aci-gate.yml — a copy-pasteable GitHub Actions workflow wiring the three steps (start sim → run automation → assert).

assert_mit.py check syntax

Each --expect (repeatable):

Check Meaning
class:<cls>[>=N] the class query returns ≥ N objects (default N=1)
mo:<dn> GET /api/mo/<dn>.json returns the object (exists)
absent:<dn> the MO does NOT exist (e.g. after a state=absent / delete)
attr:<dn>:<key>=<val> the MO at <dn> has attribute <key> == <val>

Try it locally

# 1. start the sim (ships MS-TN1 / SF-TN1-* tenants from topology.yaml)
aci-sim run &

# 2. assert the seeded end state
python examples/ci/assert_mit.py --host 127.0.0.1:8443 \
    --expect "class:fvTenant>=1" \
    --expect "mo:uni/tn-MS-TN1" \
    --expect "attr:uni/tn-MS-TN1:name=MS-TN1" \
    --expect "absent:uni/tn-DoesNotExist"
# → 4/4 checks passed, exit 0

Because assert_mit.py speaks the plain APIC REST API, you can point it at a real APIC too (--host <apic-ip> --user ... --password ...) to diff sim-vs-real, or to validate the same expectations against staging gear.

Real-world shape

In practice step 2 is your existing playbook (see ../ansible/smoke.yml for a full cisco.aci create→idempotency example), and step 3's --expect list is the objects that playbook is contracted to produce. When someone edits the playbook in a way that stops creating those objects, the PR goes red — before anything touches production.