Commit 3257c5b6 by Michael DeHaan

Some caching improvements to paramiko which are still not yet fully leveraged

in playbook mode, since the Runner still closes abstract host connections completely
and does not have a LRU.
parent 4c83c274
...@@ -33,6 +33,12 @@ with warnings.catch_warnings(): ...@@ -33,6 +33,12 @@ with warnings.catch_warnings():
except ImportError: except ImportError:
pass pass
# keep connection objects on a per host basis to avoid repeated attempts to reconnect
SSH_CONNECTION_CACHE = {}
SFTP_CONNECTION_CACHE = {}
class Connection(object): class Connection(object):
''' SSH based connections with Paramiko ''' ''' SSH based connections with Paramiko '''
...@@ -45,7 +51,20 @@ class Connection(object): ...@@ -45,7 +51,20 @@ class Connection(object):
if port is None: if port is None:
self.port = self.runner.remote_port self.port = self.runner.remote_port
def _cache_key(self):
return "%s__%s__" % (self.host, self.runner.remote_user)
def connect(self): def connect(self):
cache_key = self._cache_key()
if cache_key in SSH_CONNECTION_CACHE:
print "DEBUG: using cached"
self.ssh = SSH_CONNECTION_CACHE[cache_key]
else:
print "DEBUG: using new"
self.ssh = SSH_CONNECTION_CACHE[cache_key] = self._connect_uncached()
return self
def _connect_uncached(self):
''' activates the connection object ''' ''' activates the connection object '''
if not HAVE_PARAMIKO: if not HAVE_PARAMIKO:
...@@ -76,8 +95,7 @@ class Connection(object): ...@@ -76,8 +95,7 @@ class Connection(object):
else: else:
raise errors.AnsibleConnectionFailed(msg) raise errors.AnsibleConnectionFailed(msg)
self.ssh = ssh return ssh
return self
def exec_command(self, cmd, tmp_path, sudo_user, sudoable=False): def exec_command(self, cmd, tmp_path, sudo_user, sudoable=False):
''' run a command on the remote host ''' ''' run a command on the remote host '''
...@@ -143,11 +161,19 @@ class Connection(object): ...@@ -143,11 +161,19 @@ class Connection(object):
except IOError: except IOError:
raise errors.AnsibleError("failed to transfer file to %s" % out_path) raise errors.AnsibleError("failed to transfer file to %s" % out_path)
def _connect_sftp(self):
cache_key = "%s__%s__" % (self.host, self.runner.remote_user)
if cache_key in SFTP_CONNECTION_CACHE:
return SFTP_CONNECTION_CACHE[cache_key]
else:
result = SFTP_CONNECTION_CACHE[cache_key] = self.connect().ssh.open_sftp()
return result
def fetch_file(self, in_path, out_path): def fetch_file(self, in_path, out_path):
''' save a remote file to the specified path ''' ''' save a remote file to the specified path '''
vvv("FETCH %s TO %s" % (in_path, out_path), host=self.host) vvv("FETCH %s TO %s" % (in_path, out_path), host=self.host)
try: try:
self.sftp = self.ssh.open_sftp() self.sftp = self._connect_sftp()
except: except:
raise errors.AnsibleError("failed to open a SFTP connection") raise errors.AnsibleError("failed to open a SFTP connection")
try: try:
...@@ -157,7 +183,10 @@ class Connection(object): ...@@ -157,7 +183,10 @@ class Connection(object):
def close(self): def close(self):
''' terminate the connection ''' ''' terminate the connection '''
cache_key = self._cache_key()
SSH_CONNECTION_CACHE.pop(cache_key, None)
SFTP_CONNECTION_CACHE.pop(cache_key, None)
if self.sftp is not None: if self.sftp is not None:
self.sftp.close() self.sftp.close()
self.ssh.close() self.ssh.close()
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment