You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@libcloud.apache.org by to...@apache.org on 2014/05/28 16:40:20 UTC
git commit: Add "timeout" argument to ParamikoSSHClient.run method.
Repository: libcloud
Updated Branches:
refs/heads/trunk 4ffa70380 -> 1ad8e0396
Add "timeout" argument to ParamikoSSHClient.run method.
If this argument is specified, run method will throw if the command doesn't
finish in the provded time period.
Project: http://git-wip-us.apache.org/repos/asf/libcloud/repo
Commit: http://git-wip-us.apache.org/repos/asf/libcloud/commit/1ad8e039
Tree: http://git-wip-us.apache.org/repos/asf/libcloud/tree/1ad8e039
Diff: http://git-wip-us.apache.org/repos/asf/libcloud/diff/1ad8e039
Branch: refs/heads/trunk
Commit: 1ad8e03967e15e93c7fe72ee75f0fdce29f73999
Parents: 4ffa703
Author: Tomaz Muraus <to...@apache.org>
Authored: Wed May 28 16:29:17 2014 +0200
Committer: Tomaz Muraus <to...@apache.org>
Committed: Wed May 28 16:30:40 2014 +0200
----------------------------------------------------------------------
CHANGES.rst | 12 +++++++++++
libcloud/compute/ssh.py | 47 +++++++++++++++++++++++++++++++++++++-------
2 files changed, 52 insertions(+), 7 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/libcloud/blob/1ad8e039/CHANGES.rst
----------------------------------------------------------------------
diff --git a/CHANGES.rst b/CHANGES.rst
index e1e0a39..3d97fee 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -162,6 +162,18 @@ Compute
- Add new driver for Kili public cloud (http://kili.io/)
[Tomaz Muraus]
+- Add "timeout" argument to the ParamikoSSHClient.run method. If this argument
+ is specified and the command passed to run method doesn't finish in the
+ defined timeout, `SSHCommandTimeoutError` is throw and the connection to the
+ remote server is closed.
+
+ Note #1: If timed out happens, this functionality doesn't guarantee that the
+ underlying command will be stopped / killed. The way it works it simply
+ closes a connect to the remote server.
+ [Tomaz Muraus]
+
+ Note #2: "timeout" argument is only available in the Paramiko SSH client.
+
Storage
~~~~~~~
http://git-wip-us.apache.org/repos/asf/libcloud/blob/1ad8e039/libcloud/compute/ssh.py
----------------------------------------------------------------------
diff --git a/libcloud/compute/ssh.py b/libcloud/compute/ssh.py
index 68a4da4..fe9d856 100644
--- a/libcloud/compute/ssh.py
+++ b/libcloud/compute/ssh.py
@@ -41,11 +41,30 @@ from os.path import join as pjoin
from libcloud.utils.logging import ExtraLogFormatter
from libcloud.utils.py3 import StringIO
+__all__ = [
+ 'BaseSSHClient',
+ 'ParamikoSSHClient',
+ 'ShellOutSSHClient',
+
+ 'SSHCommandTimeoutError'
+]
+
# Maximum number of bytes to read at once from a socket
CHUNK_SIZE = 1024
+class SSHCommandTimeoutError(Exception):
+ """
+ Exception which is raised when an SSH command times out.
+ """
+ def __init__(self, cmd, timeout):
+ self.cmd = cmd
+ self.timeout = timeout
+ message = 'Command didn\'t finish in %s seconds' % (timeout)
+ super(SSHCommandTimeoutError, self).__init__(message)
+
+
class BaseSSHClient(object):
"""
Base class representing a connection over SSH/SCP to a remote node.
@@ -92,8 +111,8 @@ class BaseSSHClient(object):
"""
Connect to the remote node over SSH.
- :return: True if the connection has been successfully established,
- False otherwise.
+ :return: True if the connection has been successfuly established, False
+ otherwise.
:rtype: ``bool``
"""
raise NotImplementedError(
@@ -128,8 +147,8 @@ class BaseSSHClient(object):
:type path: ``str``
:keyword path: File path on the remote node.
- :return: True if the file has been successfully deleted,
- False otherwise.
+ :return: True if the file has been successfuly deleted, False
+ otherwise.
:rtype: ``bool``
"""
raise NotImplementedError(
@@ -151,8 +170,8 @@ class BaseSSHClient(object):
"""
Shutdown connection to the remote node.
- :return: True if the connection has been successfully closed,
- False otherwise.
+ :return: True if the connection has been successfuly closed, False
+ otherwise.
:rtype: ``bool``
"""
raise NotImplementedError(
@@ -285,10 +304,14 @@ class ParamikoSSHClient(BaseSSHClient):
sftp.close()
return True
- def run(self, cmd):
+ def run(self, cmd, timeout=None):
"""
Note: This function is based on paramiko's exec_command()
method.
+
+ :param timeout: How long to wait (in seconds) for the command to
+ finish (optional).
+ :type timeout: ``float``
"""
extra = {'_cmd': cmd}
self.logger.debug('Executing command', extra=extra)
@@ -299,6 +322,7 @@ class ParamikoSSHClient(BaseSSHClient):
transport = self.client.get_transport()
chan = transport.open_session()
+ start_time = time.time()
chan.exec_command(cmd)
stdout = StringIO()
@@ -320,6 +344,15 @@ class ParamikoSSHClient(BaseSSHClient):
exit_status_ready = chan.exit_status_ready()
while not exit_status_ready:
+ current_time = time.time()
+ elapsed_time = (current_time - start_time)
+
+ if timeout and (elapsed_time > timeout):
+ # TODO: Is this the right way to clean up?
+ chan.close()
+
+ raise SSHCommandTimeoutError(cmd=cmd, timeout=timeout)
+
if chan.recv_ready():
data = chan.recv(CHUNK_SIZE)