Nothing is beyond me. When it comes to computers, I am all conquering.

That actually might be an exaggeration. But I just pulled off a stunt that really impressed me.

I'm moving all my systems from CentOS 5 to CentOS 6. (Why so soon? Shut up) In the process, I need to move my VMs from VMware Server 1 (Seriously? Shut up) to KVM (libvirt specificly). For the most part, I'm actually starting up whole new VMs and reconfiging them. But I still might want to look at my old data, fetch old files, and what not. This means being able to read VMware's vmdk files. This is "easy":

modprobe nbd max_part=8
qemu-nbd -r --connect=/dev/nbd0 /vmware/files/sda.vmdk
kpartx -a /dev/nbd0
vgchange -a y VolGroup00
mount -o ro /dev/mapper/VolGroup00-LogVol00 /mnt/files

There are 3 complications to this:

First, you can't have multiple VGs with the same name active at once. Work around is to only mount one at a time. You can renamed VGs with vgrename but that's a job for another day.

Next off, I chose to have my vmdk split into multiple 2GB files. This makes copying them around so much more fun. But qemu only understands monolithic files, so you need vmware-vdiskmanager to convert them. Specificly

vmware-vdiskmanager -r /vmware/files/sda.vmdk -t 0 /vmware/files/single.vmdk

Lastly (and this is the main point of this post) CENTOS 6 DOESN'T SHIP WITH NBD! After WTFing about as hard as I could, I googled around for one. Someone must have needed nbd at some point, surely. The only solution I found was to recompile the kernel from scratch. Which is stupid. As a work around, I used the kernel-lt from elrepo. But the real solution would be a kmod. I thought doing a kmod would be hard, so I set aside a few hours. Turns out, it's really easy and I got it right on the first try.

tl;dr - rpm -ivh kmod-nbd-0.0-1.el6.x86_64.rpm

I based my kmod on kmod-jfs from elrepo.

  1. Install the kmod-jfs SRPM;
  2. Copy jfs-kmod.spec to nbd-kmod.spec;
  3. Copy kmodtool-jfs-el6.sh to kmodtool-nbd-el6.sh
  4. Edit nbd-kmod.spec. You have to change kmod_name and the %changelog section. You might also want to change kversion to your current kernel (uname -r). If not, you need to add --define "kversion $(uname -r)" when running rpmbuild;
  5. Create nbd-0.0.tar.bz2;
  6. Build, install and test the new module.
    rpmbuild -ba nbd-kmod.spec
    rpm -ivh ~/rpmbuild/RPMS/x86_64/kmod-nbd-0.0-1.el6.x86_64.rpm
    modprobe nbd
    ls -l /dev/nbd*

The hard part (of course) is that I wasn't sure what to put in nbd-0.0.tar.bz2. The contents of jfs-0.0.tar.bz2 just look like the files from drivers/jfs in the kernel tree with Kconfig and Makefile added on. So I pull down the kernel SRPM, did a rpmbuild -bp on that (just commend out all the BuildRequires that give you grief. You aren't doing a full build.) Then I poked around for nbd in ~/rpmbuild/BUILD/vanilla-2.6.32-431.5.1.el6/. Turns out there's only nbd.c and nbd.h. So that goes in the pot. I copied over the Makefile from jfs, modifying it slightly because jfs is spread over multiple source files. Kconfig looked like kernel configuration vars. I just copied BLK_DEV_NBD out of vanilla-2.6.32-431.5.1.el6/drivers/block/Kconfig.

This entire process took roughly 1 hours. It worked on the first try. Of course, all the magic is in kmodtool-nbd-el6.sh. But I was expecting a lot of pain. Instead it worked on the first try. I was so surprised I did modprobe -r nbd ; ls -l /dev/nbd* just to make sure I wasn't getting a false positive.

No comments: