Skip to content

Commit d6fb4a2

Browse files
author
Dan
committed
WIP for #32 - Added test for getting partial host list output in the case where the host lists contains one or more failing hosts. Refactored run_command to allow raising an exception on errors or not
1 parent cb0a90b commit d6fb4a2

File tree

3 files changed

+60
-14
lines changed

3 files changed

+60
-14
lines changed

pssh.py

Lines changed: 30 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,8 @@ def _connect(self, client, host, port, sock=None, retries=1):
204204
str(error_type), self.host, self.port,
205205
retries, self.num_retries,)
206206
except paramiko.AuthenticationException, ex:
207-
raise AuthenticationException(ex.message)
207+
msg = ex.message + "Host is '%s:%s'"
208+
raise AuthenticationException(msg, host, port)
208209
# SSHException is more general so should be below other types
209210
# of SSH failure
210211
except paramiko.SSHException, ex:
@@ -497,9 +498,19 @@ def run_command(self, *args, **kwargs):
497498
'cmd' : <greenlet>}}
498499
499500
"""
501+
stop_on_errors = kwargs['stop_on_errors'] \
502+
if 'stop_on_errors' in kwargs else True
503+
del kwargs['stop_on_errors']
500504
cmds = [self.pool.spawn(self._exec_command, host, *args, **kwargs)
501505
for host in self.hosts]
502-
return self.get_output(commands=cmds)
506+
output = {}
507+
for cmd in cmds:
508+
try:
509+
output = self.get_output(cmd)
510+
except Exception, ex:
511+
if stop_on_errors:
512+
raise ex
513+
return output
503514

504515
def exec_command(self, *args, **kwargs):
505516
"""Run command on all hosts in parallel, honoring `self.pool_size`
@@ -530,8 +541,8 @@ def _exec_command(self, host, *args, **kwargs):
530541
proxy_port=self.proxy_port)
531542
return self.host_clients[host].exec_command(*args, **kwargs)
532543

533-
def get_output(self, commands=None):
534-
"""Get output from running commands.
544+
def get_output(self, cmd):
545+
"""Get output from command.
535546
536547
:param commands: (Optional) Override commands to get output from.\
537548
Uses running commands in pool if not given.
@@ -562,17 +573,23 @@ def get_output(self, commands=None):
562573
>>> self.get_exit_code(output[host])
563574
0
564575
"""
565-
if not commands:
566-
commands = list(self.pool.greenlets)
567576
output = {}
568-
for cmd in commands:
577+
try:
569578
(channel, host, stdout, stderr) = cmd.get()
570-
output.setdefault(host, {})
571-
output[host].update({'exit_code': self._get_exit_code(channel),
572-
'channel' : channel,
573-
'stdout' : stdout,
574-
'stderr' : stderr,
575-
'cmd' : cmd, })
579+
except Exception, ex:
580+
output[host].update({'exit_code' : None,
581+
'channel' : None,
582+
'stdout' : None,
583+
'stderr' : None,
584+
'cmd' : cmd,
585+
'exception' : ex,})
586+
raise ex
587+
output.setdefault(host, {})
588+
output[host].update({'exit_code': self._get_exit_code(channel),
589+
'channel' : channel,
590+
'stdout' : stdout,
591+
'stderr' : stderr,
592+
'cmd' : cmd, })
576593
return output
577594

578595
def get_exit_code(self, host_output):

pssh_local.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
from pssh import SSHClient, ParallelSSHClient
2424
import logging
2525

26-
logger = logging.getLogger(__name__)
26+
logger = logging.getLogger('pssh')
2727

2828
def _setup_logger(_logger):
2929
"""Setup default logger"""

tests/test_pssh_client.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,35 @@ def test_pssh_client_auth_failure(self):
190190
del client
191191
server.join()
192192

193+
def test_pssh_client_hosts_list_part_failure(self):
194+
"""Test getting output for remainder of host list in the case where one
195+
host in the host list has a failure"""
196+
server2_socket = make_socket('127.0.0.2', port=self.listen_port)
197+
server2_port = server2_socket.getsockname()[1]
198+
server1 = start_server({ self.fake_cmd : self.fake_resp },
199+
self.listen_socket, fail_auth=True)
200+
server2 = start_server({ self.fake_cmd : self.fake_resp },
201+
server2_socket)
202+
hosts = ['127.0.0.1', '127.0.0.2']
203+
client = ParallelSSHClient(hosts,
204+
port=self.listen_port,
205+
pkey=self.user_key,
206+
)
207+
output = {}
208+
try:
209+
client.run_command(self.fake_cmd,
210+
output=output,
211+
stop_on_errors=False)
212+
except AuthenticationException:
213+
pass
214+
self.assertTrue(hosts[0] in output,
215+
msg="Failed host does not exist in output - output is %s" % (output,))
216+
self.assertTrue(hosts[1] in output,
217+
msg="Successful host does not exist in output - output is %s" % (output,))
218+
del client
219+
server1.kill()
220+
server2.kill()
221+
193222
def test_pssh_client_ssh_exception(self):
194223
server = start_server({ self.fake_cmd : self.fake_resp },
195224
self.listen_socket,

0 commit comments

Comments
 (0)