def put(sftp: pysftp.Connection, filename: str): try: sftp.put(filename, os.path.basename(filename), preserve_mtime=False) return True except FileNotFoundError: print("Error:", FILE_NOT_FOUND_ERROR_MESSAGE) return False except OSError: if sftp.isdir(filename): # The file we want to upload is a directory on remote. # pysftp doesn't handle this case well, so we'll print a helpful # error message of our own. print("Error:", FOLDER_CONFLICT_ERROR_MESSAGE) return False else: # It's some other error; we'll let the main handler deal with it. raise
class SFTP: def __init__(self, sftp_server_config): self.server = sftp_server_config['host_address'] self.username = sftp_server_config['user_name'] self.private_key = sftp_server_config['key_path'] self.sftp_folder = sftp_server_config['sftp_folder'] self.connection_opts = CnOpts() self.connection_opts.hostkeys = None self.__connection: Connection = None def connect(self): if not self.__connection: self.__connection = Connection(self.server, self.username, self.private_key, cnopts=self.connection_opts) return self def put(self, file, remote_path): return self.__connection.put(file, remote_path) def remove(self, path): return self.__connection.remove(path) def rmdir(self, path): return self.__connection.rmdir(path) def listdir(self, path): return self.__connection.listdir(path) def is_dir(self, path): return self.__connection.isdir(path) def is_file(self, path): return self.__connection.isfile(path) def close(self): self.__connection.close() self.__connection = None
def _process_file(self, sftp_conn: pysftp.Connection, f: dict, field_dict: dict, record_info: object, record_creator: object): """Process single remote file. :param sftp_conn: [description] :type sftp_conn: pysftp.Connection :param f: [description] :type f: dict :param field_dict: [description] :type field_dict: dict :param record_creator: [description] :type record_creator: object """ # These fields are shared by all tool modes (directories only for LIST_FILES) record_info[field_dict['Filename']].set_from_string( record_creator, f['filename']) record_info[field_dict['Size']].set_from_int32(record_creator, f['size']) record_info[field_dict['TimeAdded']].set_from_string( record_creator, f['atime']) record_info[field_dict['TimeModified']].set_from_string( record_creator, f['mtime']) if self.tool_mode == self.ToolMode.LIST_FILES: # Fields only present for LIST_FILES mode record_info[field_dict['UID']].set_from_string( record_creator, f['uid']) record_info[field_dict['GID']].set_from_string( record_creator, f['gid']) record_info[field_dict['Mode']].set_from_string( record_creator, f['mode']) record_info[field_dict['IsDirectory']].set_from_bool( record_creator, f['is_dir']) record_info[field_dict['IsFile']].set_from_bool( record_creator, f['is_file']) elif self.tool_mode != self.ToolMode.LIST_FILES: # Download files if not in LIST_FILES mode if self.tool_mode == self.ToolMode.DOWNLOAD_TO_BLOB: # Generate temporary filename out_fname = self.alteryx_engine.create_temp_file_name('tmp') elif self.tool_mode == self.ToolMode.DOWNLOAD_TO_PATH: # Build local path for download out_fname = os.path.join(self.output_settings['local_path'], f['filename']) # Download file try: # Download file to temporary folder sftp_conn.get(f['filename'], localpath=out_fname) except IOError as e: self.output_message('Error transferring file "{}": {}'.format( f['filename'], e)) # Generate BLOB for Alteryx if self.tool_mode == self.ToolMode.DOWNLOAD_TO_BLOB: # Read file as binary for blob with open(out_fname, 'rb') as temp_f: blob_content = temp_f.read() if self.tool_mode == self.ToolMode.DOWNLOAD_TO_BLOB: # Add file as blob record_info[field_dict[ self.output_settings['blobfield']]].set_from_blob( record_creator, blob_content) elif self.tool_mode == self.ToolMode.DOWNLOAD_TO_PATH: # Add file path record_info[field_dict['FilePath']].set_from_string( record_creator, out_fname) # Finalize record for this file and push out_record = record_creator.finalize_record() self.output_anchor.push_record(out_record, False) # Reset for next file record_creator.reset() # Handle file after it has been downloaded if self.file_handling == self.FileHandling.MOVE_FILES: # Check if target folder exists if not sftp_conn.exists(self.sftp_settings['move_path']): self.output_message( "The target folder {} does not exist.".format( self.sftp_settings['move_path']), messageType=Sdk.EngineMessageType.warning) return # Check if it is actually a folder if not sftp_conn.isdir(self.sftp_settings['move_path']): self.output_message( "The target folder {} is not a directory.".format( self.sftp_settings['move_path']), messageType=Sdk.EngineMessageType.warning) return # Try to move file try: sftp_conn.rename( sftp_conn.pwd + "/" + f['filename'], sftp_conn.normalize(self.sftp_settings['move_path']) + "/" + f['filename']) except IOError as e: self.output_message('Error moving file "{}": {}'.format( f['filename'], e)) else: self.output_message('File {} moved to {}.'.format( f['filename'], sftp_conn.normalize(self.sftp_settings['move_path'])), messageType=Sdk.EngineMessageType.info) elif self.file_handling == self.FileHandling.DELETE_FILES: # Simply delete file try: sftp_conn.remove(sftp_conn.pwd + "/" + f['filename']) except IOError as e: self.output_message('Error deleting file "{}": {}'.format( f['filename'], e)) else: self.output_message('File {} deleted from server.'.format( f['filename']), messageType=Sdk.EngineMessageType.info)