Skip to main content

Asynchronous parallel SSH library

Project description

Non-blocking, asynchronous parallel SSH client library.

Run SSH commands over many - hundreds/hundreds of thousands - number of servers asynchronously and with minimal system load on the client host.

Native code based client with extremely high performance - based on libssh2 C library.

License Latest Version https://travis-ci.org/ParallelSSH/parallel-ssh.svg?branch=master https://ci.appveyor.com/api/projects/status/github/parallelssh/parallel-ssh?svg=true&branch=master https://codecov.io/gh/ParallelSSH/parallel-ssh/branch/master/graph/badge.svg https://img.shields.io/pypi/wheel/parallel-ssh.svg Latest documentation

Installation

pip install parallel-ssh

Usage Example

See documentation on read the docs for more complete examples.

Run uname on two remote hosts in parallel with sudo.

from __future__ import print_function

from pssh.pssh_client import ParallelSSHClient

hosts = ['myhost1', 'myhost2']
client = ParallelSSHClient(hosts)

output = client.run_command('uname')
for host, host_output in output.items():
    for line in host_output.stdout:
        print(line)
Output:
Linux
Linux

Native client

Starting from version 1.2.0, a new client is supported in parallel-ssh which offers much greater performance and reduced overhead than the current default client.

The new client is based on libssh2 via the ssh2-python extension library and supports non-blocking mode natively. Binary wheel packages with libssh2 included are provided for Linux, OSX and Windows platforms and all supported Python versions.

See this post for a performance comparison of the available clients.

To make use of this new client, ParallelSSHClient can be imported from pssh.pssh2_client instead. Their respective APIs are almost identical.

The new client will become the default and will replace the current pssh.pssh_client in a new major version of the library - 2.0.0 - once remaining features have been implemented.

The current default client will remain available as an option under a new name.

For example:

from pprint import pprint
from pssh.pssh2_client import ParallelSSHClient

hosts = ['myhost1', 'myhost2']
client = ParallelSSHClient(hosts)

output = client.run_command('uname')
for host, host_output in output.items():
    for line in host_output.stdout:
        print(line)

See documentation for a feature comparison of the two clients.

Native Code Client Features

  • Highest performance and least overhead of any Python SSH libraries

  • Thread safe - makes use of native threads for blocking calls like authentication

  • Natively non-blocking utilising libssh2 via ssh2-python - no monkey patching of the Python standard library

  • Significantly reduced overhead in CPU and memory usage

Exit codes

Once either standard output is iterated on to completion, or client.join(output) is called, exit codes become available in host output. Iteration ends only when remote command has completed, though it may be interrupted and resumed at any point.

for host in output:
    print(output[host].exit_code)
Output:
0
0

The client’s join function can be used to wait for all commands in output object to finish:

client.join(output)

Similarly, output and exit codes are available after client.join is called:

from pprint import pprint

output = client.run_command('exit 0')

# Wait for commands to complete and gather exit codes.
# Output is updated in-place.
client.join(output)
pprint(output.values()[0].exit_code)

# Output remains available in output generators
for host, host_output in output.items():
    for line in host_output.stdout:
        pprint(line)
Output:
0
<..stdout..>

There is also a built in host logger that can be enabled to log output from remote hosts. The helper function pssh.utils.enable_host_logger will enable host logging to stdout.

To log output without having to iterate over output generators, the consume_output flag must be enabled - for example:

from pssh.utils import enable_host_logger

enable_host_logger()
client.join(client.run_command('uname'), consume_output=True)
Output:
[localhost]       Linux

SFTP

SFTP is supported natively.

To copy a local file to remote hosts in parallel:

from pssh.pssh_client import ParallelSSHClient
from pssh.utils import enable_logger, logger
from gevent import joinall

enable_logger(logger)
hosts = ['myhost1', 'myhost2']
client = ParallelSSHClient(hosts)
cmds = client.copy_file('../test', 'test_dir/test')
joinall(cmds, raise_error=True)
Output:
Copied local file ../test to remote destination myhost1:test_dir/test
Copied local file ../test to remote destination myhost2:test_dir/test

There is similar capability to copy remote files to local ones suffixed with the host’s name with the copy_remote_file function.

Directory recursion is supported in both cases via the recurse parameter - defaults to off.

See SFTP documentation for more examples.

Design And Goals

parallel-ssh’s design goals and motivation are to provide a library for running non-blocking asynchronous SSH commands in parallel with little to no load induced on the system by doing so with the intended usage being completely programmatic and non-interactive.

To meet these goals, API driven solutions are preferred first and foremost. This frees up developers to drive the library via any method desired, be that environment variables, CI driven tasks, command line tools, existing OpenSSH or new configuration files, from within an application et al.

Comparison With Alternatives

There are not many alternatives for SSH libraries in Python. Of the few that do exist, here is how they compare with parallel-ssh.

As always, it is best to use a tool that is suited to the task at hand. parallel-ssh is a library for programmatic and non-interactive use - see Design And Goals. If requirements do not match what it provides then it best not be used. Same applies for the tools described below.

Paramiko

The default SSH client library in parallel-ssh 1.x.x series.

Pure Python code, while having native extensions as dependencies, with poor performance and numerous bugs compared to both OpenSSH binaries and the libssh2 based native clients in parallel-ssh 1.2.x and above. Recent versions have regressed in performance and have blocker issues.

It does not support non-blocking mode, so to make it non-blocking monkey patching must be used which affects all other uses of the Python standard library. However, some functionality like Kerberos (GSS-API) authentication is not provided by other libraries.

asyncssh

Python 3 only asyncio framework using client library. License (EPL) is not compatible with GPL, BSD or other open source licenses and combined works cannot be distributed.

Therefore unsuitable for use in many projects, including parallel-ssh.

Fabric

Port of Capistrano from Ruby to Python. Intended for command line use and is heavily systems administration oriented rather than non-interactive library. Same maintainer as Paramiko.

Uses Paramiko and suffers from the same limitations. More over, uses threads for parallelisation, while not being thread safe, and exhibits very poor performance and extremely high CPU usage even for limited number of hosts - 1 to 10 - with scaling limited to one core.

Library API is non-standard, poorly documented and with numerous issues as API use is not intended.

Ansible

A configuration management and automation tool that makes use of SSH remote commands. Uses, in parts, both Paramiko and OpenSSH binaries.

Similarly to Fabric, uses threads for parallelisation and suffers from the poor scaling that this model offers.

See The State of Python SSH Libraries for what to expect from scaling SSH with threads, as compared to non-blocking I/O with parallel-ssh.

Again similar to Fabric, its intended and documented use is interactive via command line rather than library API based. It may, however, be an option if Ansible is already being used for automation purposes with existing playbooks, the number of hosts is small, and when the use case is interactive via command line.

parallel-ssh is, on the other hand, a suitable option for Ansible as an SSH client that would improve its parallel SSH performance significantly.

ssh2-python

Wrapper to libssh2 C library. Used by parallel-ssh as of 1.2.0 and is by same author.

Does not do parallelisation out of the box but can be made parallel via Python’s threading library relatively easily and as it is a wrapper to a native library that releases Python’s GIL, can scale to multiple cores.

parallel-ssh uses ssh2-python in its native non-blocking mode with event loop and co-operative sockets provided by gevent for an extremely high performance library without the side-effects of monkey patching - see benchmarks.

In addition, parallel-ssh uses native threads to offload CPU blocked tasks like authentication in order to scale to multiple cores while still remaining non-blocking for network I/O.

pssh.ssh2_client.SSHClient is a single host natively non-blocking client for users that do not need parallel capabilities but still want a non-blocking client with native code performance.

Out of all the available Python SSH libraries, libssh2 and ssh2-python have been shown, see benchmarks above, to perform the best with the least resource utilisation and ironically for a native code extension the least amount of dependencies. Only libssh2 C library and its dependencies which are included in binary wheels.

However, it lacks support for some SSH features present elsewhere like ECDSA keys (PR pending), agent forwarding (PR also pending) and Kerberos authentication - see feature comparison.

Scaling

Some guide lines on scaling parallel-ssh and pool size numbers.

In general, long lived commands with little or no output gathering will scale better. Pool sizes in the multiple thousands have been used successfully with little CPU overhead in the single thread running them in these use cases.

Conversely, many short lived commands with output gathering will not scale as well. In this use case, smaller pool sizes in the hundreds are likely to perform better with regards to CPU overhead in the event loop.

Multiple Python native threads, each of which can get its own event loop, may be used to scale this use case further as number of CPU cores allows. Note that parallel-ssh imports must be done within the target function of the newly started thread for it to receive its own event loop. gevent.get_hub() may be used to confirm that the worker thread event loop differs from the main thread.

Gathering is highlighted here as output generation does not affect scaling. Only when output is gathered either over multiple still running commands, or while more commands are being triggered, is overhead increased.

Technical Details

To understand why this is, consider that in co-operative multi tasking, which is being used in this project via the gevent library, a co-routine (greenlet) needs to yield the event loop to allow others to execute - co-operation. When one co-routine is constantly grabbing the event loop in order to gather output, or when co-routines are constantly trying to start new short-lived commands, it causes contention with other co-routines that also want to use the event loop.

This manifests itself as increased CPU usage in the process running the event loop and reduced performance with regards to scaling improvements from increasing pool size.

On the other end of the spectrum, long lived remote commands that generate no output only need the event loop at the start, when they are establishing connections, and at the end, when they are finished and need to gather exit codes, which results in practically zero CPU overhead at any time other than start or end of command execution.

Output generation is done remotely and has no effect on the event loop until output is gathered - output buffers are iterated on. Only at that point does the event loop need to be held.

User’s group

There is a public ParallelSSH Google group setup for this purpose - both posting and viewing are open to the public.

https://ga-beacon.appspot.com/UA-9132694-7/parallel-ssh/README.rst?pixel

Project details


Release history Release notifications | RSS feed

This version

1.5.5

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

parallel-ssh-1.5.5.tar.gz (93.5 kB view details)

Uploaded Source

Built Distributions

parallel_ssh-1.5.5-cp36-cp36m-win_amd64.whl (106.4 kB view details)

Uploaded CPython 3.6m Windows x86-64

parallel_ssh-1.5.5-cp36-cp36m-win32.whl (97.0 kB view details)

Uploaded CPython 3.6m Windows x86

parallel_ssh-1.5.5-cp36-cp36m-manylinux1_x86_64.whl (1.6 MB view details)

Uploaded CPython 3.6m

parallel_ssh-1.5.5-cp35-cp35m-win_amd64.whl (106.0 kB view details)

Uploaded CPython 3.5m Windows x86-64

parallel_ssh-1.5.5-cp35-cp35m-win32.whl (96.7 kB view details)

Uploaded CPython 3.5m Windows x86

parallel_ssh-1.5.5-cp35-cp35m-manylinux1_x86_64.whl (1.6 MB view details)

Uploaded CPython 3.5m

parallel_ssh-1.5.5-cp34-cp34m-win_amd64.whl (104.0 kB view details)

Uploaded CPython 3.4m Windows x86-64

parallel_ssh-1.5.5-cp34-cp34m-win32.whl (97.6 kB view details)

Uploaded CPython 3.4m Windows x86

parallel_ssh-1.5.5-cp34-cp34m-manylinux1_x86_64.whl (1.6 MB view details)

Uploaded CPython 3.4m

parallel_ssh-1.5.5-cp33-cp33m-manylinux1_x86_64.whl (1.6 MB view details)

Uploaded CPython 3.3m

parallel_ssh-1.5.5-cp27-cp27mu-manylinux1_x86_64.whl (1.6 MB view details)

