Moving from pyrax to libcloud: A story in 3 parts

10 Sep 2018 - python

Softserve is a service that lets our community loan machines to debug test failures. They create cloud VMs based on the image that we use for our test machines. We originally used pyrax to create and delete VMs. I spent some time trying to re-do that with libcloud.

Part 1: Writing libcloud code

I started by writing a simple script that created a VM with libcloud. Then, I modified it to do an SSHKeyDeployment, and further re-wrote that code to work with MultiStepDeployment with two keys. Once I got that working, all I had left was to delete the server. All went well, I plugged in the code and pushed it. Have you seen the bug yet?

Part 2: Deepshikha tries to deploy it

Because I’m an idiot, I didn’t test my code with our application. Our tests don’t actually go and create a cloud server. We ran into bugs. We rolled back and I went about fixing them. The first one we ran into was installing dependencies. Turns out that the process of installing dependencies for libcloud was slightly more complicated for some reason (more on that later!). We needed to pull in a few new devel packages. I sat down and actually fixed all bugs I could trigger. Turns out, there were plenty.

Part 3: I find bugs

Now I ran into subtle installation bugs. Pip would throw up some weird error. The default Python on Centos 7 is pretty old. I upgraded pip and setuptools inside my virtualenv to see if that would solve the pip errors and it did. I suspect some newer packages depend on newer setuptools and pip features and it fails quite badly when those are older.

After that, I ran into an bug that was incredibly satisfying to debug. The logs had a traceback that said I wasn’t passing a string as pubkey. I couldn’t reproduce that bug locally. On my local setup, the type was str, so I had to debug on that server with a few print statements. It turns out that the variable had type unicode. Well, that’s weird. I don’t know why that’s happening – unicode sounds right, something is broken on my local setup. A check for “strings” in python2 should check for str and unicode. The code does the following check which returns False when pubkey is a unicode:

isinstance(pubkey, basestring)

On a first glance, that looked right. On python2, str and unicode are instances of basestring. A bit of sleuthing later, I discovered that libcloud has their own overridden basestring. This does not consider unicode to be an instance of basestring. I found this definition of basestring for python2:

basestring = unicode = str

That doesn’t work as I expect on Python 2. How did this ever work? Is it that almost everyone passes strings and never runs into this bug? I have a bug filed. When I figure out how to fix this correctly, I’ll send a patch. My first instinct is to replace it with a line that just says

basestring

In python2, that should Just Work™. Link to code in case anyone is curious. One part of me is screaming to replace all of this with a library like six that will handle edge cases way better.