Bug#898257 abstract out disk image access methods

Rather than providing two mutually exlusive image
access methods (loop and qemu-nbd), try each in turn.
This is to prepare for a follow up patch which will
add libguestfs as a method to try.

* nova/virt/mount.py: A new Mount class to abstract the
devce allocation, partition mapping and file sys mounting,
for each access type.
* nova/virt/disk/loop.py: A specialization of the base Mount class
to provide loop back mounting support.
* nova/virt/disk/nbd.py: A specialization of the base Mount class
to provide qemu-nbd mounting support.
* nova/virt/disk/api.py: A new file containing the nova.virt.disk
module interface.
(img_handlers): A new list of access methods to try,
with the order being honored.
(_DiskImage): An internal helper class that uses the plugin classes
above, to provide the operations available on a disk image file.
When mounting, iterate over each access method until one succeeds.
If a hint is provided about a CoW format image, the list of
methods to try will be reduced accordingly.
Note expected errors are no longer raised as exceptions during mounting.
Instead, on failure to mount an image, errors are collated and raised.
Interveining errors are logged in debug mode for successful mounts.
* nova/virt/libvirt/connection.py: Adjust the function parameter
names to be more general, rather than referencing specific
implementations like 'nbd' and 'tune2fs'.
Simplify the destroy_container() by storing and passing
back a reference to the _DiskImage object, which has the
necessary state to unmount.
* nova/utils.py (trycmd): A helper function to both deal with,
commands that issue ignorable warnings to stderr,
and commands that EXIT_SUCCESS while issuing errors to stderr.
nova/virt/xenapi/vm_utils.py: Adjust for the moved virt.disk package

Change-Id: If3a4b1c8f4e2f2e7300a21071340dcc839cb36d7
This commit is contained in:
Pádraig Brady 2011-11-30 17:00:17 +00:00 committed by Pádraig Brady
parent b2f36879b0
commit 5335b4ab0e
12 changed files with 467 additions and 153 deletions

View File

@ -112,6 +112,7 @@ Naveed Massjouni <naveedm9@gmail.com>
Nikolay Sokolov <nsokolov@griddynamics.com>
Nirmal Ranganathan <nirmal.ranganathan@rackspace.com>
Ollie Leahy <oliver.leahy@hp.com>
Pádraig Brady <pbrady@redhat.com>
Paul Voccio <paul@openstack.org>
Renuka Apte <renuka.apte@citrix.com>
Ricardo Carrillo Cruz <emaildericky@gmail.com>

View File

