# See the License for the specific language governing permissions and
# limitations under the License.
+"""Library for SSH connection management."""
+
import StringIO
from time import time, sleep
from paramiko import RSAKey
from paramiko.ssh_exception import SSHException
from scp import SCPClient
-from interruptingcow import timeout
from robot.api import logger
from robot.utils.asserts import assert_equal
class SSH(object):
+ """Contains methods for managing and using SSH connections."""
__MAX_RECV_BUF = 10*1024*1024
__existing_connections = {}
@staticmethod
def _node_hash(node):
+ """Get IP address and port hash from node dictionary.
+
+ :param node: Node in topology.
+ :type node: dict
+ :return: IP address and port for the specified node.
+ :rtype: int
+ """
+
return hash(frozenset([node['host'], node['port']]))
def connect(self, node):
pkey = None
if 'priv_key' in node:
pkey = RSAKey.from_private_key(
- StringIO.StringIO(node['priv_key']))
+ StringIO.StringIO(node['priv_key']))
self._ssh = paramiko.SSHClient()
self._ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.close()
def _reconnect(self):
+ """Close the SSH connection and open it again."""
+
node = self._node
self.disconnect(node)
self.connect(node)
"""Execute SSH command on a new channel on the connected Node.
:param cmd: Command to run on the Node.
- :param timeout: Maximal time in seconds to wait while the command is
- done. If is None then wait forever.
+ :param timeout: Maximal time in seconds to wait until the command is
+ done. If set to None then wait forever.
:type cmd: str
:type timeout: int
:return return_code, stdout, stderr
command = 'sudo -S {c} <<< "{i}"'.format(c=cmd, i=cmd_input)
return self.exec_command(command, timeout)
- def interactive_terminal_open(self, time_out=10):
+ def interactive_terminal_open(self, time_out=30):
"""Open interactive terminal on a new channel on the connected Node.
:param time_out: Timeout in seconds.
chan.get_pty()
chan.invoke_shell()
chan.settimeout(int(time_out))
+ chan.set_combine_stderr(True)
buf = ''
- try:
- with timeout(time_out, exception=RuntimeError):
- while not buf.endswith(':~$ '):
- if chan.recv_ready():
- buf = chan.recv(4096)
- except RuntimeError:
- raise Exception('Open interactive terminal timeout.')
+ while not buf.endswith(':~$ '):
+ try:
+ chunk = chan.recv(self.__MAX_RECV_BUF)
+ if not chunk:
+ break
+ buf += chunk
+ if chan.exit_status_ready():
+ logger.error('Channel exit status ready')
+ break
+ except socket.timeout:
+ raise Exception('Socket timeout: {0}'.format(buf))
return chan
- @staticmethod
- def interactive_terminal_exec_command(chan, cmd, prompt,
- time_out=10):
+ def interactive_terminal_exec_command(self, chan, cmd, prompt):
"""Execute command on interactive terminal.
interactive_terminal_open() method has to be called first!
:param cmd: Command to be executed.
:param prompt: Command prompt, sequence of characters used to
indicate readiness to accept commands.
- :param time_out: Timeout in seconds.
:return: Command output.
.. warning:: Interruptingcow is used here, and it uses
"""
chan.sendall('{c}\n'.format(c=cmd))
buf = ''
- try:
- with timeout(time_out, exception=RuntimeError):
- while not buf.endswith(prompt):
- if chan.recv_ready():
- buf += chan.recv(4096)
- except RuntimeError:
- raise Exception("Exec '{c}' timeout.".format(c=cmd))
+ while not buf.endswith(prompt):
+ try:
+ chunk = chan.recv(self.__MAX_RECV_BUF)
+ if not chunk:
+ break
+ buf += chunk
+ if chan.exit_status_ready():
+ logger.error('Channel exit status ready')
+ break
+ except socket.timeout:
+ raise Exception('Socket timeout: {0}'.format(buf))
tmp = buf.replace(cmd.replace('\n', ''), '')
return tmp.replace(prompt, '')
ssh = SSH()
try:
ssh.connect(node)
- except Exception, e:
- logger.error("Failed to connect to node" + str(e))
+ except SSHException as err:
+ logger.error("Failed to connect to node" + str(err))
return None, None, None
try:
else:
(ret_code, stdout, stderr) = ssh.exec_command_sudo(cmd,
timeout=timeout)
- except Exception, e:
- logger.error(e)
+ except SSHException as err:
+ logger.error(err)
return None, None, None
return ret_code, stdout, stderr
Returns (stdout, stderr).
"""
- (rc, stdout, stderr) = exec_cmd(node, cmd, timeout=timeout, sudo=sudo)
- assert_equal(rc, 0, 'Command execution failed: "{}"\n{}'.
+ (ret_code, stdout, stderr) = exec_cmd(node, cmd, timeout=timeout, sudo=sudo)
+ assert_equal(ret_code, 0, 'Command execution failed: "{}"\n{}'.
format(cmd, stderr))
return stdout, stderr