tags:

views:

1387

answers:

4

I need to launch a server on the remote machine and retrieve the port number that the server process is lsitening on. When invoked, the server will listen on a random port and output the port number on stderr.

I want to automate the process of logging on to the remote machine, launching the process, and retrieving the port number. I wrote a Python script called "invokejob.py" that lives on the remote machine to act as a wrapper that invokes the job and then returns the port number, it looks like this:

import re, subprocess
executable = ... # Name of executable
regex = ... # Regex to extract the port number from the output
p = subprocess.Popen(executable,
    bufsize=1, # line buffered
    stderr=subprocess.PIPE
    )
s = p.stderr.readline()
port = re.match(regex).groups()[0]
print port

If I log in interactively, this script works:

$ ssh remotehost.example.com
Last login: Thu Aug 28 17:31:18 2008 from localhost
$ ./invokejob.py
63409
$ exit
logout
Connection to remotehost.example.com closed.

(Note: successful logout, it did not hang).

However, if I try to invoke it from the command-line, it just hangs:

$ ssh remotehost.example.com invokejob.py

Does anybody know why it hangs in the second case, and what I can do to avoid this?

Note that I need to retrieve the output of the program, so I can't just use the ssh "-f" flag or redirect standard output.

+2  A: 
s = p.stderr.readline()

I suspect it's the above line. When you invoke a command directly through ssh, you don't get your full pty (assuming Linux), and thus no stderr to read from.

When you log in interactively, stdin, stdout, and stderr are set up for you, and so your script works.

Ben Collins
it is possible to get full pty when running a command through SSH, or is interacting with stdin on a running process through SSH impossible?
cdated
A: 

what if you do the following:

ssh <remote host> '<your command> ;<your regexp using awk or something>'

For example

ssh <remote host> '<your program>; ps aux | awk \'/root/ {print $2}\''

This will connect to , execute and then print each PSID for any user root or any process with root in it's description.

I have used this method for running all kinds of commands on remote machines. The catch is to wrap the command(s) you wish to execute in single quotation marks (') and to separate each command with a semi-colon (;).

Misha M
A: 

@Ben Collins

I think you're right about stderr being an issue. I am pretty sure it's blocking on the readline() call.

In the end, I gave up and decided to use the pxssh module from pexpect to automate my interaction with an ssh session.

@Misha M

Unfortunately, the semi-colon trick doesn't work here: it blocks on executing my program.

lorin
A: 

Misha, it's definitely a problem with the line:

s = sys.stderr.readline()

This line doesn't make any sense: stderr is an output stream, not an input stream. Get rid of that line and it should be fine. You aren't using the result of that line ... the result should be None anyway.

Dan