Friday, 6 July 2012

Tweak your libvirt XML with XSLT

I wanted to clone a KVM VM, and while there a several tools to do the job, I fancied doing it 'the hard way'.

Plan

  1. Get the libvirt XML definition for the XML
  2. Tweak it with an XSLT stylesheet
  3. Put it back in for the new VM
Then I can clone the HD, mount it, change some of the bits in there and voila - new VM.

Implementation

You need 'xsltproc' to perform the XSLT transformation from the commandline - easy on Ubuntu:
# apt-get -y install xsltproc
Here's the XSL:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <!-- tweak libvirt XML file when cloning simple VM --> <!-- xsltproc --stringparam newUUID 1234-5678-90zbcdef --stringparam newMAC 11:22:33:44:55:66            --stringparam newNAME fred clone.xsl eg.xml                            --> <xsl:output omit-xml-declaration="yes" />
 <xsl:param name="newUUID" select="'XXX-YYY-ZZZ'"/> <xsl:param name="newMAC" select="'XX:YY:ZZ:XX:YY:ZZ'"/> <xsl:param name="newNAME" select="'XYZ'"/> <xsl:param name="newMEMORY" select="'1048575'"/> <xsl:param name="newROOT" select="'/XYZ/ROOT.qcow'"/>
 <xsl:template match="node()|@*">  <xsl:copy>   <xsl:apply-templates select="node()|@*"/>  </xsl:copy> </xsl:template>
 <xsl:template match="uuid/text()">  <xsl:value-of select="$newUUID"/> </xsl:template>
 <xsl:template match="imagelabel/text()|label/text()">  <xsl:text>libvirt-</xsl:text><xsl:value-of select="$newUUID"/> </xsl:template>
 <xsl:template match="mac/@address">  <xsl:attribute name="address">   <xsl:value-of select="$newMAC"/>  </xsl:attribute> </xsl:template>
 <xsl:template match="memory/text()|currentMemory/text()">  <xsl:value-of select="$newMEMORY"/> </xsl:template>
 <xsl:template match="/domain/name/text()">  <xsl:value-of select="$newNAME"/> </xsl:template>
 <xsl:template match="disk/source/@file">  <xsl:attribute name="file">   <xsl:value-of select="$newROOT"/>  </xsl:attribute> </xsl:template>
</xsl:stylesheet>
Just needs the parameters specifying to override the sample ones in the scripts when you invoke it...

$ xsltproc --stringparam newNAME testvm --stringparam newMAC 11:22:33:44:55:66 clone.xsl oldvm.xml
And the new XML comes out on stdout.



Wednesday, 13 June 2012

Ubuntu NAS - ZFS on the HP Microserver

HP Microserver N40L
HP Microserver N40L
I had loads of fun setting up FreeNAS on a HP Microserver and can highly recommend this combination for a small home/office file server. But I had a few problems mainly with the performance and stability of the iScsi driver that comes with it. So I decided to pull out the FreeNAS/freebsd root disk and put in a new one on which to check out Ubuntu 12.04 server in combination with the native linux ZFS filesystem.

My target was to get 1Gb/s read and write performance out of the little microserver - ideally iScsi, but NFS would be OK too. Amazingly although the former appears to be a little optimistic the latter is acheivable.

I had setup FreeNAS with 3x2TB disks in a RAIDZ1 array. I replaced the root disk with a new one leaving the 3 ZFS disks in situ and installed ubuntu 12.04 server on the fresh root disk. I created a 'nas' user account for the box and got the installer to put SSH on for me, but nothing else.

ZFS installation is straightforward - i installed bonnie++ too so I could do some benchmarks on the box.

# apt-get update 
# apt-get upgrade 
# apt-get install python-software-properties 
# apt-add-repository ppa:zfs-native/stable 
# apt-get update 
# apt-get install ubuntu-zfs nfs-server sysstat iscsitarget iscsitarget-dkms open-iscsi bonnie
Once installed mounting the existing ZFS array was a case of doing

 # zfs import -f nasvol
and /nasvol appeared by magic on the root of the filesystem.

I then set about benchmarking performance of ZFS, ext4 (the root filesystem) NFS, iScsi using bonnie++. The fastest combination turned out to be a 4 drive RAID10 ZFS setup with NFS. I couldn't get iScsi to perform without large latency, i/o coming in bursts or high CPU. NFS on the other hand was pretty sweet - locally managing 180MB/s write and 250MB/s read. NFS speeds top out at 96MB/s write and 105MB/s read.

To get this performance, a few tips:

  1. ZFS performance is woeful (40MB/s) unless you create the zpool with '-o ashift=12'. This makes it use 4k blocks (i think) which coincides with the modern SATA drives.
  2. More spindles, more speed. Raid 10 gives it 4 to read from and 2 to spread the writes accross. 
  3. RAIDZ1 is great, but not with the Microserver's horsepower. Get an i5/i7 and you'll be able to enjoy deduplication too!
  4. NFS server set up rw, async, no_subtree_check, wdelay. (The UPS is on order)
  5. NFS client set up to use rsize/wsize 65536, tcp, and noatime.
  6. It's possible to disable checksumming in ZFS, but it didn't make much different in this setup.
As I mentioned above, iScsi performance didn't really compare too well with NFS. My ZFS zVol iScsi target managed 70MB/s writes and 50MB/s reads. None of the combinations of LVM2/ext4/iScsi I tried managed more than 80MB/s write although some did manage 100MB/s read.






Ach! NFSv4 is mungling my UIDs

Just noticed my NFS mounts had horribly long UID/GIDs which look suspicioiusly like 2^32 -1 (or close to that). It turns out that with nfs4 idmapd is used to map uids to/from the server. For my simple purposes my first instinct was how do I turn this off! But it appears that one source of it's confusion is just the the domain name it is configured with.

Changing the idmapd.conf file to set the domain to be the same at both ends did the trick - now the IDs are as expected on client and server.

**update** Only on the 12.04 server. On my 11.10 server the IDs were still mungled, and worse I couldn't restart idmapd using service restart. Manually starting rpc.idmapd didn't work either. I rested to:

# apt-get remove nfs-common libnfsidmap2
# apt-get purge nfs-common libnfsidmap2
# apt-get install nfs-common libnfsidmap2

Which after putting the correct domain back in /etc/idmapd.conf did the trick.