Blog Detail
This blog post is the third in a series covering common Python libraries that can be used to interact with network devices. In this post we will cover the Scrapli Python library by Carl Montanari. Per its documentation, Scrapli is the words “scrape” and “cli” (i.e. screen scrape) squished together. Its goal is to provide a thoroughly tested, well typed, well documented, simple API that supports both synchronous and asynchronous interaction with network devices.
Differentiation from Other Libraries
Scrapli is different from other libraries in the following ways:
- Scrapli provides multiple forms of transport. It defaults to using a system’s local SSH binary. This is in contrast to Netmiko, which uses Paramiko for transport. The forms of transport it supports can be found here along with a justification for the decision to allow for multiple transports and default to a system’s local SSH binary.
- Scrapli supports the same platforms as NAPALM out of the box. This is a subset of the platforms supported by Netmiko. The scrapli community project provides the ability for the scrapli community to contribute to and use drivers beyond those included in the base project. The platforms supported out of the box are:
- Cisco IOS-XE
- Cisco NX-OS
- Juniper JunOS
- Cisco IOS-XR
- Arista EOS
- If you’re looking to write unit/integration tests for your code, scrapli has an adjacent library called scrapli-replay that can be used to do so.
Installation
You can install Scrapli via pip install scrapli
. Or, if you are using Poetry, you can use poetry add scrapli
. Other methods for installing scrapli are documented here.
Getting Connected
Note: We will only cover connecting via SSH in this blog post.
To start, you’ll want to import and instantiate one of the scrapli “core” drivers from scrapli.driver.core
.
Scrapli requires a hostname (IP or DNS name) and an authentication method (generally username and password) to get connected. In addition to this, you will also want to specify whether or not to use SSH strict host key checking (we pass in False below).
>>> from scrapli.driver.core import IOSXEDriver
>>>
>>> conn = IOSXEDriver(
... host="192.0.2.3",
... auth_username="cisco",
... auth_password="cisco",
... auth_strict_key=False,
... )
>>> type(conn)
scrapli.driver.core.cisco_iosxe.sync_driver.IOSXEDriver
>>> conn.open()
Note: If host strict key checking is enabled (the default), an SSH session will be permitted only to hosts that have a key defined inside of your system’s “known_hosts” file.
You can also use the Scrapli
class to dynamically select and instantiate a driver (much like ConnectHandler in Netmiko) in the following way:
>>> from scrapli import Scrapli
>>>
>>> conn = Scrapli(
... host="192.0.2.3",
... auth_username="cisco",
... auth_password="cisco",
... auth_strict_key=False,
... platform="cisco_iosxe",
... )
>>> type(conn)
scrapli.driver.core.cisco_iosxe.sync_driver.IOSXEDriver
>>> conn.open()
A list of the basic driver arguments can be found here.
Sending Commands
Once you have instantiated your Driver
object, you can send single show commands via the .send_command()
method. You will use the same command syntax you would type in if you were directly connected to the device via SSH:
>>> response = conn.send_command("show ip interface brief")
>>> print(response.result)
Interface IP-Address OK? Method Status Protocol
FastEthernet0 unassigned YES NVRAM down down
GigabitEthernet1/0/1 192.0.2.3 YES unset up up
GigabitEthernet1/0/2 unassigned YES unset up up
GigabitEthernet1/0/3 unassigned YES unset up up
>>> print(response.failed)
False
Likewise, you can send multiple commands using the .send_commands()
method.
>>> response = conn.send_commands(["show ip interface brief", "show running-config | include hostname"])
>>> print(response.result[0])
Interface IP-Address OK? Method Status Protocol
FastEthernet0 unassigned YES NVRAM down down
GigabitEthernet1/0/1 192.0.2.3 YES unset up up
GigabitEthernet1/0/2 unassigned YES unset up up
GigabitEthernet1/0/3 unassigned YES unset up up
>>> print(response.result[1])
hostname cisco
You can also send commands from a file using the .send_commands_from_file()
method.
# commands.txt
show ip int br
show run | i hostname
response = conn.send_commands_from_file("commands.txt")
>>> print(response.result[0])
Interface IP-Address OK? Method Status Protocol
FastEthernet0 unassigned YES NVRAM down down
GigabitEthernet1/0/1 192.0.2.3 YES unset up up
GigabitEthernet1/0/2 unassigned YES unset up up
GigabitEthernet1/0/3 unassigned YES unset up up
>>> print(response.result[1])
hostname cisco
If you want to run a command to edit the configuration, you would use the .send_configs()
method instead. This method takes care of entering configuration mode for you, and it requires the commands be in a list or set:
>>> response = conn.send_configs(["interface Gi1/0/3", "no description"])
>>> print(response.result)
configure terminal
Enter configuration commands, one per line. End with CNTL/Z.
cisco(config)#interface Gi1/0/3
cisco(config-if)#no description
Note: The send_configs() method doesn’t exit config mode like Netmiko does. It, instead, relies on the
send_command()
method to acquire the user exec mode prompt.
As is the case with .send_commands()
, you can also send configurations from a file using the send_configs_from_file()
method.
# config_changes.txt
interface Gi1/0/3
no description
>>> response = conn.send_configs_from_file("config_changes.txt")
>>> print(response.result)
configure terminal
Enter configuration commands, one per line. End with CNTL/Z.
cisco(config)#interface Gi1/0/3
cisco(config-if)#no description
Finally, there is a send_config()
method that will parse the configuration provided as input and split it into lines, each line being sent to the device. This is useful for copying full configs over to the device.
Command Output Parsing
We’ve covered parsing strategies here on this blog before. Just as with Netmiko, Scrapli supports TextFSM, TTP, and Genie. Let’s take a quick look on how to use them with Scrapli.
TextFSM
Scrapli defines TextFSM as an “extra”. As such, the first step to using TextFSM templates with scrapli is to install the TextFSM library. You can use pip or Poetry to do so.
pip install 'scrapli[textfsm]'
poetry add 'scrapli[textfsm]'
Once TextFSM is installed, you can use the .textfsm_parse_output()
method on a Scrapli response object to return the output as parsed by the NTC template. This method uses the platform inferred by the driver to set the textfsm-platform
. It combines this with the command sent to the device to guess as to which template it should use to parse the returned data.
>>> response = conn.send_command("show interfaces")
>>> print(response.textfsm_parse_output())
[{'abort': '',
'address': '381c.1ae6.cd81',
'bandwidth': '100000 Kbit',
'bia': '381c.1ae6.cd81',
'crc': '0',
'delay': '100 usec',
...
You can see the template used for this command here.
Scrapli also supports defining the template that should be used to parse the response manually. You can import and use the textfsm_parse
function from scrapli.helper
to do so.
>>> from scrapli.helper import textfsm_parse
>>>
>>> response = conn.send_command("show interfaces")
>>> structured_result = textfsm_parse("/path/to/template", response.result)
TTP
Scrapli also supports the TTP parsing library. As with TextFSM, you will need to install it via pip install ttp
or poetry add ttp
before it can be used. The TTP installation does not currently include any templates, so you will need to find or create your own and provide the path to those templates.
>>> response = conn.send_command("show interfaces")
>>> structured_result = response.ttp_parse_output(template="show_interfaces_template.ttp")
>>> pprint(structured_result)
[[[{'description': 'CAM1',
'interface': 'GigabitEthernet1/0/1',
'link_status': 'up',
'protocol_status': 'up'},
{'description': 'CAM2',
'interface': 'GigabitEthernet1/0/2',
'link_status': 'up',
'protocol_status': 'up'},
...
Genie
The last parser that Scrapli currently supports is Genie. As with TextFSM and TTP, scrapli does not install Genie nor its required library, pyATS, by default, so you will need to install them separately via pip install 'pyats[library]'
or poetry add 'pyats[library]'
. Athough Genie parsers exist for non-Cisco platforms, In Scrapli, Genie parsers can be used only for Cisco devices.
>>> response = conn.send_command("show interfaces")
>>> structured_result = response.genie_parse_output()
>>> pprint(structured_result)
{'GigabitEthernet1/0/1': {'arp_timeout': '04:00:00',
'arp_type': 'arpa',
'bandwidth': 100000,
'connected': True,
'counters': {'in_broadcast_pkts': 41240,
...
Note: Genie does not support custom templates.
Next Steps
- Perhaps you’d like to use asyncio for interactions with network devices, or learn more advanced concepts? The documentation is excellent, and a great place to start.
- If you’d like more examples of common interactions using scrapli, Carl has created a directory with such examples here.
- Scrapli has an ecosystem including a few adjacent tools that are worth checking out (scrapli_netconf, scrapli_nornir…etc.).
Conclusion
I hope you enjoy Scrapli. It’s an excellent tool and is my personal go-to tool for new projects in which I need to automate interactions with devices for which it has a driver.
-Phillip
New to Python libraries? NTC’s Training Academy is holding a 3-day course Automating Networks with Python I on September 26-28, 2022 with 50% labs to get you up to speed.
Visit our 2022 public course schedule to see our full list.
Contact Us to Learn More
Share details about yourself & someone from our team will reach out to you ASAP!