]> review.fuel-infra Code Review - openstack-build/cinder-build.git/commitdiff
SMBFS: Add minimum qemu-img version requirement
authorLucian Petrut <lpetrut@cloudbasesolutions.com>
Mon, 16 Feb 2015 12:28:14 +0000 (14:28 +0200)
committerLucian Petrut <lpetrut@cloudbasesolutions.com>
Sat, 18 Apr 2015 10:19:59 +0000 (13:19 +0300)
This patch enforces specific qemu-img versions as minimum
requirements for the SMBFS drivers.

This way, some of the workarounds that were needed because
of qemu-img missing features or bugs related to the VHD/X
formats can be removed.

DocImpact

Change-Id: I9d14e16b1102673847f386e300179ed6d43ab576

cinder/tests/unit/test_smbfs.py
cinder/tests/unit/windows/test_smbfs.py
cinder/volume/drivers/smbfs.py
cinder/volume/drivers/windows/smbfs.py

index df04f9d3c8559f896378f799ddf02f3c57280ebf..d97ce97cd52fcf073007437d6af1ed820c646164 100644 (file)
@@ -91,41 +91,46 @@ class SmbFsTestCase(test.TestCase):
                 self._FAKE_VOLUME_PATH)
             drv._delete.assert_any_call(fake_vol_info)
 
-    def _test_setup(self, config, share_config_exists=True):
-        fake_exists = mock.Mock(return_value=share_config_exists)
+    @mock.patch('os.path.exists')
+    @mock.patch.object(image_utils, 'check_qemu_img_version')
+    def _test_setup(self, mock_check_qemu_img_version,
+                    mock_exists, config, share_config_exists=True):
+        mock_exists.return_value = share_config_exists
         fake_ensure_mounted = mock.MagicMock()
         self._smbfs_driver._ensure_shares_mounted = fake_ensure_mounted
         self._smbfs_driver.configuration = config
 
-        with mock.patch('os.path.exists', fake_exists):
-            if not (config.smbfs_shares_config and share_config_exists and
-                    config.smbfs_oversub_ratio > 0 and
-                    0 <= config.smbfs_used_ratio <= 1):
-                self.assertRaises(exception.SmbfsException,
-                                  self._smbfs_driver.do_setup,
-                                  None)
-            else:
-                self._smbfs_driver.do_setup(None)
-                self.assertEqual(self._smbfs_driver.shares, {})
-                fake_ensure_mounted.assert_called_once_with()
+        if not (config.smbfs_shares_config and share_config_exists and
+                config.smbfs_oversub_ratio > 0 and
+                0 <= config.smbfs_used_ratio <= 1):
+            self.assertRaises(exception.SmbfsException,
+                              self._smbfs_driver.do_setup,
+                              None)
+        else:
+            self._smbfs_driver.do_setup(mock.sentinel.context)
+            mock_check_qemu_img_version.assert_called_once_with()
+            self.assertEqual(self._smbfs_driver.shares, {})
+            fake_ensure_mounted.assert_called_once_with()
 
     def test_setup_missing_shares_config_option(self):
         fake_config = copy.copy(self._FAKE_SMBFS_CONFIG)
         fake_config.smbfs_shares_config = None
-        self._test_setup(fake_config, None)
+        self._test_setup(config=fake_config,
+                         share_config_exists=False)
 
     def test_setup_missing_shares_config_file(self):
-        self._test_setup(self._FAKE_SMBFS_CONFIG, False)
+        self._test_setup(config=self._FAKE_SMBFS_CONFIG,
+                         share_config_exists=False)
 
     def test_setup_invlid_oversub_ratio(self):
         fake_config = copy.copy(self._FAKE_SMBFS_CONFIG)
         fake_config.smbfs_oversub_ratio = -1
-        self._test_setup(fake_config)
+        self._test_setup(config=fake_config)
 
     def test_setup_invalid_used_ratio(self):
         fake_config = copy.copy(self._FAKE_SMBFS_CONFIG)
         fake_config.smbfs_used_ratio = -1
-        self._test_setup(fake_config)
+        self._test_setup(config=fake_config)
 
     def _test_create_volume(self, volume_exists=False, volume_format=None):
         fake_method = mock.MagicMock()
@@ -528,14 +533,10 @@ class SmbFsTestCase(test.TestCase):
         self._smbfs_driver._remotefsclient.mount.assert_called_once_with(
             self._FAKE_SHARE, self._FAKE_SHARE_OPTS.split())
 
-    def _test_copy_image_to_volume(self, unsupported_qemu_version=False,
-                                   wrong_size_after_fetch=False):
+    def _test_copy_image_to_volume(self, wrong_size_after_fetch=False):
         drv = self._smbfs_driver
 
         vol_size_bytes = self._FAKE_VOLUME['size'] << 30
-        fake_image_service = mock.MagicMock()
-        fake_image_service.show.return_value = (
-            {'id': 'fake_image_id', 'disk_format': 'raw'})
 
         fake_img_info = mock.MagicMock()
 
@@ -544,47 +545,35 @@ class SmbFsTestCase(test.TestCase):
         else:
             fake_img_info.virtual_size = vol_size_bytes
 
-        if unsupported_qemu_version:
-            qemu_version = [1, 5]
-        else:
-            qemu_version = [1, 7]
-
         drv.get_volume_format = mock.Mock(
             return_value=drv._DISK_FORMAT_VHDX)
         drv.local_path = mock.Mock(
             return_value=self._FAKE_VOLUME_PATH)
-        drv.get_qemu_version = mock.Mock(
-            return_value=qemu_version)
         drv._do_extend_volume = mock.Mock()
         drv.configuration = mock.MagicMock()
         drv.configuration.volume_dd_blocksize = (
             mock.sentinel.block_size)
 
-        exc = None
         with mock.patch.object(image_utils, 'fetch_to_volume_format') as \
                 fake_fetch, mock.patch.object(image_utils, 'qemu_img_info') as \
                 fake_qemu_img_info:
 
-            if wrong_size_after_fetch:
-                exc = exception.ImageUnacceptable
-            elif unsupported_qemu_version:
-                exc = exception.InvalidVolume
-
             fake_qemu_img_info.return_value = fake_img_info
 
-            if exc:
+            if wrong_size_after_fetch:
                 self.assertRaises(
-                    exc, drv.copy_image_to_volume,
+                    exception.ImageUnacceptable,
+                    drv.copy_image_to_volume,
                     mock.sentinel.context, self._FAKE_VOLUME,
-                    fake_image_service,
+                    mock.sentinel.image_service,
                     mock.sentinel.image_id)
             else:
                 drv.copy_image_to_volume(
                     mock.sentinel.context, self._FAKE_VOLUME,
-                    fake_image_service,
+                    mock.sentinel.image_service,
                     mock.sentinel.image_id)
                 fake_fetch.assert_called_once_with(
-                    mock.sentinel.context, fake_image_service,
+                    mock.sentinel.context, mock.sentinel.image_service,
                     mock.sentinel.image_id, self._FAKE_VOLUME_PATH,
                     drv._DISK_FORMAT_VHDX,
                     mock.sentinel.block_size)
@@ -599,9 +588,6 @@ class SmbFsTestCase(test.TestCase):
     def test_copy_image_to_volume_wrong_size_after_fetch(self):
         self._test_copy_image_to_volume(wrong_size_after_fetch=True)
 
-    def test_copy_image_to_volume_unsupported_qemu_version(self):
-        self._test_copy_image_to_volume(unsupported_qemu_version=True)
-
     def test_get_capacity_info(self):
         fake_block_size = 4096.0
         fake_total_blocks = 1024
index 9a7cd16f0070962564993c03c6438a78d65af1cf..5fa4061b987702a1ab6184216b656770210aaca1 100644 (file)
@@ -232,22 +232,13 @@ class WindowsSmbFsTestCase(test.TestCase):
     def test_copy_vhd_volume_to_image(self):
         self._test_copy_volume_to_image(volume_format='vhd')
 
-    def _test_copy_image_to_volume(self, qemu_version=[1, 7]):
+    def test_copy_image_to_volume(self):
         drv = self._smbfs_driver
 
-        fake_image_id = 'fake_image_id'
-        fake_image_service = mock.MagicMock()
-        fake_image_service.show.return_value = (
-            {'id': fake_image_id, 'disk_format': 'raw'})
-
         drv.get_volume_format = mock.Mock(
-            return_value='vhdx')
+            return_value=mock.sentinel.volume_format)
         drv.local_path = mock.Mock(
             return_value=self._FAKE_VOLUME_PATH)
-        drv._local_volume_dir = mock.Mock(
-            return_value=self._FAKE_MNT_POINT)
-        drv.get_qemu_version = mock.Mock(
-            return_value=qemu_version)
         drv.configuration = mock.MagicMock()
         drv.configuration.volume_dd_blocksize = mock.sentinel.block_size
 
@@ -255,33 +246,14 @@ class WindowsSmbFsTestCase(test.TestCase):
                                'fetch_to_volume_format') as fake_fetch:
             drv.copy_image_to_volume(
                 mock.sentinel.context, self._FAKE_VOLUME,
-                fake_image_service,
-                fake_image_id)
-
-            if qemu_version < [1, 7]:
-                fake_temp_image_name = '%s.temp_image.%s.vhd' % (
-                    self._FAKE_VOLUME['id'],
-                    fake_image_id)
-                fetch_path = os.path.join(self._FAKE_MNT_POINT,
-                                          fake_temp_image_name)
-                fetch_format = 'vpc'
-                drv.vhdutils.convert_vhd.assert_called_once_with(
-                    fetch_path, self._FAKE_VOLUME_PATH)
-                drv._delete.assert_called_with(fetch_path)
-
-            else:
-                fetch_path = self._FAKE_VOLUME_PATH
-                fetch_format = 'vhdx'
-
+                mock.sentinel.image_service,
+                mock.sentinel.image_id)
             fake_fetch.assert_called_once_with(
-                mock.sentinel.context, fake_image_service, fake_image_id,
-                fetch_path, fetch_format, mock.sentinel.block_size)
-
-    def test_copy_image_to_volume(self):
-        self._test_copy_image_to_volume()
-
-    def test_copy_image_to_volume_with_conversion(self):
-        self._test_copy_image_to_volume([1, 5])
+                mock.sentinel.context,
+                mock.sentinel.image_service,
+                mock.sentinel.image_id,
+                self._FAKE_VOLUME_PATH, mock.sentinel.volume_format,
+                mock.sentinel.block_size)
 
     def test_copy_volume_from_snapshot(self):
         drv = self._smbfs_driver
index 9191b197f9ae6419ec2ef9ec6d8d17a894ff6d44..9d59cbfd6c983c26d1bebaa6a30810f8b7becb8d 100644 (file)
@@ -14,7 +14,6 @@
 #    under the License.
 
 import os
-import re
 
 from oslo_concurrency import processutils as putils
 from oslo_config import cfg
@@ -29,7 +28,7 @@ from cinder import utils
 from cinder.volume.drivers import remotefs as remotefs_drv
 
 
-VERSION = '1.0.0'
+VERSION = '1.1.0'
 
 LOG = logging.getLogger(__name__)
 
@@ -80,6 +79,8 @@ class SmbfsDriver(remotefs_drv.RemoteFSSnapDriver):
     SHARE_FORMAT_REGEX = r'//.+/.+'
     VERSION = VERSION
 
+    _MINIMUM_QEMU_IMG_VERSION = '1.7'
+
     _DISK_FORMAT_VHD = 'vhd'
     _DISK_FORMAT_VHD_LEGACY = 'vpc'
     _DISK_FORMAT_VHDX = 'vhdx'
@@ -131,6 +132,8 @@ class SmbfsDriver(remotefs_drv.RemoteFSSnapDriver):
         }
 
     def do_setup(self, context):
+        image_utils.check_qemu_img_version(self._MINIMUM_QEMU_IMG_VERSION)
+
         config = self.configuration.smbfs_shares_config
         if not config:
             msg = (_("SMBFS config file not set (smbfs_shares_config)."))
@@ -242,26 +245,11 @@ class SmbfsDriver(remotefs_drv.RemoteFSSnapDriver):
         info_path = self._local_path_volume_info(volume)
         self._delete(info_path)
 
-    def get_qemu_version(self):
-        info, _ = self._execute('qemu-img', check_exit_code=False)
-        pattern = r"qemu-img version ([0-9\.]*)"
-        version = re.match(pattern, info)
-        if not version:
-            LOG.warn(_LW("qemu-img is not installed."))
-            return None
-        return [int(x) for x in version.groups()[0].split('.')]
-
     def _create_windows_image(self, volume_path, volume_size, volume_format):
         """Creates a VHD or VHDX file of a given size."""
         # vhd is regarded as vpc by qemu
         if volume_format == self._DISK_FORMAT_VHD:
             volume_format = self._DISK_FORMAT_VHD_LEGACY
-        else:
-            qemu_version = self.get_qemu_version()
-            if qemu_version < [1, 7]:
-                err_msg = _("This version of qemu-img does not support vhdx "
-                            "images. Please upgrade to 1.7 or greater.")
-                raise exception.SmbfsException(err_msg)
 
         self._execute('qemu-img', 'create', '-f', volume_format,
                       volume_path, str(volume_size * units.Gi),
@@ -501,16 +489,6 @@ class SmbfsDriver(remotefs_drv.RemoteFSSnapDriver):
     def copy_image_to_volume(self, context, volume, image_service, image_id):
         """Fetch the image from image_service and write it to the volume."""
         volume_format = self.get_volume_format(volume, qemu_format=True)
-        image_meta = image_service.show(context, image_id)
-        qemu_version = self.get_qemu_version()
-
-        if (qemu_version < [1, 7] and (
-                volume_format == self._DISK_FORMAT_VHDX and
-                image_meta['disk_format'] != volume_format)):
-            err_msg = _("Unsupported volume format: vhdx. qemu-img 1.7 or "
-                        "higher is required in order to properly support this "
-                        "format.")
-            raise exception.InvalidVolume(err_msg)
 
         image_utils.fetch_to_volume_format(
             context, image_service, image_id,
index 533265ed5e95a2f0371eeaba5c6c8c00a1db63d5..e6f98e93c83b53efa5570e62b688680ba6a29300 100644 (file)
@@ -31,7 +31,7 @@ from cinder.volume.drivers import smbfs
 from cinder.volume.drivers.windows import remotefs
 from cinder.volume.drivers.windows import vhdutils
 
-VERSION = '1.0.0'
+VERSION = '1.1.0'
 
 LOG = logging.getLogger(__name__)
 
@@ -43,6 +43,7 @@ CONF.set_default('smbfs_default_volume_format', 'vhd')
 
 class WindowsSmbfsDriver(smbfs.SmbfsDriver):
     VERSION = VERSION
+    _MINIMUM_QEMU_IMG_VERSION = '1.6'
 
     def __init__(self, *args, **kwargs):
         super(WindowsSmbfsDriver, self).__init__(*args, **kwargs)
@@ -206,38 +207,16 @@ class WindowsSmbfsDriver(smbfs.SmbfsDriver):
 
     def copy_image_to_volume(self, context, volume, image_service, image_id):
         """Fetch the image from image_service and write it to the volume."""
+        volume_path = self.local_path(volume)
         volume_format = self.get_volume_format(volume, qemu_format=True)
-        image_meta = image_service.show(context, image_id)
-
-        fetch_format = volume_format
-        fetch_path = self.local_path(volume)
-        self._delete(fetch_path)
-        qemu_version = self.get_qemu_version()
-
-        needs_conversion = False
-
-        if (qemu_version < [1, 7] and (
-                volume_format == self._DISK_FORMAT_VHDX and
-                image_meta['disk_format'] != self._DISK_FORMAT_VHDX)):
-            needs_conversion = True
-            fetch_format = 'vpc'
-            temp_file_name = '%s.temp_image.%s.%s' % (
-                volume['id'],
-                image_meta['id'],
-                self._DISK_FORMAT_VHD)
-            fetch_path = os.path.join(self._local_volume_dir(volume),
-                                      temp_file_name)
+        self._delete(volume_path)
 
         image_utils.fetch_to_volume_format(
             context, image_service, image_id,
-            fetch_path, fetch_format,
+            volume_path, volume_format,
             self.configuration.volume_dd_blocksize)
 
-        if needs_conversion:
-            self.vhdutils.convert_vhd(fetch_path, self.local_path(volume))
-            self._delete(fetch_path)
-
-        self.vhdutils.resize_vhd(self.local_path(volume),
+        self.vhdutils.resize_vhd(volume_path,
                                  volume['size'] * units.Gi)
 
     def _copy_volume_from_snapshot(self, snapshot, volume, volume_size):