Software Engineer

cloudstack userdata into puppet facts

· by jsnby · Read in about 3 min · (444 Words)

Update 12/06/2011:

The facter code has been updated to support Fedora and to also load the instance-id of the VM from the metadata available on the virtual router. Grab the latest from GitHub.

I’ve been playing with a proof-of-concept CloudStack based cloud at work. One of the things that caught my eye was that you can associate userdata to an instance. What I wanted to do was exploit this and use the userdata to populate facts that I could then use in my Puppet manifests. What I want is to set the userdata to something like role=foo\nenv=development\n and have that populate the role and env facts. But I wanted it to be flexible, so if you set userdata to role=foo\nenv=development\nbar=blah\n it would also populate a fact called bar, etc.

Unfortunately, the current (v 2.2.12) CloudStack web interface doesn’t allow you to set the userdata when creating an instance (if it does I missed it), but you can set this data when calling deployVirtualMachine in the API. Since I wanted to build a simple web interface to launch VM’s as a demonstration to show my team, I started looking for a php CloudStack library. I stumbled on qpleple’s cloudstack-php-client. He’s using a parser to scrape the CloudStack docs to generate the code. One thing I didn’t like about it was that the methods in the generated code were using fixed position variables….if the docs got updated and new parameters added or old ones removed, then the signatures for the methods would all change and you would have to update your code.

I couldn’t have that, so I decided to fork his project and modify it to pass the parameters as an associative array. You can find my version of the code at github. All of that aside, here’s a snippet of code that launches a VM and sets some userdata:



$cloudstack = new CloudStackClient(

// Adjust these parameters as appropriate for your environment
$zone     = 2;
$template = 209;
$offering = 10;
$userdata = "role=foo\nenv=development\n";

$vm = $cloudstack->deployVirtualMachine(array(
    'serviceofferingid' => $offering,
    'templateid'        => $template,
    'zoneid'            => $zone,
    'userdata'          => base64_encode($userdata)

echo "created vm with id {$vm->id}\n";

In my case, template 209 is a CentOS 5.7 x86_64 box with puppet already installed, pluginsync enabled, and chkconfig’ed to start at boot. So, when puppet starts up the first time, we want it to poll the userdata and transform it into a set of facts. CloudStack exposes the userdata to the VMs via an http call to the virtual routers, so we need to craft some ruby code that determines the IP address of the virtual router, makes the http request, and parses it into a set of facts. I came up with cloudstack_userdata.rb. To use it, put it into any module in your modulepath in the /lib/facter directory. Make sure that pluginsync is enabled in puppet.conf on the client.