In my last couple of posts we learned how to parse linux command output in Ansible and Saltstack using jc
. In this post we’ll do something similar with Nornir.
Nornir is a popular automation framework that allows you to use native python to control hosts and network devices. Many times it would be nice to be able to parse the output of remotely-run commands and use that information elsewhere in your scripts. jc
allows you to do this automatically – no regex/looping/slicing/etc. required to get to the data you want!
Since jc
is both a command line tool and a python library, it is easy to use inside a Nornir script to automate the boring work of command output parsing.
For more information on the motivations for creating
jc
, see my blog post.
Installation
To use jc
in a Nornir script, simply install it and import one or more parsers.
Installing jc
:
$ pip3 install jc
Import the jc
library:
import jc
Now we are ready to use the jc
in our Nornir script!
Syntax
To use the jc
parser, call the parse
function with the parser name and command output arguments. For example, to automatically parse a uname -a
output string:
uname_obj = jc.parse('uname', uname_command_output_string)
Now you can use whatever uname
field you would like in the rest of your code:
print(uname_obj['node_name'])
A Simple Example
Below we have a small Nornir script using Netmiko to call a few commands on a linux host. (uname
, date
, ifconfig
, and uptime
) I used the nornir-netmiko
package to simplify the connection to the linux host:
from nornir import InitNornir from nornir_netmiko.tasks import netmiko_send_command import jc nr = InitNornir(config_file='config.yaml') def run_commands(task, command_list): for cmd in command_list: task.run( task=netmiko_send_command, command_string=cmd, name=cmd ) commands = ['uname -a', 'date', 'ifconfig', 'uptime'] result = nr.run( task=run_commands, command_list=commands ) uname_result_string = result['host1'][1].result uname_result_obj = jc.parse('uname', uname_result_string) hostname = uname_result_obj['node_name'] kernel_version = uname_result_obj['kernel_version'] date_result_string = result['host1'][2].result date_result_obj = jc.parse('date', date_result_string) timezone = date_result_obj['timezone'] ifconfig_result_string = result['host1'][3].result ifconfig_result_obj = jc.parse('ifconfig', ifconfig_result_string) ipv4_addr = ifconfig_result_obj[1]['ipv4_addr'] uptime_result_string = result['host1'][4].result uptime_result_obj = jc.parse('uptime', uptime_result_string) uptime = uptime_result_obj['uptime'] print(f'hostname: {hostname}') print(f'kernel version: {kernel_version}') print(f'timezone: {timezone}') print(f'ip address: {ipv4_addr}') print(f'uptime: {uptime}')
Script output:
$ python3 nornir_with_jc.py hostname: my-ubuntu kernel version: #113-Ubuntu SMP Thu Jul 9 23:41:39 UTC 2020 timezone: UTC ip address: 192.168.1.239 uptime: 47 min
Here you can see we have run a few tasks and assigned the results to some variables. Let’s go over the uname -a
output:
uname_result_string = result['host1'][1].result
Above, we are grabbing the string result output attribute from the uname -a
command (the first command in the commands
list) and are assigning it to uname_result_string
. There are cleaner ways of getting the result info from Nornir, but this way we can see the structure of the result
object.
uname_result_obj = jc.parse('uname', uname_result_string)
Next, we have run uname_result_string
through the jc
uname parser and assigned the resulting dictionary object to the uname_result_obj
variable.
hostname = uname_result_obj['node_name'] kernel_version = uname_result_obj['kernel_version']
Then, we created a couple of variables that we can use in our script called hostname
and kernel_version
so we can grab just the object attributes we are interested in. jc
returns standard dictionary objects, so they are easy to use.
print(f'hostname: {hostname}') print(f'kernel version: {kernel_version}')
Finally, we use our variables in a print
function, but we could have used these objects anywhere else in the script.
Nice! Instead of parsing the STDOUT
text manually, we used jc
to automatically parse the command output, providing us a convenient object to use elsewhere in our script. No more need to regex or loop and slice your way through the output to get what you are looking for!
For a complete list of jc
parsers available and their associated schemas, see the parser documentation.
Happy parsing!