Bug#898257 support handling images with libguestfs

http://libguestfs.org/ provides both utilities and libraries
to manipulate image files containing various operating systems.
It supports various image file formats and so will expand
the formats and guest types supported by openstack.
It does have extra overhead in that it starts a VM to
access the image. This has both advantages and disadvantages.
Also qemu-nbd is not supported on some systems like RHEL 6.

* nova/virt/disk/api.py (img_handlers): Add guestfs to the default
list of access methods to try, to act as a fallback.
* nova/virt/disk/guestfs.py: A new plugin class to provide support
for libguestfs mounting.
Note we use the guestmount utility, as a non root user,
so the user will need the ability to use fusermount, which
is often provided by being a member of the 'fuser' group.
In future we might use the guestfs python module to give
greater granularity of control over the image.

Change-Id: I2e22c9d149fff7a73cd8cebaa280d68d3fb9096c
This commit is contained in:
Pádraig Brady 2011-11-30 17:00:17 +00:00 committed by Pádraig Brady
parent 5335b4ab0e
commit dd56fd39d5
3 changed files with 99 additions and 2 deletions

View File

@ -44,6 +44,14 @@ filters = [
# nova/virt/disk/loop.py: 'losetup', '--detach', device
CommandFilter("/sbin/losetup", "root"),
# nova/virt/disk/guestfs.py: 'guestmount', '--rw', '-a', image, '-i'
# nova/virt/disk/guestfs.py: 'guestmount', '--rw', '-a', image, '-m' dev
Commandfilter("/usr/bin/guestmount", "root"),
# nova/virt/disk/guestfs.py: 'fusermount', 'u', mount_dir
Commandfilter("/bin/fusermount", "root"),
Commandfilter("/usr/bin/fusermount", "root"),
# nova/virt/disk/api.py: 'tee', metadata_path
# nova/virt/disk/api.py: 'tee', '-a', keyfile
# nova/virt/disk/api.py: 'tee', netfile

View File

@ -33,6 +33,7 @@ from nova import exception
from nova import flags
from nova import log as logging
from nova import utils
from nova.virt.disk import guestfs
from nova.virt.disk import loop
from nova.virt.disk import nbd
@ -43,7 +44,7 @@ flags.DEFINE_integer('minimum_root_size', 1024 * 1024 * 1024 * 10,
flags.DEFINE_string('injected_network_template',
utils.abspath('virt/interfaces.template'),
'Template file for injected network')
flags.DEFINE_list('img_handlers', ['loop', 'nbd'],
flags.DEFINE_list('img_handlers', ['loop', 'nbd', 'guestfs'],
'Order of methods used to mount disk images')
@ -130,7 +131,7 @@ class _DiskImage(object):
@staticmethod
def _handler_class(mode):
"""Look up the appropriate class to use based on MODE."""
for cls in (loop.Mount, nbd.Mount):
for cls in (loop.Mount, nbd.Mount, guestfs.Mount):
if cls.mode == mode:
return cls
raise exception.Error(_("unknown disk image handler: %s" % mode))

88
nova/virt/disk/guestfs.py Normal file
View File

@ -0,0 +1,88 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2011 Red Hat, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
"""Support for mounting images with libguestfs"""
import os
from nova import utils
from nova.virt.disk import mount
class Mount(mount.Mount):
"""libguestfs support for arbitrary images."""
mode = 'guestfs'
def map_dev(self):
self.mapped = True
return True
def unmap_dev(self):
self.mapped = False
def mnt_dev(self):
args = ('guestmount', '--rw', '-a', self.image)
if self.partition == -1:
args += ('-i',) # find the OS partition
elif self.partition:
args += ('-m', '/dev/sda%d' % self.partition)
else:
# We don't resort to -i for this case yet,
# as some older versions of libguestfs
# have problems identifying ttylinux images for example
args += ('-m', '/dev/sda')
args += (self.mount_dir,)
# root access should not required for guestfs (if the user
# has permissions to fusermount (by being part of the fuse
# group for example)). Also note the image and mount_dir
# have appropriate creditials at this point for read/write
# mounting by the nova user. However currently there are
# subsequent access issues by both the nova and root users
# if the nova user mounts the image, as detailed here:
# https://bugzilla.redhat.com/show_bug.cgi?id=765814
_out, err = utils.trycmd(*args, discard_warnings=True,
run_as_root=True)
if err:
self.error = _('Failed to mount filesystem: %s') % err
# Be defensive and ensure this is unmounted,
# as I'm not sure guestmount will never have
# mounted when it returns EXIT_FAILURE.
# This is required if discard_warnings=False above
utils.trycmd('fusermount', '-u', self.mount_dir, run_as_root=True)
return False
# More defensiveness as there are edge cases where
# guestmount can return success while not mounting
try:
if not os.listdir(self.mount_dir):
# Assume we've just got the original empty temp dir
err = _('unknown guestmount error')
self.error = _('Failed to mount filesystem: %s') % err
return False
except OSError:
# This is the usual path and means root has
# probably mounted fine
pass
self.mounted = True
return True
def unmnt_dev(self):
if not self.mounted:
return
# root users don't need a specific unmnt_dev()
# but ordinary users do
utils.execute('fusermount', '-u', self.mount_dir, run_as_root=True)
self.mounted = False