Kernel-based Virtual Machine (KVM)

Migrating Windows Server 2003 from VMware Server 1.x to KVM

Step 1

Create KVM domain with ACPI and disk(s) of same size as origin VM and with the same MAC address. Example configuration (using libvirt):

   1 <domain type='kvm'>
   2   <name>myVirtualMachine</name>
   3   <uuid>345b2956-c610-4a0e-94b4-a96c5ebd4a0f</uuid>
   4   <memory>524288</memory>
   5   <currentMemory>524288</currentMemory>
   6   <vcpu>2</vcpu>
   7   <os>
   8     <type>hvm</type>
   9     <boot dev='hd'/>
  10   </os>
  11   <features>
  12     <acpi/>
  13   </features>
  14   <clock offset='localtime'/>
  15   <on_poweroff>destroy</on_poweroff>
  16   <on_reboot>restart</on_reboot>
  17   <on_crash>destroy</on_crash>
  18   <devices>
  19     <emulator>/usr/bin/kvm</emulator>
  20     <disk type='block' device='disk'>
  21       <source dev='/dev/vg0/myVirtualMachine-disk1'/>
  22       <target dev='hda' bus='ide'/>
  23     </disk>
  24 <!--
  25     <disk type='file' device='cdrom'>
  26       <source file='/root/ubuntu-8.10-desktop-i386.iso'/>
  27       <target dev='hdc' bus='ide'/>
  28     </disk>
  29 -->
  30 <!--
  31     <disk type='block' device='cdrom'>
  32       <source dev='/dev/cdrom'/>
  33       <target dev='hdc' bus='ide'/>
  34     </disk>
  35 -->
  36     <interface type='bridge'>
  37       <mac address='00:0c:29:3e:9a:d4'/>
  38       <source bridge='br0'/>
  39     </interface>
  40     <input type='tablet' bus='usb'/>
  41     <input type='mouse' bus='ps2'/>
  42     <graphics type='vnc' port='-1' listen='127.0.0.1'/>
  43   </devices>
  44 </domain>
  45 

Step 2

Prepare old virtual machine: Download and execute the MergeIDE-Tool (http://www.virtualbox.org/attachment/wiki/Migrate_Windows/MergeIDE.zip). Remove VMware Tools and (if necessary) change the HAL (see http://support.microsoft.com/kb/309283/en) for the configuration presented above (two VCPUs), the halmacpi.dll worked fine for me.

Step 3

Boot the original VM using a Linux live CD and use dd to copy the harddisk data to the new VM:

dd if=/dev/sda | ssh -C root@kvmhost "dd of=/dev/vg0/myVirtualMachine-disk1"

Step 4

Shutdown the original VM and start the new VM. You might need on or two reboots before Windows has installed all new hardware drivers, but then everything should run perfectly.

Generating a random MAC address

Random MAC address generator script

Mounting a Virtual Disk Partition in the Host System

In order to mount a specific partition of a virtual machine's disk image, you have to use the loop option and specify the offset, where the partition begins in the image.

First run parted <disk image> unit B print in order to find the offset of the partition (this is the number in the first column). Then run mount -oloop,offset=<offset> <disk image> <mount point> in order to mount the partition.

I found this solution on linuxwiki.de.

Graceful Shutdown

In order to shutdown a virtual machine using virt-manager, you have to prepare the virtual machine. QEMU-KVM sends an ACPI signal to the virtual machine, which has to be caught and processed.

Linux

Install the acpid package. This daemon will catch the ACPI signal and initiate the shutdown.

Windows

By default, Windows will not shutdown, unless a user is logged in to the local console. In order to make Windows shutdown anytime, you have to open the local security policies (how to open them depends on the Windows version) go the security options and activate the "Shutdown: Allow system to be shut down without having to log on" option (in German versions "Herunterfahren: Herunterfahren des Systems ohne Anmeldung zulassen"). This will allow Windows to be shutdown from the local console or by pushing the (virtual) power button, even if no user is logged on.

However, there is still a problem, if a user is loggen on to the system, when the shutdown is initiated. Windows will present a dialog on the local console asking whether the shutdown should proceed. To get rid of this dialog (which is important if you want to automate shutdown from a script), you have to go to the registry key HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows and change the value of ShutdownWarningDialogTimeout from 0xffffffff to 0x00000001. If the value does not exist yet, create a new DWORD value with this name. I found this information here.

Shutdown virtual machines on host system shutdown

On Ubuntu 10.04 LTS (Lucid Lynx) getting the virtual machines to shutdown when the host system is shutdown or restarted is quite tricky.

libvirt-bin is managed by Upstart, so we can use an Upstart job, that react on libvirt-bin's stopping event. This ensures, that libvirtd is still available, when our shutdown script is run. We place the configuration for the Upstart job in /etc/init/libvirt-shutdown-domains.conf:

   1 description "stop libvirt virtual machines"
   2 
   3 start on stopping libvirt-bin
   4 
   5 task
   6 
   7 script
   8   runlevel=`runlevel|cut -d" " -f2`
   9   case "$runlevel" in
  10     2|3|4|5)
  11       :
  12       ;;
  13     *)
  14       /usr/local/bin/libvirt-shutdown-domains
  15       ;;
  16   esac
  17 end script
  18 

The script /usr/local/bin/libvirt-shutdown-domains is a Python script for shutting down all virtual machines. Do not forget to chmod a+x the script, so that it can be executed. The script depends on the python-libvirt package.

   1 #!/usr/bin/python
   2 
   3 import libvirt
   4 import sys
   5 import time
   6 
   7 def main():
   8     conn = libvirt.open("qemu:///system")
   9     if conn == None:
  10         print "Failed to open connection"
  11         sys.exit(1)
  12 
  13     # Wait up to 5 minutes
  14     shutdownTimeOut = 300
  15 
  16     startTime = time.time()
  17 
  18     while conn.numOfDomains() > 0 and (time.time() - startTime) < shutdownTimeOut:
  19         shutdownDomains(conn)
  20         time.sleep(2)
  21     if conn.numOfDomains() > 0:
  22          sys.exit(2)
  23 
  24 
  25 def shutdownDomains(conn):
  26     domainIDs = conn.listDomainsID()
  27 
  28     for id in domainIDs:
  29         try:
  30             dom = conn.lookupByID(id)
  31             if (dom == None):
  32                 continue
  33             dom.shutdown()
  34         except Exception:
  35             print "Exception while trying to shutdown " + str(id)
  36 
  37 
  38 main()
  39 

Now, we still have the problem, that the System-V init-scripts run in parallel and /etc/init.d/sendsigs will kill our shutdown script. Even if we changed the script, so that it would not be killed by sendsigs the final reboot script would initiate the reboot, before our script is finished. Therefore, we add a new script for runlevels 0 and 6, that runs before sendsigs and just waits until libvirt-bin has been stopped, thus blocking the sendsigs script. We place this script in /etc/init.d/await-libvirt-bin-stopped:

   1 #! /bin/sh
   2 ### BEGIN INIT INFO
   3 # Provides:          await-libvirt-bin-stopped
   4 # Required-Start:    
   5 # Required-Stop:     sendsigs
   6 # Default-Start:
   7 # Default-Stop:      0 6
   8 # Short-Description: Waits until libvirt-bin has been stopped.
   9 # Description: 
  10 ### END INIT INFO
  11 
  12 PATH=/sbin:/usr/sbin:/bin:/usr/bin
  13 
  14 . /lib/lsb/init-functions
  15 
  16 JOB=libvirt-bin
  17 TIMEOUT=330
  18 
  19 do_wait () {
  20         log_action_begin_msg "Waiting for $JOB to be stopped"
  21         start_time=`date "+%s"`
  22         until status $JOB | grep stop/waiting >/dev/null; do
  23                 if [ $((`date "+%s"` - $start_time)) -gt $TIMEOUT ]; then 
  24                         log_action_end_msg 1
  25                         exit 0
  26                 fi
  27                 sleep 1
  28         done
  29         log_action_end_msg 0
  30 }
  31 
  32 case "$1" in
  33   start)
  34         # No-op
  35         ;;
  36   restart|reload|force-reload)
  37         echo "Error: argument '$1' not supported" >&2
  38         exit 3
  39         ;;
  40   stop)
  41         do_wait
  42         ;;
  43   *)
  44         echo "Usage: $0 start|stop" >&2
  45         exit 3
  46         ;;
  47 esac
  48 
  49 :
  50 

After creating this script, we have to run chmod a+x /etc/init.d/await-libvirt-bin-stopped and update-rc.d await-libvirt-bin-stopped start 19 0 6 . in order to mark the script as executable and generate the necessary symbol links. If the links for sendsigs are not called S20sendsigs, the number 19 has to be changed to be just below the number used for sendsigs.

The timeout specified in the init script should be slightly higher than the timeout in the Python script.

This combination of an Upstart job and a traditional init-script should do the job and virtual machines should be gracefully shutdown on system shutdown or reboot.

Problems and their solutions

Windows complains about parallel port service

If Windows complains that the parallel port service could not be started and you have the following message in the event log

or (in the German version)

you should just disable the "Parport" service. I found the necessary steps here. You have to change the registry key Start in the registry path HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\Parport from 3 to 4. This will disable the service.

Linux/KVM (last edited 2011-06-10 22:02:35 by SebastianMarsching)