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.2

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.2.tar.gz (93.2 kB view details)

Uploaded Source

Built Distributions

parallel_ssh-1.5.2-cp36-cp36m-win_amd64.whl (106.2 kB view details)

Uploaded CPython 3.6m Windows x86-64

parallel_ssh-1.5.2-cp36-cp36m-win32.whl (96.9 kB view details)

Uploaded CPython 3.6m Windows x86

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

Uploaded CPython 3.6m

parallel_ssh-1.5.2-cp35-cp35m-win_amd64.whl (105.8 kB view details)

Uploaded CPython 3.5m Windows x86-64

parallel_ssh-1.5.2-cp35-cp35m-win32.whl (96.6 kB view details)

Uploaded CPython 3.5m Windows x86

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

Uploaded CPython 3.5m

parallel_ssh-1.5.2-cp34-cp34m-win_amd64.whl (103.9 kB view details)

Uploaded CPython 3.4m Windows x86-64

parallel_ssh-1.5.2-cp34-cp34m-win32.whl (97.4 kB view details)

Uploaded CPython 3.4m Windows x86

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

Uploaded CPython 3.4m

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

Uploaded CPython 3.3m

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

Uploaded CPython 2.7mu

parallel_ssh-1.5.2-cp27-cp27m-win_amd64.whl (105.1 kB view details)

Uploaded CPython 2.7m Windows x86-64

parallel_ssh-1.5.2-cp27-cp27m-win32.whl (97.1 kB view details)

Uploaded CPython 2.7m Windows x86

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

Uploaded CPython 2.7m

parallel_ssh-1.5.2-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.2-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.2-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.2.tar.gz.

File metadata

File hashes

