← Back to posts
AI & Automation

Using Claude to Automate Cisco NX-OS Configuration and Operations

NX-OS Automation with Claude

Cisco NX-OS powers the Nexus switching platform — the backbone of most enterprise data centers. Its configuration complexity, especially for VXLAN EVPN fabrics, makes it an ideal target for AI-assisted automation. Claude can generate correct, best-practice NX-OS configurations from plain descriptions, analyze complex show output, and power intelligent fabric management tooling.

This post covers practical automation patterns using the Claude API directly against NX-OS devices via NX-API REST and Netmiko.


Setup

import anthropic
import requests
import json
from netmiko import ConnectHandler

client = anthropic.Anthropic()

def ask_claude(prompt: str, system: str = None) -> str:
    kwargs = {
        "model": "claude-opus-4-5",
        "max_tokens": 3000,
        "messages": [{"role": "user", "content": prompt}]
    }
    if system:
        kwargs["system"] = system
    return client.messages.create(**kwargs).content[0].text

# NX-API helper
def nxapi_call(host: str, username: str, password: str, commands: list[str]) -> dict:
    url = f"https://{host}/ins"
    payload = {
        "ins_api": {
            "version": "1.0",
            "type": "cli_show",
            "chunk": "0",
            "sid": "1",
            "input": " ; ".join(commands),
            "output_format": "json"
        }
    }
    response = requests.post(
        url, json=payload,
        auth=(username, password),
        verify=False,
        timeout=30
    )
    return response.json()

Pattern 1: VXLAN EVPN Leaf Configuration Generator

Generating VXLAN BGP EVPN configuration is error-prone manually. Claude can produce complete, consistent leaf configs from a simple data structure:

def generate_vxlan_leaf_config(leaf_params: dict) -> str:
    prompt = f"""
Generate a complete Cisco NX-OS VXLAN BGP EVPN leaf switch configuration for:

Leaf Parameters:
- Hostname: {leaf_params['hostname']}
- Loopback0 IP (Router-ID/VTEP source): {leaf_params['loopback0']}
- Loopback1 IP (Anycast VTEP): {leaf_params['loopback1']}
- BGP ASN: {leaf_params['bgp_asn']}
- Spine Route Reflectors: {leaf_params['spine_rrs']}
- Underlay Protocol: {leaf_params.get('underlay', 'ISIS')}
- Tenant VRFs: {leaf_params['vrfs']}
- Layer 2 VNIs (VNI: VLAN mapping): {leaf_params['l2_vnis']}

Include:
- Feature enables (nv overlay, bgp, interface-vlan, vn-segment-vlan-based, fabric forwarding)
- ISIS underlay config (or OSPF if specified)
- iBGP EVPN overlay with spine RRs as route-reflector-clients
- NVE interface with ingress-replication BGP
- Distributed anycast gateway with fabric forwarding anycast-gateway-mac
- VRF configs with L3 VNI and EVPN route-targets
- VLAN to VNI mappings
- SVI configs with anycast gateway

Output ONLY NX-OS CLI commands, no explanations.
"""
    return ask_claude(
        prompt,
        system="You are a Cisco data center expert. Generate only correct NX-OS CLI configuration."
    )

# Example usage
config = generate_vxlan_leaf_config({
    "hostname": "leaf-01",
    "loopback0": "10.0.0.1/32",
    "loopback1": "10.1.0.1/32",
    "bgp_asn": "65000",
    "spine_rrs": ["10.0.0.101", "10.0.0.102"],
    "underlay": "ISIS",
    "vrfs": [
        {"name": "TENANT-A", "l3_vni": 50001, "rd": "auto", "rt": "65000:50001"},
        {"name": "TENANT-B", "l3_vni": 50002, "rd": "auto", "rt": "65000:50002"},
    ],
    "l2_vnis": [
        {"vni": 10010, "vlan": 10, "vrf": "TENANT-A"},
        {"vni": 10020, "vlan": 20, "vrf": "TENANT-A"},
        {"vni": 20010, "vlan": 30, "vrf": "TENANT-B"},
    ]
})

print(config)

Pattern 2: NX-OS Show Output Parser via NX-API

Pull structured JSON from NX-API and let Claude make sense of it:

def analyze_fabric_health(host: str, username: str, password: str) -> dict:
    # Pull key fabric state via NX-API
    commands = [
        "show bgp l2vpn evpn summary",
        "show nve peers",
        "show nve vni",
        "show interface nve1",
    ]
    
    raw = nxapi_call(host, username, password, commands)
    
    prompt = f"""
Analyze this NX-OS VXLAN EVPN fabric health data and return JSON with:
- overall_status: "healthy" | "degraded" | "critical"
- issues: list of specific problems found
- vtep_count: number of active VTEP peers
- vni_count: number of active VNIs
- bgp_neighbors_up: count of established BGP EVPN neighbors
- recommendations: list of actions to take

Raw NX-API data:
{json.dumps(raw, indent=2)}

Output ONLY valid JSON.
"""
    return json.loads(ask_claude(prompt))

health = analyze_fabric_health("10.0.0.1", "admin", "password")
print(f"Fabric status: {health['overall_status']}")
for issue in health['issues']:
    print(f"  ⚠️  {issue}")

Pattern 3: VPC Configuration Generator and Validator

