@@ -857,4 +857,39 @@ def _copy_file(self, host, local_file, remote_file, recurse=False):
857857 agent = self .agent ,
858858 channel_timeout = self .channel_timeout )
859859 return self .host_clients [host ].copy_file (local_file , remote_file ,
860- recurse = recurse )
860+
861+ def copy_file_to_local (self , remote_file , local_file ):
862+ """Copy remote file to local file in parallel
863+
864+ :param remote_file: remote filepath to copy to local host
865+ :type remote_file: str
866+ :param local_file: local filepath on local host to copy file to
867+ :type local_file: str
868+
869+ .. note ::
870+ Local directories in `local_file` that do not exist will be
871+ created as long as permissions allow.
872+
873+ .. note ::
874+ Path separation is handled client side so it is possible to copy
875+ to/from hosts with differing path separators, like from/to Linux
876+ and Windows.
877+
878+ .. note ::
879+ File names will be de-duplicated by appending the hostname to the
880+ filepath.
881+
882+ :rtype: List(:mod:`gevent.Greenlet`) of greenlets for remote copy \
883+ commands
884+ """
885+ return [self .pool .spawn (self ._copy_file_to_local , host , remote_file , local_file )
886+ for host in self .hosts ]
887+
888+ def _copy_file_to_local (self , host , remote_file , local_file ):
889+ """Make sftp client, copy file to local"""
890+ if not self .host_clients [host ]:
891+ self .host_clients [host ] = SSHClient (host , user = self .user ,
892+ password = self .password ,
893+ port = self .port , pkey = self .pkey ,
894+ forward_ssh_agent = self .forward_ssh_agent )
895+ return self .host_clients [host ].copy_file_to_local (remote_file , local_file + '_' + host )
0 commit comments