diff --git a/overlay_volumes/Pike/overlay_volumes_Cinder-Pike.patch b/overlay_volumes/Pike/overlay_volumes_Cinder-Pike.patch index 498810b..ec7e4f5 100644 --- a/overlay_volumes/Pike/overlay_volumes_Cinder-Pike.patch +++ b/overlay_volumes/Pike/overlay_volumes_Cinder-Pike.patch @@ -1,5 +1,5 @@ diff --git cinder/tests/unit/volume/drivers/test_quobyte.py cinder/tests/unit/volume/drivers/test_quobyte.py -index 9ab535f..bed5742 100644 +index 9ab535f..3f7195c 100644 --- cinder/tests/unit/volume/drivers/test_quobyte.py +++ cinder/tests/unit/volume/drivers/test_quobyte.py @@ -15,14 +15,18 @@ @@ -115,7 +115,7 @@ index 9ab535f..bed5742 100644 + self._driver._create_regular_file(tmp_path, test_size) + + qb_exec_mock.assert_called_once_with( -+ 'fallocate', '-l', '%sG' % test_size, tmp_path, ++ 'fallocate', '-l', '%sGiB' % test_size, tmp_path, + run_as_root=self._driver._execute_as_root) + + @mock.patch.object(remotefs.RemoteFSSnapDriverDistributed, @@ -364,73 +364,7 @@ index 9ab535f..bed5742 100644 drv.local_path(volume)) def test_mount_quobyte_should_mount_correctly(self): -@@ -220,11 +509,73 @@ class QuobyteDriverTestCase(test.TestCase): - mock_execute.assert_has_calls([mkdir_call, mount_call], - any_order=False) - -+ @mock.patch.object(image_utils, "qemu_img_info") -+ def test_optimize_volume_not(self, iu_qii_mock): -+ drv = self._driver -+ vol = self._simple_volume() -+ vol.size = 3 -+ img_data = mock.Mock() -+ img_data.disk_size = 3 * units.Gi -+ iu_qii_mock.return_value = img_data -+ drv._execute = mock.Mock() -+ drv._create_regular_file = mock.Mock() -+ drv.local_path = mock.Mock(return_value="/some/path") -+ -+ drv.optimize_volume(vol) -+ -+ iu_qii_mock.assert_called_once_with("/some/path", -+ run_as_root=drv._execute_as_root) -+ self.assertFalse(drv._execute.called) -+ self.assertFalse(drv._create_regular_file.called) -+ -+ @mock.patch.object(image_utils, "qemu_img_info") -+ def test_optimize_volume_sparse(self, iu_qii_mock): -+ drv = self._driver -+ vol = self._simple_volume() -+ vol.size = 3 -+ img_data = mock.Mock() -+ img_data.disk_size = 2 * units.Gi -+ iu_qii_mock.return_value = img_data -+ drv._execute = mock.Mock() -+ drv._create_regular_file = mock.Mock() -+ drv.local_path = mock.Mock(return_value="/some/path") -+ -+ drv.optimize_volume(vol) -+ -+ iu_qii_mock.assert_called_once_with(drv.local_path(), -+ run_as_root=drv._execute_as_root) -+ drv._execute.assert_called_once_with( -+ 'truncate', '-s', '%sG' % vol.size, drv.local_path(), -+ run_as_root=drv._execute_as_root) -+ self.assertFalse(drv._create_regular_file.called) -+ -+ @mock.patch.object(image_utils, "qemu_img_info") -+ def test_optimize_volume_regular(self, iu_qii_mock): -+ drv = self._driver -+ drv.configuration.quobyte_qcow2_volumes = False -+ drv.configuration.quobyte_sparsed_volumes = False -+ vol = self._simple_volume() -+ vol.size = 3 -+ img_data = mock.Mock() -+ img_data.disk_size = 2 * units.Gi -+ iu_qii_mock.return_value = img_data -+ drv._execute = mock.Mock() -+ drv._create_regular_file = mock.Mock() -+ drv.local_path = mock.Mock(return_value="/some/path") -+ -+ drv.optimize_volume(vol) -+ -+ iu_qii_mock.assert_called_once_with(drv.local_path(), -+ run_as_root=drv._execute_as_root) -+ self.assertFalse(drv._execute.called) -+ drv._create_regular_file.assert_called_once_with(drv.local_path(), -+ vol.size) -+ - def test_get_hash_str(self): +@@ -224,7 +513,7 @@ class QuobyteDriverTestCase(test.TestCase): """_get_hash_str should calculation correct value.""" drv = self._driver @@ -439,7 +373,7 @@ index 9ab535f..bed5742 100644 drv._get_hash_str(self.TEST_QUOBYTE_VOLUME)) def test_get_available_capacity_with_df(self): -@@ -346,6 +697,32 @@ class QuobyteDriverTestCase(test.TestCase): +@@ -346,6 +635,32 @@ class QuobyteDriverTestCase(test.TestCase): qb_snso_mock.assert_called_once_with(is_new_cinder_install=mock.ANY) @@ -472,7 +406,7 @@ index 9ab535f..bed5742 100644 def test_check_for_setup_error_throws_quobyte_volume_url_not_set(self): """check_for_setup_error throws if 'quobyte_volume_url' is not set.""" drv = self._driver -@@ -425,6 +802,7 @@ class QuobyteDriverTestCase(test.TestCase): +@@ -425,6 +740,7 @@ class QuobyteDriverTestCase(test.TestCase): updates = {'id': self.VOLUME_UUID, 'provider_location': self.TEST_QUOBYTE_VOLUME, 'display_name': 'volume-%s' % self.VOLUME_UUID, @@ -480,7 +414,7 @@ index 9ab535f..bed5742 100644 'size': 10, 'status': 'available'} -@@ -541,6 +919,9 @@ class QuobyteDriverTestCase(test.TestCase): +@@ -541,6 +857,9 @@ class QuobyteDriverTestCase(test.TestCase): mock_local_path_volume, \ mock.patch.object(self._driver, '_local_path_volume_info') as \ mock_local_path_volume_info: @@ -490,7 +424,7 @@ index 9ab535f..bed5742 100644 mock_local_volume_dir.return_value = self.TEST_MNT_POINT mock_active_image_from_info.return_value = volume_filename mock_local_path_volume.return_value = volume_path -@@ -560,23 +941,77 @@ class QuobyteDriverTestCase(test.TestCase): +@@ -560,23 +879,77 @@ class QuobyteDriverTestCase(test.TestCase): mock_delete_if_exists.assert_any_call(volume_path) mock_delete_if_exists.assert_any_call(info_file) @@ -573,7 +507,7 @@ index 9ab535f..bed5742 100644 def test_delete_should_not_delete_if_provider_location_not_provided(self): """delete_volume shouldn't delete if provider_location missed.""" -@@ -634,15 +1069,7 @@ class QuobyteDriverTestCase(test.TestCase): +@@ -634,15 +1007,7 @@ class QuobyteDriverTestCase(test.TestCase): dest_vol_path = os.path.join(vol_dir, dest_volume['name']) info_path = os.path.join(vol_dir, src_volume['name']) + '.info' @@ -590,23 +524,21 @@ index 9ab535f..bed5742 100644 snap_file = dest_volume['name'] + '.' + snapshot['id'] snap_path = os.path.join(vol_dir, snap_file) -@@ -663,7 +1090,8 @@ class QuobyteDriverTestCase(test.TestCase): +@@ -663,7 +1028,7 @@ class QuobyteDriverTestCase(test.TestCase): {'active': snap_file, snapshot['id']: snap_file}) image_utils.qemu_img_info = mock.Mock(return_value=img_info) - drv._set_rw_permissions_for_all = mock.Mock() + drv._set_rw_permissions = mock.Mock() -+ drv.optimize_volume = mock.Mock() drv._copy_volume_from_snapshot(snapshot, dest_volume, size) -@@ -675,7 +1103,190 @@ class QuobyteDriverTestCase(test.TestCase): +@@ -675,7 +1040,183 @@ class QuobyteDriverTestCase(test.TestCase): dest_vol_path, 'raw', run_as_root=self._driver._execute_as_root)) - drv._set_rw_permissions_for_all.assert_called_once_with(dest_vol_path) + drv._set_rw_permissions.assert_called_once_with(dest_vol_path) -+ drv.optimize_volume.assert_called_once_with(dest_volume) + + @mock.patch.object(os, "access", return_value=True) + def test_copy_volume_from_snapshot_cached(self, os_ac_mock): @@ -649,7 +581,6 @@ index 9ab535f..bed5742 100644 + image_utils.qemu_img_info = mock.Mock(return_value=img_info) + drv._set_rw_permissions = mock.Mock() + shutil.copyfile = mock.Mock() -+ drv.optimize_volume = mock.Mock() + + drv._copy_volume_from_snapshot(snapshot, dest_volume, size) + @@ -663,7 +594,6 @@ index 9ab535f..bed5742 100644 + drv._local_volume_from_snap_cache_path(snapshot), os.F_OK) + shutil.copyfile.assert_called_once_with(cache_path, dest_vol_path) + drv._set_rw_permissions.assert_called_once_with(dest_vol_path) -+ drv.optimize_volume.assert_called_once_with(dest_volume) + + @mock.patch.object(os, "symlink") + @mock.patch.object(os, "access", return_value=False) @@ -710,7 +640,6 @@ index 9ab535f..bed5742 100644 + image_utils.qemu_img_info = mock.Mock(return_value=img_info) + drv._set_rw_permissions = mock.Mock() + drv._create_overlay_volume_from_snapshot = mock.Mock() -+ drv.optimize_volume = mock.Mock() + + drv._copy_volume_from_snapshot(snapshot, dest_volume, size) + @@ -731,7 +660,6 @@ index 9ab535f..bed5742 100644 + drv._create_overlay_volume_from_snapshot.assert_called_once_with( + dest_volume, snapshot, size, 'qcow2') + drv._set_rw_permissions.assert_called_once_with(dest_vol_path) -+ drv.optimize_volume.assert_called_once_with(dest_volume) + + def test_copy_volume_from_snapshot_not_cached(self): + drv = self._driver @@ -774,7 +702,6 @@ index 9ab535f..bed5742 100644 + image_utils.qemu_img_info = mock.Mock(return_value=img_info) + drv._set_rw_permissions = mock.Mock() + shutil.copyfile = mock.Mock() -+ drv.optimize_volume = mock.Mock() + + drv._copy_volume_from_snapshot(snapshot, dest_volume, size) + @@ -788,11 +715,10 @@ index 9ab535f..bed5742 100644 + run_as_root=self._driver._execute_as_root)) + shutil.copyfile.assert_called_once_with(cache_path, dest_vol_path) + drv._set_rw_permissions.assert_called_once_with(dest_vol_path) -+ drv.optimize_volume.assert_called_once_with(dest_volume) def test_create_volume_from_snapshot_status_not_available(self): """Expect an error when the snapshot's status is not 'available'.""" -@@ -719,14 +1330,12 @@ class QuobyteDriverTestCase(test.TestCase): +@@ -719,14 +1260,12 @@ class QuobyteDriverTestCase(test.TestCase): drv._ensure_shares_mounted = mock.Mock() drv._find_share = mock.Mock(return_value=self.TEST_QUOBYTE_VOLUME) @@ -808,10 +734,10 @@ index 9ab535f..bed5742 100644 assert_called_once_with(snap_ref, new_volume, new_volume['size'])) diff --git cinder/volume/drivers/quobyte.py cinder/volume/drivers/quobyte.py -index bf6f231..238a331 100644 +index bf6f231..7aed494 100644 --- cinder/volume/drivers/quobyte.py +++ cinder/volume/drivers/quobyte.py -@@ -17,13 +17,18 @@ +@@ -17,13 +17,17 @@ import errno import os import psutil @@ -823,14 +749,13 @@ index bf6f231..238a331 100644 from oslo_log import log as logging from oslo_utils import fileutils +from oslo_utils.fnmatch import fnmatch -+from oslo_utils import units from cinder import compute +from cinder import coordination from cinder import exception from cinder.i18n import _ from cinder.image import image_utils -@@ -32,7 +37,7 @@ from cinder import utils +@@ -32,7 +36,7 @@ from cinder import utils from cinder.volume import configuration from cinder.volume.drivers import remotefs as remotefs_drv @@ -839,7 +764,7 @@ index bf6f231..238a331 100644 LOG = logging.getLogger(__name__) -@@ -45,8 +50,7 @@ volume_opts = [ +@@ -45,8 +49,7 @@ volume_opts = [ cfg.BoolOpt('quobyte_sparsed_volumes', default=True, help=('Create volumes as sparse files which take no space.' @@ -849,7 +774,7 @@ index bf6f231..238a331 100644 cfg.BoolOpt('quobyte_qcow2_volumes', default=True, help=('Create volumes as QCOW2 files rather than raw files.')), -@@ -54,6 +58,21 @@ volume_opts = [ +@@ -54,6 +57,21 @@ volume_opts = [ default='$state_path/mnt', help=('Base dir containing the mount point' ' for the Quobyte volume.')), @@ -871,7 +796,7 @@ index bf6f231..238a331 100644 ] CONF = cfg.CONF -@@ -86,7 +105,9 @@ class QuobyteDriver(remotefs_drv.RemoteFSSnapDriverDistributed): +@@ -86,7 +104,9 @@ class QuobyteDriver(remotefs_drv.RemoteFSSnapDriverDistributed): 1.1.3 - Explicitely mounts Quobyte volumes w/o xattrs 1.1.4 - Fixes capability to configure redundancy in quobyte_volume_url 1.1.5 - Enables extension of volumes with snapshots @@ -882,7 +807,7 @@ index bf6f231..238a331 100644 """ driver_volume_type = 'quobyte' -@@ -97,6 +118,8 @@ class QuobyteDriver(remotefs_drv.RemoteFSSnapDriverDistributed): +@@ -97,6 +117,8 @@ class QuobyteDriver(remotefs_drv.RemoteFSSnapDriverDistributed): # ThirdPartySystems wiki page CI_WIKI_NAME = "Quobyte_CI" @@ -891,13 +816,13 @@ index bf6f231..238a331 100644 def __init__(self, execute=processutils.execute, *args, **kwargs): super(QuobyteDriver, self).__init__(*args, **kwargs) self.configuration.append_config_values(volume_opts) -@@ -104,6 +127,137 @@ class QuobyteDriver(remotefs_drv.RemoteFSSnapDriverDistributed): +@@ -104,6 +126,137 @@ class QuobyteDriver(remotefs_drv.RemoteFSSnapDriverDistributed): # Used to manage snapshots which are currently attached to a VM. self._nova = None + def _create_regular_file(self, path, size): + """Creates a regular file of given size in GiB.""" -+ self._execute('fallocate', '-l', '%sG' % size, ++ self._execute('fallocate', '-l', '%sGiB' % size, + path, run_as_root=self._execute_as_root) + + @coordination.synchronized('{self.driver_prefix}-{snapshot.id}') @@ -1029,7 +954,7 @@ index bf6f231..238a331 100644 def do_setup(self, context): """Any initialization the volume driver does while starting.""" super(QuobyteDriver, self).do_setup(context) -@@ -111,6 +265,17 @@ class QuobyteDriver(remotefs_drv.RemoteFSSnapDriverDistributed): +@@ -111,6 +264,17 @@ class QuobyteDriver(remotefs_drv.RemoteFSSnapDriverDistributed): self.set_nas_security_options(is_new_cinder_install=False) self.shares = {} # address : options self._nova = compute.API() @@ -1047,41 +972,7 @@ index bf6f231..238a331 100644 def check_for_setup_error(self): if not self.configuration.quobyte_volume_url: -@@ -131,6 +296,33 @@ class QuobyteDriver(remotefs_drv.RemoteFSSnapDriverDistributed): - else: - raise - -+ def optimize_volume(self, volume): -+ """Optimizes a volume for Quobyte -+ -+ This optimization is normally done during creation but volumes created -+ from e.g. snapshots require additional grooming. -+ -+ :param volume: volume reference -+ """ -+ volume_path = self.local_path(volume) -+ volume_size = volume.size -+ data = image_utils.qemu_img_info(self.local_path(volume), -+ run_as_root=self._execute_as_root) -+ if data.disk_size >= (volume_size * units.Gi): -+ LOG.debug("Optimization of volume %(volpath)s is not required," -+ "skipping this step.", {'volpath': volume_path}) -+ return -+ -+ LOG.debug("Optimizing volume %(optpath)s", {'optpath': volume_path}) -+ -+ if (self.configuration.quobyte_qcow2_volumes or -+ self.configuration.quobyte_sparsed_volumes): -+ self._execute('truncate', '-s', '%sG' % volume_size, -+ volume_path, run_as_root=self._execute_as_root) -+ else: -+ # _create_regular_file does fallocate so we use that -+ self._create_regular_file(volume_path, volume_size) -+ - def set_nas_security_options(self, is_new_cinder_install): - self._execute_as_root = False - -@@ -174,7 +366,7 @@ class QuobyteDriver(remotefs_drv.RemoteFSSnapDriverDistributed): +@@ -174,7 +338,7 @@ class QuobyteDriver(remotefs_drv.RemoteFSSnapDriverDistributed): "(allowing other/world read & write access).") def _qemu_img_info(self, path, volume_name): @@ -1090,7 +981,7 @@ index bf6f231..238a331 100644 path, volume_name, self.configuration.quobyte_mount_point_base) @utils.synchronized('quobyte', external=False) -@@ -182,6 +374,33 @@ class QuobyteDriver(remotefs_drv.RemoteFSSnapDriverDistributed): +@@ -182,6 +346,33 @@ class QuobyteDriver(remotefs_drv.RemoteFSSnapDriverDistributed): """Creates a clone of the specified volume.""" return self._create_cloned_volume(volume, src_vref) @@ -1124,7 +1015,7 @@ index bf6f231..238a331 100644 @utils.synchronized('quobyte', external=False) def create_volume(self, volume): return super(QuobyteDriver, self).create_volume(volume) -@@ -190,24 +409,27 @@ class QuobyteDriver(remotefs_drv.RemoteFSSnapDriverDistributed): +@@ -190,31 +381,34 @@ class QuobyteDriver(remotefs_drv.RemoteFSSnapDriverDistributed): def create_volume_from_snapshot(self, volume, snapshot): return self._create_volume_from_snapshot(volume, snapshot) @@ -1135,8 +1026,8 @@ index bf6f231..238a331 100644 This is done with a qemu-img convert to raw/qcow2 from the snapshot - qcow2. + qcow2. If the quobyte_volume_from_snapshot_cache is active the result -+ is copied into the cache and all volumes created from this -+ snapshot id are directly copied from the cache. ++ is written into the cache and all volumes created from this ++ snapshot id are created directly from the cache. """ LOG.debug("snapshot: %(snap)s, volume: %(vol)s, ", @@ -1153,8 +1044,9 @@ index bf6f231..238a331 100644 + self._ensure_shares_mounted() # Find the file which backs this file, which represents the point # when this snapshot was created. - img_info = self._qemu_img_info(forward_path, -@@ -215,6 +437,7 @@ class QuobyteDriver(remotefs_drv.RemoteFSSnapDriverDistributed): +- img_info = self._qemu_img_info(forward_path, +- snapshot.volume.name) ++ img_info = self._qemu_img_info(forward_path, snapshot.volume.name) path_to_snap_img = os.path.join(vol_path, img_info.backing_file) path_to_new_vol = self._local_path_volume(volume) @@ -1162,7 +1054,7 @@ index bf6f231..238a331 100644 LOG.debug("will copy from snapshot at %s", path_to_snap_img) -@@ -223,14 +446,61 @@ class QuobyteDriver(remotefs_drv.RemoteFSSnapDriverDistributed): +@@ -223,14 +417,60 @@ class QuobyteDriver(remotefs_drv.RemoteFSSnapDriverDistributed): else: out_format = 'raw' @@ -1205,7 +1097,6 @@ index bf6f231..238a331 100644 + {'volpath': path_to_new_vol}) + shutil.copyfile(path_to_cached_vol, path_to_new_vol) + self._set_rw_permissions(path_to_new_vol) -+ self.optimize_volume(volume) + + def _create_overlay_volume_from_snapshot(self, volume, snapshot, + volume_size, out_format): @@ -1232,7 +1123,7 @@ index bf6f231..238a331 100644 def delete_volume(self, volume): """Deletes a logical volume.""" -@@ -242,8 +512,17 @@ class QuobyteDriver(remotefs_drv.RemoteFSSnapDriverDistributed): +@@ -242,8 +482,17 @@ class QuobyteDriver(remotefs_drv.RemoteFSSnapDriverDistributed): self._ensure_share_mounted(volume.provider_location) volume_dir = self._local_volume_dir(volume) @@ -1252,7 +1143,7 @@ index bf6f231..238a331 100644 self._execute('rm', '-f', mounted_path, run_as_root=self._execute_as_root) -@@ -263,11 +542,6 @@ class QuobyteDriver(remotefs_drv.RemoteFSSnapDriverDistributed): +@@ -263,11 +512,6 @@ class QuobyteDriver(remotefs_drv.RemoteFSSnapDriverDistributed): return self._create_snapshot(snapshot) @utils.synchronized('quobyte', external=False) @@ -1264,7 +1155,7 @@ index bf6f231..238a331 100644 def initialize_connection(self, volume, connector): """Allow connection to connector and return connection info.""" -@@ -467,6 +741,8 @@ class QuobyteDriver(remotefs_drv.RemoteFSSnapDriverDistributed): +@@ -467,6 +711,8 @@ class QuobyteDriver(remotefs_drv.RemoteFSSnapDriverDistributed): if mounted: self._validate_volume(mount_path) diff --git a/overlay_volumes/README.md b/overlay_volumes/README.md index 0e7fa22..8066e86 100644 --- a/overlay_volumes/README.md +++ b/overlay_volumes/README.md @@ -2,7 +2,7 @@ ## overlay_volumes patch (**beta**) This patch adds optional overlay volumes based on the cache for volumes generated from snapshots in the Quobyte Cinder driver, which speeds up the creation of volumes from large snapshots. -The corresponding [upstream change](https://review.openstack.org/#/c/507050/9) is still in review which is why this patch is currently in **beta** state and subject to possible changes. Please note that this patch also includes a range of several [volume creation performance improvements](https://review.openstack.org/#/c/500782/7) and the [volume from snapshot cache](https://review.openstack.org/#/c/502974/9), who this implementation depends upon. +The corresponding [upstream change](https://review.openstack.org/#/c/507050/12) is still in review which is why this patch is currently in **beta** state and subject to possible changes. Please note that this patch also includes a range of several [volume creation performance improvements](https://review.openstack.org/#/c/500782/9) and the [volume from snapshot cache](https://review.openstack.org/#/c/502974/11), who this implementation depends upon. ### Usage