Working on Data Flow (step 2)
* Added ExpressionEvaluator interface and YAQL implementation * Removed yaql_utils, evaluator is now a more flexible replacement * Fixed the places where yaql_utils was used * Adjusted test cases Change-Id: I7de70e678c211df34788763047b8361de0d3902a
This commit is contained in:
parent
58407b6f94
commit
b3c23b7e1b
@ -64,7 +64,7 @@ def get_rest_action(task):
|
|||||||
|
|
||||||
# input_yaql = task.get('input')
|
# input_yaql = task.get('input')
|
||||||
# TODO(nmakhotkin) extract input from context within the YAQL expression
|
# TODO(nmakhotkin) extract input from context within the YAQL expression
|
||||||
task_input = {} # yaql_utils.evaluate(input_yaql, ctx)
|
task_input = {} # expressions.evaluate(input_expr, ctx)
|
||||||
task_data = {}
|
task_data = {}
|
||||||
|
|
||||||
if method.upper() == "GET":
|
if method.upper() == "GET":
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
from mistral.engine.actions import action_types as a_t
|
from mistral.engine.actions import action_types as a_t
|
||||||
from mistral import exceptions as exc
|
from mistral import exceptions as exc
|
||||||
from mistral.engine import states
|
from mistral.engine import states
|
||||||
from mistral.utils import yaql_utils
|
from mistral.engine import expressions as expr
|
||||||
|
|
||||||
|
|
||||||
def get_action_type(task):
|
def get_action_type(task):
|
||||||
@ -30,16 +30,17 @@ def is_task_synchronous(task):
|
|||||||
|
|
||||||
def extract_state_result(action, action_result):
|
def extract_state_result(action, action_result):
|
||||||
# All non-Mistral tasks are sync-auto because service doesn't know
|
# All non-Mistral tasks are sync-auto because service doesn't know
|
||||||
# about Mistral and we need to receive the result immediately
|
# about Mistral and we need to receive the result immediately.
|
||||||
if action.type != a_t.MISTRAL_REST_API:
|
if action.type != a_t.MISTRAL_REST_API:
|
||||||
if action.result_helper.get('select'):
|
if action.result_helper.get('select'):
|
||||||
result = yaql_utils.evaluate(action.result_helper['select'],
|
result = expr.evaluate(action.result_helper['select'],
|
||||||
action_result)
|
action_result)
|
||||||
# TODO(nmakhotkin) get state for other actions
|
# TODO(nmakhotkin) get state for other actions
|
||||||
state = states.get_state_by_http_status_code(action.status)
|
state = states.get_state_by_http_status_code(action.status)
|
||||||
else:
|
else:
|
||||||
raise exc.InvalidActionException("Cannot get the result of sync "
|
raise exc.InvalidActionException("Cannot get the result of sync "
|
||||||
"task without YAQL expression")
|
"task without YAQL expression")
|
||||||
|
|
||||||
return state, result
|
return state, result
|
||||||
raise exc.InvalidActionException("Error. Wrong type of action to "
|
raise exc.InvalidActionException("Error. Wrong type of action to "
|
||||||
"retrieve the result")
|
"retrieve the result")
|
||||||
|
57
mistral/engine/expressions.py
Normal file
57
mistral/engine/expressions.py
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# Copyright 2013 - Mirantis, Inc.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
|
||||||
|
import abc
|
||||||
|
import yaql
|
||||||
|
|
||||||
|
from mistral.openstack.common import log as logging
|
||||||
|
|
||||||
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class Evaluator(object):
|
||||||
|
"""Expression evaluator interface.
|
||||||
|
|
||||||
|
Having this interface gives the flexibility to change the actual expression
|
||||||
|
language used in Mistral DSL for conditions, output calculation etc.
|
||||||
|
"""
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
@abc.abstractmethod
|
||||||
|
def evaluate(cls, expression, context):
|
||||||
|
"""Evaluates the expression against the given data context.
|
||||||
|
|
||||||
|
:param expression: Expression string
|
||||||
|
:param context: Data context
|
||||||
|
:return: Expression result
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class YAQLEvaluator(Evaluator):
|
||||||
|
@classmethod
|
||||||
|
def evaluate(cls, expression, context):
|
||||||
|
LOG.debug("Evaluating YAQL expression [expression='%s', context=%s]")
|
||||||
|
|
||||||
|
return yaql.parse(expression).evaluate(context)
|
||||||
|
|
||||||
|
|
||||||
|
# TODO(rakhmerov): Make it configurable.
|
||||||
|
_EVALUATOR = YAQLEvaluator()
|
||||||
|
|
||||||
|
|
||||||
|
def evaluate(expression, context):
|
||||||
|
_EVALUATOR.evaluate(expression, context)
|
@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
import unittest2
|
import unittest2
|
||||||
|
|
||||||
from mistral.utils import yaql_utils
|
from mistral.engine import expressions as expr
|
||||||
|
|
||||||
|
|
||||||
DATA = {
|
DATA = {
|
||||||
@ -44,33 +44,37 @@ SERVERS = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class YaqlTest(unittest2.TestCase):
|
class YaqlEvaluatorTest(unittest2.TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
super(YaqlEvaluatorTest, self).setUp()
|
||||||
|
self._evaluator = expr.YAQLEvaluator()
|
||||||
|
|
||||||
def test_expression_result(self):
|
def test_expression_result(self):
|
||||||
res = yaql_utils.evaluate("$.server", DATA)
|
res = self._evaluator.evaluate('$.server', DATA)
|
||||||
self.assertEqual(res, {
|
self.assertEqual(res, {
|
||||||
"id": "03ea824a-aa24-4105-9131-66c48ae54acf",
|
'id': "03ea824a-aa24-4105-9131-66c48ae54acf",
|
||||||
"name": "cloud-fedora",
|
'name': 'cloud-fedora',
|
||||||
"status": "ACTIVE"
|
'status': 'ACTIVE'
|
||||||
})
|
})
|
||||||
|
|
||||||
res = yaql_utils.evaluate("$.server.id", DATA)
|
res = self._evaluator.evaluate('$.server.id', DATA)
|
||||||
self.assertEqual(res, "03ea824a-aa24-4105-9131-66c48ae54acf")
|
self.assertEqual(res, '03ea824a-aa24-4105-9131-66c48ae54acf')
|
||||||
|
|
||||||
res = yaql_utils.evaluate("$.server.status = 'ACTIVE'", DATA)
|
res = self._evaluator.evaluate("$.server.status = 'ACTIVE'", DATA)
|
||||||
self.assertTrue(res)
|
self.assertTrue(res)
|
||||||
|
|
||||||
def test_wrong_expression(self):
|
def test_wrong_expression(self):
|
||||||
res = yaql_utils.evaluate("$.status = 'Invalid value'", DATA)
|
res = self._evaluator.evaluate("$.status = 'Invalid value'", DATA)
|
||||||
self.assertFalse(res)
|
self.assertFalse(res)
|
||||||
|
|
||||||
res = yaql_utils.evaluate("$.wrong_key", DATA)
|
res = self._evaluator.evaluate('$.wrong_key', DATA)
|
||||||
self.assertIsNone(res)
|
self.assertIsNone(res)
|
||||||
|
|
||||||
expression_str = "invalid_expression_string"
|
expression_str = 'invalid_expression_string'
|
||||||
res = yaql_utils.evaluate(expression_str, DATA)
|
res = self._evaluator.evaluate(expression_str, DATA)
|
||||||
self.assertEqual(res, expression_str)
|
self.assertEqual(res, expression_str)
|
||||||
|
|
||||||
def test_select_result(self):
|
def test_select_result(self):
|
||||||
res = yaql_utils.evaluate("$.servers[$.name = ubuntu]", SERVERS)
|
res = self._evaluator.evaluate('$.servers[$.name = ubuntu]', SERVERS)
|
||||||
item = list(res)[0]
|
item = list(res)[0]
|
||||||
self.assertEqual(item, {'name': 'ubuntu'})
|
self.assertEqual(item, {'name': 'ubuntu'})
|
@ -1,21 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
#
|
|
||||||
# Copyright 2013 - Mirantis, Inc.
|
|
||||||
#
|
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
# you may not use this file except in compliance with the License.
|
|
||||||
# You may obtain a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
# See the License for the specific language governing permissions and
|
|
||||||
# limitations under the License.
|
|
||||||
|
|
||||||
import yaql
|
|
||||||
|
|
||||||
|
|
||||||
def evaluate(expression_str, data):
|
|
||||||
return yaql.parse(expression_str).evaluate(data)
|
|
Loading…
Reference in New Issue
Block a user