Shipped · 19-node containerlab fabric

NAPALM Live Lab

Senior network engineering — AI-native network operations tooling.

A Flask dashboard on a live multivendor CLOS-EVPN fabric — Arista cEOS, Nokia SR Linux, and FRRouting — that shows the honest truth about NAPALM’s multivendor promise, node by node and getter by getter. Plus a secure Command Console running 2,361 curated operational commands against real lab gear.

Honesty contract

This site describes the shipped Python lab: 19 nodes, 3 vendors (cEOS · SR Linux · FRR). Junos is a core NAPALM driver in DRIVER_MAP — it is not in the containerlab topology. A cRPD leaf, gNMI subscribe, and a napalm-frr stub are the next increment, documented below as plan, not as deployed. The live coverage matrix is the Flask dashboard after you clone and run the lab — it is not a route on this static Pages site.

19
shipped nodes
2,361
curated commands
3
vendors in topology
76
hermetic tests
Why this exists

NAPALM promises one API for every vendor.
This lab shows where that promise frays.

NAPALM’s pitch is a single Python API that talks to any vendor — call get_bgp_neighbors() and you get the same normalized data structure whether the box runs Arista EOS, Cisco IOS-XR, or Juniper Junos. It’s a genuinely good abstraction, and for the vendors with first-class drivers it largely delivers. But the moment you build a real multivendor fabric, the promise frays in ways the marketing never mentions — and the gaps are exactly where you find out the hard way, usually mid-automation, against production.

This lab makes those gaps visible and reproducible instead of surprising. It runs a live multivendor CLOS-EVPN fabric (3 spine + 6 leaf, mixing Arista cEOS, Nokia SR Linux, and FRRouting) plus a 10-router 3-Tier FRR network, and shows you — node by node, getter by getter — what NAPALM actually returns versus what it claims to.

First-class · shipped

cEOS — Arista

The eos driver ships in core NAPALM and talks eAPI over HTTPS. The standard getters work. This is what “NAPALM works” looks like. Official EOS still has method-level holes (no get_ipv6_neighbors_table, no get_ntp_peers).

Community · shipped

SR Linux — Nokia

No core driver — coverage comes from the separate napalm-srl package over JSON-RPC. Real, but a different package on a different cadence. get_bgp_neighbors is a known parse gap. Labeled community-sourced, not pretended equal.

No driver · shipped

FRR — FRRouting

No NAPALM driver exists. The lab doesn’t fake one — FRR is collected via docker exec … vtysh -c " json", mapped into NAPALM-shaped dicts and tagged method: exec, napalm_supported: false. You see the seam.

Mapped · not shipped

Junos — Juniper

Core junos driver over NETCONF/SSH. In DRIVER_MAP. Official matrix: no get_arp_table. Not in the 19-node topology. A cRPD leaf is the next CLOS increment — first-class is not every getter, and it is not deployed here.

The macOS-can’t-route-to-containers problem — solved by a sidecar

On Docker Desktop for Mac, the host has no route to container management IPs — you can’t open an eAPI/JSON-RPC session from your laptop to 172.20.20.x the way native Linux Docker allows. NAPALM needs that L3 reachability, so on a Mac it simply can’t connect. The fix is a sidecar pattern: a napalm-runner container attached to the lab’s management networks runs the real NAPALM drivers from inside the fabric, and the host dispatches collection to it over docker exec (argv list, never a shell). Because every collection path — runner for eos/srl, vtysh for FRR — is docker exec-based, the exact same code runs identically on macOS and Linux. No VPN, no route add, no host-networking hacks, no “works on my Linux box” caveat.

Who it’s for

Built for engineers who need the truth before they commit code.

01

Network engineers learning NAPALM

Run real getters against real (containerized) multivendor devices instead of reading driver docs and guessing what the output looks like.

02

Architects evaluating NAPALM’s coverage

Decide whether NAPALM can underpin an automation platform across an Arista/Nokia/FRR estate — with the coverage matrix before writing thousands of lines against an abstraction that’s thinner than advertised on half the fleet.