vPC misconfiguration is a common source of outages. Claude generates correct config and validates existing setups:

def generate_vpc_config(primary: dict, secondary: dict) -> tuple[str, str]:
    prompt = f"""
Generate Cisco NX-OS vPC configuration for a vPC pair:

Primary Switch:
- Hostname: {primary['hostname']}
- Management IP: {primary['mgmt_ip']}
- vPC domain ID: {primary['vpc_domain']}
- Peer-link interfaces: {primary['peer_link_ports']}
- Keepalive source: {primary['keepalive_src']}
- Keepalive destination: {secondary['keepalive_src']}
- Role priority: 100 (primary wins)

Secondary Switch:
- Hostname: {secondary['hostname']}
- Role priority: 200

Return a JSON object with keys "primary_config" and "secondary_config",
each containing the complete NX-OS vPC configuration block.

Include: feature vpc, vpc domain, peer-link port-channel, keepalive,
peer-gateway, auto-recovery, delay restore timers, ip arp synchronize.

Output ONLY valid JSON.
"""
    result = json.loads(ask_claude(prompt))
    return result['primary_config'], result['secondary_config']

def validate_vpc_consistency(switch1_output: str, switch2_output: str) -> dict:
    prompt = f"""
Compare these two NX-OS 'show vpc' outputs and identify any consistency issues.
Return JSON with:
- consistent: true/false
- mismatches: list of specific parameter mismatches
- risk_level: "low" | "medium" | "high" 
- fix_commands: list of commands to resolve mismatches

Switch 1 output:
{switch1_output}

Switch 2 output:
{switch2_output}

Output ONLY valid JSON.
"""
    return json.loads(ask_claude(prompt))

Pattern 4: Automated Change Window Assistant

Before a maintenance window, Claude helps build the runbook and validates readiness:

def pre_change_checklist(host: str, change_description: str, conn) -> dict:
    # Gather current state
    state_commands = {
        "bgp_summary": "show bgp l2vpn evpn summary",
        "vpc_status": "show vpc",
        "interface_errors": "show interface counters errors | grep -v '0        0        0        0'",
        "nve_peers": "show nve peers",
        "spanning_tree": "show spanning-tree summary",
    }
    
    current_state = {}
    for key, cmd in state_commands.items():
        current_state[key] = conn.send_command(cmd)
    
    prompt = f"""
Pre-change assessment for NX-OS switch {host}.

Planned change: {change_description}

Current device state:
{json.dumps(current_state, indent=2)}

Analyze and return JSON with:
- ready_for_change: true/false
- blockers: list of issues that must be resolved before proceeding
- warnings: list of non-blocking concerns
- baseline_snapshot: key metrics to verify after the change
- rollback_commands: NX-OS commands to revert the change
- estimated_impact: description of traffic impact during change

Output ONLY valid JSON.
"""
    return json.loads(ask_claude(prompt))

device = {"device_type": "cisco_nxos", "host": "10.0.0.1", "username": "admin", "password": "pass"}
with ConnectHandler(**device) as conn:
    assessment = pre_change_checklist(
        "10.0.0.1",
        "Upgrade VXLAN leaf from NX-OS 9.3.8 to 10.2.5",
        conn
    )
    
print(f"Ready: {assessment['ready_for_change']}")
for blocker in assessment['blockers']:
    print(f"  BLOCKER: {blocker}")

Pattern 5: NX-OS Upgrade Readiness Checker

def check_upgrade_readiness(host: str, target_version: str, conn) -> dict:
    # Pull upgrade-relevant data
    commands = {
        "version": "show version",
        "modules": "show module",
        "fex": "show fex",
        "features": "show feature | grep enabled",
        "memory": "show system resources",
        "boot_config": "show boot",
    }
    
    device_data = {}
    for key, cmd in commands.items():
        device_data[key] = conn.send_command(cmd)
    
    prompt = f"""
Assess NX-OS upgrade readiness from current version to {target_version}.

Device data:
{json.dumps(device_data, indent=2)}

Return JSON with:
- upgrade_path: list of intermediate versions if direct upgrade not supported
- pre_upgrade_steps: ordered list of actions before upgrading  
- compatibility_issues: list of features/modules with known issues in {target_version}
- estimated_downtime: string description
- post_upgrade_verification: list of commands to verify success
- rollback_procedure: steps to revert if upgrade fails

Output ONLY valid JSON.
"""
    return json.loads(ask_claude(prompt))

Working with NX-OS Structured Output

NX-OS supports JSON output natively — combine this with Claude for maximum efficiency:

def get_mac_owner(host: str, mac_address: str, username: str, password: str) -> str:
    """Find which port a MAC address is learned on, with context"""
    data = nxapi_call(host, username, password, [
        f"show mac address-table address {mac_address}",
        f"show ip arp | include {mac_address}"
    ])
    
    prompt = f"""
A network engineer is trying to locate MAC address {mac_address}.
Based on this NX-OS data, provide a clear, one-paragraph explanation of:
- Where this MAC is learned (interface, VLAN, VNI if VXLAN)
- What IP address it maps to (if in ARP table)
- Whether it appears to be a local or remote VTEP endpoint

Data: {json.dumps(data, indent=2)}
"""
    return ask_claude(prompt)
// Found this useful? Share it or start a conversation.