Uploaded CPython 2.7mu

parallel_ssh-1.5.5-cp27-cp27m-win_amd64.whl (105.3 kB view details)

Uploaded CPython 2.7m Windows x86-64

parallel_ssh-1.5.5-cp27-cp27m-win32.whl (97.3 kB view details)

Uploaded CPython 2.7m Windows x86

parallel_ssh-1.5.5-cp27-cp27m-manylinux1_x86_64.whl (1.6 MB view details)

Uploaded CPython 2.7m

parallel_ssh-1.5.5-cp27-cp27m-macosx_10_12_x86_64.whl (1.2 MB view details)

Uploaded CPython 2.7m macOS 10.12+ x86-64

parallel_ssh-1.5.5-cp27-cp27m-macosx_10_11_x86_64.whl (1.2 MB view details)

Uploaded CPython 2.7m macOS 10.11+ x86-64

parallel_ssh-1.5.5-cp27-cp27m-macosx_10_10_intel.whl (1.3 MB view details)

Uploaded CPython 2.7m macOS 10.10+ intel

File details

Details for the file parallel-ssh-1.5.5.tar.gz.

File metadata

File hashes

Hashes for parallel-ssh-1.5.5.tar.gz
Algorithm Hash digest
SHA256 ee717496c68a4c7ae4f8c7ead539876db452b898d76c0c9ee9382c51d6fab38f
MD5 b34b2c691572940b038b746a6373548f
BLAKE2b-256 44891b37871105f5c3e385b1efbb0495b44fa1c4d776bc561aa106655baf627e

See more details on using hashes here.

File details

Details for the file parallel_ssh-1.5.5-cp36-cp36m-win_amd64.whl.

File metadata

File hashes

Hashes for parallel_ssh-1.5.5-cp36-cp36m-win_amd64.whl
Algorithm Hash digest
SHA256 f228cafb3bd64a77f1aa762ceb3b37959efeb68e1dc5900f9acf462fb542baab
MD5 f9728797cc5b7305f69f379c1ecbd458
BLAKE2b-256 398e826948752c222e3c7e823e8559d7c79ef14d7e3dfc196291ba8a3b34bf00

See more details on using hashes here.

File details

Details for the file parallel_ssh-1.5.5-cp36-cp36m-win32.whl.

File metadata

File hashes

Hashes for parallel_ssh-1.5.5-cp36-cp36m-win32.whl
Algorithm Hash digest
SHA256 a1c9eb02e58f7efcaa202ca54e278119ed7a1d5ea47889bce8b924865c981ba8
MD5 0afdc377149721a641961eb5b0b4b72c
BLAKE2b-256 913f51a3914902d9f14a3712aa6e12658d7df31c3e78f08f82e328f4a5ab1d16

See more details on using hashes here.

File details

Details for the file parallel_ssh-1.5.5-cp36-cp36m-manylinux1_x86_64.whl.

File metadata

File hashes

Hashes for parallel_ssh-1.5.5-cp36-cp36m-manylinux1_x86_64.whl
Algorithm Hash digest
SHA256 4b33cd4ca92c137c9a95d4293a29cb4bed3ede1333bdc31ddc301650780d2a00
MD5 4ebdfdfc08ae9edaeb9c86e456f6b528
BLAKE2b-256 f10b2680a8ec5bb50cfee06b18449e3664d1fc0e7cea480b08569c5580cdabf9

See more details on using hashes here.

File details

Details for the file parallel_ssh-1.5.5-cp35-cp35m-win_amd64.whl.

File metadata

File hashes

Hashes for parallel_ssh-1.5.5-cp35-cp35m-win_amd64.whl
Algorithm Hash digest
SHA256 a0a77f5da0697ac0816ae634cd5c6d6754fdfc067c0141c32a127691fcb35cd2
MD5 fbffabdb5aa6668d9da1dea15caab0fe
BLAKE2b-256 94dc422e3507c1cdce34ca17b0bfb04125d723993ff3368ab702875742b7424e

