Skip to content
February 13, 2012 / jonathanunderwood

Multi-user use of virt-manager

Recently I wanted to deploy the libvirt/virt-manager/qemu-kvm virtualization stack on a bunch of Scientific Linux 6 workstations. This presented a number of requirements:

  • Virtual machines need to be able to be installed and started by non-root users
  • The workstations are multi-user, so we need to prevent users from running or modifying each other’s virtual machines
  • On these machines home directories are mounted over NFS, but we want the VM disk images located on a local scratch disk for performance
  • VMs will be considered to be scratch data – i.e. not backed up

Allowing non-root users to manage virtual machines

Fortunately the libvirt stack has support for PolicyKit, and so allowing non-root users is simply a matter of setting some policy. Placing the following in the file /etc/polkit-1/localauthority/50-local.d/50-virt.pkla will allow all users to manage virtual machines:

[Allow all users libvirt management permissions but require password]
Identity=*
Action=org.libvirt.unix.manage
ResultAny=auth_self_keep
ResultInactive=auth_self_keep
ResultActive=auth_self_keep

With this file in place, a user starting virt-manager will be asked to enter their password (note: not root’s password), and can then proceed.

Setting up per-user storage pools

Now, at this point, the expectation made by libvirt/virt-manager is that virtual machine disk images are stored in /var/lib/libvirt/images, and indeed all users are able to create and manage virtual machines under this directory, as evidence by its permissions:

$ ls -ldZ /var/lib/libvirt/images
drwx--x--x. root root system_u:object_r:virt_image_t:s0 /var/lib/libvirt/images/

However, we want to have private storage pools for each user, and we don’t want to have them stored under /var, but rather on a locally mounted scratch disk (mounted at /scratch). We could proceed by requiring each user to create a storage pool using the virt-manager (via the Edit->Connection Details menu entry and chosing the Storage tab). However, unfortunately doing so as a non-root user results in the storage pool directory having the wrong permissions. For example, if I create a storage pool while running virt-manager as user jgu under /scratch/test:

$ ls -ldZ /scratch/temp/
drwx------. root root unconfined_u:object_r:root_t:s0 /scratch/temp/

which unfortunately won’t actually be usable by the user jgu. Similarly using virsh will have the same problem:

$ virsh --connect qemu:///system "pool-define-as jgu-vmstore  --type=dir --target=/scratch/virt/jgu/images ; pool-build jgu-vmstore ; pool-start jgu-vmstore ; pool-autostart jgu-vmstore"
...
$ ls -ldZ /scratch/virt/jgu/images
drwx------. root root unconfined_u:object_r:default_t:s0 /scratch/virt/jgu/images

I’ve reported this problem in the following bug reports:
Redhat Bugzilla #790038
Redhat Bugzilla #790045

Taking a look at the file /etc/libvirtd/storage/jgu-vmstore.xml that was created as a result of the virsh command above gives us a clue as to a solution to this problem:

<pool type='dir'>
  <name>jgu-vmstore2</name>
  <uuid>6a81e62f-5c42-fc94-c32b-18877e025c31</uuid>
  <capacity>0</capacity>
  <allocation>0</allocation>
  <available>0</available>
  <source>
  </source>
  <target>
    <path>/scratch/virt/jgu/images</path>
    <permissions>
      <mode>0700</mode>
      <owner>-1</owner>
      <group>-1</group>
    </permissions>
  </target>
</pool>

Notice the permissions block – so it seems possible to specify user and group during storage pool creation with virsh using the -pool-define switch together with an xml file desribing the storage pool. The bash script below does exactly this:

#!/bin/bash

usage=$(cat <<EOF
USEAGE:
$0 ROOTDIR STORAGE-POOL

ROOTDIR            directory under which to store virtual machine data
STORAGE-POOL       name of storage pool for virtual machine images

This script will create a directory for storage of virtual machine images, and
register it as a storage pool with libvirt. The script creates the following
directories:

ROOTDIR/STORAGE-POOL      for storage of virtual machine images
ROOTDIR/iso               for storage of operating system install disk ISO 
                          images
EOF
)

if [[ "$1" == "" || "$2" == "" ]] ; then
    echo "${usage}"
    exit 1
fi

ROOTDIR=$1
IMGSTORE=$2

USERNAME=`whoami`
GID=`id -g`
IMGDIR=${ROOTDIR}/${IMGSTORE}

if [[ ! -d ${ROOTDIR} || ! -w ${ROOTDIR} ]] ; then
    echo "Can't write to ${ROOTDIR}."
    exit 1
fi

# Create the storage pool. Here we could do something like the following:
#
# virsh --connect qemu:///system "\
# pool-define-as ${IMGSTORE}  --type=dir --target=${IMGDIR} ; \
# pool-build ${IMGSTORE} ; \
# pool-start ${IMGSTORE} ; \
# pool-autostart ${IMGSTORE} \
# "
#
# however, then the storage pool will be owned by root, whereas we want it to
# be owned by the user. Unfortunately pool-define-as doesn't have arguments
# for user and group, but it is possible to specify owner and group in an xml
# description and use pool-define. So, we'll do that.

XMLFILE=`mktemp` 

cat > ${XMLFILE} <<EOF
<pool type='dir'>
  <name>${IMGSTORE}</name>
  <target>
    <path>${IMGDIR}</path>
    <permissions>
      <mode>0700</mode>
      <owner>${UID}</owner>
      <group>${GID}</group>
    </permissions>
  </target>
</pool>
EOF

echo "Creating storage pool ${IMGSTORE}:"
virsh --connect qemu:///system "\
pool-define ${XMLFILE} ; \
pool-build ${IMGSTORE} ; \
pool-start ${IMGSTORE} ; \
pool-autostart ${IMGSTORE} \
"

if [[ $? -ne 0 ]] ; then
    rm -f ${XMLFILE}
    echo "Could not create storage pool."
    exit 1
else
    rm -f ${XMLFILE}
    echo "Storage pool \"${USERNAME}-vmstore\" created at ${IMGDIR}."
    echo "Use this to store your virtual machine images."
    echo
fi

# Create a directory for storing ISO images
ISODIR=${ROOTDIR}/iso
echo "Creating directory to store OS ISO images at ${ISODIR}:"
mkdir -p ${ISODIR}
if [[ $? -ne 0 ]] ; then
    echo "Failed to create ${ISODIR}."
    exit 1
else
    chown ${UID}:${GID} ${ISODIR}
    chmod 700 ${ISODIR}
    echo "${ISODIR} created"
    echo "Use this to store any ISO images of operating system installation disks"
fi

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: