Source code for pyworkflow.utils.remote

# **************************************************************************
# *
# * Authors:     J.M. De la Rosa Trevin (jmdelarosa@cnb.csic.es)
# *
# * Unidad de  Bioinformatica of Centro Nacional de Biotecnologia , CSIC
# *
# * This program is free software; you can redistribute it and/or modify
# * it under the terms of the GNU General Public License as published by
# * the Free Software Foundation; either version 3 of the License, or
# * (at your option) any later version.
# *
# * This program is distributed in the hope that it will be useful,
# * but WITHOUT ANY WARRANTY; without even the implied warranty of
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# * GNU General Public License for more details.
# *
# * You should have received a copy of the GNU General Public License
# * along with this program; if not, write to the Free Software
# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
# * 02111-1307  USA
# *
# *  All comments concerning this program package may be sent to the
# *  e-mail address 'scipion@cnb.csic.es'
# *
# **************************************************************************

# This file is not really being used, and its tests cannot run because
# of this. So far we are not really using paramiko, and so all its
# dependencies are broken.
#
# I am commenting out all of them today. If used in the future, please
# fix. If not, please remove this file (remote.py) and test_remote.py
#
# Jordi. June 2014.

"""
This modules contains some wrappers over the ssh paramiko library
to provide handling functions on remote hosts through ssh.

Main classes are:

    RemotePath: this class use an ssh/sftp connection to mimic the
        functions in utils.path but remotely and provides basic file transfer


"""

import os
import errno
# import paramiko

from pyworkflow.utils.path import makeFilePath
from pyworkflow.utils.log import ScipionLogger

LOCAL_USER_AND_HOST = ''
SSH_PORT = 22
PAIRS_SEPARATOR = ':'

log = ScipionLogger()


[docs]def testHostConfig(host): """ Test the connection to a remote host give its configuration.(see HostConfig class) Params: host: configuration of the remote host, should contains hostName, userName and password. Returns: True if the host could be reached. """ try: ssh = sshConnectFromHost(host) rpath = RemotePath(ssh) rpath.listdir('.') rpath.close() return True except Exception as ex: return False
[docs]def sshConnect(hostName, userName, password, port=SSH_PORT, **args): """ Common way to create a ssh connection. Params: hostName: Remote host name. userName: User name. password: Password. port: port to establish connection (usually 22) Returns: ssh connection handler. """ raise NotImplementedError('No dependence on paramiko yet')
# ssh = paramiko.SSHClient() # ssh.load_system_host_keys() # ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) # ssh.connect(hostName, port, userName, password, **args) # return ssh
[docs]def sshConnectFromHost(host): """ Establish a connection receiving a HostConfig class. """ return sshConnect(host.getHostName(), host.getUserName(), host.getPassword())
[docs]class RemotePath(object): """ This class will server as a Wrapper to the paramiko sftp protocol through a ssh connection. This class will implement useful methods for remote path handling such as: creating files, deleting folders... """
[docs] @classmethod def fromCredentials(cls, hostName, userName, password, port=SSH_PORT, **args): ssh = sshConnect(hostName, userName, password, port, **args) rpath = RemotePath(ssh) return rpath
def __init__(self, ssh): self.ssh = ssh self.sftp = ssh.open_sftp() # Shortcut some of the sftp methods self.listdir = self.sftp.listdir
[docs] def exists(self, path): """ Check if a remote path exists(like os.path.exists remotely). """ try: self.sftp.stat(path) except IOError as e: if e.errno == errno.ENOENT: return False else: return True
[docs] def isdir(self, path): """ Check if a remote path is a directory (like os.path.isdir remotely). """ try: from stat import S_ISDIR return S_ISDIR(self.sftp.stat(path).st_mode) except IOError: # Path does not exist, so by definition not a directory return False
[docs] def makedirs(self, remoteFolder): """ Like os.makedirs remotely. """ if len(remoteFolder) and not self.exists(remoteFolder): log.info('RemotePath.makedirs, path: %s' % remoteFolder) parent = os.path.dirname(remoteFolder) # if have parent and it doesn't exist, create it recursively if len(parent) and not self.exists(parent): self.makedirs(parent) self.sftp.mkdir(remoteFolder)
[docs] def getFile(self, remoteFile, localFile): """ Wrapper around sftp.get that ensures path exists for localFile. """ makeFilePath(localFile) self.sftp.get(remoteFile, localFile)
[docs] def putFile(self, localFile, remoteFile): """ Wrapper around sftp.put that ensures the remote path exists for put the file. """ self.makeFilePath(remoteFile) log.info('RemotePath.putFile, local=%s, remote=%s' % (localFile, remoteFile)) self.sftp.put(localFile, remoteFile)
[docs] def makeFilePath(self, *remoteFiles): """ Create the remote folder path for remoteFiles. """ self.makePath(*[os.path.dirname(r) for r in remoteFiles])
[docs] def makePath(self, *remoteFolders): """ Make all path in remoteFolders list. """ for p in remoteFolders: if len(p): self.makedirs(p)
[docs] def close(self): """ Close both ssh and sftp connections. """ self.sftp.close() self.ssh.close()
[docs] def copyTree(self, localFolder, remoteFolder): """ Same as shutil.copytree, but allowing that the dest folder also exists. dest is a remote folder. """ if not self.exists(remoteFolder): self.makePath(remoteFolder) for path in os.listdir(localFolder): localPath = os.path.join(localFolder, path) remotePath = os.path.join(remoteFolder, path) # Create folders if os.path.isdir(localPath): self.copyTree(localPath, remotePath) elif os.path.isfile(localPath): self.putFile(localPath, remotePath)
[docs] def cleanPath(self, *remotePaths): """ Same as pyworkflow.utils.path.cleanPath but for remote folders or files. """ for path in remotePaths: if self.exists(path): # Create folders if self.isdir(path): files = [os.path.join(path, f) for f in self.sftp.listdir(path)] self.cleanPath(*files) log.info('RemotePath.cleanPath, rmdir path: %s' % path) self.sftp.rmdir(path) else: # os.path.isfile(path): log.info('RemotePath.cleanPath, remove path: %s' % path) self.sftp.remove(path)