Back to Learn

Network as Code (NaC) lab

A full network-as-code workflow: model devices as variables, generate configs with Ansible Roles + Jinja2, diff against live devices, and commit-merge through a CI/CD pipeline.

Ansible
NAPALM
Jinja2
GitLab CI/CD
Cisco IOS / vASA
JunOS / VyOS
group_vars / host_vars as a single source of truth
Roles + Jinja2 generate full & partial configs
Diff → commit-merge via NAPALM and GitLab CI/CD

Setup, key steps & run commands

Step 0 — clone & install
Setup

Clone the repo and install the Python dependencies (Ansible, NAPALM, pyATS and friends) into a virtualenv.

Step 0 — clone & install
bash
# Clone the lab
git clone https://github.com/dmmar/netascode.git
cd netascode

# Install Python dependencies
pip3 install -r requirements.txt
Ansible/ansible.cfg
NAPALM modules

Point Ansible at the napalm-ansible modules and action plugins so playbooks can talk to multi-vendor devices.

Ansible/ansible.cfg
bash
[defaults]
library = /usr/local/lib/python3.7/site-packages/napalm_ansible/modules
action_plugins = /usr/local/lib/python3.7/site-packages/napalm_ansible/plugins/action

# Find the exact paths on your machine with:
#   napalm-ansible
Modules/PING/ping.yaml
Connectivity test

Before generating anything, verify SSH reachability to every device in an environment's inventory.

Modules/PING/ping.yaml
bash
# Development environment
ansible-playbook -i inventories/development/hosts \
  inventories/development/Modules/PING/ping.yaml

# Test / production use their own inventory + Modules folder
ansible-playbook -i inventories/test/hosts \
  inventories/test/Modules/PING/ping.yaml
group_vars/host_vars (source of truth)
Variables → config

Each device is described as a YAML file. group_vars holds shared values per group (e.g. Cisco), host_vars holds per-device values. Roles + Jinja2 turn these into real configs.

group_vars/host_vars (source of truth)
bash
# inventories/development/group_vars/Cisco.yaml
ntp_servers:
  - 10.0.0.123
snmp_community: lab-ro

# inventories/development/host_vars/BR1-AC1.yaml
hostname: BR1-AC1
interfaces:
  - name: GigabitEthernet0/0
    ip: 10.10.1.1
    mask: 255.255.255.0
generate-all-config-and-make-diff.yml
Generate + diff

Render full and partial configs from the variables, then diff the generated FINAL config against what is live on the device.

generate-all-config-and-make-diff.yml
bash
ansible-playbook -i inventories/development/hosts \
  inventories/development/Modules/generate/generate-all-config-and-make-diff.yml

# Output lands in:
#   inventories/development/CONFIGS/<DEVICE>/FINAL_pre.conf
#   inventories/development/CONFIGS/<DEVICE>/FINAL_pre_DIFF.conf
commit-merge-final-config.yml
Apply (commit-merge)

Push the reviewed FINAL config to devices via NAPALM commit-merge — or let the GitLab CI/CD pipeline do it on merge.

commit-merge-final-config.yml
bash
ansible-playbook -i inventories/development/hosts \
  inventories/development/Modules/commit-merge/commit-merge-final-config.yml

# Or trigger the same flow through .gitlab-ci.yml on merge to master

Tested on Cisco IOS (IOSv, IOSvL2), Cisco vASA 9.x, JunOS (vSRX) and VyOS 1.1.8. The lab is designed to run against a GNS3 topology; see the repo for startup configs and topology images.