I am requesting advice for running concurrent pysftp API commands, such as listing files in a directory and downloading them from a server. It seems that when I test this all requests are blocked until the previous is finished.
I'm using pysftp with Django and I'm not sure how to implement this in a way that will scale a bit so I can have multiple users on the page making requests without them being blocked until another users request has been served.
I tried something like this:
class sftp:
def __init__(self):
self.response = HttpResponse()
self.cnopts = pysftp.CnOpts()
self.cnopts.hostkeys = None
def download(self):
with pysftp.Connection('host.exmaple.com', username='user1', password='test_password',
cnopts=self.cnopts) as sftp:
sftp.getfo(
'/var/lib/stuff/file.mp3',
self.response)
self.response['Content-Type'] = 'audio/mp3'
return self.response
Then in my view I would call something like this:
return sftp().download()
I needed something similar for one of my projects.
I wrote a module that handle listing and reading files on remote server over SSH.
Difference is that it's not using pysftp but paramiko, but it should do the job I guess.
import paramiko
class SSHClient:
__slots__ = ['transport', 'sftp']
def __init__(self, host, user, passw, port):
"""Init connection to SFTP server.
Args:
host (str): Server IP address
user (str): Server username
passw (str): Server password
port (int): connection port
"""
self.transport = paramiko.Transport((host, port))
self.transport.connect(username=user, password=passw)
self.sftp = paramiko.SFTPClient.from_transport(t=self.transport)
def __enter__(self):
return self
def __exit__(self, exception_type, exception_value, traceback):
"""Close SFTP connection"""
self.transport.close()
self.sftp.close()
def list_files(self, remote_path) -> list:
"""List files from specific server directory.
Args:
remote_path (str): SFTP server path directory.
Returns:
list of files & folders in directory.
"""
return self.sftp.listdir(path=remote_path)
def read_remote_file(self, remote_path, filename):
"""Read remote file content from server.
Args:
remote_path (str): SFTP server path.
filename (str): name of file.
"""
return self.sftp.open(
filename='{path}/{file}'.format(path=remote_path, file=filename),
mode='r'
)
def close_conn(self) -> None:
"""Close SFTP connection"""
self.transport.close()
self.sftp.close()
Then you could download a file using the content fetched using read_remote_file() to one of your views in your Django app.
Related
So I want to send and IMAGE file from client to server using Python Paramiko. For example: .jpeg, .jpg, .png
I don't get an error, but, it does print this message:
Failure
Here is example code:
from PIL import ImageGrab
import paramiko
class Client:
def __init__(self, hostname, username, password):
self.hostname = hostname
self.username = username
self.password = password
self.client = paramiko.SSHClient()
def connect(self):
self.client.load_system_host_keys()
self.client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
self.client.connect(hostname=self.hostname, username=self.username, password=self.password, port=22)
def close(self):
self.client.close()
ImageGrab.grab().save("screenshot.png") # Saves a screenshot
client = Client("hostname", "username", "password")
client.connect()
sftp_client = client.client.open_sftp()
sftp_client.put("screenshot.png", "/home") # Line that has the error
The line that I believe is messed up is the last line.
Feel free to run this code and test it. If you have any questions about this, go ahead and ask. If I did not include enough information, please say something.
Based on the issue post on paramiko github repo, you need to specify the destination parameter to the file name instead of the directory name, such as
sftp_client.put("screenshot.png", "/home/screenshot.png")
I'm trying to get a list of files and paths under a directory in an FTP site using ftputil's walk method:
import ftputil
from ftplib import FTP_TLS
host = 'my_host'
user = 'my_user'
pw = 'my_pw'
folder = '/my/dir'
ftp = ftputil.FTPHost(host, user, pw, session_factory=FTP_TLS)
for root,dirs,files in ftp.walk(folder):
print(root, dirs, files)
However, nothing is printed. ftp.walk(folder) does return a generator object, but nothing is being generated. What am I missing? Maybe I'm not handling the TLS connection right (although I don't get any error)?
I needed to run prot_p as part of setting up the session:
class TLSFTPSession(FTP_TLS):
def __init__(self, host, userid, password):
FTP_TLS.__init__(self)
#self.set_debuglevel(2)
self.connect(host, 21)
self.login(userid, password)
self.prot_p()
ftp = ftputil.FTPHost(host, user, pw, session_factory=TLSFTPSession)
Then it works!
I am having a very specific problem. I use Putty for database management for my small business. We recently had an update and our normal command path to update our records is no longer in use.
We run Putty on all computers in store. Putty is used on a virtual machine with oracle. We have a main computer for the system in which the update occurred.
We normally input ~/Desktop/getdata.sh into putty using root user and it complies an updated list, creates a text file that we use. Unfortunately, the person who created this script no longer works with us.
I am trying to find a way to re execute this file again.
After the update, when we type in ~/Desktop/getdata.sh (after logging in as root) into Putty we get 'directory cannot be found.' I've searched everyday to find this file. However, I did find a getdata.py file and a getdata.bat files.
I can show both scripts if needed, I can update the question.
When I tried to run getdata.py I get
[root#RT_Store-01 /]# ~/Desktop/getdata.py
import: unable to open X server `'.
import: unable to open X server `'.
import: unable to open X server `'.
import: unable to open X server `'.
: command not foundta.py: line 5:
/root/Desktop/getdata.py: line 6: from: command not found
/root/Desktop/getdata.py: line 7: from: command not found
: command not foundta.py: line 8:
/root/Desktop/getdata.py: line 9: syntax error near unexpected token `('
/root/Desktop/getdata.py: line 9: `dir_path = os.path.dirname(os.path.realpath(_'file__))
Do I need to convert my files to .sh? How would I do that? Is this a bigger problem?
The script for getdata.py is
import os
import tempfile
import paramiko
import time
from pywinauto import Application
from subprocess import Popen, PIPE, STDOUT
dir_path = os.path.dirname(os.path.realpath(__file__))
class Connection(object):
"""Connects and logs into the specified hostname.
Arguments that are not given are guessed from the environment."""
def __init__(self,
host,
username=None,
private_key=None,
password=None,
port=22,
):
self._sftp_live = False
self._sftp = None
if not username:
username = os.environ['LOGNAME']
# Log to a temporary file.
templog = tempfile.mkstemp('.txt', 'ssh-')[1]
paramiko.util.log_to_file(templog)
# Begin the SSH transport.
self._transport = paramiko.Transport((host, port))
self._tranport_live = True
# Authenticate the transport.
if password:
# Using Password.
self._transport.connect(username=username, password=password)
else:
# Use Private Key.
if not private_key:
# Try to use default key.
if os.path.exists(os.path.expanduser('~/.ssh/id_rsa')):
private_key = '~/.ssh/id_rsa'
elif os.path.exists(os.path.expanduser('~/.ssh/id_dsa')):
private_key = '~/.ssh/id_dsa'
else:
raise TypeError(
"You have not specified a password or key.")
private_key_file = os.path.expanduser(private_key)
rsa_key = paramiko.RSAKey.from_private_key_file(private_key_file)
self._transport.connect(username=username, pkey=rsa_key)
def _sftp_connect(self):
"""Establish the SFTP connection."""
if not self._sftp_live:
self._sftp = paramiko.SFTPClient.from_transport(self._transport)
self._sftp_live = True
def get(self, remotepath, localpath=None):
"""Copies a file between the remote host and the local host."""
if not localpath:
localpath = os.path.split(remotepath)[1]
self._sftp_connect()
self._sftp.get(remotepath, localpath)
def put(self, localpath, remotepath=None):
"""Copies a file between the local host and the remote host."""
if not remotepath:
remotepath = os.path.split(localpath)[1]
self._sftp_connect()
self._sftp.put(localpath, remotepath)
def execute(self, command):
"""Execute the given commands on a remote machine."""
channel = self._transport.open_session()
channel.exec_command(command)
output = channel.makefile('rb', -1).readlines()
if output:
return output
else:
return channel.makefile_stderr('rb', -1).readlines()
def update(self):
"""Execute the given commands on a remote machine."""
channel = self._transport.invoke_shell(term='xterm')
channel.exec_command('~/Desktop/update.sh')
output = channel.makefile('rb', -1).readlines()
if output:
return output
else:
return channel.makefile_stderr('rb', -1).readlines()
def close(self):
"""Closes the connection and cleans up."""
# Close SFTP Connection.
if self._sftp_live:
self._sftp.close()
self._sftp_live = False
# Close the SSH Transport.
if self._tranport_live:
self._transport.close()
self._tranport_live = False
def __del__(self):
"""Attempt to clean up if not explicitly closed."""
self.close()
def getData():
"""Create, get, and put delim file when called directly."""
app = Application().start(r"c:\putty.exe trak#10.1.10.70 -pw trak")
app.window_(
title_re=".*trak.*").TypeKeys("/home/trak/Desktop/getdata.sh && exit{ENTER}")
app.window_(title_re=".*trak.*").WaitNot("exists", timeout=120)
trakfile = dir_path + '/storage/trakdelim.txt'
shell = Connection('10.1.10.70', "trak", password="trak")
shell.get('/trak/data/trakdelim.txt', trakfile)
shell.close()
if __name__ == "__main__":
getData()
I appreciate anyone who can help and I can clarify when needed!
A bit of googling showed me what this is:
Someone copied this code and wrote a simple script with it that takes a file (/trak/data/trakdelim.txt) on a remote computer with ip address 10.1.10.70 username trak and password trak and copies it to the storage/trakdelim.txt file. if this is not working for you now then take a tool that allows you to do this manually with such as winSCP and use that instead.
Good luck.
You need to execute it as a python script.
python ~/Desktop/getdata.py
Having error when using FTPtool module for Python
class FTPHost(object):
"""Represent a connection to a remote host.
A remote host has a working directory, and an ftplib object connected.
"""
def __init__(self, ftp_obj):
"""Initialize with a ftplib.FTP instance (or an instance of a
subclass). Use the classmethod connect to create an actual ftplib
connection and get an FTPHost instance.
"""
self.ftp_obj = ftp_obj
def __repr__(self):
return "%s(%r)" % (self.__class__.__name__, self.ftp_obj)
def __str__(self):
return "<%s at %s:%d (%s)>" % (self.__class__.__name__,
self.ftp_obj.host, self.ftp_obj.port, self.ftp_obj)
#classmethod
def connect(cls, host, port=21, user=None, password=None, account=None,
ftp_client=ftplib.FTP, debuglevel=0, timeout=None):
"""Connect to host, using port. If user is given, login with given
user, password and account. The two latter can be None, in which case
ftplib will set the password to 'anonymous#'. You can choose which
class to instance by means of ftp_client.
"""
ftp_obj = ftp_client()
ftp_obj.set_debuglevel(debuglevel)
if timeout is not None:
old_timeout = socket.getdefaulttimeout()
socket.setdefaulttimeout(float(timeout))
ftp_obj.connect(host, port)
socket.setdefaulttimeout(old_timeout)
else:
ftp_obj.connect(host, port)
# And log in.
if user:
ftp_obj.login(user, password, account)
return cls(ftp_obj)
When calling FTPhost.connect(server, name, pass) i get the error FTPhost not defined. New to Python and have tried looking all around the code but to no avail.
I'm fresh to ftptool as well, and I met the same problem.
Here's my way.
from ftptool import FTPHost
I would like to write a script that performs the following Linux commands sequence:
rsh rr01 ( here the system will ask for password )
ssh rr02 ( here the system will ask for password again)
activate my app on some file
I was naively (and stupidly) tried to accomplish that with a simple os.system
bear in mind I using python 2.3 and would like to avoid adding modules (if possible).
Thanks in advance!
[EDIT] Check out also another example using paramiko on http://code.google.com/p/lexel-intern0t/source/browse/trunk/Python/ssh_client.py.
The script found on http://media.commandline.org.uk//code/ssh.txt may help you. It includes os module (to find the keys) and tempfile module for logging purposes, both found in python 2.3 global module index ( http://docs.python.org/release/2.3/modindex.html ) and paramiko ( http://www.lag.net/paramiko/docs/ ) for the SSH2 protocol implementation, which is supposed to work on python 2.3 and above. It's a simple piece of code:
"""Friendly Python SSH2 interface."""
import os
import tempfile
import paramiko
class Connection(object):
"""Connects and logs into the specified hostname.
Arguments that are not given are guessed from the environment."""
def __init__(self,
host,
username = None,
private_key = None,
password = None,
port = 22,
):
self._sftp_live = False
self._sftp = None
if not username:
username = os.environ['LOGNAME']
# Log to a temporary file.
templog = tempfile.mkstemp('.txt', 'ssh-')[1]
paramiko.util.log_to_file(templog)
# Begin the SSH transport.
self._transport = paramiko.Transport((host, port))
self._tranport_live = True
# Authenticate the transport.
if password:
# Using Password.
self._transport.connect(username = username, password = password)
else:
# Use Private Key.
if not private_key:
# Try to use default key.
if os.path.exists(os.path.expanduser('~/.ssh/id_rsa')):
private_key = '~/.ssh/id_rsa'
elif os.path.exists(os.path.expanduser('~/.ssh/id_dsa')):
private_key = '~/.ssh/id_dsa'
else:
raise TypeError, "You have not specified a password or key."
private_key_file = os.path.expanduser(private_key)
rsa_key = paramiko.RSAKey.from_private_key_file(private_key_file)
self._transport.connect(username = username, pkey = rsa_key)
def _sftp_connect(self):
"""Establish the SFTP connection."""
if not self._sftp_live:
self._sftp = paramiko.SFTPClient.from_transport(self._transport)
self._sftp_live = True
def get(self, remotepath, localpath = None):
"""Copies a file between the remote host and the local host."""
if not localpath:
localpath = os.path.split(remotepath)[1]
self._sftp_connect()
self._sftp.get(remotepath, localpath)
def put(self, localpath, remotepath = None):
"""Copies a file between the local host and the remote host."""
if not remotepath:
remotepath = os.path.split(localpath)[1]
self._sftp_connect()
self._sftp.put(localpath, remotepath)
def execute(self, command):
"""Execute the given commands on a remote machine."""
channel = self._transport.open_session()
channel.exec_command(command)
output = channel.makefile('rb', -1).readlines()
if output:
return output
else:
return channel.makefile_stderr('rb', -1).readlines()
def close(self):
"""Closes the connection and cleans up."""
# Close SFTP Connection.
if self._sftp_live:
self._sftp.close()
self._sftp_live = False
# Close the SSH Transport.
if self._tranport_live:
self._transport.close()
self._tranport_live = False
def __del__(self):
"""Attempt to clean up if not explicitly closed."""
self.close()
def main():
"""Little test when called directly."""
# Set these to your own details.
myssh = Connection('example.com')
myssh.put('ssh.py')
myssh.close()
# start the ball rolling.
if __name__ == "__main__":
main()