Skip to content

Commit 9720304

Browse files
author
Dan
committed
Fixed host output de-duplication for more than 2 identical hosts. Workaround for gevent/threading import race condition. Resolves #46
1 parent 6fc8f60 commit 9720304

File tree

3 files changed

+21
-13
lines changed

3 files changed

+21
-13
lines changed

pssh/pssh_client.py

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,15 +18,18 @@
1818

1919
"""Package containing ParallelSSHClient class."""
2020

21-
21+
import sys
22+
if 'threading' in sys.modules:
23+
del sys.modules['threading']
2224
from gevent import monkey
2325
monkey.patch_all()
2426
import logging
2527
import gevent.pool
2628
import gevent.hub
2729
gevent.hub.Hub.NOT_ERROR = (Exception,)
2830
import warnings
29-
import hashlib
31+
import string
32+
import random
3033
from .constants import DEFAULT_RETRIES
3134
from .ssh_client import SSHClient
3235

@@ -137,7 +140,7 @@ def __init__(self, hosts,
137140
``exit_code`` in ``output`` will be ``None`` if command has not finished.
138141
139142
``get_exit_codes`` is not a blocking function and will not wait for commands
140-
to finish. Use ``client.pool.join()`` to block until all commands have
143+
to finish. Use ``client.join(output)`` to block until all commands have
141144
finished.
142145
143146
``output`` parameter is modified in-place.
@@ -169,7 +172,7 @@ def __init__(self, hosts,
169172
170173
>>> client = ParallelSSHClient(['localhost'])
171174
>>> output = client.run_command('ls -ltrh /tmp/aasdfasdf')
172-
>>> client.pool.join()
175+
>>> client.join(output)
173176
174177
:netstat: ``tcp 0 0 127.0.0.1:53054 127.0.0.1:22 ESTABLISHED``
175178
@@ -239,9 +242,9 @@ def run_command(self, *args, **kwargs):
239242
0
240243
0
241244
242-
*Wait for completion, no stdout*
245+
*Wait for completion, no stdout printing*
243246
244-
>>> client.pool.join()
247+
>>> client.join(output)
245248
246249
*Run with sudo*
247250
@@ -269,7 +272,7 @@ def run_command(self, *args, **kwargs):
269272
**Do not stop on errors, return per-host exceptions in output**
270273
271274
>>> output = client.run_command('ls -ltrh', stop_on_errors=False)
272-
>>> client.pool.join()
275+
>>> client.join(output)
273276
>>> print output
274277
275278
::
@@ -376,7 +379,10 @@ def _update_host_output(self, output, host, exit_code, channel, stdout, stderr,
376379
exception=None):
377380
"""Update host output with given data"""
378381
if host in output:
379-
new_host = "_".join([host, hashlib.sha1().hexdigest()[:10]])
382+
new_host = "_".join([host,
383+
''.join(random.choice(
384+
string.ascii_lowercase + string.digits)
385+
for _ in xrange(8))])
380386
logger.warning("Already have output for host %s - changing host key for %s to %s",
381387
host, host, new_host)
382388
host = new_host

pssh/ssh_client.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@
1818

1919
"""Package containing SSHClient class."""
2020

21-
21+
import sys
22+
if 'threading' in sys.modules:
23+
del sys.modules['threading']
2224
import gevent
2325
from gevent import monkey
2426
monkey.patch_all()

tests/test_pssh_client.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -426,17 +426,17 @@ def test_bash_variable_substitution(self):
426426
def test_identical_host_output(self):
427427
"""Test that we get output when running with duplicated hosts"""
428428
# Make socket with no server listening on it just for testing output
429-
_socket = make_socket(self.host)
430-
port = _socket.getsockname()[1]
431-
hosts = [self.host, self.host]
429+
_socket1, _socket2 = make_socket(self.host), make_socket(self.host)
430+
port = _socket1.getsockname()[1]
431+
hosts = [self.host, self.host, self.host]
432432
client = ParallelSSHClient(hosts, port=port,
433433
pkey=self.user_key)
434434
output = client.run_command(self.fake_cmd, stop_on_errors=False)
435435
client.pool.join()
436436
self.assertEqual(len(hosts), len(output.keys()),
437437
msg="Host list contains %s identical hosts, only got output for %s" % (
438438
len(hosts), len(output.keys())))
439-
del _socket
439+
del _socket1, _socket2
440440

441441
def test_connection_error_exception(self):
442442
"""Test that we get connection error exception in output with correct arguments"""

0 commit comments

Comments
 (0)