2323from gevent import joinall , spawn , Timeout as GTimeout
2424from gevent .hub import Hub
2525
26- from ..common import _validate_pkey_path
26+ from ..common import _validate_pkey_path , _validate_pkey
2727from ...config import HostConfig
2828from ...constants import DEFAULT_RETRIES , RETRY_DELAY
2929from ...exceptions import HostArgumentError , Timeout , ShellError , HostConfigError
@@ -39,7 +39,7 @@ class BaseParallelSSHClient(object):
3939 def __init__ (self , hosts , user = None , password = None , port = None , pkey = None ,
4040 allow_agent = True ,
4141 num_retries = DEFAULT_RETRIES ,
42- timeout = 120 , pool_size = 10 ,
42+ timeout = 120 , pool_size = 100 ,
4343 host_config = None , retry_delay = RETRY_DELAY ,
4444 identity_auth = True ,
4545 ipv6_only = False ,
@@ -64,7 +64,8 @@ def __init__(self, hosts, user=None, password=None, port=None, pkey=None,
6464 self .user = user
6565 self .password = password
6666 self .port = port
67- self .pkey = pkey
67+ self .pkey = _validate_pkey (pkey )
68+ self .__pkey_data = self ._load_pkey_data (pkey ) if pkey is not None else None
6869 self .num_retries = num_retries
6970 self .timeout = timeout
7071 self ._host_clients = {}
@@ -113,9 +114,26 @@ def hosts(self, _hosts):
113114 self ._host_clients .pop ((i , host ), None )
114115 self ._hosts = _hosts
115116
117+ def __del__ (self ):
118+ self .disconnect ()
119+
120+ def disconnect (self ):
121+ if not hasattr (self , '_host_clients' ):
122+ return
123+ for s_client in self ._host_clients .values ():
124+ try :
125+ s_client .disconnect ()
126+ except Exception as ex :
127+ logger .debug ("Client disconnect failed with %s" , ex )
128+ pass
129+ del s_client
130+
116131 def _check_host_config (self ):
117132 if self .host_config is None :
118133 return
134+ if not isinstance (self .host_config , list ):
135+ raise HostConfigError ("Host configuration of type %s is invalid - valid types are List[HostConfig]" ,
136+ type (self .host_config ))
119137 host_len = len (self .hosts )
120138 if host_len != len (self .host_config ):
121139 raise ValueError (
@@ -231,7 +249,7 @@ def _get_output_from_cmds(self, cmds, raise_error=False):
231249
232250 def _get_output_from_greenlet (self , cmd_i , cmd , raise_error = False ):
233251 host = self .hosts [cmd_i ]
234- alias = self ._get_host_config (cmd_i , host ).alias
252+ alias = self ._get_host_config (cmd_i ).alias
235253 try :
236254 host_out = cmd .get ()
237255 return host_out
@@ -256,7 +274,7 @@ def get_last_output(self, cmds=None):
256274 return self ._get_output_from_cmds (
257275 cmds , raise_error = False )
258276
259- def _get_host_config (self , host_i , host ):
277+ def _get_host_config (self , host_i ):
260278 if self .host_config is None :
261279 config = HostConfig (
262280 user = self .user , port = self .port , password = self .password , private_key = self .pkey ,
@@ -275,17 +293,13 @@ def _get_host_config(self, host_i, host):
275293 alias = None ,
276294 )
277295 return config
278- elif not isinstance (self .host_config , list ):
279- raise HostConfigError ("Host configuration of type %s is invalid - valid types are list[HostConfig]" ,
280- type (self .host_config ))
281296 config = self .host_config [host_i ]
282297 return config
283298
284299 def _run_command (self , host_i , host , command , sudo = False , user = None ,
285300 shell = None , use_pty = False ,
286301 encoding = 'utf-8' , read_timeout = None ):
287302 """Make SSHClient if needed, run command on host"""
288- logger .debug ("_run_command with read timeout %s" , read_timeout )
289303 try :
290304 _client = self ._get_ssh_client (host_i , host )
291305 host_out = _client .run_command (
@@ -311,13 +325,13 @@ def connect_auth(self):
311325 :returns: list of greenlets to ``joinall`` with.
312326 :rtype: list(:py:mod:`gevent.greenlet.Greenlet`)
313327 """
314- cmds = [spawn (self ._get_ssh_client , i , host ) for i , host in enumerate (self .hosts )]
328+ cmds = [self . pool . spawn (self ._get_ssh_client , i , host ) for i , host in enumerate (self .hosts )]
315329 return cmds
316330
317331 def _consume_output (self , stdout , stderr ):
318- for line in stdout :
332+ for _ in stdout :
319333 pass
320- for line in stderr :
334+ for _ in stderr :
321335 pass
322336
323337 def join (self , output = None , consume_output = False , timeout = None ):
@@ -346,6 +360,9 @@ def join(self, output=None, consume_output=False, timeout=None):
346360 :rtype: ``None``"""
347361 if output is None :
348362 output = self .get_last_output ()
363+ if output is None :
364+ logger .info ("No last output to join on - run_command has never been run." )
365+ return
349366 elif not isinstance (output , list ):
350367 raise ValueError ("Unexpected output object type" )
351368 cmds = [self .pool .spawn (self ._join , host_out , timeout = timeout ,
@@ -544,32 +561,26 @@ def _copy_remote_file(self, host_i, host, remote_file, local_file, recurse,
544561 return client .copy_remote_file (
545562 remote_file , local_file , recurse = recurse , ** kwargs )
546563
547- def _handle_greenlet_exc (self , func , host , * args , ** kwargs ):
548- try :
549- return func (* args , ** kwargs )
550- except Exception as ex :
551- raise ex
552-
553564 def _get_ssh_client (self , host_i , host ):
554565 logger .debug ("Make client request for host %s, (host_i, host) in clients: %s" ,
555566 host , (host_i , host ) in self ._host_clients )
556567 _client = self ._host_clients .get ((host_i , host ))
557568 if _client is not None :
558569 return _client
559- cfg = self ._get_host_config (host_i , host )
570+ cfg = self ._get_host_config (host_i )
560571 _pkey = self .pkey if cfg .private_key is None else cfg .private_key
561572 _pkey_data = self ._load_pkey_data (_pkey )
562573 _client = self ._make_ssh_client (host , cfg , _pkey_data )
563574 self ._host_clients [(host_i , host )] = _client
564575 return _client
565576
566577 def _load_pkey_data (self , _pkey ):
567- if isinstance (_pkey , str ):
568- _validate_pkey_path ( _pkey )
569- with open (_pkey , 'rb' ) as fh :
570- _pkey_data = fh . read ()
571- return _pkey_data
572- return _pkey
578+ if not isinstance (_pkey , str ):
579+ return _pkey
580+ _pkey = _validate_pkey_path (_pkey )
581+ with open ( _pkey , 'rb' ) as fh :
582+ _pkey_data = fh . read ()
583+ return _pkey_data
573584
574585 def _make_ssh_client (self , host , cfg , _pkey_data ):
575586 raise NotImplementedError
0 commit comments