← Kỹ sư mạng← Network Engineer
Kỹ sư mạngNetwork Engineer19 Th7, 2026Jul 19, 202622 phút đọc19 min read

Tự động hóa mạngNetwork Automation

Thuộc bộ kiến thức Network Engineer Roadmap.

Tổng quan

Network automation (tự động hóa mạng) là việc dùng phần mềm — script, API, dữ liệu có cấu trúc và các công cụ — để cấu hình, quản lý, kiểm thử và vận hành thiết bị cùng dịch vụ mạng, thay vì gõ lệnh bằng tay vào CLI trên từng thiết bị một.

Suốt nhiều thập kỷ, giao diện chính của network engineer là terminal: SSH vào một switch, dán một khối config, save, rồi chuyển sang thiết bị tiếp theo. Cách làm đó không trụ được khi quy mô tăng lên. Khi bạn có 5 thiết bị, bạn có thể đăng nhập từng cái. Khi có 500, 5.000, hoặc một fleet trải rộng qua các cloud VPC và data center on-prem, cấu hình thủ công trở nên chậm, thiếu nhất quán và nguy hiểm — chỉ một dòng ACL gõ nhầm hay một subnet mask sai lúc 2 giờ sáng có thể black-hole toàn bộ traffic của cả một region.

Những lý do để automate rất cụ thể:

Động lựcThủ công (CLI)Automated
ConsistencyMỗi thiết bị drift một kiểu; config “snowflake” không cái nào giống cái nàoMột template render ra config giống hệt nhau ở mọi nơi
Tốc độVài phút mỗi thiết bị, tuần tựHàng trăm thiết bị song song, tính bằng giây
Ít lỗi hơnGõ sai, sót bước, lỗi copy-pasteCode idempotent, đã test, đã review
ScaleCông sức tuyến tính — 10× thiết bị = 10× côngCông sức gần như không đổi bất kể fleet lớn cỡ nào
Auditability”Ai đổi cái gì?” tan biến trong trí nhớMọi thay đổi là một Git commit có author và diff
RepeatabilityRunbook nằm trong wiki, thực thi không nhất quánCùng một playbook, cùng kết quả, mọi lần

Xu hướng của ngành là dịch chuyển từ CLI sang Infrastructure as Code (IaC): trạng thái mạng được mô tả trong các file text (YAML, HCL, Jinja2 template, YANG model), lưu trong version control, review qua pull request, và áp dụng bằng công cụ. Tư duy này — đối xử với mạng theo cách các đội phần mềm đối xử với ứng dụng — thường được gọi là NetDevOps: mang văn hóa và công cụ DevOps (Git, CI/CD, testing, code review, một source of truth duy nhất) vào network engineering.

Ghi chú này đi từ nền tảng (Linux, shell, API) qua các công cụ cốt lõi (Python, Ansible, Terraform) đến các thực hành vận hành (CI/CD, version control, drift detection, source of truth) giúp automation trở nên đáng tin cậy trong production. Nó gắn chặt với các ghi chú DevOps về Infrastructure as CodeConfiguration Management, và giả định bạn đã quen với core protocols cùng cloud networking ở các phần trước.

Kiến thức nền tảng

Linux và shell: nền tảng không thể thiếu

Gần như mọi công cụ automation đều chạy trên Linux, phần lớn network operating system bên dưới là Linux (Cumulus, SONiC, Arista EOS, Cisco NX-OS, IOS-XR đều expose một Linux shell), và mọi CI runner cùng container đều là một máy Linux. Bạn không cần phải là kernel hacker, nhưng bạn phải thoải mái với:

Một ví dụ nhanh — backup running config của mọi thiết bị trong một danh sách, song song:

#!/usr/bin/env bash
# backup-configs.sh — pull running-config from each device over SSH
set -euo pipefail

DEVICES_FILE="devices.txt"        # one host per line
BACKUP_DIR="backups/$(date +%F)"
mkdir -p "$BACKUP_DIR"

