avi
avi

Reputation: 1846

can't make ssh connection via python

I followed this question I have this function in PostgreSQL:

CREATE OR REPLACE FUNCTION a()
  RETURNS void AS
$BODY$
import subprocess
cmd1 = "usr/bin/ssh [email protected] time"
out1, err1 = subprocess.Popen(cmd1,
                              stdout=subprocess.PIPE,
                              stderr=subprocess.PIPE).communicate()
plpy.notice(out1)
$BODY$
  LANGUAGE plpythonu VOLATILE

This should login to the server specified and display its time. No matter what I do I always get :

ERROR: OSError: [Errno 2] No such file or directory

The only time I don't get the error is if cmd1 = "usr/bin/ssh" but then it does nothing.

How can I make it work?

Upvotes: 0

Views: 152

Answers (1)

Torxed
Torxed

Reputation: 23480

The problem you're facing is that Popen() assumes the command to be a list of command+arguments.

There for, cmd1 should look more like:

cmd1 = ['/usr/bin/ssh', '[email protected]', 'time']

(unless dangerously supplying shell=True, then you can keep your command string as is).

You can also use:

import shlex
cmd1 = shlex.split("/usr/bin/ssh [email protected] time")

This is also covered under the docs for Popen().

Last notes: I've never used plpythonu or this SQL version of code execution, but I'd assume that you would want to specify the full path for SSH as Lix pointed out, that being /usr/bin/ssh and not usr/bin/ssh. But your main problem is how you pass the arguments to Popen().

Don't forget to allow SSH to login with a key, otherwise the command might hang asking for a password in the background.

Seeing as many people have issues running system commands that hangs without the programmer understanding why, try the following modification to get output as the command is executed instead of at the end (.communicate() will wait for EOL, meaning hang forever if the process never quits):

CREATE OR REPLACE FUNCTION a()
  RETURNS void AS
$BODY$
import subprocess
cmd1 = ["usr/bin/ssh", "[email protected]", "time"]
process = subprocess.Popen(cmd1,
                              stdout=subprocess.PIPE,
                              stderr=subprocess.STDOUT).communicate()
while process.poll() is None:
    plpy.notice(process.stdout.readline())
$BODY$
  LANGUAGE plpythonu VOLATILE

It's still highly inefficient since i fused STDERR and STDOUT together and using readline() instead of read(). Also import select might be useful here.

But this will give you output "live" from the command instead of bunkered up at the end. It should also print any errors that the command is throwing (but still hanging because the error didn't close the application properly).

This is a common mistake and people aught to read the examples/docs more on this.

Upvotes: 1

Related Questions