Workflow
nornir_cli
has a workflow that is familiar to the nornir user. There is:
You can run a workflow as a single command or you can split it into parts
Initializing Nornir#
You can initialize nornir with a configuration file, with code or with a combination of both.
With configuration file#
Let's start with a configuration file. It is a typical Nornir configuration file.
By default, nornir_cli
uses config.yaml
in your current working directory. But you can specify path to your own configuration file with option --config_file
or -c
:
# with default config.yaml in current working directory
$ nornir_cli nornir-netmiko init
# with path to config_file
$ nornir_cli nornir-netmiko init -c ~/config.yaml
nornir-netmiko
here? nornir_cli
runs Tasks based on Nornir plugins or your custom Nornir runbooks, so the first step is to select an available plugin or custom group (see Runbook collections).
For version 1.3.0
, the following Nornir plugins are available:
$ nornir_cli --help
Usage: nornir_cli [OPTIONS] COMMAND [ARGS]...
Nornir CLI
Orchestrate your Inventory and start Tasks and Runbooks
Options:
--version Show the version and exit.
--help Show this message and exit.
Commands:
nornir-f5 nornir_f5 plugin
nornir-http nornir_http plugin
nornir-jinja2 nornir_jinja2 plugin
nornir-napalm nornir_napalm plugin
nornir-netconf nornir_netconf plugin
nornir-netmiko nornir_netmiko plugin
nornir-paramiko nornir_paramiko plugin
nornir-pyez nornir_pyez plugin
nornir-pyxl nornir_pyxl plugin
nornir-routeros nornir_routeros plugin
nornir-scrapli nornir_scrapli plugin
Without a configuration file#
You can initialize nornir programmatically without a configuration file.
-f
or --from_dict
option waits json string:
-c
or --config_file
can be ""
, None
, null
Here you can pass parameters as json strings using "=" or without it. In the case of "=", the nornir_cli
completely repeats the syntax from Nornir runbooks, and you can use the Nornir configuration patterns that are already familiar to you (or see the Nornir docs). In the case without using "=", you can pass all parameters as a json string. This can be useful in scripts or automation pipelines, when using nornir_cli
with json utilities such as jq
, jc
.
This way(json string using "=" or json string without "=") you can pass parameters to initializing, filtering and Nornir plugins/tasks running processes.
Examples:
$ nornir_cli nornir-netmiko init -c "" -f 'inventory={"plugin":"NetBoxInventory2", \
"options": {"nb_url": "http://your_netbox_domain", "nb_token": "your_netbox_token", \
"ssl_verify": false}} runner={"plugin": "threaded", "options": {"num_workers": 50}} \
logging={"enabled":true, "level": "DEBUG", "to_console": true}'
$ nornir_cli nornir-netmiko init -c "" -f '{"inventory":{"plugin":"NetBoxInventory2", \
"options": {"nb_url": "http://your_netbox_domain", "nb_token": "your_netbox_token", \
"ssl_verify": false}}, "runner":{"plugin": "threaded", "options": {"num_workers": 50}}, \
"logging":{"enabled":true, "level": "DEBUG", "to_console": true}}'
Or you can initialize nornir with a combination of both methods:
Both ways#
$ nornir_cli nornir-netmiko init -f 'runner={"plugin": "threaded", "options": {"num_workers": 50}}'
$ nornir_cli nornir-netmiko init -f '{"runner":{"plugin": "threaded", "options": {"num_workers": 50}}}'
-c
or --config_file
uses config.yaml
in your current working directory, by default, so there is no -c
option and only -f
option here
Inventory#
nornir_cli
follows Nornir
filtering interface.
init
returns nornir.core.Nornir object, which saved to temp.pkl
file for future reference. init
is enough to perform once in any way described above. After that, you can filter inventory.
Now, let's take nornir_netbox inventory plugin and do init
, at first:
config.yaml:
# we will use NetBox Inventory
inventory:
plugin: NetBoxInventory2
options:
nb_url: "http://your_nebox_domain"
nb_token: "your_netbox_token"
ssl_verify: False
init:
# -u / --username and -p / --password will assign a username and password in defaults
# -co / --connection_options will assign options for Scrapli framework
# huawei is here just as an example
$ nornir_cli nornir-scrapli init -u username -p password -co '{"scrapli": {"platform": "huawei_vrp", "extras":{"ssh_config_file": true}}}'
And now let's filter NetBox inventory, as instance:
Filtering#
# let's filter current inventory and get dev_1 inventory object
# --hosts shows filtered hosts list
$ nornir_cli nornir-scrapli filter --hosts name=dev_1
[
"dev_1"
]
# --inventory=host shows "hosts" inventory parameters for filtered hosts (dev_1 in example)
# --hosts shows filtered hosts list
# huawei is here just as an example
$ nornir_cli nornir-scrapli filter --inventory=hosts --hosts 'primary_ip={"address": "10.1.0.1/32", "family": 4, "id": 13, "url": "http://your_netbox_domain/api/ipam/ip-addresses/13/"} name=dev_1'
# or an alternative way(json string without "=")
# $ nornir_cli nornir-scrapli filter --inventory=hosts --hosts '{"primary_ip":{"address": "10.1.0.1/32", "family": 4, "id": 13, "url": "http://your_netbox_domain/api/ipam/ip-addresses/13/"}, "name":"dev_1"}'
{
"hosts": {
"dev_1": {
"name": "dev_1",
"connection_options": {},
"groups": [],
"data": {
"id": 13,
"name": "dev_1",
"display_name": "dev_1",
"device_type": {
...
"hostname": "10.1.0.1",
"port": null,
"username": "username",
"password": "password",
"platform": "huawei"
}
}
}
[
"dev_1"
]
# --hosts shows filtered hosts list
# -a / --advanced option enables advanced filtering
$ nornir_cli nornir-scrapli filter --hosts -a 'name__contains=dev_1 device_role__name__contains=spine'
[
"dev_1"
]
# the same with &
$ nornir_cli nornir-scrapli filter --hosts -a 'name__contains=dev_1 & device_role__name__contains=spine'
[
"dev_1"
]
# or |
$ nornir_cli nornir-scrapli filter --hosts -a 'name__contains=dev_1 | name__contains=dev_2'
Are you sure you want to output list of all required hosts on stdout? [Y/n]:
[
"dev_1"
"dev_2"
]
# another example
# --count shows the first 3 items from filtered inventory (for hosts list with --hosts option in example)
$ nornir_cli nornir-netmiko filter --hosts --count 3 -a 'data__device_type__model__contains=S2320-28TP-EI-DC & name__contains=dev_ | data__device_type__model__contains=S2320-28TP-EI-DC & name__contains=access'
[
"dev_1"
"dev_2"
"access_1"
]
By default, the filtered Inventory is not saved for future reference. It was done to perform init
only once, and then to filter Inventory and run any commands from Nornir Plugins (see available plugins with nornir_cli --help
command) or Nornir Runbooks (see Runbook collections) as a single command (see Command chains). This is useful and saves time on init
with large inventories.
But, you can save the Inventory state after filtering with -s
or --save
option and work with new Inventory object. So any commands from Nornir Plugins or Nornir Runbooks will be run for the saved object.
Filter Inventory ans save it as much as needed. Perform init
if you need to return full Inventory state again.
As instance, let's save Inventory after simple filtering:
# get new inventory object with single host (dev_1)
# --hosts shows filtered and saved hosts
$ nornir_cli nornir-scrapli filter --hosts -s name=dev_1
[
"dev_1"
]
IMPORTANT: if you want to save the Inventory state after filtering for future references, please use --save
or -s
option.
Show inventory#
As you may have already noticed, it's possible to view the current inventory state with show_inventory
command:
$ nornir_cli nornir-scrapli show_inventory -i hosts -h -g --count 6
# hosts inventory
{
"hosts": {
"dev_1": {
"name": "dev_1",
"connection_options": {},
"groups": [],
"data": {
"id": 13,
"name": "dev_1",
"display_name": "dev_1",
"device_type": {
...
"hostname": "10.1.0.1",
"port": null,
"username": "username",
"password": "password",
"platform": "huawei"
}
}
}
... # there is 6 Hosts Inventory in json format
# hosts list
[
"dev_1"
"dev_2"
"dev_3"
"dev_4"
"dev_5"
"access_1"
]
# groups list
[]
-i
or --inventory
option can be hosts
, groups
, defaults
or all
.
-cou
or --count
is counter, that refers to each requested parameter.
-cou
or --count
can be:
-
--count -100
- last 100 items -
--count 100
- first 100 items -
--count 0
- 0 items -
without
--count
option - all items (default value)
As instance:
$ nornir_cli nornir-scrapli show_inventory -h -cou 2
# hosts list for the first 2 hosts
[
"dev_1"
"dev_2"
]
-h
or --hosts
option is default option, so the same is nornir_cli nornir-scrapli show_inventory -cou 2
.
For the latest 2 hosts from Inventory use -cou -2
$ nornir_cli nornir-scrapli show_inventory -h -g -cou 2
# hosts list for the first 2 hosts
[
"dev_1"
"dev_2"
]
# groups list for the first 2 groups (groups don't exist)
[]
$ nornir_cli nornir-scrapli show_inventory -h -i hosts -cou 2
# hosts inventory for the first 2 hosts
{
"hosts": {
"dev_1": {
"name": "dev_1",
"connection_options": {},
"groups": [],
"data": {
"id": 13,
"name": "dev_1",
"display_name": "dev_1",
"device_type": {
...
"hostname": "10.1.0.1",
"port": null,
"username": "username",
"password": "password",
"platform": "huawei"
}
"dev_2": {
"name": "dev_2",
"connection_options": {},
"groups": [],
"data": {
"id": 14,
"name": "dev_2",
"display_name": "dev_2",
"device_type": {
...
"hostname": "10.1.0.2",
"port": null,
"username": "username",
"password": "password",
"platform": "huawei"
}
}
}
# hosts list for the first 2 hosts
[
"dev_1"
"dev_2"
]
$ nornir_cli nornir-scrapli show_inventory -h -i all -cou 2
# hosts inventory for the first 2 hosts
{
"hosts": {
"dev_1": {
"name": "dev_1",
"connection_options": {},
"groups": [],
"data": {
"id": 13,
"name": "dev_1",
"display_name": "dev_1",
"device_type": {
...
"hostname": "10.1.0.1",
"port": null,
"username": "username",
"password": "password",
"platform": "huawei"
}
"dev_2": {
"name": "dev_2",
"connection_options": {},
"groups": [],
"data": {
"id": 14,
"name": "dev_2",
"display_name": "dev_2",
"device_type": {
...
"hostname": "10.1.0.2",
"port": null,
"username": "username",
"password": "password",
"platform": "huawei"
}
}
}
# groups inventory for the first 2 groups (groups don't exist)
{
"groups": {}
}
# defaults inventory is always 1, so counter (`-cou` or `--count`) doesn't work for it
{
"defaults": {
"data": {},
"connection_options": {},
"hostname": null,
"port": null,
"username": "username",
"password": "password",
"platform": null
}
}
# hosts list for the first 2 hosts
[
"dev_1"
"dev_2"
]
all
inventory here is the first 2 hosts, groups (groups don't exist in example) and defaults inventory parameters. Counter (-cou
or --count
) doesn't work for defaults, because defaults is always 1.
And you can invoke show_inventory
command from init
or filter
commands with -i / --inventory
, -h / --hosts
, -g / --groups
options.
Changing credentials#
You can change credentials in any time for current Inventory with change_credentials
command.
To save Inventory state for future references use -s
or --save
option.
$ nornir_cli nornir-scrapli change_credentials --help
Usage: nornir_cli nornir-scrapli change_credentials [OPTIONS]
Change username and password for current Nornir object.
If no options are specified, the username and password will be changed for
defaults only, as instance:
nornir_cli nornir-scrapli change_credentials -u user -p password
show_inventory -i defaults
If only hosts or groups are specified (use string for single host and list
of strings for many hosts), then the username and password will be changed
only for them, as instance:
nornir_cli nornir-scrapli change_credentials -u user -p password -h
'["spine_1"]'
To change the username and password for all hosts or groups, use "all" as
option value, as instance:
nornir_cli nornir-scrapli change_credentials -u user -p password -h
"all"
Options:
-u, --username TEXT Hosts, groups or defaults username
-p, --password TEXT Hosts, groups or defaults password
-h, --hosts TEXT List of hosts (json string) or single host (str)
-g, --groups TEXT List of groups (json string) or single group (str)
-d, --defaults Defaults credentials
-s, --save Save Nornir object with new credentials to pickle file
for later use
--help Show this message and exit.
Let's take nornir_netbox inventory plugin and do init
, at first:
config.yaml:
# we will use NetBox Inventory
inventory:
plugin: NetBoxInventory2
options:
nb_url: "http://your_nebox_domain"
nb_token: "your_netbox_token"
ssl_verify: False
init:
# -u / --username and -p / --password will assign a username and password in defaults
$ nornir_cli nornir-scrapli init -u username -p password
And now let's change_credentials
for defaults
Inventory and run show_inventory
with new credentials:
# use -s option to save Inventory with new credentials for future references
$ nornir_cli nornir-scrapli change_credentials -u user -p pass show_inventory -i defaults
{
"defaults": {
"data": {},
"connection_options": {},
"hostname": null,
"port": null,
"username": "user",
"password": "pass",
"platform": null
}
}
change_credentials
for all hosts
and check hosts
Inventory with new credentials (you can do the same for groups
Inventory):
# use -s option to save Inventory with new credentials for future references
$ nornir_cli nornir-scrapli change_credentials -u user -p pass -h all show_inventory -i hosts
{
"hosts": {
"dev_1": {
"name": "dev_1",
"connection_options": {},
"groups": [],
"data": {},
"hostname": "10.3.2.1",
"port": 22,
"username": "user",
"password": "pass",
"platform": null
}
...
# other hosts
...
}
}
change_credentials
for hosts
list and check hosts
Inventory with new credentials (you can do the same for groups
Inventory):
# use -s option to save Inventory with new credentials for future references
$ nornir_cli nornir-scrapli change_credentials -u username -p password -h '["dev_1"]' show_inventory -i hosts
{
"hosts": {
"dev_1": {
"name": "dev_1",
"connection_options": {},
"groups": [],
"data": {},
"hostname": "10.3.2.1",
"port": 22,
"username": "username",
"password": "password",
"platform": null
}
...
# other hosts with "user" username and "password" password
...
}
}
Also, you can use environment variables, NORNIR_CLI_USERNAME
and NORNIR_CLI_PASSWORD
:
$ export NORNIR_CLI_USERNAME=user
$ export NORNIR_CLI_PASSWORD=pass
# use -s option to save Inventory with new credentials for future references
$ nornir_cli nornir-scrapli change_credentials -h '["dev_1"]' show_inventory -i hosts
{
"hosts": {
"dev_1": {
"name": "dev_1",
"connection_options": {},
"groups": [],
"data": {},
"hostname": "10.3.2.1",
"port": 22,
"username": "user",
"password": "pass",
"platform": null
}
...
# other hosts with "user" username and "password" password
...
}
}
Tasks and runbooks#
I must say that each argument or option parameter can be passed to the Task as a json string. It's important.
Single tasks#
Ok, now we have filtered inventory for dev_1
:
# we will use NetBox Inventory
inventory:
plugin: NetBoxInventory2
options:
nb_url: "http://your_nebox_domain"
nb_token: "your_netbox_token"
ssl_verify: False
# -u / --username and -p / --password will assign a username and password in defaults
# -co / --connection_options will assign options for Scrapli framework
# huawei is here just as an example
$ nornir_cli nornir-scrapli init -u username -p password -co '{"scrapli": {"platform": "huawei_vrp", "extras":{"ssh_config_file": true}}}'
# let's filter current inventory, get dev_1 inventory object and save it
# --hosts shows filtered hosts list
$ nornir_cli nornir-scrapli filter --hosts -s name=dev_1
# or an alternative way(json string)
# $ nornir_cli nornir-scrapli filter --hosts -s '{"name":"dev_1"}'
[
"dev_1"
]
And let's start some Task based on Nornir plugins:
At first, let's check all available Tasks/commands for current list of Nornir plugins:
$ nornir_cli nornir-netmiko
Usage: nornir_cli nornir-netmiko [OPTIONS] COMMAND1 [ARGS]... [COMMAND2
[ARGS]...]...
nornir_netmiko plugin
Options:
--help Show this message and exit.
Commands:
change_credentials Change username and password
filter Do simple or advanced filtering
init Initialize a Nornir
netmiko_commit Execute Netmiko commit method
netmiko_file_transfer Execute Netmiko file_transfer method
netmiko_multiline Execute Netmiko send_multiline method (or
send_multiline_timing)
netmiko_save_config Execute Netmiko save_config method
netmiko_send_command Execute Netmiko send_command method (or
send_command_timing)
netmiko_send_config Execute Netmiko send_config_set method (or
send_config_from_file)
print_result print_result from nornir_utils
show_inventory Show current inventory
write_file Write_file, but not from nornir_utils
write_result Write `Result` object to file
write_results Write `Result` object to files
$ nornir_cli nornir-scrapli
Usage: nornir_cli nornir-scrapli [OPTIONS] COMMAND1 [ARGS]... [COMMAND2
[ARGS]...]...
nornir_scrapli plugin
Options:
--help Show this message and exit.
Commands:
cfg_abort_config Abort a device candidate config with scrapli-cfg
cfg_commit_config Commit a device candidate config with scrapli-cfg
cfg_diff_config Diff a device candidate config vs a source config
with scrapli-cfg
cfg_get_config Get device config with scrapli-cfg
cfg_get_version Get device version with scrapli-cfg
cfg_load_config Load device config with scrapli-cfg
change_credentials Change username and password
filter Do simple or advanced filtering
get_prompt Get current prompt from device using scrapli
init Initialize a Nornir
netconf_capabilities Retrieve the device config with scrapli_netconf
netconf_commit Commit the device config with scrapli_netconf
netconf_delete_config Send a "delete-config" rcp to the device with
scrapli_netconf
netconf_discard Discard the device config with scrapli_netconf
netconf_edit_config Edit config from the device with scrapli_netconf
netconf_get Get from the device with scrapli_netconf
netconf_get_config Get config from the device with scrapli_netconf
netconf_lock Lock the device with scrapli_netconf
netconf_rpc Send a "bare" rcp to the device with
scrapli_netconf
netconf_unlock Unlock the device with scrapli_netconf
netconf_validate Send a "validate" rcp to the device with
scrapli_netconf
print_result print_result from nornir_utils
send_command Send a single command to device using scrapli
send_commands Send a list of commands to device using scrapli
send_commands_from_file Send a list of commands from a file to device using
scrapli
send_config Send a config to device using scrapli
send_configs Send configs to device using scrapli
send_configs_from_file Send configs from a file to device using scrapli
send_interactive Send inputs in an interactive fashion using
scrapli; usually used to handle prompts
show_inventory Show current inventory
write_file Write_file, but not from nornir_utils
write_result Write `Result` object to file
write_results Write `Result` object to files
$ nornir_cli nornir-napalm
Usage: nornir_cli nornir-napalm [OPTIONS] COMMAND1 [ARGS]... [COMMAND2
[ARGS]...]...
nornir_napalm plugin
Options:
--help Show this message and exit.
Commands:
change_credentials Change username and password
filter Do simple or advanced filtering
init Initialize a Nornir
napalm_cli Run commands on remote devices using napalm
napalm_configure Loads configuration into a network devices using napalm
napalm_get Gather information from network devices using napalm
napalm_ping Executes ping on the device and returns a dictionary
with the result
napalm_validate Gather information with napalm and validate it
print_result print_result from nornir_utils
show_inventory Show current inventory
write_file Write_file, but not from nornir_utils
write_result Write `Result` object to file
write_results Write `Result` object to files
$ nornir_cli nornir-jinja2
Usage: nornir_cli nornir-jinja2 [OPTIONS] COMMAND1 [ARGS]... [COMMAND2
[ARGS]...]...
nornir_jinja2 plugin
Options:
--help Show this message and exit.
Commands:
change_credentials Change username and password
filter Do simple or advanced filtering
init Initialize a Nornir
print_result print_result from nornir_utils
show_inventory Show current inventory
template_file Renders contants of a file with jinja2. All the host
data is available in the template
template_string Renders a string with jinja2. All the host data is
available in the template
write_file Write_file, but not from nornir_utils
write_result Write `Result` object to file
write_results Write `Result` object to files
$ nornir_cli nornir-pyez
Usage: nornir_cli nornir-pyez [OPTIONS] COMMAND1 [ARGS]... [COMMAND2
[ARGS]...]...
nornir_pyez plugin
Options:
--help Show this message and exit.
Commands:
change_credentials Change username and password
filter Do simple or advanced filtering
init Initialize a Nornir
print_result print_result from nornir_utils
pyez_chassis_inventory
pyez_checksum
pyez_cmd
pyez_commit
pyez_config
pyez_diff
pyez_facts
pyez_get_arp
pyez_get_config
pyez_get_int_optics_diag_info
pyez_int_terse
pyez_rollback
pyez_route_info
pyez_rpc
pyez_scp
pyez_sec_ike
pyez_sec_ipsec
pyez_sec_nat_dest
pyez_sec_nat_src
pyez_sec_policy
pyez_sec_zones
show_inventory Show current inventory
write_file Write_file, but not from nornir_utils
write_result Write `Result` object to file
write_results Write `Result` object to files
$ nornir_cli nornir-f5
Usage: nornir_cli nornir-f5 [OPTIONS] COMMAND1 [ARGS]... [COMMAND2
[ARGS]...]...
nornir_f5 plugin
Options:
--help Show this message and exit.
Commands:
atc Task to deploy declaratives on F5 devices
atc_info Task to verify if ATC service is available
and collect service info
bigip_cm_config_sync Task to synchronize the configuration
between devices
bigip_cm_failover_status Task to get the failover status of the
device
bigip_cm_sync_status Task to get the synchronization status of
the device
bigip_shared_file_transfer_uploads
Upload a file to a BIG-IP system using the
iControl REST API
bigip_shared_iapp_lx_package Task to manage Javascript LX packages on a
BIG-IP
bigip_sys_version Gets the system version of the BIG-IP
bigip_util_unix_ls Task to list information about the FILEs
bigip_util_unix_rm Task to delete a file from a BIG-IP system
change_credentials Change username and password
filter Do simple or advanced filtering
init Initialize a Nornir
print_result print_result from nornir_utils
show_inventory Show current inventory
write_file Write_file, but not from nornir_utils
write_result Write `Result` object to file
write_results Write `Result` object to files
$ nornir_cli nornir-paramiko
Usage: nornir_cli nornir-paramiko [OPTIONS] COMMAND1 [ARGS]... [COMMAND2
[ARGS]...]...
nornir_paramiko plugin
Options:
--help Show this message and exit.
Commands:
change_credentials Change username and password
filter Do simple or advanced filtering
init Initialize a Nornir
paramiko_command Executes a command remotely on the host
paramiko_sftp Transfer files from/to the device using sftp protocol
print_result print_result from nornir_utils
show_inventory Show current inventory
write_file Write_file, but not from nornir_utils
write_result Write `Result` object to file
write_results Write `Result` object to files
$ nornir_cli nornir-http
Usage: nornir_cli nornir-http [OPTIONS] COMMAND1 [ARGS]... [COMMAND2
[ARGS]...]...
nornir_http plugin
Options:
--help Show this message and exit.
Commands:
change_credentials Change username and password
filter Do simple or advanced filtering
http_method This is a helper task that uses `httpx
<https://www.python-httpx.org/api/>`_ to interact with
an HTTP server
init Initialize a Nornir
print_result print_result from nornir_utils
show_inventory Show current inventory
write_file Write_file, but not from nornir_utils
write_result Write `Result` object to file
write_results Write `Result` object to files
$ nornir_cli nornir-pyxl
Usage: nornir_cli nornir-pyxl [OPTIONS] COMMAND1 [ARGS]... [COMMAND2
[ARGS]...]...
nornir_pyxl plugin
Options:
--help Show this message and exit.
Commands:
change_credentials Change username and password
filter Do simple or advanced filtering
init Initialize a Nornir
print_result print_result from nornir_utils
pyxl_ez_data Loads a specific sheet from a workbook(xlsx file)
show_inventory Show current inventory
write_file Write_file, but not from nornir_utils
write_result Write `Result` object to file
write_results Write `Result` object to files
$ nornir_cli nornir-netconf
Usage: nornir_cli nornir-netconf [OPTIONS] COMMAND1 [ARGS]... [COMMAND2
[ARGS]...]...
nornir_netconf plugin
Options:
--help Show this message and exit.
Commands:
change_credentials Change username and password
filter Do simple or advanced filtering
init Initialize a Nornir
netconf_capabilities Gather Netconf capabilities from device
netconf_commit Commit operation
netconf_edit_config Edit configuration of device using Netconf
netconf_get Get information over Netconf from device
netconf_get_config Get configuration over Netconf from device
netconf_get_schemas Fetch provided schemas and write to a file
netconf_lock NETCONF locking operations for a specified datastore
print_result print_result from nornir_utils
show_inventory Show current inventory
write_file Write_file, but not from nornir_utils
write_result Write `Result` object to file
write_results Write `Result` object to files
Usage: nornir_cli nornir-routeros [OPTIONS] COMMAND1 [ARGS]... [COMMAND2
[ARGS]...]...
nornir_routeros plugin
Options:
--help Show this message and exit.
Commands:
change_credentials Change username and password
filter Do simple or advanced filtering
init Initialize a Nornir
print_result print_result from nornir_utils
routeros_command Runs a RouterOS command such as ping or fetch
routeros_config_item Configures an item
routeros_get Returns a RouterOS resource
show_inventory Show current inventory
write_file Write_file, but not from nornir_utils
write_result Write `Result` object to file
write_results Write `Result` object to files
And start netmiko_send_command
, for example:
$ nornir_cli nornir-netmiko netmiko_send_command --command_string "display clock"
# or using json string as command argument
# $ nornir_cli nornir-netmiko netmiko_send_command '{"command_string":"display clock"}'
netmiko_send_command************************************************************
* dev_1 ** changed : False *****************************************************
vvvv netmiko_send_command ** changed : False vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv INFO
2021-03-19 12:57:11+03:00
Friday
Time Zone(Moscow) : UTC+03:00
^^^^ END netmiko_send_command ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
dev_1 : ok=1 changed=0 failed=0
OK : 1
CHANGED : 0
FAILED : 0
Before, we added connection options for scrapli in init
command.
Let's check out some nornir-scrapli
command:
$ nornir_cli nornir-scrapli send_command --command "display clock"
# or using json string as command argument
# $ nornir_cli nornir-scrapli send_command '{"command":"display clock"}'
send_command********************************************************************
* dev_1 ** changed : False *****************************************************
vvvv send_command ** changed : False vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv INFO
2021-03-19 13:18:53+03:00
Friday
Time Zone(Moscow) : UTC+03:00
^^^^ END send_command ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
dev_1 : ok=1 changed=0 failed=0
OK : 1
CHANGED : 0
FAILED : 0
As you may have noticed, there is a result and statistic in the output above. There are options --print_result
and --print_stat
for this. Options --no_print_result
and --no_print_stat
disable it.
nornir-scrapli send_command
options, as instance:
$ nornir_cli nornir-scrapli send_command --help
Usage: nornir_cli nornir-scrapli send_command [OPTIONS] [ARGUMENTS]
Send a single command to device using scrapli
Args:
command: string to send to device in privilege exec mode
strip_prompt: True/False strip prompt from returned output
failed_when_contains: string or list of strings indicating failure
if found in response
timeout_ops: timeout ops value for this operation; only sets the
timeout_ops value for the duration of the operation, value is reset
to initial value after operation is completed
Returns: nornir Result attributes(optional), statistic, progress
bar(optional)
Options:
--pg_bar Progress bar flag
--print_result / --no_print_result
print_result from nornir_utils [default:
print_result]
--print_stat / --no_print_stat Print Result statistic for Nornir object
[default: print_stat]
--command TEXT [required]
--strip_prompt BOOLEAN [default: True]
--failed_when_contains TEXT [default: None]
--timeout_ops TEXT [default: None]
--help Show this message and exit.
The examples above show 2 ways to pass parameters to the command: - using the command option:
$ nornir_cli nornir-netmiko netmiko_send_command --command_string "display clock"
$ nornir_cli nornir-netmiko netmiko_send_command '{"command_string":"display clock"}'
# or
$ nornir_cli nornir-netmiko netmiko_send_command 'command_string=display clock'
# or
$ nornir_cli nornir-netmiko netmiko_send_command '"command_string"="display clock"'
When using options and arguments at the same time, the priority of options will be higher. For example, nornir_cli nornir-netmiko netmiko_send_command --command_string "disp ver" '{"command_string":"disp clock"}'
will send disp ver
command to device.
Result processing#
print_result
As you can see, you can disable default option --print_result
, --print_stat
and use print_result
command instead of these.
--print_result
option uses default arguments, but print_result
command allows you to customize the output. You can output class Result
attributes, limit results with --count
option, print statistic with --print_stat
option, etc.
Let's see print_result
options and run it:
$ nornir_cli nornir-scrapli print_result --help
Usage: nornir_cli nornir-scrapli print_result [OPTIONS]
print_result from nornir_utils
Options:
-ph, --print_host BOOLEAN Print hostnames [default: True]
-attrs, --attributes TEXT Result class attributes you want to print
-ps, --print_stat / -no_ps, --no_print_stat
Print Result statistic for Nornir object
[default: no_ps]
-cou, --count INTEGER Results counter
-sl, --severity_level [CRITICAL|ERROR|WARNING|INFO|DEBUG|NOTSET]
Show only errors with this severity level or
higher [default: INFO]
--failed BOOLEAN If True assume the task failed [default:
False]
--help Show this message and exit.
$ nornir_cli nornir-scrapli send_command --command "disp clock" --no_print_result --no_print_stat print_result -attrs '["result", "diff"]' -ps
# or using json string as command argument
# please note that the arguments must be specified after the options
# $ nornir_cli nornir-scrapli send_command --no_print_result --no_print_stat '{"command":"disp clock"}' print_result -attrs '["result", "diff"]' -ps
send_command********************************************************************
* dev_1 ** changed : False *****************************************************
vvvv send_command ** changed : False vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv INFO
2021-10-03 16:40:06+03:00
Sunday
Time Zone(Moscow) : UTC+03:00
^^^^ END send_command ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
dev_1 : ok=1 changed=0 failed=0
OK : 1
CHANGED : 0
FAILED : 0
# send_command doesn't have "diff" attribute, so it's not displayed
write_result and write_results
Result can be written to a file using write_result
command for all hosts from current Inventory.
By default, write_result
tries to create a file in the current directory or in the specified directory, if file doesn't exist.
write_result
command has many options. For example, you can exclude errors from a file, write "diff" to another file or output it, use different write modes, limit entries number, etc.
If you want to see which hosts have completed the task with an error, but do not add errors to the files, use --no_errors
or -ne
with --print_stat
or -ps
option.
$ nornir_cli nornir-scrapli write_result --help
Usage: nornir_cli nornir-scrapli write_result [OPTIONS]
Write an object of type `nornir.core.task.Result` to file
Options:
-f, --filename TEXT File you want to write into [required]
-ne, --no_errors Do not write errors to file [default:
False]
-wh, --write_host BOOLEAN Write hostnames [default: True]
-dtf, --diff_to_file PATH Write diff to file
-pd, --print_diff / -no_pd, --no_print_diff
Print diff [default: no_pd]
-a, --append Whether you want to replace the contents or
append to it [default: False]
-attrs, --attributes TEXT Result attributes you want to write (str or
list(json string)). There can be any Result
attributes or text. By default, the result
attribute is used
-ps, --print_stat / -no_ps, --no_print_stat
Print Result statistic for Nornir object
[default: no_ps]
-cou, --count INTEGER Results counter
-sl, --severity_level [CRITICAL|ERROR|WARNING|INFO|DEBUG|NOTSET]
Show only errors with this severity level or
higher [default: INFO]
--failed BOOLEAN If True assume the task failed [default:
False]
--help Show this message and exit.
$ nornir_cli nornir-scrapli send_command --command "disp clock" --no_print_result --no_print_stat write_result -f test.txt -ne -ps -attrs '["result", "diff"]'
# or using json string as command argument
# please note that the arguments must be specified after the options
# $ nornir_cli nornir-scrapli send_command --no_print_result --no_print_stat '{"command":"disp clock"}' write_result -f test.txt -ne -ps -attrs '["result", "diff"]'
dev_1 : ok=1 changed=0 failed=0
OK : 1
CHANGED : 0
FAILED : 0
# send_command doesn't have "diff" attribute, so it's not displayed
vvvv dev_1: ** send_command ** changed : False INFO
2021-10-03 17:03:41+03:00
Sunday
Time Zone(Moscow) : UTC+03:00
Result can be written to a files with hostnames as filenames using write_results
command for all hosts from current Inventory. For example, it is usefull for diagnostic commands, that run many show something
or display something
commands.
By default, write_results
tries to create a specified directory, if it doesn't exist.
write_results
command has the same options as write_result
, but uses -d
or --dirname
instead of -f
or --filename
.
If you want to see which hosts have completed the task with an error, but do not add errors to the files, use --no_errors
or -ne
with --print_stat
or -ps
option.
$ nornir_cli nornir-scrapli write_results --help
Usage: nornir_cli nornir-scrapli write_results [OPTIONS]
Write an object of type `nornir.core.task.Result` to files with hostname
names
Options:
-d, --dirname TEXT Direcotry you want to write into [required]
-ne, --no_errors Do not write errors to file [default:
False]
-wh, --write_host BOOLEAN Write hostnames [default: True]
-dtf, --diff_to_file PATH Write diff to file
-pd, --print_diff / -no_pd, --no_print_diff
Print diff [default: no_pd]
-a, --append Whether you want to replace the contents or
append to it [default: False]
-attrs, --attributes TEXT Result attributes you want to write (str or
list(json string)). There can be any Result
attributes or text. By default, the result
attribute is used
-ps, --print_stat / -no_ps, --no_print_stat
Print Result statistic for Nornir object
[default: no_ps]
-cou, --count INTEGER Results counter
-sl, --severity_level [CRITICAL|ERROR|WARNING|INFO|DEBUG|NOTSET]
Show only errors with this severity level or
higher [default: INFO]
--failed BOOLEAN If True assume the task failed [default:
False]
--help Show this message and exit.
$ nornir_cli nornir-scrapli send_command --command "disp clock" --no_print_result --no_print_stat write_results -d test -ne -ps -attrs '["result", "diff"]'
# or using json string as command argument
# please note that the arguments must be specified after the options
# $ nornir_cli nornir-scrapli send_command --no_print_result --no_print_stat '{"command":"disp clock"}' write_results -d test -ne -ps -attrs '["result", "diff"]'
dev_1 : ok=1 changed=0 failed=0
OK : 1
CHANGED : 0
FAILED : 0
# send_command doesn't have "diff" attribute, so it's not displayed
vvvv dev_1 ** send_command ** changed : False INFO
2021-10-03 17:28:57+03:00
Sunday
Time Zone(Moscow) : UTC+03:00
write_file
write_file
command writes any text to a file with the required number of indents. So you can add some useful data to previously generated file test.txt
:
$ nornir_cli nornir-scrapli write_file --help
Usage: nornir_cli nornir-scrapli write_file [OPTIONS]
Write_file, but not from nornir_utils
Options:
-l, --line_feed number of \n before text [default: 0;x>=0]
-a, --append Whether you want to replace the contents or append to
it [default: False]
-c, --content TEXT Content you want to write (string) [required]
-f, --filename TEXT File you want to write into [required]
--help Show this message and exit.
$ nornir_cli nornir-scrapli write_file -lll -a -c "some useful data" -f test.txt
vvvv dev_1 ** send_command ** changed : False INFO
2021-10-03 17:03:41+03:00
Sunday
Time Zone(Moscow) : UTC+03:00
some useful data
What about netconf?#
If some devices support netconf, you can use nornir-scrapli
, nornir-netconf
or nornir-pyez
Nornir plugins from nornir_cli
.
Here is easy way to get xml tree from yang
As instance,dev_3
understands netconf XML. Let's get nornir.core.Nornir
object for dev_3
and run some netconf command with nornir-scrapli and nornir-netconf:
nornir-scrapli:
$ nornir_cli nornir-scrapli init -u username -p password -co '{"scrapli": {"platform": "huawei_vrp", "extras":{"ssh_config_file": true}}}' filter --hosts -s 'name=dev_3'
[
"dev_3"
]
$ nornir_cli nornir-scrapli netconf_get --filter_='<ifm xmlns="http://www.huawei.com/netconf/vrp/huawei-ifm"><interfaces><interface><ifName/></interface></interfaces></ifm>' --filter_type subtree
# or
# $ nornir_cli nornir-scrapli netconf_get --filter_ '<ifm xmlns="http://www.huawei.com/netconf/vrp/huawei-ifm"><interfaces><interface><ifName/></interface></interfaces></ifm>' --filter_type subtree
...
netconf_get*********************************************************************
* dev_3 ** changed : False *****************************************************
vvvv netconf_get ** changed : False vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv INFO
<rpc-reply xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" message-id="101">
<data>
<ifm xmlns="http://www.huawei.com/netconf/vrp/huawei-ifm">
<interfaces>
<interface>
<ifIndex>1</ifIndex>
<ifName>Virtual-Template0</ifName>
</interface>
...
<interface>
<ifIndex>717</ifIndex>
<ifName>GigabitEthernet4/1/1.514</ifName>
</interface>
</interfaces>
</ifm>
</data>
</rpc-reply>
^^^^ END netconf_get ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
dev_3 : ok=1 changed=0 failed=0
OK : 1
CHANGED : 0
FAILED : 0
nornir-netconf with write_result command:
nornir_cli nornir-netconf init -u username -p password -c None -co '{"netconf": {"extras":{"allow_agent": false, "look_for_keys": false, "hostkey_verify": false}}}' -f 'inventory={"plugin":"NetBoxInventory2", "options": {"nb_url": "http://your_netbox_domain", "nb_token": "your_netbox_token", "ssl_verify": false}} runner={"plugin": "threaded", "options": {"num_workers": 50}}'
$ nornir_cli nornir-netconf filter -s 'name=dev_3'
[
"dev_3"
]
$ nornir_cli nornir-netconf netconf_get --path '<ifm xmlns="http://www.huawei.com/netconf/vrp/huawei-ifm" content-version="1.0" format-version="1.0"> <interfaces> <interface> <ifName/> </interface> </interfaces></ifm>' --filter_type subtree --no_print_result --no_print_stat write_result -f netconf.txt
vvvv dev_3: netconf_get ** changed : False vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv INFO
{'error': None, 'errors': [], 'ok': True, 'rpc': <?xml version="1.0" encoding="UTF-8"?>
<rpc-reply message-id="urn:uuid:3" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
<data>
<ifm xmlns="http://www.huawei.com/netconf/vrp/huawei-ifm">
<interfaces>
<interface>
<ifName>Virtual-Template0</ifName>
</interface>
<interface>
<ifName>NULL0</ifName>
</interface>
<interface>
<ifName>GigabitEthernet0/0/0</ifName>
</interface>
...
</interfaces>
</ifm>
</data>
</rpc-reply>}
What about http, xlsx, jinja2?#
nornir_cli
includes nornir-http
, nornir-pyxl
, nornir-jinja2
Nornir plugins.
Remember that when using these plugins, each command is run for each host from the Inventory. Therefore, if you need to process xlsx
, execute http request
or get a single jinja2
template without binding to devices, then run the command from the Nornir plugin for one device from the Inventory.
See examples
Command chains#
And, of course, you can run any command chains, even very scary ones. For nornir_cli
version <= 1.2.0
, you can use the following syntax:
$ nornir_cli nornir-scrapli init -u username -p password \
-co '{"scrapli": {"platform": "huawei_vrp", "extras":{"ssh_config_file": true}}}' \
filter --hosts -s 'name=dev_1' send_command --command "display clock" \
send_interactive --interact_events '[["save", "Are you sure to continue?[Y/N]", false], \
["Y", "Save the configuration successfully.", true]]'
For nornir_cli
version >= 1.3.0
, you can use only json strings as an argument:
# $ nornir_cli nornir-scrapli init -u username -p password \
-co '{"scrapli": {"platform": "huawei_vrp", "extras":{"ssh_config_file": true}}}' \
filter --hosts -s '{"name":"dev_1"}' send_command '{"command":"display clock"}' \
send_interactive '{"interact_events":[["save", "Are you sure to continue?[Y/N]", false], \
["Y", "Save the configuration successfully.", true]]}'
[
"dev_1"
]
send_command********************************************************************
* dev_1 ** changed : False *****************************************************
vvvv send_command ** changed : False vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv INFO
2021-03-19 14:12:38+03:00
Friday
Time Zone(Moscow) : UTC+03:00
^^^^ END send_command ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
dev_1 : ok=1 changed=0 failed=0
OK : 1
CHANGED : 0
FAILED : 0
send_interactive****************************************************************
* dev_1 ** changed : True ******************************************************
vvvv send_interactive ** changed : True vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv INFO
^^^^ END send_interactive ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
dev_1 : ok=1 changed=1 failed=0
OK : 1
CHANGED : 1
FAILED : 0
Again, i repeat that each argument can be passed to the Task as a json string.
Runbook collections#
If you solve some automation tasks with the Nornir, then you, probably, have Nornir runbooks.You can use nornir_cli
as interface for manage these Nornir runbooks.
Create any directory trees in the custom_commands
directory and put your Nornir runbooks there, following the simple rules. Then run them for any hosts from CLI, managing your inventory with nornir_cli
. This is very similar to Ansible Roles
.
Let's create a collection of your Nornir runbooks using nornir_cli
.
For example, I have Nornir runbook called "cmd_dhcp_snooping.py"
, and I want to add it to a dhcp
group in nornir_cli
.
Then, my directory tree:
$ tree ~/virtenvs/py3.8.4/lib/python3.8/site-packages/nornir_cli/custom_commands/
/home/user/virtenvs/py3.8.4/lib/python3.8/site-packages/nornir_cli/custom_commands/
├── dhcp
│ ├── cmd_dhcp_snooping.py
│ └── templates
│ ├── dhcp_snooping.j2
│ └── disp_int.template
└── __init__.py
2 directories, 4 files
And my nornir_cli
structure:
$ nornir_cli
Usage: nornir_cli [OPTIONS] COMMAND [ARGS]...
Nornir CLI
Orchestrate your Inventory and start Tasks and Runbooks
Options:
--version Show the version and exit.
--help Show this message and exit.
Commands:
dhcp
nornir-f5 nornir_f5 plugin
nornir-http nornir_http plugin
nornir-jinja2 nornir_jinja2 plugin
nornir-napalm nornir_napalm plugin
nornir-netconf nornir_netconf plugin
nornir-netmiko nornir_netmiko plugin
nornir-paramiko nornir_paramiko plugin
nornir-pyez nornir_pyez plugin
nornir-pyxl nornir_pyxl plugin
nornir-routeros nornir_routeros plugin
nornir-scrapli nornir_scrapli plugin
$ nornir_cli dhcp
Usage: nornir_cli dhcp [OPTIONS] COMMAND1 [ARGS]... [COMMAND2 [ARGS]...]...
Options:
--help Show this message and exit.
Commands:
change_credentials Change username and password
dhcp_snooping Configure dhcp snooping
filter Do simple or advanced filtering
init Initialize a Nornir
print_result print_result from nornir_utils
show_inventory Show current inventory
write_file Write_file, but not from nornir_utils
write_result Write `Result` object to file
write_results Write `Result` object to files
Ok, let's run the dhcp_snooping
command on all access switches from our NetBox Inventory:
$ nornir_cli dhcp init filter --hosts -s -a 'data__device_type__model__contains=S2320-28TP-EI-DC & name__contains=access'
[
"access_1"
]
$ nornir_cli dhcp dhcp_snooping
access_1 : ok=1 changed=1 failed=0
OK : 1
CHANGED : 1
FAILED : 0
More detailed - How to add your custom Nornir runbook in nornir_cli