Fun with mod_macro and django

At work we yestoday decided to update our internal url structure for our client test sites, issue management systems and such arround a bit. Seeing as we decided on purchasing a genuine signed ssl wildcard certificate, we needed to change our url’s a bit.

We used to have a url schema consisting of the following components:

    [dev.|test.]<project-name>.<client-name>.companyname.tld

That made for very long url’s, and furthermore, the url’s would not be supported by a *.companyname.tld. Based on this infomation, and wanting to create a more generelized, nicer url schema, we choose to cross over to the following schema:

   [dev-|test-]<project-name>.companyname.tld

Which besides from supporting a wildcard ssl certificate just fine, just, well, looks nicer.

Either way, me beeing in charge of the contents in /etc/, and getting a little sick of growing apache configuration files, I chooose to write some macros to configure our project sites.

We generally have 2 types of project sites. django based sites, and PHP based sites.

A typical django apache configuration consists of a VirtualHost and some mod_python settings inside a Location block. Lot’s of configuration, very little actual diffrence between the configration projects in between.

An example of a django based application running inside a apache VirtualHost, could look like this:

    <VirtualHost *:80>
        ServerName test-project.company.tld
        <Location />
            SetHandler python-program
            PythonHandler django.core.handlers.modpython
            PythonPath "['/path/to/project', '/other/path/to/inject']"
            SetEnv DJANGO_SETTINGS_MODULE project.settings
        </Location>
        <Location /media/>
            SetHandler none
        </Location>
        Alias /media/admin/ /path/to/django/contrib/admin/media/
        Alias /media/ /path/to/project/media/
    </VirtualHost>

And the on top of that comes SSL configuration, auth and such. 25 lines of configuration per django site. Now, I really wanted to acomplish two things.

  • Make the configuration easier to maintain
  • Enable other users to setup sites without knowing the depths of django and mod_python

Now, apache configuration, meet mod_macro. The solution to my problem was very simple. Create a macro that handles all the django configuration, given 4 parameters. A server name (i.e. the url), the parent directory of the django site and the module name of the site.

So i started building my macro.

    <Macro DjangoSite $servername $root $module>
        <VirtualHost *:80>
            ServerName $servername
            <Location />
                SetHandler python-program
                PythonHandler django.core.handlers.modpython
                PythonPath "['/common/path/to/inject', '$root']"
                SetEnv DJANGO_SETTINGS_MODULE $modulename.settings
            </Location>
            <Location /media/>
                SetHandler none
            </Location>
            Alias /media/admin/ /path/to/django/contrib/admin/media/
            Alias /media/ $root/$module/media/
        </VirtualHost>
    </Macro>

mod_macro is really simple, it will do a longest-match search and replace on the macro’s content. So, if we had a django site in /path/to/djangosite/testsite/ the above macro could be used as:

    Use DjangoSite www.example.org /path/to/djangosite/ testsite

Which would expand to:

    <VirtualHost *:80>
        ServerName www.example.org
        <Location />
            SetHandler python-program
            PythonHandler django.core.handlers.modpython
            PythonPath "['/common/path/to/inject', '/path/to/djangosite/']"
            SetEnv DJANGO_SETTINGS_MODULE testsite.settings
        </Location>
        <Location /media/>
            SetHandler none
        </Location>
        Alias /media/admin/ /path/to/django/contrib/admin/media/
        Alias /media/ /path/to/djangosite/testsite/media/
    </VirtualHost>

Hope you find this infomation a little useful. I actually like looking at our apache configuration file now.