Wednesday, 2 April 2008

Calling Python from Perl

After a long silence this is definitely worth an entry - the Perl Inline module for calling code in various other languages from Perl...

I've been looking into integrating NERC DataGrid Security (all written in Python) into the existing BADC web site Perl CGI code - quick dirty if necessary.

The NDG Security Single Sign On service has a http interface so this should be straightforward - Perl on one side of the interface and Python the other. However the various SOAP interfaces with WS-Security added into the mix doesn't make it very attractive. I've not looked into Perl SOAP support - and this may be great - but if we are migrating all our Perl code to Python it would seem a wasted effort.
Inline is really impressive. I had a python client call to the NDG Attribute Authority working in minutes - Perl calling Python calling a SOAP Service and returning the response back to Perl as a local variable:

Perl <-> Python <-> SOAP + WS-Security <-> Python Attribute Authority Web service

Installation was fairly straightforward on Ubuntu - libinline-perl package is available but Inline-Python required downloaded and install from CPAN.

I was expecting all kinds of shared library link errors but all works perfectly. It's nice when things work simply easily and quickly for a change :)


#!/usr/bin/env perl
use Inline Python => <<'END';
def getAAHostsInfo():
    from ndg.security.common.AttAuthority import AttAuthorityClient
    import os

    aaClnt = AttAuthorityClient(uri="http://localhost:5000/AttributeAuthority",
                                cfgFilePath='wssecurity.cfg')

    allHostsInfo = aaClnt.getAllHostsInfo()
    return "All hosts info = %s" % allHostsInfo
END

print getAAHostsInfo(), "\n";

Adapting Python setuptools to Execute Post-installation Steps

I've been experimenting with the Python setuptools package for sometime now to enable customisations for the NERC DataGrid Security installation (eggifying the Python OpenSSL package M2Crypto).  For NDG Security, a wrapper script ndg-security-install.py to easy_install allows for a custom M2Crypto build and for the fact that at the time the Python Twisted package was not available as an egg.

I now want to make the installation easier still. There's a config directory for the server egg that needs to be set-up post egg install. This a manual process but I've now incorporated this step into ndg-security-install.py. A copy is made of the ndg.security.server.conf package from the egg to a separate location - default is /etc/ndg/security/conf

To do this I need to know how to get a handle on the directory path ndg.security.server.conf contained in the latest egg. Digging into the setuptools pkg_resources package this turns out to be easy:


eggConfigDir = pkg_resources.resource_filename('ndg.security.server', 
'conf')



... but I then wanted some capability to avoid trashing a pre-existing conf/ from a previous installation. I've done this by installing the new conf/ with a suffix corresponding to the latest NDG Security server egg version. To get the version:


# Get distribution version info
serverDistro = pkg_resources.get_distribution('ndg-security-server')
configDirVers = "%s.%s" % (self.opt.configDir, serverDistro.version)


but when tested I noticed that it was picking up the wrong version - the version of the LAST install not the NEW one from the update. Moving my pkg_resources import to immediately BEFORE the version check fixed this!! ...


import pkg_resources
eggConfigDir = pkg_resources.resource_filename('ndg.security.server', 
'conf')
# Get distribution version info
serverDistro = pkg_resources.get_distribution('ndg-security-server')
configDirVers = "%s.%s" % (self.opt.configDir, serverDistro.version)
# Get distribution version info
serverDistro = pkg_resources.get_distribution('ndg-security-server')
configDirVers = "%s.%s" % (self.opt.configDir, serverDistro.version)


Previously I had my import at the top of the file. pkg_resources must check for the current egg version at import. The code to install the updated packages occurs of course at a later point in the execution.