Use the json format output of qemu-img info

Support for the human format by oslo_utils.imageutils.QemuImgInfo was
deprecated since oslo.utils 4.9.1 [1]. This change replaces the human
format with the json format which will be used by default.

[1] 73eb0673f627aad382e08a816191b637af436465

Backport note: The json format is preferable because it allows access
to format specific details (since oslo.utils 4.1.0).  These details
are not present when the default 'human' format is used.  See change
I133da07a5a9628b8a9 for details.

Closes-Bug: #1940540
Change-Id: Ia0353204abf849467106ee08982d1271de23101a
(cherry picked from commit c0d2e7ebd8)
(cherry picked from commit 11b0f97a01)
(cherry picked from commit 4cef5c0c42)
(cherry picked from commit 9810c05e74)
(cherry picked from commit 60a5de1f6d)
(cherry picked from commit 6a1260ea80)
Conflicts:
  cinder/tests/unit/volume/drivers/test_nfs.py
  - patch changed QEMU_IMG_INFO_OUT5 test data which isn't present
    in ussuri
  cinder/volume/flows/manager/create_volume.py
  - parent patch of 6a1260ea8 imported netutils, but that's not used
    in this file in ussuri
(cherry picked from commit 6df27994d9)
This commit is contained in:
Takashi Kajinami 2021-07-06 21:48:44 +09:00 committed by Brian Rosmaita
parent 14c2db209b
commit 9f9194d804
5 changed files with 134 additions and 117 deletions

View File