See more details on using hashes here.

File details

Details for the file parallel_ssh-1.5.5-cp35-cp35m-win32.whl.

File metadata

File hashes

Hashes for parallel_ssh-1.5.5-cp35-cp35m-win32.whl
Algorithm Hash digest
SHA256 99db193dee4252128b479f6f463e5151faaa181c600f18025ca9880da35f0abc
MD5 0873313b3eba4dfcca8082bff47afed8
BLAKE2b-256 bac7a3187f95caa2b2f5e7f70fb490685efc448da0e6f9a30a62ae7dd64ff192

See more details on using hashes here.

File details

Details for the file parallel_ssh-1.5.5-cp35-cp35m-manylinux1_x86_64.whl.

File metadata

File hashes

Hashes for parallel_ssh-1.5.5-cp35-cp35m-manylinux1_x86_64.whl
Algorithm Hash digest
SHA256 71033a7e06829b30c2af87df52ca677bd715f6d22d38ef2eeb6f266d5a1709ab
MD5 9bab732b3c0ab35dde6403505129051d
BLAKE2b-256 c3bb04491f846537024e1288527c062fda8344ad4e8759c8530d65cfac7e27de

See more details on using hashes here.

File details

Details for the file parallel_ssh-1.5.5-cp34-cp34m-win_amd64.whl.

File metadata

File hashes

Hashes for parallel_ssh-1.5.5-cp34-cp34m-win_amd64.whl
Algorithm Hash digest
SHA256 02d38dd809542513d563494217ae6a5a355d41e4adab8d47080e3431e7a0447b
MD5 0ff04c833fc33aac619726686476cdfc
BLAKE2b-256 b4982e5d07ed66977ef1b319a954cf8b2248b231e9219957b3364b2bd34dd185

See more details on using hashes here.

File details

Details for the file parallel_ssh-1.5.5-cp34-cp34m-win32.whl.

File metadata

File hashes

Hashes for parallel_ssh-1.5.5-cp34-cp34m-win32.whl
Algorithm Hash digest
SHA256 f82c1d3297628c2e913eb7d70eec9703e66102c2b04a5ef93d4868a3b1243313
MD5 9f1666d5cd82f23730704bb2f67c9f58
BLAKE2b-256 817ffa09675113c5c2336b7dfa1245a93fc85415bfc38d826e67ccf8364b0785

See more details on using hashes here.

File details

Details for the file parallel_ssh-1.5.5-cp34-cp34m-manylinux1_x86_64.whl.

File metadata

File hashes

Hashes for parallel_ssh-1.5.5-cp34-cp34m-manylinux1_x86_64.whl
Algorithm Hash digest
SHA256 a3a321b5474fcd683adb8e12634799dae36ac442d231fa9ec12e52477aa2307a
MD5 27f7354ca03168f2af3b162db608eb15
BLAKE2b-256 de41921082db1263d502b0dd66dd0ec9a6c2c9d621136d930465deaf8242fd79

See more details on using hashes here.

File details

Details for the file parallel_ssh-1.5.5-cp33-cp33m-manylinux1_x86_64.whl.

File metadata

File hashes

Hashes for parallel_ssh-1.5.5-cp33-cp33m-manylinux1_x86_64.whl
Algorithm Hash digest
SHA256 55cd8036c6d357c4786451cbefdd418b9cc93c737c1dcf42f0a141bdfde8036d
MD5 4b77df13375431d8c736150ab6069668
BLAKE2b-256 00f25a43da28d31f2fa8df88e3c9d8eed14c3d218881c6792b4d0ad8f83bfc10

See more details on using hashes here.

File details

Details for the file parallel_ssh-1.5.5-cp27-cp27mu-manylinux1_x86_64.whl.

File metadata

File hashes

