Showing posts with label KVM. Show all posts
Showing posts with label KVM. Show all posts

Tuesday, April 1, 2014

Windows 8.1 in KVM

As Windows XP comes to its end of life, I have to get with the times and test my windows programs in Windows 8.1.

Naturally I am drawn to KVM which is where I run all my Windows instances.

Despite some initial concerns regarding the lack of the +sep flag (covered in my winpe pxe blog), installing Windows 8.1 turned out to be a breeze. I just used the settings for Windows 7 64bit.

After the install I was prompted to log. I have no interest in using a 'Microsoft Account' so I used the obscure procedure of 'Don't have an account' -> 'Sign in without a Microsoft account' which would be better described as 'Create local account'.

The next confronting issue was the start menu or whatever they call it these days. I worked out that I should not to look at it, just to start typing. That works more or less the same as the 'search' on Windows 7 (but possibly faster. It makes by mind boggle that it can take so long to run cmd.exe on Windows 7).

Once I had the basics under control, I set about installing the VirtIO & Spice drivers for extra performance and GUI features (like screen resizing). Alas, spice-guest-tools-0.74.exe does not support Windows 8 and fails during the install complaining about an unsupported version of Windows.

I know the virtio drivers work because I have used them in WinPE so I set about installing them manually. Although they are compatible, installing them is not straight forward.

The driver files are made available under Program Files (x86)\SPICE Guest Tools

The method I normally use is to use guestfish to install the driver file and configure it in the Critical Driver Data Base (CDDB) using a registry patch. Windows 8 no longer has a CDDB so this method does not work.

In the end I reverted to an old method:
  • Add a new (temporary) VirtIO disk to the VM
  • Boot into Windows
  • Install the drivers for VirtIO
  • Shut down windows
  • Remove the temporary disk
  • Change the main disk from IDE to VirtIO
This method works much like it has since Windows 7 allowed changing of the boot path.

The VirtIO network seems to work fine.

Talking to a Samba sever required adjusting some settings. First there are some updates which are apparently required (according to Microsoft) so I make sure all the OS patches were installed first.

Next I adjusted some policy settings under Administrative Tools -> Local Security Policy -> Local Policies -> Security Options:
  • Network security: LAN Manager authentication level = Send LM & NTLM - use NTLMv2 session security if negotiated
  • Network security: Minimum session security for NTLM SSP based (including secure RPC) clients = No Minimum
Then restart the workstation service or reboot.

Finally, the graphics drivers. For reasons which don't seem to be explained, the QXL video driver is not compatible with Windows 8.1. The performance of the 'Microsoft' driver is not too bad but it means no resizing which is annoying.

I am hoping that the spice people make their drivers and installer work soon.

One final observation is to do with the windows version number. Windows 8.1 is NT 6.3 but unless your program is manifested for windows 8.1, you will get the version number 6.2. This is by design. Some kind of new design which means the the GetVersion... API has been deprecated. What are they doing over at Microsoft???

Monday, September 23, 2013

Windows 8?

My first brush win WinPE turned out to be rather successful http://blog.chrysocome.net/2013/02/pxe-boot-winpe.html but recently our Windows team upgraded the SCCM server. Now when I attempt to install Windows 7 in KVM on CentOS-6, I get a windows 8 logo and then the dreaded error 0x0000005D.

The cause for this is, as always, long and complex. The new SCCM release now uses WinPE version 4 which is bases on Windows 8. Windows 8 requires a minimum level of CPU features to run. If you don't meet the minimum you get a well worded error message (well, at least it is easier to search for than a BSOD report).

I can't do much about SCCM, WinPE or Windows 8 so the next part of the problem is why does my KVM virtual machine not meet the Windows 8 requirements?

You guessed it. Bugs! It seems (more or less) that the 'sep' cpu feature was forgotten by libvirt and there is no fix coming soon.

What is needed then is a well implemented work around. KVM does support the required flag (-cpu +sep) but libvirt has no method to pass the flag to kvm. I already have a wrapper around kvm http://blog.chrysocome.net/2013/05/can-kvm-guest-found-out-who-its-host-is.html so it seemed logical to extend that script to add the missing flag.

Below is my solution which adds the +sep flag to the existing CPU configuration as well as set the serial number, as per the original script. Installation is the same as shown in my other blog post, edit the guest and set the <emulator> path to /usr/local/libexec/qemu-kvm (either using virsh edit or your favourite XML editor).

