Skip to content

Commit 1e1df90

Browse files
author
Dan
committed
Updated documentation
1 parent 245cb40 commit 1e1df90

File tree

6 files changed

+265
-58
lines changed

6 files changed

+265
-58
lines changed

doc/advanced.rst

Lines changed: 209 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,13 @@ Agents and Private Keys
1212
SSH Agent forwarding
1313
-----------------------
1414

15-
SSH agent forwarding, what ``ssh -A`` does on the command line, is supported and enabled by default. Creating an object as ``ParallelSSHClient(hosts, forward_ssh_agent=False)`` will disable this behaviour.
15+
SSH agent forwarding, what ``ssh -A`` does on the command line, is supported and enabled by default. Creating a client object as:
16+
17+
.. code-block:: python
18+
19+
ParallelSSHClient(hosts, forward_ssh_agent=False)
20+
21+
will disable this behaviour.
1622

1723
Programmatic Private Keys
1824
--------------------------
@@ -32,6 +38,10 @@ Where ``my_key`` is a private key file in current working directory.
3238

3339
The helper function :py:func:`load_private_key <pssh.utils.load_private_key>` will attempt to load all available key types and raises :mod:`SSHException <pssh.exceptions.SSHException>` if it cannot load the key file.
3440

41+
.. seealso::
42+
43+
:py:func:`load_private_key <pssh.utils.load_private_key>`
44+
3545
Disabling use of system SSH Agent
3646
----------------------------------
3747

@@ -73,6 +83,10 @@ It is also possible to programmatically provide an SSH agent for the client to u
7383

7484
Supplying an agent programmatically implies that a system SSH agent will *not* be used even if available.
7585

86+
.. seealso::
87+
88+
:py:class:`pssh.agent.SSHAgent`
89+
7690

7791
Tunneling
7892
**********
@@ -106,7 +120,7 @@ In the above example, connection to the target host is made via ``my_proxy_user@
106120

107121
.. note::
108122

109-
Proxy host connections are asynchronous and use the SSH protocol's native TCP tunneling - aka local port forward. No external commands are used for the proxy connection, unlike the `ProxyCommand` directive in OpenSSH and other utilities.
123+
Proxy host connections are asynchronous and use the SSH protocol's native TCP tunneling - aka local port forward. No external commands or processes are used for the proxy connection, unlike the `ProxyCommand` directive in OpenSSH and other utilities.
110124

111125
While the connections initiated by ``ParallelSSH`` are asynchronous, the connections from proxy host -> target hosts may not be, depending on SSH server implementation. If only one proxy host is used to connect to a large number of target hosts and proxy SSH server connections are *not* asynchronous, this may adversely impact performance on the proxy host.
112126

@@ -180,6 +194,193 @@ In the following example, first host in host list will use cmd ``host-index-0``,
180194
output = client.run_command('%(cmd)s', host_args=host_args)
181195
182196
197+
Run command features and options
198+
*********************************
199+
200+
See :py:func:`run_command API documentation <pssh.pssh_client.ParallelSSHClient.run_command>` for a complete list of features and options.
201+
202+
.. note::
203+
204+
With a PTY, stdout and stderr output is combined into stdout.
205+
206+
Without a PTY, separate output is given for stdout and stderr, although some programs and server configurations require a PTY.
207+
208+
Run with sudo
209+
---------------
210+
211+
``ParallelSSH`` can be instructed to run its commands under ``sudo``:
212+
213+
.. code-block:: python
214+
215+
client = <..>
216+
217+
output = client.run_command(<..>, sudo=True)
218+
client.join(output)
219+
220+
While not best practice and password-less `sudo` is best configured for a limited set of commands, a sudo password may be provided via the stdin channel:
221+
222+
.. code-block:: python
223+
224+
client = <..>
225+
226+
output = client.run_command(<..>, sudo=True)
227+
for host in output:
228+
stdin = output[host].stdin
229+
stdin.write('my_password\n')
230+
stdin.flush()
231+
client.join(output)
232+
233+
Output encoding
234+
-----------------
235+
236+
By default, output is encoded as ``UTF-8``. This can be configured with the ``encoding`` keyword argument.
237+
238+
.. code-block:: python
239+
240+
client = <..>
241+
242+
client.run_command(<..>, encoding='utf-16')
243+
stdout = list(output[client.hosts[0]].stdout)
244+
245+
Contents of ``stdout`` will be `UTF-16` encoded.
246+
247+
.. note::
248+
249+
Encoding must be valid `Python codec <https://docs.python.org/2.7/library/codecs.html>`_
250+
251+
Disabling use of pseudo terminal emulation
252+
--------------------------------------------
253+
254+
By default, ``ParallelSSH`` uses the user's configured shell to run commands with. As a shell is used by default, a pseudo terminal (`PTY`) is also requested by default.
255+
256+
For cases where use of a `PTY` is not wanted, such as having separate stdout and stderr outputs, or the remote command is a daemon that needs to fork and detach itself or when use of a shell is explicitly disabled, use of PTY can also be disabled.
257+
258+
The following example prints to stderr with PTY disabled.
259+
260+
.. code-block:: python
261+
262+
from __future__ import print_function
263+
264+
client = <..>
265+
266+
client.run_command("echo 'asdf' >&2", use_pty=False)
267+
for line in output[client.hosts[0]].stderr:
268+
print(line)
269+
270+
:Output:
271+
.. code-block:: shell
272+
273+
asdf
274+
275+
Combined stdout/stderr
276+
-----------------------
277+
278+
With a PTY, stdout and stderr output is combined.
279+
280+
The same example as above with a PTY:
281+
282+
.. code-block:: python
283+
284+
from __future__ import print_function
285+
286+
client = <..>
287+
288+
client.run_command("echo 'asdf' >&2")
289+
for line in output[client.hosts[0]].stdout:
290+
print(line)
291+
292+
Note output is now from the ``stdout`` channel.
293+
294+
:Output:
295+
.. code-block:: shell
296+
297+
asdf
298+
299+
Stderr is empty:
300+
301+
.. code-block:: python
302+
303+
for line in output[client.hosts[0]].stderr:
304+
print(line)
305+
306+
No output from ``stderr``.
307+
308+
SFTP
309+
*****
310+
311+
SFTP - `SCP version 2` - is supported by ``Parallel-SSH`` and two functions are provided by the client for copying files with SFTP.
312+
313+
SFTP does not have a shell interface and no output is provided for any SFTP commands.
314+
315+
As such, SFTP functions in ``ParallelSSHClient`` return greenlets that will need to be joined to raise any exceptions from them. :py:func:`gevent.joinall` may be used for that.
316+
317+
318+
Copying files to remote hosts in parallel
319+
----------------------------------------------
320+
321+
To copy the local file with relative path ``../test`` to the remote relative path ``test_dir/test`` - remote directory will be created if it does not exist, permissions allowing. ``raise_error=True`` instructs ``joinall`` to raise any exceptions thrown by the greenlets.
322+
323+
.. code-block:: python
324+
325+
from pssh.pssh_client import ParallelSSHClient
326+
from gevent import joinall
327+
328+
client = ParallelSSHClient(hosts)
329+
330+
greenlets = client.copy_file('../test', 'test_dir/test')
331+
joinall(greenlets, raise_error=True)
332+
333+
To recursively copy directory structures, enable the ``recurse`` flag:
334+
335+
.. code-block:: python
336+
337+
greenlets = client.copy_file('my_dir', 'my_dir', recurse=True)
338+
joinall(greenlets, raise_error=True)
339+
340+
.. seealso::
341+
342+
:py:func:`copy_file <pssh.pssh_client.ParallelSSHClient.copy_file>` API documentation and exceptions raised.
343+
344+
:py:func:`gevent.joinall` Gevent's ``joinall`` API documentation.
345+
346+
Copying files from remote hosts in parallel
347+
----------------------------------------------
348+
349+
Copying remote files in parallel requires that file names are de-duplicated otherwise they will overwrite each other. ``copy_remote_file`` names local files as ``<local_file><suffix_separator><host>``, suffixing each file with the host name it came from, separated by a configurable character or string.
350+
351+
.. code-block:: python
352+
353+
from pssh.pssh_client import ParallelSSHClient
354+
from gevent import joinall
355+
356+
client = ParallelSSHClient(hosts)
357+
358+
greenlets = client.copy_remote_file('remote.file', 'local.file')
359+
joinall(greenlets, raise_error=True)
360+
361+
The above will create files ``local.file_host1`` where ``host1`` is the host name the file was copied from.
362+
363+
.. seealso::
364+
365+
:py:func:`copy_remote_file <pssh.pssh_client.ParallelSSHClient.copy_remote_file>` API documentation and exceptions raised.
366+
367+
Single host copy
368+
-----------------
369+
370+
If wanting to copy a file from a single remote host and retain the original filename, can use the single host :py:class:`SSHClient <pssh.ssh_client.SSHClient>` and its :py:func:`copy_file <pssh.ssh_client.SSHClient.copy_remote_file>` directly.
371+
372+
.. code-block:: python
373+
374+
from pssh.ssh_client import SSHClient
375+
376+
client = SSHClient('localhost')
377+
client.copy_remote_file('remote_filename', 'local_filename')
378+
379+
.. seealso::
380+
381+
:py:func:`SSHClient.copy_remote_file <pssh.ssh_client.SSHClient.copy_remote_file>` API documentation and exceptions raised.
382+
383+
183384
Hosts filtering and overriding
184385
*******************************
185386
@@ -209,7 +410,7 @@ Any type of iterator may be used as hosts list, including generator and list com
209410
210411
.. note ::
211412
212-
Since generators by design only iterate over a sequence once then stop, ``client.hosts`` should be re-assigned after each call to ``run_command`` when using generators as target of `client.hosts`.
413+
Since generators by design only iterate over a sequence once then stop, ``client.hosts`` should be re-assigned after each call to ``run_command`` when using generators as target of ``client.hosts``.
213414
214415
Overriding hosts list
215416
----------------------
@@ -218,6 +419,8 @@ Hosts list can be modified in place. A call to ``run_command`` will create new c
218419
219420
.. code-block:: python
220421
221-
client.hosts = ['otherhost']
222-
print(client.run_command('exit 0'))
223-
{'otherhost': exit_code=None, <..>}
422+
client = <..>
423+
424+
client.hosts = ['otherhost']
425+
print(client.run_command('exit 0'))
426+
{'otherhost': exit_code=None, <..>}