Hashes for parallel_ssh-1.5.5-cp27-cp27mu-manylinux1_x86_64.whl
Algorithm Hash digest
SHA256 5d8fca901c2c0b7424d57bf901014beb75e63bdac104eb03c5663a164896d682
MD5 ed56a9cc7e5b051bd1f0f49a2a4a0291
BLAKE2b-256 a003fe7b013736e70fccc70764de15d32cb8d1ea7c7c0aec54072bf48cafb0b2

See more details on using hashes here.

File details

Details for the file parallel_ssh-1.5.5-cp27-cp27m-win_amd64.whl.

File metadata

File hashes

Hashes for parallel_ssh-1.5.5-cp27-cp27m-win_amd64.whl
Algorithm Hash digest
SHA256 072edea18e89e3abef47e0036a6508b410072c40ec6e3b88fd76985485bab8de
MD5 4d7008bf9d2c5f0c6ac9d4a6a83dba20
BLAKE2b-256 6cff2fdd9308925cf2cae0b9fb84072df078d1b1e4ae6e14749ad2339895410a

See more details on using hashes here.

File details

Details for the file parallel_ssh-1.5.5-cp27-cp27m-win32.whl.

File metadata

File hashes

Hashes for parallel_ssh-1.5.5-cp27-cp27m-win32.whl
Algorithm Hash digest
SHA256 36cf6901b11d9398ba4da0cf43c2d8da5582fb6e7764d072632943422daaa49e
MD5 79cf96c6975f2560b227e06af3cee48d
BLAKE2b-256 1f4de75bf38074ee592c84081011ecb0ae892e41028d773db10b21df81dc3b38

See more details on using hashes here.

File details

Details for the file parallel_ssh-1.5.5-cp27-cp27m-manylinux1_x86_64.whl.

File metadata

File hashes

Hashes for parallel_ssh-1.5.5-cp27-cp27m-manylinux1_x86_64.whl
Algorithm Hash digest
SHA256 3817f9794c8d774df9b3e9fdac4f26ff41dbe5077bfb73925685107b7ca74ba3
MD5 adcb492569aa92a65c97ff43acb23c3d
BLAKE2b-256 08afce8060ce2b473853982cafea63963604cb760a0305411ef27c3a453e8387

See more details on using hashes here.

File details

Details for the file parallel_ssh-1.5.5-cp27-cp27m-macosx_10_12_x86_64.whl.

File metadata

File hashes

Hashes for parallel_ssh-1.5.5-cp27-cp27m-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 12c077d8b49dc513b545c8885ae32144f616d5db66ab88fafa87b47cf10bcf0e
MD5 4ed36109bcde510f5846c248a141524f
BLAKE2b-256 37ef9fbe412d809f455aaea0bfa1a976081d343869ffdf81359cda7d252d19d8

See more details on using hashes here.

File details

Details for the file parallel_ssh-1.5.5-cp27-cp27m-macosx_10_11_x86_64.whl.

File metadata

File hashes

Hashes for parallel_ssh-1.5.5-cp27-cp27m-macosx_10_11_x86_64.whl
Algorithm Hash digest
SHA256 a0844bb2c893241fee082a83b035f2f64e81b1081109a23cd146f55b4d73c8f9
MD5 613b70c22b01df2397614a3027f2baa1
BLAKE2b-256 f254d90bb07a0bb11000e3b321a9c40ad4b706d71932347f468c1430c15f1b20

See more details on using hashes here.

File details

Details for the file parallel_ssh-1.5.5-cp27-cp27m-macosx_10_10_intel.whl.

File metadata

File hashes

Hashes for parallel_ssh-1.5.5-cp27-cp27m-macosx_10_10_intel.whl
Algorithm Hash digest
SHA256 32f9ce6000f400af26180b105711724b293d2e4078a11cac5b03faacacedc2b5
MD5 792fbc04f10f2091c7eb0223abd45c6d
BLAKE2b-256 b5fcfcd01373f02198bb3b6c2204be1f5dd08ccae2cb6d14a6005a07b97a7594

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page