Merge "Fix incorrect exit status checking in sshutils"

This commit is contained in:
Jenkins
2013-12-27 12:34:37 +00:00
committed by Gerrit Code Review
2 changed files with 38 additions and 39 deletions

View File

@@ -93,35 +93,34 @@ class SSH(object):
self._get_ssh_connection() self._get_ssh_connection()
cmd = ' '.join(cmd) cmd = ' '.join(cmd)
transport = self.client.get_transport() transport = self.client.get_transport()
channel = transport.open_session() session = transport.open_session()
channel.fileno() session.exec_command(cmd)
channel.exec_command(cmd)
channel.shutdown_write()
poll = select.poll()
poll.register(channel, select.POLLIN)
start_time = time.time() start_time = time.time()
while True: while True:
ready = poll.poll(16) errors = select.select([session], [], [], 4)[2]
if not any(ready):
if not self._is_timed_out(start_time): if session.recv_ready():
continue data = session.recv(4096)
raise exceptions.TimeoutException('SSH Timeout') LOG.debug(data)
if not ready[0]:
continue
out_chunk = err_chunk = None
if channel.recv_ready():
out_chunk = channel.recv(4096)
if get_stdout: if get_stdout:
yield (1, out_chunk) yield (1, data)
LOG.debug("stdout: %s" % out_chunk) continue
if channel.recv_stderr_ready():
err_chunk = channel.recv_stderr(4096) if session.recv_stderr_ready():
data = session.recv_stderr(4096)
LOG.debug(data)
if get_stderr: if get_stderr:
yield (2, err_chunk) yield (2, data)
LOG.debug("stderr: %s" % err_chunk) continue
if channel.closed and not err_chunk and not out_chunk:
if errors or session.exit_status_ready():
break break
exit_status = channel.recv_exit_status()
if self._is_timed_out(start_time):
raise exceptions.TimeoutException('SSH Timeout')
exit_status = session.recv_exit_status()
if 0 != exit_status: if 0 != exit_status:
raise exceptions.SSHError( raise exceptions.SSHError(
'SSHExecCommandFailed with exit_status %s' 'SSHExecCommandFailed with exit_status %s'

View File

@@ -27,49 +27,49 @@ class SSHTestCase(test.TestCase):
super(SSHTestCase, self).setUp() super(SSHTestCase, self).setUp()
self.ssh = sshutils.SSH('example.net', 'root') self.ssh = sshutils.SSH('example.net', 'root')
self.channel = mock.Mock() self.channel = mock.Mock()
self.channel.fileno.return_value = 15 self.channel.recv.return_value = 'ok'
self.channel.recv.return_value = '' self.channel.recv_stderr.return_value = 'error'
self.channel.recv_stderr.return_value = ''
self.channel.recv_exit_status.return_value = 0 self.channel.recv_exit_status.return_value = 0
self.transport = mock.Mock() self.transport = mock.Mock()
self.transport.open_session = mock.MagicMock(return_value=self.channel) self.transport.open_session = mock.MagicMock(return_value=self.channel)
self.poll = mock.Mock()
self.poll.poll.return_value = [(self.channel, 1)]
self.policy = mock.Mock() self.policy = mock.Mock()
self.client = mock.Mock() self.client = mock.Mock()
self.client.get_transport = mock.MagicMock(return_value=self.transport) self.client.get_transport = mock.MagicMock(return_value=self.transport)
self.channel.exit_status_ready.return_value = True
self.channel.recv_ready.side_effect = [True, False, False]
self.channel.recv_stderr_ready.side_effect = [True, False, False]
@mock.patch('rally.sshutils.paramiko') @mock.patch('rally.sshutils.paramiko')
@mock.patch('rally.sshutils.select') @mock.patch('rally.sshutils.select')
def test_generator(self, st, pk): def test_generator(self, st, pk):
pk.SSHClient.return_value = self.client pk.SSHClient.return_value = self.client
st.poll.return_value = self.poll st.select.return_value = ([], [], [])
self.channel.recv.side_effect = ['ok', '']
self.channel.recv_stderr.side_effect = ['error', '']
chunks = list(self.ssh.execute_generator('ps ax')) chunks = list(self.ssh.execute_generator('ps ax'))
self.assertEqual([(1, 'ok'), (2, 'error'), (1, ''), (2, '')], chunks) self.assertEqual([(1, 'ok'), (2, 'error')], chunks)
@mock.patch('rally.sshutils.paramiko') @mock.patch('rally.sshutils.paramiko')
@mock.patch('rally.sshutils.select') @mock.patch('rally.sshutils.select')
def test_execute(self, st, pk): def test_execute(self, st, pk):
pk.SSHClient.return_value = self.client pk.SSHClient.return_value = self.client
st.poll.return_value = self.poll st.select.return_value = ([], [], [])
stdout, stderr = self.ssh.execute('uname') stdout, stderr = self.ssh.execute('uname')
self.assertEqual('', stdout) self.assertEqual('', stdout)
self.assertEqual('', stderr) self.assertEqual('', stderr)
expected = [mock.call.fileno(), expected = [mock.call.exec_command('uname'),
mock.call.exec_command('uname'),
mock.call.shutdown_write(),
mock.call.recv_ready(), mock.call.recv_ready(),
mock.call.recv(4096), mock.call.recv(4096),
mock.call.recv_ready(),
mock.call.recv_stderr_ready(), mock.call.recv_stderr_ready(),
mock.call.recv_stderr(4096), mock.call.recv_stderr(4096),
mock.call.recv_ready(),
mock.call.recv_stderr_ready(),
mock.call.exit_status_ready(),
mock.call.recv_exit_status()] mock.call.recv_exit_status()]
self.assertEqual(self.channel.mock_calls, expected) self.assertEqual(expected, self.channel.mock_calls)
@mock.patch('rally.sshutils.paramiko') @mock.patch('rally.sshutils.paramiko')
def test_upload_file(self, pk): def test_upload_file(self, pk):