Kernel-based Virtual Machine (KVM)
Contents
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
- The Parallel port driver service failed to start due to the following error: The service cannot be started, either because it is disabled or because it has no enabled devices associated with it.
or (in the German version)
- Der Dienst "Treiber für parallelen Anschluss" wurde aufgrund folgenden Fehlers nicht gestartet: Der angegebene Dienst kann nicht gestartet werden. Er ist deaktiviert oder nicht mit aktivierten Geräten verbunden.
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.
