Skip to content

Commit 31a09ee

Browse files
Initial commit: Arista eAPI with Python (containerlab-based lab)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 133b27d commit 31a09ee

12 files changed

Lines changed: 409 additions & 67 deletions

File tree

.env.example

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# ---------------------------------------------------------------------------
2+
# NextGen Network Academy · Arista eAPI with Python
3+
#
4+
# 1. cp .env.example .env
5+
# 2. The defaults below match the included containerlab topology — no edits
6+
# needed if you used `containerlab deploy -t topo/topology.clab.yml`.
7+
# 3. NEVER commit your .env. The .gitignore in this repo blocks it, but
8+
# double-check before every push.
9+
# ---------------------------------------------------------------------------
10+
11+
# Switch reachable address. Defaults to the published port from the lab topo.
12+
EAPI_HOST=localhost
13+
14+
# eAPI port. The lab publishes the cEOS container's 443 to host 8443.
15+
# Real switches usually leave this at 443.
16+
EAPI_PORT=8443
17+
18+
# Lab credentials — baked into topo/configs/eos1.cfg for convenience.
19+
# Replace if you point this script at a different switch.
20+
EAPI_USERNAME=admin
21+
EAPI_PASSWORD=admin

.github/workflows/lint.yml

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
name: lint
2+
3+
on:
4+
push:
5+
branches: [main]
6+
pull_request:
7+
8+
jobs:
9+
syntax-check:
10+
runs-on: ubuntu-latest
11+
steps:
12+
- uses: actions/checkout@v4
13+
14+
- name: Set up Python
15+
uses: actions/setup-python@v5
16+
with:
17+
python-version: "3.11"
18+
19+
- name: Install dependencies
20+
run: |
21+
python -m pip install --upgrade pip
22+
pip install -r requirements.txt
23+
pip install pyflakes
24+
25+
- name: Compile every Python file
26+
run: |
27+
python -m compileall reference starter
28+
29+
- name: Lint with pyflakes (non-blocking informational pass)
30+
run: |
31+
pyflakes reference || true
32+
# `starter/` is allowed to fail because it contains intentional
33+
# NotImplementedError stubs students must complete.

.gitignore

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# Credentials — never commit
2+
.env
3+
.env.*
4+
!.env.example
5+
6+
# Python
7+
__pycache__/
8+
*.py[cod]
9+
*$py.class
10+
.venv/
11+
venv/
12+
env/
13+
.Python
14+
*.egg-info/
15+
.pytest_cache/
16+
17+
# Editor / OS
18+
.idea/
19+
.vscode/
20+
.DS_Store
21+
Thumbs.db
22+
*.swp
23+
*~
24+
25+
# Output captures students might generate
26+
*.csv
27+
*.log
28+
output/
29+
screenshots/

README.md

Lines changed: 43 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2,58 +2,82 @@
22

