Blog>>Networks>>Network automation>>Python Paramiko and Netmiko for automation

Python Paramiko and Netmiko for automation

Python, with its simplicity and versatility, has emerged as a powerful programming language for infrastructure automation. It is the best option for engineers and administrators to start programming and automate their work. With many useful libraries, Python allows you to quickly implement an infrastructure management strategy tailored to your situation.

This article is an introduction to Paramiko and Netmiko, which are the most popular Python SSH libraries. It should be valuable to both administrators and developers who want to start their automation journey and become aware of the differences between server host automation and network device automation.

Agentless automation with SSH

In agentless automation, automation tasks are performed on remote systems without software agents installed on those systems. Unlike agent-based automation implemented with tools such as Puppet or Chef, agentless automation relies on remote management protocols such as SSH or WinRM to execute commands remotely. Agentless automation is easier to implement because it reuses existing management protocols. It also has lower administrative costs since one, or at most several, central automation agents need to be deployed and managed.

The most popular tool used to establish agentless automation is SSH (Secure Shell). SSH is a protocol for secure system administration, file transfers, and other communication across the Internet or other untrusted networks. It encrypts identities, passwords and transmitted data to prevent eavesdropping and theft. SSH is widely used because it provides security using various authentication and encryption methods and is standardized. Thanks to many existing implementations, including open source, SSH is in widespread use. SSH is used to configure services and retrieve configuration settings and state parameters. It is one of the key components of higher-level automation tools such as Ansible, Napalm, and Nornir.

Paramiko

Paramiko      link-icon is a handy LGPL-licensed library that implements the SSHv2 protocol. It is written in pure Python, so it can be easily installed and used to connect to any system that provides an SSH service. For these reasons, it has become a first choice if someone wants to play with agentless automation. However, simplicity of use is not everything. Its functionality and implementation are modeled on OpenSSH, the most commonly used SSH protocol implementation. This origin makes Paramiko versatile and very useful in more complex scenarios.

That is possible because it provides full implementation of all internal SSH components, i.e.: transport layer (RFC4252      link-icon), user authentication (RFC4253      link-icon) and connection protocols (RFC4254      link-icon). Additionally, it implements Secure File Transfer Protocol (SFTP) over SSH channels, which can be used to manage remote files and transfer them in both directions.

Fig.1: SSH components implemented by Paramiko
SSH components implemented by Paramiko

Paramiko usage example

Let's skip the details of Paramiko’s low-level SSH components and focus on the fact that Paramiko provides a high-level API that simplifies the creation of SSH clients, servers or port forwarders. We can check the use of Paramiko in a simple scenario. We would like to connect to a Linux host and fetch all network interfaces. The use of Paramiko.SSHClient is shown in Listing 1. 

import paramiko 

ssh = paramiko.SSHClient() ssh.set_missing_host_key_policy(paramiko.WarningPolicy())
key = paramiko.ECDSAKey.from_private_key_file('host_ecdsa_256.key')
ssh.connect('192.168.0.1', username='user', pkey=key)
stdin, stdout, stderr = ssh.exec_command('ip addr show') 
output = stdout.read().decode()
ssh.close()

Listing. 1 Example implementation of SSH client using Paramiko

Looking at the code, we can see that once the SSHClient instance is created, a policy is established to warn about unknown host keys. WarningPolicy allows you to seamlessly connect to any new host, while RejectPolicy should be used in production environments.  Later, a private ECDSA key is loaded to connect to the host machine (Paramiko can also use RSA, DSA or Ed25519 keys). Finally, a connection to the server is established and the required Linux command is remotely executed on the host. The command result is read from the standard output and decoded as UTF-8. Unfortunately, this is only a raw string of characters, so additional operations must be performed to parse it; e.g. the IP addresses of the interfaces. Extracting the required information from command results is beyond the scope of the Paramiko library.

Executing simple commands in the SSH EXEC channel

