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
This commit is contained in:
Nikolay Mahotkin 2014-04-16 18:33:24 +04:00
parent afffb51b25
commit bc0838aa15
5 changed files with 95 additions and 90 deletions

View File

@ -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()

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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)