33
> A NextGen Network Academy guide. Companion code lives here; the conceptual
44
> walkthrough and learning objectives live on the
5-
> [foundations site](https://learn.nextgennetworkacademy.com/learn/foundations/).
5+
> [netops site](https://learn.nextgennetworkacademy.com/learn/netops/).
66
7-
This repo contains the working code, starter skeleton, and challenge brief
8-
for retrieving switch information from an Arista EOS device using Python and
7+
This repo contains a self-contained lab — a containerlab topology with a
8+
pre-staged Arista cEOS-lab node — plus the Python script, starter skeleton,
9+
and challenge brief for retrieving switch information from the device using
910
eAPI.
1011

12+
No physical switch required. `containerlab deploy` and you have a working
13+
environment.
14+
1115
## What's inside
1216

1317
| Path | Purpose |
1418
|---|---|
19+
| `topo/topology.clab.yml` | Containerlab topology — single cEOS node, eAPI pre-enabled |
20+
| `topo/configs/eos1.cfg` | Startup config baked into the cEOS device |
1521
| `reference/eapi_show_version.py` | Complete working solution. Read after you've tried the challenge. |
1622
| `starter/eapi_starter.py` | Skeleton with TODO blocks. This is your starting point. |
17-
| `examples/sample_output.json` | Captured eAPI response — useful when you don't have lab access. |
23+
| `examples/sample_output.json` | Captured eAPI response — useful for offline iteration. |
1824
| `docs/instructor-guide.md` | Walkthrough notes for instructors using this in class. |
1925
| `docs/student-challenge.md` | The hands-on challenge brief and grading rubric. |
2026
| `docs/instructor-notes.md` | Answer key, common failure modes, time-box guidance. |
2127

28+
## Lab prerequisites
29+
30+
Install once on your machine:
31+
32+
| Tool | Purpose | Install |
33+
|---|---|---|
34+
| Docker | Container runtime | [docs.docker.com/get-docker](https://docs.docker.com/get-docker/) |
35+
| Containerlab | Topology orchestrator | [containerlab.dev/install](https://containerlab.dev/install/) |
36+
| cEOS-lab image | The switch itself | Free download from [arista.com](https://www.arista.com/en/support/software-download) (account required) |
37+
| Python 3.9+ | The script | [python.org/downloads](https://www.python.org/downloads/) |
38+
39+
After downloading the cEOS-lab tarball, import it once:
40+
41+
```bash
42+
docker import cEOSarm-lab-4.34.4M.tar ceosarm:4.34.4M
43+
docker images | grep ceos # confirm it's there
44+
```
45+
46+
Linux users will need `sudo` for containerlab. macOS (Docker Desktop or
47+
OrbStack) and Windows-WSL2 typically don't.
48+
2249
## Quick start
2350

2451
```bash
2552
# 1. Clone
2653
git clone https://github.com/nextgen-network-academy/arista-eapi-python.git
2754
cd arista-eapi-python
2855

29-
# 2. Set up a virtual environment
56+
# 2. Bring up the lab
57+
sudo containerlab deploy -t topo/topology.clab.yml
58+
59+
# 3. Set up the Python environment
3060
python3 -m venv .venv
3161
source .venv/bin/activate # Windows: .venv\Scripts\activate
3262
pip install -r requirements.txt
3363

34-
# 3. Configure credentials
64+
# 4. Configure (defaults already match the lab — no edits needed)
3565
cp .env.example .env
36-
# edit .env with your switch IP, username, password
3766

38-
# 4. Run the reference solution
67+
# 5. Run the reference solution
3968
python reference/eapi_show_version.py
4069
```
4170

42-
## Switch-side prerequisite
71+
You should see two GitHub-flavored markdown tables in your terminal — `show
72+
version` and `show interfaces status`, both pulled from the running cEOS node
73+
over eAPI.
4374

44-
On the EOS switch (or vEOS / cEOS lab device), enable eAPI **once**:
75+
## Tear down when you're done
4576

46-
```text
47-
switch# configure terminal
48-
switch(config)# management api http-commands
49-
switch(config-mgmt-api-http-cmds)# no shutdown
50-
switch(config-mgmt-api-http-cmds)# protocol https
51-
switch(config-mgmt-api-http-cmds)# end
52-
switch# show management api http-commands
77+
```bash
78+
sudo containerlab destroy -t topo/topology.clab.yml --cleanup
5379
```
5480

55-
You should see `Enabled: Yes` and `HTTPS server: running, set to use port 443`.
56-
5781
## A word on terminology
5882

5983
You will hear engineers call eAPI a "REST API." Strictly speaking, it isn't —

docs/instructor-guide.md

Lines changed: 41 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
**Audience:** Networking students with basic CLI experience and beginner-level Python
44
**Suggested duration:** ~90 minutes
55
**Format:** Lecture + live demo + hands-on lab
6-
**Prerequisites:** Python 3.9+ installed; access to an EOS switch or vEOS / Arista cEOS lab
6+
**Prerequisites:** Python 3.9+, Docker, containerlab, and a cEOS-lab image imported as `ceosarm:<tag>`. Verify all of this on student machines *before* class — see `instructor-notes.md`.
77

88
---
99

@@ -14,7 +14,7 @@ After working through this guide, the student will be able to:
1414
| # | Objective | Bloom level |
1515
|---|-----------|-------------|
1616
| 1 | Define API, REST, JSON-RPC, and explain how they differ | Understand |
17-
| 2 | Enable and verify eAPI on an EOS switch | Apply |
17+
| 2 | Read a switch startup config to identify what enables eAPI, and verify the lab device is reachable | Apply |
1818
| 3 | Construct a JSON-RPC request payload for `runCmds` | Apply |
1919
| 4 | Use the `requests` library to send authenticated HTTPS calls | Apply |
2020
| 5 | Parse JSON responses and render them as readable tables | Analyze |
@@ -24,10 +24,10 @@ After working through this guide, the student will be able to:
2424

2525
## Materials needed
2626

27-
- Lab pod with at least one EOS / vEOS / cEOS switch reachable over the network
28-
- Switch credentials with `privilege 15` (lab user, **not** production)
29-
- Student workstation with Python 3.9+ and `pip`
30-
- This repository, cloned locally
27+
- Student workstations with Docker, containerlab, Python 3.9+, and the
28+
cEOS-lab image already imported. Pre-class setup is non-trivial — see
29+
the pre-class checklist in `instructor-notes.md`.
30+
- This repository, cloned locally on each student's machine.
3131

3232
---
3333

@@ -79,31 +79,55 @@ Highlight: HTTPS (encrypted), Basic Auth (header, not URL), JSON body.
7979

8080
---
8181

82-
### Part 2 — Live demo (25 min)
82+
### Part 2 — Lab spin-up + live demo (25 min)
8383

84-
Walk students through `reference/eapi_show_version.py` line by line.
84+
**2.1 Bring up the topology (5 min) — instructor screen-share**
8585

86-
**2.1 Enabling eAPI on the switch (5 min) — instructor screen-share**
86+
The lab is a single cEOS node defined in `topo/topology.clab.yml`. Walk
87+
through what happens when you deploy it.
88+
89+
```bash
90+
sudo containerlab deploy -t topo/topology.clab.yml
91+
sudo containerlab inspect -t topo/topology.clab.yml
92+
```
93+
94+
Show the inspect output — students see the running container, its name
95+
(`clab-arista-eapi-python-eos1`), management IP, and published ports
96+
(8443→443, 2222→22). Reinforce that this is the same shape they'd get from
97+
any production cEOS device, just packaged for their laptop.
98+
99+
**2.2 The startup config (5 min) — read configs/eos1.cfg together**
100+
101+
Open `topo/configs/eos1.cfg` in the editor. Highlight the eAPI block:
87102

88103
```text
89-
switch(config)# management api http-commands
90-
switch(config-mgmt-api-http-cmds)# no shutdown
91-
switch(config-mgmt-api-http-cmds)# protocol https
92-
switch# show management api http-commands
104+
management api http-commands
105+
no shutdown
106+
protocol https
107+
no protocol http
93108
```
94109

95-
**2.2 First call with `curl` before Python (5 min)**
110+
> **Teaching point:** This is the *exact same configuration* you'd type into
111+
> a physical switch's CLI to enable eAPI. Pre-staging it as text in Git is
112+
> the GitOps mindset in miniature — configuration is code, version-controlled,
113+
> reproducible, reviewable. Students will see this pattern again in the
114+
> NetOps and GitOps tracks.
115+
116+
Also walk through the VLAN and interface stanzas — these are what produce
117+
non-trivial output when students later run `show interfaces status`.
118+
119+
**2.3 First call with `curl` before Python (5 min)**
96120

97121
Show that this is just HTTP — Python isn't magic.
98122

99123
```bash
100-
curl -k -u admin:lab123 \
124+
curl -k -u admin:admin \
101125
-H 'Content-Type: application/json' \
102126
-d '{"jsonrpc":"2.0","method":"runCmds","params":{"version":1,"cmds":["show version"],"format":"json"},"id":1}' \
103-
https://10.0.0.5/command-api | python3 -m json.tool
127+
https://localhost:8443/command-api | python3 -m json.tool
104128
```
105129

106-
**2.3 Same call in Python (15 min)**
130+
**2.4 Same call in Python (10 min)**
107131

108132
Step through `reference/eapi_show_version.py`. Pause at:
109133

docs/instructor-notes.md

Lines changed: 28 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,24 @@
55
66
## Pre-class checklist
77

8-
- [ ] Confirm lab switches are reachable from student workstations
9-
- [ ] Verify eAPI is **enabled** on each pod switch (`show management api http-commands`)
10-
- [ ] Pre-create a low-privilege lab user on each switch (don't hand out admin)
11-
- [ ] Confirm Python 3.9+ on lab images
12-
- [ ] Run `reference/eapi_show_version.py` yourself end-to-end the morning of class
8+
The biggest risk to this session is uneven setup across student laptops. Run
9+
the lab spin-up on each student's machine *before* class — losing 20 minutes
10+
to a missing cEOS image is a common failure mode.
11+
12+
- [ ] Verify Docker is installed and running on each student machine
13+
(`docker version`)
14+
- [ ] Verify containerlab is installed (`containerlab version`)
15+
- [ ] Verify the cEOS-lab image is imported (`docker images | grep ceos`).
16+
If not, walk students through the download from arista.com and the
17+
`docker import cEOSarm-lab-X.Y.Z.tar ceosarm:X.Y.Z` step. **This is the
18+
step most likely to derail a class** — students need an arista.com
19+
account, which takes a few minutes to register.
20+
- [ ] Confirm Python 3.9+ on lab images (`python3 --version`)
21+
- [ ] Run `sudo containerlab deploy -t topo/topology.clab.yml` yourself end
22+
to end the morning of class, then `python reference/eapi_show_version.py`
23+
to confirm the full path works.
24+
- [ ] Tear down with `sudo containerlab destroy -t topo/topology.clab.yml --cleanup`
25+
so students start clean.
1326

1427
## Rubric notes
1528

@@ -61,11 +74,15 @@ grading guidance:
6174

6275
| Symptom | Likely cause | Fix |
6376
|---------|--------------|-----|
64-
| `ConnectionRefusedError` | eAPI not enabled on switch | `management api http-commands` / `no shutdown` |
65-
| `SSL: CERTIFICATE_VERIFY_FAILED` | Self-signed cert + `verify=True` | `verify=False` (lab) or install a trusted cert |
66-
| `401 Unauthorized` | Wrong username/password | Check `.env`; check switch user privilege |
77+
| `containerlab: command not found` | clab not installed | Reinstall per [containerlab.dev/install](https://containerlab.dev/install/) |
78+
| `Error: image ceos:X.Y.Z not found` | cEOS image not imported | `docker import cEOSarm-lab-X.Y.Z.tar ceosarm:X.Y.Z`, or set `CEOS_IMAGE` to a tag that *is* present |
79+
| `bind: address already in use` (port 8443 or 2222) | Another process holds the port | Stop the conflicting process, or edit `topo/topology.clab.yml` to publish a different host port and update `.env` to match |
80+
| Lab deploys but `containerlab inspect` shows status `unhealthy` | cEOS startup not yet complete | Wait 30–60 seconds; cEOS is slow to boot. If still unhealthy, `docker logs clab-arista-eapi-python-eos1` |
81+
| `ConnectionRefusedError` from the Python script | Lab not deployed, or wrong port in `.env` | `containerlab inspect -t topo/topology.clab.yml`; confirm `EAPI_PORT=8443` |
82+
| `SSL: CERTIFICATE_VERIFY_FAILED` | cEOS self-signed cert + `verify=True` | `verify=False` in lab; document why this is unacceptable in production |
83+
| `401 Unauthorized` | Wrong username/password in `.env` | Defaults are `admin / admin` — match the startup config |
6784
| `KeyError: 'result'` | eAPI returned an error block | Check for `'error'` key first; print `error.message` |
68-
| Empty interface list | User lacks privilege 15 | Re-create user with `privilege 15` or `role network-admin` |
85+
| Student on macOS reports lab "looks deployed but I can't reach it" | Trying to use container IP instead of `localhost:8443` | Use `localhost:8443` — the topology publishes ports for cross-platform reach |
6986

7087
## Time-box guidance
7188

@@ -77,8 +94,8 @@ grading guidance:
7794

7895
## Natural follow-on topics
7996

80-
These build directly on what students learn here. They sit naturally in the
81-
NetOps and GitOps tracks rather than Foundations:
97+
These build directly on what students learn here. The first few belong in
98+
NetOps; the deeper automation and AIOps items push into GitOps and AIOps:
8299

83100
- Configuration changes via eAPI (privileged `runCmds`, change control)
84101
- Concurrency — hitting many switches in parallel with `concurrent.futures`

docs/student-challenge.md

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,23 @@ to confirm software versions before a maintenance window. Your job: write a
88
Python script that pulls switch info from one device today, so you can scale
99
it to 40 next sprint.
1010

11+
For this challenge you'll work against a single cEOS-lab device spun up by
12+
the included containerlab topology — the script you write here will work
13+
unchanged against a real switch.
14+
15+
## Lab setup before you start
16+
17+
```bash
18+
# From the repo root
19+
sudo containerlab deploy -t topo/topology.clab.yml
20+
sudo containerlab inspect -t topo/topology.clab.yml # confirm it's running
21+
22+
# Tear down when you're done
23+
sudo containerlab destroy -t topo/topology.clab.yml --cleanup
24+
```
25+
26+
(macOS / Windows-WSL2: drop `sudo` if your Docker setup doesn't require it.)
27+
1128
## What you must build
1229

1330
A Python script (`starter/eapi_starter.py` is your starting point) that:
@@ -81,12 +98,17 @@ Submit (as a pull request to your fork of this repo):
8198

8299
## Hints
83100

84-
- The eAPI URL is `https://<switch>/command-api` — note the singular endpoint.
85-
- Lab switches usually have self-signed certs. You'll need
86-
`verify=False` *and* `urllib3.disable_warnings(...)`. **Never** ship that to
87-
production.
101+
- The eAPI URL is `https://<host>:<port>/command-api`. With the default lab,
102+
that's `https://localhost:8443/command-api`.
103+
- The `.env.example` already has the right values for the included lab —
104+
copy it to `.env` and you're connected.
105+
- cEOS uses self-signed certs. You'll need `verify=False` *and*
106+
`urllib3.disable_warnings(...)`. **Never** ship that to production.
88107
- The `result` field in the response is a **list**, indexed in the same order
89108
as the `cmds` you sent.
90109
- `tabulate` is your friend for tables. `from tabulate import tabulate`.
110+
- To test your error handling without leaving the lab: temporarily set
111+
`EAPI_PORT=9999` in `.env`. Your script should report a clear connection
112+
error, not a Python traceback.
91113

92114
Good luck. Ask questions early and often.

0 commit comments

Comments
 (0)