The Paramiko usage example in the previous section uses the SSHClient.exec_command method. This method creates an SSH EXEC channel. An EXEC channel accepts a single command or a set of commands, but does so only at the time the channel is created. The SSH server executes the commands received from the channel and returns all generated output when execution is complete. 

Fig.2: The SSH EXEC channel behavior
The SSH EXEC channel behavior

Linux SSH servers execute commands from the EXEC channel mainly in non-interactive and non-login shells. It is important to know what environment a command is being executed in as it can have a significant impact on the behavior of commands, especially those that are parameterized by environment variables. This may happen because some startup scripts (e.g. ~/.bash_profile) may not execute and environment variables may be set differently. By default, the EXEC channel doesn’t use terminal emulation to avoid commands to do fancy things like adjusting output to terminal width and height, pagination, and coloring. In summary, the EXEC channel is ideal for automating simple commands for which you can collect output.

The SSH SHELL channel for interactive applications

When an interactive application needs to be automated, a different type of SSH channel is required. The recommended channel type is SSH SHELL. Thanks to the SHELL channel, additional input data can be provided to the application, such as additional "yes/no" confirmations, option selections or set values. This channel continuously puts command results into the standard output stream. Linux SSH servers execute commands from the SHELL channel mainly in interactive and login shells. This is the same environment where you log in manually using an SSH terminal client.

Fig.3: The SSH SHELL channel behavior
The SSH SHELL channel behavior

In Paramiko, the output of the SHELL channel is exposed in the form of stdin and stderr streams, which require more complex handling, similar to the use of network sockets. All command output becomes unstructured in the output stream, and the automation code must recognize different parts of the results. The time aspects of communication, such as the waiting time for specific information, should also be properly determined.

Why isn’t Paramiko enough for network automation?

Most Linux and BSD systems use OpenSSH as their implementation of the SSH protocol. This implementation runs as a daemon called sshd. Compared to servers, network devices have their own SSH server implementation quirks which causes important differences when establishing a connection. An example of such a dissimilarity is how the user is authenticated. In the case of hosts, mechanisms built into the SSH protocol are always used for this purpose. However, in the case of network devices, there are cases where user authentication takes place in a separate application launched immediately after establishing an SSH session.

The second significant difference between network devices and hosts is the use of specialized CLI shells that allow easy navigation through a large number of available commands. Network equipment manufacturers treat shells as their intellectual property and trademark, and carefully cultivate differences in the behavior of their shells. This causes shells from different manufacturers to behave differently and have different command hierarchies. Therefore, implementing automation for network devices using Paramiko itself is much more complicated than it might initially seem. A few years ago, the user support for Paramiko (aka GitHub issues) was full of problems with people trying to connect to various network devices or execute specific commands. Currently, such unfortunate people are quickly redirected to another library: Netmiko.

Python Netmiko library to rescue

Netmiko      link-icon is an open-source, Python MIT-licensed library designed to interact with a wide range of network devices (Cisco, Juniper, Arista, Huawei, and many others      link-icon). It hides low-level differences between different vendors and provides a high-level API that exposes common behaviors of many web CLI shells (e.g. the existence of operational/configuration modes) in a consistent way.

Netmiko uses several communication technologies that enable the automation of network devices. The most important of these is SSH, which is supported on Netmiko using Paramiko. SCP is available through the scp library      link-icon (it is also implemented on top of Paramiko). Netmiko also supports telnet (using telnetlib      link-icon) and serial (using pyserial      link-icon). Additionally, SNMP (pysnmp      link-icon) is used, but only for automatic device type detection, which helps select the appropriate device driver.

Fig.4: Communication protocols supported by Netmiko
 Communication protocols supported by Netmiko

Netmiko usage example

Let's demonstrate using Netmiko to connect to a Cisco IOS router to obtain the IP addresses of all interfaces. Please refer to Listing. 2 below.

import netmiko

