Skip to content

Mounting VirtualBox VDI images on a MacOS X host

During all this VirtualBox hackery stuff I came across an interesting blogpost on how to mount a VirtualBox VDI in MacOS X. That is, we don't really want to mount it, we merely want to access the VDI file via a blockdevice. In GNU/Linux or Solaris one would use losetup resp. lofiadm to attach any file to a blockdevice.

In MacOS X there's hdid. By default, hdid not only tries to assign a blockdevice to the file but it tries to mount it too. We don't want this, so we use -nomount:
$ file linux.vdi
linux.vdi: VDI Image version 1.1 (<<< Oracle VM VirtualBox Disk Image >>>), \
           2147483648 bytes

$ hdid -nomount linux.vdi 
hdid: attach failed - not recognized
Still, hdid failed. The blogpost above helped, we have to use the magic .img extension for the filename, oh well:
$ ln linux.vdi linux.img
$ hdid -nomount linux.img
/dev/disk5
However, we're still not entirely satisfied. Our linux.vdi contains a whole virtual disk (partition table + data), so let's apply the blogpost above to our disk. Read the post again to understand what we do here:
$ hdiutil detach disk5
$ hexdump -C linux.vdi | grep -m1 ^00000150
00000150  00 4e 88 00 00 10 00 00  00 50 10 00 00 00 00 00  |.N.......P......|

$ echo 'obase=16; 512; ibase=16; 00015000 / 200' | bc
200
A8
Now that we have the offset to our disk, we can instruct hdid to just attach this disk (minus the VDI header):
$ hdid -section 0xa8 -nomount linux.img 
/dev/disk5             GUID_partition_scheme
/dev/disk5s1           EFI

$ file -Ls /dev/disk5*
/dev/disk5:   x86 boot sector
/dev/disk5s1: Linux rev 1.0 ext4 filesystem data, [...]
Now we could even fsck our virtual Linux partion from MacOS, hey! :-)

Update: Two mindful readers noted that my calculation was incorrect. This should now be fixed in the article.

Virtualbox: How to resize a VDI disk

Resizing virtual disks (VDI, Virtual Disk Image) in Virtualbox is still not possible*). There are several rather long tutorials out there how to do this, that's the short version of it:
  • Create a new VDI disk of desired size. We've created a 2GB deb02.vdi, as our 1GB deb01.vdi was too small.

  • Create a new VM, attach both the old (too small) and new (bigger, but still empty) disk to the VM, boot from a bootable CD, e.g. grml.

  • Once booted, we transfer the old disk (sda) to the new, bigger one (sdb):
      $ dd if=/dev/sda of=/dev/sdb bs=1M
      $ sfdisk -R /dev/sdb
      
    Yes, that's right. We're just copying the whole disk (with its partition table!) to the new disk. I tried to just copy the partition and make it larger with GNU/parted, but it kept barking about unsupported flags on the ext4 partiton (sdb1) and whatnot and I gave up quickly. Anyway, now we have a 2GB sdb with the partitiontable from sda, that is: sdb1 is still 1GB in size, 1GB is unallocated space.

  • Luckily our disklayout was easy enough (and we had a simple MS-DOS partition-table). Thus, we just started cfdisk, deleted sdb1 and created a new sdb1, but filling out the whole disk (2GB).

  • $ sfdisk -R /dev/sdb again to re-read the partition-table.

  • Now that our partition is in good shape, we need to enlarge the peni^W filesystem as well:
       $ e2fsck -vf /dev/sdb1
       $ resize2fs -p /dev/sdb1
      
    We might have to mount /dev/sdb1 for this, I don't remember.

If all goes well, we should now have a perfectly good sdb, so we could go on and replace the small deb0.vdi VDI disk with the bigger one, deb1.vdi. I've done this a few days ago and I already forgot wether I had to re-install the bootloader. But I'm sure you'll find out if you have to :-)


*) as opposed to e.g. VMware, where it should be possible to resize a virtual disk. I've even done it once :-)

