Network Automation
Managing networks with code instead of by hand: controllers and SDN, REST APIs and JSON, and tools such as Ansible.
Why automate?
Network automation means using software to configure, check and operate network devices instead of typing commands on each one by hand. Consider adding a virtual local area network (VLAN) to 120 access switches. By hand, that is 120 Secure Shell (SSH) sessions, the same five lines typed 120 times, and a real chance that switch 87 gets VLAN 210 instead of 201. With automation, you describe the change once and a tool applies it everywhere.
- Scale: the effort barely grows with the number of devices.
- Consistency: every device gets exactly the same configuration, generated from the same template.
- Fewer typos: people make small mistakes when repeating a task; a tested script does not get tired.
- Speed: changes and checks that took a day take minutes, which also shortens outages.
- Less configuration drift: over time, quick manual fixes make devices differ from the standard. Automation can compare every device against the intended configuration and report — or correct — the differences.
Automation does not replace network knowledge. A script that pushes a wrong access control list (ACL) to 120 switches breaks 120 switches in seconds; you still need to know what the right configuration is.
Management, control and data planes
To see what automation and controllers change, it helps to split a network device's work into three planes.
| Plane | Job | Examples |
|---|---|---|
| Management plane | Lets people and tools configure and monitor the device | SSH and the command-line interface (CLI), SNMP, NETCONF, REST APIs, syslog |
| Control plane | Decides where traffic should go and builds the tables for that | Open Shortest Path First (OSPF) and Border Gateway Protocol (BGP) building the routing table, Spanning Tree, ARP |
| Data plane | Moves each frame or packet from an input to an output interface, using those tables | MAC table and routing table lookups, applying ACLs, NAT, adding 802.1Q tags |
The management plane is how you reach the device: every SSH login, SNMP poll and API call. The control plane is the device's brain. It runs on the general-purpose CPU, talks to neighbors with routing protocols and decides which paths are best. The data plane (also called the forwarding plane) does the actual work, millions of times per second, usually in specialized chips (application-specific integrated circuits, ASICs) rather than the CPU.
The split explains familiar behavior: a router can keep forwarding traffic while its CPU is busy with a routing update, and a problem with SSH access (management plane) does not interrupt user traffic (data plane).
Controllers and SDN
In traditional networking, every device has its own control plane and its own configuration. Engineers manage them one by one, and the network's overall behavior emerges from hundreds of separate configurations.
Software-defined networking (SDN) centralizes that intelligence in software. A controller holds a view of the whole network and decides how it should behave; the devices mainly forward traffic as instructed. In the pure SDN model the control plane itself moves to the controller. In the controller-based networking that most enterprises run today, devices keep their own control planes, and the controller automates their configuration, monitoring and software from one place. Cisco's Catalyst Center (formerly DNA Center) is one example of such a controller.
The interfaces are named after their position in such a diagram:
- Southbound APIs connect the controller to the devices. Examples are OpenFlow (which programs a switch's forwarding table directly), NETCONF (Network Configuration Protocol, which exchanges Extensible Markup Language (XML) over SSH, usually on port 830), RESTCONF (the same data models over HTTPS) and plain SSH to the CLI. NETCONF and RESTCONF describe configuration with YANG (Yet Another Next Generation) data models, so a tool can read and change it as structured data instead of as text.
- Northbound APIs connect applications and scripts to the controller — usually REST APIs with JSON data. A monitoring system can ask the controller for the health of every device with one request instead of logging in to each.
Controllers in data centers and campus networks often build an overlay: virtual networks (tunnels) running on top of a physical underlay network that only needs simple, stable IP connectivity. Together they form the fabric.
REST APIs
An API (application programming interface) is a defined way for one program to ask another for data or actions. A REST API (representational state transfer) does this over HTTP: every object — a device, an interface, a VLAN — has its own URL, and the HTTP method says what to do with it. REST APIs are stateless: each request carries everything the server needs, including authentication (typically a token in a header), so the server keeps no session between requests.
| CRUD action | HTTP method | Example |
|---|---|---|
| Create | POST |
Add a new VLAN |
| Read | GET |
List the interfaces of a switch |
| Update |
PUT (replace) or PATCH (modify)
|
Change an interface description |
| Delete | DELETE |
Remove a VLAN |
PUT replaces the whole object with what you send;
PATCH changes only the fields you send. The server
answers with a status code that tells you at a glance how it went:
| Code | Meaning |
|---|---|
200 OK |
The request succeeded; the body holds the result. |
201 Created |
A POST created a new object. |
204 No Content |
Success, with no body (common after DELETE).
|
400 Bad Request |
The request itself is wrong, such as invalid JSON. |
401 Unauthorized |
Missing or invalid authentication. |
403 Forbidden |
Authenticated, but not allowed to do this. |
404 Not Found |
No object at that URL. |
500 Internal Server Error |
The server failed while handling a valid request. |
The rule of thumb: 2xx is success, 4xx means the client (you) did something wrong, 5xx means the server has a problem. A request and its response look like this (the controller's address and URL are made up):
GET /api/v1/devices/switch1/interfaces HTTP/1.1 Host: controller.example.com Accept: application/json Authorization: Bearer <token>
HTTP/1.1 200 OK Content-Type: application/json
Data formats: JSON and YAML
JSON
JSON (JavaScript Object Notation) is the usual format of REST API
bodies. It has objects in { } with
"key": value pairs, arrays in [ ], strings
in double quotes, numbers, true, false and
null. Whitespace does not matter, but a missing comma
or a trailing comma makes the whole document invalid.
{
"device": "Switch1",
"interfaces": [
{
"name": "GigabitEthernet0/2",
"description": "Printer 2nd floor",
"enabled": true,
"oper_status": "down",
"vlan": 30
}
]
}
Read it from the outside in: an object with two keys;
interfaces holds an array of objects, one per
interface. In Python, json.loads() turns this text into
dictionaries and lists — see
JSON files
in the Python topic.
Checking interfaces from an API response
This script works on the body of a response like the one above. It reports interfaces that are not up, and tells an interface that was shut down on purpose apart from one that is enabled but has no link — only the second needs attention. The response is a string in the code, so the example contacts nothing.
import json
# The body of a response to GET /api/v1/devices/switch1/interfaces,
# pasted here as a string so the example needs no network.
RESPONSE_BODY = """
{
"device": "Switch1",
"interfaces": [
{"name": "GigabitEthernet0/1", "description": "Uplink to R1",
"enabled": true, "oper_status": "up", "vlan": null},
{"name": "GigabitEthernet0/2", "description": "Printer 2nd floor",
"enabled": true, "oper_status": "down", "vlan": 30},
{"name": "GigabitEthernet0/3", "description": "",
"enabled": false, "oper_status": "down", "vlan": 999},
{"name": "GigabitEthernet0/4", "description": "Access point AP-07",
"enabled": true, "oper_status": "up", "vlan": 10}
]
}
"""
data = json.loads(RESPONSE_BODY)
print(f"{data['device']}: {len(data['interfaces'])} interfaces")
for interface in data["interfaces"]:
if interface["oper_status"] == "up":
continue
if interface["enabled"]:
problem = "DOWN - enabled but no link, investigate"
else:
problem = "shut down on purpose (administratively down)"
label = interface["description"] or "(no description)"
print(f" {interface['name']:20} {label:20} {problem}")
Switch1: 4 interfaces GigabitEthernet0/2 Printer 2nd floor DOWN - enabled but no link, investigate GigabitEthernet0/3 (no description) shut down on purpose (administratively down)
JSON true, false and
null become Python True,
False and None. In a real script the text
would come from an HTTP library such as requests; the
parsing and checks stay exactly the same.
YAML
YAML (YAML Ain't Markup Language) holds the same kind of data as
JSON but is written for people: no braces or quotes needed,
structure by indentation, and # comments. Lists use a
leading -. Automation tools such as Ansible use it for
inventories and playbooks. The same interface in YAML:
device: Switch1
interfaces:
- name: GigabitEthernet0/2
description: Printer 2nd floor # free text
enabled: true
oper_status: down
vlan: 30
Infrastructure as code
Infrastructure as code (IaC) means describing the desired state of infrastructure — VLANs, interface settings, firewall rules, servers — in text files that a tool applies. The files, not the devices, become the source of truth. Most IaC tools are declarative (you describe what should exist, not the commands to get there) and idempotent (running them twice gives the same result as once: if the VLAN already exists, nothing changes). The whole approach, for servers and cloud resources too, is the subject of Infrastructure as Code & Automation.
Ansible
Ansible is an open-source automation tool that is especially popular for networks because it is agentless: nothing needs to be installed on the devices. A control node (a Linux machine with Ansible) connects to them over SSH, or through an API, and pushes the changes. It reads two kinds of YAML file:
- An inventory: which devices exist, in which groups, and how to connect to them.
- A playbook: one or more plays, each a list of tasks run against a group of hosts. Each task calls a module that knows how to do one thing on one platform.
# inventory.yml
access_switches:
hosts:
switch1:
ansible_host: 192.168.1.11
switch2:
ansible_host: 192.168.1.12
vars:
ansible_connection: ansible.netcommon.network_cli
ansible_network_os: cisco.ios.ios
ansible_user: netadmin
# vlans.yml
---
- name: Ensure standard VLANs exist on access switches
hosts: access_switches
gather_facts: false
tasks:
- name: Merge VLAN definitions
cisco.ios.ios_vlans:
config:
- vlan_id: 10
name: USERS
- vlan_id: 20
name: VOICE
state: merged
- name: Save the configuration if it changed
cisco.ios.ios_config:
save_when: modified
The play targets the group access_switches. The first
task uses the cisco.ios.ios_vlans module: with
state: merged it adds VLANs 10 and 20 where they are
missing and leaves everything else alone; on a switch where they
already exist it reports "ok" and changes nothing. The second task
saves the running configuration only if the running configuration
differs from the saved startup configuration. Running
ansible-playbook -i inventory.yml vlans.yml --check --diff
first shows what would change without changing it, for
modules that support check mode. The password is not in these files:
it is entered at run time or kept encrypted with
Ansible Vault. The same tool for Linux servers:
Ansible Basics.
Terraform, Puppet and Chef
- Terraform is a declarative IaC tool that keeps a state file of what it has built and uses providers to talk to APIs. It is strongest in cloud infrastructure (virtual networks, security groups, load balancers), and providers exist for some network platforms.
- Puppet and Chef are older configuration management tools, traditionally agent-based: software on each managed server pulls its configuration from a central server. That suits servers better than network devices, which usually cannot run such agents. Puppet uses its own declarative language; Chef uses Ruby.
Version control for configurations
Once configurations, templates and playbooks are text files, they belong in version control with Git, exactly like program code — see Version Control with Git. That gives you a history of every change (who, when, why), an easy way back to the last working version, and a review step: a change is proposed as a pull request, a colleague reviews the diff, and only merged changes are deployed. Many teams also back up the running configuration of every device into a repository each night, so a diff shows any manual change made since.
Python libraries for network engineers
Python is the common language of network automation. You will meet these libraries by name:
- Netmiko: logs in over SSH to many vendors' devices, sends CLI commands and returns the text output. The simplest step up from typing commands by hand.
-
NAPALM (Network Automation and Programmability
Abstraction Layer with Multivendor support): one set of functions
(such as
get_facts()andget_interfaces()) that works the same across vendors, returning structured data instead of text, plus configuration replace and compare. - ncclient: a NETCONF client, for devices that offer NETCONF with YANG models.
A typical Netmiko script is only a few lines. It is shown here for
recognition, not run, because it needs a real device and the
third-party netmiko package:
import os
from netmiko import ConnectHandler
device = {
"device_type": "cisco_ios",
"host": "192.168.1.11",
"username": "netadmin",
"password": os.environ["NET_PASSWORD"], # never hard-code credentials
}
with ConnectHandler(**device) as connection:
output = connection.send_command("show ip interface brief")
print(output)
ConnectHandler opens the SSH session,
send_command() runs one read-only command and returns
its text, and the with block closes the session.
Parsing that text is the hard part — which is why APIs that return
JSON, or libraries that return structured data, are preferred where
the devices support them.
A safe way to start
Automation multiplies both good and bad changes, so build trust in small steps:
-
Read-only first. Start with scripts that only
collect:
showcommands, APIGETrequests, inventory and compliance reports. They are useful on day one and cannot break anything. - Use a lab or sandbox. Try changes on virtual devices (for example in Cisco Modeling Labs, Containerlab or a vendor's free online sandbox) before production.
- Review and version everything. Keep code in Git, have a colleague review each change, and use check or dry-run modes to see the effect first.
- Start small in production. Run a change on one device, then a few, then the rest, inside a normal change window and with a rollback plan.
- Protect credentials. Use a dedicated automation account with only the rights it needs, and keep passwords and tokens in a vault or environment variables — never in the script or the repository.