Paramiko equvalent of pipline controls and input/output pipes - python

I need a method of paramiko based file transfer with a lightweight SSH2 server (dropbear) which has no support for SCP or SFTP. Is there a way of achieving a cat and redirect style file transfer, such as:
ssh server "cat remote_file" > local_file
with paramiko channels?
Can paramiko.Transport.open_channel() or Message() do the job? I am unsure of how to proceed.

If the limitation, as you say, is only in your client, you can easily implement a SFTP client directly with paramiko -- e.g., look at this example code.

pyfilesystem implements an sftp filesystem on top of paramiko.

Related

Paramiko SFTP file renaming: OSError('Extended request not supported.')

I can't find anything about this exception. I am trying to rename a remote file on a local (Windows) SFTP server with fsspec. Paramiko behind the scenes is doing a posix_rename(). What does the error mean?
fs.rename(old_file_path, new_file_path)
Paths look like /folder/file.ext.
I can rename files with other FTP clients on that same server.
Indeed, fsspec SFTPFileSystem.mv calls Paramiko SFTPClient.posix_rename. That's imo a bad choice. The SFTPClient.posix_rename internally uses a proprietary OpenSSH posix-rename#openssh.com extension, which is naturally not supported by most other SFTP servers (such as yours).
I do not know what is the best solution/workaround. You can probably add your own "file system" implementation based on SFTPFileSystem, reimplementing SFTPFileSystem.mv to call standard Paramiko SFTPClient.rename (which uses standard SFTP rename request).
Actually, I just found that the SFTPClient is exposed through the SFTPFileSystem and I can call rename() on it directly, which worked!
fs.ftp.rename("testfile.txt", "x")

Paramiko session scope

I have some doubts about Paramiko. If I do the standard code found in internet:
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(hostname='remote_host', username='...', password='...')
// TODO
ssh.close()
Let's say I have some kind of JDBC connector and I try to connect to a database placing the code below within the TODO section
ssh.connect(hostname='remote_host', username='...', password='...')
connector.connect(database_params...)
ssh.close()
My question is. In that case the client of the database server would be remote_host or my local machine where the Python script is being executed?
Or the right way would be using sshtunnel? like so:
with open_tunnel(
('remote_host', '22'),
ssh_username=...,
ssh_password=...,
remote_bind_address=('DB_ADDRESS', 'DB_PORT')
local_bind_address=('SOME_IP', 'SOME_PORT')
) as server:
connector.connect(db_host='SOME_IP', db_port='SOME_PORT', ...)
Is there any difference between those two approaches?
Thanks in advance.
Opening SSH connection using Paramiko or any other way, has no effect whatsoever on your database connection, nor any other connections, nor a file access, nor command execution. So your first code has no chance of doing, what you want.
Everything you want to do via the SSH connection, you need to do via the Paramiko API.
And that's what open_tunnel does, internally.
For an equivalent standalone code, see forward_tunnel function in Paramiko forward.py demo.

Uploading a file from an SSH server with python (alternative to PyAutoIt)

I found a small script that can select data in the explorere to upload it using PyAutoIt. The script looks like this:
autoit.win_active("Open")
sleep(2)
autoit.control_send("Open","Edit1",data_path)
sleep(1.5)
autoit.control_send("Open","Edit1","{ENTER}")
I want to do the same thing, but from my Debian GNU/Linux SSH server. The problem is that PyAutoIt only works for windows. Are there any well documented alternatives out there that I could use to preform the same actions?
You could use native python and scp
import subprocess
# Use subprocess to run 'scp' take FILE and pass it to the ssh host
subprocess.run(["scp", FILE, "USER#SERVER:PATH"])
#e.g. subprocess.run(["scp", "somefile.txt", "john#doe.org:/path/to/somefile.txt"])
Note that you have to generate an ssh key so that scp automatically gets authenticated - that way you will not be asked to provide the password.
Alternatively you could probably do (I have not tested this)
import subprocess
# Use subprocess to run 'scp' take FILE and pass it to the ssh host
subprocess.run(["scp", FILE, "USER:PASSWORD#SERVER:PATH"])
#e.g. subprocess.run(["scp", "somefile.txt", "john:secretpassword#<IPADDRESSorDNSNAME>:/path/to/somefile.txt"])

Using ssh_config file with Paramiko

I need to connect to a server with SSH to download files. I have Ubuntu and I've set up SSH in the standard way: I have a ssh_config file in .ssh which defines a host entry (say host_key) for the server address (Hostname.com) and username, and I've set up an RSA key. So when I try to log into SSH from the command line or bash, I just need to use ssh host_key
I would like to do this in Python. The standard solutions seems to be to use Paramiko to set up the connection. I tried this:
from paramiko import SSHClient
from scp import SCPClient
ssh = SSHClient()
ssh.load_system_host_keys()
ssh.connect('host_key')
scp = SCPClient(ssh.get_transport())
# etc...
However, it always seems to hang and time out on ssh.connect('host_key'). Even when I try to include the username and password: ssh.connect('host_key', username='usrnm', password='pswd').
Are my host keys not loading properly? And would this take care of the RSA keys as well?
It only works if I use the whole Hostname.com with username and typed-out password. Which is maybe a bit insecure.
Since paramiko has a SSHConfig class, you can use it for your ~/.ssh/config.
However, it is slightly messy, I recommend you to use fabric instead of that.
Here is the code example:
from fabric.api import put
put('local path', 'remote path')
I do not think that it is common to use ssh_config file with Paramiko (or any other code/language). ssh_config is a configuration file for OpenSSH tools, not for SSH in general.
Usually, you specify your private key directly in your code as an argument of SSHClient.connect method:
How to access to a remote server using Paramiko with a public key-file
If you want to keep using ssh_config, Paramiko can parse it. Check parse_ssh_config and lookup_ssh_host_config functions. But I believe, you still have to look up the key file from the config and pass it explicitly to SSHClient.connect method.

Client to Server Remote Function Calls in Python. How to implement?

I'm trying to set up a simple client to server interface for calling functions/programs on the server. A client will send a simple command to the server listening for such commands. Once the server receives a command from the client it will execute the following function or program on the server. I have looked into a simple TCP server receiving a text string and parsing that string then executing the a function or external program. I have read into using XML-RPC implemented with a twisted server as well.
What I'm asking is which would be the easiest to set up or are there any other ways to easily do this task?
Thanks.
There is a great tutorial for twisted that will do just fine as a teaching tool (and guide you by hand in writing a basic server/client services). Have a go at it http://twistedmatrix.com/documents/current/core/howto/tutorial/ what you will probably want to do is parse received info and act accordingly.
If it is appliable in your case, maybe you can use full-featured system for async/remote job execution like Celery?
There are more than one way to achieve your requirement ach with some pros and cons:
Python Low Level Sockets
Using Standard python socket libraries and cliet server architecture
Connecting to Server via protocols like Telnet/SSh and then triggering some code.
Using Python libraries like Telnet/ssh or Subprocess.
XML-RPC
Sending a XMP RPC request as described here http://docs.python.org/2/library/xmlrpclib.html
In my opinion easiest method to achieve remote method triggering is via Python Subprocess Module. I generally use following kind of syntax for my general purposes.
import subprocess
ret = subprocess.call(["ssh", "user#host", "program"]);
# or, with stderr:
prog = subprocess.Popen(["ssh", "user#host", "program"], stderr=subprocess.PIPE)
errdata = prog.communicate()[1]
Hope it helps

Categories