Add support for zfs backend

Add support for zfs ephemeral storage backends. Also
use nova.virt.driver.block_device_info_get_ephemerals
method for determining ephemeral information.

Change-Id: Ie85e12ca22118e6439e9ebfd88af1ed53bfaebd7
Signed-off-by: Chuck Short <chuck.short@canonical.com>
This commit is contained in:
Chuck Short 2016-07-06 13:40:41 -04:00
parent bb20ba8c6d
commit 3f9f39e32b
3 changed files with 122 additions and 24 deletions

View File

@ -2,4 +2,4 @@
# This file should be owned by (and only-writable by) the root user
[Filters]
tar: CommandFilter, tar, root
zfs: CommandFilter, zfs, root

View File

@ -126,6 +126,7 @@ class LXDDriverTest(test.NoDBTestCase):
lxd_driver.setup_image = mock.Mock()
lxd_driver.vif_driver = mock.Mock()
lxd_driver.firewall_driver = mock.Mock()
lxd_driver._add_ephemeral = mock.Mock()
lxd_driver.create_profile = mock.Mock(return_value={
'name': instance.name, 'config': {}, 'devices': {}})
@ -146,6 +147,8 @@ class LXDDriverTest(test.NoDBTestCase):
instance, network_info)
fd.apply_instance_filter.assert_called_once_with(
instance, network_info)
lxd_driver._add_ephemeral.assert_called_once_with(
block_device_info, lxd_driver.client.host_info, instance)
def test_spawn_already_exists(self):
"""InstanceExists is raised if the container already exists."""
@ -165,6 +168,39 @@ class LXDDriverTest(test.NoDBTestCase):
ctx, instance, image_meta, injected_files, admin_password,
None, None)
@mock.patch('os.stat')
@mock.patch('nova.virt.lxd.driver.container_utils.get_container_storage')
@mock.patch.object(driver.utils, 'execute')
@mock.patch('nova.virt.driver.block_device_info_get_ephemerals')
def test_add_ephemerals_with_zfs(
self, block_device_info_get_ephemerals, execute,
get_container_storage, stat):
ctx = context.get_admin_context()
block_device_info_get_ephemerals.return_value = [
{'virtual_name': 'ephemerals0'}]
instance = fake_instance.fake_instance_obj(ctx, name='test')
block_device_info = mock.Mock()
lxd_config = {'environment': {'storage': 'zfs'},
'config': {'storage.zfs_pool_name': 'zfs'}}
get_container_storage.return_value = '/path'
stat.return_value.st_uid = 1234
lxd_driver = driver.LXDDriver(None)
lxd_driver.init_host(None)
lxd_driver._add_ephemeral(block_device_info, lxd_config, instance)
block_device_info_get_ephemerals.assert_called_once_with(
block_device_info)
expected_calls = [
mock.call(
'zfs', 'create', '-o', 'mountpoint=/path', '-o', 'quota=0G',
'zfs/instance-00000001-ephemeral', run_as_root=True),
mock.call('chown', 1234, '/path', run_as_root=True)
]
self.assertEqual(expected_calls, execute.call_args_list)
def test_destroy(self):
mock_profile = mock.Mock()
mock_container = mock.Mock()
@ -202,22 +238,52 @@ class LXDDriverTest(test.NoDBTestCase):
instance = fake_instance.fake_instance_obj(ctx, name='test')
network_info = [mock.Mock()]
instance_dir = utils.get_instance_dir(instance.name)
block_device_info = mock.Mock()
lxd_driver = driver.LXDDriver(None)
lxd_driver.init_host(None)
lxd_driver.vif_driver = mock.Mock()
lxd_driver.firewall_driver = mock.Mock()
lxd_driver._remove_ephemeral = mock.Mock()
lxd_driver.cleanup(ctx, instance, network_info)
lxd_driver.cleanup(ctx, instance, network_info, block_device_info)
lxd_driver.vif_driver.unplug.assert_called_once_with(
instance, network_info[0])
lxd_driver.firewall_driver.unfilter_instance.assert_called_once_with(
instance, network_info)
lxd_driver._remove_ephemeral.assert_called_once_with(
block_device_info, lxd_driver.client.host_info, instance)
execute.assert_called_once_with(
'chown', '-R', 'user:user', instance_dir, run_as_root=True)
rmtree.assert_called_once_with(instance_dir)
@mock.patch.object(driver.utils, 'execute')
@mock.patch('nova.virt.driver.block_device_info_get_ephemerals')
def test_remove_emepheral_with_zfs(
self, block_device_info_get_ephemerals, execute):
block_device_info_get_ephemerals.return_value = [
{'virtual_name': 'ephemerals0'}]
ctx = context.get_admin_context()
instance = fake_instance.fake_instance_obj(ctx, name='test')
block_device_info = mock.Mock()
lxd_config = {'environment': {'storage': 'zfs'},
'config': {'storage.zfs_pool_name': 'zfs'}}
lxd_driver = driver.LXDDriver(None)
lxd_driver.init_host(None)
lxd_driver._remove_ephemeral(block_device_info, lxd_config, instance)
block_device_info_get_ephemerals.assert_called_once_with(
block_device_info)
expected_calls = [
mock.call('zfs', 'destroy', 'zfs/instance-00000001-ephemeral',
run_as_root=True)
]
self.assertEqual(expected_calls, execute.call_args_list)
def test_reboot(self):
ctx = context.get_admin_context()
instance = fake_instance.fake_instance_obj(ctx, name='test')

