Make image_conversion use action wrapper

This makes the image_conversion plugin use the action wrapper for
its image inspection and mutation activities.

Note that several important actions from the execute handler are not
asserted in the test, so this adds those checks to make sure they
are actually happening.

Change-Id: I575dbc45781aaed521aeb5ef085322ad2018f378
This commit is contained in:
Dan Smith 2021-02-09 10:38:52 -08:00
parent 050802dd67
commit d2bb1252e6
2 changed files with 31 additions and 21 deletions

View File

@ -62,19 +62,22 @@ class _ConvertImage(task.Task):
default_provides = 'file_path' default_provides = 'file_path'
def __init__(self, context, task_id, task_type, def __init__(self, context, task_id, task_type, action_wrapper):
image_repo, image_id):
self.context = context self.context = context
self.task_id = task_id self.task_id = task_id
self.task_type = task_type self.task_type = task_type
self.image_repo = image_repo self.action_wrapper = action_wrapper
self.image_id = image_id self.image_id = action_wrapper.image_id
self.dest_path = "" self.dest_path = ""
self.python = CONF.wsgi.python_interpreter self.python = CONF.wsgi.python_interpreter
super(_ConvertImage, self).__init__( super(_ConvertImage, self).__init__(
name='%s-Convert_Image-%s' % (task_type, task_id)) name='%s-Convert_Image-%s' % (task_type, task_id))
def execute(self, file_path, **kwargs): def execute(self, file_path, **kwargs):
with self.action_wrapper as action:
return self._execute(action, file_path, **kwargs)
def _execute(self, action, file_path, **kwargs):
target_format = CONF.image_conversion.output_format target_format = CONF.image_conversion.output_format
# TODO(jokke): Once we support other schemas we need to take them into # TODO(jokke): Once we support other schemas we need to take them into
@ -111,13 +114,11 @@ class _ConvertImage(task.Task):
raise RuntimeError(msg) raise RuntimeError(msg)
virtual_size = metadata.get('virtual-size', 0) virtual_size = metadata.get('virtual-size', 0)
image = self.image_repo.get(self.image_id) action.set_image_attribute(virtual_size=virtual_size)
image.virtual_size = virtual_size
if source_format == target_format: if source_format == target_format:
LOG.debug("Source is already in target format, " LOG.debug("Source is already in target format, "
"not doing conversion for %s", self.image_id) "not doing conversion for %s", self.image_id)
self.image_repo.save(image)
return file_path return file_path
try: try:
@ -135,9 +136,8 @@ class _ConvertImage(task.Task):
if stderr: if stderr:
raise RuntimeError(stderr) raise RuntimeError(stderr)
image.disk_format = target_format action.set_image_attribute(disk_format=target_format,
image.container_format = 'bare' container_format='bare')
self.image_repo.save(image)
os.remove(src_path) os.remove(src_path)
@ -161,14 +161,13 @@ def get_flow(**kwargs):
:param task_type: Type of the task. :param task_type: Type of the task.
:param image_repo: Image repository used. :param image_repo: Image repository used.
:param image_id: Image ID :param image_id: Image ID
:param action_wrapper: An api_image_import.ActionWrapper.
""" """
context = kwargs.get('context') context = kwargs.get('context')
task_id = kwargs.get('task_id') task_id = kwargs.get('task_id')
task_type = kwargs.get('task_type') task_type = kwargs.get('task_type')
image_repo = kwargs.get('image_repo') action_wrapper = kwargs.get('action_wrapper')
image_id = kwargs.get('image_id')
return lf.Flow(task_type).add( return lf.Flow(task_type).add(
_ConvertImage(context, task_id, task_type, _ConvertImage(context, task_id, task_type, action_wrapper)
image_repo, image_id),
) )

View File

@ -21,6 +21,7 @@ import glance_store
from oslo_concurrency import processutils from oslo_concurrency import processutils
from oslo_config import cfg from oslo_config import cfg
import glance.async_.flows.api_image_import as import_flow
import glance.async_.flows.plugins.image_conversion as image_conversion import glance.async_.flows.plugins.image_conversion as image_conversion
from glance.async_ import utils as async_utils from glance.async_ import utils as async_utils
from glance.common import utils from glance.common import utils
@ -79,24 +80,32 @@ class TestConvertImageTask(test_utils.BaseTestCase):
task_time_to_live=task_ttl, task_time_to_live=task_ttl,
task_input=task_input) task_input=task_input)
self.image.extra_properties = {
'os_glance_import_task': self.task.task_id}
self.wrapper = import_flow.ImportActionWrapper(self.img_repo,
self.image_id,
self.task.task_id)
@mock.patch.object(os, 'remove') @mock.patch.object(os, 'remove')
def test_image_convert_success(self, mock_os_remove): def test_image_convert_success(self, mock_os_remove):
mock_os_remove.return_value = None mock_os_remove.return_value = None
image_convert = image_conversion._ConvertImage(self.context, image_convert = image_conversion._ConvertImage(self.context,
self.task.task_id, self.task.task_id,
self.task_type, self.task_type,
self.img_repo, self.wrapper)
self.image_id)
self.task_repo.get.return_value = self.task self.task_repo.get.return_value = self.task
image = mock.MagicMock(image_id=self.image_id, virtual_size=None, image = mock.MagicMock(image_id=self.image_id, virtual_size=None,
extra_properties={
'os_glance_import_task': self.task.task_id},
disk_format='qcow2') disk_format='qcow2')
self.img_repo.get.return_value = image self.img_repo.get.return_value = image
with mock.patch.object(processutils, 'execute') as exc_mock: with mock.patch.object(processutils, 'execute') as exc_mock:
exc_mock.return_value = ("", None) exc_mock.return_value = ("", None)
with mock.patch.object(json, 'loads') as jloads_mock: with mock.patch.object(json, 'loads') as jloads_mock:
jloads_mock.return_value = {'format': 'raw'} jloads_mock.return_value = {'format': 'raw',
'virtual-size': 123}
image_convert.execute('file:///test/path.raw') image_convert.execute('file:///test/path.raw')
# NOTE(hemanthm): Asserting that the source format is passed # NOTE(hemanthm): Asserting that the source format is passed
@ -106,12 +115,15 @@ class TestConvertImageTask(test_utils.BaseTestCase):
self.assertIn('-f', exc_mock.call_args[0]) self.assertIn('-f', exc_mock.call_args[0])
self.assertEqual("qcow2", image.disk_format) self.assertEqual("qcow2", image.disk_format)
self.assertEqual('bare', image.container_format)
self.assertEqual('qcow2', image.disk_format)
self.assertEqual(123, image.virtual_size)
def _setup_image_convert_info_fail(self): def _setup_image_convert_info_fail(self):
image_convert = image_conversion._ConvertImage(self.context, image_convert = image_conversion._ConvertImage(self.context,
self.task.task_id, self.task.task_id,
self.task_type, self.task_type,
self.img_repo, self.wrapper)
self.image_id)
self.task_repo.get.return_value = self.task self.task_repo.get.return_value = self.task
image = mock.MagicMock(image_id=self.image_id, virtual_size=None, image = mock.MagicMock(image_id=self.image_id, virtual_size=None,
@ -235,8 +247,7 @@ class TestConvertImageTask(test_utils.BaseTestCase):
image_convert = image_conversion._ConvertImage(self.context, image_convert = image_conversion._ConvertImage(self.context,
self.task.task_id, self.task.task_id,
self.task_type, self.task_type,
self.img_repo, self.wrapper)
self.image_id)
self.task_repo.get.return_value = self.task self.task_repo.get.return_value = self.task