Network automation: from intent to devices
CPE Lyon, WAN DevNet course, 2026 In progress
A 3-site Cisco network described as data (YAML, then NetBox), validated in Python, rendered with Jinja2 and deployed with Netmiko, NAPALM and Nornir.
Intent means describing what the network should be as data. The code then checks it, turns it into Cisco configurations and deploys them to the devices.
Course subjects, lab and code skeletons are provided by the teacher; I write the data, functions and templates. Graded code is not published.
At a glance
- 3 sitesLyon, Marseille, Paris
- 10 devicesin the Nornir inventory
- 9 testspytest, all passing
- ~12 sOSPF deployed on 5 routers in parallel
The network
Emulated in GNS3, individual work. VRRP on two routers at Lyon and Marseille, one router at Paris.
The chain
- 1IntentYAML, then NetBox
- 2Validateyamllint, check_site, pytest
- 3RenderJinja2, 8 configs
- 4DeployNetmiko, NAPALM, Nornir
- 5DevicesGNS3
The project follows the Network Automation Forum (NAF) framework: intent, executor, then observability.
Progress
TP-01 Describe the network
Lyon configured by hand, the 3 sites described in YAML.
TP-02 Validate and generate
check_site() with 4 checks, Jinja2 templates, 8 configs.
TP-03 Netmiko and NAPALMPartial
Scripted deployment, dry-run diff, then commit. NAPALM rollback test not verified.
TP-04 Scale with NornirPartial
10-device inventory, OSPF on 5 routers in about 12 s. OSPF failover test not verified.
TP-05 NetBox as source of truth
Same data, same configs, deployed from NetBox.
TP-06 Drift, orchestration, CI
Subject not published yet.
TP-07 Final test
The whole chain. Not started.
A change made in NetBox, not in a file
- 1VRRP priority of R2-LYON set to 120 in the NetBox interface
- 2Dry-run: the diff shows the change
- 3Deployment to the devices
- 4R2-LYON becomes Master
YAML and NetBox give the same dictionary and identical configs (diff -r): only the source of truth changes, not the templates.
Extracts
- hostname: R1-PARS
platform: ios
model: c7200
loopback: 10.255.0.31/32
lan_interface: GigabitEthernet0/0
wan:
- interface: Serial1/0
ip: 10.0.0.22/30
peer: CORE-1
- interface: Serial1/1
ip: 10.0.0.26/30
peer: CORE-2
ips:
10: 172.16.50.254/24
20: 172.16.60.254/24hostname R1-PARS
!
interface GigabitEthernet0/0.10
encapsulation dot1Q 10
ip address 172.16.50.254 255.255.255.0
no shutdown
!
interface GigabitEthernet0/0.20
encapsulation dot1Q 20
ip address 172.16.60.254 255.255.255.0
no shutdown
!Problems I ran into
| Problem | Diagnosis | Fix |
|---|---|---|
| Devices unreachable after a restart: the emulated switches lost all VLANs, including admin VLAN 99. | vlan.dat is never written to flash. R2 had a route tied to an IP SLA probe that fell with the VLAN. Found with a ping from the VM, show ip interface brief, show interfaces trunk and show track. | VLANs recreated by hand (basic administration, outside the generated config), then Nornir rerun only on the failed hosts. VLAN persistence not solved. |
| A NAPALM diff that is never empty. | On IOS, merge mode compares text: vrrp preempt, no shutdown and priority 100 are defaults missing from the running config, so they reappear in every diff. | Accepted: the configuration is idempotent in effect, not in the text diff. Templates that skip IOS defaults are on the to-do list. |
| A NetBox change that seemed invisible. | The dry-run did not show the expected change. Reading the API and the Changelog showed it had never been saved. | Change made again, then checked through the API. |
In progress / next
- TP-06: detect drift between intent and network, orchestrate, and a GitHub Actions CI pipeline. Subject not published yet.
- TP-07: the final test, the whole chain. Not started.
- Not verified all the way: the NAPALM rollback test (TP-03, deliberate error on the VRRP VIP) and the OSPF failover test when the R1-LYON to CORE-1 link is cut (TP-04).
- To improve: VLAN persistence on the emulated switches, and templates that do not write IOS defaults, to get an empty NAPALM diff.
All the details
Context and principle
- WAN DevNet course, CPE Lyon, 4IRC (2026). Individual work on a lab emulated in GNS3. The teacher provides the subjects, the lab and code skeletons; I write the requested functions, the data and the templates, then apply them to the network.
- The network is described as data, first in YAML then in NetBox. The data is validated in Python, then turned into Cisco IOS configurations by Jinja2 templates. The configurations are deployed automatically with Netmiko, NAPALM and Nornir. The project follows the Network Automation Forum framework: intent, executor, then observability.
- This page describes the work. It does not contain the code of the lab exercises, which are graded.
The network
- 3 sites: CPE-LYON (head office), CPE-MARS (Marseille) and CPE-PARS (Paris, branch), linked to a core of two routers (CORE-1, CORE-2) provided by the teacher.
- Devices: 5 site routers (Cisco c7200), 3 switches (c3725 with an EtherSwitch module) and PCs.
- Protocols: VLANs 10 and 20, 802.1Q trunks, inter-VLAN routing with subinterfaces, VRRP (two routers at Lyon and Marseille), OSPF area 0 towards the core, and a separate administration network (VLAN 99).
Tools
- Python 3.12, PyYAML, Jinja2, yamllint, pytest, Netmiko, NAPALM, Nornir (nornir-netmiko, nornir-napalm, nornir-netbox), NetBox (Docker), pynetbox, requests, GNS3, Git and GitHub (two remotes: upstream for the teacher, origin for my private repository).
TP-01 to TP-03
- TP-01: manual configuration of the Lyon site (VLAN, trunk, dot1Q subinterfaces, VRRP), the 3 sites described in YAML, and load_yaml() and summarize() written by me.
- TP-02: check_site() with 4 checks (unique VLAN ids, gateway inside its network, router IPs in the right network, different VRRP priorities when there are two routers), site_switch.j2 and site_router.j2 templates (VRRP only when the site has two routers), render functions producing 8 config files. The 6 validation tests and 3 rendering tests pass. Marseille configs applied in GNS3: R1-MARS is VRRP Master, R2-MARS is Backup.
- TP-03: Netmiko (connect, show, deploy_file, backup) with Paris deployed by script and configuration backups before and after; NAPALM (open_device, preview with compare_config, apply with diff, confirmation, then commit or discard). A VLAN description added in the YAML, then the template, applied on R1-MARS and R2-MARS after reading the diff; on the second pass it no longer appears in the diff.
TP-04 and TP-05
- TP-04: Nornir inventory of 10 devices with groups by role and by site, credentials read from an .env file ignored by Git; init_nornir(), site_routers() (5 routers, never the core), render_ospf() and deploy_ospf() with an ospf.j2 template. OSPF deployed in parallel on the 5 routers in about 12 s; R1-PARS has both neighbours (CORE-1 and CORE-2) in FULL.
- TP-05: NetBox in Docker; REST API with curl then requests, HTTP codes tested with no token or an invalid one; get_api() and get_or_create() import the 3 sites idempotently; list_sites() and _vlans() read NetBox back and give exactly the same dictionary as the YAML (--compare OK), and the generated configs are identical (diff -r); site_devices() and deploy_site() deployed the VRRP priority change of R2-LYON made in NetBox.
Contact
Email meLinkedInBased in Lyon, France
Last updated