Posted by virantha on Mon 09 March 2015

Migrating XenServer Virtual Machine VDIs to KVM

After having worked with Xenserver 6.2 for over a year now, I've decided to migrate away from it. It just wasn't stable enough with SATA pass-through on my machine, and it had some really annoying bugs with the way snapshots and backups were handled:

  • Under load, my SATA 8-bay enclosure would sometimes hang the entire server (not just the Windows 7 host that was the end-point)
  • Snapshots would fail with error saying not enough space, even though the disk was less than three quarters full
  • No built-in backup solution (combined with the snapshot unreliability, this is a dealbreaker)
  • Need to manually clean up disk clusters/vms (documented bug)
  • Network transfers to a remote system/disk across management NICs are throttled (good god)
  • No USB 3.0 support, so good luck backing up even to a local disk

Needless to say, I've been itching to give another solution a shot. I finally decided to migrate to KVM, and it took me a while to figure out how to seamlessly migrate my Windows virtual machines over. The actual process is very simple and detailed below.

1   Googling it

There are lots of tutorials on the web about using XenCenter in Windows to export disks, but in my experience, XenCenter was extremely unreliable even for imports and I didn't want to build another Windows VM just to export disks.

2   The easy way

Turns out, and it appears not many people are aware of it, there's a simple command line interface to the Transfer VMs built into Xenserver 6.x. Using the Transfer VM on the host (dom0), you can expose any offline VDI as a raw image over HTTP using built-in commands with no additional software to install. Then, on your client disk system, you simply use curl to download the disk image over the network. Very simple, and no third-party tools involved. The steps involved are given below:

2.1   Expose the VDI on your Xenserver Host

There are three pieces of information (UUIDs) that you're going to need for this process, and I've summarized them in the table below, including the commands you'll run on dom0 as root. Just find the particular UUID that identifies the resource you need in the text output that is generated by each command below.

UUIDs you'll need
UUID Command
HOST-UUID xe host-list
NETWORK-UUID xe network-list
VDI-UUID xe vdi-list

Once you have all of the details above, shut down the VM or detach the VDI, and execute the following:

xe host-call-plugin host-uuid=HOST-UUID fn=expose args:vdi_uuid=VDI-UUID args:network_uuid=NETWORK-UUID args:transfer_mode=http

This will return (print out) a new record locator UUID that you should copy down. Let's call it RECORD-UUID and use it in the following command to get the exposed URL:

xe host-call-plugin host-uuid=HOST-UUID plugin=transfer fn=get_record args:record_handle=RECORD-UUID

This will print out something like the following:

<?xml version="1.0"?>
<transfer_record
  username="70f8e0b297fcdd94"
  status="exposed"
  url_path="/vdi_uuid_4b26aeff-bc12-44f0-a5b6-2e07ec37e75c"
  record_handle="dda7a17f-2621-a77a-0464-6d95a19fbbc3"
  ip="10.80.238.238"
  transfer_mode="http"
  url_full="http://70f8e0b297fcdd94:8c21f66590fcb08e@10.80.238.238:80/vdi_uuid_4b26aeff-bc12-44f0-a5b6-2e07ec37e75c"
  device="xvdn"
  use_ssl="false"
  password="8c21f66590fcb08e"
  port="80"
  vdi_uuid="4b26aeff-bc12-44f0-a5b6-2e07ec37e75c">
</transfer_record>

What you need is the url_full entry; let's call it VDI_URL. This is the url where the Transfer VM will supply the raw disk image of the VDI you specified.

2.2   Install the image on your KVM host

On the destination machine, all you have to do is issue the following command to download that VDI as a raw image:

curl VDI_URL -o disk.raw

Next, convert this to a .qcow2 image for KVM using the following command:

qemu-img convert -O qcow2 disk.raw disk.qcow2

Now, you can just attach this disk to any KVM virtual machine. If you're migrating from a Windows 7 machine, you will probably need to make sure you use the IDE drivers and not the virtio drivers for the disk for the first boot. So, you would change something like this in your .xml configuration:

<target dev='hda' bus='virtio'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/>

To something like this:

<target dev='hda' bus='ide'/>
<address type='drive' controller='0' bus='0' target='0' unit='0'/>

And that's it!

2.3   Cleanup

Optional: You may also want to go back to your XenServer host and un-expose your VDI, so you can reattach/restart your VM by executing:

xe host-call-plugin host-uuid=HOST-UUID plugin=transfer fn=unexpose args:record_handle=RECORD-UUID

You may also want to zero some of the free space on your Windows disk image, to take full advantage of the compressibility of the qcow2 image format. First, in your Windows VM, download the sdelete utility from here. Then, run the following command from a command prompt in Windows:

sdelete.exe -z c:

This will take some time to complete. Once that's done, shut down your VM, and run the following command on your Linux KVM host:

qemu-img convert -c -O qcow2 original.qcow2 compressed.qcow2

Startup your VM using the new compressed.qcow2 and if all looks good, you can go ahead and delete the original.qcow2 image.

© Virantha Ekanayake. Built using Pelican. Modified svbhack theme, based on theme by Carey Metcalfe