Breaking the Vendor Lock in Network Automation: A Pure Python Architecture
Server automation is largely solved, but networks remain manual due to multi-vendor complexity. Here’s a Python-based solution to automate network operations.
Join the DZone community and get the full member experience.
Join For FreeIn the world of Infrastructure as Code (IaC), servers are a solved problem. We spin up thousands of VMs with a single script. But the network layer? That often remains a manual bottleneck.
The reason is the “Multi-Vendor Trap.” Enterprise networks are rarely homogeneous. They are a patchwork of routers, switches, and load balancers from different vendors (Cisco, Juniper, F5), each with its own proprietary CLI syntax. This fragmentation makes standard automation difficult, leading to long lead times (often weeks) just to open a VLAN or update a firewall rule.
Based on recent case studies in large-scale financial systems, this article outlines a proven architecture for multi-vendor network automation. By abstracting vendor specifics into standardized Python functions, engineering teams can reduce operational lead times by 50% and cut manual effort by 80%.
The Problem: The “Human Middleware”
In traditional network operations, the engineer acts as the middleware.
- Request: A developer asks for a new subnet.
- Translation: The engineer translates this generic request into vendor-specific commands (e.g., Cisco IOS vs. Junos OS).
- Execution: The engineer SSHs into each device and pastes the commands.
- Validation: The engineer runs
showcommands to verify the state.
This process is slow, error-prone, and heavily dependent on individual expertise. If the only engineer who knows the F5 syntax is on vacation, the deployment stalls.
The Architecture: Abstraction via Python (Nornir)
The solution is to decouple the intent (what we want to do) from the implementation (how we do it on specific hardware).
While tools like Ansible use YAML, a pure Python approach using Nornir allows for more robust debugging, type checking, and complex logic handling.
Layer 1: The Standardized Input (Intent)
Instead of vague ticket descriptions, we define the desired state as a structured Python object (dictionary or data class). This acts as the “contract” for the automation.
request_payload.py
# The Intent: Vendor-Agnostic
network_request = {
"type": "vlan_addition",
"params": {
"vlan_id": 100,
"name": "app_tier_01"
},
"targets": ["switch_core_01", "switch_dist_01"]
}
Layer 2: The “Translator” Function
This is the core architectural pattern. We write a Python task that acts as a translator. The script detects the device platform at runtime and injects the correct syntax.
automation_engine.py
from nornir import InitNornir
from nornir_netmiko.tasks import netmiko_send_config
def configure_vlan(task, vlan_id, vlan_name):
"""
The Abstraction Layer:
Translates generic intent into vendor-specific commands.
"""
config_cmds = []
# Logic for Cisco IOS
if task.host.platform == "cisco_ios":
config_cmds = [
f"vlan {vlan_id}",
f"name {vlan_name}"
]
# Logic for Juniper Junos
elif task.host.platform == "junos":
config_cmds = [
f"set vlans {vlan_name} vlan-id {vlan_id}"
]
# Execution
if config_cmds:
task.run(task=netmiko_send_config, config_commands=config_cmds)
# 1. Initialize Inventory
nr = InitNornir(config_file="config.yaml")
# 2. Filter Targets based on Request
targets = nr.filter(name__in=network_request["targets"])
# 3. Execute the Task across all targets in parallel
result = targets.run(
task=configure_vlan,
vlan_id=network_request["params"]["vlan_id"],
vlan_name=network_request["params"]["name"]
)
This abstraction allows you to run the same script across a mixed fleet. If you swap a Cisco switch for an Arista one, you simply update the inventory platform variable; the automation logic handles the rest.
Validation Design: The “Health Check” Pattern
Automating the change is only half the battle. The biggest risk in network automation is breaking the “ecosystem.” A firewall change might succeed technically but break the application heartbeat.
We implement a pre-check / post-check pattern using Python’s native comparison capabilities.
- Snapshot: Before the change, run Python scripts to capture the current state of routing tables.
- Execution: Apply the configuration change.
- Validation: Run the capture again and diff the results programmatically.
Python validation logic:
def validate_routes(pre_change_routes, post_change_routes):
"""
Compares routing tables sets to ensure no routes were lost.
"""
missing_routes = pre_change_routes - post_change_routes
if missing_routes:
raise Exception(f"CRITICAL: Routes lost after change: {missing_routes}")
else:
print("SUCCESS: Network state is healthy.")
The Workflow: From Ticket to Trunk
The final architecture integrates this logic into a CI/CD pipeline (e.g., Azure DevOps or Jenkins).

Results and ROI
Implementing this multi-vendor abstraction strategy yields significant operational improvements:
- Lead time reduction: Network delivery time dropped by 50% (from 10 days to 5 days).
- Effort reduction: Manual engineering hours reduced by 86%.
- Standardization: The codebase becomes the documentation. “Tribal knowledge” is converted into Git repositories, eliminating dependency on specific individuals.
Conclusion
Network automation in a multi-vendor environment is not about writing a separate script for every device. It is about architectural abstraction.
By treating network changes as software (Python functions) and validation as unit tests, you can break vendor lock-in and build a network that moves as fast as your servers.
Opinions expressed by DZone contributors are their own.
Comments