A structured lesson workspace with readable content, hands-on examples, and a clean path to completion.
python3 -c "from netmiko import ConnectHandler; print('Netmiko ready')"
Python is the network automation language. Not because it's the only option — Go, Ruby, and shell scripts all work — but because the ecosystem of network libraries (Netmiko, NAPALM, Nornir, pyATS) is deepest in Python. If you're going to learn one language for network automation, this is it.
from netmiko import ConnectHandler# Define the devicedevice = {'device_type': 'cisco_ios','host': '10.10.20.10','username': 'admin','password': 'MyPassword','secret': 'MyEnablePassword',}# Connect and run a commandwith ConnectHandler(**device) as net_connect:net_connect.enable()output = net_connect.send_command('show ip interface brief')print(output)# Make a config changeconfig_commands = ['interface GigabitEthernet0/5','description Automation-added','switchport mode access','switchport access vlan 30',]result = net_connect.send_config_set(config_commands)print(result)# Savenet_connect.save_config()
That's the entire pattern. Connect to a device, run show commands, push config commands, save. Netmiko handles SSH, enable mode, prompt detection, and pagination. Whatever device type — `cisco_ios`, `cisco_nxos`, `juniper_junos`, `arista_eos` — the pattern is the same.
The `with` statement matters. It ensures the connection is closed cleanly even if an exception occurs. Without it, a failure mid-script leaves stale SSH sessions on the device. Always use `with ConnectHandler(...) as net_connect` — it's the standard idiom.
import reoutput = net_connect.send_command('show ip interface brief')# Parse with regexlines = output.split('\n')for line in lines:match = re.match(r'(\S+)\s+(\S+)\s+\S+\s+\S+\s+(up|down|administratively down)\s+(up|down)', line)if match:interface, ip, status, protocol = match.groups()print(f'{interface}: {ip} — {status}/{protocol}')
Regular expressions are how you extract structured data from unstructured CLI output. The pattern `(\S+)` captures non-whitespace tokens; `\s+` matches one or more whitespace. That said — for modern devices and controllers, prefer JSON/XML output when available. Regex against CLI output breaks when the format changes; JSON doesn't.
from netmiko import ConnectHandlerimport json# Load device inventory from a JSON filewith open('devices.json') as f:devices = json.load(f)# Run a command against every devicefor dev in devices:print(f'=== {dev["host"]} ===')try:with ConnectHandler(**dev) as conn:conn.enable()version = conn.send_command('show version | include Version')print(version)except Exception as e:print(f'Error on {dev["host"]}: {e}')# Expected devices.json:# [# {"device_type": "cisco_ios", "host": "10.10.20.10", "username": "admin", "password": "x"},# {"device_type": "cisco_ios", "host": "10.10.20.11", "username": "admin", "password": "x"}# ]
The pattern is: load inventory, loop over devices, wrap each connection in try/except so one failure doesn't stop the script. This scales from 2 devices to 2,000 with the same code. If you need parallelism (faster execution across thousands of devices), use Nornir or concurrent.futures — but the sequential pattern is the starting point.
Section 18 complete. You've covered automation concepts, controller-based networking, REST APIs, JSON, HTTP methods, DNA Center, CI/CD workflows, and Python fundamentals with Netmiko. This is the toolkit for modern network operations. Sections 19-21 cover network operations, configuration labs, and exam prep — coming in the final batch.
Finish the lesson once you have worked through the material. This awards ★ 115 XP.
Write a function that takes a list of VLAN dictionaries and returns a list of Cisco IOS config commands to create them.