1

I'm writing a script that needs to take advantage of a Java daemon via the local dbus of the linux machines it will run on. This daemon in particular will return an array of tuples which I want so that I can parse through/use the information in later in my code. I want this code to take this value from multiple machines at once, but the problem is the only way I see to really take return/exit values from a terminal which I am ssh'ed into is by parsing stdout's output. I don't want to do this, I'd much prefer to get the actual variable. Right now I have this:

import os
message = "import dbus, sys\nbus=dbus.SystemBus()\nremote_object=bus.get_object('daemon.location', '/daemon')\ncontroller=dbus.Interface(remote_object, 'daemon.path')\nsys.exit(controller.getValue())"
x = os.system('echo \-e "%s" \| ssh %s python' %(message, ip))

In this example when I run "controller.getValue()" it returns an array of tuples. I'm trying to figure out a way to get that array. When using something like popen it pipes the output in stdout into a file and returns it to you, that way you get a string equivalent of the array. What I'm trying to figure out is how to get the actual array. As if to pass the variable returned when exiting the ssh tty into my code. Any ideas?

SuperFamousGuy
  • 1,455
  • 11
  • 16

3 Answers3

1

You can't avoid serialization if there is no shared memory. There are only bytes on the wire. You could use a library that hides it from you e.g., with execnet module:

#!/usr/bin/env python
import execnet

gw = execnet.makegateway("ssh=user@host")
channel = gw.remote_exec("""
import dbus, sys

bus = dbus.SystemBus()
remote_object = bus.get_object('daemon.location', '/daemon')
controller = dbus.Interface(remote_object, 'daemon.path')

channel.send(controller.getValue())
""")
tuple_ = channel.receive()
print tuple_
print tuple_[0]

But it easy to parse simple tuple values yourself using ast.literal_eval() from stdlib:

#fabfile.py
import ast
from fabric.api import run

def getcontroller():
    """Return controller value."""
    cmd = """
import dbus, sys

bus = dbus.SystemBus()
remote_object = bus.get_object('daemon.location', '/daemon')
controller = dbus.Interface(remote_object, 'daemon.path')

print repr(controller.getValue())
""" #NOTE: you must escape all quotation marks
    output = run('python -c "%s"' % cmd)
    tuple_ = ast.literal_eval(output)
    print tuple_[0]

Example: $ fab getcontroller -H user@host

Here I've used fabric to run the command on remote host.

You could use JSON as a serialization format if the other end doesn't produce Python literals:

>>> import json
>>> t = (1, "a")
>>> json.dumps(t)
'[1, "a"]'
>>> json.loads(_)
[1, u'a']
>>>
jfs
  • 399,953
  • 195
  • 994
  • 1,670
0

Why not use popen?

lines = os.popen("your command here").readlines()
Richie
  • 535
  • 3
  • 3
  • This does what I was saying I was trying to avoid. It parses the output of stdout in your tty. os.popen pipes the value of stdout into a file object which it returns to you. I'm trying to actually get the variable my daemon returns. – SuperFamousGuy Oct 11 '11 at 19:20
  • Since there are several processes and machines involved this maybe a bit tricky. Since each process will return status to its parent and the parent would have to pass it back up. Why is parsing the output of popen so bad? – Richie Oct 11 '11 at 19:39
  • Becasue it degrades efficiency from potential O(1) worst case scenario O(log(n)) to O(n). It's not the worst thing in the world. I was just wondering if there was a better way. It seems like one of those things that should be possible but I've got no idea how to do it. – SuperFamousGuy Oct 11 '11 at 19:48
  • 1
    @Richie `os.popen` is [deprecated](http://docs.python.org/library/os.html#os.popen) since 2.6. You should use `subprocess` instead. – Ben Oct 11 '11 at 20:33
  • `output = subprocess.check_output(["ssh"]+args)` – jfs Oct 11 '11 at 21:40
0

If you just want a shell variable then you could do this

$ FOO="myFOO"
$ export FOO
$ cat x.py
#!/usr/bin/python
import os
print os.environ['FOO']
$ ./x.py
myFOO
$ 

If you want the return code of a program:

try:
    retcode = call("mycmd" + " myarg", shell=True)
    if retcode < 0:
        print >>sys.stderr, "Child was terminated by signal", -retcode
    else:
        print >>sys.stderr, "Child returned", retcode
except OSError, e:
    print >>sys.stderr, "Execution failed:", e

If you could probably explain you requirement a little better, you might get better help

Lelouch Lamperouge
  • 8,171
  • 8
  • 49
  • 60
  • Sorry if I was a bit vague, I edited my post to try to be more clear. It seems like your code is either running it in the shell, or parsing shell output into a variable. I'm trying to do sort of the opposite, in that I'm trying to take a variable (in this case an array) from the shell. – SuperFamousGuy Oct 11 '11 at 20:07