Proxmoxia is a simple python library which wraps operations with Proxmox.
Proxmox is an open source server virtualization platform which allows you to create and manage any number of virtual machines based on either KVM or OpenVZ.
At Baseblack we utilise Proxmox to provide us with the majority of our central infrastructure. For example we run a pair of DNS servers, an almost countless number of license servers and farm manager all as openvz containers. Doing this provides us with a far higher level of service since if any one of our virtualization nodes go down we can quickly and pretty painlessly re-start the downed services on one of the other nodes whilst we work outs whats happening.
An area of active development for us is the automation of builds of new software packages for deployment onto our workstations, render nodes and virtual hosts.
This is where Proxmoxia comes in.
Until recently anytime we’ve needed to spin up a new virtual server, we’ve needed to login to the web interface and manually create a new instance. Not only is this tedious and time consuming, but it can also lead to the occasional mistake.
We knew that our plans for automated builds, and testing of packages would involve us spinning up more and more sacrificial virtual machines which we could use as testing/build bots, each being discarded once they had completed their assigned tasks.
Clone or fork from my github account:
After a short burst of ‘Spanish Flea’ our preferred google search background music we found that the majority of the existing implementations of wrappers for the rest API had been in languages we either weren’t keen on or flat out refused to use.
Perl, Java, PHP need not apply
Unfortunately I didn’t come across PyProxmox (a major omission of mine) until I’d already spent the better part of a day planning on how to make proxmoxia. And by then I well and truly had the bit between my teeth.
I wanted to create a library which followed a few simple rules:
- It should ‘feel’ pythonic.
- I wanted the wrapper to extend itself. Or in a few more words; I didn’t want to have to personally write wrapper functions for each and every endpoint and method combination which are currently exposed in the rest api.
Personally I don’t like PyProxmox’s implementation for both of these reasons which is why I feel justified in completing Proxmoxia.
We’re going to be using the library as part of our testing suite, creating new VMs off of the back of Jenkins builds. Hopefully it’s going to work out to be really useful.
Finally Some Examples
Okay, so here are some examples to show what I’m talking about. Head over to the github site for the source for these.
First up, Proxmox uses a token based authentication mechanism which must be attached to the headers of each request.
Connect to any node in the cluster and get the auth_token:
Next create Proxmox and Node access objects, these are the bread and butter of the library:
The library translates its requests into the url equivalent of what you call. So here we request the status on a vm with id number 108:
Which is converted to the URL:
Find a vm template filepath and use this as the os-template for a new vm you create. And then start it up once it has finished being created:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 # find the path for the template you want to use. for template in node.storage('virtual-nfs').content(content='vztmpl'): if re.match('.*ubuntu-12.04-bb-20121010b_amd64.tar.gz$', template['volid']): volume = node.storage('virtual-nfs').content(template['volid']).get() # create the container, giving it some sensible settings taskid = node.openvz.post( ostemplate=volume.get('path'), vmid=204, hostname='test-4', ip_address='192.168.123.204', storage='local' ) # keep an eye on task and see when its completed while node.tasks(taskid).status()['status'] == 'running': time.sleep(1) # print out the logs for line in node.tasks(taskid).log(): print line['t'] try: # start up the container node.openvz('204').status.start.post() except: raise Exception('Unable to start container')
Find if a user exists and create them if they do not: