Nornir Inspect is a tool, developed by Packet Coders to help learn, and troubleshoot the config management framework - Nornir, by allowing you to visualise the various result objects, attributes and hierarchies. Like so:

nornir_inspect(result)

<class 'nornir.core.task.AggregatedResult'>
β”œβ”€β”€ failed = False
β”œβ”€β”€ failed_hosts = {}
β”œβ”€β”€ name = task_1
β”œβ”€β”€ <class 'nornir.core.task.MultiResult'> ['node1']
β”‚   β”œβ”€β”€ failed = False
β”‚   β”œβ”€β”€ failed_hosts = {}
β”‚   β”œβ”€β”€ name = task_1
β”‚   └── <class 'nornir.core.task.Result'> [0]
β”‚       β”œβ”€β”€ changed = False
β”‚       β”œβ”€β”€ diff =
β”‚       β”œβ”€β”€ exception = None
β”‚       β”œβ”€β”€ failed = False
β”‚       β”œβ”€β”€ host = node1
β”‚       β”œβ”€β”€ name = task_1
β”‚       β”œβ”€β”€ result = 2
β”‚       β”œβ”€β”€ severity_level = 20
β”‚       β”œβ”€β”€ stderr = None
β”‚       └── stdout = None
β”œβ”€β”€ <class 'nornir.core.task.MultiResult'> ['node2']
β”‚   β”œβ”€β”€ failed = False
β”‚   β”œβ”€β”€ failed_hosts = {}
β”‚   β”œβ”€β”€ name = task_1
β”‚   └── <class 'nornir.core.task.Result'> [0]
β”‚       β”œβ”€β”€ changed = False
β”‚       β”œβ”€β”€ diff =
β”‚       β”œβ”€β”€ exception = None
β”‚       β”œβ”€β”€ failed = False
β”‚       β”œβ”€β”€ host = node2
β”‚       β”œβ”€β”€ name = task_1
β”‚       β”œβ”€β”€ result = 2
β”‚       β”œβ”€β”€ severity_level = 20
β”‚       β”œβ”€β”€ stderr = None
β”‚       └── stdout = None
└── <class 'nornir.core.task.MultiResult'> ['node3']
    β”œβ”€β”€ failed = False
    β”œβ”€β”€ failed_hosts = {}
    β”œβ”€β”€ name = task_1
    └── <class 'nornir.core.task.Result'> [0]
        β”œβ”€β”€ changed = False
        β”œβ”€β”€ diff =
        β”œβ”€β”€ exception = None
        β”œβ”€β”€ failed = False
        β”œβ”€β”€ host = node3
        β”œβ”€β”€ name = task_1
        β”œβ”€β”€ result = 2
        β”œβ”€β”€ severity_level = 20
        β”œβ”€β”€ stderr = None
        └── stdout = None

Why is this useful?

Well, Nornir provides various result objects, each object containing attributes/result data, like so.

<class 'nornir.core.task.AggregatedResult'> # All results.
β”œβ”€β”€ <class 'nornir.core.task.MultiResult'>  # Results of all tasks for a single device.
β”‚   └── <class 'nornir.core.task.Result'>   # Result of a single task for a single device.
β”œβ”€β”€ <class 'nornir.core.task.MultiResult'>
β”‚   └── <class 'nornir.core.task.Result'>
└── <class 'nornir.core.task.MultiResult'>
    └── <class 'nornir.core.task.Result'>

Typically, the Nornir function print_result is used to print out the main data from the Nornir results, however, you may need to visualise the "result tree" for learning purposes, or to help understand how to lookup data from the various nested result objects. This is where Nornir Inspect comes into play.

New to Nornir? If so check out our Nornir 101 here.

Installation

Nornir Inspect can be installed like so:

$ pip install nornir-inspect

or

$ poetry add nornir-inspect

Example

Once installed after running your Nornir tasks, you can inspect your results by supplying then to Nornir Inspect, from which it will display the "result tree".

Inital Nornir setup and task execution.


from nornir import InitNornir
from nornir.core.task import Result, Task

nr = InitNornir(
     runner={
         "plugin": "threaded",
         "options": {
             "num_workers": 10,
         },
     },
     inventory={
         "plugin": "SimpleInventory",
         "options": {"host_file": "tests/hosts.yaml"},
     },
     logging={"enabled": False},
 )

def task_1(task: Task, number: int) -> Result:
     n = number + 1
     return Result(host=task.host, result=f"{n}")

result = nr.run(task=task_1, number=1)
from nornir_inspect import nornir_inspect

nornir_inspect(result)
<-output->
<class 'nornir.core.task.AggregatedResult'>
β”œβ”€β”€ failed = False
β”œβ”€β”€ failed_hosts = {}
β”œβ”€β”€ name = task_1
β”œβ”€β”€ <class 'nornir.core.task.MultiResult'> ['node1']
β”‚   β”œβ”€β”€ failed = False
β”‚   β”œβ”€β”€ failed_hosts = {}
β”‚   β”œβ”€β”€ name = task_1
β”‚   └── <class 'nornir.core.task.Result'> [0]
β”‚       β”œβ”€β”€ changed = False
β”‚       β”œβ”€β”€ diff =
β”‚       β”œβ”€β”€ exception = None
β”‚       β”œβ”€β”€ failed = False
β”‚       β”œβ”€β”€ host = node1
β”‚       β”œβ”€β”€ name = task_1
β”‚       β”œβ”€β”€ result = 2
β”‚       β”œβ”€β”€ severity_level = 20
β”‚       β”œβ”€β”€ stderr = None
β”‚       └── stdout = None
β”œβ”€β”€ <class 'nornir.core.task.MultiResult'> ['node2']
β”‚   β”œβ”€β”€ failed = False
β”‚   β”œβ”€β”€ failed_hosts = {}
β”‚   β”œβ”€β”€ name = task_1
β”‚   └── <class 'nornir.core.task.Result'> [0]
β”‚       β”œβ”€β”€ changed = False
β”‚       β”œβ”€β”€ diff =
β”‚       β”œβ”€β”€ exception = None
β”‚       β”œβ”€β”€ failed = False
β”‚       β”œβ”€β”€ host = node2
β”‚       β”œβ”€β”€ name = task_1
β”‚       β”œβ”€β”€ result = 2
β”‚       β”œβ”€β”€ severity_level = 20
β”‚       β”œβ”€β”€ stderr = None
β”‚       └── stdout = None
└── <class 'nornir.core.task.MultiResult'> ['node3']
    β”œβ”€β”€ failed = False
    β”œβ”€β”€ failed_hosts = {}
    β”œβ”€β”€ name = task_1
    └── <class 'nornir.core.task.Result'> [0]
        β”œβ”€β”€ changed = False
        β”œβ”€β”€ diff =
        β”œβ”€β”€ exception = None
        β”œβ”€β”€ failed = False
        β”œβ”€β”€ host = node3
        β”œβ”€β”€ name = task_1
        β”œβ”€β”€ result = 2
        β”œβ”€β”€ severity_level = 20
        β”œβ”€β”€ stderr = None
        └── stdout = None

We can now see the result tree structure. We can also use the heading helpers to help us navigate through the result structure like so:


Additional Options

Nornir Inspect provides 2 additional options:

Values

Allows you to hide the various object attributes. This is performed by passing in the argument vals=False. The default is True.

nornir_inspect(vals=False, nr_result=result)

<class 'nornir.core.task.AggregatedResult'>
β”œβ”€β”€ <class 'nornir.core.task.MultiResult'> ['node1']
β”‚   └── <class 'nornir.core.task.Result'> [0]
β”œβ”€β”€ <class 'nornir.core.task.MultiResult'> ['node2']
β”‚   └── <class 'nornir.core.task.Result'> [0]
└── <class 'nornir.core.task.MultiResult'> ['node3']
    └── <class 'nornir.core.task.Result'> [0]

Headings

Allows you to hide the additional heading information that is shown, such as the object key or list index. The default is True.

nornir_inspect(vals=False, headings=False, nr_result=result)

<class 'nornir.core.task.AggregatedResult'>
β”œβ”€β”€ <class 'nornir.core.task.MultiResult'>
β”‚   └── <class 'nornir.core.task.Result'>
β”œβ”€β”€ <class 'nornir.core.task.MultiResult'>
β”‚   └── <class 'nornir.core.task.Result'>
└── <class 'nornir.core.task.MultiResult'>
    └── <class 'nornir.core.task.Result'>
Want to check out the code for Nornir Inspect? If so head over to: https://github.com/packetcoders/nornir-inspect
Ready to Master Network Automation? Start Your Journey Today!
Our membership provides:
  • Full deep-dive course library (inc. Batfish, pyATS, Netmiko)
  • Code repositories inc. full course code, scripts and examples
  • 24x7 multi-vendor labs (Arista, Cisco, Juniper)
  • Private online community
  • Live monthly tech sessions
  • Access to tech session library

Join Now ➜