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.

SDN architecture: applications at the top talk to a central controller through a northbound REST API; the controller talks to a router and two switches below through southbound APIs. Applications Monitoring Python script Ansible Northbound API REST, JSON Controller (central view and control) Southbound APIs NETCONF, RESTCONF, OpenFlow, SSH R1 SW1 SW2 Devices: data plane (forwarding traffic)
Applications ask the controller for information or changes through the northbound API; the controller programs the devices through southbound APIs.

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() and get_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:

  1. Read-only first. Start with scripts that only collect: show commands, API GET requests, inventory and compliance reports. They are useful on day one and cannot break anything.
  2. 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.
  3. 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.
  4. 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.
  5. 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.