libvirt: Provide the backing file format when creating qcow2 disks

Libvirt v6.0.0 [1] will now fail to launch a domain when using qcow2
disks where the backing file format is not recorded in the qcow2
metadata.

There are some discussions upstream around relaxing this slightly [2]
but for now any attempt to launch an instance using qcow2 disks will
fail as Nova does not populate this value when creating the disk.

Nova needs to at a minimum start populating this field and depending on
the outcome of the thread upstream in Libvirt also potentially handle
the upgrade case where we may need to rebase existing disks in order to
update the metadata.

For now this change simply adds the backing_fmt option to the qemu-img
command line used to create these disks.

[1] 3615e8b39b
[2] https://www.redhat.com/archives/libvir-list/2020-February/msg00616.html

Partial-Bug: #1864020
Change-Id: I77ebada015f6522a300be4fa043fb8676458402b
(cherry picked from commit 0cfe9c81e3)
This commit is contained in:
Lee Yarwood 2020-02-19 20:39:54 +00:00
parent 40c288b1fb
commit 7fd41e9b8c
2 changed files with 16 additions and 10 deletions

View File

@ -354,16 +354,21 @@ ID TAG VM SIZE DATE VM CLOCK
@mock.patch('os.path.exists', return_value=True)
@mock.patch('oslo_concurrency.processutils.execute')
def test_create_cow_image(self, mock_execute, mock_exists):
@mock.patch('nova.virt.images.qemu_img_info')
def test_create_cow_image(self, mock_info, mock_execute, mock_exists):
mock_execute.return_value = ('stdout', None)
libvirt_utils.create_cow_image('/some/path', '/the/new/cow')
expected_args = [(('env', 'LC_ALL=C', 'LANG=C',
'qemu-img', 'info', '/some/path'),
{'prlimit': images.QEMU_IMG_LIMITS}),
(('qemu-img', 'create', '-f', 'qcow2',
'-o', 'backing_file=/some/path',
'/the/new/cow'),)]
self.assertEqual(expected_args, mock_execute.call_args_list)
mock_info.return_value = mock.Mock(
file_format=mock.sentinel.backing_fmt,
cluster_size=mock.sentinel.cluster_size)
libvirt_utils.create_cow_image(mock.sentinel.backing_path,
mock.sentinel.new_path)
mock_info.assert_called_once_with(mock.sentinel.backing_path)
mock_execute.assert_has_calls([mock.call(
'qemu-img', 'create', '-f', 'qcow2', '-o',
'backing_file=%s,backing_fmt=%s,cluster_size=%s' % (
mock.sentinel.backing_path, mock.sentinel.backing_fmt,
mock.sentinel.cluster_size),
mock.sentinel.new_path)])
@ddt.unpack
@ddt.data({'fs_type': 'some_fs_type',

View File

@ -114,8 +114,9 @@ def create_cow_image(backing_file, path, size=None):
base_cmd = ['qemu-img', 'create', '-f', 'qcow2']
cow_opts = []
if backing_file:
cow_opts += ['backing_file=%s' % backing_file]
base_details = images.qemu_img_info(backing_file)
cow_opts += ['backing_file=%s' % backing_file]
cow_opts += ['backing_fmt=%s' % base_details.file_format]
else:
base_details = None
# Explicitly inherit the value of 'cluster_size' property of a qcow2