Merge "GlusterFS: Using 'fallocate' instead of 'dd'"

This commit is contained in:
Jenkins 2015-08-07 19:25:01 +00:00 committed by Gerrit Code Review
commit f179315ae8
4 changed files with 75 additions and 92 deletions

View File

@ -90,8 +90,6 @@ class GlusterFsDriverTestCase(test.TestCase):
self.TEST_SHARES_CONFIG_FILE
self._configuration.glusterfs_mount_point_base = \
self.TEST_MNT_POINT_BASE
self._configuration.glusterfs_sparsed_volumes = True
self._configuration.glusterfs_qcow2_volumes = False
self._configuration.nas_secure_file_permissions = 'false'
self._configuration.nas_secure_file_operations = 'false'
self._configuration.nas_ip = None
@ -227,8 +225,8 @@ class GlusterFsDriverTestCase(test.TestCase):
self.assertEqual(3.0, provisioned_capacity)
def test_update_volume_stats_sparse(self):
"""_update_volume_stats_sparse with sparse files."""
def test_update_volume_stats_thin(self):
"""_update_volume_stats_thin with qcow2 files."""
drv = self._driver
rfsdriver = remotefs_drv.RemoteFSSnapDriver
@ -239,33 +237,7 @@ class GlusterFsDriverTestCase(test.TestCase):
data = {'total_capacity_gb': 10.0,
'free_capacity_gb': 2.0}
drv._stats = data
drv.configuration.glusterfs_sparsed_volumes = True
drv.configuration.glusterfs_qcow2_volumes = False
drv.configuration.max_over_subscription_ratio = 20.0
mock_get_provisioned_capacity.return_value = 8.0
drv._update_volume_stats()
data['max_over_subscription_ratio'] = 20.0
data['thick_provisioning_support'] = False
data['thin_provisioning_support'] = True
self.assertEqual(data, drv._stats)
self.assertTrue(mock_get_provisioned_capacity.called)
self.assertTrue(mock_update_volume_stats.called)
def test_update_volume_stats_qcow2(self):
"""_update_volume_stats_sparse with qcow2 files."""
drv = self._driver
rfsdriver = remotefs_drv.RemoteFSSnapDriver
with mock.patch.object(rfsdriver, '_update_volume_stats') as \
mock_update_volume_stats,\
mock.patch.object(drv, '_get_provisioned_capacity') as \
mock_get_provisioned_capacity:
data = {'total_capacity_gb': 10.0,
'free_capacity_gb': 2.0}
drv._stats = data
drv.configuration.glusterfs_sparsed_volumes = False
drv.configuration.glusterfs_qcow2_volumes = True
drv.configuration.nas_volume_prov_type = 'thin'
drv.configuration.max_over_subscription_ratio = 20.0
mock_get_provisioned_capacity.return_value = 8.0
drv._update_volume_stats()
@ -278,7 +250,7 @@ class GlusterFsDriverTestCase(test.TestCase):
self.assertTrue(mock_update_volume_stats.called)
def test_update_volume_stats_thick(self):
"""_update_volume_stats_sparse with raw files."""
"""_update_volume_stats_thick with raw files."""
drv = self._driver
rfsdriver = remotefs_drv.RemoteFSSnapDriver
@ -287,8 +259,7 @@ class GlusterFsDriverTestCase(test.TestCase):
data = {'total_capacity_gb': 10.0,
'free_capacity_gb': 2.0}
drv._stats = data
drv.configuration.glusterfs_sparsed_volumes = False
drv.configuration.glusterfs_qcow2_volumes = False
drv.configuration.nas_volume_prov_type = 'thick'
drv.configuration.max_over_subscription_ratio = 20.0
drv._update_volume_stats()
data['provisioned_capacity_gb'] = 8.0
@ -525,74 +496,68 @@ class GlusterFsDriverTestCase(test.TestCase):
return volume
def test_create_sparsed_volume(self):
def test_create_thin_volume(self):
drv = self._driver
volume = self._simple_volume()
self.override_config('glusterfs_sparsed_volumes', True)
self._configuration.nas_volume_prov_type = 'thin'
with mock.patch.object(drv, '_create_sparsed_file') as \
mock_create_sparsed_file,\
with mock.patch.object(drv, '_create_qcow2_file') as \
mock_create_qcow2_file,\
mock.patch.object(drv, '_set_rw_permissions_for_all') as \
mock_set_rw_permissions_for_all:
drv._do_create_volume(volume)
volume_path = drv.local_path(volume)
volume_size = volume['size']
mock_create_sparsed_file.assert_called_once_with(volume_path,
volume_size)
mock_create_qcow2_file.assert_called_once_with(volume_path,
volume_size)
mock_set_rw_permissions_for_all.\
assert_called_once_with(volume_path)
def test_create_nonsparsed_volume(self):
def test_create_thick_fallocate_volume(self):
drv = self._driver
volume = self._simple_volume()
old_value = self._configuration.glusterfs_sparsed_volumes
self._configuration.glusterfs_sparsed_volumes = False
self._configuration.nas_volume_prov_type = 'thick'
with mock.patch.object(drv, '_create_regular_file') as \
mock_create_regular_file,\
with mock.patch.object(drv, '_fallocate') as \
mock_fallocate,\
mock.patch.object(drv, '_set_rw_permissions_for_all') as \
mock_set_rw_permissions_for_all:
drv._do_create_volume(volume)
volume_path = drv.local_path(volume)
volume_size = volume['size']
mock_fallocate.assert_called_once_with(volume_path,
volume_size)
mock_set_rw_permissions_for_all.\
assert_called_once_with(volume_path)
def test_create_thick_dd_volume(self):
drv = self._driver
volume = self._simple_volume()
self._configuration.nas_volume_prov_type = 'thick'
with mock.patch.object(drv, '_fallocate') as \
mock_fallocate,\
mock.patch.object(drv, '_create_regular_file') as \
mock_create_regular_file,\
mock.patch.object(drv, '_set_rw_permissions_for_all') as \
mock_set_rw_permissions_for_all:
mock_fallocate.side_effect = putils.ProcessExecutionError(
stderr='Fallocate: Operation not supported.')
drv._do_create_volume(volume)
volume_path = drv.local_path(volume)
volume_size = volume['size']
mock_fallocate.assert_called_once_with(volume_path,
volume_size)
mock_create_regular_file.assert_called_once_with(volume_path,
volume_size)
mock_set_rw_permissions_for_all.\
assert_called_once_with(volume_path)
self._configuration.glusterfs_sparsed_volumes = old_value
def test_create_qcow2_volume(self):
drv = self._driver
volume = self._simple_volume()
old_value = self._configuration.glusterfs_qcow2_volumes
self._configuration.glusterfs_qcow2_volumes = True
with mock.patch.object(drv, '_execute') as mock_execute,\
mock.patch.object(drv, '_set_rw_permissions_for_all') as \
mock_set_rw_permissions_for_all:
hashed = drv._get_hash_str(volume['provider_location'])
path = '%s/%s/volume-%s' % (self.TEST_MNT_POINT_BASE,
hashed,
self.VOLUME_UUID)
drv._do_create_volume(volume)
volume_path = drv.local_path(volume)
volume_size = volume['size']
mock_execute.assert_called_once_with('qemu-img', 'create',
'-f', 'qcow2', '-o',
'preallocation=metadata',
path,
str(volume_size * units.Gi),
run_as_root=True)
mock_set_rw_permissions_for_all.\
assert_called_once_with(volume_path)
self._configuration.glusterfs_qcow2_volumes = old_value
def test_create_volume_should_ensure_glusterfs_mounted(self):
"""create_volume ensures shares provided in config are mounted."""

