Merge "Fix root disk not be detached after deleting lxc container"

This commit is contained in:
Jenkins
2013-10-15 19:43:58 +00:00
committed by Gerrit Code Review
3 changed files with 68 additions and 4 deletions

View File

@@ -137,3 +137,34 @@ class TestVirtDisk(test.NoDBTestCase):
]
self.assertEqual(self.executes, expected_commands)
def test_lxc_teardown_container_with_namespace_cleaned(self):
def proc_mounts(self, mount_point):
return None
self.stubs.Set(os.path, 'exists', lambda _: True)
self.stubs.Set(disk_api._DiskImage, '_device_for_path', proc_mounts)
expected_commands = []
disk_api.teardown_container('/mnt/loop/nopart', '/dev/loop0')
expected_commands += [
('losetup', '--detach', '/dev/loop0'),
]
disk_api.teardown_container('/mnt/loop/part', '/dev/loop0')
expected_commands += [
('losetup', '--detach', '/dev/loop0'),
]
disk_api.teardown_container('/mnt/nbd/nopart', '/dev/nbd15')
expected_commands += [
('qemu-nbd', '-d', '/dev/nbd15'),
]
disk_api.teardown_container('/mnt/nbd/part', '/dev/nbd15')
expected_commands += [
('qemu-nbd', '-d', '/dev/nbd15'),
]
self.assertEqual(self.executes, expected_commands)

View File

@@ -208,6 +208,8 @@ class _DiskImage(object):
self.mount_dir = mount_dir
self.use_cow = use_cow
self.device = None
# Internal
self._mkdir = False
self._mounter = None
@@ -239,6 +241,7 @@ class _DiskImage(object):
mount_name = os.path.basename(self.mount_dir or '')
self._mkdir = mount_name.startswith(self.tmp_prefix)
self.device = self._mounter.device
@property
def errors(self):
@@ -344,6 +347,8 @@ def setup_container(image, container_dir, use_cow=False):
It will mount the loopback image to the container directory in order
to create the root filesystem for the container.
Returns path of image device which is mounted to the container directory.
"""
img = _DiskImage(image=image, use_cow=use_cow, mount_dir=container_dir)
if not img.mount():
@@ -352,9 +357,11 @@ def setup_container(image, container_dir, use_cow=False):
{"image": img, "target": container_dir,
"errors": img.errors})
raise exception.NovaException(img.errors)
else:
return img.device
def teardown_container(container_dir):
def teardown_container(container_dir, container_root_device=None):
"""Teardown the container rootfs mounting once it is spawned.
It will umount the container that is mounted,
@@ -363,6 +370,17 @@ def teardown_container(container_dir):
try:
img = _DiskImage(image=None, mount_dir=container_dir)
img.teardown()
# Make sure container_root_device is released when teardown container.
if container_root_device:
if 'loop' in container_root_device:
LOG.debug(_("Release loop device %s"), container_root_device)
utils.execute('losetup', '--detach', container_root_device,
run_as_root=True, attempts=3)
else:
LOG.debug(_('Release nbd device %s'), container_root_device)
utils.execute('qemu-nbd', '-d', container_root_device,
run_as_root=True)
except Exception as exn:
LOG.exception(_('Failed to teardown container filesystem: %s'), exn)

View File

@@ -930,6 +930,13 @@ class LibvirtDriver(driver.ComputeDriver):
disk_dev)
if destroy_disks:
#NOTE(GuanQiang): teardown lxc container to avoid resource leak
if CONF.libvirt_type == 'lxc':
inst_path = libvirt_utils.get_instance_path(instance)
container_dir = os.path.join(inst_path, 'rootfs')
container_root_device = instance.get('root_device_name')
disk.teardown_container(container_dir, container_root_device)
self._delete_instance_files(instance)
self._cleanup_lvm(instance)
@@ -3126,10 +3133,18 @@ class LibvirtDriver(driver.ComputeDriver):
container_dir = os.path.join(inst_path, 'rootfs')
fileutils.ensure_tree(container_dir)
image = self.image_backend.image(instance, 'disk')
disk.setup_container(image.path,
container_root_device = disk.setup_container(image.path,
container_dir=container_dir,
use_cow=CONF.use_cow_images)
#Note(GuanQiang): save container root device name here, used for
# detaching the linked image device when deleting
# the lxc instance.
if container_root_device:
self.virtapi.instance_update(
nova_context.get_admin_context(), instance['uuid'],
{'root_device_name': container_root_device})
if xml:
try:
domain = self._conn.defineXML(xml)