def instantiate(spec_type, definition): if not definition: raise ValueError('Workflow definition is empty.') if isinstance(definition, six.string_types): definition = yaml.safe_load(definition) if not isinstance(definition, dict): raise ValueError('Unable to convert workflow definition into dict.') spec_module = spec_loader.get_spec_module(spec_type) version = definition.pop('version', None) if not version: raise ValueError('Version of the workflow definition is not provided.') spec_version = spec_module.VERSION if str(version) != str(spec_version): raise ValueError('Workflow definition is not the supported version "%s".', spec_version) if not definition.keys(): raise ValueError('Workflow definition contains no workflow.') return spec_module.instantiate(definition)
def test_get_spec(self): spec_module = spec_loader.get_spec_module(self.spec_module_name) self.assertEqual( spec_module.WorkflowSpec, mistral_specs.WorkflowSpec )
def test_spec_catalog(self): spec_module = spec_loader.get_spec_module(self.spec_module_name) self.assertEqual( spec_module.WorkflowSpec.get_catalog(), self.spec_module_name )
def test_request_task_execution_bad_action(self): wf_meta = self.get_wf_fixture_meta_data(TEST_PACK_PATH, 'sequential.yaml') # Manually create the liveaction and action execution objects without publishing. lv_ac_db = lv_db_models.LiveActionDB(action=wf_meta['name']) lv_ac_db, ac_ex_db = ac_svc.create_request(lv_ac_db) # Request the workflow execution. wf_def = self.get_wf_def(TEST_PACK_PATH, wf_meta) st2_ctx = self.mock_st2_context(ac_ex_db) wf_ex_db = wf_svc.request(wf_def, ac_ex_db, st2_ctx) # Manually request task execution. task_id = 'task1' spec_module = specs_loader.get_spec_module(wf_ex_db.spec['catalog']) wf_spec = spec_module.WorkflowSpec.deserialize(wf_ex_db.spec) task_spec = wf_spec.tasks.get_task(task_id) task_ctx = {'foo': 'bar'} st2_ctx = {'execution_id': wf_ex_db.action_execution} task_spec.action = 'mock.foobar' self.assertRaises(ac_exc.InvalidActionReferencedException, wf_svc.request_task_execution, wf_ex_db, task_id, task_spec, task_ctx, st2_ctx)
def run_workflow_step( self, wf_ex_db, task_id, route, ctx=None, expected_ac_ex_db_status=ac_const.LIVEACTION_STATUS_SUCCEEDED, expected_tk_ex_db_status=wf_statuses.SUCCEEDED, ): spec_module = specs_loader.get_spec_module(wf_ex_db.spec["catalog"]) wf_spec = spec_module.WorkflowSpec.deserialize(wf_ex_db.spec) st2_ctx = {"execution_id": wf_ex_db.action_execution} task_spec = wf_spec.tasks.get_task(task_id) task_actions = [ {"action": task_spec.action, "input": getattr(task_spec, "input", {})} ] task_req = { "id": task_id, "route": route, "spec": task_spec, "ctx": ctx or {}, "actions": task_actions, } task_ex_db = wf_svc.request_task_execution(wf_ex_db, st2_ctx, task_req) ac_ex_db = self.get_action_ex(str(task_ex_db.id)) ac_ex_db = self._wait_on_ac_ex_status(ac_ex_db, expected_ac_ex_db_status) wf_svc.handle_action_execution_completion(ac_ex_db) task_ex_db = wf_db_access.TaskExecution.get_by_id(str(task_ex_db.id)) self.assertEqual(task_ex_db.status, expected_tk_ex_db_status)
def setUpClass(cls): WorkflowGraphTest.setUpClass() WorkflowSpecTest.setUpClass() cls.composer = plugin_util.get_module('orquesta.composers', cls.spec_module_name) cls.spec_module = spec_loader.get_spec_module(cls.spec_module_name) cls.wf_spec_type = cls.spec_module.WorkflowSpec
def run_workflow_step( self, wf_ex_db, task_id, route, ctx=None, expected_ac_ex_db_status=ac_const.LIVEACTION_STATUS_SUCCEEDED, expected_tk_ex_db_status=wf_statuses.SUCCEEDED): spec_module = specs_loader.get_spec_module(wf_ex_db.spec['catalog']) wf_spec = spec_module.WorkflowSpec.deserialize(wf_ex_db.spec) st2_ctx = {'execution_id': wf_ex_db.action_execution} task_spec = wf_spec.tasks.get_task(task_id) task_actions = [{ 'action': task_spec.action, 'input': getattr(task_spec, 'input', {}) }] task_req = { 'id': task_id, 'route': route, 'spec': task_spec, 'ctx': ctx or {}, 'actions': task_actions } task_ex_db = wf_svc.request_task_execution(wf_ex_db, st2_ctx, task_req) ac_ex_db = self.get_action_ex(str(task_ex_db.id)) ac_ex_db = self._wait_on_ac_ex_status(ac_ex_db, expected_ac_ex_db_status) wf_svc.handle_action_execution_completion(ac_ex_db) task_ex_db = wf_db_access.TaskExecution.get_by_id(str(task_ex_db.id)) self.assertEqual(task_ex_db.status, expected_tk_ex_db_status)
def test_request_task_execution(self): wf_meta = self.get_wf_fixture_meta_data(TEST_PACK_PATH, 'sequential.yaml') # Manually create the liveaction and action execution objects without publishing. lv_ac_db = lv_db_models.LiveActionDB(action=wf_meta['name']) lv_ac_db, ac_ex_db = action_service.create_request(lv_ac_db) # Request the workflow execution. wf_def = self.get_wf_def(TEST_PACK_PATH, wf_meta) st2_ctx = self.mock_st2_context(ac_ex_db) wf_ex_db = workflow_service.request(wf_def, ac_ex_db, st2_ctx) spec_module = specs_loader.get_spec_module(wf_ex_db.spec['catalog']) wf_spec = spec_module.WorkflowSpec.deserialize(wf_ex_db.spec) # Manually request task execution. task_id = 'task1' task_spec = wf_spec.tasks.get_task(task_id) task_ctx = {'foo': 'bar'} st2_ctx = {'execution_id': wf_ex_db.action_execution} task_ex_req = { 'id': task_id, 'spec': task_spec, 'ctx': task_ctx, 'actions': [{ 'action': 'core.echo', 'input': { 'message': 'Veni, vidi, vici.' } }] } workflow_service.request_task_execution(wf_ex_db, st2_ctx, task_ex_req) # Check task execution is saved to the database. task_ex_dbs = wf_db_access.TaskExecution.query( workflow_execution=str(wf_ex_db.id)) self.assertEqual(len(task_ex_dbs), 1) # Check required attributes. task_ex_db = task_ex_dbs[0] self.assertIsNotNone(task_ex_db.id) self.assertGreater(task_ex_db.rev, 0) self.assertEqual(task_ex_db.workflow_execution, str(wf_ex_db.id)) self.assertEqual(task_ex_db.status, wf_states.RUNNING) # Check action execution for the task query with task execution ID. ac_ex_dbs = ex_db_access.ActionExecution.query( task_execution=str(task_ex_db.id)) self.assertEqual(len(ac_ex_dbs), 1) # Check action execution for the task query with workflow execution ID. ac_ex_dbs = ex_db_access.ActionExecution.query( workflow_execution=str(wf_ex_db.id)) self.assertEqual(len(ac_ex_dbs), 1)
def request(wf_def, ac_ex_db, st2_ctx): wf_ac_ex_id = str(ac_ex_db.id) LOG.info('[%s] Processing action execution request for workflow.', wf_ac_ex_id) # Load workflow definition into workflow spec model. spec_module = specs_loader.get_spec_module('native') wf_spec = spec_module.instantiate(wf_def) # Inspect the workflow spec. inspect(wf_spec, st2_ctx, raise_exception=True) # Identify the action to execute. action_db = action_utils.get_action_by_ref(ref=ac_ex_db.action['ref']) if not action_db: error = 'Unable to find action "%s".' % ac_ex_db.action['ref'] raise ac_exc.InvalidActionReferencedException(error) # Identify the runner for the action. runner_type_db = action_utils.get_runnertype_by_name( action_db.runner_type['name']) # Render action execution parameters. runner_params, action_params = param_utils.render_final_params( runner_type_db.runner_parameters, action_db.parameters, ac_ex_db.parameters, ac_ex_db.context) # Instantiate the workflow conductor. conductor_params = {'inputs': action_params, 'context': st2_ctx} conductor = conducting.WorkflowConductor(wf_spec, **conductor_params) # Set the initial workflow state to requested. conductor.request_workflow_state(states.REQUESTED) # Serialize the conductor which initializes some internal values. data = conductor.serialize() # Create a record for workflow execution. wf_ex_db = wf_db_models.WorkflowExecutionDB(action_execution=str( ac_ex_db.id), spec=data['spec'], graph=data['graph'], flow=data['flow'], context=data['context'], input=data['input'], output=data['output'], errors=data['errors'], status=data['state']) # Insert new record into the database and publish to the message bus. wf_ex_db = wf_db_access.WorkflowExecution.insert(wf_ex_db, publish=True) LOG.info('[%s] Workflow execution "%s" created.', wf_ac_ex_id, str(wf_ex_db.id)) return wf_ex_db
def run_workflow_step(self, wf_ex_db, task_id, ctx=None): spec_module = specs_loader.get_spec_module(wf_ex_db.spec['catalog']) wf_spec = spec_module.WorkflowSpec.deserialize(wf_ex_db.spec) task_spec = wf_spec.tasks.get_task(task_id) st2_ctx = {'execution_id': wf_ex_db.action_execution} task_ex_db = wf_svc.request_task_execution(wf_ex_db, task_id, task_spec, ctx or {}, st2_ctx) ac_ex_db = self.get_action_ex(str(task_ex_db.id)) self.assertEqual(ac_ex_db.status, ac_const.LIVEACTION_STATUS_SUCCEEDED) wf_svc.handle_action_execution_completion(ac_ex_db) task_ex_db = wf_db_access.TaskExecution.get_by_id(str(task_ex_db.id)) self.assertEqual(task_ex_db.status, wf_lib_states.SUCCEEDED)
def post(self, wf_def): # Load workflow definition into workflow spec model. spec_module = specs_loader.get_spec_module('native') wf_spec = spec_module.instantiate(wf_def) # Mock the st2 context that is typically passed to the workflow engine. st2_ctx = self.mock_st2_ctx() # Inspect the workflow spec and return the errors instead of raising exception. errors = workflow_service.inspect(wf_spec, st2_ctx, raise_exception=False) # Return the result of the inspection. return router.Response(json=errors)
def test_request_task_execution(self): wf_meta = self.get_wf_fixture_meta_data(TEST_PACK_PATH, 'sequential.yaml') # Manually create the liveaction and action execution objects without publishing. lv_ac_db = lv_db_models.LiveActionDB(action=wf_meta['name']) lv_ac_db, ac_ex_db = action_service.create_request(lv_ac_db) # Request the workflow execution. wf_def = self.get_wf_def(TEST_PACK_PATH, wf_meta) st2_ctx = self.mock_st2_context(ac_ex_db) wf_ex_db = workflow_service.request(wf_def, ac_ex_db, st2_ctx) spec_module = specs_loader.get_spec_module(wf_ex_db.spec['catalog']) wf_spec = spec_module.WorkflowSpec.deserialize(wf_ex_db.spec) # Manually request task execution. task_route = 0 task_id = 'task1' task_spec = wf_spec.tasks.get_task(task_id) task_ctx = {'foo': 'bar'} st2_ctx = {'execution_id': wf_ex_db.action_execution} task_ex_req = { 'id': task_id, 'route': task_route, 'spec': task_spec, 'ctx': task_ctx, 'actions': [ {'action': 'core.echo', 'input': {'message': 'Veni, vidi, vici.'}} ] } workflow_service.request_task_execution(wf_ex_db, st2_ctx, task_ex_req) # Check task execution is saved to the database. task_ex_dbs = wf_db_access.TaskExecution.query(workflow_execution=str(wf_ex_db.id)) self.assertEqual(len(task_ex_dbs), 1) # Check required attributes. task_ex_db = task_ex_dbs[0] self.assertIsNotNone(task_ex_db.id) self.assertGreater(task_ex_db.rev, 0) self.assertEqual(task_ex_db.workflow_execution, str(wf_ex_db.id)) self.assertEqual(task_ex_db.status, wf_statuses.RUNNING) # Check action execution for the task query with task execution ID. ac_ex_dbs = ex_db_access.ActionExecution.query(task_execution=str(task_ex_db.id)) self.assertEqual(len(ac_ex_dbs), 1) # Check action execution for the task query with workflow execution ID. ac_ex_dbs = ex_db_access.ActionExecution.query(workflow_execution=str(wf_ex_db.id)) self.assertEqual(len(ac_ex_dbs), 1)
def __init__(self, session, *args, **kwargs): super(WorkflowRehearsal, self).__init__(*args, **kwargs) if not session: raise exc.WorkflowRehearsalError( "The session object is not provided.") if not isinstance(session, WorkflowTestCase) and not isinstance( session, WorkflowRerunTestCase): raise exc.WorkflowRehearsalError( "The session object is not type of WorkflowTestCase or WorkflowRerunTestCase." ) self.session = session self.inspection_errors = {} self.rerun = False if isinstance(session, WorkflowTestCase): self.spec_module = spec_loader.get_spec_module( session.spec_module_name) self.wf_spec = self.spec_module.instantiate(self.session.wf_def) self.conductor = None elif isinstance(session, WorkflowRerunTestCase): self.conductor = self.session.conductor self.spec_module = self.conductor.spec_module self.wf_spec = self.conductor.spec self.rerun = True for mock_ac_ex in self.session.mock_action_executions: if not self.wf_spec.tasks.has_task(mock_ac_ex.task_id): raise exc.InvalidTask(mock_ac_ex.task_id) task_spec = self.wf_spec.tasks.get_task(mock_ac_ex.task_id) if task_spec.has_items() and mock_ac_ex.item_id is None: msg = 'Mock action execution for with items task "%s" is misssing "item_id".' raise exc.WorkflowRehearsalError(msg % mock_ac_ex.task_id) if not mock_ac_ex.result_path: continue if not os.path.isfile(mock_ac_ex.result_path): msg = 'The result path "%s" for the mock action execution does not exist.' raise exc.WorkflowRehearsalError(msg % mock_ac_ex.result_path) name, ext = os.path.splitext(mock_ac_ex.result_path) with open(mock_ac_ex.result_path) as f: mock_ac_ex.result = (fixture_loader.FIXTURE_EXTS[ext](f) if ext in fixture_loader.FIXTURE_EXTS else f.read())
def deserialize(cls, data): spec_module = spec_loader.get_spec_module(data['spec']['catalog']) spec = spec_module.WorkflowSpec.deserialize(data['spec']) graph = graphing.WorkflowGraph.deserialize(data['graph']) inputs = copy.deepcopy(data['input']) context = copy.deepcopy(data['context']) state = WorkflowState.deserialize(data['state']) log = copy.deepcopy(data.get('log', [])) errors = copy.deepcopy(data['errors']) outputs = copy.deepcopy(data['output']) instance = cls(spec) instance.restore(graph, log, errors, state, inputs, outputs, context) return instance
def __init__(self, spec, context=None, inputs=None): if not spec or not isinstance(spec, spec_base.Spec): raise ValueError('The value of "spec" is not type of Spec.') self.spec = spec self.catalog = self.spec.get_catalog() self.spec_module = spec_loader.get_spec_module(self.catalog) self.composer = plugin_util.get_module('orquesta.composers', self.catalog) self._errors = [] self._graph = None self._inputs = inputs or {} self._log = [] self._outputs = None self._parent_ctx = context or {} self._workflow_state = None
def test_request_task_execution_bad_action(self): wf_meta = self.get_wf_fixture_meta_data(TEST_PACK_PATH, "sequential.yaml") # Manually create the liveaction and action execution objects without publishing. lv_ac_db = lv_db_models.LiveActionDB(action=wf_meta["name"]) lv_ac_db, ac_ex_db = action_service.create_request(lv_ac_db) # Request the workflow execution. wf_def = self.get_wf_def(TEST_PACK_PATH, wf_meta) st2_ctx = self.mock_st2_context(ac_ex_db) wf_ex_db = workflow_service.request(wf_def, ac_ex_db, st2_ctx) spec_module = specs_loader.get_spec_module(wf_ex_db.spec["catalog"]) wf_spec = spec_module.WorkflowSpec.deserialize(wf_ex_db.spec) # Manually request task execution. task_route = 0 task_id = "task1" task_spec = wf_spec.tasks.get_task(task_id) task_ctx = {"foo": "bar"} st2_ctx = {"execution_id": wf_ex_db.action_execution} task_ex_req = { "id": task_id, "route": task_route, "spec": task_spec, "ctx": task_ctx, "actions": [{ "action": "mock.echo", "input": { "message": "Veni, vidi, vici." } }], } self.assertRaises( action_exc.InvalidActionReferencedException, workflow_service.request_task_execution, wf_ex_db, st2_ctx, task_ex_req, )
def test_duplicate_tasks(self): wf_def = """ version: 1.0 description: A sample workflow with a single task loop. input: - count: 0 tasks: init: action: core.noop next: - do: task1 task1: action: core.noop task1: action: core.noop next: - when: <% ctx().count < 2 %> publish: - count: <% ctx().count + 1 %> do: task1 """ expected_error = 'Failed to load workflow definition because found duplicate key "task1"' assertRaisesRegex = self.assertRaisesRegex if six.PY3 else self.assertRaisesRegexp assertRaisesRegex( ValueError, expected_error, spec_util.instantiate, self.spec_module_name, wf_def, ) spec_module = spec_loader.get_spec_module(self.spec_module_name) assertRaisesRegex( ValueError, expected_error, spec_module.instantiate, wf_def, )
def test_request_task_execution(self): wf_meta = self.get_wf_fixture_meta_data(TEST_PACK_PATH, TEST_FIXTURES['workflows'][0]) # Manually create the liveaction and action execution objects without publishing. lv_ac_db = lv_db_models.LiveActionDB(action=wf_meta['name']) lv_ac_db, ac_ex_db = ac_svc.create_request(lv_ac_db) # Request the workflow execution. wf_def = self.get_wf_def(TEST_PACK_PATH, wf_meta) st2_ctx = self.mock_st2_context(ac_ex_db) wf_ex_db = wf_svc.request(wf_def, ac_ex_db, st2_ctx) # Manually request task execution. task_id = 'task1' spec_module = specs_loader.get_spec_module(wf_ex_db.spec['catalog']) wf_spec = spec_module.WorkflowSpec.deserialize(wf_ex_db.spec) task_spec = wf_spec.tasks.get_task(task_id) task_ctx = {'foo': 'bar'} st2_ctx = {'execution_id': wf_ex_db.action_execution} wf_svc.request_task_execution(wf_ex_db, task_id, task_spec, task_ctx, st2_ctx) # Check task execution is saved to the database. task_ex_dbs = wf_db_access.TaskExecution.query( workflow_execution=str(wf_ex_db.id)) self.assertEqual(len(task_ex_dbs), 1) # Check required attributes. task_ex_db = task_ex_dbs[0] self.assertIsNotNone(task_ex_db.id) self.assertGreater(task_ex_db.rev, 0) self.assertEqual(task_ex_db.workflow_execution, str(wf_ex_db.id)) self.assertEqual(task_ex_db.status, wf_lib_states.RUNNING) # Check action execution for the task query with task execution ID. ac_ex_dbs = ex_db_access.ActionExecution.query( task_execution=str(task_ex_db.id)) self.assertEqual(len(ac_ex_dbs), 1) # Check action execution for the task query with workflow execution ID. ac_ex_dbs = ex_db_access.ActionExecution.query( workflow_execution=str(wf_ex_db.id)) self.assertEqual(len(ac_ex_dbs), 1)
def test_request_task_execution_bad_action(self): wf_meta = self.get_wf_fixture_meta_data(TEST_PACK_PATH, 'sequential.yaml') # Manually create the liveaction and action execution objects without publishing. lv_ac_db = lv_db_models.LiveActionDB(action=wf_meta['name']) lv_ac_db, ac_ex_db = action_service.create_request(lv_ac_db) # Request the workflow execution. wf_def = self.get_wf_def(TEST_PACK_PATH, wf_meta) st2_ctx = self.mock_st2_context(ac_ex_db) wf_ex_db = workflow_service.request(wf_def, ac_ex_db, st2_ctx) spec_module = specs_loader.get_spec_module(wf_ex_db.spec['catalog']) wf_spec = spec_module.WorkflowSpec.deserialize(wf_ex_db.spec) # Manually request task execution. task_route = 0 task_id = 'task1' task_spec = wf_spec.tasks.get_task(task_id) task_ctx = {'foo': 'bar'} st2_ctx = {'execution_id': wf_ex_db.action_execution} task_ex_req = { 'id': task_id, 'route': task_route, 'spec': task_spec, 'ctx': task_ctx, 'actions': [{ 'action': 'mock.echo', 'input': { 'message': 'Veni, vidi, vici.' } }] } self.assertRaises(action_exc.InvalidActionReferencedException, workflow_service.request_task_execution, wf_ex_db, st2_ctx, task_ex_req)
def run_workflow_step(self, wf_ex_db, task_id, route, ctx=None): spec_module = specs_loader.get_spec_module(wf_ex_db.spec['catalog']) wf_spec = spec_module.WorkflowSpec.deserialize(wf_ex_db.spec) st2_ctx = {'execution_id': wf_ex_db.action_execution} task_spec = wf_spec.tasks.get_task(task_id) task_actions = [{'action': task_spec.action, 'input': getattr(task_spec, 'input', {})}] task_req = { 'id': task_id, 'route': route, 'spec': task_spec, 'ctx': ctx or {}, 'actions': task_actions } task_ex_db = wf_svc.request_task_execution(wf_ex_db, st2_ctx, task_req) ac_ex_db = self.get_action_ex(str(task_ex_db.id)) ac_ex_db = self._wait_on_ac_ex_status(ac_ex_db, ac_const.LIVEACTION_STATUS_SUCCEEDED) wf_svc.handle_action_execution_completion(ac_ex_db) task_ex_db = wf_db_access.TaskExecution.get_by_id(str(task_ex_db.id)) self.assertEqual(task_ex_db.status, wf_statuses.SUCCEEDED)
def test_request_task_execution_bad_action(self): wf_meta = self.get_wf_fixture_meta_data(TEST_PACK_PATH, 'sequential.yaml') # Manually create the liveaction and action execution objects without publishing. lv_ac_db = lv_db_models.LiveActionDB(action=wf_meta['name']) lv_ac_db, ac_ex_db = action_service.create_request(lv_ac_db) # Request the workflow execution. wf_def = self.get_wf_def(TEST_PACK_PATH, wf_meta) st2_ctx = self.mock_st2_context(ac_ex_db) wf_ex_db = workflow_service.request(wf_def, ac_ex_db, st2_ctx) spec_module = specs_loader.get_spec_module(wf_ex_db.spec['catalog']) wf_spec = spec_module.WorkflowSpec.deserialize(wf_ex_db.spec) # Manually request task execution. task_route = 0 task_id = 'task1' task_spec = wf_spec.tasks.get_task(task_id) task_ctx = {'foo': 'bar'} st2_ctx = {'execution_id': wf_ex_db.action_execution} task_ex_req = { 'id': task_id, 'route': task_route, 'spec': task_spec, 'ctx': task_ctx, 'actions': [ {'action': 'mock.echo', 'input': {'message': 'Veni, vidi, vici.'}} ] } self.assertRaises( action_exc.InvalidActionReferencedException, workflow_service.request_task_execution, wf_ex_db, st2_ctx, task_ex_req )
def test_get_module(self): self.assertEqual(loader.get_spec_module(self.spec_module_name), orquesta_specs)
def test_get_module(self): self.assertEqual(loader.get_spec_module('mock'), mock)
def test_get_spec(self): spec_module = loader.get_spec_module('mock') self.assertEqual(spec_module.WorkflowSpec.get_catalog(), 'mock') self.assertEqual(spec_module.WorkflowSpec, mock.WorkflowSpec)
def test_get_module(self): self.assertEqual(loader.get_spec_module(self.spec_module_name), mistral)
def test_request_action_execution_render(self): # Manually create ConfigDB output = 'Testing' value = {"config_item_one": output} config_db = pk_db_models.ConfigDB(pack=PACK_7, values=value) config = pk_db_access.Config.add_or_update(config_db) self.assertEqual(len(config), 3) wf_meta = self.get_wf_fixture_meta_data(TEST_PACK_PATH, 'render_config_context.yaml') # Manually create the liveaction and action execution objects without publishing. lv_ac_db = lv_db_models.LiveActionDB(action=wf_meta['name']) lv_ac_db, ac_ex_db = action_service.create_request(lv_ac_db) # Request the workflow execution. wf_def = self.get_wf_def(TEST_PACK_PATH, wf_meta) st2_ctx = self.mock_st2_context(ac_ex_db) wf_ex_db = workflow_service.request(wf_def, ac_ex_db, st2_ctx) spec_module = specs_loader.get_spec_module(wf_ex_db.spec['catalog']) wf_spec = spec_module.WorkflowSpec.deserialize(wf_ex_db.spec) # Pass down appropriate st2 context to the task and action execution(s). root_st2_ctx = wf_ex_db.context.get('st2', {}) st2_ctx = { 'execution_id': wf_ex_db.action_execution, 'user': root_st2_ctx.get('user'), 'pack': root_st2_ctx.get('pack') } # Manually request task execution. task_route = 0 task_id = 'task1' task_spec = wf_spec.tasks.get_task(task_id) task_ctx = {'foo': 'bar'} task_ex_req = { 'id': task_id, 'route': task_route, 'spec': task_spec, 'ctx': task_ctx, 'actions': [{ 'action': 'dummy_pack_7.render_config_context', 'input': None }] } workflow_service.request_task_execution(wf_ex_db, st2_ctx, task_ex_req) # Check task execution is saved to the database. task_ex_dbs = wf_db_access.TaskExecution.query( workflow_execution=str(wf_ex_db.id)) self.assertEqual(len(task_ex_dbs), 1) workflow_service.request_task_execution(wf_ex_db, st2_ctx, task_ex_req) # Manually request action execution task_ex_db = task_ex_dbs[0] action_ex_db = workflow_service.request_action_execution( wf_ex_db, task_ex_db, st2_ctx, task_ex_req['actions'][0]) # Check required attributes. self.assertIsNotNone(str(action_ex_db.id)) self.assertEqual(task_ex_db.workflow_execution, str(wf_ex_db.id)) expected_parameters = {'value1': output} self.assertEqual(expected_parameters, action_ex_db.parameters)
def request(wf_def, ac_ex_db, st2_ctx, notify_cfg=None): wf_ac_ex_id = str(ac_ex_db.id) LOG.info('[%s] Processing action execution request for workflow.', wf_ac_ex_id) # Load workflow definition into workflow spec model. spec_module = specs_loader.get_spec_module('native') wf_spec = spec_module.instantiate(wf_def) # Inspect the workflow spec. inspect(wf_spec, st2_ctx, raise_exception=True) # Identify the action to execute. action_db = action_utils.get_action_by_ref(ref=ac_ex_db.action['ref']) if not action_db: error = 'Unable to find action "%s".' % ac_ex_db.action['ref'] raise ac_exc.InvalidActionReferencedException(error) # Identify the runner for the action. runner_type_db = action_utils.get_runnertype_by_name(action_db.runner_type['name']) # Render action execution parameters. runner_params, action_params = param_utils.render_final_params( runner_type_db.runner_parameters, action_db.parameters, ac_ex_db.parameters, ac_ex_db.context ) # Instantiate the workflow conductor. conductor_params = {'inputs': action_params, 'context': st2_ctx} conductor = conducting.WorkflowConductor(wf_spec, **conductor_params) # Serialize the conductor which initializes some internal values. data = conductor.serialize() # Create a record for workflow execution. wf_ex_db = wf_db_models.WorkflowExecutionDB( action_execution=str(ac_ex_db.id), spec=data['spec'], graph=data['graph'], input=data['input'], context=data['context'], state=data['state'], status=data['state']['status'], output=data['output'], errors=data['errors'] ) # Inspect that the list of tasks in the notify parameter exist in the workflow spec. if runner_params.get('notify'): invalid_tasks = list(set(runner_params.get('notify')) - set(wf_spec.tasks.keys())) if invalid_tasks: raise wf_exc.WorkflowExecutionException( 'The following tasks in the notify parameter do not exist ' 'in the workflow definition: %s.' % ', '.join(invalid_tasks) ) # Write notify instruction to record. if notify_cfg: # Set up the notify instruction in the workflow execution record. wf_ex_db.notify = { 'config': notify_cfg, 'tasks': runner_params.get('notify') } # Insert new record into the database and do not publish to the message bus yet. wf_ex_db = wf_db_access.WorkflowExecution.insert(wf_ex_db, publish=False) LOG.info('[%s] Workflow execution "%s" is created.', wf_ac_ex_id, str(wf_ex_db.id)) # Update the context with the workflow execution id created on database insert. # Publish the workflow execution requested status to the message bus. if wf_ex_db.status not in statuses.COMPLETED_STATUSES: # Set the initial workflow status to requested. conductor.request_workflow_status(statuses.REQUESTED) data = conductor.serialize() wf_ex_db.state = data['state'] wf_ex_db.status = data['state']['status'] # Put the ID of the workflow execution record in the context. wf_ex_db.context['st2']['workflow_execution_id'] = str(wf_ex_db.id) wf_ex_db.state['contexts'][0]['st2']['workflow_execution_id'] = str(wf_ex_db.id) # Update the workflow execution record. wf_ex_db = wf_db_access.WorkflowExecution.update(wf_ex_db, publish=False) wf_db_access.WorkflowExecution.publish_status(wf_ex_db) msg = '[%s] Workflow execution "%s" is published.' LOG.info(msg, wf_ac_ex_id, str(wf_ex_db.id)) else: msg = '[%s] Unable to request workflow execution. It is already in completed status "%s".' LOG.info(msg, wf_ac_ex_id, wf_ex_db.status) return wf_ex_db
def setUp(self): super(SpecsUtilTest, self).setUp() self.spec_module = loader.get_spec_module(self.spec_module_name)
def deserialize(data): spec_type = data.get('catalog') spec_module = spec_loader.get_spec_module(spec_type) return spec_module.deserialize(data)
def test_get_module(self): self.assertEqual(spec_loader.get_spec_module(self.spec_module_name), native_specs)
def test_request_action_execution_render(self): # Manually create ConfigDB output = "Testing" value = {"config_item_one": output} config_db = pk_db_models.ConfigDB(pack=PACK_7, values=value) config = pk_db_access.Config.add_or_update(config_db) self.assertEqual(len(config), 3) wf_meta = self.get_wf_fixture_meta_data(TEST_PACK_PATH, "render_config_context.yaml") # Manually create the liveaction and action execution objects without publishing. lv_ac_db = lv_db_models.LiveActionDB(action=wf_meta["name"]) lv_ac_db, ac_ex_db = action_service.create_request(lv_ac_db) # Request the workflow execution. wf_def = self.get_wf_def(TEST_PACK_PATH, wf_meta) st2_ctx = self.mock_st2_context(ac_ex_db) wf_ex_db = workflow_service.request(wf_def, ac_ex_db, st2_ctx) spec_module = specs_loader.get_spec_module(wf_ex_db.spec["catalog"]) wf_spec = spec_module.WorkflowSpec.deserialize(wf_ex_db.spec) # Pass down appropriate st2 context to the task and action execution(s). root_st2_ctx = wf_ex_db.context.get("st2", {}) st2_ctx = { "execution_id": wf_ex_db.action_execution, "user": root_st2_ctx.get("user"), "pack": root_st2_ctx.get("pack"), } # Manually request task execution. task_route = 0 task_id = "task1" task_spec = wf_spec.tasks.get_task(task_id) task_ctx = {"foo": "bar"} task_ex_req = { "id": task_id, "route": task_route, "spec": task_spec, "ctx": task_ctx, "actions": [{ "action": "dummy_pack_7.render_config_context", "input": None }], } workflow_service.request_task_execution(wf_ex_db, st2_ctx, task_ex_req) # Check task execution is saved to the database. task_ex_dbs = wf_db_access.TaskExecution.query( workflow_execution=str(wf_ex_db.id)) self.assertEqual(len(task_ex_dbs), 1) workflow_service.request_task_execution(wf_ex_db, st2_ctx, task_ex_req) # Manually request action execution task_ex_db = task_ex_dbs[0] action_ex_db = workflow_service.request_action_execution( wf_ex_db, task_ex_db, st2_ctx, task_ex_req["actions"][0]) # Check required attributes. self.assertIsNotNone(str(action_ex_db.id)) self.assertEqual(task_ex_db.workflow_execution, str(wf_ex_db.id)) expected_parameters = {"value1": output} self.assertEqual(expected_parameters, action_ex_db.parameters)
def test_request_task_execution(self): wf_meta = self.get_wf_fixture_meta_data(TEST_PACK_PATH, "sequential.yaml") # Manually create the liveaction and action execution objects without publishing. lv_ac_db = lv_db_models.LiveActionDB(action=wf_meta["name"]) lv_ac_db, ac_ex_db = action_service.create_request(lv_ac_db) # Request the workflow execution. wf_def = self.get_wf_def(TEST_PACK_PATH, wf_meta) st2_ctx = self.mock_st2_context(ac_ex_db) wf_ex_db = workflow_service.request(wf_def, ac_ex_db, st2_ctx) spec_module = specs_loader.get_spec_module(wf_ex_db.spec["catalog"]) wf_spec = spec_module.WorkflowSpec.deserialize(wf_ex_db.spec) # Manually request task execution. task_route = 0 task_id = "task1" task_spec = wf_spec.tasks.get_task(task_id) task_ctx = {"foo": "bar"} st2_ctx = {"execution_id": wf_ex_db.action_execution} task_ex_req = { "id": task_id, "route": task_route, "spec": task_spec, "ctx": task_ctx, "actions": [{ "action": "core.echo", "input": { "message": "Veni, vidi, vici." } }], } workflow_service.request_task_execution(wf_ex_db, st2_ctx, task_ex_req) # Check task execution is saved to the database. task_ex_dbs = wf_db_access.TaskExecution.query( workflow_execution=str(wf_ex_db.id)) self.assertEqual(len(task_ex_dbs), 1) # Check required attributes. task_ex_db = task_ex_dbs[0] self.assertIsNotNone(task_ex_db.id) self.assertGreater(task_ex_db.rev, 0) self.assertEqual(task_ex_db.workflow_execution, str(wf_ex_db.id)) self.assertEqual(task_ex_db.status, wf_statuses.RUNNING) # Check action execution for the task query with task execution ID. ac_ex_dbs = ex_db_access.ActionExecution.query( task_execution=str(task_ex_db.id)) self.assertEqual(len(ac_ex_dbs), 1) # Check action execution for the task query with workflow execution ID. ac_ex_dbs = ex_db_access.ActionExecution.query( workflow_execution=str(wf_ex_db.id)) self.assertEqual(len(ac_ex_dbs), 1)
def test_get_spec(self): spec_module = loader.get_spec_module(self.spec_module_name) self.assertEqual(spec_module.WorkflowSpec, orquesta_specs.WorkflowSpec)
def test_request_action_execution_render(self): # Manually create ConfigDB output = 'Testing' value = { "config_item_one": output } config_db = pk_db_models.ConfigDB(pack=PACK_7, values=value) config = pk_db_access.Config.add_or_update(config_db) self.assertEqual(len(config), 3) wf_meta = self.get_wf_fixture_meta_data(TEST_PACK_PATH, 'render_config_context.yaml') # Manually create the liveaction and action execution objects without publishing. lv_ac_db = lv_db_models.LiveActionDB(action=wf_meta['name']) lv_ac_db, ac_ex_db = action_service.create_request(lv_ac_db) # Request the workflow execution. wf_def = self.get_wf_def(TEST_PACK_PATH, wf_meta) st2_ctx = self.mock_st2_context(ac_ex_db) wf_ex_db = workflow_service.request(wf_def, ac_ex_db, st2_ctx) spec_module = specs_loader.get_spec_module(wf_ex_db.spec['catalog']) wf_spec = spec_module.WorkflowSpec.deserialize(wf_ex_db.spec) # Pass down appropriate st2 context to the task and action execution(s). root_st2_ctx = wf_ex_db.context.get('st2', {}) st2_ctx = { 'execution_id': wf_ex_db.action_execution, 'user': root_st2_ctx.get('user'), 'pack': root_st2_ctx.get('pack') } # Manually request task execution. task_route = 0 task_id = 'task1' task_spec = wf_spec.tasks.get_task(task_id) task_ctx = {'foo': 'bar'} task_ex_req = { 'id': task_id, 'route': task_route, 'spec': task_spec, 'ctx': task_ctx, 'actions': [ {'action': 'dummy_pack_7.render_config_context', 'input': None} ] } workflow_service.request_task_execution(wf_ex_db, st2_ctx, task_ex_req) # Check task execution is saved to the database. task_ex_dbs = wf_db_access.TaskExecution.query(workflow_execution=str(wf_ex_db.id)) self.assertEqual(len(task_ex_dbs), 1) workflow_service.request_task_execution(wf_ex_db, st2_ctx, task_ex_req) # Manually request action execution task_ex_db = task_ex_dbs[0] action_ex_db = workflow_service.request_action_execution(wf_ex_db, task_ex_db, st2_ctx, task_ex_req['actions'][0]) # Check required attributes. self.assertIsNotNone(str(action_ex_db.id)) self.assertEqual(task_ex_db.workflow_execution, str(wf_ex_db.id)) expected_parameters = {'value1': output} self.assertEqual(expected_parameters, action_ex_db.parameters)
def request(wf_def, ac_ex_db, st2_ctx, notify_cfg=None): wf_ac_ex_id = str(ac_ex_db.id) LOG.info('[%s] Processing action execution request for workflow.', wf_ac_ex_id) # Load workflow definition into workflow spec model. spec_module = specs_loader.get_spec_module('native') wf_spec = spec_module.instantiate(wf_def) # Inspect the workflow spec. inspect(wf_spec, st2_ctx, raise_exception=True) # Identify the action to execute. action_db = action_utils.get_action_by_ref(ref=ac_ex_db.action['ref']) if not action_db: error = 'Unable to find action "%s".' % ac_ex_db.action['ref'] raise ac_exc.InvalidActionReferencedException(error) # Identify the runner for the action. runner_type_db = action_utils.get_runnertype_by_name( action_db.runner_type['name']) # Render action execution parameters. runner_params, action_params = param_utils.render_final_params( runner_type_db.runner_parameters, action_db.parameters, ac_ex_db.parameters, ac_ex_db.context) # Instantiate the workflow conductor. conductor_params = {'inputs': action_params, 'context': st2_ctx} conductor = conducting.WorkflowConductor(wf_spec, **conductor_params) # Serialize the conductor which initializes some internal values. data = conductor.serialize() # Create a record for workflow execution. wf_ex_db = wf_db_models.WorkflowExecutionDB(action_execution=str( ac_ex_db.id), spec=data['spec'], graph=data['graph'], input=data['input'], context=data['context'], state=data['state'], status=data['state']['status'], output=data['output'], errors=data['errors']) # Inspect that the list of tasks in the notify parameter exist in the workflow spec. if runner_params.get('notify'): invalid_tasks = list( set(runner_params.get('notify')) - set(wf_spec.tasks.keys())) if invalid_tasks: raise wf_exc.WorkflowExecutionException( 'The following tasks in the notify parameter do not exist ' 'in the workflow definition: %s.' % ', '.join(invalid_tasks)) # Write notify instruction to record. if notify_cfg: # Set up the notify instruction in the workflow execution record. wf_ex_db.notify = { 'config': notify_cfg, 'tasks': runner_params.get('notify') } # Insert new record into the database and do not publish to the message bus yet. wf_ex_db = wf_db_access.WorkflowExecution.insert(wf_ex_db, publish=False) LOG.info('[%s] Workflow execution "%s" is created.', wf_ac_ex_id, str(wf_ex_db.id)) # Update the context with the workflow execution id created on database insert. # Publish the workflow execution requested status to the message bus. if wf_ex_db.status not in statuses.COMPLETED_STATUSES: # Set the initial workflow status to requested. conductor.request_workflow_status(statuses.REQUESTED) data = conductor.serialize() wf_ex_db.state = data['state'] wf_ex_db.status = data['state']['status'] # Put the ID of the workflow execution record in the context. wf_ex_db.context['st2']['workflow_execution_id'] = str(wf_ex_db.id) wf_ex_db.state['contexts'][0]['st2']['workflow_execution_id'] = str( wf_ex_db.id) # Update the workflow execution record. wf_ex_db = wf_db_access.WorkflowExecution.update(wf_ex_db, publish=False) wf_db_access.WorkflowExecution.publish_status(wf_ex_db) msg = '[%s] Workflow execution "%s" is published.' LOG.info(msg, wf_ac_ex_id, str(wf_ex_db.id)) else: msg = '[%s] Unable to request workflow execution. It is already in completed status "%s".' LOG.info(msg, wf_ac_ex_id, wf_ex_db.status) return wf_ex_db