juan reyero ←

Remotex, a Python library for remote execution

Remotex is a very simple Python module for executing functions remotely. It is convenient when you need a copy of your module running as a background process and keeping state for ephemeral instances of it.

I have used it for phototag, a Python program for geo- and time-tagging photos: it implements a server that runs on the background, and when requested loads a GPS track, shows it in Google Earth, and answers location queries with the point in the track that is closest to the center of the Google Earth screen.

Example: the frame of a bulletin board

Below is the code for the server of a billeting board. It has a NewsItem class that takes care of printing news, and a BBoard class that implements the bulletin board.

#!/usr/bin/env python

from remotex import Remotex, remote
from datetime import datetime
from socket import gethostname

class NewsItem(object):
    def __init__(self, item, by):
        self.item = item
        self.by = by
        self.when = datetime.utcnow().replace(microsecond=0)

    def __str__(self):
        now = datetime.utcnow().replace(microsecond=0)
        return "From %s, %s ago: %s" % (self.by, 
                                        now-self.when,
                                        self.item)

class BBoard(object):
    server = Remotex(gethostname())
    news = []

    @classmethod
    @remote(server)
    def post(klass, item, by=''):
        klass.news.append(NewsItem(item, by))

    @classmethod
    @remote(server)
    def read(klass):
        return klass.news

if __name__ == '__main__':
    BBoard().server.listen()

BBoard has two class attributes: a Remotex server that takes care of the socket connections, and a list of news that will remain in memory for as long as the server is running, providing state permanence. It has two methods: post for adding new items to the list, and read for reading the list.

Both methods have been decorated with @remote(server). This will ensure that, when imported and run from the client, instead of actually executing the method the client will establish a connection with the server, who will do the execution and return the result.

The @classmethod decorators ensure that the news class attribute in the server is used, instead of the one in the client instance. When an @remote decorated function is run on the client all its parameters are pickled and sent to the server; if it were not a class method, the self of the client instance would also be sent, together with the value of news in the client, and the news in the server would not be accessible.

This is how the client looks like:

#!/usr/bin/env python

import sys
from socket import gethostname
from bboardServer import BBoard, NewsItem

bb = BBoard()

if len(sys.argv) > 1:
    bb.post(item=sys.argv[1], by=gethostname())
else:
    news = bb.read()
    if news['success']:
        for item in news['return']:
            print str(item)
    else:
        print "** Error:", news['return']

Note that it does almost nothing: just call read or post in a BBoard object.

Security

Remotex is not secure. An attacker could exploit the fact that the server unpickles the parameters sent to the @remote decorated functions.

Download

It is hosted at Github. Either clone it with git:

git://github.com/juanre/remotex.git

or download the package.

Installation

In the remotex directory,

sudo python setup.py install
Juan Reyero Barcelona, 2009-12-08
 

blog comments powered by Disqus