Nornir Network Automation: Inventory and Tasks Guide - 夜莺博客

Nornir Network Automation: Inventory and Tasks Guide

Most network automation tools ask you to learn a pseudo-language that is almost, but not quite, a programming language - so debugging, testing and integrating with other systems become painful. Nornir takes the opposite approach: it is a pure Python framework that handles the boring parts (inventory, host data resolution, parallel task dispatch, result collection) and lets you write ordinary Python for the logic. This guide walks through the inventory model, how groups and defaults are inherited, how filtering works, and how to build composable tasks that run against Cisco, Juniper, Arista or Linux hosts in one run.

Why a pure Python framework

Nornir does not invent a DSL. Hosts are Python objects, tasks are functions that take a Task object and return a Result, and results are plain Python you can assert on in a unit test. That means the same tooling you use for application code - linters, type hints, pytest, CI - applies to network automation. The framework itself only takes care of inventory resolution, threading (num_workers), and dispatch.

The inventory: hosts, groups and defaults

The default inventory plugin (SimpleInventory) stores data in three YAML files:

# hosts.yaml
leaf01.cmh:
  hostname: 127.0.0.1
  port: 12203
  username: automation
  platform: junos
  groups:
    - cmh
  data:
    site: cmh
    role: leaf
    asn: 65101

The groups.yaml file uses the same schema, and the defaults.yaml file holds values that apply when nothing more specific exists. Connection parameters live on the host object; everything under data is free-form and is what you normally filter and template on (site, role, type, asn).

Inheritance and data resolution

Data resolution walks the group tree recursively: host data wins, then the nearest parent group, then grandparents, then defaults. A group called global referenced by every regional group is the standard idiom for credentials and domain settings. If nothing matches you get a KeyError - deliberate behaviour, because silently substituting a blank value in a template is how configs get flattened. Use host.data when you want the host's own values without group resolution.

Filtering before you touch a device

from nornir import InitNornir
nr = InitNornir(config_file="config.yaml")

cmh_leaves = nr.filter(site="cmh", role="leaf")
cmh_leaves = nr.filter(filter_func=lambda h: len(h.name) == 11)

Filtering is the single most important safety feature in a runbook: build the selection, print nr.inventory.hosts.keys(), confirm the list, then execute. Filter objects support nested keys with a double underscore (nested_data__a_dict__a) and __contains to test membership inside dicts, lists and strings.

Tasks, and tasks calling tasks

from nornir.core.task import Task, Result

def collect(task: Task) -> Result:
    task.run(name="Facts", task=napalm_get, getters=["facts", "interfaces"])
    task.run(name="Uptime", task=cli, command="show version | match uptime")
    return Result(host=task.host, result=f"{task.host.name} collected")

results = nr.run(task=collect, num_workers=20)
print_result(results)

A parent task composes smaller tasks, each with its own name, so the printed result tree reads like a runbook. Failed hosts are exposed through results.failed_hosts, and each host result carries failed, changed, diff and per-subtask tracebacks - which is exactly what you want to gate a change window on.

Operational tips

  • Start every run with dry_run=True in the Nornir init and switch it off only for the actual change.
  • Set num_workers conservatively (10-20); device CPU, not your laptop, is usually the bottleneck during show-heavy tasks.
  • Keep inventory in Git and generate it from your IPAM/CMDB rather than editing YAML by hand.
  • Wrap tasks in pytest with a fake inventory so a bad Jinja2 template fails in CI, not at 02:00 in production.

Related: Ansible network automation playbook examples, Junos PyEZ and ncclient automation, and Jinja2 config templating guide.

原文链接:https://nornir.readthedocs.io/en/latest/tutorial/inventory.html