Main menu

Storing data in Aegir

5 April 2011

Aegir is a very clever Drupal hosting system built using Drupal and Drush. It is divided into two parts: the frontend and the backend. The frontend is essentially just a standard Drupal site that stores its data in the database and then some drush scripts that manipulate the data. The backend (provision) is just a collection of drush scripts, and it stores its data in Aegir contexts which are essentially just arrays of data stored in text files on disk. One of the most mysterious processes in Aegir is sending data from the frontend to the backend to be stored in these contexts. Recently I cracked this mystery, and I'm going to explain how.

The problem

I wanted to add a couple of simple lines to the auto-generated settings.php and virtual host files, these needed to be based on a value defined in the frontend, and stored against particular sites. I imagine this is probably quite a frequent requirement.

Mig5 has written a tutorial that does something similar to this, but the settings are lost whenever the backend does something on its own, such as migrating or cloning a site. This is because the approach that mig5 took relies on the frontend telling the backend the particular options every time a command is run on the backend, and if the backend triggers a command all by itself, the frontend isn't going to be able let it know the extra data in the options. This happens everytime a clone or migrate happens.

Contexts and services

If I can get my data into a provison context, then I'll be able to access it any time a settings.php or vhost file is being written, and I can add the extra lines I want. There is one and only one way to ensure that additional data is stored in a provison context file: services.

A service in Aegir is a couple of classes that essentially define some resource on a server, like a HTTP server, or DB server. Services are tied to servers, which means that Aegir makes it really easy to say which of your servers have particular services available, and then it makes it easy to use those services when working with sites in the backend, for example, it's quite easy when creating a new site to ask the DB service to create a new database for the site.

Back to front

When writing a service from scratch its much easier to start in the backend, then write the frontend component, though obviously some tweaking will occur in both at the same time.

My service is going to be very simple indeed, and I'm going to call it the 'subfolder' service, and it's not even going to have an implementation, but that won't stop me from using it to store the data.

I started by adding a folder: .drush/provision/subfolder to hold the code for my service. These path names are hard coded in Aegir at the moment, so it's not the easiest to extend modularly unfortunately. The real meat of the backend code is stored in .drush/provision/subfolder/subfolder.drush.inc:

/** * @file * The subfolder provision service. */

include_once(dirname(__FILE__) . '/../provision.service.inc');

/** * Expose the service type this extension defines to provision. * * @return * An array with the service type the key, and the default implementation the value. */function subfolder_provision_services() { return array('subfolder' => NULL);}

subfolder_provision_services() just declares the service type to provision, and then there's a very simple class that defines the service type itself. The important bit here is the static method: subscribe_site(), this method is called when provision is initialising a site context and we call the setProperty method on the $context object, passing in a value of subfolder_path. This is the key line, this means that if we send the subfolder_path option from the frontend to the backend, instead of it disappearing into oblivion it will get saved into the file the context is stored in.

Now I just need to use the data in the context, to get the correct lines in the settings.php and the vhost file, so to the same file, I added the following:

You can see here that I'm able to access the property on the context by just doing d()->subfolder_path, nice!

The frontend

I now need a simple Drupal module in the frontend, my cm_subfolders.info file just contains:

name = Hosting subfoldersdescription = A hacky way to get sites to use subfolders.package = Hostingdependencies[] = hostingcore = 6.x

Because my service is so simple, I don't even need to surface it to the frontend in Aegir, so my cm_subfolders.module just contains the code to the load and store the subfolder path from the variable table. Note that you should store data in your own database tables really, and not put random stuff in the variables table, but to cut down on the amount of code, that's what I've gone for here.

The first hook just sends the 'subfolder_path' property of the site node to the backend in the 'subfolder_path' context option, this will then get stored by the service that I created earlier in the backend.

The second hook is there because when you are cloning a site, the Aegir backend sends the provision context to the frontend to be imported to the site node, so this hook just looks for our property and sets it on the site node.

Note that these are module hooks, but they are only ever invoked when running a drush command, so they are safe to put in a drush include.

Conclusion

That's it! The data will get stored in the frontend, in the variable table in my case, passed to the backend, and stored by the service in the provison context. Other scripts can now use the data I've stored to build things like the settings.php. Genius! This is how you must store data in the backend for your drush scripts that need it.

All the above code is available from github to save you from copy/pasting.

About the author

Steven has a wealth of experience building Drupal-based websites and tools associated with them. He is a maintainer of the Aegir project and has contributed to many other projects on Drupal.org. He is currently our infrastructure lead and is a lead architect on many of our projects.

He is a Master of Mathematics graduate from the University of Warwick and got involved in Drupal creating a website for the Maths society there.