Related to my previous post on monitoring output, I also needed to provide a script to transfer the output files from the scripts to a remote server. For the same reasons, so the researcher can maintain his own scripts, this was written in Python rather than Bash.

I used the Paramiko library to do this with Python, which is available by default on our HPC cluster.

#!/usr/bin/env python

# Core libraries
import os
from pathlib import Path, PurePath

# 3rd party libraries
from paramiko.client import SSHClient


def copy_file(source_path, destination_host, destination_path,
              destination_username, private_key_file,
              private_key_passphrase):
    """
    Transfer a file with SFTP to remote system.

    Args:
        source_path: local file path to copy
        destination_host: remote host to copy to
        destination_path: remote path to copy to
        destination_username: remote username to login as
        private_key_file: local path to private key
        private_key_passphrase: passphrase to unlock the private key
    """

    client = SSHClient()
    client.load_system_host_keys()
    client.connect(destination_host, username=destination_username,
                   key_filename=private_key_file,
                   passphrase=private_key_passphrase)
    sftp = client.open_sftp()
    sftp.put(source_path, destination_path)
    sftp.close()
    client.close()


def copy_dir(source_path, destination_host, destination_path,
             destination_username, private_key_file,
             private_key_passphrase):
    """
    Transfer a directory recursively with SFTP to remote system.

    Args:
        source_path: local directory to copy
        destination_host: remote host to copy to
        destination_path: remote directory to copy into
        destination_username: remote username to login as
        private_key_file: local path to private key
        private_key_passphrase: passphrase to unlock the private key
    """

    def __copy_dir(sftp_client, dir_path, destination_path):
        for file in [x for x in dir_path.iterdir()]:
            if file.is_dir():
                sftp_client.mkdir(os.fspath(destination_path / file.name))
                # Recursively copy sub-directory
                __copy_dir(sftp_client, file, destination_path / file.name)
            else:
                sftp_client.put(os.fspath(file),
                                os.fspath(destination_path / file.name))

    client = SSHClient()
    client.load_system_host_keys()
    client.connect(destination_host, username=destination_username,
                   key_filename=private_key_file,
                   passphrase=private_key_passphrase)
    sftp = client.open_sftp()
    __copy_dir(sftp, Path(source_path), PurePath(destination_path))
    sftp.close()
    client.close()


if __name__ == '__main__':
    # copy_file('/path/to/python-sftp/test_scp.py',
    #           'remote-host.tld', '/remote/folder/test_scp.py',
    #           'remote-user', '/path/to/ssh/key', 'ssh-key-passphrase')
    copy_dir('/path/to/python-sftp', 'remote-host.tld',
             '/remote/folder', 'remote-user', '/path/to/ssh/key',
             'ssh-key-passphrase')