Migrating from VMware Server via OVF

After manually migrating a VMware VM to Virtualbox and all the hackery involved (although it was fun to learn), we need to remember that we should be able to accomplish the same with the help of OVF, the Open Virtual Machine Format. With that, things are a lot easier. Let's export that WindowsXP VMware-Server VM again, so that I can deploy it in a VMware-ESX Server later on:
# ls -lgho *vmx* *vmdk
-rwxr-xr-x 1 2.0K 2010-06-22 21:54 winxp.vmx
-rw-r--r-- 1  278 2010-05-15 00:32 winxp.vmxf
-rw-r--r-- 1 6.0G 2010-06-08 00:22 winxp-flat.vmdk
-rw-r--r-- 1  435 2010-06-07 23:44 winxp.vmdk

# time ovftool winxp.vmx winxp.ovf
Opening VMX source: winxp.vmx
Opening OVF target: winxp.ovf
Target: winxp.ovf
Disk Transfer Completed         
Completed successfully

real    13m25.328s
user    7m56.998s
sys     1m32.942s

# ls -lgho *vmx* *vmdk
[...]
-rw-r--r-- 1 3.1G 2010-06-22 22:07 winxp-disk1.vmdk
-rw-r--r-- 1 4.4K 2010-06-22 22:07 winxp.ovf
-rw-r--r-- 1  123 2010-06-22 22:07 winxp.mf
Note that our 6GB winxp-flat.vmdk has been converted to a 3.1GB winxp-disk1.vmdk:
# file winxp-flat.vmdk winxp-disk1.vmdk
winxp-flat.vmdk:      x86 boot sector, Microsoft Windows XP MBR
winxp-disk1.vmdk:     VMware4 disk image
Now we can logon to our ESX Server an deploy the winxp.ovf. We should be able to import the same VM into VirtualBox (supported since v2.2.0), I did not try it though. So yeah, OVF FTW, hm? :)

Migrating from VMware Server to VirtualBox

Even though VMware Server was working fine with Ubuntu 10.04 (apart from random lockups without a backtrace in sight to debug with), I was kinda unhappy with all the hoops one has to go through just to get a virtual machine going. The kernel modules might break on the next upgrade and are tainting the kernel unnecessarily. Fortunately today we have a few virtualization options to pick from and I chose VirtualBox for this particular setup, as it seemed to be the easiest migration path. Let's begin with installing the prerequisites:

# apt-get install virtualbox-ose virtualbox-ose-dkms qemu
Then we had to convert our 2GB-split VMware VMDK files into a single VMDK file, otherwise qemu-bin would produce empty raw files in the 2nd step:

# vmware-vdiskmanager -r orig/test.vmdk -t 2 test.vmdk
# qemu-img convert -O raw test-flat.vmdk test.raw

# VBoxManage convertfromraw test.raw test.vdi
Converting from raw image file="test.raw" to file="test.vdi"...
Creating dynamic image with size 2147483648 bytes (2048MB)...

# ls -lgo *vmdk *raw *vdi
-rw------- 1 2147483648 2010-06-05 18:17 test-flat.vmdk
-rw-r--r-- 1 2147483648 2010-06-05 18:28 test.raw
-rw------- 1 1676681728 2010-06-06 12:50 test.vdi
-rw------- 1        432 2010-06-05 18:17 test.vmdk
Somehow VBoxManage cannot convert VMDK images directly, hence the qemu-img step. All these conversions will take a while, depending on image-size and diskspeed. There's no progress-bar, so just be patient. With our VDI image now in place, we can register it to VirtualBox:
# VBoxManage openmedium disk test.vdi
# VBoxManage list hdds
UUID:       ddaaf826-3d25-48d6-9b2a-1afefdd3350f
Format:     VDI
Location:   /data/vbox-vm/test/test.vdi
Accessible: yes
Type:       normal
Now for the actual virtual machine creation. It's important to create the new machine with the same/similar hardware as the initial VMware instance was configured with, so that the guest OS won't be too suprised about the "new" hardware, i.e. storage- or network-controllers.
# VBoxManage createvm --ostype Debian --register --name "test" \
   --basefolder `pwd`
# VBoxManage modifyvm test --memory 128 --audio none \
   --boot1 disk --clipboard disabled
# VBoxManage modifyvm test --pae off --hwvirtex off \
  --hwvirtexexcl off --nestedpaging off --vtxvpid off
# VBoxManage modifyvm test --nic1 bridged --bridgeadapter1 eth1 \
  --nictype1 Am79C970A --macaddress1 000c291ac243
I've disabled any kind of hardware virtualization features, as the host-CPU is too old and doesn't support it anyway. Also, I used the MAC address of the VMware VM, so that the guest-OS will (hopefully) receive its known DHCP address. Now for the storage devices. Again, try to use the same controller as configured in the VMware server (see the .vmx file of the old VMware instance). Also, we're attaching the virtual harddisk from above to our virtual machine.
# VBoxManage storagectl test --name "SCSI Controller" \
   --add scsi --controller LsiLogic
# VBoxManage storageattach test --storagectl "SCSI Controller" \
   --port 0 --device 0 --type hdd --medium ddaaf826-3d25-48d6-9b2a-1afefdd3350f
Having done that, it should look like this:
# VBoxManage list -l vms | egrep 'Control|MAC'
Storage Controller Name (0):            SCSI Controller
Storage Controller Type (0):            LsiLogic
Storage Controller Instance Number (0): 0
Storage Controller Max Port Count (0):  16
Storage Controller Port Count (0):      16
SCSI Controller (0, 0): /data/vbox-vm/test/test.vdi 
        (UUID: ddaaf826-3d25-48d6-9b2a-1afefdd3350f)
NIC 1:           MAC: 000C291AC243, Attachment: Bridged Interface \
                    'eth1', Cable connected: on, Trace: off (file: none), \
                    Type: Am79C970A, Reported speed: 0 Mbps
Now our virtual machine should be able to start just fine:
# VBoxHeadless -s test
You probably want to remove the VMware tools from the guest (vmware-uninstall-tools.pl) and tweak your startscripts to start your VM during bootup. Oh, and if the machine just won't start up, we can still cheat and install the VirtualBox GUI:
# apt-get install virtualbox-ose-qt tightvncserver xfonts-base wm2
Update: Migrating a WindowsXM VM from VMware to Virtualbox was equally straightforward, but I could not get the NIC type right. Neither Am79C970A (PCnet-PCI II) nor Am79C973 (PCnet-FAST III) seemed equal to the VMware Accelerated AMD PCNet Adapter in VMware. So I had to use the VirtualBox GUI again, as VirtualBox OSE does not ship with RDP support to connect to. Also, the Ubuntu/Lucid version does not ship with VNC support, yet. Here are the commands for the WindowsXP VM again:
# VBoxManage createvm --ostype WindowsXP --register --name winxp --basefolder `pwd`
# qemu-img convert -O raw ../../vmware-vm/winxp/winxp-static-flat.vmdk winxp.raw
# VBoxManage convertfromraw winxp.raw winxp.vdi
# VBoxManage openmedium disk winxp.vdi
# VBoxManage modifyvm winxp --memory 256 --audio none --boot1 disk \
                     --clipboard disabled --pae off --hwvirtex off --hwvirtexexcl off \
                     --nestedpaging off --vtxvpid off --nic1 bridged \
                     --bridgeadapter1 eth1 --nictype1 Am79C970A \
                     --macaddress1 000c11b9c19c
# VBoxManage storagectl winxp --name "IDE Controller" --add ide --controller PIIX4
# VBoxManage storageattach winxp --storagectl "IDE Controller" --port 0 --device 0 \
                       --type hdd --medium a6723e4d-2caa-433d-91ec-f67238ff36a9