2015-07-18

The use case

This isn’t exactly far-fetched but nothing seems to do it out of the box: migrate Glance images from a backend to the other.

We’re in the process of moving our Glance default store to Swift, it simply scales infinitely better than the file backend.
Now, changing the default store does just that: change the default store.
It makes it so the newly created images will be uploaded to the new store - it doesn’t do anything for the existing images.

It’s fine if you plan on keeping the old storage backend around but if you have to keep the images and want to get rid of the old backend, Glance doesn’t help you magically migrate images to the new shiny store.

Let’s look at how we can migrate images from file to Swift while keeping their attributes and properties, things like:

UUID (as users might be relying on this, whether we like it or not)

Name

Container format

Disk format

Visibility - public or private

Other params like min_disk, min_ram

Custom properties

etc.

The attempts

Delete and re-create the images with the same properties

My good friend Emilien Macchi (follow him on twitter @EmilienMacchi) got my hopes up with what seemed a simple but effective script to do almost just that.

It was flawed on a very important point, though - it is not possible to delete an image and create a new one with the same UUID.
The script also doesn’t keep properties but some bash-fu could have fixed that if the UUID wasn’t problematic.

Essentially, the delete is a “soft” delete. The image remains in the database but at the status “deleted”.

Trick Glance into uploading the image directly to Swift

Looking at the Glance database, you can see how it stores the images’ locations for a file based image:

In contrast, the location of the same image stored in Swift would look like this instead:

The location of the image is pretty predictable since everything is according to the configuration of your Swift store.

I tried to download the image and upload it directly to the Glance Swift container using Swiftclient and then update the image location in the database from the file-based one to the Swift one.

It turns out it’s not easily possible: Glance chunks larger images by itself prior to uploading the image with it’s own way of doing things. In Swift, an image created by Glance will look like this:

I found this kind of odd since Swiftclient has a built-in mechanism to segment a large file into smaller chunks. You’d get something like this instead:

The image in the glance container is actually a manifest file which references the chunks. If you download the manifest file, Swift’ll in fact serve you the chunks as one big file.

Anyway, back to the drawing board as this didn’t work out either.

The solution

What I ended up doing is a fairly generic script that could potentially be used to migrate from any backend to any backend. It’s rough around the edges but suits my needs right now. It also does everything through the API and there’s no manual SQL work involved.

What the script does:

Authenticates a session through Openstackclient. The usual environment variables are fine.

Lists all current images

Downloads each image and create a new one (in the new backend) with the same properties (except UUID)

Deletes the original image at the orginal location (glance location-delete)
— This effectively deletes the image at the original location

Updates the location of the original image to the location of the new image

Protects both images to prevent them from being deleted and orphaned

Deletes the temporary copy of the downloaded image

The result is that all your original images are created as new images on the new backend and
the original images’ location point to the new image. You end up with two images but one location (file).

The repository for the script is available here: https://github.com/dmsimard/migrate-glance-backend

I definitely want to improve the script further when I have time, contributions are also welcome !

Show more