import contextlib
import math
import os
+import re
import tempfile
from oslo_concurrency import processutils
from oslo_utils import units
from cinder import exception
-from cinder.i18n import _
+from cinder.i18n import _, _LW
from cinder.openstack.common import fileutils
from cinder.openstack.common import imageutils
from cinder import utils
return imageutils.QemuImgInfo(out)
+def get_qemu_img_version():
+ info = utils.execute('qemu-img', '--help', check_exit_code=False)[0]
+ pattern = r"qemu-img version ([0-9\.]*)"
+ version = re.match(pattern, info)
+ if not version:
+ LOG.warning(_LW("qemu-img is not installed."))
+ return None
+ return _get_version_from_string(version.groups()[0])
+
+
+def _get_version_from_string(version_string):
+ return [int(x) for x in version_string.split('.')]
+
+
+def check_qemu_img_version(minimum_version):
+ qemu_version = get_qemu_img_version()
+ if qemu_version < _get_version_from_string(minimum_version):
+ if qemu_version:
+ current_version = '.'.join((str(element)
+ for element in qemu_version))
+ else:
+ current_version = None
+
+ _msg = _('qemu-img %(minimum_version)s or later is required by '
+ 'this volume driver. Current qemu-img version: '
+ '%(current_version)s') % {'minimum_version': minimum_version,
+ 'current_version': current_version}
+ raise exception.VolumeBackendAPIException(data=_msg)
+
+
def _convert_image(prefix, source, dest, out_format, run_as_root=True):
"""Convert image to other format."""
run_as_root=True)
self.assertEqual(mock_info.return_value, output)
+ @mock.patch('cinder.utils.execute')
+ def test_get_qemu_img_version(self, mock_exec):
+ mock_out = "qemu-img version 2.0.0"
+ mock_err = mock.sentinel.err
+ mock_exec.return_value = (mock_out, mock_err)
+
+ expected_version = [2, 0, 0]
+ version = image_utils.get_qemu_img_version()
+
+ mock_exec.assert_called_once_with('qemu-img', '--help',
+ check_exit_code=False)
+ self.assertEqual(expected_version, version)
+
+ @mock.patch.object(image_utils, 'get_qemu_img_version')
+ def test_validate_qemu_img_version(self, mock_get_qemu_img_version):
+ fake_current_version = [1, 8]
+ mock_get_qemu_img_version.return_value = fake_current_version
+ minimum_version = '1.8'
+
+ image_utils.check_qemu_img_version(minimum_version)
+
+ mock_get_qemu_img_version.assert_called_once_with()
+
+ @mock.patch.object(image_utils, 'get_qemu_img_version')
+ def _test_validate_unsupported_qemu_img_version(self,
+ mock_get_qemu_img_version,
+ current_version=None):
+ mock_get_qemu_img_version.return_value = current_version
+ minimum_version = '2.0'
+
+ self.assertRaises(exception.VolumeBackendAPIException,
+ image_utils.check_qemu_img_version,
+ minimum_version)
+
+ mock_get_qemu_img_version.assert_called_once_with()
+
+ def test_validate_qemu_img_version_not_installed(self):
+ self._test_validate_unsupported_qemu_img_version()
+
+ def test_validate_older_qemu_img_version(self):
+ self._test_validate_unsupported_qemu_img_version(
+ current_version=[1, 8])
+
class TestConvertImage(test.TestCase):
@mock.patch('cinder.image.image_utils.os.stat')