def test_unexpected_action_params_failure(self): def_dict = self._read_yaml_file_as_json(WF_UNEXP_PARAM_PATH) with self.assertRaises(WorkflowDefinitionException) as cm: utils.transform_definition(def_dict) self.assertIn('Unexpected parameters', str(cm))
def test_required_action_params_failure(self): def_dict = self._read_yaml_file_as_json(WF_NO_REQ_PARAM_PATH) with self.assertRaises(WorkflowDefinitionException) as cm: utils.transform_definition(def_dict) self.assertIn('Missing required parameters', str(cm))
def validate(self, definition): def_dict = yaml.safe_load(definition) is_workbook = ('workflows' in def_dict) if not is_workbook: # Non-workbook definition containing multiple workflows is not supported. if len([k for k, _ in six.iteritems(def_dict) if k != 'version']) != 1: return [self.parse('Multiple workflows is not supported workflow ' 'only (not a workbook) definition.')] # Select validation function. func = self._client.workbooks.validate if is_workbook else self._client.workflows.validate # Validate before custom DSL transformation. result = func(definition) if not result.get('valid', None): return [self.parse(result.get('error', 'Unknown exception.'))] try: # Run custom DSL transformer to check action parameters. utils.transform_definition(def_dict) except WorkflowDefinitionException as e: return [self.parse(str(e))] return []
def test_mixed_jinja_context_separate_delimiters(self): def_dict = self._read_yaml_file_as_json(WF_JINJA_MIXED_CTX2_PATH) with self.assertRaises(WorkflowDefinitionException) as cm: utils.transform_definition(def_dict) self.assertIn('inttype', str(cm)) self.assertIn('references to both local context', str(cm))
def test_mixed_jinja_context_same_delimiter(self): def_dict = self._read_yaml_file_as_json(WF_JINJA_MIXED_CTX1_PATH) with self.assertRaises(WorkflowDefinitionException) as cm: utils.transform_definition(def_dict) self.assertIn('strtype', cm.exception.message) self.assertIn('references to both local context', cm.exception.message)
def start(self, action_parameters): # Test connection self._client.workflows.list() # Setup inputs for the workflow execution. inputs = self.runner_parameters.get('context', dict()) inputs.update(action_parameters) # Get workbook/workflow definition from file. with open(self.entry_point, 'r') as def_file: def_yaml = def_file.read() def_dict = yaml.safe_load(def_yaml) is_workbook = ('workflows' in def_dict) if not is_workbook: # Non-workbook definition containing multiple workflows is not supported. if len([k for k, _ in six.iteritems(def_dict) if k != 'version' ]) != 1: raise Exception( 'Workflow (not workbook) definition is detected. ' 'Multiple workflows is not supported.') action_ref = '%s.%s' % (self.action.pack, self.action.name) self._check_name(action_ref, is_workbook, def_dict) def_dict_xformed = utils.transform_definition(def_dict) def_yaml_xformed = yaml.safe_dump(def_dict_xformed, default_flow_style=False) # Construct additional options for the workflow execution options = self._construct_workflow_execution_options() # Save workbook/workflow definition. if is_workbook: self._save_workbook(action_ref, def_yaml_xformed) default_workflow = self._find_default_workflow(def_dict_xformed) execution = self._client.executions.create(default_workflow, workflow_input=inputs, **options) else: self._save_workflow(action_ref, def_yaml_xformed) execution = self._client.executions.create(action_ref, workflow_input=inputs, **options) status = LIVEACTION_STATUS_RUNNING partial_results = {'tasks': []} # pylint: disable=no-member current_context = { 'execution_id': str(execution.id), 'workflow_name': execution.workflow_name } exec_context = self.context exec_context = self._build_mistral_context(exec_context, current_context) LOG.info('Mistral query context is %s' % exec_context) return (status, partial_results, exec_context)
def start(self, action_parameters): # Test connection self._client.workflows.list() # Setup inputs for the workflow execution. inputs = self.runner_parameters.get('context', dict()) inputs.update(action_parameters) # Get workbook/workflow definition from file. with open(self.entry_point, 'r') as def_file: def_yaml = def_file.read() def_dict = yaml.safe_load(def_yaml) is_workbook = ('workflows' in def_dict) if not is_workbook: # Non-workbook definition containing multiple workflows is not supported. if len([k for k, _ in six.iteritems(def_dict) if k != 'version']) != 1: raise Exception('Workflow (not workbook) definition is detected. ' 'Multiple workflows is not supported.') action_ref = '%s.%s' % (self.action.pack, self.action.name) self._check_name(action_ref, is_workbook, def_dict) def_dict_xformed = utils.transform_definition(def_dict) def_yaml_xformed = yaml.safe_dump(def_dict_xformed, default_flow_style=False) # Construct additional options for the workflow execution options = self._construct_workflow_execution_options() # Save workbook/workflow definition. if is_workbook: self._save_workbook(action_ref, def_yaml_xformed) default_workflow = self._find_default_workflow(def_dict_xformed) execution = self._client.executions.create(default_workflow, workflow_input=inputs, **options) else: self._save_workflow(action_ref, def_yaml_xformed) execution = self._client.executions.create(action_ref, workflow_input=inputs, **options) status = LIVEACTION_STATUS_RUNNING partial_results = {'tasks': []} # pylint: disable=no-member current_context = { 'execution_id': str(execution.id), 'workflow_name': execution.workflow_name } exec_context = self.context exec_context = self._build_mistral_context(exec_context, current_context) LOG.info('Mistral query context is %s' % exec_context) return (status, partial_results, exec_context)
def test_transform_workbook_dsl_dict(self): def_dict = self._read_yaml_file_as_json(WB_PRE_XFORM_PATH) actual = utils.transform_definition(def_dict) expected = copy.deepcopy(WB_POST_XFORM_DEF) self.assertDictEqual(actual, expected)
def try_run(self, action_parameters): # Test connection self._client.workflows.list() # Setup inputs for the workflow execution. inputs = self.runner_parameters.get('context', dict()) inputs.update(action_parameters) api_url = get_full_public_api_url() endpoint = api_url + '/actionexecutions' # Build context with additional information parent_context = {'execution_id': self.execution_id} if getattr(self.liveaction, 'context', None): parent_context.update(self.liveaction.context) st2_execution_context = { 'endpoint': endpoint, 'parent': parent_context, 'notify': {}, 'skip_notify_tasks': self._skip_notify_tasks } # Include notification information if self._notify: notify_dict = NotificationsHelper.from_model( notify_model=self._notify) st2_execution_context['notify'] = notify_dict if self.auth_token: st2_execution_context['auth_token'] = self.auth_token.token options = { 'env': { 'st2_execution_id': self.execution_id, 'st2_liveaction_id': self.liveaction_id, '__actions': { 'st2.action': { 'st2_context': st2_execution_context } } } } # Get workbook/workflow definition from file. with open(self.entry_point, 'r') as def_file: def_yaml = def_file.read() def_dict = yaml.safe_load(def_yaml) is_workbook = ('workflows' in def_dict) if not is_workbook: # Non-workbook definition containing multiple workflows is not supported. if len([k for k, _ in six.iteritems(def_dict) if k != 'version' ]) != 1: raise Exception( 'Workflow (not workbook) definition is detected. ' 'Multiple workflows is not supported.') action_ref = '%s.%s' % (self.action.pack, self.action.name) self._check_name(action_ref, is_workbook, def_dict) def_dict_xformed = utils.transform_definition(def_dict) def_yaml_xformed = yaml.safe_dump(def_dict_xformed, default_flow_style=False) # Save workbook/workflow definition. if is_workbook: self._save_workbook(action_ref, def_yaml_xformed) default_workflow = self._find_default_workflow(def_dict_xformed) execution = self._client.executions.create(default_workflow, workflow_input=inputs, **options) else: self._save_workflow(action_ref, def_yaml_xformed) execution = self._client.executions.create(action_ref, workflow_input=inputs, **options) status = LIVEACTION_STATUS_RUNNING partial_results = {'tasks': []} # pylint: disable=no-member current_context = { 'execution_id': str(execution.id), 'workflow_name': execution.workflow_name } exec_context = self.context exec_context = self._build_mistral_context(exec_context, current_context) LOG.info('Mistral query context is %s' % exec_context) return (status, partial_results, exec_context)
def test_transform_workflow_with_jinja_st2kv_dsl_yaml(self): def_yaml = self._read_file_content(WF_JINJA_ST2KV_PRE_XFORM_PATH) new_def = utils.transform_definition(def_yaml) actual = yaml.safe_load(new_def) expected = copy.deepcopy(WF_JINJA_ST2KV_POST_XFORM_DEF) self.assertDictEqual(actual, expected)
def test_transform_workflow_with_jinja_st2kv_dsl_dict(self): def_dict = self._read_yaml_file_as_json(WF_JINJA_ST2KV_PRE_XFORM_PATH) actual = utils.transform_definition(def_dict) expected = copy.deepcopy(WF_JINJA_ST2KV_POST_XFORM_DEF) self.assertDictEqual(actual, expected)
def test_transform_workbook_dsl_yaml(self): def_yaml = self._read_file_content(WB_PRE_XFORM_PATH) new_def = utils.transform_definition(def_yaml) actual = yaml.safe_load(new_def) expected = copy.deepcopy(WB_POST_XFORM_DEF) self.assertDictEqual(actual, expected)
def run(self, action_parameters): # Test connection self._client.workflows.list() # Setup inputs for the workflow execution. inputs = self.runner_parameters.get('context', dict()) inputs.update(action_parameters) # This URL is used by Mistral to talk back to the API api_url = get_mistral_api_url() endpoint = api_url + '/actionexecutions' # This URL is available in the context and can be used by the users inside a workflow, # similar to "ST2_ACTION_API_URL" environment variable available to actions public_api_url = get_full_public_api_url() # Build context with additional information parent_context = { 'execution_id': self.execution_id } if getattr(self.liveaction, 'context', None): parent_context.update(self.liveaction.context) st2_execution_context = { 'endpoint': endpoint, 'parent': parent_context, 'notify': {}, 'skip_notify_tasks': self._skip_notify_tasks } # Include notification information if self._notify: notify_dict = NotificationsHelper.from_model(notify_model=self._notify) st2_execution_context['notify'] = notify_dict if self.auth_token: st2_execution_context['auth_token'] = self.auth_token.token options = { 'env': { 'st2_execution_id': self.execution_id, 'st2_liveaction_id': self.liveaction_id, 'st2_action_api_url': public_api_url, '__actions': { 'st2.action': { 'st2_context': st2_execution_context } } } } # Get workbook/workflow definition from file. with open(self.entry_point, 'r') as def_file: def_yaml = def_file.read() def_dict = yaml.safe_load(def_yaml) is_workbook = ('workflows' in def_dict) if not is_workbook: # Non-workbook definition containing multiple workflows is not supported. if len([k for k, _ in six.iteritems(def_dict) if k != 'version']) != 1: raise Exception('Workflow (not workbook) definition is detected. ' 'Multiple workflows is not supported.') action_ref = '%s.%s' % (self.action.pack, self.action.name) self._check_name(action_ref, is_workbook, def_dict) def_dict_xformed = utils.transform_definition(def_dict) def_yaml_xformed = yaml.safe_dump(def_dict_xformed, default_flow_style=False) # Save workbook/workflow definition. if is_workbook: self._save_workbook(action_ref, def_yaml_xformed) default_workflow = self._find_default_workflow(def_dict_xformed) execution = self._client.executions.create(default_workflow, workflow_input=inputs, **options) else: self._save_workflow(action_ref, def_yaml_xformed) execution = self._client.executions.create(action_ref, workflow_input=inputs, **options) status = LIVEACTION_STATUS_RUNNING partial_results = {'tasks': []} # pylint: disable=no-member current_context = { 'execution_id': str(execution.id), 'workflow_name': execution.workflow_name } exec_context = self.context exec_context = self._build_mistral_context(exec_context, current_context) LOG.info('Mistral query context is %s' % exec_context) return (status, partial_results, exec_context)