so.very.tired
so.very.tired

Reputation: 3086

Automate ssh connection and execution of program with Python's Paramiko

I want to automate a specific task using python.
This task includes, among some other things, connecting with ssh to a remote server, and running a specific program (call it prog.out) that may or may not ask for user input.
After some research and after weighting my options, I decided to use Python's Paramiko (which may turned out to be wrong, considering the below...).

Let's start with the easy possibility of prog.out not asking any input, but rather just prints some info to console:

int main(int argc, char* argv[]) {

        printf("Hey there, fella\n");
        printf("How are you this morning?\n");
        printf("See ya...\n");

        return 0;
}

which compiles to: prog.out, and sits on server_name, waiting to be executed.
So in that case:

client = paramiko.SSHClient()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
client.connect("server_name")
sin, sout, serr = client.exec_command('./prog.out')

for line in sout.readlines():
    print(line, end = '')

Will work perfectly fine, and will print out whatever prog.out produces.
But if instead prog.out is:

int main(int argc, char* argv[]) {

        printf("Hey there, fella\n");
        printf("How are you this morning?\n");
        printf("please enter an integer...\n");
        int a;
        scanf("%d", &a);
        printf("you entered %d\n", a);
        printf("see ya...\n");

        return 0;
}

then the above python code will block at sout.readlines() (waiting for eof?)...
The way to avoid blocking in sout.readlines() is to provide input to prog.out by writing to its stdin pipe:

client = paramiko.SSHClient()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
client.connect("server_name")
sin, sout, serr = client.exec_command('./prog.out')

sin.write('55\n')

for line in sout.readlines():
    print(line, end = '')

But I can't know in advance if prog.out will require user's input or not...
I am looking for a robust way to run prog.out and let the user interact with it for as long as necessary. Is there some indication when prog.out expects input?

EDIT

OK, I did a little experimenting, and found out that any attempt to read() from the channel will block, as long as prog.out has not exited, but prog.out can't exit as long as it wasn't provided with input...
How come I can't read bytes that were already sent by prog.out even when it is not finished yet?
I'd really love to simulate to the user as if he or she interacts directly with prog.out...

Upvotes: 2

Views: 3428

Answers (1)

e4c5
e4c5

Reputation: 53774

There is a library built on top of Paramiko that's perhaps better suited for your needs.

I am speaking of python fabric (of which I have no association)

Fabric is a Python (2.5-2.7) library and command-line tool for streamlining the use of SSH for application deployment or systems administration tasks.

It provides a basic suite of operations for executing local or remote shell commands (normally or via sudo) and uploading/downloading files, as well as auxiliary functionality such as prompting the running user for input, or aborting execution.

If I have understood your requirement correctly, your code might look something like this.

from fabric.api import run

@task
def run_a_out()
    run('echo "some input for a.out" | ./a.out')

And you would execute the remote program with

    fab --hosts=someserver run_a_out

If you wanted to dynamically controll what get's passed into a.out, you can add a parameter to run_a_out() and pass it from the command line.

In short Fabric provides a higher level API for paramiko with most of it's complexity hidden away.

Upvotes: 3

Related Questions