Juju is revolutionizing the way web services are deployed in the cloud, taking what was either a labor-intensive manual task, or a very labor-intensive re-invention of the wheel (or deployment automation in this case), and distilling it into a collection of reusable components called “Charms” that let anybody deploy multiple inter-connected services in the cloud with ease.
There are currently 84 Juju charms written for everything from game backends to WordPress sites, with databases and cache servers that work with them. Charms are great when you can deploy the same service the same way, regardless of it’s intended use. Wordpress is a good use case, since the process of deploying WordPress is going to be the same from one blog to the next.
But when you go a little lower in the stack, to web frameworks, it’s not quite so simple. Take Django, for instance. While much of the process of deploying a Django service will be the same, there is going to be a lot that is specific to the project. A Django site can have any number of dependencies, both common additions like South and Celery, as well as many custom modules. It might use MySQL, or PostgreSQL, or Oracle (even SQLite for development and testing). Still more things will depend on the development process, while WordPress is available in a DEB package, or a tarball from the upstream site, a Django project may be anywhere, and most frequently in a source control branch specific to that project. All of this makes writing a single Django charm nearly impossible.
There have been some attempts at making a generic, reusable Django charm. Michael Nelson made one that uses Puppet and a custom config.yaml for each project. While this works, it has two drawbacks: 1) It requires Puppet, which isn’t natural for a Python project, and 2) It required so many options in the config.yaml that you still had to do a lot by hand to make it work. The first of these was done because ISD (where Michael was at the time) was using Puppet to deploy and configure their Django services, and could easily have been done another way. The second, however, is the necessary consequence of trying to make a reusable Django charm.
Just for Fun
Given the problems detailed above, and not liking the idea of making config options for every possible variation of a Django project, I recently took a different approach. Instead of making one Django Charm to rule them all, I wrote a small Django App that would generate a customized Charm for any given project. My goal is to gather enough information from the project and it’s environment to produce a charm that is very nearly complete for that project. I named this charming code “Naguine” after Django Reinhardt’s second wife, Sophie “Naguine” Ziegler. It seemed fitting, since this project would be charming Django webapps.
Naguine is very much a JFDI project, so it’s not highly architected or even internally consistent at this point, but with a little bit of hacking I was able to get a significant return. For starters, using Naguine is about as simple as can be, you simply install it on your PYTHONPATH and run:
python manage.py charm --settings naguine
The –settings naguine will inject the naguine django app into your INSTALLED_APPS, which makes the charm command available.
This Kind of Friend
The charm command makes use of your Django settings to learn about your other INSTALLED_APPS as well as your database settings. It will also look for a requirements.txt and setup.py, inspecting each to learn more about your project’s dependencies. From there it will try to locate system packages that will provide those dependencies and add them to the install hook in the Juju charm.
The charm command also looks to see if your project is currently in a bzr branch, and if it is it will use the remote branch to pull down your project’s code during the install. In the future I hope to also support git and hg deployments.
Finally the command will write hooks for linking to a database instance on another server, including running syncdb to create the tables for your models, adding a superuser account with a randomly generated password and, if you are using South, running any migration scripts as well. It also writes some metadata about your charm and a short README explaining how to use it.
All that is left for you to do is review the generated charm, manually add any dependencies Naguine couldn’t find a matching package for, and manually add any install or database initialization that is specific to your project. The amount of custom work needed to get a charm working is extremely minor, even for moderately complex projects.
Are you in the Mood
To try Naguine with your Django project, use the following steps:
- cd to your django project root (where your manage.py is)
- bzr branch lp:naguine
- python manage.py charm –settings naguine
That’s all you need. If your django project lives in a bzr branch, and if it normally uses settings.py, you should have a directory called ./charms/precise/ that contains an almost working Juju charm for your project.
I’ve only tested this on a few Django project, all of which followed the same general conventions when it came to development, so don’t be surprised if you run into problems. This is still a very early-stage project after all. But you already have the code (if you followed step #2 above), so you can poke around and try to get it working or working better for your project. Then submit your changes back to me on Launchpad, and I’ll merge them in. You can also find me on IRC (mhall119 on freenode) if you get stuck and I will help you get it working.
(For those who are interested, each of the headers in this post is the name of a Django Reinhardt song)