Remove img_handlers config parameter usage
Now that the only disk code requiring host filesystem mounts is the LXC filesystem setup, the img_handlers config parameter is an solution looking for a purpose. For any disk image format we can categorically say whether it should be mounted using loop or qemu-nbd mount impls. There is no desire to use libguestfs FUSE for mounting LXC disk images, since users of LXC do not want a huge KVM process alongside every container! Move the mount class choice logic into the mount API, by creating new methods nova.virt.disk.mount.API.instance_for_format() nova.virt.disk.mount.API.instance_for_device() and then call these from nova.virt.disk.API code blueprint: virt-disk-api-refactoring Change-Id: I088b5debdf62d4a9a6b4521eee68cd4757f2ff42 Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
This commit is contained in:
parent
72918415f2
commit
6aebaca79a
|
@ -107,7 +107,6 @@ class TestVirtDisk(test.TestCase):
|
|||
'/mnt/loop/part': '/dev/mapper/loop0p1',
|
||||
'/mnt/nbd/nopart': '/dev/nbd15',
|
||||
'/mnt/nbd/part': '/dev/mapper/nbd15p1',
|
||||
'/mnt/guestfs': 'guestmount',
|
||||
}
|
||||
return mount_points[mount_point]
|
||||
|
||||
|
@ -141,11 +140,4 @@ class TestVirtDisk(test.TestCase):
|
|||
('qemu-nbd', '-d', '/dev/nbd15'),
|
||||
]
|
||||
|
||||
disk_api.destroy_container('/mnt/guestfs')
|
||||
expected_commands += [
|
||||
('fusermount', '-u', '/mnt/guestfs'),
|
||||
]
|
||||
# It's not worth trying to match the last timeout command
|
||||
self.executes.pop()
|
||||
|
||||
self.assertEqual(self.executes, expected_commands)
|
||||
|
|
|
@ -37,9 +37,7 @@ from nova.openstack.common import cfg
|
|||
from nova.openstack.common import jsonutils
|
||||
from nova.openstack.common import log as logging
|
||||
from nova import utils
|
||||
from nova.virt.disk.mount import guestfs
|
||||
from nova.virt.disk.mount import loop
|
||||
from nova.virt.disk.mount import nbd
|
||||
from nova.virt.disk.mount import api as mount
|
||||
from nova.virt.disk.vfs import api as vfs
|
||||
from nova.virt import images
|
||||
|
||||
|
@ -50,9 +48,6 @@ disk_opts = [
|
|||
cfg.StrOpt('injected_network_template',
|
||||
default='$pybasedir/nova/virt/interfaces.template',
|
||||
help='Template file for injected network'),
|
||||
cfg.ListOpt('img_handlers',
|
||||
default=['loop', 'nbd', 'guestfs'],
|
||||
help='Order of methods used to mount disk images'),
|
||||
|
||||
# NOTE(yamahata): ListOpt won't work because the command may include a
|
||||
# comma. For example:
|
||||
|
@ -174,25 +169,14 @@ class _DiskImage(object):
|
|||
self.image = image
|
||||
self.partition = partition
|
||||
self.mount_dir = mount_dir
|
||||
self.use_cow = use_cow
|
||||
|
||||
# Internal
|
||||
self._mkdir = False
|
||||
self._mounter = None
|
||||
self._errors = []
|
||||
|
||||
# As a performance tweak, don't bother trying to
|
||||
# directly loopback mount a cow image.
|
||||
self.handlers = CONF.img_handlers[:]
|
||||
if use_cow and 'loop' in self.handlers:
|
||||
self.handlers.remove('loop')
|
||||
|
||||
if not self.handlers:
|
||||
msg = _('no capable image handler configured')
|
||||
raise exception.NovaException(msg)
|
||||
|
||||
if mount_dir:
|
||||
# Note the os.path.ismount() shortcut doesn't
|
||||
# work with libguestfs due to permissions issues.
|
||||
device = self._device_for_path(mount_dir)
|
||||
if device:
|
||||
self._reset(device)
|
||||
|
@ -211,12 +195,10 @@ class _DiskImage(object):
|
|||
|
||||
def _reset(self, device):
|
||||
"""Reset internal state for a previously mounted directory."""
|
||||
mounter_cls = self._handler_class(device=device)
|
||||
mounter = mounter_cls(image=self.image,
|
||||
partition=self.partition,
|
||||
mount_dir=self.mount_dir,
|
||||
device=device)
|
||||
self._mounter = mounter
|
||||
self._mounter = mount.Mount.instance_for_device(self.image,
|
||||
self.mount_dir,
|
||||
self.partition,
|
||||
device)
|
||||
|
||||
mount_name = os.path.basename(self.mount_dir or '')
|
||||
self._mkdir = mount_name.startswith(self.tmp_prefix)
|
||||
|
@ -226,17 +208,6 @@ class _DiskImage(object):
|
|||
"""Return the collated errors from all operations."""
|
||||
return '\n--\n'.join([''] + self._errors)
|
||||
|
||||
@staticmethod
|
||||
def _handler_class(mode=None, device=None):
|
||||
"""Look up the appropriate class to use based on MODE or DEVICE."""
|
||||
for cls in (loop.LoopMount, nbd.NbdMount, guestfs.GuestFSMount):
|
||||
if mode and cls.mode == mode:
|
||||
return cls
|
||||
elif device and cls.device_id_string in device:
|
||||
return cls
|
||||
msg = _("no disk image handler for: %s") % mode or device
|
||||
raise exception.NovaException(msg)
|
||||
|
||||
def mount(self):
|
||||
"""Mount a disk image, using the object attributes.
|
||||
|
||||
|
@ -252,21 +223,19 @@ class _DiskImage(object):
|
|||
self.mount_dir = tempfile.mkdtemp(prefix=self.tmp_prefix)
|
||||
self._mkdir = True
|
||||
|
||||
try:
|
||||
for h in self.handlers:
|
||||
mounter_cls = self._handler_class(h)
|
||||
mounter = mounter_cls(image=self.image,
|
||||
partition=self.partition,
|
||||
mount_dir=self.mount_dir)
|
||||
if mounter.do_mount():
|
||||
self._mounter = mounter
|
||||
break
|
||||
else:
|
||||
LOG.debug(mounter.error)
|
||||
self._errors.append(mounter.error)
|
||||
finally:
|
||||
if not self._mounter:
|
||||
self.umount() # rmdir
|
||||
imgfmt = "raw"
|
||||
if self.use_cow:
|
||||
imgfmt = "qcow2"
|
||||
|
||||
mounter = mount.Mount.instance_for_format(self.image,
|
||||
self.mount_dir,
|
||||
self.partition,
|
||||
imgfmt)
|
||||
if mounter.do_mount():
|
||||
self._mounter = mounter
|
||||
else:
|
||||
LOG.debug(mounter.error)
|
||||
self._errors.append(mounter.error)
|
||||
|
||||
return bool(self._mounter)
|
||||
|
||||
|
@ -275,6 +244,7 @@ class _DiskImage(object):
|
|||
try:
|
||||
if self._mounter:
|
||||
self._mounter.do_umount()
|
||||
self._mounter = None
|
||||
finally:
|
||||
if self._mkdir:
|
||||
os.rmdir(self.mount_dir)
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
import os
|
||||
|
||||
from nova.openstack.common import importutils
|
||||
from nova.openstack.common import log as logging
|
||||
from nova import utils
|
||||
|
||||
|
@ -30,7 +31,29 @@ class Mount(object):
|
|||
to be called in that order.
|
||||
"""
|
||||
|
||||
mode = device_id_string = None # to be overridden in subclasses
|
||||
mode = None # to be overridden in subclasses
|
||||
|
||||
@staticmethod
|
||||
def instance_for_format(imgfile, mountdir, partition, imgfmt):
|
||||
if imgfmt == "raw":
|
||||
return importutils.import_object(
|
||||
"nova.virt.disk.mount.loop.LoopMount",
|
||||
imgfile, mountdir, partition)
|
||||
else:
|
||||
return importutils.import_object(
|
||||
"nova.virt.disk.mount.nbd.NbdMount",
|
||||
imgfile, mountdir, partition)
|
||||
|
||||
@staticmethod
|
||||
def instance_for_device(imgfile, mountdir, partition, device):
|
||||
if "loop" in device:
|
||||
return importutils.import_object(
|
||||
"nova.virt.disk.mount.loop.LoopMount",
|
||||
imgfile, mountdir, partition, device)
|
||||
else:
|
||||
return importutils.import_object(
|
||||
"nova.virt.disk.mount.nbd.NbdMount",
|
||||
imgfile, mountdir, partition, device)
|
||||
|
||||
def __init__(self, image, mount_dir, partition=None, device=None):
|
||||
|
||||
|
|
|
@ -22,7 +22,6 @@ from nova.virt.disk.mount import api
|
|||
class LoopMount(api.Mount):
|
||||
"""loop back support for raw images."""
|
||||
mode = 'loop'
|
||||
device_id_string = mode
|
||||
|
||||
def get_dev(self):
|
||||
out, err = utils.trycmd('losetup', '--find', '--show', self.image,
|
||||
|
|
|
@ -39,7 +39,6 @@ CONF.register_opts(nbd_opts)
|
|||
class NbdMount(api.Mount):
|
||||
"""qemu-nbd support disk images."""
|
||||
mode = 'nbd'
|
||||
device_id_string = mode
|
||||
|
||||
# NOTE(padraig): There are three issues with this nbd device handling
|
||||
# 1. max_nbd_devices should be inferred (#861504)
|
||||
|
|
Loading…
Reference in New Issue