03

Automation developers doing lab-driven dev

A reproducible, disposable fabric to write and test collection/audit code against — known topology, known BGP/EVPN state, zero risk to production.

04

Job seekers building a portfolio

A demonstrable running artifact: a live multivendor fabric, a real NAPALM coverage matrix, and a security-conscious command console — concrete evidence of containerlab fluency, not a slide deck.

What you get

Honest engineering, end to end.

Every benefit below is computed from real collection against a live fabric — no marketing-grade “supports all vendors.”

M

Honest coverage matrix

Per-node, per-getter pass/fail computed from real collection — napalm_native vs exec_fallback vs unreachable, broken out by driver. You see exactly where the abstraction holds and where it doesn’t.

napalm_nativeexec_fallbackper-getter
C

Command Console — 2,361 commands

A curated catalog of 2,361 single-line multivendor commands, executed live against lab nodes with the right CLI wrapper per vendor: Cli for cEOS, vtysh for FRR, sr_cli for SR Linux. 634 live-runnable on this fabric; Cisco and Juniper rows are reference-only.

Clisr_clivtysh634 live
T

Multivendor topology

Arista cEOS, Nokia SR Linux, and FRRouting in one CLOS-EVPN fabric (3+6) plus a 10-router 3-Tier FRR network. True multivendor, not single-vendor cosplay — the mix is where tooling actually breaks.

cEOSSR LinuxFRRCLOS-EVPN
S

Real NAPALM via sidecar

A napalm-runner container runs the real drivers from inside the fabric, dispatched over docker exec. Sidesteps the Docker-Desktop routing wall — identical behavior on macOS and Linux.

docker execrunner sidecarmac = linux
G

Secure read-only console

Hostnames validated against a fabric allowlist; commands run as an argv list (no shell, no injection); a read-only guard permits only show/display/get/ping-class verbs; pipe filters are an allowlist; newlines and control chars rejected.

allowlistargv-onlyread-only guard
Q

76 hermetic tests + CI

A fixed containerlab topology with known state means repeatable results run-to-run. 76 hermetic pytest tests cover the collection backend, the security guard, and the catalog loader. GitHub Actions runs them on every push and pull request.

pytesthermeticGitHub Actions
The coverage matrix

Three vendors shipped. A fourth mapped, not deployed.

No papered-over seams. Each vendor is collected the way it actually has to be, and labeled honestly in the UI.

Vendor / NOS NAPALM tier Transport / method What you get
Arista cEOS Full · shipped eos driver · eAPI / HTTPS Core NAPALM driver. Standard getters work. Falls back to Cli -c "show version | json" if eAPI is down.
Nokia SR Linux Partial · shipped napalm-srl · JSON-RPC Community package, separate maintenance cadence. get_bgp_neighbors is a known parse gap. Labeled community-sourced — not pretended equal.
FRRouting Exec fallback · shipped vtysh -c "… json" No NAPALM driver. Collected via vtysh, mapped into NAPALM-shaped dicts. Tagged napalm_supported:false; LLDP / environment marked unsupported with reason.
Juniper Junos Mapped · not shipped junos driver · NETCONF / SSH Core driver in DRIVER_MAP. Official NAPALM matrix: no get_arp_table. Not part of the 19-node topology. A cRPD leaf is plan, not inventory.
Shipped CLOS: spine1 SR Linux, spine2 cEOS, spine3 FRR, leaf1–6 mixed vendors. No leaf7. spine1SR Linux spine2cEOS spine3FRR leaf1cEOS leaf2SR Linux leaf3FRR leaf4cEOS leaf5SR Linux leaf6FRR CLOS-EVPN · 3 spine + 6 leaf · plus 10 FRR nodes in the 3-tier fabric · no leaf7
Arista cEOS Nokia SR Linux FRRouting Junos — mapped, not in this drawing

Cross-vendor command cheat-sheet

