Skip to content

Commit

Permalink
Add support for LXC volumes.
Browse files Browse the repository at this point in the history
This introduces volume support for LXC containers in Nova.
The way that this works is that when a device is attached to an
LXC container is that, the xml is parsed to find out which device to
connect to the LXC container, binds the device to the LXC container,
and allow the device through cgroups.

This bug fixes LP: #924601.

Change-Id: I00b41426ae8354b3cd4212655ecb48319a63aa9b
Signed-off-by: Chuck Short <chuck.short@canonical.com>
  • Loading branch information
Chuck Short committed Feb 8, 2012
1 parent 799713e commit e40b659
Show file tree
Hide file tree
Showing 3 changed files with 99 additions and 2 deletions.
21 changes: 21 additions & 0 deletions nova/tests/test_libvirt.py
Expand Up @@ -195,6 +195,27 @@ def test_libvirt_rbd_driver(self):
libvirt_driver.disconnect_volume(connection_info, mount_device)
connection_info = vol_driver.terminate_connection(vol, self.connr)

def test_libvirt_lxc_volume(self):
self.stubs.Set(os.path, 'exists', lambda x: True)
vol_driver = volume_driver.ISCSIDriver()
libvirt_driver = volume.LibvirtISCSIVolumeDriver(self.fake_conn)
location = '10.0.2.15:3260'
name = 'volume-00000001'
iqn = 'iqn.2010-10.org.openstack:%s' % name
vol = {'id': 1,
'name': name,
'provider_auth': None,
'provider_location': '%s,fake %s' % (location, iqn)}
connection_info = vol_driver.initialize_connection(vol, self.connr)
mount_device = "vde"
xml = libvirt_driver.connect_volume(connection_info, mount_device)
tree = xml_to_tree(xml)
dev_str = '/dev/disk/by-path/ip-%s-iscsi-%s-lun-0' % (location, iqn)
self.assertEqual(tree.get('type'), 'block')
self.assertEqual(tree.find('./source').get('dev'), dev_str)
libvirt_driver.disconnect_volume(connection_info, mount_device)
connection_info = vol_driver.terminate_connection(vol, self.connr)


class CacheConcurrencyTestCase(test.TestCase):
def setUp(self):
Expand Down
20 changes: 20 additions & 0 deletions nova/virt/disk/api.py
Expand Up @@ -106,6 +106,26 @@ def extend(image, size):
utils.execute('resize2fs', image, check_exit_code=False)


def bind(src, target, instance_name):
"""Bind device to a filesytem"""
if src:
utils.execute('touch', target, run_as_root=True)
utils.execute('mount', '-o', 'bind', src, target,
run_as_root=True)
s = os.stat(src)
cgroup_info = "c %s:%s rwm" % (os.major(s.st_rdev),
os.minor(s.st_rdev))
cgroups_path = \
"/sys/fs/cgroup/devices/sysdefault/libvirt/lxc/%s/devices.allow" \
% instance_name
utils.execute('echo', '>', cgroup_info, cgroups_path, run_as_root=True)


def unbind(target):
if target:
utils.execute('umount', target, run_as_root=True)


class _DiskImage(object):
"""Provide operations on a disk image file."""

Expand Down
60 changes: 58 additions & 2 deletions nova/virt/libvirt/connection.py
Expand Up @@ -449,7 +449,11 @@ def attach_volume(self, connection_info, instance_name, mountpoint):
xml = self.volume_driver_method('connect_volume',
connection_info,
mount_device)
virt_dom.attachDevice(xml)

if FLAGS.libvirt_type == 'lxc':
self._attach_lxc_volume(xml, virt_dom, instance_name)
else:
virt_dom.attachDevice(xml)

@staticmethod
def _get_disk_xml(xml, device):
Expand All @@ -476,12 +480,64 @@ def detach_volume(self, connection_info, instance_name, mountpoint):
xml = self._get_disk_xml(virt_dom.XMLDesc(0), mount_device)
if not xml:
raise exception.DiskNotFound(location=mount_device)
virt_dom.detachDevice(xml)
if FLAGS.libvirt_type == 'lxc':
self._detach_lxc_volume(xml, vort_dom, instance_name)
else:
virt_dom.detachDevice(xml)
finally:
self.volume_driver_method('disconnect_volume',
connection_info,
mount_device)

@exception.wrap_exception()
def _attach_lxc_volume(self, xml, virt_dom, instance_name):
LOG.info(_('attaching LXC block device'))

lxc_container_root = self.get_lxc_container_root(virt_dom)
lxc_host_volume = self.get_lxc_host_device(xml)
lxc_container_device = self.get_lxc_container_target(xml)
lxc_container_target = "%s/%s" % (lxc_container_root,
lxc_container_device)

if lxc_container_target:
disk.bind(lxc_host_volume, lxc_container_target, instance_name)

@exception.wrap_exception()
def _detach_lxc_volume(self, xml, virt_dom, instance_name):
LOG.info(_('detaching LXC block device'))

lxc_container_root = self.get_lxc_container_root(virt_dom)
lxc_host_volume = self.get_lxc_host_device(xml)
lxc_container_device = self.get_lxc_container_target(xml)
lxc_container_target = "%s/%s" % (lxc_container_root,
lxc_container_device)

if lxc_container_target:
disk.unbind(lxc_container_target)

@staticmethod
def get_lxc_container_root(virt_dom):
xml = virt_dom.XMLDesc(0)
doc = ElementTree.fromstring(xml)
filesystem_block = doc.findall('./devices/filesystem')
for cnt, filesystem_nodes in enumerate(filesystem_block):
return filesystem_nodes[cnt].get('dir')

@staticmethod
def get_lxc_host_device(xml):
dom = minidom.parseString(xml)

for device in dom.getElementsByTagName('source'):
return device.getAttribute('dev')

@staticmethod
def get_lxc_container_target(xml):
dom = minidom.parseString(xml)

for device in dom.getElementsByTagName('target'):
filesystem = device.getAttribute('dev')
return 'dev/%s' % filesystem

@exception.wrap_exception()
def snapshot(self, context, instance, image_href):
"""Create snapshot from a running VM instance.
Expand Down

1 comment on commit e40b659

@heiher
Copy link

@heiher heiher commented on e40b659 Oct 22, 2012

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't work after restart....

Please sign in to comment.