Building your first CCIE Automation practice lab with Python and NETCONF on Cisco CML takes about 30-60 minutes and gives you a hands-on environment that directly mirrors the exam. The CCIE Automation lab exam (formerly DevNet Expert) is an 8-hour test where you write real code against real devices — and the only way to prepare is by writing real code against real devices.
Key Takeaway: The fastest path to CCIE Automation lab readiness starts with a CML topology, three IOS-XE routers with NETCONF enabled, and a single Python ncclient script. Master that foundation first, then expand to RESTCONF, Ansible, and Terraform.
In this guide, I’ll walk you through the exact setup I use with my students at FirstPassLab — from spinning up the CML topology to running your first ncclient script that pulls a running config, then pushing configuration changes programmatically. No theory-only hand-waving. Every step has working code you can run today.
Why CCIE Automation Demands a Hands-On Lab
The CCIE Automation exam (rebranded from DevNet Expert in February 2026) consists of two modules:
- Module 1 — Design (3 hours): Scenario-based questions where you make architectural decisions about automation solutions. You can’t go back once you submit an answer.
- Module 2 — Develop, Test, Deploy, and Maintain (5 hours): Hands-on coding where you write Python scripts, interact with NETCONF/RESTCONF APIs, use Ansible and Terraform, and troubleshoot broken CI/CD pipelines.
According to DevNet Academy, you should aim for about 80% successful task completion across both modules to pass. The Module 2 coding section is where most candidates either pass or fail — and it tests skills you can only build through repetition.
Reading documentation won’t cut it. You need muscle memory for ncclient connection setup, YANG model navigation, and XML filter construction. That starts here.
What You Need Before Starting
| Component | Minimum Requirement | Recommended |
|---|---|---|
| Cisco CML | CML 2.5+ (Personal license $199/yr) | CML 2.7+ with API access |
| Host Machine | 16 GB RAM, 4 CPU cores | 32 GB RAM, 8 cores |
| Python | Python 3.9+ | Python 3.11+ |
| ncclient | Latest via pip | v0.6.15+ |
| IOS-XE Image | CSR1000v or Cat8000v | Cat8000v 17.9+ |
| NX-OS Image | Nexus 9000v | N9Kv 10.3+ |
If you don’t have CML yet, check out our CML vs INE vs GNS3 comparison to pick the right lab platform for your situation.
Step 1: Build Your CML Topology
Start simple. You don’t need a 20-device topology to learn NETCONF. Here’s the minimal topology that covers every CCIE Automation NETCONF/RESTCONF concept:
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ CSR1000v-1 │────│ CSR1000v-2 │────│ CSR1000v-3 │
│ (IOS-XE) │ │ (IOS-XE) │ │ (IOS-XE) │
│ 10.10.10.1 │ │ 10.10.10.2 │ │ 10.10.10.3 │
└──────┬───────┘ └──────────────┘ └──────────────┘
│
┌──────┴───────┐
│ External │
│ Connector │
│ (Bridge to │
│ host) │
└──────────────┘
In CML, create this topology:
- Drop three Cat8000v (or CSR1000v) nodes onto the canvas
- Connect them in a chain: R1↔R2, R2↔R3
- Add an External Connector bridged to your host network
- Connect the External Connector to R1’s management interface
- Assign management IPs in the 192.168.25.0/24 range (or whatever subnet your host uses)
The External Connector is critical — it gives your Python scripts on the host machine direct TCP connectivity to the virtual routers on port 830 (NETCONF) and port 443 (RESTCONF).
Step 2: Enable NETCONF and RESTCONF on IOS-XE
Console into each router and run these commands:
! Enable NETCONF over SSH (port 830)
configure terminal
netconf-yang
netconf-yang feature candidate-datastore
! Enable RESTCONF (HTTPS on port 443)
restconf
ip http secure-server
! Create a dedicated automation user
username automation privilege 15 secret AutoPass123!
! Enable SSH for NETCONF transport
line vty 0 4
transport input ssh
login local
end
write memory
Verify NETCONF is running:
show netconf-yang status
! Expected output:
! netconf-yang: enabled
! netconf-yang candidate-datastore: enabled
! netconf-yang ssh port: 830
Verify RESTCONF:
show platform software yang-management process
! Look for:
! confd : Running
! nesd : Running
! nginx : Running
Pro tip: The candidate-datastore feature is important for CCIE Automation prep. It lets you stage changes before committing — exactly like the exam environment uses.
Step 3: Install Python Dependencies
On your host machine (the one running CML or connected to CML’s management network):
# Create a virtual environment (always isolate your projects)
python3 -m venv ccie-auto-lab
source ccie-auto-lab/bin/activate
# Install the essentials
pip install ncclient lxml paramiko requests pyang
| Library | Purpose |
|---|---|
| ncclient | Python NETCONF client — handles SSH, XML, and RPC operations |
| lxml | XML parsing — needed for building and reading NETCONF filters |
| paramiko | SSH transport (ncclient dependency) |
| requests | HTTP client for RESTCONF calls |
| pyang | YANG model browser — helps you find the right XPaths |
Step 4: Your First ncclient Script — Pull the Running Config
This is the moment of truth. Create a file called get_config.py:
#!/usr/bin/env python3
"""
First CCIE Automation Lab Script
Pull running configuration via NETCONF from IOS-XE
"""
from ncclient import manager
import xml.dom.minidom
# Connection parameters — match your CML topology
DEVICE = {
"host": "192.168.25.11",
"port": 830,
"username": "automation",
"password": "AutoPass123!",
"hostkey_verify": False,
"device_params": {"name": "csr"}
}
def get_running_config():
"""Connect via NETCONF and retrieve the running configuration."""
with manager.connect(**DEVICE) as m:
# Print supported NETCONF capabilities
print(f"Connected to {DEVICE['host']}")
print(f"NETCONF version: {m.server_capabilities}\n")
# Get the full running config
config = m.get_config(source="running")
# Pretty-print the XML
print(xml.dom.minidom.parseString(config.xml).toprettyxml())
if __name__ == "__main__":
get_running_config()
Run it:
python3 get_config.py
If you see XML output with your router’s configuration, congratulations — you just did what the CCIE Automation exam expects you to do in Module 2. If you get a connection error, check:
- Connectivity:
ping 192.168.25.11from your host - Port 830:
nc -zv 192.168.25.11 830(should report open) - NETCONF enabled:
show netconf-yang statuson the router - Credentials: Verify the username/password match
Step 5: Filtered GET — Pull Specific Data with YANG
Pulling the entire running config is useful for learning, but the exam tests your ability to query specific data using YANG model paths. Here’s how to pull just the interfaces:
#!/usr/bin/env python3
"""
Filtered NETCONF GET using ietf-interfaces YANG model
"""
from ncclient import manager
import xml.dom.minidom
DEVICE = {
"host": "192.168.25.11",
"port": 830,
"username": "automation",
"password": "AutoPass123!",
"hostkey_verify": False,
"device_params": {"name": "csr"}
}
# YANG filter for ietf-interfaces
INTERFACE_FILTER = """
<filter xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
<interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces">
<interface>
<name/>
<type/>
<enabled/>
<ietf-ip:ipv4 xmlns:ietf-ip="urn:ietf:params:xml:ns:yang:ietf-ip">
<address>
<ip/>
<netmask/>
</address>
</ietf-ip:ipv4>
</interface>
</interfaces>
</filter>
"""
def get_interfaces():
with manager.connect(**DEVICE) as m:
result = m.get(INTERFACE_FILTER)
print(xml.dom.minidom.parseString(result.xml).toprettyxml())
if __name__ == "__main__":
get_interfaces()
This uses the ietf-interfaces YANG model — one of the most commonly tested models on the CCIE Automation exam. You’re not just pulling data; you’re demonstrating that you understand YANG model namespaces and XPath filtering.
Step 6: Push Configuration Changes via NETCONF
Now the real power — changing device configuration programmatically:
#!/usr/bin/env python3
"""
Push a loopback interface configuration via NETCONF edit-config
"""
from ncclient import manager
DEVICE = {
"host": "192.168.25.11",
"port": 830,
"username": "automation",
"password": "AutoPass123!",
"hostkey_verify": False,
"device_params": {"name": "csr"}
}
# Configuration payload — create Loopback99
LOOPBACK_CONFIG = """
<config xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
<interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces">
<interface>
<name>Loopback99</name>
<description>Created by CCIE Automation Lab Script</description>
<type xmlns:ianaift="urn:ietf:params:xml:ns:yang:iana-if-type">
ianaift:softwareLoopback
</type>
<enabled>true</enabled>
<ipv4 xmlns="urn:ietf:params:xml:ns:yang:ietf-ip">
<address>
<ip>99.99.99.1</ip>
<netmask>255.255.255.0</netmask>
</address>
</ipv4>
</interface>
</interfaces>
</config>
"""
def create_loopback():
with manager.connect(**DEVICE) as m:
# Push the configuration
response = m.edit_config(target="running", config=LOOPBACK_CONFIG)
if response.ok:
print("✅ Loopback99 created successfully!")
print(f" IP: 99.99.99.1/24")
print(f" Device: {DEVICE['host']}")
else:
print(f"❌ Failed: {response.errors}")
if __name__ == "__main__":
create_loopback()
After running this, SSH into the router and verify:
show ip interface brief | include Loopback99
! Expected: Loopback99 99.99.99.1 YES manual up up
You just programmatically configured a Cisco router. This exact pattern — connect, build XML payload, edit_config, verify — is what Module 2 of the CCIE Automation exam tests repeatedly.
Step 7: RESTCONF — The HTTP Alternative
RESTCONF provides the same YANG-model-based configuration but over HTTPS with JSON payloads. Many candidates find it more intuitive than NETCONF’s XML:
#!/usr/bin/env python3
"""
RESTCONF GET — Pull interfaces using HTTP/JSON
"""
import requests
import json
# Disable SSL warnings for lab environment
requests.packages.urllib3.disable_warnings()
BASE_URL = "https://192.168.25.11/restconf"
HEADERS = {
"Accept": "application/yang-data+json",
"Content-Type": "application/yang-data+json"
}
AUTH = ("automation", "AutoPass123!")
def get_interfaces_restconf():
url = f"{BASE_URL}/data/ietf-interfaces:interfaces"
response = requests.get(url, headers=HEADERS, auth=AUTH, verify=False)
if response.status_code == 200:
interfaces = response.json()
print(json.dumps(interfaces, indent=2))
else:
print(f"Error: {response.status_code} - {response.text}")
if __name__ == "__main__":
get_interfaces_restconf()
When to use which on the exam:
| Protocol | Best For | Transport | Payload |
|---|---|---|---|
| NETCONF | Bulk config changes, transactions, rollback | SSH (port 830) | XML |
| RESTCONF | Quick reads, single-resource CRUD, API integrations | HTTPS (port 443) | JSON or XML |
Step 8: Scale to Multiple Devices
The CCIE Automation lab tests your ability to manage multiple devices. Here’s how to loop through all three routers:
#!/usr/bin/env python3
"""
Multi-device NETCONF configuration push
Deploy Loopback99 across all lab routers
"""
from ncclient import manager
from concurrent.futures import ThreadPoolExecutor
DEVICES = [
{"host": "192.168.25.11", "loopback_ip": "99.99.99.1"},
{"host": "192.168.25.12", "loopback_ip": "99.99.99.2"},
{"host": "192.168.25.13", "loopback_ip": "99.99.99.3"},
]
COMMON_PARAMS = {
"port": 830,
"username": "automation",
"password": "AutoPass123!",
"hostkey_verify": False,
"device_params": {"name": "csr"}
}
def configure_device(device):
config = f"""
<config xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
<interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces">
<interface>
<name>Loopback99</name>
<description>Automated by CCIE Lab Script</description>
<type xmlns:ianaift="urn:ietf:params:xml:ns:yang:iana-if-type">
ianaift:softwareLoopback
</type>
<enabled>true</enabled>
<ipv4 xmlns="urn:ietf:params:xml:ns:yang:ietf-ip">
<address>
<ip>{device['loopback_ip']}</ip>
<netmask>255.255.255.0</netmask>
</address>
</ipv4>
</interface>
</interfaces>
</config>
"""
try:
with manager.connect(host=device["host"], **COMMON_PARAMS) as m:
response = m.edit_config(target="running", config=config)
status = "✅" if response.ok else "❌"
print(f"{status} {device['host']} — Loopback99 {device['loopback_ip']}")
except Exception as e:
print(f"❌ {device['host']} — Error: {e}")
# Deploy to all devices in parallel
with ThreadPoolExecutor(max_workers=3) as executor:
executor.map(configure_device, DEVICES)
This demonstrates threading for parallel device configuration — a technique that saves significant time during the 5-hour Module 2 coding section.
What to Practice Next
Once you’re comfortable with the basics above, expand your lab to cover these CCIE Automation exam topics:
- YANG model exploration with pyang — Learn to browse available models:
pyang -f tree ietf-interfaces.yang - Candidate datastore workflow — Lock, edit candidate, validate, commit, unlock
- Ansible with NETCONF — Use
ansible.netcommon.netconf_configmodule - Terraform for IOS-XE — The CiscoDevNet/terraform-provider-iosxe provider automates IOS-XE via RESTCONF
- pyATS testing — Cisco’s Python Automated Test System validates your automation against device state
- CI/CD integration — Git-based config deployment with pre-commit validation
For more context on how the rebrand affects your study plan, read our DevNet to CCIE Automation Rebrand guide.
How This Maps to the CCIE Automation Exam
| Lab Exercise | Exam Section | Weight |
|---|---|---|
| ncclient connect + get_config | Module 2: NETCONF operations | High |
| XML filters with YANG paths | Module 2: Data model navigation | High |
| edit_config push | Module 2: Configuration automation | High |
| RESTCONF GET/PUT/PATCH | Module 2: REST API interactions | Medium |
| Multi-device threading | Module 2: Scalable automation | Medium |
| Candidate datastore commit | Module 2: Transactional config | Medium |
According to SMENode Academy, Module 2’s 5-hour hands-on section tests real Python scripting, API interaction, and tool usage — exactly what this lab builds.
Frequently Asked Questions
What is the best lab environment for CCIE Automation practice?
Cisco Modeling Labs (CML) is the best choice for CCIE Automation practice because it runs official IOS-XE and NX-OS images with full NETCONF/RESTCONF support. CML Personal costs $199/year and runs on your laptop or a dedicated server. EVE-NG is a solid free alternative, but CML’s built-in API and topology management make it ideal for automation workflows. We compared the options in detail in our CML vs INE vs GNS3 lab comparison.
Do I need programming experience for CCIE Automation?
Basic Python knowledge is essential — variables, loops, functions, and pip package management. You don’t need to be a software developer. The ncclient library abstracts most NETCONF complexity, and RESTCONF is standard HTTP. Most network engineers I work with at FirstPassLab get comfortable with the required Python level in 4-6 weeks of focused practice.
How long does it take to set up a CCIE Automation lab on CML?
A basic NETCONF automation lab takes about 30-60 minutes — topology creation, NETCONF enablement, and first script execution. The CML software installation itself takes 1-2 hours if you’re starting from scratch. Once your base topology is saved, you can spin it up in under 5 minutes for daily practice.
What is the difference between NETCONF and RESTCONF for CCIE Automation?
NETCONF uses SSH (port 830) with XML payloads and supports full transactions with rollback capability — ideal for bulk configuration changes. RESTCONF uses HTTPS with JSON or XML and follows REST principles (GET, PUT, POST, PATCH, DELETE) — better for quick API integrations and single-resource operations. Both protocols use YANG data models underneath. The CCIE Automation exam tests both, so practice with both.
Is the CCIE Automation lab exam all coding?
No. The 8-hour exam has two modules: a 3-hour design section with web-based scenario questions (similar to CCNP-style but much harder), and a 5-hour hands-on coding section. You need to score above the minimum in both modules, and your combined score must meet the passing threshold. According to exam takers, aiming for 80% task completion gives you a strong chance of passing.
Ready to fast-track your CCIE Automation journey? Whether you’re a CCNP holder looking to level up or a DevNet Associate exploring the expert track, structured lab practice is the difference between passing and failing. Contact us on Telegram @phil66xx for a free assessment of your current skill level and a personalized study plan.