cisco = {
    'device_type': 'cisco_ios',
    'host': '192.168.0.10',
    'username': 'user',
    'use_keys': True,
    'key_file': 'cisco_rsa.key',
    'disabled_algorithms': {'pubkeys': 
        ['rsa-sha2-512', 'rsa-sha2-256']}
}
with netmiko.ConnectHandler(**cisco) as ssh:
    interfaces = ssh.send_command('show ip interface brief',
                                  use_textfsm=True)
ip_addresses = (interface['ipaddr'] for interface in interfaces)

Listing. 2 Example implementation of SSH client using Paramiko

This example uses the netmiko.ConnectHandler factory function. ConnectHandler requires device type information and other access arguments. Using these arguments, ConnectHandler creates a dedicated SSH client for the Cisco IOS router. The appropriate Cisco command is then sent. The use_textfsm argument is set so that send_command returns fully parsed interface information using NTC templates      link-icon (this is a large collection of TestFSM      link-icon templates for parsing network device text output). Since the returned output of the command is a list of Python dictionaries describing the attributes of each interface, the user of the Netmiko library can easily filter the required information (i.e. interface IP addresses).

If the type of network device is not known, the Netmiko library user should first try using the netmiko.ssh_autodetect module. It will most likely provide the correct device type.

What problems does Netmiko solve?

A network automation engineer’s work is much easier using Netmiko. The list of the most important Netmiko functionalities is presented in Fig. 5.

Fig.5: Common issues solved by Netmiko
Common issues solved by Netmiko

The library includes a long list of dedicated SSH clients for many types of network devices. Each Netmiko client implements the necessary quirks enabling successful login to a specific network platform (i.e. non-standard user authentication methods, additional user confirmations immediately after the login, skipping login banners). After logging in, the library user can easily change CLI mode to privileged and configuration mode. Additionally, each dedicated SSH client includes the expected prompts for a specific mode. 

Netmiko also provides a number of features required to successfully execute commands. First, device-specific window size settings are applied to created SSH channels and pagination is disabled, so that structured and multiline commands produce clear results. Secondly, Netmiko supports parsing command output using TestFSM      link-icon, Genie      link-icon and TTP      link-icon libraries. Some network devices copy commands to output, but Netmiko can automatically remove them from the generated output. The library also provides useful commands      link-icon and their options to handle commands that generate additional questions instead of the expected prompts.

Many network devices experience problems with slowdown periods when responding to commands. For this reason, Netmiko implements a hierarchy of delay factors      link-icon as well as different command timing strategies. Finally, it provides a convenient method for saving/committing a new configuration.

What if performance really matters?

Both Paramiko and Netmiko are implemented in pure Python, so there are situations where their low performance is problematic. This may be important when building automation systems for hundreds or thousands of nodes. In this case, there are alternative open-source Python SSH libraries that could be a better fit:

Both libraries excel when used directly to process hundreds of calls in parallel, as documented here      link-icon. However, you should be prepared for installation issues and problems in successful connections to many network devices.

Summary

This article introduced you to the two most popular Python libraries for the SSH protocol. The first is Paramiko, a solid solution that will help you automate your work on servers. With Paramiko, you can automate both simple applications or scripts as well as programs with more interactive behavior. The second library is Netmiko, which is indispensable when you want to remotely manage network devices. It supports many important behaviors of various network equipment manufacturers and provides parsed command results.

However, when performance is a deciding factor, it's worth trying one of the asynchronous SSH implementations such as parallel-ssh or asyncssh.

Parniewicz  Damian

Damian Parniewicz

Senior Software Engineer

Damian Parniewicz is a Senior Software Engineer with nearly 20 years of experience. He specializes in networking technologies. His previous roles included network systems design, implementation and deployment, IT and network infrastructure provisioning, as well as problem solving for network protocols,...Read about author >

Read also

Get your project estimate

For businesses that need support in their software or network engineering projects, please fill in the form and we’ll get back to you within one business day.

For businesses that need support in their software or network engineering projects, please fill in the form and we’ll get back to you within one business day.

We guarantee 100% privacy.

Trusted by leaders:

Cisco Systems
Palo Alto Services
Equinix
Jupiter Networks
Nutanix