def _find_next_tasks(self, task_ex, ctx): t_n = task_ex.name t_s = task_ex.state ctx_view = data_flow.ContextView( data_flow.get_current_task_dict(task_ex), ctx, data_flow.get_workflow_environment_dict(self.wf_ex), self.wf_ex.context, self.wf_ex.input) # [(task_name, params, 'on-success'|'on-error'|'on-complete'), ...] result = [] if t_s == states.ERROR: for name, cond, params in self.wf_spec.get_on_error_clause(t_n): if not cond or expr.evaluate(cond, ctx_view): params = expr.evaluate_recursively(params, ctx_view) result.append((name, params, 'on-error')) if t_s == states.SUCCESS: for name, cond, params in self.wf_spec.get_on_success_clause(t_n): if not cond or expr.evaluate(cond, ctx_view): params = expr.evaluate_recursively(params, ctx_view) result.append((name, params, 'on-success')) if states.is_completed(t_s) and not states.is_cancelled(t_s): for name, cond, params in self.wf_spec.get_on_complete_clause(t_n): if not cond or expr.evaluate(cond, ctx_view): params = expr.evaluate_recursively(params, ctx_view) result.append((name, params, 'on-complete')) return result
def publish_variables(task_ex, task_spec): if task_ex.state not in [states.SUCCESS, states.ERROR]: return wf_ex = task_ex.workflow_execution expr_ctx = ContextView(task_ex.in_context, wf_ex.context, wf_ex.input) if task_ex.name in expr_ctx: LOG.warning( 'Shadowing context variable with task name while ' 'publishing: %s', task_ex.name ) publish_spec = task_spec.get_publish(task_ex.state) if not publish_spec: return # Publish branch variables. branch_vars = publish_spec.get_branch() task_ex.published = expr.evaluate_recursively(branch_vars, expr_ctx) # Publish global variables. global_vars = publish_spec.get_global() utils.merge_dicts( task_ex.workflow_execution.context, expr.evaluate_recursively(global_vars, expr_ctx) )
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 _convert_params(self, params): base_params_spec = self.action_spec.base_parameters if not base_params_spec: return {} return expr.evaluate_recursively(base_params_spec, params)
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)
def _get_adhoc_action_input(action_def, input_dict, wf_name=None, wf_spec=None): action_spec = spec_parser.get_action_spec(action_def.spec) base_name = action_spec.get_base() action_def = resolve_action_definition( base_name, wf_name if wf_name else None, wf_spec.get_name() if wf_spec else None ) _inject_action_ctx_for_validating(action_def, input_dict) e_utils.validate_input(action_def, input_dict, action_spec) base_input = action_spec.get_base_input() if base_input: input_dict = expr.evaluate_recursively( base_input, input_dict ) else: input_dict = {} return input_dict
def _schedule_run_action(task_ex, task_spec, action_input, index, wf_spec): action_spec_name = task_spec.get_action_name() action_def = action_handler.resolve_definition( action_spec_name, task_ex, wf_spec ) action_ex = action_handler.create_action_execution( action_def, action_input, task_ex, index ) target = expr.evaluate_recursively( task_spec.get_target(), utils.merge_dicts( copy.deepcopy(action_input), copy.deepcopy(task_ex.in_context) ) ) scheduler.schedule_call( None, 'mistral.engine.action_handler.run_existing_action', 0, action_ex_id=action_ex.id, target=target )
def _get_environment(params): env = params.get('env', {}) if not env: return {} if isinstance(env, dict): env_dict = env elif isinstance(env, six.string_types): env_db = db_api.load_environment(env) if not env_db: raise exc.InputException( 'Environment is not found: %s' % env ) env_dict = env_db.variables else: raise exc.InputException( 'Unexpected value type for environment [env=%s, type=%s]' % (env, type(env)) ) if ('evaluate_env' in params and not params['evaluate_env']): return env_dict else: return expr.evaluate_recursively(env_dict, {'__env': env_dict})
def evaluate_object_fields(obj, context): fields = inspect_utils.get_public_fields(obj) evaluated_fields = expr.evaluate_recursively(fields, context) for k, v in evaluated_fields.items(): setattr(obj, k, v)
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)
def _prepare_input(self, input_dict): base_input_dict = input_dict for action_def in self.adhoc_action_defs: action_spec = spec_parser.get_action_spec(action_def.spec) for k, v in action_spec.get_input().items(): if (k not in base_input_dict or base_input_dict[k] is utils.NotDefined): base_input_dict[k] = v base_input_expr = action_spec.get_base_input() if base_input_expr: ctx_view = data_flow.ContextView( base_input_dict, self.task_ctx, self.wf_ctx ) base_input_dict = expr.evaluate_recursively( base_input_expr, ctx_view ) else: base_input_dict = {} return super(AdHocAction, self)._prepare_input(base_input_dict)
def publish_variables(task_ex, task_spec): if task_ex.state not in [states.SUCCESS, states.ERROR]: return wf_ex = task_ex.workflow_execution expr_ctx = ContextView( task_ex.in_context, wf_ex.context, wf_ex.input ) if task_ex.name in expr_ctx: LOG.warning( 'Shadowing context variable with task name while publishing: %s' % task_ex.name ) data = ( task_spec.get_publish() if task_ex.state == states.SUCCESS else task_spec.get_publish_on_error() ) task_ex.published = expr.evaluate_recursively(data, expr_ctx)
def _evaluate_expression(self, expression, ctx=None): ctx_view = data_flow.ContextView( data_flow.get_current_task_dict(self.task_ex), data_flow.get_workflow_environment_dict(self.wf_ex), ctx or self.ctx, self.wf_ex.context, self.wf_ex.input) return expr.evaluate_recursively(expression, ctx_view)
def _prepare_input(self, input_dict): if self._prepared_input is not None: return self._prepared_input base_input_dict = input_dict for action_def in self.adhoc_action_defs: action_spec = spec_parser.get_action_spec(action_def.spec) for k, v in action_spec.get_input().items(): if (k not in base_input_dict or base_input_dict[k] is utils.NotDefined): base_input_dict[k] = v base_input_expr = action_spec.get_base_input() if base_input_expr: wf_ex = (self.task_ex.workflow_execution if self.task_ex else None) ctx_view = data_flow.ContextView( base_input_dict, self.task_ctx, data_flow.get_workflow_environment_dict(wf_ex), self.wf_ctx) base_input_dict = expr.evaluate_recursively( base_input_expr, ctx_view) else: base_input_dict = {} self._prepared_input = super(AdHocAction, self)._prepare_input(base_input_dict) return self._prepared_input
def _get_with_items_values(self): """Returns all values evaluated from 'with-items' expression. Example: DSL: with-items: - var1 in <% $.arrayI %> - var2 in <% $.arrayJ %> where arrayI = [1,2,3] and arrayJ = [a,b,c] The result of the method in this case will be: { 'var1': [1,2,3], 'var2': [a,b,c] } :return: Evaluated 'with-items' expression values. """ ctx_view = data_flow.ContextView( self.ctx, self.wf_ex.context, self.wf_ex.input ) return expr.evaluate_recursively( self.task_spec.get_with_items(), ctx_view )
def add_workflow_variables_to_context(wf_ex, wf_spec): wf_ex.context = wf_ex.context or {} return utils.merge_dicts( wf_ex.context, expr.evaluate_recursively(wf_spec.get_vars(), wf_ex.context) )
def test_evaluate_complex_expressions(self): data = { 'a': 1, 'b': 2, 'c': 3, 'd': True, 'e': False, 'f': 10.1, 'g': 10, 'h': [1, 2, 3, 4, 5], 'i': 'We are OpenStack!', 'j': 'World', 'k': 'Mistral', 'l': 'awesome', 'm': 'the way we roll' } test_cases = [('<% $.a + $.b * $.c %>', 7), ('<%($.a + $.b) * $.c %>', 9), ('<% $.d and $.e %>', False), ('<% $.f > $.g %>', True), ('<% $.h.len() >= 5 %>', True), ('<% $.h.len() >= $.b + $.c %>', True), ('<% 100 in $.h %>', False), ('<% $.a in $.h%>', True), ('<% ' 'OpenStack' ' in $.i %>', True), ('Hello, <% $.j %>!', 'Hello, World!'), ('<% $.k %> is <% $.l %>!', 'Mistral is awesome!'), ('This is <% $.m %>.', 'This is the way we roll.'), ('<% 1 + 1 = 3 %>', False)] for expression, expected in test_cases: actual = expr.evaluate_recursively(expression, data) self.assertEqual(expected, actual)
def _schedule_run_action(task_ex, task_spec, action_input, index): wf_ex = task_ex.workflow_execution wf_spec = spec_parser.get_workflow_spec(wf_ex.spec) action_spec_name = task_spec.get_action_name() action_def = action_handler.resolve_definition( action_spec_name, task_ex, wf_spec ) action_ex = action_handler.create_action_execution( action_def, action_input, task_ex, index ) target = expr.evaluate_recursively( task_spec.get_target(), utils.merge_dicts( copy.deepcopy(action_input), copy.copy(task_ex.in_context) ) ) scheduler.schedule_call( None, 'mistral.engine.action_handler.run_existing_action', 0, action_ex_id=action_ex.id, target=target )
def _get_target(self, input_dict): ctx_view = data_flow.ContextView( input_dict, self.ctx, data_flow.get_workflow_environment_dict(self.wf_ex), self.wf_ex.context, self.wf_ex.input) return expr.evaluate_recursively(self.task_spec.get_target(), ctx_view)
def add_environment_to_context(wf_ex): wf_ex.context = wf_ex.context or {} # If env variables are provided, add an evaluated copy into the context. if 'env' in wf_ex.params: env = copy.deepcopy(wf_ex.params['env']) # An env variable can be an expression of other env variables. wf_ex.context['__env'] = expr.evaluate_recursively(env, {'__env': env})
def _get_target(self, input_dict): return expr.evaluate_recursively( self.task_spec.get_target(), utils.merge_dicts( copy.deepcopy(input_dict), copy.deepcopy(self.ctx) ) )
def _convert_result(self, result): transformer = self.action_spec.output if not transformer: return result # Use base action result as a context for evaluating expressions. return expr.evaluate_recursively(transformer, result)
def _get_action_input(self, ctx=None): ctx = ctx or self.ctx input_dict = expr.evaluate_recursively(self.task_spec.get_input(), ctx) return utils.merge_dicts(input_dict, self._get_action_defaults(), overwrite=False)
def get_task_output(task, result): publish_transformer = task['task_spec'].get('publish') output = expr.evaluate_recursively(publish_transformer, result) or {} if result: output['task'] = {task['name']: result} return output
def _get_action_input(self, ctx=None): ctx = ctx or self.ctx input_dict = expr.evaluate_recursively(self.task_spec.get_input(), ctx) return utils.merge_dicts( input_dict, self._get_action_defaults(), overwrite=False )
def add_workflow_variables_to_context(wf_ex, wf_spec): wf_ex.context = wf_ex.context or {} # The context for calculating workflow variables is workflow input # and other data already stored in workflow initial context. ctx_view = ContextView(wf_ex.context, wf_ex.input) wf_vars = expr.evaluate_recursively(wf_spec.get_vars(), ctx_view) utils.merge_dicts(wf_ex.context, wf_vars)
def _prepare_input(self, input_dict): base_input_expr = self.action_spec.get_base_input() if base_input_expr: base_input_dict = expr.evaluate_recursively( base_input_expr, input_dict) else: base_input_dict = {} return super(AdHocAction, self)._prepare_input(base_input_dict)
def add_environment_to_context(wf_ex): # TODO(rakhmerov): This is redundant, we can always get env from WF params wf_ex.context = wf_ex.context or {} # If env variables are provided, add an evaluated copy into the context. if 'env' in wf_ex.params: env = copy.deepcopy(wf_ex.params['env']) # An env variable can be an expression of other env variables. wf_ex.context['__env'] = expr.evaluate_recursively(env, {'__env': env})
def _evaluate_expression(self, expression, ctx=None): ctx_view = data_flow.ContextView( data_flow.get_current_task_dict(self.task_ex), data_flow.get_workflow_environment_dict(self.wf_ex), ctx or self.ctx, self.wf_ex.context, self.wf_ex.input ) return expr.evaluate_recursively(expression, ctx_view)
def convert(self, event_type, event): edef = self.get_event_definition(event_type) if edef is None: LOG.debug('No event definition found for type: %s, use default ' 'settings instead.', event_type) return expressions.evaluate_recursively(DEFAULT_PROPERTIES, event) return edef.convert(event)
def _get_action_input(wf_spec, task_ex, task_spec, ctx): input_dict = expr.evaluate_recursively(task_spec.get_input(), ctx) action_spec_name = task_spec.get_action_name() action_def = e_utils.resolve_action_definition( task_ex.workflow_name, wf_spec.get_name(), action_spec_name ) input_dict = utils.merge_dicts( input_dict, _get_action_defaults(task_ex, task_spec), overwrite=False ) if action_def.spec: # Ad-hoc action. action_spec = spec_parser.get_action_spec(action_def.spec) base_name = action_spec.get_base() action_def = e_utils.resolve_action_definition( task_ex.workflow_name, wf_spec.get_name(), base_name ) e_utils.validate_input(action_def, action_spec, input_dict) base_input = action_spec.get_base_input() if base_input: input_dict = expr.evaluate_recursively( base_input, input_dict ) else: input_dict = {} return input_dict
def _get_action_input(wf_spec, task_ex, task_spec, ctx): input_dict = expr.evaluate_recursively(task_spec.get_input(), ctx) action_spec_name = task_spec.get_action_name() input_dict = utils.merge_dicts(input_dict, _get_action_defaults(task_ex, task_spec), overwrite=False) return action_handler.get_action_input(action_spec_name, input_dict, task_ex.workflow_name, wf_spec)
def _get_action_input(self, ctx=None): ctx = ctx or self.ctx ctx_view = data_flow.ContextView(ctx, self.wf_ex.context, self.wf_ex.input) input_dict = expr.evaluate_recursively(self.task_spec.get_input(), ctx_view) return utils.merge_dicts(input_dict, self._get_action_defaults(), overwrite=False)
def _evaluate_expression(self, expression, ctx=None): ctx = ctx or self.ctx ctx_view = data_flow.ContextView( ctx, self.wf_ex.context, self.wf_ex.input ) input_dict = expr.evaluate_recursively( expression, ctx_view ) return input_dict
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 transform_action_result(action_spec_name, result, wf_name=None, wf_spec_name=None): action_def = resolve_action_definition(action_spec_name, wf_name, wf_spec_name) if not action_def.spec: return result transformer = spec_parser.get_action_spec(action_def.spec).get_output() if transformer is None: return result return wf_utils.Result(data=expr.evaluate_recursively(transformer, result.data), error=result.error)
def _prepare_input(self, input_dict): base_input_expr = self.action_spec.get_base_input() if base_input_expr: base_input_dict = expr.evaluate_recursively( base_input_expr, input_dict ) else: base_input_dict = {} return super(AdHocAction, self)._prepare_input(base_input_dict)
def _get_timeout(self): timeout = self.task_spec.get_policies().get_timeout() if not isinstance(timeout, (int, float)): wf_ex = self.task_ex.workflow_execution ctx_view = data_flow.ContextView(self.task_ex.in_context, wf_ex.context, wf_ex.input) timeout = expr.evaluate_recursively(data=timeout, context=ctx_view) return timeout if timeout > 0 else None
def _get_target(self, input_dict): ctx_view = data_flow.ContextView( input_dict, self.ctx, self.wf_ex.context, self.wf_ex.input ) return expr.evaluate_recursively( self.task_spec.get_target(), ctx_view )
def _prepare_input(self, input_dict): base_input_dict = input_dict for action_def in self.adhoc_action_defs: action_spec = spec_parser.get_action_spec(action_def.spec) base_input_expr = action_spec.get_base_input() if base_input_expr: base_input_dict = expr.evaluate_recursively( base_input_expr, base_input_dict) else: base_input_dict = {} return super(AdHocAction, self)._prepare_input(base_input_dict)
def publish_variables(task_ex, task_spec): if task_ex.state not in [states.SUCCESS, states.ERROR]: return wf_ex = task_ex.workflow_execution expr_ctx = ContextView( get_current_task_dict(task_ex), task_ex.in_context, get_workflow_environment_dict(wf_ex), wf_ex.context, wf_ex.input ) if task_ex.name in expr_ctx: LOG.warning( 'Shadowing context variable with task name while ' 'publishing: %s', task_ex.name ) publish_spec = task_spec.get_publish(task_ex.state) if not publish_spec: return # Publish branch variables. branch_vars = publish_spec.get_branch() task_ex.published = expr.evaluate_recursively(branch_vars, expr_ctx) # Publish global variables. global_vars = publish_spec.get_global() utils.merge_dicts( task_ex.workflow_execution.context, expr.evaluate_recursively(global_vars, expr_ctx) )
def _get_with_items_input(wf_spec, task_ex, task_spec, ctx): """Calculate input array for separating each action input. Example: DSL: with_items: - itemX in <% $.arrayI %> - itemY in <% $.arrayJ %> Assume arrayI = [1, 2], arrayJ = ['a', 'b']. with_items_input = { "itemX": [1, 2], "itemY": ['a', 'b'] } Then we get separated input: inputs_per_item = [ {'itemX': 1, 'itemY': 'a'}, {'itemX': 2, 'itemY': 'b'} ] :return: list containing dicts of each action input. """ with_items_inputs = expr.evaluate_recursively( task_spec.get_with_items(), ctx ) with_items.validate_input(with_items_inputs) inputs_per_item = [] for key, value in with_items_inputs.items(): for index, item in enumerate(value): iter_context = {key: item} if index >= len(inputs_per_item): inputs_per_item.append(iter_context) else: inputs_per_item[index].update(iter_context) action_inputs = [] for item_input in inputs_per_item: new_ctx = utils.merge_dicts(item_input, ctx) action_inputs.append(_get_workflow_or_action_input( wf_spec, task_ex, task_spec, new_ctx )) return action_inputs
def add_workflow_variables_to_context(wf_ex, wf_spec): wf_ex.context = wf_ex.context or {} # The context for calculating workflow variables is workflow input # and other data already stored in workflow initial context. ctx_view = ContextView( get_workflow_environment_dict(wf_ex), wf_ex.context, wf_ex.input ) wf_vars = expr.evaluate_recursively(wf_spec.get_vars(), ctx_view) utils.merge_dicts(wf_ex.context, wf_vars)
def _get_timeout(self): timeout = self.task_spec.get_policies().get_timeout() if not isinstance(timeout, (int, float)): wf_ex = self.task_ex.workflow_execution ctx_view = data_flow.ContextView( self.task_ex.in_context, wf_ex.context, wf_ex.input ) timeout = expr.evaluate_recursively(data=timeout, context=ctx_view) return timeout if timeout > 0 else None
def _prepare_input(self, input_dict): base_input_dict = input_dict for action_def in self.adhoc_action_defs: action_spec = spec_parser.get_action_spec(action_def.spec) base_input_expr = action_spec.get_base_input() if base_input_expr: base_input_dict = expr.evaluate_recursively( base_input_expr, base_input_dict ) else: base_input_dict = {} return super(AdHocAction, self)._prepare_input(base_input_dict)
def publish_variables(task_ex, task_spec): expr_ctx = extract_task_result_proxies_to_context(task_ex.in_context) if task_ex.name in expr_ctx: LOG.warning( 'Shadowing context variable with task name while publishing: %s' % task_ex.name ) # Add result of current task to context for variables evaluation. expr_ctx[task_ex.name] = TaskResultProxy(task_ex.id) task_ex.published = expr.evaluate_recursively( task_spec.get_publish(), expr_ctx )
def publish_variables(task_ex, task_spec): if task_ex.state != states.SUCCESS: return expr_ctx = task_ex.in_context if task_ex.name in expr_ctx: LOG.warning( 'Shadowing context variable with task name while publishing: %s' % task_ex.name ) task_ex.published = expr.evaluate_recursively( task_spec.get_publish(), expr_ctx )
def _get_target(self, input_dict): if not self.task_spec.get_target(): return None ctx_view = data_flow.ContextView( input_dict, self.ctx, data_flow.get_workflow_environment_dict(self.wf_ex), self.wf_ex.context, self.wf_ex.input ) return expr.evaluate_recursively( self.task_spec.get_target(), ctx_view )
def _prepare_output(self, result): # In case of error, we don't transform a result. if not result.is_error(): adhoc_action_spec = spec_parser.get_action_spec( self.adhoc_action_def.spec ) transformer = adhoc_action_spec.get_output() if transformer is not None: result = wf_utils.Result( data=expr.evaluate_recursively(transformer, result.data), error=result.error ) return _get_action_output(result) if result else None