/usr/local/libexec/qemu-kvm
#!/bin/bash
# This is a wrapper around qemu which will supply
# DMI information
# and correct a bug with the CPU type required for winpe4 (Windows 8)
max=${#@}
index=0

for i in $(seq 1 $max) ; do
   p=${@:$i:1}
   if [ "$p" = "-cpu" ] ; then
      (( index = $i + 1 ))
      break
   fi
done

if [ $index -gt 0 ] ; then
cpu=${@:$index:1}
cpu="$cpu,+sep"

(( ibefore = $index - 1 ))
(( iafter = $index + 1 ))
set -- "${@:1:$ibefore}" $cpu "${@:$iafter}"
fi

if [ "$1" = "-name" ] ; then
    SERIAL=$(/usr/bin/hal-get-property --udi /org/freedesktop/Hal/devices/computer --key system.hardware.serial)
    exec /usr/libexec/qemu-kvm "$@" -smbios type=1,serial="KVM-$SERIAL"
else
    exec /usr/libexec/qemu-kvm "$@"
fi

Sunday, May 12, 2013

Can a KVM guest find out who it's host is?

Our puppet configuration performs a number of checks on our asset database to make sure things are recorded correctly.

One of the properties we record for virtual machines is their location (which host they are running on).

By default, KVM does not expose this information even though there are many ways it could technically be done.

Using bits and pieces from around the internet I have come up with a process where I can pass the serial number of the host into the guest.

qemu permits you to specify many DMI values on the command line like this:
qemu-kvm ... -smbios type=1,serial="MY-SERIAL"
The virtual machine will see this value and puppet will automatically create a fact with this value.

Unfortunately, libvirt does not use this mechanism and the serial number is blank in the virtual machine. The libvirt specification permits setting a value in the .xml config file but it is still not used.

I would like to insert a value which is the same as the host serial but with a prefix to indicate that this is indeed a virtual machine and then a suffix to make sure the serial is unique (such as the vm name).

Initially I used dmidecode to get the host serial number
dmidecode -s system-serial-number
but to run that you must be root and using sudo from the qemu user turned out to be a PITA. In the end I settled for
/usr/bin/hal-get-property --udi /org/freedesktop/Hal/devices/computer --key system.hardware.serial
which uses dbus but means I can run it without being root.

The next step was a shim around qemu-kvm which could add the command line parameters. On RHEL/CentOS 6, the binary lives in /usr/libexec so I put my wrapper in /usr/local/libexec (I think that is the first time I have ever used that directory). When a vm is being started, the first parameter is -name and then the machine name is specified (at least in the current EL6 version. This was not the case in a previous release so it could change). I check to see if that has been specified because qemu-kvm is also invoked by libvirt to check it's configuration/capabilities which does not require the dmi serial (although it does not hurt).

/usr/local/libexec/qemu-kvm
#!/bin/bash
# This is a wrapper around qemu which will supply
# DMI information
if [ "$1" = "-name" ] ; then
    SERIAL=$(/usr/bin/hal-get-property --udi /org/freedesktop/Hal/devices/computer --key system.hardware.serial)
    exec /usr/libexec/qemu-kvm "$@" -smbios type=1,serial="KVM-$SERIAL-$2"
else
    exec /usr/libexec/qemu-kvm "$@"
fi


The final step is to tell libvirt to use my new shim rather than the qemu-kvm binary directly. This also does not seem optimal but can be done by editing every guest and setting the <emulator> path to /usr/local/libexec/qemu-kvm
(either using virsh edit or your favourite XML editor).

Tuesday, October 23, 2012

KVM file permissions

Recently I have been testing CentOS 6 with libvirt & KVM. My goal is to set up a cluster of servers and enable migration between them without shared storage.

This seems possible but I hit a roadblock with file permissions. I am using a directory pool but any newly created file is assigned the permissions 0600 and owned by root:cso (cso is the group that all the sysadmins are in). The XML schema for libvirt pools allows me to specify a mode, owner & group but they don't seem to be honoured when the file is created.

My workaround to this problem was to create a hook which runs when a virtual machine is started. This gives me a chance to change the permissions to the correct values. The libvirt hooks are not widely publicised but at least on CentOS 6, you create the file and it just works. See http://libvirt.org/hooks.html

The basic skeleton for my hook is:
/etc/libvirt/hooks/qemu

#!/bin/bash
if [ "$2" = "prepare" -a "$3" = "begin" ] ; then
   # Fix the permissions
fi
exit 0


The next headache is that I don't know which disks are needed for this virtual machine. This info is provided on stdin but it is in XML which is not easy for bash to process.

My solution to this was to use XSLT to transform the XML into a bash script.
I have never used XSLT before so there was a fair amount of guessing involved. The output of xsltproc always has an XML header which I strip off with grep. The output is logged to syslog with the logger command. The final hook script looks like this:
/etc/libvirt/hooks/qemu
#!/bin/bash
if [ "$2" = "prepare" -a "$3" = "begin" ] ; then
   /usr/bin/xsltproc /etc/libvirt/hooks/qemu.hook.xsl - | \
      grep -v '?xml' | \
      sh -x | logger
fi
exit 0

As for the XSL, I am no expert but I got it working. I could not work out how to correctly escape the values of the file names so there could be a nasty surprise in there if you don't trust your users.

/etc/libvirt/hooks/qemu.hook.xsl 
<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xsl:for-each select="domain/devices/disk/source">
chown qemu:cso '<xsl:value-of select="@file"/>'
chmod 0660 '<xsl:value-of select="@file"/>'
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>