Same intent, different CLI. SR Linux has no show running-config — it uses info. A Cisco/Arista command on an SRL node returns an honest device parse error, not a tool bug. Universal intents v1 (version, BGP, OSPF, interfaces, counters, routes, memory, CPU) verified live: 24/24 across the three shipped vendors.

TaskArista cEOSFRR (vtysh)Nokia SR Linux
Running configshow running-configshow running-configinfo from running
BGP summaryshow ip bgp summaryshow ip bgp summaryshow network-instance default protocols bgp neighbor
Routing tableshow ip routeshow ip routeshow …default route-table ipv4-unicast summary
Live stateshow …show …info from state …
Security model

Read-only by construction, not by hope.

The console ships publicly, so it defaults safe. Full policy in SECURITY.md.

No shell, ever

docker exec is invoked with an argv list. There is no shell to inject into. Newlines, control characters, and metacharacters are rejected before exec.

argv listno shell=True

Hostname allowlist

Every target is validated against NODE_INDEX. Arbitrary container names cannot reach the runtime. Unknown fabrics return 400 on the matrix API.

NODE_INDEX19 hostnames

Read-prefix + pipe allowlist

Positive allowlist of operational verbs (show / display / get / ping / info). Pipe filters are display-only; redirect, append, and | bash are writes and are rejected. LAB_CONSOLE_READONLY=1 kills write mode for any exposed deploy.

read verbsLAB_CONSOLE_READONLY
What’s next — plan, not inventory

Four-column CLOS. gNMI. Fail-closed. A real FRR driver.

These are designed and documented. They are not in the shipped 19-node topology. Claiming them as live would violate the honesty contract above.

shipped

GitHub Actions on the hermetic tests

pytest on every push and pull request (Python 3.12). The README badge now points at the real workflow, not a static shield. JUnit from the live test platform remains optional — it needs a fabric.

open · PR #2

Fail-closed empty suites

A suite whose selector matches zero hosts must ERROR, not export tests="0" JUnit that CI treats as green. Canonical trigger: evpn_bgp × fabric=dcn. Draft: gesh75/napalm-live-lab#2.

plan

Intent pack v2

v1 is 8 intents, 24/24 on the three shipped vendors. v2 names the CLOS as an EVPN fabric: running_config (info from running on SRL), lldp (honest FRR miss), arp, evpn, ntp.

plan

gNMI subscribe on SR Linux

JSON-RPC poll is how napalm-srl talks. SRL’s native ops plane is gNMI. Subscribe on interface stats, BGP session-state, system, NTP, route table — beside the matrix, not instead of it.

plan

napalm-frr community stub

The exec fallback already produces NAPALM-shaped dicts. Extract that mapping as a package. Keep napalm_supported: false until getters complete a live round-trip. Do not pretend FRR is a core driver.

plan

cRPD leaf7 — four-column CLOS

Add one Juniper cRPD leaf so the fabric is core + community + exec + core. Official Junos still has no get_arp_table. Putting a first-class driver next to FRR does not make ARP appear. Not deployed in this repo yet.

The elevator pitch

NAPALM Live Lab is a Flask dashboard that runs a live, multivendor containerlab fabric — Arista cEOS, Nokia SR Linux, and FRRouting across a 9-node CLOS-EVPN spine/leaf plus a 10-router 3-Tier network — and shows you the truth about NAPALM’s multivendor promise: full coverage on cEOS, partial community coverage on SR Linux, and no driver at all on FRR (collected honestly via vtysh and labeled as such). Junos is a core driver in the map and is not in the topology. Real NAPALM runs inside a sidecar container so the whole thing behaves identically on a macOS laptop and on Linux, with no host-to-container routing hacks. On top of the live coverage matrix it adds a Command Console that runs 2,000+ curated multivendor operational commands behind a read-only, allowlist-guarded, shell-injection-proof execution layer — so you can learn NAPALM, evaluate its real multivendor coverage, and develop lab-driven automation against true multivendor gear without a single piece of physical hardware.