while read -r host; do
  [[ -z "$host" || "$host" == \#* ]] && continue
  echo "Backing up $host ..."
  ssh -o ConnectTimeout=10 "netadmin@${host}" 'show running-config' \
    > "${BACKUP_DIR}/${host}.cfg" &
done < "$DEVICES_FILE"

wait   # let all background SSH jobs finish
echo "Done. Configs saved to ${BACKUP_DIR}/"

Đây là automation ở mức đơn giản nhất, và nó đã cho bạn các snapshot có ngày tháng, có thể đưa vào version control của mọi thiết bị.

API cho networking

CLI được thiết kế cho con người; API (Application Programming Interface) được thiết kế cho máy. Thiết bị mạng hiện đại expose một hoặc nhiều interface lập trình được, trả về dữ liệu có cấu trúc (JSON hoặc XML) thay vì text tự do như lệnh show xuất ra. Dữ liệu có cấu trúc chính là điểm mấu chốt — bạn không còn phải viết những regular expression mong manh để cào một giá trị ra khỏi output CLI; bạn hỏi interfaces.GigabitEthernet0/1.oper-status và nhận về một field sạch sẽ.

Các interface chính bạn sẽ gặp:

InterfaceTransportEncodingData modelDùng điển hình
REST / RESTCONFHTTP(S)JSON / XMLYANG (RESTCONF)CRUD trên URL resource; dễ dùng từ mọi ngôn ngữ
NETCONFSSH (port 830)XMLYANGConfig management chắc chắn, transaction, candidate/commit
gNMIgRPC trên HTTP/2ProtobufYANG (OpenConfig)Streaming telemetry + config; hiệu năng cao
SNMPUDP (161/162)BER (ASN.1)MIB (OID)Monitoring legacy, trap; poll counter
Vendor REST (vd. Meraki, DNAC)HTTP(S)JSONDo vendor định nghĩaFabric quản lý qua controller/cloud

YANG data model

YANG (RFC 7950) là một ngôn ngữ modeling mô tả cấu trúc của configuration và operational state — những field nào tồn tại, kiểu của chúng, ràng buộc và phân cấp — độc lập với wire encoding. NETCONF, RESTCONF và gNMI đều mang dữ liệu được định hình bởi YANG model. Hai họ đáng chú ý:

SNMP so với API cho cấu hình

SNMP tuyệt vời trong việc đọc counter và gửi trap, nhưng nó chưa bao giờ giỏi ghi cấu hình — SNMP SET cồng kềnh, hỗ trợ config kém, và ngữ nghĩa transaction yếu. Đồng thuận của ngành là: dùng SNMP (hoặc tốt hơn là gNMI streaming telemetry) cho monitoring, và dùng NETCONF/RESTCONF/gNMI hay một REST API cho cấu hình. SNMP là legacy đối với config; hãy coi nó chủ yếu để đọc.

Idempotency: mô hình tư duy cốt lõi

Khái niệm quan trọng nhất trong config automation là idempotency (tính lũy đẳng): áp dụng cùng một thao tác nhiều lần cho ra cùng kết quả như áp dụng một lần, và chỉ thực hiện thay đổi khi trạng thái hiện tại khác với trạng thái mong muốn.

Một script CLI imperative chạy interface Gi0/1 / ip address 10.0.0.1 255.255.255.0 sẽ phát lại những lệnh đó ở mỗi lần chạy bất kể chúng đã có sẵn hay chưa. Một công cụ idempotent thay vào đó đọc trạng thái hiện tại, so sánh với desired state được khai báo, và chỉ phát lệnh khi cần — báo changed=0 khi thiết bị đã đúng. Idempotency là thứ khiến việc chạy automation lặp lại nhiều lần (vd. ở mỗi lần chạy CI) trở nên an toàn mà không gây xáo trộn, và nó là nền tảng của drift detection bàn ở phần sau.

Khái niệm chính

Python cho network automation

Python là ngôn ngữ chung của network automation: dễ đọc, đầy đủ pin sẵn, và được hậu thuẫn bởi một hệ sinh thái thư viện phong phú cài qua pip (thường vào một virtual environment riêng cho từng project). Các thư viện chính:

Thư việnLàm gìCấp độ
NetmikoSSH tới thiết bị mạng, gửi lệnh CLI, xử lý prompt/paging của vendorCào màn hình CLI
NAPALMAPI trung lập vendor: get_facts, get_interfaces, config diff/merge/replace/rollbackCó cấu trúc, đa vendor
NornirFramework automation thuần Python: inventory + task runner song song (dùng Netmiko/NAPALM làm plugin)Orchestration
ncclientThư viện NETCONF client (XML/RPC trên SSH)NETCONF
ScapyTạo, gửi, sniff và mổ xẻ packet ở mọi layerTest cấp packet
pyATS / GenieFramework test/validation của Cisco với parser có cấu trúcTesting
requestsHTTP client tổng quát cho mọi REST/RESTCONF APIREST

Một ví dụ Netmiko nhỏ, thực tế — kết nối tới một switch, push một VLAN, rồi đọc lại:

#!/usr/bin/env python3
"""Create a VLAN on a Cisco IOS switch and verify it, using Netmiko."""
from netmiko import ConnectHandler

device = {
    "device_type": "cisco_ios",
    "host": "192.0.2.10",
    "username": "netadmin",
    "password": "s3cret",          # in practice: read from a vault / env var
    "secret": "enablepass",        # enable-mode password
}

vlan_id = 42
vlan_name = "AUTOMATION-LAB"

with ConnectHandler(**device) as conn:
    conn.enable()                                  # enter privileged EXEC

    # Idempotent-ish: send_config_set only changes what it needs to
    config_commands = [
        f"vlan {vlan_id}",
        f"name {vlan_name}",
    ]
    output = conn.send_config_set(config_commands)
    print(output)

    conn.save_config()                             # write mem

    # Read it back as verification
    result = conn.send_command("show vlan brief", use_textfsm=True)
    print(result)   # with TextFSM, this is structured data (list of dicts)

Cờ use_textfsm=True đáng chú ý: nó cho output CLI thô đi qua một template TextFSM để bạn nhận về một list các dictionary thay vì một khối text — một cây cầu thực dụng từ cào màn hình hướng tới dữ liệu có cấu trúc khi chưa có API thật.

Một ví dụ NAPALM cho thấy lợi thế đa vendor, có cấu trúc:

import napalm

driver = napalm.get_network_driver("eos")   # or "ios", "junos", "nxos_ssh"
device = driver(hostname="192.0.2.20", username="netadmin", password="s3cret")

device.open()
facts = device.get_facts()                   # same keys on every platform
print(facts["hostname"], facts["os_version"], facts["uptime"])

interfaces = device.get_interfaces()         # structured dict, not text
for name, data in interfaces.items():
    state = "up" if data["is_up"] else "down"
    print(f"{name:20} {state}")

device.close()

Ansible cho thiết bị mạng

Ansible là công cụ configuration management được dùng rộng rãi nhất cho mạng. Các đặc tính định danh nó cho công việc mạng:

Một inventory tối giản (inventory.yml):

all:
  children:
    ios_switches:
      hosts:
        sw1: { ansible_host: 192.0.2.10 }
        sw2: { ansible_host: 192.0.2.11 }
      vars:
        ansible_network_os: cisco.ios.ios
        ansible_connection: network_cli
        ansible_user: netadmin

Một playbook thực tế (configure-vlans.yml) cấu hình VLAN, một interface, rồi save — theo cách idempotent:

---
- name: Configure access VLANs on IOS switches
  hosts: ios_switches
  gather_facts: false

  vars:
    vlans:
      - { id: 42, name: AUTOMATION-LAB }
      - { id: 50, name: VOICE }

  tasks:
    - name: Ensure VLANs exist
      cisco.ios.ios_vlans:
        config: "{{ vlans | map('combine', {'state': 'active'}) | list }}"
        state: merged          # merged = idempotent add, no wipe

    - name: Configure access port Gi0/1 into VLAN 42
      cisco.ios.ios_l2_interfaces:
        config:
          - name: GigabitEthernet0/1
            mode: access
            access:
              vlan: 42
        state: merged

    - name: Save running-config to startup-config
      cisco.ios.ios_config:
        save_when: modified     # only writes mem if something changed

    - name: Verify VLAN 42 is present
      cisco.ios.ios_command:
        commands: show vlan id 42
      register: vlan_check

    - name: Show verification output
      ansible.builtin.debug:
        var: vlan_check.stdout_lines

Chạy nó bằng ansible-playbook -i inventory.yml configure-vlans.yml. Ở lần chạy đầu Ansible báo changed; chạy lại lần nữa nó báo ok với changed=0 — đó là idempotency trong thực tế. Từ khóa state: merged là động từ idempotent: nó thêm/cập nhật những gì bạn khai báo mà không xóa phần còn lại của config (đối lập với replaced hay overridden).

Terraform và Infrastructure as Code

Nơi Ansible tỏa sáng là configuration management các thiết bị đã tồn tại, còn Terraform tỏa sáng ở provisioning — khai báo và tạo ra chính hạ tầng. Trong networking điều này thường có nghĩa là tài nguyên cloud networking: VPC/VNet, subnet, route table, security group/firewall rule, load balancer, DNS zone và record, VPN gateway, và Transit Gateway (xem cloud networking).

Terraform là:

Một snippet thực tế — một AWS VPC với subnet, một security group và một DNS record:

terraform {
  required_providers {
    aws = { source = "hashicorp/aws", version = "~> 5.0" }
  }
}

provider "aws" {
  region = "ap-southeast-1"
}

resource "aws_vpc" "main" {
  cidr_block           = "10.20.0.0/16"
  enable_dns_hostnames = true
  tags = { Name = "prod-vpc" }
}

resource "aws_subnet" "app" {
  vpc_id            = aws_vpc.main.id
  cidr_block        = "10.20.1.0/24"
  availability_zone = "ap-southeast-1a"
  tags = { Name = "prod-app-subnet" }
}

resource "aws_security_group" "web" {
  name   = "web-sg"
  vpc_id = aws_vpc.main.id

  ingress {
    description = "HTTPS from anywhere"
    from_port   = 443
    to_port     = 443
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }
}

resource "aws_route53_record" "app" {
  zone_id = var.hosted_zone_id
  name    = "app.example.com"
  type    = "A"
  ttl     = 300
  records = ["10.20.1.10"]
}

variable "hosted_zone_id" { type = string }

Workflow là terraform initterraform plan (hiển thị diff chính xác, một lần chạy thử) → terraform apply (thực thi nó). Bước plan là lưới an toàn: bạn review chính xác những gì sẽ được tạo, đổi hay hủy trước khi bất cứ điều gì xảy ra — tương đương với code review cho hạ tầng. Xem ghi chú DevOps Infrastructure as Code để hiểu sâu hơn về state, module và remote backend.

Configuration management so với provisioning, và drift detection

Hai từ này mô tả hai công việc khác nhau và các công cụ phản ánh sự phân chia đó:

Ranh giới đôi khi mờ đi — Ansible có thể provision tài nguyên cloud, Terraform có thể push một số config — nhưng mô hình tư duy vẫn đúng: provision bằng Terraform, configure bằng Ansible là một sự phân chia phổ biến, rõ ràng.

Configuration drift là khi trạng thái thực đang chạy của thiết bị lệch khỏi trạng thái dự định được định nghĩa trong code của bạn — ai đó thực hiện một thay đổi khẩn cấp ở CLI, một bản “tạm thời” thủ công không bao giờ được gỡ, hay một thiết bị reboot về config cũ. Drift là kẻ thù của một mạng đáng tin cậy. Automation cho bạn hai cách chống lại nó:

CI/CD, version control, và source of truth

Mảnh ghép cuối cùng là đối xử với config mạng theo cách các đội phần mềm đối xử với code — trái tim của cách tiếp cận NetDevOps.

Vòng lặp NetDevOps đầu-cuối: NetBox (intent) → Jinja2/template → Git (PR + review) → CI (lint + test) → Ansible/Terraform (apply) → thiết bị → telemetry/plan (verify + phát hiện drift) → quay về intent.

Bảng so sánh công cụ

Công cụViệc chínhNgôn ngữMô hình agentParadigm cấu hìnhHợp nhất với
Bash / shellKeo dán, loop nhanhBashAgentless (SSH)ImperativeScript một lần, backup, keo orchestration
NetmikoAutomation CLI qua SSHPythonAgentless (SSH)ImperativeCào màn hình, push CLI tới mọi vendor
NAPALMAPI có cấu trúc đa vendorPythonAgentless (SSH/API)Gần declarative (config replace)Getter xuyên vendor, replace/rollback config an toàn
NornirFramework automationPython (thuần)AgentlessImperative (bạn code task)Scale task Python trên inventory lớn
AnsibleConfiguration managementYAML (+ module Python)Agentless (SSH/API)Declarative, idempotentConfig fleet, playbook, hỗ trợ vendor rộng
TerraformProvisioning (IaC)HCLAgentless (API)Declarative, dựa trên stateCloud VPC, DNS, firewall rule, load balancer
SNMPMonitoring/polling(qua lib)Agent (SNMP daemon)Chủ yếu đọcCounter, trap (config legacy)
gNMI / OpenConfigTelemetry + configProtobuf/gRPCAgentlessDeclarative (YANG)Streaming telemetry, thiết bị hiện đại quy mô lớn

Best Practices

Tài liệu tham khảo

Part of the Network Engineer Roadmap knowledge base.

Overview

Network automation is the practice of using software — scripts, APIs, structured data, and tooling — to configure, manage, test, and operate network devices and services instead of typing commands by hand into a CLI, one box at a time.

For decades the network engineer’s primary interface was the terminal: SSH into a switch, paste a block of config, save, move on to the next device. That workflow does not survive contact with scale. When you have 5 devices you can log in to each one. When you have 500, or 5,000, or a fleet spread across cloud VPCs and on-prem data centres, manual configuration becomes slow, inconsistent, and dangerous — a single fat-fingered ACL or a subnet mask typed wrong at 2 a.m. can black-hole traffic for an entire region.

The reasons to automate are concrete:

DriverManual (CLI)Automated
ConsistencyEach device drifts; “snowflake” configs no two alikeOne template renders identical config everywhere
SpeedMinutes per device, serialHundreds of devices in parallel, seconds
Fewer errorsHuman typos, missed steps, copy-paste mistakesIdempotent, tested, reviewed code
ScaleLinear effort — 10× devices = 10× workNear-constant effort regardless of fleet size
Auditability”Who changed what?” lost in memoryEvery change is a Git commit with an author and diff
RepeatabilityRunbooks in a wiki, executed inconsistentlySame playbook, same result, every time

The trajectory of the industry is a move from the CLI to Infrastructure as Code (IaC): network state is described in text files (YAML, HCL, Jinja2 templates, YANG models), stored in version control, reviewed via pull requests, and applied by tooling. This mindset — treating the network the way software teams treat applications — is often called NetDevOps: bringing DevOps culture and tooling (Git, CI/CD, testing, code review, a single source of truth) to network engineering.

This note builds up from the foundations (Linux, shell, APIs) through the core tools (Python, Ansible, Terraform) to the operational practices (CI/CD, version control, drift detection, source of truth) that make automation reliable in production. It pairs closely with the DevOps notes on Infrastructure as Code and Configuration Management, and assumes familiarity with the core protocols and cloud networking covered earlier.

Fundamentals

Linux and the shell: the non-negotiable foundation

Almost every automation tool runs on Linux, most network operating systems are Linux under the hood (Cumulus, SONiC, Arista EOS, Cisco NX-OS, IOS-XR all expose a Linux shell), and every CI runner and container is a Linux box. You do not need to be a kernel hacker, but you must be comfortable with:

A quick example — back up the running config of every device in a list, in parallel:

#!/usr/bin/env bash
# backup-configs.sh — pull running-config from each device over SSH
set -euo pipefail

DEVICES_FILE="devices.txt"        # one host per line
BACKUP_DIR="backups/$(date +%F)"
mkdir -p "$BACKUP_DIR"

while read -r host; do
  [[ -z "$host" || "$host" == \#* ]] && continue
  echo "Backing up $host ..."
  ssh -o ConnectTimeout=10 "netadmin@${host}" 'show running-config' \
    > "${BACKUP_DIR}/${host}.cfg" &
done < "$DEVICES_FILE"

wait   # let all background SSH jobs finish
echo "Done. Configs saved to ${BACKUP_DIR}/"

This is automation at its simplest, and it already gives you dated, version-controllable snapshots of every device.

APIs for networking

The CLI was designed for humans; APIs (Application Programming Interfaces) are designed for machines. Modern network devices expose one or more programmatic interfaces that return structured data (JSON or XML) instead of the free-form text a show command emits. Structured data is the whole point — you no longer have to write brittle regular expressions to scrape a value out of CLI output; you ask for interfaces.GigabitEthernet0/1.oper-status and get back a clean field.

The main interfaces you will meet:

InterfaceTransportEncodingData modelTypical use
REST / RESTCONFHTTP(S)JSON / XMLYANG (RESTCONF)CRUD over resource URLs; easy from any language
NETCONFSSH (port 830)XMLYANGRobust config management, transactions, candidate/commit
gNMIgRPC over HTTP/2ProtobufYANG (OpenConfig)Streaming telemetry + config; high performance
SNMPUDP (161/162)BER (ASN.1)MIBs (OIDs)Legacy monitoring, traps; polling counters
Vendor REST (e.g. Meraki, DNAC)HTTP(S)JSONVendor-definedController/cloud-managed fabrics

YANG data models

YANG (RFC 7950) is a modelling language that describes the structure of configuration and operational state — what fields exist, their types, constraints, and hierarchy — independently of the wire encoding. NETCONF, RESTCONF, and gNMI all carry data shaped by YANG models. Two families matter:

SNMP vs API for configuration

SNMP is excellent at reading counters and sending traps, but it was never good at writing configuration — SNMP SET is clunky, poorly supported for config, and has weak transactional semantics. The industry consensus is: use SNMP (or better, gNMI streaming telemetry) for monitoring, and use NETCONF/RESTCONF/gNMI or a REST API for configuration. SNMP is legacy for config; treat it as read-mostly.

Idempotency: the core mental model

The single most important concept in configuration automation is idempotency: applying the same operation multiple times produces the same result as applying it once, and only makes a change when the current state differs from the desired state.

An imperative CLI script that runs interface Gi0/1 / ip address 10.0.0.1 255.255.255.0 will re-issue those commands every run whether or not they are already in place. An idempotent tool instead reads the current state, compares it to the declared desired state, and issues commands only if needed — reporting changed=0 when the device is already correct. Idempotency is what makes it safe to run your automation repeatedly (e.g. on every CI run) without causing churn, and it is the foundation of drift detection discussed later.

Key Concepts

Python for network automation

Python is the lingua franca of network automation: readable, batteries-included, and backed by a rich ecosystem of libraries installed via pip (usually into a per-project virtual environment). The key libraries:

LibraryWhat it doesLevel
NetmikoSSH to network devices, send CLI commands, handle vendor prompts/pagingScreen-scraping the CLI
NAPALMVendor-agnostic API: get_facts, get_interfaces, config diff/merge/replace/rollbackStructured, multi-vendor
NornirPure-Python automation framework: inventory + parallel task runner (uses Netmiko/NAPALM as plugins)Orchestration
ncclientNETCONF client library (XML/RPC over SSH)NETCONF
ScapyCraft, send, sniff, and dissect packets at any layerPacket-level testing
pyATS / GenieCisco’s test/validation framework with structured parsersTesting
requestsGeneric HTTP client for any REST/RESTCONF APIREST

A small, real Netmiko example — connect to a switch, push a VLAN, and read it back:

#!/usr/bin/env python3
"""Create a VLAN on a Cisco IOS switch and verify it, using Netmiko."""
from netmiko import ConnectHandler

device = {
    "device_type": "cisco_ios",
    "host": "192.0.2.10",
    "username": "netadmin",
    "password": "s3cret",          # in practice: read from a vault / env var
    "secret": "enablepass",        # enable-mode password
}

vlan_id = 42
vlan_name = "AUTOMATION-LAB"

with ConnectHandler(**device) as conn:
    conn.enable()                                  # enter privileged EXEC

    # Idempotent-ish: send_config_set only changes what it needs to
    config_commands = [
        f"vlan {vlan_id}",
        f"name {vlan_name}",
    ]
    output = conn.send_config_set(config_commands)
    print(output)

    conn.save_config()                             # write mem

    # Read it back as verification
    result = conn.send_command("show vlan brief", use_textfsm=True)
    print(result)   # with TextFSM, this is structured data (list of dicts)

The use_textfsm=True flag is worth noting: it runs the raw CLI output through a TextFSM template so you get back a list of dictionaries instead of a text blob — a pragmatic bridge from screen-scraping toward structured data when a real API is not available.

A NAPALM example showing the multi-vendor, structured advantage:

import napalm

driver = napalm.get_network_driver("eos")   # or "ios", "junos", "nxos_ssh"
device = driver(hostname="192.0.2.20", username="netadmin", password="s3cret")

device.open()
facts = device.get_facts()                   # same keys on every platform
print(facts["hostname"], facts["os_version"], facts["uptime"])

interfaces = device.get_interfaces()         # structured dict, not text
for name, data in interfaces.items():
    state = "up" if data["is_up"] else "down"
    print(f"{name:20} {state}")

device.close()

Ansible for network devices

Ansible is the most widely used configuration-management tool for networks. Its defining properties for network work:

A minimal inventory (inventory.yml):

all:
  children:
    ios_switches:
      hosts:
        sw1: { ansible_host: 192.0.2.10 }
        sw2: { ansible_host: 192.0.2.11 }
      vars:
        ansible_network_os: cisco.ios.ios
        ansible_connection: network_cli
        ansible_user: netadmin

A real playbook (configure-vlans.yml) that configures VLANs, an interface, and saves — idempotently:

---
- name: Configure access VLANs on IOS switches
  hosts: ios_switches
  gather_facts: false

  vars:
    vlans:
      - { id: 42, name: AUTOMATION-LAB }
      - { id: 50, name: VOICE }

  tasks:
    - name: Ensure VLANs exist
      cisco.ios.ios_vlans:
        config: "{{ vlans | map('combine', {'state': 'active'}) | list }}"
        state: merged          # merged = idempotent add, no wipe

    - name: Configure access port Gi0/1 into VLAN 42
      cisco.ios.ios_l2_interfaces:
        config:
          - name: GigabitEthernet0/1
            mode: access
            access:
              vlan: 42
        state: merged

    - name: Save running-config to startup-config
      cisco.ios.ios_config:
        save_when: modified     # only writes mem if something changed

    - name: Verify VLAN 42 is present
      cisco.ios.ios_command:
        commands: show vlan id 42
      register: vlan_check

    - name: Show verification output
      ansible.builtin.debug:
        var: vlan_check.stdout_lines

Run it with ansible-playbook -i inventory.yml configure-vlans.yml. On the first run Ansible reports changed; run it again and it reports ok with changed=0 — that is idempotency in action. The state: merged keyword is the idempotent verb: it adds/updates what you declared without deleting the rest of the config (contrast with replaced or overridden).

Terraform and Infrastructure as Code

Where Ansible shines at configuration management of existing devices, Terraform shines at provisioning — declaring and creating the infrastructure itself. In networking this most often means cloud networking resources: VPCs/VNets, subnets, route tables, security groups/firewall rules, load balancers, DNS zones and records, VPN gateways, and Transit Gateways (see cloud networking).

Terraform is:

A real snippet — an AWS VPC with a subnet, a security group, and a DNS record:

terraform {
  required_providers {
    aws = { source = "hashicorp/aws", version = "~> 5.0" }
  }
}

provider "aws" {
  region = "ap-southeast-1"
}

resource "aws_vpc" "main" {
  cidr_block           = "10.20.0.0/16"
  enable_dns_hostnames = true
  tags = { Name = "prod-vpc" }
}

resource "aws_subnet" "app" {
  vpc_id            = aws_vpc.main.id
  cidr_block        = "10.20.1.0/24"
  availability_zone = "ap-southeast-1a"
  tags = { Name = "prod-app-subnet" }
}

resource "aws_security_group" "web" {
  name   = "web-sg"
  vpc_id = aws_vpc.main.id

  ingress {
    description = "HTTPS from anywhere"
    from_port   = 443
    to_port     = 443
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }
}

resource "aws_route53_record" "app" {
  zone_id = var.hosted_zone_id
  name    = "app.example.com"
  type    = "A"
  ttl     = 300
  records = ["10.20.1.10"]
}

variable "hosted_zone_id" { type = string }

The workflow is terraform initterraform plan (shows the exact diff, a dry run) → terraform apply (executes it). The plan step is the safety net: you review precisely what will be created, changed, or destroyed before anything happens — the network equivalent of code review for infrastructure. See the DevOps Infrastructure as Code note for a deeper treatment of state, modules, and remote backends.

Configuration management vs provisioning, and drift detection

These two words describe different jobs and the tools reflect that split:

The line blurs — Ansible can provision cloud resources, Terraform can push some config — but the mental model holds: provision with Terraform, configure with Ansible is a common, clean division.

Configuration drift is when the real, running state of a device diverges from the intended state defined in your code — someone made an emergency change at the CLI, a manual “temporary” fix that was never removed, or a device rebooted to an old config. Drift is the enemy of a reliable network. Automation gives you two ways to fight it:

CI/CD, version control, and source of truth

The final piece is treating network config the way software teams treat code — the heart of the NetDevOps approach.

The end-to-end NetDevOps loop: NetBox (intent) → Jinja2/templates → Git (PR + review) → CI (lint + test) → Ansible/Terraform (apply) → device → telemetry/plan (verify + detect drift) → back to intent.

Tool comparison

ToolPrimary jobLanguageAgent modelConfig paradigmBest for
Bash / shellGlue, quick loopsBashAgentless (SSH)ImperativeOne-off scripts, backups, orchestration glue
NetmikoSSH CLI automationPythonAgentless (SSH)ImperativeScreen-scraping, pushing CLI to any vendor
NAPALMMulti-vendor structured APIPythonAgentless (SSH/API)Declarative-ish (config replace)Cross-vendor getters, safe config replace/rollback
NornirAutomation frameworkPython (pure)AgentlessImperative (you code tasks)Scaling Python tasks over big inventories
AnsibleConfiguration managementYAML (+ Python modules)Agentless (SSH/API)Declarative, idempotentFleet config, playbooks, broad vendor support
TerraformProvisioning (IaC)HCLAgentless (API)Declarative, state-basedCloud VPCs, DNS, firewall rules, load balancers
SNMPMonitoring/polling(via libs)Agent (SNMP daemon)Read-mostlyCounters, traps (legacy config)
gNMI / OpenConfigTelemetry + configProtobuf/gRPCAgentlessDeclarative (YANG)Streaming telemetry, high-scale modern devices

Best Practices

References