View File

@ -16,6 +16,7 @@
import errno
import os
import stat
import warnings
from os_brick.remotefs import remotefs as remotefs_brick
from oslo_concurrency import processutils
@ -33,18 +34,11 @@ from cinder.volume.drivers import remotefs as remotefs_drv
LOG = logging.getLogger(__name__)
volume_opts = [
cfg.StrOpt('glusterfs_shares_config',
default='/etc/cinder/glusterfs_shares',
help='File with the list of available gluster shares'),
cfg.BoolOpt('glusterfs_sparsed_volumes',
default=True,
help=('Create volumes as sparsed files which take no space.'
'If set to False volume is created as regular file.'
'In such case volume creation takes a lot of time.')),
cfg.BoolOpt('glusterfs_qcow2_volumes',
default=False,
help=('Create volumes as QCOW2 files rather than raw files.')),
cfg.StrOpt('glusterfs_mount_point_base',
default='$state_path/mnt',
help='Base dir containing mount points for gluster shares.'),
@ -171,8 +165,7 @@ class GlusterfsDriver(remotefs_drv.RemoteFSSnapDriver, driver.CloneableVD,
global_capacity = data['total_capacity_gb']
global_free = data['free_capacity_gb']
thin_enabled = (self.configuration.glusterfs_sparsed_volumes or
self.configuration.glusterfs_qcow2_volumes)
thin_enabled = self.configuration.nas_volume_prov_type == 'thin'
if thin_enabled:
provisioned_capacity = self._get_provisioned_capacity()
else:
@ -229,7 +222,7 @@ class GlusterfsDriver(remotefs_drv.RemoteFSSnapDriver, driver.CloneableVD,
LOG.debug("will copy from snapshot at %s", path_to_snap_img)
if self.configuration.glusterfs_qcow2_volumes:
if self.configuration.nas_volume_prov_type == 'thin':
out_format = 'qcow2'
else:
out_format = 'raw'
@ -349,13 +342,19 @@ class GlusterfsDriver(remotefs_drv.RemoteFSSnapDriver, driver.CloneableVD,
LOG.error(msg)
raise exception.InvalidVolume(reason=msg)
if self.configuration.glusterfs_qcow2_volumes:
if self.configuration.nas_volume_prov_type == 'thin':
self._create_qcow2_file(volume_path, volume_size)
else:
if self.configuration.glusterfs_sparsed_volumes:
self._create_sparsed_file(volume_path, volume_size)
else:
self._create_regular_file(volume_path, volume_size)
try:
self._fallocate(volume_path, volume_size)
except processutils.ProcessExecutionError as exc:
if 'Operation not supported' in exc.stderr:
warnings.warn('Fallocate not supported by current version '
'of glusterfs. So falling back to dd.')
self._create_regular_file(volume_path, volume_size)
else:
fileutils.delete_if_exists(volume_path)
raise
self._set_rw_permissions_for_all(volume_path)

View File

@ -81,7 +81,19 @@ nas_opts = [
cfg.StrOpt('nas_mount_options',
default=None,
help=('Options used to mount the storage backend file system '
'where Cinder volumes are stored.'))
'where Cinder volumes are stored.')),
]
old_vol_type_opts = [cfg.DeprecatedOpt('glusterfs_sparsed_volumes'),
cfg.DeprecatedOpt('glusterfs_qcow2_volumes')]
volume_opts = [
cfg.StrOpt('nas_volume_prov_type',
default='thin',
choices=['thin', 'thick'],
deprecated_opts=old_vol_type_opts,
help=('Provisioning type that will be used when '
'creating volumes.')),
]
CONF = cfg.CONF
@ -137,6 +149,7 @@ class RemoteFSDriver(driver.LocalVD, driver.TransferVD, driver.BaseVD):
if self.configuration:
self.configuration.append_config_values(nas_opts)
self.configuration.append_config_values(volume_opts)
def check_for_setup_error(self):
"""Just to override parent behavior."""
@ -322,6 +335,11 @@ class RemoteFSDriver(driver.LocalVD, driver.TransferVD, driver.BaseVD):
'count=%d' % block_count,
run_as_root=self._execute_as_root)
def _fallocate(self, path, size):
"""Creates a raw file of given size in GiB using fallocate."""
self._execute('fallocate', '--length=%sG' % size,
path, run_as_root=True)
def _create_qcow2_file(self, path, size_gb):
"""Creates a QCOW2 file of a given size in GiB."""

View File

@ -103,6 +103,7 @@ netapp_nfs_find: RegExpFilter, find, root, find, ^[/]*([^/\0]+(/+)?)*$, -maxdept
# cinder/volume/drivers/glusterfs.py
chgrp: CommandFilter, chgrp, root
umount: CommandFilter, umount, root
fallocate: CommandFilter, fallocate, root
# cinder/volumes/drivers/hds/hds.py:
hus-cmd: CommandFilter, hus-cmd, root