Unleash your inner root

Xen to KVM: How to convert when xen is dead

Greetings internet wayfarer. If you have ended up here because your Xen server took a poop and you need to get those old para-virtualized Xen VM’s running on a KVM server. Well congrats, you have arrived. I just dealt with that very same problem. It’s a doozy, but fear not: There is a solution. It can be done.

Like you, I had an old xen server that died, and a running KVM server that I wanted to use to get the servers that were on the xen host running again. I ran into the problem though that most of the guides/information about converting from Xen to KVM assume a running Xen server, which did me no good.

So first of all, you’ll need your xen .img files. You’ll also want to keep track of the xen vm definition xml file. You wont need it for this conversion process, but it is good to reference to take care of things like MAC addresses after conversion is done. Get those .img files moved over to your KVM server. I’ll not go into details on the how, I’m sure you have that taken care of.

  1. You’ll need a non Xen Kernel in your VM’s
  2. This part felt pretty daunting to me at first, but there are a few tricks that can make your life much easier. Tricks that unless you have run into this situation before you may not have known about. Essentially what we’re going to do is mount the disk image on a loop device, chroot into said disk image, and download the kernel using the systems native package manager.

    • First step in this is to assess your VM’s hard drive situation, we can do that using fdisk. For the purposes of this guide let’s assume vm stores are under /images, and we’re working on a server named… *gasp* Server1.
    • fdisk -l /images/server1.img
      

      This should give you some simple fdisk output.

      Disk server1.domain1.com.img: 8388 MB, 8388608000 bytes, 16384000 sectors
      Units = sectors of 1 * 512 = 512 bytes
      Sector size (logical/physical): 512 bytes / 512 bytes
      I/O size (minimum/optimal): 512 bytes / 512 bytes
      Disk label type: dos
      Disk identifier: 0x000359ed
      
                              Device Boot      Start         End      Blocks   Id  System
      server1.domain1.com.img1   *        2048     1026047      512000   83  Linux
      server1.domain1.com.img2         1026048    16383999     7678976   8e  Linux LVM
      

      You’ll note a fairly simple disk configuration in this case, a standard linux partition set as the boot device, and an LVM Volume for the rest of the drive. The LVM part can be a bit tricky, which is why I’ve included it. If you don’t have an LVM setup on your VM, use the “offset” method that will be used for mounting the boot device, for both partitions. Easy peasy.

    • Next up on the agenda is to create a temporary mount that can be used as a target to chroot into. That is fairly easy.
    • mkdir /mnt/server1
      

      For LVM devices:
      We’ll be using a little tool called kpartx to map the .img file to to loop devices, which will allow us to do some magic with the LVM stuff.

      kpartx -av /images/server1.img
      

      Once the mapping is done your virtual drives will show up under /dev/mapper/ as loop devices, and can be accessed like normal hard drives…which means for LVM stuff…You can import them into your existing LVM config!

      vgscan
      

      This will show you a list of Volumn groups that were found, even existing ones. It should look something like this:

       Reading all physical volumes.  This may take a while...
        Found volume group "vg_server1" using metadata type lvm2
        Found volume group "vg_imageStore" using metadata type lvm2
        Found volume group "centos" using metadata type lvm2
      

      In this case, vg_server1 is your virtual volumn group, and the other two are those that I have on the host system.


    • After that it’s simple as mounting the volumn groups that are important. In the very least you’ll need the root partition, and the boot partition.
    • mount /dev/vg_server1/lv_root /mnt/server1
      

      Now, your boot device should have also been mapped to a /dev/mapper/loop device, but we’re going to pretend that’s not the case, because there is a simpler way in my opinion. For the boot device, or for all drives if you don’t have LVM, you can simply mount directly through loop using the offset option. It’s pretty cool…But does require a little math. You have to multiply the starting point of the partition, against the size of the Unit. Going back to our fdisk from above:

      Disk server1.domain1.com.img: 8388 MB, 8388608000 bytes, 16384000 sectors
      Units = sectors of 1 * 512 = 512 bytes
      Sector size (logical/physical): 512 bytes / 512 bytes
      I/O size (minimum/optimal): 512 bytes / 512 bytes
      Disk label type: dos
      Disk identifier: 0x000359ed
      
                              Device Boot      Start         End      Blocks   Id  System
      server1.domain1.com.img1   *        2048     1026047      512000   83  Linux
      server1.domain1.com.img2         1026048    16383999     7678976   8e  Linux LVM
      

      That’s Unit size of 512, and starting point of 2048. Which gives us an offset of 1048576.

      so to mount the boot device we would simply use mount like so:

      mount -t auto -o loop,offset=1048576 /images/server1.img /mnt/server1/boot
      

    • Finally we’ll need to bind /dev
    • Originally when I was going through this, I thought I was done before this point. I got things mounted. I was good to go.. so I issued a simply chroot /mnt/server1, and yum install kernel, and…. Yum apparently relies on /dev/urandom…Who knew?

      Anyway, the /dev/urandom issue is a simple fix. we’re going to bind mount /dev/ to /mnt/server1/dev…LIKE SO!

      mount --bind /dev /mnt/server1/dev
      

      Now you are good to go.

    • The final step is to simply use the package manager of the VM to install a standard kernel.
    • That is as simple as the following:

      chroot /mnt/server1
      yum -y install kernel
      exit
      

      You are done with step 1! good job, before we move on though…Let’s talk cleanup:

      umount /mnt/server1/boot
      umount /mnt/server1/dev
      umount /mnt/server1
      vgchange -an vg_server1
      vgremove my_volume_group
      kpartx -d /images/server1.img
      

      In order that is: unmounting the three partitions, deactivating volume group, removing the volume group from your local VG store, and then deleting the link to the loop devices to the server1.img file.

  3. Convert!
    • This is the easy part, you’ll need a tool called “virt-v2v”
    • yum -y install virt-v2v
      
    • After that’s done, you just need to point the conversion tool at a disk image, rather than at a remote server. This is where most of the information I found online fell short. virt-v2v has a huge amount of options, so sorting through the right way to use it can be pretty rough. Anyway, I’ve found that this works:
    • virt-v2v -i disk /images/server1.img -o local -os /images/
      

      That should take the xen server1.img, and convert it to a kvm file, as well as generating some basic KVM config XML in the /images folder. It will name the new file something different than the original image file. Probably server1-sda.img.

    • You will end up with an xml file that looks something like this:
    • <?xml version='1.0' encoding='utf-8'?>
      <domain type='kvm'>
        <name>Server1</name>
        <memory unit='KiB'>2097152</memory>
        <currentMemory unit='KiB'>2097152</currentMemory>
        <vcpu>1</vcpu>
        <os>
          <type arch='x86_64'>hvm</type>
        </os>
        <features>
          <acpi/>
          <apic/>
        </features>
        <on_poweroff>destroy</on_poweroff>
        <on_reboot>restart</on_reboot>
        <on_crash>restart</on_crash>
        <devices>
          <disk type='file' device='disk'>
            <driver name='qemu' type='raw' cache='none'/>
            <source file='/images/server1-sda'/>
            <target dev='vda' bus='virtio'/>
          </disk>
          <interface type='network'>
            <source network='default'/>
            <model type='virtio'/>
          </interface>
          <video type='qxl' ram='65536' heads='1'/>
          <graphics type='vnc' autoport='yes' port='-1'/>
          <input type='tablet' bus='usb'/>
          <input type='mouse' bus='ps2'/>
          <console type='pty'/>
        </devices>
      </domain>
      


      NOTE: Your config will depend a lot on how your other VM’s are configured, So I recomend looking at an existing KVM VM, and adding any changes that are necessary. Especially around the network interface. Very likely you will need to modify that to be in line with the network interface. It may also be a good idea to copy the MAC address from the old xen config file and add it to the interface for the new KVM VM.


    • Start the new VM!
    • virsh create /images/server1.xml
      

      NOTE: It may be a good idea to first move your xml file to wherever your existing KVM xml files are located. That is slightly outside the realm of this guide though.

That should be about it! you should be in good shape.

kpartxKVMlvmvirt-v2vXEN

Brandon.Graves • December 7, 2016


Previous Post

Next Post

Leave a Reply

Your email address will not be published / Required fields are marked *

%d bloggers like this: