Python + Cisco: Your First Automation Project

A beginner-friendly, step-by-step Python Cisco automation project that uses Netmiko to deploy VLANs across five switches from a YAML inventory file. The complete working script includes error handling, logging, and post-change verification. Perfect for engineers taking their first steps into networ

Python + Cisco: Your First Automation Project

If you've been learning Python and Cisco networking separately, this is the project that brings them together. We're going to build a real automation script that reads a YAML inventory file, connects to multiple switches using Netmiko, configures VLANs, and verifies the changes. This is exactly the kind of project you'd find in a junior network automation role.

By the end of this post, you'll have a complete, working Python Cisco project you can adapt for your own lab or environment.

What We're Building

The goal is simple: configure a set of VLANs across five switches without logging into each one manually. Our script will:

  • Read switch details and VLAN data from a YAML file
  • Connect to each switch using Netmiko
  • Push VLAN configuration commands
  • Verify the VLANs were created
  • Log success or failure for each device

Prerequisites

Before diving in, make sure you have the following installed:

pip install netmiko pyyaml

You'll also need SSH access to your switches and a basic understanding of Python functions and dictionaries. If you're using a GNS3 or EVE-NG lab, this works perfectly there too.

Step 1: Build the YAML Inventory File

Instead of hardcoding device details into your script, we keep them in a separate YAML file. This makes the script reusable without touching the code.

Create a file called inventory.yaml:

switches:
  - hostname: 192.168.1.101
    username: admin
    password: cisco123
    device_type: cisco_ios
  - hostname: 192.168.1.102
    username: admin
    password: cisco123
    device_type: cisco_ios
  - hostname: 192.168.1.103
    username: admin
    password: cisco123
    device_type: cisco_ios
  - hostname: 192.168.1.104
    username: admin
    password: cisco123
    device_type: cisco_ios
  - hostname: 192.168.1.105
    username: admin
    password: cisco123
    device_type: cisco_ios

vlans:
  - id: 10
    name: SALES
  - id: 20
    name: ENGINEERING
  - id: 30
    name: MANAGEMENT

Step 2: Write the Automation Script

Now create your main script, vlan_deploy.py. Here's the complete working code:

import yaml
import logging
from netmiko import ConnectHandler, NetmikoTimeoutException, NetmikoAuthenticationException

# Configure logging
logging.basicConfig(
    filename="vlan_deploy.log",
    level=logging.INFO,
    format="%(asctime)s - %(levelname)s - %(message)s"
)

def load_inventory(filepath):
    """Load switches and VLAN data from YAML file."""
    with open(filepath, "r") as f:
        return yaml.safe_load(f)

def build_vlan_commands(vlans):
    """Generate IOS VLAN config commands from VLAN list."""
    commands = []
    for vlan in vlans:
        commands.append(f"vlan {vlan['id']}")
        commands.append(f" name {vlan['name']}")
    return commands

def configure_switch(device, commands):
    """Connect to a switch and push configuration commands."""
    hostname = device["hostname"]
    try:
        connection = ConnectHandler(**device)
        output = connection.send_config_set(commands)
        connection.save_config()
        logging.info(f"SUCCESS: {hostname} - VLANs configured.")
        print(f"[OK] {hostname}: Configuration applied.")
        return connection
    except NetmikoTimeoutException:
        logging.error(f"TIMEOUT: {hostname} - Could not reach device.")
        print(f"[FAIL] {hostname}: Connection timed out.")
        return None
    except NetmikoAuthenticationException:
        logging.error(f"AUTH FAIL: {hostname} - Invalid credentials.")
        print(f"[FAIL] {hostname}: Authentication failed.")
        return None

def verify_vlans(connection, hostname, vlans):
    """Verify VLANs exist on the switch after configuration."""
    output = connection.send_command("show vlan brief")
    for vlan in vlans:
        vlan_id = str(vlan["id"])
        if vlan_id in output:
            print(f"  [VERIFIED] VLAN {vlan_id} on {hostname}")
            logging.info(f"VERIFIED: VLAN {vlan_id} present on {hostname}")
        else:
            print(f"  [MISSING] VLAN {vlan_id} NOT found on {hostname}")
            logging.warning(f"MISSING: VLAN {vlan_id} not confirmed on {hostname}")
    connection.disconnect()

def main():
    inventory = load_inventory("inventory.yaml")
    switches = inventory["switches"]
    vlans = inventory["vlans"]
    commands = build_vlan_commands(vlans)

    print(f"\nDeploying VLANs to {len(switches)} switches...\n")

    for switch in switches:
        connection = configure_switch(switch, commands)
        if connection:
            verify_vlans(connection, switch["hostname"], vlans)

    print("\nDeployment complete. Check vlan_deploy.log for details.")

if __name__ == "__main__":
    main()

Understanding the Key Pieces

Error Handling

The script catches two specific Netmiko exceptions: NetmikoTimeoutException for unreachable devices and NetmikoAuthenticationException for bad credentials. This prevents the entire script from crashing if one switch has a problem.

Logging

Every result gets written to vlan_deploy.log with a timestamp. This gives you an audit trail of what changed, on which device, and when. This is essential in production environments.

Verification

After pushing config, we run show vlan brief and check whether each VLAN ID appears in the output. It's a simple but effective sanity check.

Sample Output

Deploying VLANs to 5 switches...

[OK] 192.168.1.101: Configuration applied.
  [VERIFIED] VLAN 10 on 192.168.1.101
  [VERIFIED] VLAN 20 on 192.168.1.101
  [VERIFIED] VLAN 30 on 192.168.1.101
[OK] 192.168.1.102: Configuration applied.
  [VERIFIED] VLAN 10 on 192.168.1.102
...

Deployment complete. Check vlan_deploy.log for details.

What's Next

This netmiko VLAN project is a solid foundation. The natural next step is making it smarter: what if you only push changes when the VLAN doesn't already exist? That's called idempotency, and it's a key concept in professional automation. In the next post, we'll look at how to build idempotent network scripts that check before they change, saving you from duplicate configs and unexpected side effects.

🔧
If you want a more robust SSH client alongside your Python scripts, SecureCRT supports scripting and session management that pairs well with Netmiko-based workflows — especially useful when you need to manually verify or troubleshoot individual devices in your lab. SecureCRT.