I'm trying to use paramiko to upload files to a remote EC2 server.
My app.py which primarily handles my tkinter GUI imports a custom lib.file_handler module that handles some functionality. That file_handler imports my lib.ssh_handler.py module. This module has a class that will handle my ssh requests. This works fine if I test my class within a if __name__ == '__main__':
within the ssh_handler.py module. I know it's an issue with spawning the additional thread within the imported module, I just don't know how to get around that as this module is so deep inside my app. This thread suggests not calling connect() during import, which I don't think I'm doing as I have to initiate the class within the lib.file_handler.py before I use it. I don't want to always be connected to the remote server, only if I want to upload files, so I don't want paramiko.connect() within my app.py.
Issue 104 has been open since 2012, but py3compat does not seem to be part of the module anymore.
Any input on how to solve this threading issue, or a good alternative to paramiko would be appreciated. .
file_handler.py
from lib.ssh_handler import ssh_Handler
ssh = ssh_Handler()
ssh = ssh.upload_files()
ssh_hanlder.py
import paramiko
import lib.Secrets as Secrets
class ssh_Handler():
"""Handle interactions with a remote server"""
def __init__(self, hostname=Secrets.hostname, user=Secrets.ssh_user, ssh_key=Secrets.ssh_key):
self.ssh = paramiko.SSHClient()
self.ssh.load_host_keys(os.path.expanduser(os.path.join("~", ".ssh", "known_hosts")))
self.ssh.connect(hostname=hostname, port=22, username=user, key_filename=ssh_key, allow_agent=False)
self.storage_folder = '/path/to/storage'
03-18 14:02 paramiko.transport DEBUG starting thread (client mode): 0xe42de650
03-18 14:02 paramiko.transport DEBUG Local version/idstring: SSH-2.0-paramiko_3.4.0
03-18 14:02 paramiko.transport DEBUG Remote version/idstring: SSH-2.0-OpenSSH_8.9p1 Ubuntu-3ubuntu0.6
03-18 14:02 paramiko.transport INFO Connected (version 2.0, client OpenSSH_8.9p1)
I ended up abandoning Paramiko in favor of asyncssh. The working code is below. This also saves me from writing a recursive upload function.
import asyncio
import asyncssh
async def upload_directory(local_folder,
remote_folder=None,
hostname=Secrets.hostname,
user=Secrets.ssh_user,
ssh_key=Secrets.ssh_key):
if remote_folder is None:
remote_folder = 'folder/to/storage'
async with asyncssh.connect(host=hostname,
username=user,
client_keys=ssh_key,
port=22) as conn:
async with conn.start_sftp_client() as sftp:
await sftp.put(localpaths=local_folder,
remotepath=remote_folder,
recurse=True)
try:
local_path = 'path/to/directory'
asyncio.get_event_loop().run_until_complete(upload_directory(local_path))
except (OSError, asyncssh.Error) as error:
print(error)