From a486ee62727af6b09a540e744a1da32396fdf21d Mon Sep 17 00:00:00 2001 From: Lee Yarwood Date: Mon, 2 Mar 2020 14:13:20 +0000 Subject: [PATCH] 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 --- lower-constraints.txt | 2 +- nova/tests/unit/virt/libvirt/test_driver.py | 30 +++++++-------------- nova/virt/images.py | 16 +++++++++++ nova/virt/libvirt/driver.py | 19 +++---------- requirements.txt | 2 +- 5 files changed, 30 insertions(+), 39 deletions(-) diff --git a/lower-constraints.txt b/lower-constraints.txt index 8c52736d68..72e2734d63 100644 --- a/lower-constraints.txt +++ b/lower-constraints.txt @@ -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 diff --git a/nova/tests/unit/virt/libvirt/test_driver.py b/nova/tests/unit/virt/libvirt/test_driver.py index b9013354cf..d4f809b3fb 100644 --- a/nova/tests/unit/virt/libvirt/test_driver.py +++ b/nova/tests/unit/virt/libvirt/test_driver.py @@ -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. diff --git a/nova/virt/images.py b/nova/virt/images.py index f4f0da623d..85ce6ce2fb 100644 --- a/nova/virt/images.py +++ b/nova/virt/images.py @@ -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.""" diff --git a/nova/virt/libvirt/driver.py b/nova/virt/libvirt/driver.py index 6afee2bf27..1891366e67 100644 --- a/nova/virt/libvirt/driver.py +++ b/nova/virt/libvirt/driver.py @@ -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 diff --git a/requirements.txt b/requirements.txt index 52da5c2316..1f5010b0c8 100644 --- a/requirements.txt +++ b/requirements.txt @@ -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