Merge "NFS driver: Use database format in initialize_connection"
This commit is contained in:
@@ -31,6 +31,7 @@ import os
|
||||
import re
|
||||
import shutil
|
||||
import tempfile
|
||||
import typing
|
||||
from typing import ContextManager, Generator, Optional
|
||||
|
||||
import cryptography
|
||||
@@ -163,20 +164,28 @@ def qemu_img_info(
|
||||
path: str,
|
||||
run_as_root: bool = True,
|
||||
force_share: bool = False,
|
||||
allow_qcow2_backing_file: bool = False) -> imageutils.QemuImgInfo:
|
||||
allow_qcow2_backing_file: bool = False,
|
||||
img_format: Optional[str] = None) -> imageutils.QemuImgInfo:
|
||||
"""Return an object containing the parsed output from qemu-img info."""
|
||||
|
||||
format_name = cinder.privsep.format_inspector.get_format_if_safe(
|
||||
path=path,
|
||||
allow_qcow2_backing_file=allow_qcow2_backing_file)
|
||||
if format_name is None:
|
||||
LOG.warning('Image/Volume %s failed safety check', path)
|
||||
# NOTE(danms): This is the same exception as would be raised
|
||||
# by qemu_img_info() if the disk format was unreadable or
|
||||
# otherwise unsuitable.
|
||||
raise exception.Invalid(
|
||||
reason=_('Image/Volume failed safety check'))
|
||||
format_name = img_format
|
||||
# NOTE(sfernand): In case we are trying to inspect a raw volume containing
|
||||
# a qcow2 image, inspection will incorrectly report the inner (qcow2)
|
||||
# format, instead of the expected outer (raw) format. To avoid that, we
|
||||
# need skip format inspection if the Cinder volume is known to be raw.
|
||||
if img_format != 'raw':
|
||||
format_name = cinder.privsep.format_inspector.get_format_if_safe(
|
||||
path=path,
|
||||
allow_qcow2_backing_file=allow_qcow2_backing_file)
|
||||
if format_name is None:
|
||||
LOG.warning('Image/Volume %s failed safety check', path)
|
||||
# NOTE(danms): This is the same exception as would be raised
|
||||
# by qemu_img_info() if the disk format was unreadable or
|
||||
# otherwise unsuitable.
|
||||
raise exception.Invalid(
|
||||
reason=_('Image/Volume failed safety check'))
|
||||
|
||||
format_name = typing.cast(str, format_name)
|
||||
cmd = ['env', 'LC_ALL=C', 'qemu-img', 'info',
|
||||
'-f', format_name, '--output=json']
|
||||
if force_share:
|
||||
|
||||
@@ -336,6 +336,13 @@ NFS_CONFIG4 = {'max_over_subscription_ratio': 20.0,
|
||||
'nas_secure_file_permissions': 'false',
|
||||
'nas_secure_file_operations': 'true'}
|
||||
|
||||
VOLUME_ADMIN_METADATA_QCOW2_FORMAT = {
|
||||
'format': 'qcow2'
|
||||
}
|
||||
VOLUME_ADMIN_METADATA_RAW_FORMAT = {
|
||||
'format', 'raw'
|
||||
}
|
||||
|
||||
QEMU_IMG_INFO_OUT1 = """{
|
||||
"filename": "%(volid)s",
|
||||
"format": "raw",
|
||||
@@ -1372,10 +1379,12 @@ class NfsDriverTestCase(test.TestCase):
|
||||
mock_read_info_file.assert_called_once_with(info_path)
|
||||
snap_info_call = mock.call(snap_path,
|
||||
force_share=True, run_as_root=True,
|
||||
allow_qcow2_backing_file=True)
|
||||
allow_qcow2_backing_file=True,
|
||||
img_format=None)
|
||||
src_info_call = mock.call(src_vol_path,
|
||||
force_share=True, run_as_root=True,
|
||||
allow_qcow2_backing_file=True)
|
||||
allow_qcow2_backing_file=True,
|
||||
img_format=None)
|
||||
self.assertEqual(2, mock_img_info.call_count)
|
||||
mock_img_info.assert_has_calls([snap_info_call, src_info_call])
|
||||
used_qcow = nfs_conf['nfs_qcow2_volumes']
|
||||
@@ -1483,16 +1492,22 @@ class NfsDriverTestCase(test.TestCase):
|
||||
new_volume,
|
||||
fake_snap)
|
||||
|
||||
@ddt.data([NFS_CONFIG1, QEMU_IMG_INFO_OUT1],
|
||||
[NFS_CONFIG2, QEMU_IMG_INFO_OUT2],
|
||||
[NFS_CONFIG3, QEMU_IMG_INFO_OUT1],
|
||||
[NFS_CONFIG4, QEMU_IMG_INFO_OUT2])
|
||||
@ddt.data([NFS_CONFIG1, QEMU_IMG_INFO_OUT1, 'raw'],
|
||||
[NFS_CONFIG2, QEMU_IMG_INFO_OUT2, 'qcow2'],
|
||||
[NFS_CONFIG3, QEMU_IMG_INFO_OUT1, 'raw'],
|
||||
[NFS_CONFIG4, QEMU_IMG_INFO_OUT2, 'qcow2'])
|
||||
@ddt.unpack
|
||||
def test_initialize_connection(self, nfs_confs, qemu_img_info):
|
||||
@mock.patch('cinder.objects.volume.Volume.get_by_id')
|
||||
@mock.patch('cinder.context.get_admin_context')
|
||||
def test_initialize_connection(self, nfs_confs, qemu_img_info,
|
||||
expected_format, mock_get_admin_context,
|
||||
mock_volume_get_by_id):
|
||||
self._set_driver(extra_confs=nfs_confs)
|
||||
drv = self._driver
|
||||
|
||||
volume = self._simple_volume()
|
||||
volume.admin_metadata = {'format': expected_format}
|
||||
|
||||
vol_dir = os.path.join(self.TEST_MNT_POINT_BASE,
|
||||
drv._get_hash_str(volume.provider_location))
|
||||
vol_path = os.path.join(vol_dir, volume.name)
|
||||
@@ -1510,17 +1525,24 @@ class NfsDriverTestCase(test.TestCase):
|
||||
mock_img_utils.assert_called_once_with(vol_path,
|
||||
force_share=True,
|
||||
run_as_root=True,
|
||||
allow_qcow2_backing_file=True)
|
||||
allow_qcow2_backing_file=True,
|
||||
img_format=expected_format)
|
||||
|
||||
self.assertEqual('nfs', conn_info['driver_volume_type'])
|
||||
self.assertEqual(volume.name, conn_info['data']['name'])
|
||||
self.assertEqual(self.TEST_MNT_POINT_BASE,
|
||||
conn_info['mount_point_base'])
|
||||
self.assertEqual(expected_format, conn_info['data']['format'])
|
||||
|
||||
@mock.patch.object(image_utils, 'qemu_img_info')
|
||||
def test_initialize_connection_raise_exception(self, mock_img_info):
|
||||
@mock.patch('cinder.objects.volume.Volume.get_by_id')
|
||||
def test_initialize_connection_raise_exception(self, mock_get,
|
||||
mock_img_info):
|
||||
self._set_driver()
|
||||
drv = self._driver
|
||||
volume = self._simple_volume()
|
||||
volume.admin_metadata = {}
|
||||
mock_get.return_value = volume
|
||||
|
||||
qemu_img_output = """{
|
||||
"filename": "%s",
|
||||
@@ -1538,10 +1560,14 @@ class NfsDriverTestCase(test.TestCase):
|
||||
None)
|
||||
|
||||
@mock.patch.object(image_utils, 'qemu_img_info')
|
||||
def test_initialize_connection_raise_on_wrong_size(self, mock_img_info):
|
||||
@mock.patch('cinder.objects.volume.Volume.get_by_id')
|
||||
def test_initialize_connection_raise_on_wrong_size(self, mock_get,
|
||||
mock_img_info):
|
||||
self._set_driver()
|
||||
drv = self._driver
|
||||
volume = self._simple_volume()
|
||||
volume.admin_metadata = {}
|
||||
mock_get.return_value = volume
|
||||
|
||||
qemu_img_output = """{
|
||||
"filename": "%s",
|
||||
|
||||
@@ -273,7 +273,8 @@ class QuobyteDriverTestCase(test.TestCase):
|
||||
mock_qemu_img_info.assert_called_with(mock.sentinel.image_path,
|
||||
force_share=True,
|
||||
run_as_root=True,
|
||||
allow_qcow2_backing_file=True)
|
||||
allow_qcow2_backing_file=True,
|
||||
img_format=None)
|
||||
|
||||
@ddt.data(['/other_random_path', '/mnt'],
|
||||
['/other_basedir/' + TEST_MNT_HASH + '/volume-' + VOLUME_UUID,
|
||||
@@ -986,7 +987,8 @@ class QuobyteDriverTestCase(test.TestCase):
|
||||
volume_path,
|
||||
force_share=True,
|
||||
run_as_root=False,
|
||||
allow_qcow2_backing_file=True)
|
||||
allow_qcow2_backing_file=True,
|
||||
img_format=None)
|
||||
image_utils.resize_image.assert_called_once_with(volume_path, 3)
|
||||
|
||||
def test_copy_volume_from_snapshot(self):
|
||||
@@ -1034,7 +1036,8 @@ class QuobyteDriverTestCase(test.TestCase):
|
||||
snap_path,
|
||||
force_share=True,
|
||||
run_as_root=False,
|
||||
allow_qcow2_backing_file=True)
|
||||
allow_qcow2_backing_file=True,
|
||||
img_format=None)
|
||||
(mock_convert.
|
||||
assert_called_once_with(src_vol_path,
|
||||
dest_vol_path,
|
||||
@@ -1094,7 +1097,8 @@ class QuobyteDriverTestCase(test.TestCase):
|
||||
snap_path,
|
||||
force_share=True,
|
||||
run_as_root=False,
|
||||
allow_qcow2_backing_file=True)
|
||||
allow_qcow2_backing_file=True,
|
||||
img_format=None)
|
||||
self.assertFalse(mock_convert.called,
|
||||
("_convert_image was called but should not have been")
|
||||
)
|
||||
@@ -1160,7 +1164,8 @@ class QuobyteDriverTestCase(test.TestCase):
|
||||
snap_path,
|
||||
force_share=True,
|
||||
run_as_root=False,
|
||||
allow_qcow2_backing_file=True)
|
||||
allow_qcow2_backing_file=True,
|
||||
img_format=None)
|
||||
(mock_convert.
|
||||
assert_called_once_with(
|
||||
src_vol_path,
|
||||
@@ -1225,7 +1230,8 @@ class QuobyteDriverTestCase(test.TestCase):
|
||||
snap_path,
|
||||
force_share=True,
|
||||
run_as_root=False,
|
||||
allow_qcow2_backing_file=True)
|
||||
allow_qcow2_backing_file=True,
|
||||
img_format=None)
|
||||
(mock_convert.
|
||||
assert_called_once_with(
|
||||
src_vol_path,
|
||||
@@ -1298,7 +1304,8 @@ class QuobyteDriverTestCase(test.TestCase):
|
||||
vol_path,
|
||||
force_share=True,
|
||||
run_as_root=False,
|
||||
allow_qcow2_backing_file=True)
|
||||
allow_qcow2_backing_file=True,
|
||||
img_format=None)
|
||||
|
||||
self.assertEqual('raw', conn_info['data']['format'])
|
||||
self.assertEqual('quobyte', conn_info['driver_volume_type'])
|
||||
@@ -1351,7 +1358,8 @@ class QuobyteDriverTestCase(test.TestCase):
|
||||
volume_path,
|
||||
force_share=True,
|
||||
run_as_root=False,
|
||||
allow_qcow2_backing_file=True)
|
||||
allow_qcow2_backing_file=True,
|
||||
img_format=None)
|
||||
mock_upload_volume.assert_called_once_with(
|
||||
mock.ANY, mock.ANY, mock.ANY, upload_path, run_as_root=False,
|
||||
store_id=None, base_image_ref=None, compress=True,
|
||||
@@ -1406,7 +1414,8 @@ class QuobyteDriverTestCase(test.TestCase):
|
||||
volume_path,
|
||||
force_share=True,
|
||||
run_as_root=False,
|
||||
allow_qcow2_backing_file=True)
|
||||
allow_qcow2_backing_file=True,
|
||||
img_format=None)
|
||||
mock_convert_image.assert_called_once_with(
|
||||
volume_path, upload_path, 'raw', run_as_root=False)
|
||||
mock_upload_volume.assert_called_once_with(
|
||||
@@ -1465,7 +1474,8 @@ class QuobyteDriverTestCase(test.TestCase):
|
||||
volume_path,
|
||||
force_share=True,
|
||||
run_as_root=False,
|
||||
allow_qcow2_backing_file=True)
|
||||
allow_qcow2_backing_file=True,
|
||||
img_format=None)
|
||||
mock_convert_image.assert_called_once_with(
|
||||
volume_path, upload_path, 'raw', run_as_root=False)
|
||||
mock_upload_volume.assert_called_once_with(
|
||||
|
||||
@@ -676,7 +676,8 @@ class RemoteFsSnapDriverTestCase(test.TestCase):
|
||||
mock_qemu_img_info.assert_called_with(mock.sentinel.image_path,
|
||||
force_share=False,
|
||||
run_as_root=True,
|
||||
allow_qcow2_backing_file=True)
|
||||
allow_qcow2_backing_file=True,
|
||||
img_format=None)
|
||||
|
||||
@ddt.data([None, '/fake_basedir'],
|
||||
['/fake_basedir/cb2016/fake_vol_name', '/fake_basedir'],
|
||||
|
||||
@@ -141,8 +141,19 @@ class NfsDriver(remotefs.RemoteFSSnapDriverDistributed):
|
||||
active_vol = self.get_active_image_from_info(volume)
|
||||
volume_dir = self._local_volume_dir(volume)
|
||||
path_to_vol = os.path.join(volume_dir, active_vol)
|
||||
|
||||
vol_format = None
|
||||
admin_metadata = None
|
||||
# admin context is required for admin_metadata
|
||||
with volume.obj_as_admin():
|
||||
admin_metadata = volume.admin_metadata
|
||||
|
||||
if admin_metadata and 'format' in admin_metadata:
|
||||
vol_format = admin_metadata['format']
|
||||
|
||||
info = self._qemu_img_info(path_to_vol,
|
||||
volume['name'])
|
||||
volume['name'],
|
||||
img_format=vol_format)
|
||||
|
||||
data = {'export': volume.provider_location,
|
||||
'name': active_vol}
|
||||
@@ -581,13 +592,14 @@ class NfsDriver(remotefs.RemoteFSSnapDriverDistributed):
|
||||
|
||||
self._delete(base_volume_path)
|
||||
|
||||
def _qemu_img_info(self, path, volume_name):
|
||||
def _qemu_img_info(self, path, volume_name, img_format=None):
|
||||
return super(NfsDriver, self)._qemu_img_info_base(
|
||||
path,
|
||||
volume_name,
|
||||
self.configuration.nfs_mount_point_base,
|
||||
force_share=True,
|
||||
run_as_root=True)
|
||||
run_as_root=True,
|
||||
img_format=img_format)
|
||||
|
||||
def _check_snapshot_support(self, setup_checking=False):
|
||||
"""Ensure snapshot support is enabled in config."""
|
||||
|
||||
@@ -858,7 +858,8 @@ class RemoteFSSnapDriverBase(RemoteFSDriver):
|
||||
basedir: str,
|
||||
ext_bf_template=None,
|
||||
force_share=False,
|
||||
run_as_root=False) -> imageutils.QemuImgInfo:
|
||||
run_as_root=False,
|
||||
img_format=None) -> imageutils.QemuImgInfo:
|
||||
"""Sanitize image_utils' qemu_img_info.
|
||||
|
||||
This code expects to deal only with relative filenames.
|
||||
@@ -877,7 +878,8 @@ class RemoteFSSnapDriverBase(RemoteFSDriver):
|
||||
info = image_utils.qemu_img_info(path,
|
||||
force_share=force_share,
|
||||
run_as_root=run_as_root,
|
||||
allow_qcow2_backing_file=True)
|
||||
allow_qcow2_backing_file=True,
|
||||
img_format=img_format)
|
||||
if info.image:
|
||||
info.image = os.path.basename(info.image)
|
||||
if info.backing_file:
|
||||
|
||||
Reference in New Issue
Block a user