diff --git a/cinder/image/image_utils.py b/cinder/image/image_utils.py index 37d745b4208..933e9171688 100644 --- a/cinder/image/image_utils.py +++ b/cinder/image/image_utils.py @@ -128,7 +128,7 @@ def qemu_img_info(path: str, run_as_root: bool = True, force_share: bool = False) -> imageutils.QemuImgInfo: """Return an object containing the parsed output from qemu-img info.""" - cmd = ['env', 'LC_ALL=C', 'qemu-img', 'info'] + cmd = ['env', 'LC_ALL=C', 'qemu-img', 'info', '--output=json'] if force_share: if qemu_img_supports_force_share(): cmd.append('--force-share') @@ -142,7 +142,7 @@ def qemu_img_info(path: str, cmd = cmd[2:] out, _err = utils.execute(*cmd, run_as_root=run_as_root, prlimit=QEMU_IMG_LIMITS) - info = imageutils.QemuImgInfo(out) + info = imageutils.QemuImgInfo(out, format='json') # From Cinder's point of view, any 'luks' formatted images # should be treated as 'raw'. diff --git a/cinder/tests/unit/test_image_utils.py b/cinder/tests/unit/test_image_utils.py index 5bbe895be25..95667df14ca 100644 --- a/cinder/tests/unit/test_image_utils.py +++ b/cinder/tests/unit/test_image_utils.py @@ -40,7 +40,8 @@ class TestQemuImgInfo(test.TestCase): output = image_utils.qemu_img_info(test_path) mock_exec.assert_called_once_with('env', 'LC_ALL=C', 'qemu-img', - 'info', test_path, run_as_root=True, + 'info', '--output=json', test_path, + run_as_root=True, prlimit=image_utils.QEMU_IMG_LIMITS) self.assertEqual(mock_info.return_value, output) @@ -57,7 +58,8 @@ class TestQemuImgInfo(test.TestCase): force_share=False, run_as_root=False) mock_exec.assert_called_once_with('env', 'LC_ALL=C', 'qemu-img', - 'info', test_path, run_as_root=False, + 'info', '--output=json', test_path, + run_as_root=False, prlimit=image_utils.QEMU_IMG_LIMITS) self.assertEqual(mock_info.return_value, output) @@ -72,8 +74,8 @@ class TestQemuImgInfo(test.TestCase): mock_os.name = 'nt' output = image_utils.qemu_img_info(test_path) - mock_exec.assert_called_once_with('qemu-img', 'info', test_path, - run_as_root=True, + mock_exec.assert_called_once_with('qemu-img', 'info', '--output=json', + test_path, run_as_root=True, prlimit=image_utils.QEMU_IMG_LIMITS) self.assertEqual(mock_info.return_value, output) diff --git a/cinder/tests/unit/volume/drivers/test_nfs.py b/cinder/tests/unit/volume/drivers/test_nfs.py index fb3481f4387..74b1e8b2c3e 100644 --- a/cinder/tests/unit/volume/drivers/test_nfs.py +++ b/cinder/tests/unit/volume/drivers/test_nfs.py @@ -335,102 +335,112 @@ NFS_CONFIG4 = {'max_over_subscription_ratio': 20.0, 'nas_secure_file_permissions': 'false', 'nas_secure_file_operations': 'true'} -QEMU_IMG_INFO_OUT1 = """image: %(volid)s - file format: raw - virtual size: %(size_gb)sG (%(size_b)s bytes) - disk size: 173K - """ +QEMU_IMG_INFO_OUT1 = """{ + "filename": "%(volid)s", + "format": "raw", + "virtual-size": %(size_b)s, + "actual-size": 173000 +}""" -QEMU_IMG_INFO_OUT2 = """image: %(volid)s -file format: qcow2 -virtual size: %(size_gb)sG (%(size_b)s bytes) -disk size: 196K -cluster_size: 65536 -Format specific information: - compat: 1.1 - lazy refcounts: false - refcount bits: 16 - corrupt: false - """ +QEMU_IMG_INFO_OUT2 = """{ + "filename": "%(volid)s", + "format": "qcow2", + "virtual-size": %(size_b)s, + "actual-size": 196000, + "cluster-size": 65536, + "format-specific": { + "compat": "1.1", + "lazy-refcounts": false, + "refcount-bits": 16, + "corrupt": false + } +}""" -QEMU_IMG_INFO_OUT3 = """image: volume-%(volid)s.%(snapid)s -file format: qcow2 -virtual size: %(size_gb)sG (%(size_b)s bytes) -disk size: 196K -cluster_size: 65536 -backing file: volume-%(volid)s -backing file format: qcow2 -Format specific information: - compat: 1.1 - lazy refcounts: false - refcount bits: 16 - corrupt: false - """ +QEMU_IMG_INFO_OUT3 = """{ + "filename": "volume-%(volid)s.%(snapid)s", + "format": "qcow2", + "virtual-size": %(size_b)s, + "actual-size": 196000, + "cluster-size": 65536, + "backing-filename": "volume-%(volid)s", + "backing-filename-format": "qcow2", + "format-specific": { + "compat": "1.1", + "lazy-refcounts": false, + "refcount-bits": 16, + "corrupt": false + } +}""" -QEMU_IMG_INFO_OUT4 = """image: volume-%(volid)s.%(snapid)s -file format: raw -virtual size: %(size_gb)sG (%(size_b)s bytes) -disk size: 196K -cluster_size: 65536 -backing file: volume-%(volid)s -backing file format: raw -Format specific information: - compat: 1.1 - lazy refcounts: false - refcount bits: 16 - corrupt: false - """ +QEMU_IMG_INFO_OUT4 = """{ + "filename": "volume-%(volid)s.%(snapid)s", + "format": "raw", + "virtual-size": %(size_b)s, + "actual-size": 196000, + "cluster-size": 65536, + "backing-filename": "volume-%(volid)s", + "backing-filename-format": "raw" +}""" -QEMU_IMG_INFO_OUT5 = """image: volume-%(volid)s.%(snapid)s -file format: qcow2 -virtual size: %(size_gb)sG (%(size_b)s bytes) -disk size: 196K -encrypted: yes -cluster_size: 65536 -backing file: volume-%(volid)s -backing file format: raw -Format specific information: - compat: 1.1 - lazy refcounts: false - refcount bits: 16 - encrypt: - ivgen alg: plain64 - hash alg: sha256 - cipher alg: aes-256 - uuid: 386f8626-33f0-4683-a517-78ddfe385e33 - format: luks - cipher mode: xts - slots: - [0]: - active: true - iters: 1892498 - key offset: 4096 - stripes: 4000 - [1]: - active: false - key offset: 262144 - [2]: - active: false - key offset: 520192 - [3]: - active: false - key offset: 778240 - [4]: - active: false - key offset: 1036288 - [5]: - active: false - key offset: 1294336 - [6]: - active: false - key offset: 1552384 - [7]: - active: false - key offset: 1810432 - payload offset: 2068480 - master key iters: 459347 - corrupt: false -""" +QEMU_IMG_INFO_OUT5 = """{ + "filename": "volume-%(volid)s.%(snapid)s", + "format": "qcow2", + "virtual-size": %(size_b)s, + "actual-size": 196000, + "encrypted": true, + "cluster-size": 65536, + "backing-filename": "volume-%(volid)s", + "backing-filename-format": "raw", + "format-specific": { + "type": "luks", + "data": { + "ivgen-alg": "plain64", + "hash-alg": "sha256", + "cipher-alg": "aes-256", + "uuid": "386f8626-33f0-4683-a517-78ddfe385e33", + "cipher-mode": "xts", + "slots": [ + { + "active": true, + "iters": 1892498, + "key offset": 4096, + "stripes": 4000 + }, + { + "active": false, + "key offset": 262144 + }, + { + "active": false, + "key offset": 520192 + }, + { + "active": false, + "key offset": 778240 + }, + { + "active": false, + "key offset": 1036288 + }, + { + "active": false, + "key offset": 1294336 + }, + { + "active": false, + "key offset": 1552384 + }, + { + "active": false, + "key offset": 1810432 + } + ], + "payload-offset": 2068480, + "master-key-iters": 459347 + }, + "corrupt": false + } +}""" @ddt.ddt @@ -1323,7 +1333,7 @@ class NfsDriverTestCase(test.TestCase): 'size_gb': src_volume.size, 'size_b': src_volume.size * units.Gi} - img_info = imageutils.QemuImgInfo(img_out) + img_info = imageutils.QemuImgInfo(img_out, format='json') mock_img_info = self.mock_object(image_utils, 'qemu_img_info') mock_img_info.return_value = img_info mock_convert_image = self.mock_object(image_utils, 'convert_image') @@ -1404,7 +1414,7 @@ class NfsDriverTestCase(test.TestCase): 'snapid': fake_snap.id, 'size_gb': src_volume.size, 'size_b': src_volume.size * units.Gi} - img_info = imageutils.QemuImgInfo(img_out) + img_info = imageutils.QemuImgInfo(img_out, format='json') mock_img_info = self.mock_object(image_utils, 'qemu_img_info') mock_img_info.return_value = img_info @@ -1470,7 +1480,8 @@ class NfsDriverTestCase(test.TestCase): mock_img_utils = self.mock_object(image_utils, 'qemu_img_info') img_out = qemu_img_info % {'volid': volume.id, 'size_gb': volume.size, 'size_b': volume.size * units.Gi} - mock_img_utils.return_value = imageutils.QemuImgInfo(img_out) + mock_img_utils.return_value = imageutils.QemuImgInfo(img_out, + format='json') self.mock_object(drv, '_read_info_file', return_value={'active': "volume-%s" % volume.id}) @@ -1490,12 +1501,14 @@ class NfsDriverTestCase(test.TestCase): drv = self._driver volume = self._simple_volume() - qemu_img_output = """image: %s - file format: iso - virtual size: 1.0G (1073741824 bytes) - disk size: 173K - """ % volume['name'] - mock_img_info.return_value = imageutils.QemuImgInfo(qemu_img_output) + qemu_img_output = """{ + "filename": "%s", + "format": "iso", + "virtual-size": 1073741824, + "actual-size": 173000 +}""" % volume['name'] + mock_img_info.return_value = imageutils.QemuImgInfo(qemu_img_output, + format='json') self.assertRaises(exception.InvalidVolume, drv.initialize_connection, diff --git a/cinder/tests/unit/volume/drivers/test_quobyte.py b/cinder/tests/unit/volume/drivers/test_quobyte.py index 94b82e8c269..9f35fb13b3e 100644 --- a/cinder/tests/unit/volume/drivers/test_quobyte.py +++ b/cinder/tests/unit/volume/drivers/test_quobyte.py @@ -941,13 +941,14 @@ class QuobyteDriverTestCase(test.TestCase): self.TEST_QUOBYTE_VOLUME), self.VOLUME_UUID) - qemu_img_info_output = """image: volume-%s - file format: qcow2 - virtual size: 1.0G (1073741824 bytes) - disk size: 473K - """ % self.VOLUME_UUID + qemu_img_info_output = """{ + "filename": "volume-%s", + "format": "qcow2", + "virtual-size": 1073741824, + "actual-size": 473000 +}""" % self.VOLUME_UUID - img_info = imageutils.QemuImgInfo(qemu_img_info_output) + img_info = imageutils.QemuImgInfo(qemu_img_info_output, format='json') image_utils.qemu_img_info = mock.Mock(return_value=img_info) image_utils.resize_image = mock.Mock() @@ -987,13 +988,14 @@ class QuobyteDriverTestCase(test.TestCase): size = dest_volume['size'] - qemu_img_output = """image: %s - file format: raw - virtual size: 1.0G (1073741824 bytes) - disk size: 173K - backing file: %s - """ % (snap_file, src_volume['name']) - img_info = imageutils.QemuImgInfo(qemu_img_output) + qemu_img_output = """{ + "filename": "%s", + "format": "raw", + "virtual-size": 1073741824, + "actual-size": 173000, + "backing-filename": "%s" +}""" % (snap_file, src_volume['name']) + img_info = imageutils.QemuImgInfo(qemu_img_output, format='json') # mocking and testing starts here image_utils.convert_image = mock.Mock() @@ -1043,13 +1045,14 @@ class QuobyteDriverTestCase(test.TestCase): size = dest_volume['size'] - qemu_img_output = """image: %s - file format: raw - virtual size: 1.0G (1073741824 bytes) - disk size: 173K - backing file: %s - """ % (snap_file, src_volume['name']) - img_info = imageutils.QemuImgInfo(qemu_img_output) + qemu_img_output = """{ + "filename": "%s", + "format": "raw", + "virtual-size": 1073741824, + "actual-size": 173000, + "backing-filename": "%s" +}""" % (snap_file, src_volume['name']) + img_info = imageutils.QemuImgInfo(qemu_img_output, format='json') # mocking and testing starts here image_utils.convert_image = mock.Mock() @@ -1104,13 +1107,14 @@ class QuobyteDriverTestCase(test.TestCase): size = dest_volume['size'] - qemu_img_output = """image: %s - file format: raw - virtual size: 1.0G (1073741824 bytes) - disk size: 173K - backing file: %s - """ % (snap_file, src_volume['name']) - img_info = imageutils.QemuImgInfo(qemu_img_output) + qemu_img_output = """{ + "filename": "%s", + "format": "raw", + "virtual-size": 1073741824, + "actual-size": 173000, + "backing-filename": "%s" +}""" % (snap_file, src_volume['name']) + img_info = imageutils.QemuImgInfo(qemu_img_output, format='json') # mocking and testing starts here image_utils.convert_image = mock.Mock() @@ -1168,13 +1172,14 @@ class QuobyteDriverTestCase(test.TestCase): size = dest_volume['size'] - qemu_img_output = """image: %s - file format: raw - virtual size: 1.0G (1073741824 bytes) - disk size: 173K - backing file: %s - """ % (snap_file, src_volume['name']) - img_info = imageutils.QemuImgInfo(qemu_img_output) + qemu_img_output = """{ + "filename": "%s", + "format": "raw", + "virtual-size": 1073741824, + "actual-size": 173000, + "backing-filename": "%s" +}""" % (snap_file, src_volume['name']) + img_info = imageutils.QemuImgInfo(qemu_img_output, format='json') # mocking and testing starts here image_utils.convert_image = mock.Mock() @@ -1245,12 +1250,13 @@ class QuobyteDriverTestCase(test.TestCase): drv._get_hash_str(self.TEST_QUOBYTE_VOLUME)) vol_path = os.path.join(vol_dir, volume['name']) - qemu_img_output = """image: %s - file format: raw - virtual size: 1.0G (1073741824 bytes) - disk size: 173K - """ % volume['name'] - img_info = imageutils.QemuImgInfo(qemu_img_output) + qemu_img_output = """{ + "filename": "%s", + "format": "raw", + "virtual-size": 1073741824, + "actual-size": 173000 +}""" % volume['name'] + img_info = imageutils.QemuImgInfo(qemu_img_output, format='json') drv.get_active_image_from_info = mock.Mock(return_value=volume['name']) image_utils.qemu_img_info = mock.Mock(return_value=img_info) @@ -1294,12 +1300,13 @@ class QuobyteDriverTestCase(test.TestCase): mock_create_temporary_file.return_value = self.TEST_TMP_FILE - qemu_img_output = """image: %s - file format: raw - virtual size: 1.0G (1073741824 bytes) - disk size: 173K - """ % volume['name'] - img_info = imageutils.QemuImgInfo(qemu_img_output) + qemu_img_output = """{ + "filename": "%s", + "format": "raw", + "virtual-size": 1073741824, + "actual-size": 173000 +}""" % volume['name'] + img_info = imageutils.QemuImgInfo(qemu_img_output, format='json') mock_qemu_img_info.return_value = img_info upload_path = volume_path @@ -1346,12 +1353,13 @@ class QuobyteDriverTestCase(test.TestCase): mock_create_temporary_file.return_value = self.TEST_TMP_FILE - qemu_img_output = """image: %s - file format: qcow2 - virtual size: 1.0G (1073741824 bytes) - disk size: 173K - """ % volume['name'] - img_info = imageutils.QemuImgInfo(qemu_img_output) + qemu_img_output = """{ + "filename": "%s", + "format": "qcow2", + "virtual-size": 1073741824, + "actual-size": 173000 +}""" % volume['name'] + img_info = imageutils.QemuImgInfo(qemu_img_output, format='json') mock_qemu_img_info.return_value = img_info upload_path = self.TEST_TMP_FILE @@ -1401,13 +1409,14 @@ class QuobyteDriverTestCase(test.TestCase): mock_create_temporary_file.return_value = self.TEST_TMP_FILE - qemu_img_output = """image: volume-%s.%s - file format: qcow2 - virtual size: 1.0G (1073741824 bytes) - disk size: 173K - backing file: %s - """ % (self.VOLUME_UUID, self.SNAP_UUID, volume_filename) - img_info = imageutils.QemuImgInfo(qemu_img_output) + qemu_img_output = """{ + "filename": "volume-%s.%s", + "format": "qcow2", + "virtual-size": 1073741824, + "actual-size": 173000, + "backing-filename": "%s" +}""" % (self.VOLUME_UUID, self.SNAP_UUID, volume_filename) + img_info = imageutils.QemuImgInfo(qemu_img_output, format='json') mock_qemu_img_info.return_value = img_info upload_path = self.TEST_TMP_FILE diff --git a/cinder/volume/flows/manager/create_volume.py b/cinder/volume/flows/manager/create_volume.py index c176574f608..0a0d5bdd231 100644 --- a/cinder/volume/flows/manager/create_volume.py +++ b/cinder/volume/flows/manager/create_volume.py @@ -23,6 +23,7 @@ from oslo_log import log as logging from oslo_utils import excutils from oslo_utils import fileutils from oslo_utils import netutils +from oslo_utils import strutils from oslo_utils import timeutils from oslo_utils import uuidutils import taskflow.engines @@ -557,7 +558,8 @@ class CreateVolumeFromSpecTask(flow_utils.CinderTask): volume, encryption) - if image_info.encrypted == 'yes': + # see Bug #1942682 and Change I949f07582a708 for why we do this + if strutils.bool_from_string(image_info.encrypted): key_str = source_pass + "\n" + new_pass + "\n" del source_pass