doc/front_page.rst

Lines changed: 0 additions & 28 deletions
This file was deleted.

doc/index.rst

Lines changed: 30 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,43 @@
33
You can adapt this file completely to your liking, but it should at least
44
contain the root `toctree` directive.
55
6-
============================
7-
Parallel-SSH's documentation
8-
============================
6+
===========================
7+
Parallel-SSH Documentation
8+
===========================
9+
10+
.. image:: https://img.shields.io/badge/License-LGPL%20v2-blue.svg
11+
:target: https://pypi.python.org/pypi/parallel-ssh
12+
:alt: License
13+
.. image:: https://img.shields.io/pypi/v/parallel-ssh.svg
14+
:target: https://pypi.python.org/pypi/parallel-ssh
15+
:alt: Latest Version
16+
.. image:: https://travis-ci.org/ParallelSSH/parallel-ssh.svg?branch=master
17+
:target: https://travis-ci.org/ParallelSSH/parallel-ssh
18+
.. image:: https://coveralls.io/repos/ParallelSSH/parallel-ssh/badge.png?branch=master
19+
:target: https://coveralls.io/r/ParallelSSH/parallel-ssh?branch=master
20+
.. image:: https://readthedocs.org/projects/parallel-ssh/badge/?version=latest
21+
:target: http://parallel-ssh.readthedocs.org/en/latest/
22+
:alt: Latest documentation
23+
24+
25+
``Parallel-SSH`` is a parallel SSH client library. It uses asynchronous SSH connections and is, to date, the only publicly available asynchronous SSH client library for Python, as well as the only asynchronous *parallel* SSH client library available for Python.
926

1027
.. toctree::
11-
:maxdepth: 3
12-
13-
front_page
28+
:maxdepth: 2
29+
30+
introduction
31+
installation
32+
quickstart
33+
advanced
34+
api
1435

1536
In a nutshell
1637
**************
1738

1839
.. code-block:: python
19-
40+
41+
from __future__ import print_function
42+
2043
from pssh.pssh_client import ParallelSSHClient
2144
2245
client = ParallelSSHClient(['localhost'])

0 commit comments

Comments
 (0)