Merge "image_utils: Detect missing device before calling qemu-img convert"
This commit is contained in:
@@ -51,6 +51,7 @@ from cinder.i18n import _
|
|||||||
from cinder.image import accelerator
|
from cinder.image import accelerator
|
||||||
from cinder.image import glance
|
from cinder.image import glance
|
||||||
import cinder.privsep.format_inspector
|
import cinder.privsep.format_inspector
|
||||||
|
import cinder.privsep.path
|
||||||
from cinder import utils
|
from cinder import utils
|
||||||
from cinder.volume import throttling
|
from cinder.volume import throttling
|
||||||
from cinder.volume import volume_utils
|
from cinder.volume import volume_utils
|
||||||
@@ -376,6 +377,16 @@ def check_qemu_img_version(minimum_version: str) -> None:
|
|||||||
raise exception.VolumeBackendAPIException(data=_msg)
|
raise exception.VolumeBackendAPIException(data=_msg)
|
||||||
|
|
||||||
|
|
||||||
|
def _ensure_exists(dest_path: str) -> None:
|
||||||
|
# Ensure that "dest" exists if it is in /dev/
|
||||||
|
# This prevents qemu-img from creating a file in /dev/
|
||||||
|
# if the block device has disappeared.
|
||||||
|
if dest_path.startswith('/dev/'):
|
||||||
|
if not cinder.privsep.path.exists(dest_path):
|
||||||
|
raise exception.CinderException(
|
||||||
|
"qemu-img convert destination %s does not exist" % dest_path)
|
||||||
|
|
||||||
|
|
||||||
def _convert_image(
|
def _convert_image(
|
||||||
prefix: tuple,
|
prefix: tuple,
|
||||||
source: str,
|
source: str,
|
||||||
@@ -443,6 +454,8 @@ def _convert_image(
|
|||||||
src_passphrase_file=src_passphrase_file,
|
src_passphrase_file=src_passphrase_file,
|
||||||
disable_sparse=disable_sparse)
|
disable_sparse=disable_sparse)
|
||||||
|
|
||||||
|
_ensure_exists(dest)
|
||||||
|
|
||||||
start_time = timeutils.utcnow()
|
start_time = timeutils.utcnow()
|
||||||
|
|
||||||
# If there is not enough space on the conversion partition, include
|
# If there is not enough space on the conversion partition, include
|
||||||
|
|||||||
@@ -37,3 +37,8 @@ def symlink(src, dest):
|
|||||||
if not os.path.exists(src):
|
if not os.path.exists(src):
|
||||||
raise exception.FileNotFound(file_path=src)
|
raise exception.FileNotFound(file_path=src)
|
||||||
os.symlink(src, dest)
|
os.symlink(src, dest)
|
||||||
|
|
||||||
|
|
||||||
|
@cinder.privsep.sys_admin_pctxt.entrypoint
|
||||||
|
def exists(path: str | os.PathLike) -> bool:
|
||||||
|
return os.path.exists(path)
|
||||||
|
|||||||
@@ -264,6 +264,8 @@ class TestQemuImgInfo(test.TestCase):
|
|||||||
|
|
||||||
@ddt.ddt
|
@ddt.ddt
|
||||||
class TestConvertImage(test.TestCase):
|
class TestConvertImage(test.TestCase):
|
||||||
|
@mock.patch('cinder.image.image_utils._ensure_exists',
|
||||||
|
new=mock.MagicMock())
|
||||||
@mock.patch('cinder.image.image_utils.qemu_img_info')
|
@mock.patch('cinder.image.image_utils.qemu_img_info')
|
||||||
@mock.patch('cinder.utils.execute')
|
@mock.patch('cinder.utils.execute')
|
||||||
@mock.patch('cinder.utils.is_blk_device', return_value=True)
|
@mock.patch('cinder.utils.is_blk_device', return_value=True)
|
||||||
@@ -296,6 +298,8 @@ class TestConvertImage(test.TestCase):
|
|||||||
'-O', out_format, source, dest,
|
'-O', out_format, source, dest,
|
||||||
run_as_root=True)
|
run_as_root=True)
|
||||||
|
|
||||||
|
@mock.patch('cinder.image.image_utils._ensure_exists',
|
||||||
|
new=mock.MagicMock())
|
||||||
@mock.patch('cinder.image.image_utils.qemu_img_info')
|
@mock.patch('cinder.image.image_utils.qemu_img_info')
|
||||||
@mock.patch('cinder.utils.execute')
|
@mock.patch('cinder.utils.execute')
|
||||||
@mock.patch('cinder.utils.is_blk_device', return_value=True)
|
@mock.patch('cinder.utils.is_blk_device', return_value=True)
|
||||||
@@ -333,6 +337,8 @@ class TestConvertImage(test.TestCase):
|
|||||||
'-O', out_format, source, dest,
|
'-O', out_format, source, dest,
|
||||||
run_as_root=True)
|
run_as_root=True)
|
||||||
|
|
||||||
|
@mock.patch('cinder.image.image_utils._ensure_exists',
|
||||||
|
new=mock.MagicMock())
|
||||||
@mock.patch('cinder.volume.volume_utils.check_for_odirect_support',
|
@mock.patch('cinder.volume.volume_utils.check_for_odirect_support',
|
||||||
return_value=True)
|
return_value=True)
|
||||||
@mock.patch('cinder.image.image_utils.qemu_img_info')
|
@mock.patch('cinder.image.image_utils.qemu_img_info')
|
||||||
@@ -358,6 +364,8 @@ class TestConvertImage(test.TestCase):
|
|||||||
source, dest,
|
source, dest,
|
||||||
run_as_root=True)
|
run_as_root=True)
|
||||||
|
|
||||||
|
@mock.patch('cinder.image.image_utils._ensure_exists',
|
||||||
|
new=mock.MagicMock())
|
||||||
@mock.patch('cinder.volume.volume_utils.check_for_odirect_support',
|
@mock.patch('cinder.volume.volume_utils.check_for_odirect_support',
|
||||||
return_value=True)
|
return_value=True)
|
||||||
@mock.patch('cinder.image.image_utils.qemu_img_info')
|
@mock.patch('cinder.image.image_utils.qemu_img_info')
|
||||||
@@ -383,6 +391,8 @@ class TestConvertImage(test.TestCase):
|
|||||||
source, dest,
|
source, dest,
|
||||||
run_as_root=True)
|
run_as_root=True)
|
||||||
|
|
||||||
|
@mock.patch('cinder.image.image_utils._ensure_exists',
|
||||||
|
new=mock.MagicMock())
|
||||||
@mock.patch('cinder.image.image_utils.qemu_img_info')
|
@mock.patch('cinder.image.image_utils.qemu_img_info')
|
||||||
@mock.patch('cinder.utils.execute')
|
@mock.patch('cinder.utils.execute')
|
||||||
@mock.patch('cinder.utils.is_blk_device', return_value=True)
|
@mock.patch('cinder.utils.is_blk_device', return_value=True)
|
||||||
@@ -403,6 +413,8 @@ class TestConvertImage(test.TestCase):
|
|||||||
'-O', out_format, '-t', 'none',
|
'-O', out_format, '-t', 'none',
|
||||||
source, dest, run_as_root=True)
|
source, dest, run_as_root=True)
|
||||||
|
|
||||||
|
@mock.patch('cinder.image.image_utils._ensure_exists',
|
||||||
|
new=mock.MagicMock())
|
||||||
@mock.patch('cinder.image.image_utils.qemu_img_info')
|
@mock.patch('cinder.image.image_utils.qemu_img_info')
|
||||||
@mock.patch('cinder.utils.execute')
|
@mock.patch('cinder.utils.execute')
|
||||||
@mock.patch('cinder.utils.is_blk_device', return_value=False)
|
@mock.patch('cinder.utils.is_blk_device', return_value=False)
|
||||||
@@ -422,6 +434,8 @@ class TestConvertImage(test.TestCase):
|
|||||||
source, dest, run_as_root=True)
|
source, dest, run_as_root=True)
|
||||||
|
|
||||||
@ddt.data(True, False)
|
@ddt.data(True, False)
|
||||||
|
@mock.patch('cinder.image.image_utils._ensure_exists',
|
||||||
|
new=mock.MagicMock())
|
||||||
@mock.patch('cinder.image.image_utils.qemu_img_info')
|
@mock.patch('cinder.image.image_utils.qemu_img_info')
|
||||||
@mock.patch('cinder.utils.execute')
|
@mock.patch('cinder.utils.execute')
|
||||||
@mock.patch('cinder.utils.is_blk_device', return_value=False)
|
@mock.patch('cinder.utils.is_blk_device', return_value=False)
|
||||||
@@ -446,6 +460,8 @@ class TestConvertImage(test.TestCase):
|
|||||||
mock_exec.assert_called_once_with(*exec_args,
|
mock_exec.assert_called_once_with(*exec_args,
|
||||||
run_as_root=True)
|
run_as_root=True)
|
||||||
|
|
||||||
|
@mock.patch('cinder.image.image_utils._ensure_exists',
|
||||||
|
new=mock.MagicMock())
|
||||||
@mock.patch('cinder.image.image_utils.qemu_img_info')
|
@mock.patch('cinder.image.image_utils.qemu_img_info')
|
||||||
@mock.patch('cinder.utils.execute')
|
@mock.patch('cinder.utils.execute')
|
||||||
@mock.patch('cinder.utils.is_blk_device', return_value=False)
|
@mock.patch('cinder.utils.is_blk_device', return_value=False)
|
||||||
@@ -464,6 +480,8 @@ class TestConvertImage(test.TestCase):
|
|||||||
'-O', out_format, '-S', '0', source,
|
'-O', out_format, '-S', '0', source,
|
||||||
dest, run_as_root=True)
|
dest, run_as_root=True)
|
||||||
|
|
||||||
|
@mock.patch('cinder.image.image_utils._ensure_exists',
|
||||||
|
new=mock.MagicMock())
|
||||||
@mock.patch('cinder.volume.volume_utils.check_for_odirect_support',
|
@mock.patch('cinder.volume.volume_utils.check_for_odirect_support',
|
||||||
return_value=True)
|
return_value=True)
|
||||||
@mock.patch('cinder.image.image_utils.qemu_img_info')
|
@mock.patch('cinder.image.image_utils.qemu_img_info')
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
---
|
||||||
|
fixes:
|
||||||
|
- |
|
||||||
|
`Bug #2132083 <https://bugs.launchpad.net/cinder/+bug/2132083>`_: When
|
||||||
|
creating a volume from an image, a storage connectivity failure or
|
||||||
|
similar could result in the local block device node disappearing. In
|
||||||
|
this situation, avoid writing the image to a file in /dev/ when calling
|
||||||
|
qemu-img.
|
||||||
Reference in New Issue
Block a user