Don't include plugins on 'copy-image' import

The import plugins were designed to interact with the image data
or metadata before the image becomes active. It does not make sense
to try to run them on 'copy-image' taskflow which is just copying
the data between stores on active image.

Co-Authored-By: Erno Kuvaja <jokke@usr.fi>
Co-Authored-By: Abhishek Kekane <akekane@redhat.com>

Closes-Bug: #1885725
Change-Id: I2df30aa26f96a0f210989758868b42bcb9d2d72f
This commit is contained in:
Erno Kuvaja 2020-06-30 14:28:09 +01:00 committed by Dan Smith
parent 63d982588f
commit b8332d9b6b
3 changed files with 164 additions and 2 deletions

View File

@ -435,8 +435,14 @@ def get_flow(**kwargs):
flow.add(_VerifyStaging(task_id, task_type, task_repo, file_uri))
for plugin in import_plugins.get_import_plugins(**kwargs):
flow.add(plugin)
# Note(jokke): The plugins were designed to act on the image data or
# metadata during the import process before the image goes active. It
# does not make sense to try to execute them during 'copy-image'.
if import_method != 'copy-image':
for plugin in import_plugins.get_import_plugins(**kwargs):
flow.add(plugin)
else:
LOG.debug("Skipping plugins on 'copy-image' job.")
for idx, store in enumerate(stores, 1):
set_active = (not all_stores_must_succeed) or (idx == len(stores))

View File

@ -16,9 +16,16 @@
from unittest import mock
import glance_store as store
from oslo_config import cfg
from taskflow.patterns import linear_flow
import glance.async_
from glance.async_.flows import api_image_import
import glance.tests.utils as test_utils
CONF = cfg.CONF
class TestTaskExecutor(test_utils.BaseTestCase):
@ -47,3 +54,146 @@ class TestTaskExecutor(test_utils.BaseTestCase):
# assert the call
mock_run.assert_called_once_with(task_id, task_type)
class TestImportTaskFlow(test_utils.BaseTestCase):
def setUp(self):
super(TestImportTaskFlow, self).setUp()
store.register_opts(CONF)
self.config(default_store='file',
stores=['file', 'http'],
filesystem_store_datadir=self.test_dir,
group="glance_store")
self.config(enabled_import_methods=[
'glance-direct', 'web-download', 'copy-image'])
self.config(node_staging_uri='file:///tmp/staging')
store.create_stores(CONF)
self.base_flow = ['ConfigureStaging', 'ImportToStore',
'DeleteFromFS', 'SaveImage',
'CompleteTask']
self.import_plugins = ['Convert_Image',
'Decompress_Image',
'InjectMetadataProperties']
def _get_flow(self, import_req=None):
inputs = {
'task_id': mock.MagicMock(),
'task_type': mock.MagicMock(),
'task_repo': mock.MagicMock(),
'image_repo': mock.MagicMock(),
'image_id': mock.MagicMock(),
'import_req': import_req or mock.MagicMock()
}
flow = api_image_import.get_flow(**inputs)
return flow
def _get_flow_tasks(self, flow):
flow_comp = []
for c, p in flow.iter_nodes():
if isinstance(c, linear_flow.Flow):
flow_comp += self._get_flow_tasks(c)
else:
name = str(c).split('-')
if len(name) > 1:
flow_comp.append(name[1])
return flow_comp
def test_get_default_flow(self):
# This test will ensure that without import plugins
# and without internal plugins flow builds with the
# base_flow components
flow = self._get_flow()
flow_comp = self._get_flow_tasks(flow)
# assert flow has 5 tasks
self.assertEqual(5, len(flow_comp))
for c in self.base_flow:
self.assertIn(c, flow_comp)
def test_get_flow_web_download_enabled(self):
# This test will ensure that without import plugins
# and with web-download plugin flow builds with
# base_flow components and '_WebDownload'
import_req = {
'method': {
'name': 'web-download',
'uri': 'http://cloud.foo/image.qcow2'
}
}
flow = self._get_flow(import_req=import_req)
flow_comp = self._get_flow_tasks(flow)
# assert flow has 6 tasks
self.assertEqual(6, len(flow_comp))
for c in self.base_flow:
self.assertIn(c, flow_comp)
self.assertIn('WebDownload', flow_comp)
@mock.patch.object(store, 'get_store_from_store_identifier')
def test_get_flow_copy_image_enabled(self, mock_store):
# This test will ensure that without import plugins
# and with copy-image plugin flow builds with
# base_flow components and '_CopyImage'
import_req = {
'method': {
'name': 'copy-image',
'stores': ['fake-store']
}
}
mock_store.return_value = mock.Mock()
flow = self._get_flow(import_req=import_req)
flow_comp = self._get_flow_tasks(flow)
# assert flow has 6 tasks
self.assertEqual(6, len(flow_comp))
for c in self.base_flow:
self.assertIn(c, flow_comp)
self.assertIn('CopyImage', flow_comp)
def test_get_flow_with_all_plugins_enabled(self):
# This test will ensure that flow includes import plugins
# and base flow
self.config(image_import_plugins=['image_conversion',
'image_decompression',
'inject_image_metadata'],
group='image_import_opts')
flow = self._get_flow()
flow_comp = self._get_flow_tasks(flow)
# assert flow has 8 tasks (base_flow + plugins)
self.assertEqual(8, len(flow_comp))
for c in self.base_flow:
self.assertIn(c, flow_comp)
for c in self.import_plugins:
self.assertIn(c, flow_comp)
@mock.patch.object(store, 'get_store_from_store_identifier')
def test_get_flow_copy_image_not_includes_import_plugins(
self, mock_store):
# This test will ensure that flow does not includes import
# plugins as import method is copy image
self.config(image_import_plugins=['image_conversion',
'image_decompression',
'inject_image_metadata'],
group='image_import_opts')
mock_store.return_value = mock.Mock()
import_req = {
'method': {
'name': 'copy-image',
'stores': ['fake-store']
}
}
flow = self._get_flow(import_req=import_req)
flow_comp = self._get_flow_tasks(flow)
# assert flow has 6 tasks
self.assertEqual(6, len(flow_comp))
for c in self.base_flow:
self.assertIn(c, flow_comp)
self.assertIn('CopyImage', flow_comp)

View File

@ -0,0 +1,6 @@
---
fixes:
- |
* Bug 1885725_: 'copy-image' import job should not run additional plugins
.. _1885725: https://code.launchpad.net/bugs/1885725