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

ComponentMinimum RequirementRecommended
Cisco CMLCML 2.5+ (Personal license $199/yr)CML 2.7+ with API access
Host Machine16 GB RAM, 4 CPU cores32 GB RAM, 8 cores
PythonPython 3.9+Python 3.11+
ncclientLatest via pipv0.6.15+
IOS-XE ImageCSR1000v or Cat8000vCat8000v 17.9+
NX-OS ImageNexus 9000vN9Kv 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:

  1. Drop three Cat8000v (or CSR1000v) nodes onto the canvas
  2. Connect them in a chain: R1↔R2, R2↔R3
  3. Add an External Connector bridged to your host network
  4. Connect the External Connector to R1’s management interface
  5. 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
LibraryPurpose
ncclientPython NETCONF client — handles SSH, XML, and RPC operations
lxmlXML parsing — needed for building and reading NETCONF filters
paramikoSSH transport (ncclient dependency)
requestsHTTP client for RESTCONF calls
pyangYANG 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:

  1. Connectivity: ping 192.168.25.11 from your host
  2. Port 830: nc -zv 192.168.25.11 830 (should report open)
  3. NETCONF enabled: show netconf-yang status on the router
  4. 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:

ProtocolBest ForTransportPayload
NETCONFBulk config changes, transactions, rollbackSSH (port 830)XML
RESTCONFQuick reads, single-resource CRUD, API integrationsHTTPS (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:

  1. YANG model exploration with pyang — Learn to browse available models: pyang -f tree ietf-interfaces.yang
  2. Candidate datastore workflow — Lock, edit candidate, validate, commit, unlock
  3. Ansible with NETCONF — Use ansible.netcommon.netconf_config module
  4. Terraform for IOS-XE — The CiscoDevNet/terraform-provider-iosxe provider automates IOS-XE via RESTCONF
  5. pyATS testing — Cisco’s Python Automated Test System validates your automation against device state
  6. 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 ExerciseExam SectionWeight
ncclient connect + get_configModule 2: NETCONF operationsHigh
XML filters with YANG pathsModule 2: Data model navigationHigh
edit_config pushModule 2: Configuration automationHigh
RESTCONF GET/PUT/PATCHModule 2: REST API interactionsMedium
Multi-device threadingModule 2: Scalable automationMedium
Candidate datastore commitModule 2: Transactional configMedium

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.