libvirt: Use oslo.utils >= 4.1.0 to fetch format-specific image data

This change is a follow up to I0c3f14100a18107f7e416293f3d4fcc641ce5e55
and removes the direct call to nova.privsep.qemu with one to the images
API that now returns an oslo_utils.imageutils.QemuImgInfo object.
Version 4.1.0 of oslo.utils introducing support for the format-specific
data returned by qemu-img info for LUKSv1 based images.

Change-Id: I573396116e10cf87f80f1ded55f2cd8f498859e4
This commit is contained in:
Lee Yarwood 2020-03-02 14:13:20 +00:00
parent 961df12393
commit a486ee6272
5 changed files with 30 additions and 39 deletions

View File

@ -87,7 +87,7 @@ oslo.rootwrap==5.8.0
oslo.serialization==2.21.1
oslo.service==1.40.1
oslo.upgradecheck==0.1.1
oslo.utils==3.40.2
oslo.utils==4.1.0
oslo.versionedobjects==1.35.0
oslo.vmware==2.17.0
oslotest==3.8.0

View File

@ -9223,7 +9223,7 @@ class LibvirtConnTestCase(test.NoDBTestCase,
block_device.resize.assert_not_called()
@mock.patch('os_brick.encryptors.get_encryption_metadata')
@mock.patch('nova.privsep.qemu.privileged_qemu_img_info')
@mock.patch('nova.virt.images.privileged_qemu_img_info')
def test_extend_volume_luksv1_DiskNotFound(self, mock_qemu_img_info,
mock_get_encryption_metadata):
drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), False)
@ -9261,7 +9261,7 @@ class LibvirtConnTestCase(test.NoDBTestCase,
block_device.resize.assert_not_called()
@mock.patch('os_brick.encryptors.get_encryption_metadata')
@mock.patch('nova.privsep.qemu.privileged_qemu_img_info')
@mock.patch('nova.virt.images.privileged_qemu_img_info')
def test_extend_volume_luksv1_block(self, mock_qemu_img_info,
mock_get_encryption_metadata):
drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), False)
@ -9279,9 +9279,6 @@ class LibvirtConnTestCase(test.NoDBTestCase,
guest.get_block_device.return_value = block_device
guest.get_power_state.return_value = power_state.RUNNING
conn = mock.Mock()
conn.getVersion = mock.Mock(return_value=mock.sentinel.qemu_version)
# The requested_size is provided to extend_volume in bytes.
new_size = 20 * units.Gi
# The LUKSv1 payload offset as reported by qemu-img info in bytes.
@ -9289,13 +9286,11 @@ class LibvirtConnTestCase(test.NoDBTestCase,
# The new size is provided to Libvirt virDomainBlockResize in units.Ki.
new_size_minus_offset_kb = (new_size - payload_offset) // units.Ki
drvr._host.get_connection = mock.Mock(return_value=conn)
drvr._host.get_guest = mock.Mock(return_value=guest)
drvr._extend_volume = mock.Mock(return_value=new_size)
info_dict = {
'format-specific': {'data': {'payload-offset': payload_offset}}}
mock_qemu_img_info.return_value = jsonutils.dumps(info_dict)
mock_qemu_img_info.return_value = mock.Mock(
format_specific={'data': {'payload-offset': payload_offset}})
mock_get_encryption_metadata.return_value = {
'provider': 'luks',
'control_location': 'front-end'}
@ -9311,15 +9306,14 @@ class LibvirtConnTestCase(test.NoDBTestCase,
mock_get_encryption_metadata.assert_called_once_with(
self.context, drvr._volume_api, uuids.volume_id, connection_info)
mock_qemu_img_info.assert_called_once_with(
mock.sentinel.device_path, output_format='json',
qemu_version=mock.sentinel.qemu_version)
mock.sentinel.device_path, output_format='json')
# Assert that the Libvirt call to resize the device within the instance
# is called with the LUKSv1 payload offset taken into account.
block_device.resize.assert_called_once_with(new_size_minus_offset_kb)
@mock.patch('os_brick.encryptors.get_encryption_metadata')
@mock.patch('nova.privsep.qemu.privileged_qemu_img_info')
@mock.patch('nova.virt.images.privileged_qemu_img_info')
def test_extend_volume_luksv1_rbd(self, mock_qemu_img_info,
mock_get_encryption_metadata):
drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), False)
@ -9343,9 +9337,6 @@ class LibvirtConnTestCase(test.NoDBTestCase,
guest.get_power_state.return_value = power_state.RUNNING
guest.get_all_disks.return_value = [disk_1, disk_2]
conn = mock.Mock()
conn.getVersion = mock.Mock(return_value=mock.sentinel.qemu_version)
# The requested_size is provided to extend_volume in bytes.
new_size = 20 * units.Gi
# The LUKSv1 payload offset as reported by qemu-img info in bytes.
@ -9353,13 +9344,11 @@ class LibvirtConnTestCase(test.NoDBTestCase,
# The new size is provided to Libvirt virDomainBlockResize in units.Ki.
new_size_minus_offset_kb = (new_size - payload_offset) // units.Ki
drvr._host.get_connection = mock.Mock(return_value=conn)
drvr._host.get_guest = mock.Mock(return_value=guest)
drvr._extend_volume = mock.Mock(return_value=new_size)
info_dict = {
'format-specific': {'data': {'payload-offset': payload_offset}}}
mock_qemu_img_info.return_value = jsonutils.dumps(info_dict)
mock_qemu_img_info.return_value = mock.Mock(
format_specific={'data': {'payload-offset': payload_offset}})
mock_get_encryption_metadata.return_value = {
'provider': 'luks',
'control_location': 'front-end'}
@ -9375,8 +9364,7 @@ class LibvirtConnTestCase(test.NoDBTestCase,
mock_get_encryption_metadata.assert_called_once_with(
self.context, drvr._volume_api, uuids.volume_id, connection_info)
mock_qemu_img_info.assert_called_once_with(
'rbd:pool/volume', output_format='json',
qemu_version=mock.sentinel.qemu_version)
'rbd:pool/volume', output_format='json')
# Assert that the Libvirt call to resize the device within the instance
# is called with the LUKSv1 payload offset taken into account.

View File

@ -59,6 +59,22 @@ def qemu_img_info(path, format=None, output_format=None):
return imageutils.QemuImgInfo(info)
def privileged_qemu_img_info(path, format=None, output_format=None):
"""Return an object containing the parsed output from qemu-img info."""
# TODO(mikal): this code should not be referring to a libvirt specific
# flag.
if not os.path.exists(path) and CONF.libvirt.images_type != 'rbd':
raise exception.DiskNotFound(location=path)
info = nova.privsep.qemu.privileged_qemu_img_info(
path, format=format, qemu_version=QEMU_VERSION,
output_format=output_format)
if output_format:
return imageutils.QemuImgInfo(info, format=output_format)
else:
return imageutils.QemuImgInfo(info)
def convert_image(source, dest, in_format, out_format, run_as_root=False,
compress=False):
"""Convert image to other format."""

View File

@ -1956,22 +1956,9 @@ class LibvirtDriver(driver.ComputeDriver):
path = 'unknown'
raise exception.DiskNotFound(location='unknown')
# TODO(lyarwood): The following direct call to privsep instead
# of images.qemu_img_info avoids the need to bump
# requirements.txt to depend on a new version of oslo.utils
# that provides a version of QemuImgInfo that includes the
# format_specific attribute allowing this bugfix to be
# backported. Once landed we can replace this with the
# following and require oslo.utils >= 4.1.0:
#
# info = images.qemu_img_info(path, output_format='json',
# run_as_root=True)
# format_specific_data = info.format_specific['data']
info_dict = nova.privsep.qemu.privileged_qemu_img_info(
path, output_format='json',
qemu_version=self._host.get_connection().getVersion())
info = jsonutils.loads(info_dict)
format_specific_data = info['format-specific']['data']
info = images.privileged_qemu_img_info(
path, output_format='json')
format_specific_data = info.format_specific['data']
payload_offset = format_specific_data['payload-offset']
# NOTE(lyarwood): Ensure the underlying device is not resized

View File

@ -41,7 +41,7 @@ oslo.log>=3.36.0 # Apache-2.0
oslo.reports>=1.18.0 # Apache-2.0
oslo.serialization!=2.19.1,>=2.21.1 # Apache-2.0
oslo.upgradecheck>=0.1.1
oslo.utils>=3.40.2 # Apache-2.0
oslo.utils>=4.1.0 # Apache-2.0
oslo.db>=4.44.0 # Apache-2.0
oslo.rootwrap>=5.8.0 # Apache-2.0
oslo.messaging>=10.3.0 # Apache-2.0