View File

@ -218,11 +218,13 @@ class LXDDriver(driver.ComputeDriver):
}
LOG.debug(container_config)
container = self.client.containers.create(container_config, wait=True)
container.start()
# XXX: rockstar (6 Jul 2016) - _add_ephemeral is only used here,
# and hasn't really been audited. It may need a cleanup.
self._add_ephemeral(block_device_info, instance)
# and hasn't really been audited. It may need a cleanup
lxd_config = self.client.host_info
self._add_ephemeral(block_device_info, lxd_config, instance)
container.start()
def destroy(self, context, instance, network_info, block_device_info=None,
destroy_disks=True, migrate_data=None):
@ -257,6 +259,11 @@ class LXDDriver(driver.ComputeDriver):
pass
self.firewall_driver.unfilter_instance(instance, network_info)
# XXX: zulcss (14 Jul 2016) - _remove_ephemeral is only used here,
# and hasn't really been audited. It may need a cleanup
lxd_config = self.client.host_info
self._remove_ephemeral(block_device_info, lxd_config, instance)
name = pwd.getpwuid(os.getuid()).pw_name
container_dir = container_utils.get_instance_dir(instance.name)
@ -384,26 +391,51 @@ class LXDDriver(driver.ComputeDriver):
# have not been through the cleanup process. We know the cleanup process
# is complete when there is no more code below this comment, and the
# comment can be removed.
def _add_ephemeral(self, block_device_info, instance):
if instance.get('ephemeral_gb', 0) != 0:
ephemerals = block_device_info.get('ephemerals', [])
def _add_ephemeral(self, block_device_info, lxd_config, instance):
ephemeral_storage = driver.block_device_info_get_ephemerals(
block_device_info)
if ephemeral_storage:
storage_driver = lxd_config['environment']['storage']
container_root = container_utils.get_container_rootfs(
instance.name)
root_dir = container_utils.get_container_rootfs(instance.name)
if ephemerals == []:
ephemeral_src = container_utils.get_container_storage(
ephemerals['virtual_name'], instance.name)
fileutils.ensure_tree(ephemeral_src)
utils.execute('chown',
os.stat(root_dir).st_uid,
ephemeral_src, run_as_root=True)
else:
for id, ephx in enumerate(ephemerals):
ephemeral_src = container_utils.get_container_storage(
ephx['virtual_name'], instance.name)
fileutils.ensure_tree(ephemeral_src)
utils.execute('chown',
os.stat(root_dir).st_uid,
ephemeral_src, run_as_root=True)
for ephemeral in ephemeral_storage:
storage_dir = container_utils.get_container_storage(
ephemeral['virtual_name'], instance.name)
if storage_driver == 'zfs':
zfs_pool = lxd_config['config']['storage.zfs_pool_name']
utils.execute(
'zfs', 'create',
'-o', 'mountpoint=%s' % storage_dir,
'-o', 'quota=%sG' % instance.ephemeral_gb,
'%s/%s-ephemeral' % (zfs_pool, instance.name),
run_as_root=True)
else:
reason = _('Unsupport LXD storage detected. Supported'
' storage drivers is zfs.')
raise exception.NovaException(reason)
utils.execute(
'chown', os.stat(container_root).st_uid,
storage_dir, run_as_root=True)
def _remove_ephemeral(self, block_device_info, lxd_config, instance):
"""Remove empeheral device from the instance."""
ephemeral_storage = driver.block_device_info_get_ephemerals(
block_device_info)
if ephemeral_storage:
storage_driver = lxd_config['environment']['storage']
for ephemeral in ephemeral_storage:
if storage_driver == 'zfs':
zfs_pool = \
lxd_config['config']['storage.zfs_pool_name']
utils.execute(
'zfs', 'destroy',
'%s/%s-ephemeral' % (zfs_pool, instance.name),
run_as_root=True)
def snapshot(self, context, instance, image_id, update_task_state):
lock_path = str(os.path.join(CONF.instances_path, 'locks'))