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>


1 comment:

  1. translate(@file, '/ \:', '____') or something along those lines would get rid of some of the trickier characters (can also use character entities to specify, iirc).

    ReplyDelete