Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

execute local python script over sshClient() with Paramiko in remote machine

This is my first post in StackOverflow, so I hope to do it the right way! :)

I have this task to do for my new job that needs to connect to several servers and execute a python script in all of them. I'm not very familiar with servers (and just started using paramiko), so I apologize for any big mistakes!

The script I want to run on them modifies the authorized_keys file but to start, I'm trying it with only one server and not yet using the aforementioned script (I don't want to make a mistake and block the server in my first task!). I'm just trying to list the directory in the remote machine with a very simple function called getDir(). So far, I've been able to connect to the server with paramiko using the basics (I'm using pdb to debug the script by the way):

try_paramiko.py

#!/usr/bin/python

import paramiko
from getDir import get_dir
import pdb


def try_this(server):
    pdb.set_trace()
    ssh = paramiko.SSHClient()
    ssh.load_host_keys("pth/to/known_hosts")
    ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
    my_key = paramiko.RSAKey.from_private_key_file("pth/to/id_rsa")
    ssh.connect(server, username = "root", pkey = my_key)
    i, o, e = ssh.exec_command(getDir())

This is the function to get the directory list:

getDir.py

#!/usr/bin/python

import os
import pdb


def get_dir():
    pdb.set_trace()
    print "Current dir list is:"
    for item in os.listdir(os.getcwd()):
        print item

While debugging I got the directory list of my local machine instead of the one from the remote machine... is there a way to pass a python function as a parameter through paramiko? I would like to just have the script locally and run it remotely like when you do it with a bash file from ssh with:

ssh -i pth/to/key [email protected] 'bash -s' < script.sh

so to actually avoid to copy the python script to every machine and then run it from them (I guess with the above command the script would also be copied to the remote machine and then deleted, right?) Is there a way to do that with paramiko.sshClient()?

I have also tried to modify the code and use the standard output of the channel that creates exec_command to list the directory leaving the scripts like:

try_paramiko.py

#!/usr/bin/python

import paramiko
from getDir import get_dir
import pdb


def try_this(server):
    pdb.set_trace()
    ssh = paramiko.SSHClient()
    ssh.load_host_keys("pth/to/known_hosts")
    ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
    my_key = paramiko.RSAKey.from_private_key_file("pth/to/id_rsa")
    ssh.connect(server, username = "root", pkey = my_key)
    i, o, e = ssh.exec_command(getDir())
    for line in o.readlines():
        print line
    for line in e.readlines():
        print line    

getDir.py

def get_dir():
    return ', '.join(os.listdir(os.getcwd()))

But with this, it actually tries to run the local directory list as commands (which actually makes sense they way I have it). I had to convert the list to a string because I was having a TypeError saying that it expects a string or a read-only character buffer, not a list... I know this was a desperate attempt to pass the function... Does anyone know how I could do such thing (pass a local function through paramiko to execute it on a remote machine)? If you have any corrections or tips on the code, they are very much welcome (actually, any kind of help would be very much appreciated!).

Thanks a lot in advance! :)

like image 398
eberbis Avatar asked Nov 02 '12 19:11

eberbis


2 Answers

You cannot just execute python function through ssh. ssh is just a tunnel with your code on one side (client) and shell on another (server). You should execute shell commands on remote side.

If using raw ssh code is not critical, i suggest fabric as library for writing administration tools. It contains tools for easy ssh handling, file transferring, sudo, parallel execution and other.

like image 137
mechmind Avatar answered Oct 06 '22 01:10

mechmind


I think you might want change the paramaters you're passing into ssh.exec_command Here's an idea:

Instead of doing:

def get_dir():
    return ', '.join(os.listdir(os.getcwd()))

i, o, e = ssh.exec_command(getDir())

You might want to try:

i, o, e = ssh.exec_command('pwd')
o.printlines()

And other things to explore:

  • Writing a bash script or a Python that lives on your servers. You can use Paramiko to log onto the server and executing the script with ssh.exec_command(some_script.sh) or ssh.exec_command(some_script.py)
  • Paramiko has some FTP/SFTP utilities so you can actually use it to put the script on the server and then execute it.
like image 45
Stephen Avatar answered Oct 06 '22 01:10

Stephen