From bc0838aa15097c5599b53f31381512076d6f2044 Mon Sep 17 00:00:00 2001 From: Nikolay Mahotkin Date: Wed, 16 Apr 2014 18:33:24 +0400 Subject: [PATCH] Fix convert params and result in AdHocAction * Fixed wrong convertation of action params and result. In action parameters we can have an arbitrary dict, so this dict can contain lists, or other dicts. To convert params we should apply converter dict to base spec params and action result accordingly. Change-Id: I7549931c69637dfdf2bfa6583b8a78f8589b40b4 --- mistral/actions/std_actions.py | 13 +--- mistral/engine/data_flow.py | 27 -------- mistral/expressions.py | 28 ++++++++ .../unit/engine/test_data_flow_module.py | 52 --------------- mistral/tests/unit/test_expressions.py | 65 ++++++++++++++++++- 5 files changed, 95 insertions(+), 90 deletions(-) diff --git a/mistral/actions/std_actions.py b/mistral/actions/std_actions.py index 197a36f70..5c53a9698 100644 --- a/mistral/actions/std_actions.py +++ b/mistral/actions/std_actions.py @@ -22,8 +22,8 @@ import requests from mistral.openstack.common import log as logging from mistral.actions import base -from mistral import exceptions as exc from mistral import expressions as expr +from mistral import exceptions as exc from mistral.utils import ssh_utils @@ -214,8 +214,7 @@ class AdHocAction(base.Action): if not base_params_spec: return {} - return dict((k, expr.evaluate(v, params)) - for k, v in base_params_spec.iteritems()) + return expr.evaluate_recursively(base_params_spec, params) def _convert_result(self, result): transformer = self.action_spec.output @@ -224,13 +223,7 @@ class AdHocAction(base.Action): return result # Use base action result as a context for evaluating expressions. - if isinstance(transformer, dict): - return dict((k, expr.evaluate(v, result)) - for k, v in transformer.iteritems()) - elif isinstance(transformer, list): - return [expr.evaluate(item, result) for item in transformer] - else: - return expr.evaluate(transformer, result) + return expr.evaluate_recursively(transformer, result) def is_sync(self): return self.base_action.is_sync() diff --git a/mistral/engine/data_flow.py b/mistral/engine/data_flow.py index 6f24f0136..97f73b631 100644 --- a/mistral/engine/data_flow.py +++ b/mistral/engine/data_flow.py @@ -14,7 +14,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -import six from oslo.config import cfg from mistral.db import api as db_api @@ -95,29 +94,3 @@ def add_token_to_context(context, db_workbook): context.update(workbook_ctx.to_dict()) return context - - -def _modify_item(item, context): - if isinstance(item, six.string_types): - try: - return expr.evaluate(item, context) - except AttributeError as e: - LOG.debug("Expression %s is not evaluated, [context=%s]: %s" - % (item, context, e)) - return item - else: - return apply_context(item, context) - - -def apply_context(data, context): - if not context: - return data - - if isinstance(data, dict): - for key in data: - data[key] = _modify_item(data[key], context) - elif isinstance(data, list): - for index, item in enumerate(data): - data[index] = _modify_item(item, context) - - return data diff --git a/mistral/expressions.py b/mistral/expressions.py index 4ca659700..10ad7da5d 100644 --- a/mistral/expressions.py +++ b/mistral/expressions.py @@ -112,3 +112,31 @@ def evaluate(expression, context): return expression return _EVALUATOR.evaluate(expression, context) + + +def _evaluate_item(item, context): + if isinstance(item, six.string_types): + try: + return evaluate(item, context) + except AttributeError as e: + LOG.debug("Expression %s is not evaluated, [context=%s]: %s" + % (item, context, e)) + return item + else: + return evaluate_recursively(item, context) + + +def evaluate_recursively(data, context): + if not context: + return data + + if isinstance(data, dict): + for key in data: + data[key] = _evaluate_item(data[key], context) + elif isinstance(data, list): + for index, item in enumerate(data): + data[index] = _evaluate_item(item, context) + elif isinstance(data, six.string_types): + return _evaluate_item(data, context) + + return data diff --git a/mistral/tests/unit/engine/test_data_flow_module.py b/mistral/tests/unit/engine/test_data_flow_module.py index 0128ec4ea..c5b1b37cb 100644 --- a/mistral/tests/unit/engine/test_data_flow_module.py +++ b/mistral/tests/unit/engine/test_data_flow_module.py @@ -97,55 +97,3 @@ class DataFlowModuleTest(base.DbTestCase): } }, output) - - def test_apply_context(self): - task_spec_dict = TASK['task_spec'] - modified_task = data_flow.apply_context(task_spec_dict, CONTEXT) - - self.assertDictEqual( - { - 'parameters': { - 'p1': 'My string', - 'p2': 'val32', - 'p3': '' - }, - 'publish': { - 'new_key11': 'new_key1' - } - }, - modified_task) - - def test_apply_context_arbitrary(self): - context = { - "auth_token": "123", - "project_id": "mistral" - } - data = { - "parameters": { - "parameter1": { - "name1": "$.auth_token", - "name2": "val_name2" - }, - "param2": [ - "var1", - "var2", - "/servers/{$.project_id}/bla" - ] - }, - "token": "$.auth_token" - } - - applied = data_flow.apply_context(data, context) - - self.assertDictEqual( - { - "parameters": { - "parameter1": { - "name1": "123", - "name2": "val_name2" - }, - "param2": ["var1", "var2", "/servers/mistral/bla"] - }, - "token": "123" - }, - applied) diff --git a/mistral/tests/unit/test_expressions.py b/mistral/tests/unit/test_expressions.py index dfb7f89a1..5f627d656 100644 --- a/mistral/tests/unit/test_expressions.py +++ b/mistral/tests/unit/test_expressions.py @@ -28,7 +28,6 @@ DATA = { "status": "OK" } - SERVERS = { "servers": [ { @@ -78,3 +77,67 @@ class YaqlEvaluatorTest(unittest2.TestCase): res = self._evaluator.evaluate('$.servers[$.name = ubuntu]', SERVERS) item = list(res)[0] self.assertEqual(item, {'name': 'ubuntu'}) + + def test_evaluate_recursively(self): + task_spec_dict = { + 'parameters': { + 'p1': 'My string', + 'p2': '$.param2', + 'p3': '' + }, + 'publish': { + 'new_key11': 'new_key1' + } + } + modified_task = expr.evaluate_recursively(task_spec_dict, + { + 'param2': 'val32' + }) + + self.assertDictEqual( + { + 'parameters': { + 'p1': 'My string', + 'p2': 'val32', + 'p3': '' + }, + 'publish': { + 'new_key11': 'new_key1' + } + }, + modified_task) + + def test_evaluate_recursively_arbitrary_dict(self): + context = { + "auth_token": "123", + "project_id": "mistral" + } + data = { + "parameters": { + "parameter1": { + "name1": "$.auth_token", + "name2": "val_name2" + }, + "param2": [ + "var1", + "var2", + "/servers/{$.project_id}/bla" + ] + }, + "token": "$.auth_token" + } + + applied = expr.evaluate_recursively(data, context) + + self.assertDictEqual( + { + "parameters": { + "parameter1": { + "name1": "123", + "name2": "val_name2" + }, + "param2": ["var1", "var2", "/servers/mistral/bla"] + }, + "token": "123" + }, + applied)