Skip to content

Commit 4528ba5

Browse files
authored
Libssh clients implementation (#143)
* Added ssh-python parallel and single client implementations * Updated readme, changelog and documentation * Re-do join with timeout to be on all commands rather than EAGAIN on any - #207 * Moved tests into their own packages
1 parent 4f23edc commit 4528ba5

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

60 files changed

+4126
-1542
lines changed

.coveragerc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ omit =
1212
setup.py
1313
/home/travis/virtualenv/python*/lib/python*/*
1414
*/_version.py
15+
*.pyx
1516
exclude_lines =
1617
pragma: no cover
1718
def __repr__

.environment.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,4 @@ dependencies:
44
- python
55
- setuptools
66
- pip
7-
- libssh2
87
- toolchain3

.travis.yml

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,11 @@ install:
2828
script:
2929
# For testing SSH agent related functionality
3030
- eval `ssh-agent -s`
31-
- pytest --reruns 5 --cov-append --cov=pssh tests/test_native_tunnel.py
32-
- pytest --reruns 5 --cov-append --cov=pssh tests/test_native_*_client.py
33-
- pytest --reruns 5 --cov-append --cov=pssh tests/test_paramiko*.py
31+
- pytest --cov-append --cov=pssh tests/test_imports.py tests/test_output.py tests/test_utils.py
32+
- pytest --reruns 5 --cov-append --cov=pssh tests/miko
33+
- pytest --reruns 5 --cov-append --cov=pssh tests/native/test_tunnel.py tests/native/test_agent.py
34+
- pytest --reruns 5 --cov-append --cov=pssh tests/native/test_*_client.py
35+
- pytest --reruns 5 --cov-append --cov=pssh tests/ssh
3436
- flake8 pssh
3537
- cd doc; make html; cd ..
3638
# Test building from source distribution

Changelog.rst

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,46 @@
11
Change Log
22
============
33

4+
1.12.0
5+
++++++
6+
7+
Changes
8+
--------
9+
10+
* Added `ssh-python` (`libssh <https://libssh.org>`_) based native client with `run_command` implementation.
11+
* ``ParallelSSHClient.join`` with timeout no longer consumes output by default to allow reading of output after timeout.
12+
13+
Fixes
14+
------
15+
16+
* ``ParallelSSHClient.join`` with timeout would raise ``Timeout`` before value given when client was busy with other commands.
17+
18+
.. note::
19+
20+
``ssh-python`` client at `pssh.clients.ssh.ParallelSSHClient` is available for testing. Please report any issues.
21+
22+
To use:
23+
24+
.. code-block:: python
25+
26+
from pssh.clients.ssh import ParallelSSHClient
27+
28+
This release adds (yet another) client, this one based on `ssh-python <https://github.com/ParallelSSH/ssh-python>`_ (`libssh <https://libssh.org>`_). Key features of this client are more supported authentication methods compared to `ssh2-python`.
29+
30+
Future releases will also enable certificate authentication for the ssh-python client.
31+
32+
Please migrate to one of the two native clients if have not already as paramiko is very quickly accumulating yet more bugs and the `2.0.0` release which removes it is imminent.
33+
34+
Users that require paramiko for any reason can pin their parallel-ssh versions to `parallel-ssh<2.0.0`.
35+
36+
437
1.11.2
538
++++++
639

740
Fixes
841
------
942

10-
* `ParallelSSHClient.disconnect` would cause new client sessions to fail if `client.join` was not called prior - #200
43+
* `ParallelSSHClient` going out of scope would cause new client sessions to fail if `client.join` was not called prior - #200
1144

1245

1346
1.11.0
@@ -18,6 +51,8 @@ Changes
1851

1952
* Moved polling to gevent.select.poll to increase performance and better handle high number of sockets - #189
2053
* ``HostOutput.exit_code`` is now a dynamic property returning either ``None`` when exit code not ready or the exit code as reported by channel. ``ParallelSSHClient.get_exit_codes`` is now a no-op and scheduled to be removed.
54+
* Native client exit codes are now more explicit and return ``None`` if no exit code is ready. Would previously return ``0`` by default.
55+
2156

2257
Packaging
2358
---------
@@ -29,6 +64,7 @@ Fixes
2964

3065
* Native client would fail on opening sockets with large file descriptor values - #189
3166

67+
3268
1.10.0
3369
+++++++
3470

@@ -39,6 +75,7 @@ Changes
3975
* Updated native clients for new version of ``ssh2-python``.
4076
* Manylinux 2010 wheels.
4177

78+
4279
Fixes
4380
------
4481

README.rst

Lines changed: 39 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -44,19 +44,17 @@ Usage Example
4444

4545
See documentation on `read the docs`_ for more complete examples.
4646

47-
Run ``uname`` on two remote hosts in parallel with ``sudo``.
47+
Run ``uname`` on two remote hosts in parallel.
4848

4949
.. code-block:: python
5050
51-
from __future__ import print_function
52-
5351
from pssh.clients import ParallelSSHClient
5452
55-
hosts = ['myhost1', 'myhost2']
53+
hosts = ['localhost', 'localhost']
5654
client = ParallelSSHClient(hosts)
5755
58-
output = client.run_command('uname')
59-
for host, host_output in output.items():
56+
output = client.run_command('uname', return_list=True)
57+
for host_output in output:
6058
for line in host_output.stdout:
6159
print(line)
6260
@@ -71,26 +69,21 @@ Run ``uname`` on two remote hosts in parallel with ``sudo``.
7169
Native client
7270
**************
7371

74-
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.
72+
Starting from version ``1.2.0``, the default client in ``parallel-ssh`` has changed to the native clint which offers much greater performance and reduced overhead than the current default client.
7573

76-
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.
74+
The new default 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.
7775

7876
See `this post <https://parallel-ssh.org/post/parallel-ssh-libssh2>`_ for a performance comparison of the available clients.
7977

80-
To make use of this new client, ``ParallelSSHClient`` can be imported from ``pssh.clients.native`` instead. Their respective APIs are almost identical.
81-
82-
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``.
83-
84-
The paramiko based client will become an optional install via pip `extras`, available under ``pssh.clients.miko``.
78+
The paramiko based client under ``pssh.clients.miko`` and the old ``pssh.pssh_client`` imports will be **removed** on the release of ``2.0.0``.
8579

86-
For example:
80+
Default client:
8781

8882
.. code-block:: python
8983
90-
from pprint import pprint
91-
from pssh.clients.native import ParallelSSHClient
84+
from pssh.clients import ParallelSSHClient
9285
93-
hosts = ['myhost1', 'myhost2']
86+
hosts = ['localhost', 'localhost']
9487
client = ParallelSSHClient(hosts)
9588
9689
output = client.run_command('uname')
@@ -106,8 +99,8 @@ See `documentation <http://parallel-ssh.readthedocs.io/en/latest/ssh2.html>`_ fo
10699
Native Code Client Features
107100
****************************
108101

109-
* Highest performance and least overhead of any Python SSH libraries
110-
* Thread safe - makes use of native threads for blocking calls like authentication
102+
* Highest performance and least overhead of any Python SSH library
103+
* Thread safe - makes use of native threads for CPU bound calls like authentication
111104
* Natively non-blocking utilising ``libssh2`` via ``ssh2-python`` - **no monkey patching of the Python standard library**
112105
* Significantly reduced overhead in CPU and memory usage
113106

@@ -116,7 +109,7 @@ Native Code Client Features
116109
Exit codes
117110
***********
118111

119-
Once *either* standard output is iterated on *to completion*, or ``client.join(output)`` is called, exit codes become available in host output.
112+
Once *either* standard output is iterated on *to completion*, or ``client.join(output, consume_output=True)`` is called, exit codes become available in host output.
120113

121114
Iteration ends *only when remote command has completed*, though it may be interrupted and resumed at any point.
122115

@@ -126,44 +119,52 @@ Once all output has been gathered exit codes become available even without calli
126119

127120
.. code-block:: python
128121
129-
for host in output:
130-
print(output[host].exit_code)
122+
output = client.run_command('uname', return_list=True)
123+
for host_out in output:
124+
for line in host_out.stdout:
125+
print(line)
126+
print(host_out.exit_code)
131127
132128
:Output:
133129
.. code-block:: python
134130
131+
Linux
135132
0
133+
Linux
136134
0
137135
136+
The client's ``join`` function can be used to wait for all commands in output object to finish.
138137

139-
The client's ``join`` function can be used to wait for all commands in output object to finish:
138+
After ``join`` returns, commands have finished and output can be read.
140139

141140
.. code-block:: python
142141
143142
client.join(output)
144143
145-
Similarly, output and exit codes are available after ``client.join`` is called:
144+
for host_out in output:
145+
for line in host_output.stdout:
146+
print(line)
147+
print(host_out.exit_code)
146148
147-
.. code-block:: python
149+
Similarly, exit codes are available after ``client.join(output, consume_output=True)``.
148150

149-
from pprint import pprint
151+
``consume_output`` flag must be set to get exit codes when not reading from ``stdout``. Future releases aim to remove the need for `consume_output` to be set.
150152

151-
output = client.run_command('exit 0')
153+
.. code-block:: python
152154
153-
# Wait for commands to complete
154-
client.join(output)
155-
pprint(output.values()[0].exit_code)
155+
output = client.run_command('uname')
156156
157-
# Output remains available in output generators
158-
for host, host_output in output.items():
159-
for line in host_output.stdout:
160-
pprint(line)
157+
# Wait for commands to complete and consume output so can get exit codes
158+
client.join(output, consume_output=True)
159+
160+
for host_output in output:
161+
print(host_out.exit_code)
161162
162163
:Output:
163164
.. code-block:: python
164165
165166
0
166-
<..stdout..>
167+
0
167168
168169
169170
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.
@@ -175,7 +176,8 @@ To log output without having to iterate over output generators, the ``consume_ou
175176
from pssh.utils import enable_host_logger
176177
177178
enable_host_logger()
178-
client.join(client.run_command('uname'), consume_output=True)
179+
output = client.run_command('uname')
180+
client.join(output, consume_output=True)
179181
180182
:Output:
181183
.. code-block:: shell
@@ -259,7 +261,7 @@ As always, it is best to use a tool that is suited to the task at hand. ``parall
259261
Paramiko
260262
________
261263

262-
The default SSH client library in ``parallel-ssh`` ``1.x.x`` series.
264+
The default SSH client library in ``parallel-ssh`` <=``1.6.x`` series.
263265

264266
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 <https://github.com/ParallelSSH/parallel-ssh/issues/83>`_.
265267

0 commit comments

Comments
 (0)