NetAuto Academy

Nornir for Network Engineers

InitNornir() and Your First Task Function

Advanced13 min read

What you'll learn

  • How InitNornir() bootstraps a Nornir object from inventory files
  • The def task(task: Task) -> Result signature convention
  • What nr.run() actually returns: AggregatedResult and MultiResult
  • How this maps onto Phase 3.3's own hand-built result types
🎓 Teach This Lesson

Listen to a guided explanation of this lesson.

Spoken narration isn't supported in this browser.

Bootstrapping from Lesson 2's inventory

bootstrap.py
from nornir import InitNornir

nr = InitNornir(
  inventory={
      "plugin": "SimpleInventory",
      "options": {
          "host_file": "inventory/hosts.yaml",
          "group_file": "inventory/groups.yaml",
          "defaults_file": "inventory/defaults.yaml",
      },
  },
)

print(list(nr.inventory.hosts.keys()))

Real, verified output: ['SW1', 'SW2', 'SW3', 'SW4', 'SW5'] -- the exact three files built in Lesson 2, now loaded into a working Nornir object.

Quick checkConcept check
What does InitNornir() actually do?

A task function, in real Nornir's own convention

first_task.py
from nornir.core.task import Task, Result

def greet(task: Task) -> Result:
  return Result(host=task.host, result=f"Hello from {task.host.name} ({task.host.hostname})")

agg = nr.run(task=greet)

Every Nornir task function takes a Task and returns a Result -- ordinary Python, not YAML. task.host gives access to the current host's own data (name, hostname, and anything set under data:).

Quick checkIdentify the correct code
Which function signature correctly matches Nornir's task convention?

What nr.run() actually returns

inspect_the_result.py
print(type(agg))
print(list(agg.keys()))

for hostname, multi_result in agg.items():
  print(hostname, "->", type(multi_result), "len:", len(multi_result))
  print("   .result:", multi_result.result)
  print("   .failed:", multi_result.failed)

print("agg.failed:", agg.failed)

agg is dict-like, keyed by hostname. Each value is a MultiResult -- list-like, holding one or more Result objects (more than one only when tasks are composed, Lesson 6).

output — real, verified
<class 'nornir.core.task.AggregatedResult'>
['SW1', 'SW2', 'SW3', 'SW4', 'SW5']
SW1 -> <class 'nornir.core.task.MultiResult'> len: 1
 .result: Hello from SW1 (10.10.10.1)
 .failed: False
SW2 -> <class 'nornir.core.task.MultiResult'> len: 1
 .result: Hello from SW2 (10.10.10.2)
 .failed: False
...
agg.failed: False

Real, verified output (trimmed for length -- all 5 hosts follow the same shape). agg.failed is True if ANY host's task failed -- a quick, whole-run check before inspecting individual hosts.

The framework's version of what you built by hand

Phase 3.3's AutomationResult dataclass held one device's outcome, and the capstone collected a plain Python list of them. Nornir's AggregatedResult/MultiResult is the same idea — one structured result per device — provided by the framework, keyed by hostname automatically, instead of a list you build and index yourself.

Quick checkScenario
In Phase 3.3, results were collected into a plain list of AutomationResult objects. What does Nornir's AggregatedResult provide instead?
Quick checkPredict output
A task function has a bug and never returns a Result object at all (just returns None). What would you expect from nr.run() based on Nornir's task/Result contract verified in this lesson?

Key takeaways

  • InitNornir() bootstraps a Nornir object from inventory — no device is contacted until a task actually runs.
  • A task function's signature is def task(task: Task) -> Result — ordinary Python, verified directly.
  • nr.run() returns an AggregatedResult (dict-like, keyed by hostname); each value is a MultiResult (list-like) of real Result objects.
  • AggregatedResult/MultiResult is Nornir's framework-provided version of the AutomationResult collection Phase 3.3 built by hand — keyed automatically instead of searched.