X-Git-Url: https://gerrit.fd.io/r/gitweb?p=csit.git;a=blobdiff_plain;f=resources%2Flibraries%2Fpython%2Fssh.py;h=4beec5aa83c4979fb6e0efe2addaa62c4e7aa3a9;hp=108c1e4e1ee4a7a5e18a019ff9059ece93aa8a0c;hb=5f809dd2414d50fd6f229fc2ba2ff42d66df5dde;hpb=852b10b6724f0ae221e45f1ccb3f8020077b1f33 diff --git a/resources/libraries/python/ssh.py b/resources/libraries/python/ssh.py index 108c1e4e1e..4beec5aa83 100644 --- a/resources/libraries/python/ssh.py +++ b/resources/libraries/python/ssh.py @@ -1,4 +1,4 @@ -# Copyright (c) 2018 Cisco and/or its affiliates. +# Copyright (c) 2019 Cisco and/or its affiliates. # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at: @@ -13,15 +13,15 @@ """Library for SSH connection management.""" +import paramiko +import socket import StringIO -from time import time, sleep -import socket -import paramiko from paramiko import RSAKey -from paramiko.ssh_exception import SSHException -from scp import SCPClient +from paramiko.ssh_exception import SSHException, NoValidConnectionsError from robot.api import logger +from scp import SCPClient +from time import time, sleep __all__ = ["exec_cmd", "exec_cmd_no_error"] @@ -104,6 +104,10 @@ class SSH(object): except SSHException: raise IOError('Cannot connect to {host}'. format(host=node['host'])) + except NoValidConnectionsError as err: + logger.error(repr(err)) + raise IOError('Unable to connect to port {port} on {host}'. + format(port=node['port'], host=node['host'])) def disconnect(self, node): """Close SSH connection to the node. @@ -320,7 +324,7 @@ class SSH(object): def interactive_terminal_close(chan): """Close interactive terminal SSH channel. - :param: chan: SSH channel to be closed. + :param chan: SSH channel to be closed. """ chan.close() @@ -371,6 +375,17 @@ def exec_cmd(node, cmd, timeout=600, sudo=False): """Convenience function to ssh/exec/return rc, out & err. Returns (rc, stdout, stderr). + + :param node: The node to execute command on. + :param cmd: Command to execute. + :param timeout: Timeout value in seconds. Default: 600. + :param sudo: Sudo privilege execution flag. Default: False. + :type node: dict + :type cmd: str + :type timeout: int + :type sudo: bool + :returns: RC, Stdout, Stderr. + :rtype: tuple(int, str, str) """ if node is None: raise TypeError('Node parameter is None') @@ -380,10 +395,35 @@ def exec_cmd(node, cmd, timeout=600, sudo=False): raise ValueError('Empty command parameter') ssh = SSH() + + if node.get('host_port') is not None: + ssh_node = dict() + ssh_node['host'] = '127.0.0.1' + ssh_node['port'] = node['port'] + ssh_node['username'] = node['username'] + ssh_node['password'] = node['password'] + import pexpect + options = '-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null' + tnl = '-L {port}:127.0.0.1:{port}'.format(port=node['port']) + ssh_cmd = 'ssh {tnl} {op} {user}@{host} -p {host_port}'.\ + format(tnl=tnl, op=options, user=node['host_username'], + host=node['host'], host_port=node['host_port']) + logger.trace('Initializing local port forwarding:\n{ssh_cmd}'. + format(ssh_cmd=ssh_cmd)) + child = pexpect.spawn(ssh_cmd) + child.expect('.* password: ') + logger.trace(child.after) + child.sendline(node['host_password']) + child.expect('Welcome .*') + logger.trace(child.after) + logger.trace('Local port forwarding finished.') + else: + ssh_node = node + try: - ssh.connect(node) + ssh.connect(ssh_node) except SSHException as err: - logger.error("Failed to connect to node" + str(err)) + logger.error("Failed to connect to node" + repr(err)) return None, None, None try: @@ -393,7 +433,7 @@ def exec_cmd(node, cmd, timeout=600, sudo=False): (ret_code, stdout, stderr) = ssh.exec_command_sudo(cmd, timeout=timeout) except SSHException as err: - logger.error(err) + logger.error(repr(err)) return None, None, None return ret_code, stdout, stderr @@ -416,7 +456,7 @@ def exec_cmd_no_error(node, cmd, timeout=600, sudo=False, message=None): :type message: str :returns: Stdout, Stderr. :rtype: tuple(str, str) - :raise RuntimeError: If bash return code is not 0. + :raises RuntimeError: If bash return code is not 0. """ ret_code, stdout, stderr = exec_cmd(node, cmd, timeout=timeout, sudo=sudo) msg = ('Command execution failed: "{cmd}"\n{stderr}'.