Hashes for parallel-ssh-1.5.2.tar.gz
Algorithm Hash digest
SHA256 d99e65facc5ab9668dcc5702b84eb2cd09060069c2ab27b0a46e47be0eed86c8
MD5 fcb1419c8e5a6c24a8e49953624c4f24
BLAKE2b-256 4e877ab2ab7a5b5b08484e34763243abb58752b6bab1d6b41c78fed121bf69f3

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for parallel_ssh-1.5.2-cp36-cp36m-win_amd64.whl
Algorithm Hash digest
SHA256 16ec8bd91ae8fd3c9435a0c68ce210ab1e45c55f5db1a6ffc56826d061f63c0e
MD5 f8f1893b85db66b4d94688c228b027a6
BLAKE2b-256 a5e7600aea84579c9c290871e211b08dd0090e41e2f969393c51f88a327796ce

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for parallel_ssh-1.5.2-cp36-cp36m-win32.whl
Algorithm Hash digest
SHA256 8d81d3910a53c4fed22666917800bbdd5a2698a58c3036b877fd383d592983ca
MD5 14ca1ff6dc619a44adfaebf31c4cf1ea
BLAKE2b-256 09cb4ffc7913617d1c38567c93dd52fdc3a8a4f778a6b5e816882feefe7158f0

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for parallel_ssh-1.5.2-cp36-cp36m-manylinux1_x86_64.whl
Algorithm Hash digest
SHA256 707f70080a153be066a195683e2731f8480875f33f9ec4dbce0f82d233d9eccb
MD5 2bdea9f2feb364b1af9a56b8b7596399
BLAKE2b-256 09babd9d0ab5d545803e38f3fc7dda398a160fd00a398ab4ec314dea2eec35b5

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for parallel_ssh-1.5.2-cp35-cp35m-win_amd64.whl
Algorithm Hash digest
SHA256 f0300fb3691863a7efad6f7c9186dcac39ba1e0f802f1de4cd38845282179a62
MD5 d68930369457cadcf11a704d6d8d59a8
BLAKE2b-256 97a36507fc9794039c4ddc172b1a77fd95940607a8767a95d15ba6bb2ab66a9c

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for parallel_ssh-1.5.2-cp35-cp35m-win32.whl
Algorithm Hash digest
SHA256 a85ee8b867634099b15d240a83bc90c7bedeb7ec8b605640871cf9616d09db2e
MD5 25803f4f986fda7e8ab0a6b0a978fd74
BLAKE2b-256 864b30fb8307dd3c5bad253a19acc93d34a7392e65ef0249c470fb3cffc8dd16

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for parallel_ssh-1.5.2-cp35-cp35m-manylinux1_x86_64.whl
Algorithm Hash digest
SHA256 abb0d63db3f41b0612cf23a7aba9d35af146465cee3b4c245bc20980527f9628
MD5 aacca1bac874e7d45006f480fb8a25c5
BLAKE2b-256 0ac11465a291652eac8d5fa3ce3f4ac3e722580e7b96317a6be82b12fe3b118b

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for parallel_ssh-1.5.2-cp34-cp34m-win_amd64.whl
Algorithm Hash digest
SHA256 0ad49969ed1e17a5d8c77ee1365b9fc873c0b3df922cf4878191c418861cefa0
MD5 a7d25ada6f87e6ab12535d1f169610e7
BLAKE2b-256 28b2316d2316a7045ec756917996fee6dc7760963314751e1a90723c6c1fc7f8

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for parallel_ssh-1.5.2-cp34-cp34m-win32.whl
Algorithm Hash digest
SHA256 f7ae77cbd8521b8b8e7b78179e2f5f9fc0fb05b15f01dc3dea8bc2a5d9aae506
MD5 1db4a68b62d5421897c1722a3cf83733
BLAKE2b-256 f160dbd793cf47d84049c69554c5527259f1c08dc6e6918a72d5c25da386c79d

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for parallel_ssh-1.5.2-cp34-cp34m-manylinux1_x86_64.whl
Algorithm Hash digest
SHA256 52781dbd6e1e03e60048b13f44a91cb15f96d1c2ec5338798bd6abc9ba42814e
MD5 8429e91443c46cb69c7d12872c524a00
BLAKE2b-256 c60a09bc7fd5516dc04a5edce25db8c21f46ccec824b15fe163b3d2ff1d0aae5

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for parallel_ssh-1.5.2-cp33-cp33m-manylinux1_x86_64.whl
Algorithm Hash digest
SHA256 62022449d586c03536a9a338c96b36d67b2908dde091c13ddc7b178ba4d9fd89
MD5 ce63f9631bf33cb38ea33051bc58e59a
BLAKE2b-256 288fe81ad7c9c58eb01fa96956158493ce66375de2f86e1290e32d8eec3905e0

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for parallel_ssh-1.5.2-cp27-cp27mu-manylinux1_x86_64.whl
Algorithm Hash digest
SHA256 c3a8126b9fa6074984036356163f174914920385d1c21aa07b7e685bd34a5a07
MD5 2cd3c98015018d30188aec9d40bfc5bc
BLAKE2b-256 26c17b50b770ee9f76eae1f04c2fa765d1d93c46d9ef6ed02156785a98a53765

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for parallel_ssh-1.5.2-cp27-cp27m-win_amd64.whl
Algorithm Hash digest
SHA256 a98ae07458f757f3096151f4ff518986dd5c690df20940b56ffd5156d22dab48
MD5 e2d20e2dacd1b4bf4bf9a5bb60e6835a
BLAKE2b-256 243fd45bd0b6cabf34fac88134cd0542996222c9a684b3ccdf703ce20a155e8e

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for parallel_ssh-1.5.2-cp27-cp27m-win32.whl
Algorithm Hash digest
SHA256 55a2f907762ca5c3fb0714babdda455ea5211cd07b0855b2aa2d22d78ede72e6
MD5 aa137dac57ff1dcb95ac052a049b0402
BLAKE2b-256 892629b34dad1d84c0c14c57dea84a5834bed2cd539e3af778b7c493bc0e0ede

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for parallel_ssh-1.5.2-cp27-cp27m-manylinux1_x86_64.whl
Algorithm Hash digest
SHA256 89fd97fe941ec8e7c32d0582cbe93170d40f6ce12d6b198996398550f7d054dd
MD5 cf056b1211f354cf4ee77f380ae43e2c
BLAKE2b-256 e97461ee7bc658dc366848a7ddfa9b89fc2b94e3358c0f771bc5cb491e1603db

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for parallel_ssh-1.5.2-cp27-cp27m-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 31bd73ca5d82f4198c474f3fed454c4b638c2dbf6f639f2246eeff3e230fe49f
MD5 9df4d1c8c45593fe8501caabd44d1d12
BLAKE2b-256 1d70a13241bef3cb2bdac34fe3e7ebbe6169af277d54b6b734717ab245bc8d2b

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for parallel_ssh-1.5.2-cp27-cp27m-macosx_10_11_x86_64.whl
Algorithm Hash digest
SHA256 43e6ed10d6e8174db4491b42a6bcfef741024a1662855838ed42cf2afb6448e0
MD5 a3d776ac840cef9ce11d706379fe9bfb
BLAKE2b-256 934849bb1ebdec80172431e0d705f411cf411edf8b46064baa2d4844c9753eb3

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for parallel_ssh-1.5.2-cp27-cp27m-macosx_10_10_intel.whl
Algorithm Hash digest
SHA256 729e2719852350135756993e7844cecc56ffba37f98e10385eb9527bbfd2f275
MD5 39e2ab4456254725ee60f697bfc72b5c
BLAKE2b-256 7a615b64314d1cbcc1acbfd1bc12cf50531b82463379113e5d56f7dca438593d

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