Skip to content

Commit 30631c0

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 c5a8d85 commit 30631c0

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
@@ -199,7 +199,8 @@ def _connect(self, client, host, port, sock=None, retries=1):
199199
str(error_type), self.host, self.port,
200200
retries, self.num_retries,)
201201
except paramiko.AuthenticationException, ex:
202-
raise AuthenticationException(ex.message)
202+
msg = ex.message + "Host is '%s:%s'"
203+
raise AuthenticationException(msg, host, port)
203204
# SSHException is more general so should be below other types
204205
# of SSH failure
205206
except paramiko.SSHException, ex:
@@ -492,9 +493,19 @@ def run_command(self, *args, **kwargs):
492493
'cmd' : <greenlet>}}
493494
494495
"""
496+
stop_on_errors = kwargs['stop_on_errors'] \
497+
if 'stop_on_errors' in kwargs else True
498+
del kwargs['stop_on_errors']
495499
cmds = [self.pool.spawn(self._exec_command, host, *args, **kwargs)
496500
for host in self.hosts]
497-
return self.get_output(commands=cmds)
501+
output = {}
502+
for cmd in cmds:
503+
try:
504+
output = self.get_output(cmd)
505+
except Exception, ex:
506+
if stop_on_errors:
507+
raise ex
508+
return output
498509

499510
def exec_command(self, *args, **kwargs):
500511
"""Run command on all hosts in parallel, honoring `self.pool_size`
@@ -525,8 +536,8 @@ def _exec_command(self, host, *args, **kwargs):
525536
proxy_port=self.proxy_port)
526537
return self.host_clients[host].exec_command(*args, **kwargs)
527538

528-
def get_output(self, commands=None):
529-
"""Get output from running commands.
539+
def get_output(self, cmd):
540+
"""Get output from command.
530541
531542
:param commands: (Optional) Override commands to get output from.\
532543
Uses running commands in pool if not given.
@@ -557,17 +568,23 @@ def get_output(self, commands=None):
557568
>>> self.get_exit_code(output[host])
558569
0
559570
"""
560-
if not commands:
561-
commands = list(self.pool.greenlets)
562571
output = {}
563-
for cmd in commands:
572+
try:
564573
(channel, host, stdout, stderr) = cmd.get()
565-
output.setdefault(host, {})
566-
output[host].update({'exit_code': self._get_exit_code(channel),
567-
'channel' : channel,
568-
'stdout' : stdout,
569-
'stderr' : stderr,
570-
'cmd' : cmd, })
574+
except Exception, ex:
575+
output[host].update({'exit_code' : None,
576+
'channel' : None,
577+
'stdout' : None,
578+
'stderr' : None,
579+
'cmd' : cmd,
580+
'exception' : ex,})
581+
raise ex
582+
output.setdefault(host, {})
583+
output[host].update({'exit_code': self._get_exit_code(channel),
584+
'channel' : channel,
585+
'stdout' : stdout,
586+
'stderr' : stderr,
587+
'cmd' : cmd, })
571588
return output
572589

573590
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)