@ -19,53 +19,50 @@
from nova.rootwrap.filters import CommandFilter, DnsmasqFilter
filters = [
# nova/virt/disk.py: 'kpartx', '-a', device
# nova/virt/disk.py: 'kpartx', '-d', device
# nova/virt/disk/mount.py: 'kpartx', '-a', device
# nova/virt/disk/mount.py: 'kpartx', '-d', device
CommandFilter("/sbin/kpartx", "root"),
# nova/virt/disk.py: 'tune2fs', '-c', 0, '-i', 0, mapped_device
# nova/virt/disk/mount.py: 'tune2fs', '-c', 0, '-i', 0, mapped_device
# nova/virt/xenapi/vm_utils.py: "tune2fs", "-O ^has_journal", part_path
# nova/virt/xenapi/vm_utils.py: "tune2fs", "-j", partition_path
CommandFilter("/sbin/tune2fs", "root"),
# nova/virt/disk.py: 'mount', mapped_device, tmpdir
# nova/virt/disk.py: 'mount', device, container_dir
# nova/virt/disk.py: 'mount'
# nova/virt/disk/mount.py: 'mount', mapped_device, mount_dir
# nova/virt/xenapi/vm_utils.py: 'mount', '-t', 'ext2,ext3,ext4,reiserfs'..
CommandFilter("/bin/mount", "root"),
# nova/virt/disk.py: 'umount', mapped_device
# nova/virt/disk.py: 'umount', container_dir
# nova/virt/disk/mount.py: 'umount', mapped_device
# nova/virt/xenapi/vm_utils.py: 'umount', dev_path
CommandFilter("/bin/umount", "root"),
# nova/virt/disk.py: 'qemu-nbd', '-c', device, image
# nova/virt/disk.py: 'qemu-nbd', '-d', device
# nova/virt/disk/nbd.py: 'qemu-nbd', '-c', device, image
# nova/virt/disk/nbd.py: 'qemu-nbd', '-d', device
CommandFilter("/usr/bin/qemu-nbd", "root"),
# nova/virt/disk.py: 'losetup', '--find', '--show', image
# nova/virt/disk.py: 'losetup', '--detach', device
# nova/virt/disk/loop.py: 'losetup', '--find', '--show', image
# nova/virt/disk/loop.py: 'losetup', '--detach', device
CommandFilter("/sbin/losetup", "root"),
# nova/virt/disk.py: 'tee', metadata_path
# nova/virt/disk.py: 'tee', '-a', keyfile
# nova/virt/disk.py: 'tee', netfile
# nova/virt/disk/api.py: 'tee', metadata_path
# nova/virt/disk/api.py: 'tee', '-a', keyfile
# nova/virt/disk/api.py: 'tee', netfile
CommandFilter("/usr/bin/tee", "root"),
# nova/virt/disk.py: 'mkdir', '-p', sshdir
# nova/virt/disk.py: 'mkdir', '-p', netdir
# nova/virt/disk/api.py: 'mkdir', '-p', sshdir
# nova/virt/disk/api.py: 'mkdir', '-p', netdir
CommandFilter("/bin/mkdir", "root"),
# nova/virt/disk.py: 'chown', 'root', sshdir
# nova/virt/disk.py: 'chown', 'root:root', netdir
# nova/virt/disk/api.py: 'chown', 'root', sshdir
# nova/virt/disk/api.py: 'chown', 'root:root', netdir
# nova/virt/libvirt/connection.py: 'chown', os.getuid(), console_log
# nova/virt/libvirt/connection.py: 'chown', os.getuid(), console_log
# nova/virt/libvirt/connection.py: 'chown', 'root', basepath('disk')
# nova/virt/xenapi/vm_utils.py: 'chown', os.getuid(), dev_path
CommandFilter("/bin/chown", "root"),
# nova/virt/disk.py: 'chmod', '700', sshdir
# nova/virt/disk.py: 'chmod', 755, netdir
# nova/virt/disk/api.py: 'chmod', '700', sshdir
# nova/virt/disk/api.py: 'chmod', 755, netdir
CommandFilter("/bin/chmod", "root"),
# nova/virt/libvirt/vif.py: 'ip', 'tuntap', 'add', dev, 'mode', 'tap'

View File

@ -36,7 +36,7 @@ from nova import utils
from nova.api.ec2 import cloud
from nova.compute import power_state
from nova.compute import vm_states
from nova.virt import disk
from nova.virt.disk import api as disk
from nova.virt import images
from nova.virt import driver
from nova.virt.libvirt import connection

View File

@ -238,6 +238,36 @@ def execute(*cmd, **kwargs):
greenthread.sleep(0)
def trycmd(*args, **kwargs):
"""
A wrapper around execute() to more easily handle warnings and errors.
Returns an (out, err) tuple of strings containing the output of
the command's stdout and stderr. If 'err' is not empty then the
command can be considered to have failed.
:discard_warnings True | False. Defaults to False. If set to True,
then for succeeding commands, stderr is cleared
"""
discard_warnings = kwargs.pop('discard_warnings', False)
try:
out, err = execute(*args, **kwargs)
failed = False
except exception.ProcessExecutionError, exn:
out, err = '', str(exn)
LOG.debug(err)
failed = True
if not failed and discard_warnings and err:
# Handle commands that output to stderr but otherwise succeed
LOG.debug(err)
err = ''
return out, err
def ssh_execute(ssh, cmd, process_input=None,
addl_env=None, check_exit_code=True):
LOG.debug(_('Running cmd (SSH): %s'), ' '.join(cmd))

View File

@ -0,0 +1,21 @@
# 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.
"""
Operations on disk images including:
resize, file system creation, data injection.
"""

View File

@ -28,13 +28,13 @@ Includes injection of SSH PGP keys into authorized_keys file.
import json
import os
import tempfile
import time
from nova import exception
from nova import flags
from nova import log as logging
from nova import utils
from nova.virt.disk import loop
from nova.virt.disk import nbd
LOG = logging.getLogger('nova.compute.disk')
FLAGS = flags.FLAGS
@ -43,10 +43,9 @@ 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_integer('timeout_nbd', 10,
'time to wait for a NBD device coming up')
flags.DEFINE_integer('max_nbd_devices', 16,
'maximum number of possible nbd devices')
flags.DEFINE_list('img_handlers', ['loop', 'nbd'],
'Order of methods used to mount disk images')
# NOTE(yamahata): DEFINE_list() doesn't work because the command may
# include ','. For example,
@ -101,8 +100,89 @@ def extend(image, size):
utils.execute('resize2fs', image, check_exit_code=False)
class _DiskImage(object):
"""Provide operations on a disk image file."""
def __init__(self, image, partition=None, use_cow=False,
disable_auto_fsck=False, mount_dir=None):
# These passed to each mounter
self.image = image
self.partition = partition
self.disable_auto_fsck = disable_auto_fsck
self.mount_dir = mount_dir
# 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 = FLAGS.img_handlers[:]
if use_cow:
self.handlers.remove('loop')
@property
def errors(self):
"""Return the collated errors from all operations."""
return '\n--\n'.join([''] + self._errors)
@staticmethod
def _handler_class(mode):
"""Look up the appropriate class to use based on MODE."""
for cls in (loop.Mount, nbd.Mount):
if cls.mode == mode:
return cls
raise exception.Error(_("unknown disk image handler: %s" % mode))
def mount(self):
"""Mount a disk image, using the object attributes.
The first supported means provided by the mount classes is used.
True, or False is returned and the 'errors' attribute
contains any diagnostics.
"""
if self._mounter:
raise exception.Error(_('image already mounted'))
if not self.mount_dir:
self.mount_dir = tempfile.mkdtemp()
self._mkdir = True
try:
for h in self.handlers:
mounter_cls = self._handler_class(h)
mounter = mounter_cls(image=self.image,
partition=self.partition,
disable_auto_fsck=self.disable_auto_fsck,
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
return bool(self._mounter)
def umount(self):
"""Unmount a disk image from the file system."""
try:
if self._mounter:
self._mounter.do_umount()
finally:
if self._mkdir:
os.rmdir(self.mount_dir)
# Public module functions
def inject_data(image, key=None, net=None, metadata=None,
partition=None, nbd=False, tune2fs=True):
partition=None, use_cow=False, disable_auto_fsck=True):
"""Injects a ssh key and optionally net data into a disk image.
it will mount the image as a fully partitioned disk and attempt to inject
@ -111,57 +191,19 @@ def inject_data(image, key=None, net=None, metadata=None,
If partition is not specified it mounts the image as a single partition.
"""
device = _link_device(image, nbd)
try:
if not partition is None:
# create partition
out, err = utils.execute('kpartx', '-a', device, run_as_root=True)
if err:
raise exception.Error(_('Failed to load partition: %s') % err)
mapped_device = '/dev/mapper/%sp%s' % (device.split('/')[-1],
partition)
else:
mapped_device = device
img = _DiskImage(image=image, partition=partition, use_cow=use_cow,
disable_auto_fsck=disable_auto_fsck)
if img.mount():
try:
# We can only loopback mount raw images. If the device isn't there,
# it's normally because it's a .vmdk or a .vdi etc
if not os.path.exists(mapped_device):
raise exception.Error('Mapped device was not found (we can'
' only inject raw disk images): %s' %
mapped_device)
if tune2fs:
# Configure ext2fs so that it doesn't auto-check every N boots
out, err = utils.execute('tune2fs', '-c', 0, '-i', 0,
mapped_device, run_as_root=True)
tmpdir = tempfile.mkdtemp()
try:
# mount loopback to dir
out, err = utils.execute('mount', mapped_device, tmpdir,
run_as_root=True)
if err:
raise exception.Error(_('Failed to mount filesystem: %s')
% err)
try:
inject_data_into_fs(tmpdir, key, net, metadata,
utils.execute)
finally:
# unmount device
utils.execute('umount', mapped_device, run_as_root=True)
finally:
# remove temporary directory
utils.execute('rmdir', tmpdir)
inject_data_into_fs(img.mount_dir, key, net, metadata,
utils.execute)
finally:
if not partition is None:
# remove partitions
utils.execute('kpartx', '-d', device, run_as_root=True)
finally:
_unlink_device(device, nbd)
img.umount()
else:
raise exception.Error(img.errors)
def setup_container(image, container_dir=None, nbd=False):
def setup_container(image, container_dir=None, use_cow=False):
"""Setup the LXC container.
It will mount the loopback image to the container directory in order
@ -170,86 +212,30 @@ def setup_container(image, container_dir=None, nbd=False):
LXC does not support qcow2 images yet.
"""
try:
device = _link_device(image, nbd)
utils.execute('mount', device, container_dir, run_as_root=True)
img = _DiskImage(image=image, use_cow=use_cow, mount_dir=container_dir)
if img.mount():
return img
else:
raise exception.Error(img.errors)
except Exception, exn:
LOG.exception(_('Failed to mount filesystem: %s'), exn)
_unlink_device(device, nbd)
def destroy_container(target, instance, nbd=False):
def destroy_container(img):
"""Destroy the container once it terminates.
It will umount the container that is mounted, try to find the loopback
device associated with the container and delete it.
It will umount the container that is mounted,
and delete any linked devices.
LXC does not support qcow2 images yet.
"""
out, err = utils.execute('mount', run_as_root=True)
for loop in out.splitlines():
if instance['name'] in loop:
device = loop.split()[0]
try:
container_dir = '%s/rootfs' % target
utils.execute('umount', container_dir, run_as_root=True)
_unlink_device(device, nbd)
if img:
img.umount()
except Exception, exn:
LOG.exception(_('Failed to remove container: %s'), exn)
def _link_device(image, nbd):
"""Link image to device using loopback or nbd"""
if nbd:
device = _allocate_device()
utils.execute('qemu-nbd', '-c', device, image, run_as_root=True)
# NOTE(vish): this forks into another process, so give it a chance
# to set up before continuuing
for i in xrange(FLAGS.timeout_nbd):
if os.path.exists("/sys/block/%s/pid" % os.path.basename(device)):
return device
time.sleep(1)
raise exception.Error(_('nbd device %s did not show up') % device)
else:
out, err = utils.execute('losetup', '--find', '--show', image,
run_as_root=True)
if err:
raise exception.Error(_('Could not attach image to loopback: %s')
% err)
return out.strip()
def _unlink_device(device, nbd):
"""Unlink image from device using loopback or nbd"""
if nbd:
utils.execute('qemu-nbd', '-d', device, run_as_root=True)
_free_device(device)
else:
utils.execute('losetup', '--detach', device, run_as_root=True)
_DEVICES = ['/dev/nbd%s' % i for i in xrange(FLAGS.max_nbd_devices)]
def _allocate_device():
# NOTE(vish): This assumes no other processes are allocating nbd devices.
# It may race cause a race condition if multiple
# workers are running on a given machine.
while True:
if not _DEVICES:
raise exception.Error(_('No free nbd devices'))
device = _DEVICES.pop()
if not os.path.exists("/sys/block/%s/pid" % os.path.basename(device)):
break
return device
def _free_device(device):
_DEVICES.append(device)
def inject_data_into_fs(fs, key, net, metadata, execute):
"""Injects data into a filesystem already mounted by the caller.
Virt connections can call this directly if they mount their fs

41
nova/virt/disk/loop.py Normal file
View File

@ -0,0 +1,41 @@
# 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 the loop device"""
from nova import utils
from nova.virt.disk import mount
class Mount(mount.Mount):
"""loop back support for raw images."""
mode = 'loop'
def get_dev(self):
out, err = utils.trycmd('losetup', '--find', '--show', self.image,
run_as_root=True)
if err:
self.error = _('Could not attach image to loopback: %s') % err
return False
self.device = out.strip()
self.linked = True
return True
def unget_dev(self):
if not self.linked:
return
utils.execute('losetup', '--detach', self.device, run_as_root=True)
self.linked = False

142
nova/virt/disk/mount.py Normal file
View File

@ -0,0 +1,142 @@
# 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 virtual image files"""
import os
from nova import log as logging
from nova import utils
LOG = logging.getLogger('nova.compute.disk')
class Mount(object):
"""Standard mounting operations, that can be overridden by subclasses.
The basic device operations provided are get, map and mount,
to be called in that order.
"""
def __init__(self, image, mount_dir, partition=None,
disable_auto_fsck=False):
# Input
self.image = image
self.partition = partition
self.disable_auto_fsck = disable_auto_fsck
self.mount_dir = mount_dir
# Output
self.error = ""
# Internal
self.linked = self.mapped = self.mounted = False
self.device = self.mapped_device = None
def get_dev(self):
"""Make the image available as a block device in the file system."""
self.device = None
self.linked = True
return True
def unget_dev(self):
"""Release the block device from the file system namespace."""
self.linked = False
def map_dev(self):
"""Map partitions of the device to the file system namespace."""
assert(os.path.exists(self.device))
if self.partition:
map_path = '/dev/mapper/%sp%s' % (self.device.split('/')[-1],
self.partition)
assert(not os.path.exists(map_path))
# Note kpartx can output warnings to stderr and succeed
# Also it can output failures to stderr and "succeed"
# So we just go on the existence of the mapped device
_out, err = utils.trycmd('kpartx', '-a', self.device,
run_as_root=True, discard_warnings=True)
# Note kpartx does nothing when presented with a raw image,
# so given we only use it when we expect a partitioned image, fail
if not os.path.exists(map_path):
if not err:
err = _('no partitions found')
self.error = _('Failed to map partitions: %s') % err
else:
self.mapped_device = map_path
self.mapped = True
else:
self.mapped_device = self.device
self.mapped = True
# This is an orthogonal operation
# which only needs to be done once
if self.disable_auto_fsck and self.mapped:
self.disable_auto_fsck = False
# attempt to set ext[234] so that it doesn't auto-fsck
_out, err = utils.trycmd('tune2fs', '-c', 0, '-i', 0,
self.mapped_device, run_as_root=True)
if err:
LOG.info(_('Failed to disable fs check: %s') % err)
return self.mapped
def unmap_dev(self):
"""Remove partitions of the device from the file system namespace."""
if not self.mapped:
return
if self.partition:
utils.execute('kpartx', '-d', self.device, run_as_root=True)
self.mapped = False
def mnt_dev(self):
"""Mount the device into the file system."""
_out, err = utils.trycmd('mount', self.mapped_device, self.mount_dir,
run_as_root=True)
if err:
self.error = _('Failed to mount filesystem: %s') % err
return False
self.mounted = True
return True
def unmnt_dev(self):
"""Unmount the device from the file system."""
if not self.mounted:
return
utils.execute('umount', self.mapped_device, run_as_root=True)
self.mounted = False
def do_mount(self):
"""Call the get, map and mnt operations."""
status = False
try:
status = self.get_dev() and self.map_dev() and self.mnt_dev()
finally:
if not status:
self.do_umount()
return status
def do_umount(self):
"""Call the unmnt, unmap and unget operations."""
if self.mounted:
self.unmnt_dev()
if self.mapped:
self.unmap_dev()
if self.linked:
self.unget_dev()

95
nova/virt/disk/nbd.py Normal file
View File

@ -0,0 +1,95 @@
# 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 qemu-nbd"""
import os
import time
from nova import flags
from nova import utils
from nova.virt.disk import mount
FLAGS = flags.FLAGS
flags.DEFINE_integer('timeout_nbd', 10,
'time to wait for a NBD device coming up')
flags.DEFINE_integer('max_nbd_devices', 16,
'maximum number of possible nbd devices')
class Mount(mount.Mount):
"""qemu-nbd support disk images."""
mode = 'nbd'
# NOTE(padraig): There are three issues with this nbd device handling
# 1. max_nbd_devices should be inferred (#861504)
# 2. We assume nothing else on the system uses nbd devices
# 3. Multiple workers on a system can race against each other
# A patch has been proposed in Nov 2011, to add add a -f option to
# qemu-nbd, akin to losetup -f. One could test for this by running qemu-nbd
# with just the -f option, where it will fail if not supported, or if there
# are no free devices. Note that patch currently hardcodes 16 devices.
# We might be able to alleviate problem 2. by scanning /proc/partitions
# like the aformentioned patch does.
_DEVICES = ['/dev/nbd%s' % i for i in range(FLAGS.max_nbd_devices)]
def _allocate_nbd(self):
while True:
if not self._DEVICES:
# really want to log this info, not raise
self.error = _('No free nbd devices')
return None
device = self._DEVICES.pop()
if not os.path.exists("/sys/block/%s/pid" %
os.path.basename(device)):
break
return device
def _free_nbd(self, device):
self._DEVICES.append(device)
def get_dev(self):
device = self._allocate_nbd()
if not device:
return False
_out, err = utils.trycmd('qemu-nbd', '-c', device, self.image,
run_as_root=True)
if err:
self.error = _('qemu-nbd error: %s') % err
self._free_nbd(device)
return False
# NOTE(vish): this forks into another process, so give it a chance
# to set up before continuing
for _i in range(FLAGS.timeout_nbd):
if os.path.exists("/sys/block/%s/pid" % os.path.basename(device)):
self.device = device
break
time.sleep(1)
else:
self.error = _('nbd device %s did not show up') % device
self._free_nbd(device)
return False
self.linked = True
return True
def unget_dev(self):
if not self.linked:
return
utils.execute('qemu-nbd', '-d', self.device, run_as_root=True)
self._free_nbd(self.device)
self.linked = False
self.device = None

View File

@ -63,7 +63,7 @@ from nova import flags
import nova.image
from nova import log as logging
from nova import utils
from nova.virt import disk
from nova.virt.disk import api as disk
from nova.virt import driver
from nova.virt import images
from nova.virt.libvirt import utils as libvirt_utils
@ -181,6 +181,7 @@ class LibvirtConnection(driver.ComputeDriver):
self._host_state = None
self._wrapped_conn = None
self.container = None
self.read_only = read_only
fw_class = utils.import_class(FLAGS.firewall_driver)
@ -404,7 +405,7 @@ class LibvirtConnection(driver.ComputeDriver):
LOG.info(_('instance %(instance_name)s: deleting instance files'
' %(target)s') % locals())
if FLAGS.libvirt_type == 'lxc':
disk.destroy_container(target, instance, nbd=FLAGS.use_cow_images)
disk.destroy_container(self.container)
if os.path.exists(target):
shutil.rmtree(target)
@ -1037,11 +1038,11 @@ class LibvirtConnection(driver.ComputeDriver):
if config_drive: # Should be True or None by now.
injection_path = basepath('disk.config')
img_id = 'config-drive'
tune2fs = False
disable_auto_fsck = False
else:
injection_path = basepath('disk')
img_id = inst.image_ref
tune2fs = True
disable_auto_fsck = True
for injection in ('metadata', 'key', 'net'):
if locals()[injection]:
@ -1051,8 +1052,8 @@ class LibvirtConnection(driver.ComputeDriver):
try:
disk.inject_data(injection_path, key, net, metadata,
partition=target_partition,
nbd=FLAGS.use_cow_images,
tune2fs=tune2fs)
use_cow=FLAGS.use_cow_images,
disable_auto_fsck=disable_auto_fsck)
except Exception as e:
# This could be a windows image, or a vmdk format disk
@ -1060,9 +1061,9 @@ class LibvirtConnection(driver.ComputeDriver):
' data into image %(img_id)s (%(e)s)') % locals())
if FLAGS.libvirt_type == 'lxc':
disk.setup_container(basepath('disk'),
container_dir=container_dir,
nbd=FLAGS.use_cow_images)
self.container = disk.setup_container(basepath('disk'),
container_dir=container_dir,
use_cow=FLAGS.use_cow_images)
if FLAGS.libvirt_type == 'uml':
libvirt_utils.chown(basepath('disk'), 'root')

View File

@ -26,7 +26,7 @@ import shutil
from nova import exception
from nova import flags
from nova import utils
from nova.virt import disk
from nova.virt.disk import api as disk
from nova.virt import images
FLAGS = flags.FLAGS

View File

@ -40,7 +40,7 @@ from nova import log as logging
from nova import utils
from nova.compute import instance_types
from nova.compute import power_state
from nova.virt import disk
from nova.virt.disk import api as disk
from nova.virt.xenapi import HelperBase
from nova.virt.xenapi import volume_utils