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)
This commit is contained in:
Takashi Kajinami
2021-07-06 21:48:44 +09:00
committed by Brian Rosmaita
parent d061455d4f
commit 6a1260ea80
5 changed files with 193 additions and 167 deletions

View File

@@ -122,7 +122,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')
@@ -136,7 +136,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

@@ -335,102 +335,112 @@ 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
"""
QEMU_IMG_INFO_OUT5 = """image: volume-%(volid)s.%(snapid)s QEMU_IMG_INFO_OUT5 = """{
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,
encrypted: yes "actual-size": 196000,
cluster_size: 65536 "encrypted": true,
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 "format-specific": {
lazy refcounts: false "type": "luks",
refcount bits: 16 "data": {
encrypt: "ivgen-alg": "plain64",
ivgen alg: plain64 "hash-alg": "sha256",
hash alg: sha256 "cipher-alg": "aes-256",
cipher alg: aes-256 "uuid": "386f8626-33f0-4683-a517-78ddfe385e33",
uuid: 386f8626-33f0-4683-a517-78ddfe385e33 "cipher-mode": "xts",
format: luks "slots": [
cipher mode: xts {
slots: "active": true,
[0]: "iters": 1892498,
active: true "key offset": 4096,
iters: 1892498 "stripes": 4000
key offset: 4096 },
stripes: 4000 {
[1]: "active": false,
active: false "key offset": 262144
key offset: 262144 },
[2]: {
active: false "active": false,
key offset: 520192 "key offset": 520192
[3]: },
active: false {
key offset: 778240 "active": false,
[4]: "key offset": 778240
active: false },
key offset: 1036288 {
[5]: "active": false,
active: false "key offset": 1036288
key offset: 1294336 },
[6]: {
active: false "active": false,
key offset: 1552384 "key offset": 1294336
[7]: },
active: false {
key offset: 1810432 "active": false,
payload offset: 2068480 "key offset": 1552384
master key iters: 459347 },
corrupt: false {
""" "active": false,
"key offset": 1810432
}
],
"payload-offset": 2068480,
"master-key-iters": 459347
},
"corrupt": false
}
}"""
@ddt.ddt @ddt.ddt
@@ -1312,7 +1322,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')
@@ -1392,7 +1402,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
@@ -1458,7 +1468,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})
@@ -1478,12 +1489,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

@@ -940,13 +940,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()
@@ -986,13 +987,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()
@@ -1042,13 +1044,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()
@@ -1103,13 +1106,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()
@@ -1167,13 +1171,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()
@@ -1244,12 +1249,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
@@ -1345,12 +1352,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
@@ -1400,13 +1408,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

@@ -21,6 +21,7 @@ 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 netutils from oslo_utils import netutils
from oslo_utils import strutils
from oslo_utils import timeutils from oslo_utils import timeutils
from oslo_utils import uuidutils from oslo_utils import uuidutils
import six import six
@@ -552,7 +553,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