@ -108,7 +108,7 @@ def from_qemu_img_disk_format(disk_format):
def qemu_img_info(path, run_as_root=True, force_share=False): def qemu_img_info(path, run_as_root=True, force_share=False):
"""Return an object containing the parsed output from qemu-img info.""" """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 force_share:
if qemu_img_supports_force_share(): if qemu_img_supports_force_share():
cmd.append('--force-share') cmd.append('--force-share')
@ -122,7 +122,7 @@ def qemu_img_info(path, run_as_root=True, force_share=False):
cmd = cmd[2:] cmd = cmd[2:]
out, _err = utils.execute(*cmd, run_as_root=run_as_root, out, _err = utils.execute(*cmd, run_as_root=run_as_root,
prlimit=QEMU_IMG_LIMITS) prlimit=QEMU_IMG_LIMITS)
info = imageutils.QemuImgInfo(out) info = imageutils.QemuImgInfo(out, format='json')
# From Cinder's point of view, any 'luks' formatted images # From Cinder's point of view, any 'luks' formatted images
# should be treated as 'raw'. # should be treated as 'raw'.

View File

@ -41,7 +41,8 @@ class TestQemuImgInfo(test.TestCase):
output = image_utils.qemu_img_info(test_path) output = image_utils.qemu_img_info(test_path)
mock_exec.assert_called_once_with('env', 'LC_ALL=C', 'qemu-img', 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) prlimit=image_utils.QEMU_IMG_LIMITS)
self.assertEqual(mock_info.return_value, output) self.assertEqual(mock_info.return_value, output)
@ -58,7 +59,8 @@ class TestQemuImgInfo(test.TestCase):
force_share=False, force_share=False,
run_as_root=False) run_as_root=False)
mock_exec.assert_called_once_with('env', 'LC_ALL=C', 'qemu-img', 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) prlimit=image_utils.QEMU_IMG_LIMITS)
self.assertEqual(mock_info.return_value, output) self.assertEqual(mock_info.return_value, output)
@ -73,8 +75,8 @@ class TestQemuImgInfo(test.TestCase):
mock_os.name = 'nt' mock_os.name = 'nt'
output = image_utils.qemu_img_info(test_path) output = image_utils.qemu_img_info(test_path)
mock_exec.assert_called_once_with('qemu-img', 'info', test_path, mock_exec.assert_called_once_with('qemu-img', 'info', '--output=json',
run_as_root=True, test_path, run_as_root=True,
prlimit=image_utils.QEMU_IMG_LIMITS) prlimit=image_utils.QEMU_IMG_LIMITS)
self.assertEqual(mock_info.return_value, output) self.assertEqual(mock_info.return_value, output)

View File

@ -330,51 +330,52 @@ NFS_CONFIG4 = {'max_over_subscription_ratio': 20.0,
'nas_secure_file_permissions': 'false', 'nas_secure_file_permissions': 'false',
'nas_secure_file_operations': 'true'} 'nas_secure_file_operations': 'true'}
QEMU_IMG_INFO_OUT1 = """image: %(volid)s QEMU_IMG_INFO_OUT1 = """{
file format: raw "filename": "%(volid)s",
virtual size: %(size_gb)sG (%(size_b)s bytes) "format": "raw",
disk size: 173K "virtual-size": %(size_b)s,
""" "actual-size": 173000
}"""
QEMU_IMG_INFO_OUT2 = """image: %(volid)s QEMU_IMG_INFO_OUT2 = """{
file format: qcow2 "filename": "%(volid)s",
virtual size: %(size_gb)sG (%(size_b)s bytes) "format": "qcow2",
disk size: 196K "virtual-size": %(size_b)s,
cluster_size: 65536 "actual-size": 196000,
Format specific information: "cluster-size": 65536,
compat: 1.1 "format-specific": {
lazy refcounts: false "compat": "1.1",
refcount bits: 16 "lazy-refcounts": false,
corrupt: false "refcount-bits": 16,
""" "corrupt": false
}
}"""
QEMU_IMG_INFO_OUT3 = """image: volume-%(volid)s.%(snapid)s QEMU_IMG_INFO_OUT3 = """{
file format: qcow2 "filename": "volume-%(volid)s.%(snapid)s",
virtual size: %(size_gb)sG (%(size_b)s bytes) "format": "qcow2",
disk size: 196K "virtual-size": %(size_b)s,
cluster_size: 65536 "actual-size": 196000,
backing file: volume-%(volid)s "cluster-size": 65536,
backing file format: qcow2 "backing-filename": "volume-%(volid)s",
Format specific information: "backing-filename-format": "qcow2",
compat: 1.1 "format-specific": {
lazy refcounts: false "compat": "1.1",
refcount bits: 16 "lazy-refcounts": false,
corrupt: false "refcount-bits": 16,
""" "corrupt": false
}
}"""
QEMU_IMG_INFO_OUT4 = """image: volume-%(volid)s.%(snapid)s QEMU_IMG_INFO_OUT4 = """{
file format: raw "filename": "volume-%(volid)s.%(snapid)s",
virtual size: %(size_gb)sG (%(size_b)s bytes) "format": "raw",
disk size: 196K "virtual-size": %(size_b)s,
cluster_size: 65536 "actual-size": 196000,
backing file: volume-%(volid)s "cluster-size": 65536,
backing file format: raw "backing-filename": "volume-%(volid)s",
Format specific information: "backing-filename-format": "raw"
compat: 1.1 }"""
lazy refcounts: false
refcount bits: 16
corrupt: false
"""
@ddt.ddt @ddt.ddt
@ -1191,7 +1192,7 @@ class NfsDriverTestCase(test.TestCase):
'size_gb': src_volume.size, 'size_gb': src_volume.size,
'size_b': src_volume.size * units.Gi} '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 = self.mock_object(image_utils, 'qemu_img_info')
mock_img_info.return_value = img_info mock_img_info.return_value = img_info
mock_convert_image = self.mock_object(image_utils, 'convert_image') mock_convert_image = self.mock_object(image_utils, 'convert_image')
@ -1262,7 +1263,7 @@ class NfsDriverTestCase(test.TestCase):
'snapid': fake_snap.id, 'snapid': fake_snap.id,
'size_gb': src_volume.size, 'size_gb': src_volume.size,
'size_b': src_volume.size * units.Gi} '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 = self.mock_object(image_utils, 'qemu_img_info')
mock_img_info.return_value = img_info mock_img_info.return_value = img_info
@ -1328,7 +1329,8 @@ class NfsDriverTestCase(test.TestCase):
mock_img_utils = self.mock_object(image_utils, 'qemu_img_info') mock_img_utils = self.mock_object(image_utils, 'qemu_img_info')
img_out = qemu_img_info % {'volid': volume.id, 'size_gb': volume.size, img_out = qemu_img_info % {'volid': volume.id, 'size_gb': volume.size,
'size_b': volume.size * units.Gi} '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', self.mock_object(drv, '_read_info_file',
return_value={'active': "volume-%s" % volume.id}) return_value={'active': "volume-%s" % volume.id})
@ -1348,12 +1350,14 @@ class NfsDriverTestCase(test.TestCase):
drv = self._driver drv = self._driver
volume = self._simple_volume() volume = self._simple_volume()
qemu_img_output = """image: %s qemu_img_output = """{
file format: iso "filename": "%s",
virtual size: 1.0G (1073741824 bytes) "format": "iso",
disk size: 173K "virtual-size": 1073741824,
""" % volume['name'] "actual-size": 173000
mock_img_info.return_value = imageutils.QemuImgInfo(qemu_img_output) }""" % volume['name']
mock_img_info.return_value = imageutils.QemuImgInfo(qemu_img_output,
format='json')
self.assertRaises(exception.InvalidVolume, self.assertRaises(exception.InvalidVolume,
drv.initialize_connection, drv.initialize_connection,

View File

@ -936,13 +936,14 @@ class QuobyteDriverTestCase(test.TestCase):
self.TEST_QUOBYTE_VOLUME), self.TEST_QUOBYTE_VOLUME),
self.VOLUME_UUID) self.VOLUME_UUID)
qemu_img_info_output = """image: volume-%s qemu_img_info_output = """{
file format: qcow2 "filename": "volume-%s",
virtual size: 1.0G (1073741824 bytes) "format": "qcow2",
disk size: 473K "virtual-size": 1073741824,
""" % self.VOLUME_UUID "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.qemu_img_info = mock.Mock(return_value=img_info)
image_utils.resize_image = mock.Mock() image_utils.resize_image = mock.Mock()
@ -975,13 +976,14 @@ class QuobyteDriverTestCase(test.TestCase):
size = dest_volume['size'] size = dest_volume['size']
qemu_img_output = """image: %s qemu_img_output = """{
file format: raw "filename": "%s",
virtual size: 1.0G (1073741824 bytes) "format": "raw",
disk size: 173K "virtual-size": 1073741824,
backing file: %s "actual-size": 173000,
""" % (snap_file, src_volume['name']) "backing-filename": "%s"
img_info = imageutils.QemuImgInfo(qemu_img_output) }""" % (snap_file, src_volume['name'])
img_info = imageutils.QemuImgInfo(qemu_img_output, format='json')
# mocking and testing starts here # mocking and testing starts here
image_utils.convert_image = mock.Mock() image_utils.convert_image = mock.Mock()
@ -1031,13 +1033,14 @@ class QuobyteDriverTestCase(test.TestCase):
size = dest_volume['size'] size = dest_volume['size']
qemu_img_output = """image: %s qemu_img_output = """{
file format: raw "filename": "%s",
virtual size: 1.0G (1073741824 bytes) "format": "raw",
disk size: 173K "virtual-size": 1073741824,
backing file: %s "actual-size": 173000,
""" % (snap_file, src_volume['name']) "backing-filename": "%s"
img_info = imageutils.QemuImgInfo(qemu_img_output) }""" % (snap_file, src_volume['name'])
img_info = imageutils.QemuImgInfo(qemu_img_output, format='json')
# mocking and testing starts here # mocking and testing starts here
image_utils.convert_image = mock.Mock() image_utils.convert_image = mock.Mock()
@ -1092,13 +1095,14 @@ class QuobyteDriverTestCase(test.TestCase):
size = dest_volume['size'] size = dest_volume['size']
qemu_img_output = """image: %s qemu_img_output = """{
file format: raw "filename": "%s",
virtual size: 1.0G (1073741824 bytes) "format": "raw",
disk size: 173K "virtual-size": 1073741824,
backing file: %s "actual-size": 173000,
""" % (snap_file, src_volume['name']) "backing-filename": "%s"
img_info = imageutils.QemuImgInfo(qemu_img_output) }""" % (snap_file, src_volume['name'])
img_info = imageutils.QemuImgInfo(qemu_img_output, format='json')
# mocking and testing starts here # mocking and testing starts here
image_utils.convert_image = mock.Mock() image_utils.convert_image = mock.Mock()
@ -1156,13 +1160,14 @@ class QuobyteDriverTestCase(test.TestCase):
size = dest_volume['size'] size = dest_volume['size']
qemu_img_output = """image: %s qemu_img_output = """{
file format: raw "filename": "%s",
virtual size: 1.0G (1073741824 bytes) "format": "raw",
disk size: 173K "virtual-size": 1073741824,
backing file: %s "actual-size": 173000,
""" % (snap_file, src_volume['name']) "backing-filename": "%s"
img_info = imageutils.QemuImgInfo(qemu_img_output) }""" % (snap_file, src_volume['name'])
img_info = imageutils.QemuImgInfo(qemu_img_output, format='json')
# mocking and testing starts here # mocking and testing starts here
image_utils.convert_image = mock.Mock() image_utils.convert_image = mock.Mock()
@ -1247,12 +1252,13 @@ class QuobyteDriverTestCase(test.TestCase):
drv._get_hash_str(self.TEST_QUOBYTE_VOLUME)) drv._get_hash_str(self.TEST_QUOBYTE_VOLUME))
vol_path = os.path.join(vol_dir, volume['name']) vol_path = os.path.join(vol_dir, volume['name'])
qemu_img_output = """image: %s qemu_img_output = """{
file format: raw "filename": "%s",
virtual size: 1.0G (1073741824 bytes) "format": "raw",
disk size: 173K "virtual-size": 1073741824,
""" % volume['name'] "actual-size": 173000
img_info = imageutils.QemuImgInfo(qemu_img_output) }""" % volume['name']
img_info = imageutils.QemuImgInfo(qemu_img_output, format='json')
drv.get_active_image_from_info = mock.Mock(return_value=volume['name']) drv.get_active_image_from_info = mock.Mock(return_value=volume['name'])
image_utils.qemu_img_info = mock.Mock(return_value=img_info) image_utils.qemu_img_info = mock.Mock(return_value=img_info)
@ -1293,12 +1299,13 @@ class QuobyteDriverTestCase(test.TestCase):
mock_create_temporary_file.return_value = self.TEST_TMP_FILE mock_create_temporary_file.return_value = self.TEST_TMP_FILE
qemu_img_output = """image: %s qemu_img_output = """{
file format: raw "filename": "%s",
virtual size: 1.0G (1073741824 bytes) "format": "raw",
disk size: 173K "virtual-size": 1073741824,
""" % volume['name'] "actual-size": 173000
img_info = imageutils.QemuImgInfo(qemu_img_output) }""" % volume['name']
img_info = imageutils.QemuImgInfo(qemu_img_output, format='json')
mock_qemu_img_info.return_value = img_info mock_qemu_img_info.return_value = img_info
upload_path = volume_path upload_path = volume_path
@ -1340,12 +1347,13 @@ class QuobyteDriverTestCase(test.TestCase):
mock_create_temporary_file.return_value = self.TEST_TMP_FILE mock_create_temporary_file.return_value = self.TEST_TMP_FILE
qemu_img_output = """image: %s qemu_img_output = """{
file format: qcow2 "filename": "%s",
virtual size: 1.0G (1073741824 bytes) "format": "qcow2",
disk size: 173K "virtual-size": 1073741824,
""" % volume['name'] "actual-size": 173000
img_info = imageutils.QemuImgInfo(qemu_img_output) }""" % volume['name']
img_info = imageutils.QemuImgInfo(qemu_img_output, format='json')
mock_qemu_img_info.return_value = img_info mock_qemu_img_info.return_value = img_info
upload_path = self.TEST_TMP_FILE upload_path = self.TEST_TMP_FILE
@ -1390,13 +1398,14 @@ class QuobyteDriverTestCase(test.TestCase):
mock_create_temporary_file.return_value = self.TEST_TMP_FILE mock_create_temporary_file.return_value = self.TEST_TMP_FILE
qemu_img_output = """image: volume-%s.%s qemu_img_output = """{
file format: qcow2 "filename": "volume-%s.%s",
virtual size: 1.0G (1073741824 bytes) "format": "qcow2",
disk size: 173K "virtual-size": 1073741824,
backing file: %s "actual-size": 173000,
""" % (self.VOLUME_UUID, self.SNAP_UUID, volume_filename) "backing-filename": "%s"
img_info = imageutils.QemuImgInfo(qemu_img_output) }""" % (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 mock_qemu_img_info.return_value = img_info
upload_path = self.TEST_TMP_FILE upload_path = self.TEST_TMP_FILE

View File

@ -20,6 +20,7 @@ from oslo_config import cfg
from oslo_log import log as logging from oslo_log import log as logging
from oslo_utils import excutils from oslo_utils import excutils
from oslo_utils import fileutils from oslo_utils import fileutils
from oslo_utils import strutils
from oslo_utils import timeutils from oslo_utils import timeutils
import six import six
import taskflow.engines import taskflow.engines
@ -551,7 +552,8 @@ class CreateVolumeFromSpecTask(flow_utils.CinderTask):
volume, volume,
encryption) 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" key_str = source_pass + "\n" + new_pass + "\n"
del source_pass del source_pass