Skip to content

Commit 4c078cd

Browse files
committed
Added retries on connection failures to ssh client. Changed tests to wait for server to come up before client trying to connect
1 parent 0dac2c7 commit 4c078cd

File tree

2 files changed

+31
-20
lines changed

2 files changed

+31
-20
lines changed

pssh.py

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
handler.setFormatter(host_log_format)
1818
host_logger.addHandler(handler)
1919
host_logger.setLevel(logging.INFO)
20+
NUM_RETRIES = 3
2021

2122
logger = logging.getLogger(__name__)
2223

@@ -90,24 +91,29 @@ def __init__(self, host,
9091
self.host = resolved_address
9192
self._connect()
9293

93-
def _connect(self):
94+
def _connect(self, retries=1):
9495
"""Connect to host, throw UnknownHost exception on DNS errors"""
9596
try:
9697
self.client.connect(self.host, username=self.user,
9798
password=self.password, port=self.port)
9899
except socket.gaierror, e:
99100
logger.error("Could not resolve host '%s'", self.host,)
101+
while retries < NUM_RETRIES:
102+
gevent.sleep(5)
103+
return self._connect(retries=retries+1)
100104
raise UnknownHostException("%s - %s" % (str(e.args[1]),
101105
self.host,))
102106
except socket.error, e:
103107
logger.error("Error connecting to host '%s:%s'" % (self.host,
104108
self.port,))
109+
while retries < NUM_RETRIES:
110+
gevent.sleep(5)
111+
return self._connect(retries=retries+1)
105112
raise ConnectionErrorException("%s for host '%s:%s'" % (str(e.args[1]),
106113
self.host,
107114
self.port,))
108115
except paramiko.AuthenticationException, e:
109116
raise AuthenticationException(e)
110-
gevent.sleep(0)
111117

112118
def exec_command(self, command, sudo=False, **kwargs):
113119
"""Wrapper to :mod:`paramiko.SSHClient.exec_command`
@@ -147,7 +153,6 @@ def _make_sftp(self):
147153
"""Make SFTP client from open transport"""
148154
transport = self.client.get_transport()
149155
channel = transport.open_session()
150-
gevent.sleep(0)
151156
return paramiko.SFTPClient.from_transport(transport)
152157

153158
def mkdir(self, sftp, directory):
@@ -164,7 +169,6 @@ def mkdir(self, sftp, directory):
164169
except IOError, error:
165170
logger.error("Error occured creating directory on %s - %s",
166171
self.host, error)
167-
gevent.sleep(0)
168172

169173
def copy_file(self, local_file, remote_file):
170174
"""Copy local file to host via SFTP/SCP
@@ -195,7 +199,6 @@ def copy_file(self, local_file, remote_file):
195199
else:
196200
logger.info("Copied local file %s to remote destination %s:%s",
197201
local_file, self.host, remote_file)
198-
gevent.sleep(0)
199202

200203
class ParallelSSHClient(object):
201204
"""

tests/test_pssh_client.py

Lines changed: 23 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import logging
1111
import gevent
1212
import threading
13+
import time
1314

1415
_setup_logger(server_logger)
1516

@@ -34,7 +35,28 @@ def _run_client_exec_command(self):
3435
gevent.sleep(0)
3536
del client
3637

37-
def _run_client_fail_auth(self):
38+
# def _run_client_fail_auth(self):
39+
# try:
40+
# except Exception:
41+
# raise SystemExit
42+
43+
def test_pssh_client_exec_command(self):
44+
server = listen({ self.fake_cmd : self.fake_resp }, self.listener)
45+
time.sleep(5)
46+
client = ParallelSSHClient(['localhost'], port=self.listen_port)
47+
cmd = client.exec_command(self.fake_cmd)[0]
48+
output = client.get_stdout(cmd)
49+
expected = {'localhost' : {'exit_code' : 0}}
50+
self.assertEqual(expected, output,
51+
msg = "Got unexpected command output - %s" % (output,))
52+
gevent.sleep(0)
53+
del client
54+
server.join()
55+
56+
def test_pssh_client_auth_failure(self):
57+
server = listen({ self.fake_cmd : self.fake_resp },
58+
self.listener, fail_auth=True)
59+
time.sleep(5)
3860
client = ParallelSSHClient(['localhost'], port=self.listen_port)
3961
cmd = client.exec_command(self.fake_cmd)[0]
4062
# Handle exception
@@ -44,18 +66,4 @@ def _run_client_fail_auth(self):
4466
except AuthenticationException:
4567
pass
4668
del client
47-
48-
def test_pssh_client_exec_command(self):
49-
server = listen({ self.fake_cmd : self.fake_resp }, self.listener)
50-
client = threading.Thread(target=self._run_client_exec_command)
51-
client.start()
52-
client.join()
53-
server.join()
54-
55-
def test_pssh_client_auth_failure(self):
56-
server = listen({ self.fake_cmd : self.fake_resp },
57-
self.listener, fail_auth=True)
58-
client = threading.Thread(target=self._run_client_fail_auth)
59-
client.start()
60-
client.join()
6169
server.join()

0 commit comments

Comments
 (0)