def test_get_value_from_datastore_through_render_live_params(self): # Register datastore value to be refered by this test-case register_kwargs = [ { 'name': 'test_key', 'value': 'foo' }, { 'name': 'user1:test_key', 'value': 'bar', 'scope': FULL_USER_SCOPE }, { 'name': '%s:test_key' % cfg.CONF.system_user.user, 'value': 'baz', 'scope': FULL_USER_SCOPE }, ] for kwargs in register_kwargs: KeyValuePair.add_or_update(KeyValuePairDB(**kwargs)) # Assert that datastore value can be got via the Jinja expression from individual scopes. context = {'user': '******'} param = { 'system_value': { 'default': '{{ st2kv.system.test_key }}' }, 'user_value': { 'default': '{{ st2kv.user.test_key }}' }, } live_params = param_utils.render_live_params(runner_parameters={}, action_parameters=param, params={}, action_context=context) self.assertEqual(live_params['system_value'], 'foo') self.assertEqual(live_params['user_value'], 'bar') # Assert that datastore value in the user-scope that is registered by user1 # cannot be got by the operation of user2. context = {'user': '******'} param = {'user_value': {'default': '{{ st2kv.user.test_key }}'}} live_params = param_utils.render_live_params(runner_parameters={}, action_parameters=param, params={}, action_context=context) self.assertEqual(live_params['user_value'], '') # Assert that system-user's scope is selected when user and api_user parameter specified context = {} param = {'user_value': {'default': '{{ st2kv.user.test_key }}'}} live_params = param_utils.render_live_params(runner_parameters={}, action_parameters=param, params={}, action_context=context) self.assertEqual(live_params['user_value'], 'baz')
def test_get_value_from_datastore_through_render_live_params(self): # Register datastore value to be refered by this test-case register_kwargs = [ {"name": "test_key", "value": "foo"}, {"name": "user1:test_key", "value": "bar", "scope": FULL_USER_SCOPE}, { "name": "%s:test_key" % cfg.CONF.system_user.user, "value": "baz", "scope": FULL_USER_SCOPE, }, ] for kwargs in register_kwargs: KeyValuePair.add_or_update(KeyValuePairDB(**kwargs)) # Assert that datastore value can be got via the Jinja expression from individual scopes. context = {"user": "******"} param = { "system_value": {"default": "{{ st2kv.system.test_key }}"}, "user_value": {"default": "{{ st2kv.user.test_key }}"}, } live_params = param_utils.render_live_params( runner_parameters={}, action_parameters=param, params={}, action_context=context, ) self.assertEqual(live_params["system_value"], "foo") self.assertEqual(live_params["user_value"], "bar") # Assert that datastore value in the user-scope that is registered by user1 # cannot be got by the operation of user2. context = {"user": "******"} param = {"user_value": {"default": "{{ st2kv.user.test_key }}"}} live_params = param_utils.render_live_params( runner_parameters={}, action_parameters=param, params={}, action_context=context, ) self.assertEqual(live_params["user_value"], "") # Assert that system-user's scope is selected when user and api_user parameter specified context = {} param = {"user_value": {"default": "{{ st2kv.user.test_key }}"}} live_params = param_utils.render_live_params( runner_parameters={}, action_parameters=param, params={}, action_context=context, ) self.assertEqual(live_params["user_value"], "baz")
def test_get_live_params_with_additional_context(self): runner_param_info = { 'r1': { 'default': 'some' } } action_param_info = { 'r2': { 'default': '{{ r1 }}' } } params = { 'r3': 'lolcathost', 'r1': '{{ additional.stuff }}' } action_context = {} additional_contexts = { 'additional': { 'stuff': 'generic' } } live_params = param_utils.render_live_params( runner_param_info, action_param_info, params, action_context, additional_contexts) expected_params = { 'r1': 'generic', 'r3': 'lolcathost' } self.assertEqual(live_params, expected_params)
def _schedule_execution(self, liveaction): # Initialize execution context if it does not exist. if not hasattr(liveaction, 'context'): liveaction.context = dict() liveaction.context['user'] = get_requester() LOG.debug('User is: %s' % liveaction.context['user']) # Retrieve other st2 context from request header. if 'st2-context' in pecan.request.headers and pecan.request.headers['st2-context']: context = jsonify.try_loads(pecan.request.headers['st2-context']) if not isinstance(context, dict): raise ValueError('Unable to convert st2-context from the headers into JSON.') liveaction.context.update(context) # Schedule the action execution. liveaction_db = LiveActionAPI.to_model(liveaction) liveaction_db, actionexecution_db = action_service.create_request(liveaction_db) action_db = action_utils.get_action_by_ref(liveaction_db.action) runnertype_db = action_utils.get_runnertype_by_name(action_db.runner_type['name']) try: liveaction_db.parameters = param_utils.render_live_params( runnertype_db.runner_parameters, action_db.parameters, liveaction_db.parameters, liveaction_db.context) except ParamException as e: raise ValueValidationException(str(e)) liveaction_db = LiveAction.add_or_update(liveaction_db, publish=False) _, actionexecution_db = action_service.publish_request(liveaction_db, actionexecution_db) from_model_kwargs = self._get_from_model_kwargs_for_request(request=pecan.request) return ActionExecutionAPI.from_model(actionexecution_db, from_model_kwargs)
def test_get_live_params_with_additional_context(self): runner_param_info = { 'r1': { 'default': 'some' } } action_param_info = { 'r2': { 'default': '{{ r1 }}' } } params = { 'r3': 'lolcathost', 'r1': '{{ additional.stuff }}' } action_context = {} additional_contexts = { 'additional': { 'stuff': 'generic' } } live_params = param_utils.render_live_params( runner_param_info, action_param_info, params, action_context, additional_contexts) expected_params = { 'r1': 'generic', 'r2': 'generic', 'r3': 'lolcathost' } self.assertEqual(live_params, expected_params)
def request_action_execution(wf_ex_db, task_ex_db, st2_ctx, ac_ex_req): wf_ac_ex_id = wf_ex_db.action_execution action_ref = ac_ex_req['action'] action_input = ac_ex_req['input'] item_id = ac_ex_req.get('item_id') # If the task is with items and item_id is not provided, raise exception. if task_ex_db.itemized and item_id is None: msg = 'Unable to request action execution. Identifier for the item is not provided.' raise Exception(msg) # Identify the action to execute. action_db = action_utils.get_action_by_ref(ref=action_ref) if not action_db: error = 'Unable to find action "%s".' % 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']) # Set context for the action execution. ac_ex_ctx = { 'parent': st2_ctx, 'orquesta': { 'workflow_execution_id': str(wf_ex_db.id), 'task_execution_id': str(task_ex_db.id), 'task_name': task_ex_db.task_name, 'task_id': task_ex_db.task_id } } if item_id is not None: ac_ex_ctx['orquesta']['item_id'] = item_id # Render action execution parameters and setup action execution object. ac_ex_params = param_utils.render_live_params( runner_type_db.runner_parameters or {}, action_db.parameters or {}, action_input or {}, ac_ex_ctx) lv_ac_db = lv_db_models.LiveActionDB(action=action_ref, workflow_execution=str(wf_ex_db.id), task_execution=str(task_ex_db.id), context=ac_ex_ctx, parameters=ac_ex_params) # Set the task execution to running first otherwise a race can occur # where the action execution finishes first and the completion handler # conflicts with this status update. task_ex_db.status = states.RUNNING task_ex_db = wf_db_access.TaskExecution.update(task_ex_db, publish=False) # Request action execution. lv_ac_db, ac_ex_db = ac_svc.request(lv_ac_db) msg = '[%s] Action execution "%s" requested for task "%s".' LOG.info(msg, wf_ac_ex_id, str(ac_ex_db.id), task_ex_db.task_id) return ac_ex_db
def _schedule_execution(self, liveaction, user=None, context_string=None, show_secrets=False): # Initialize execution context if it does not exist. if not hasattr(liveaction, 'context'): liveaction.context = dict() liveaction.context['user'] = user LOG.debug('User is: %s' % liveaction.context['user']) # Retrieve other st2 context from request header. if context_string: context = try_loads(context_string) if not isinstance(context, dict): raise ValueError( 'Unable to convert st2-context from the headers into JSON.' ) liveaction.context.update(context) # Schedule the action execution. liveaction_db = LiveActionAPI.to_model(liveaction) liveaction_db, actionexecution_db = action_service.create_request( liveaction_db) action_db = action_utils.get_action_by_ref(liveaction_db.action) runnertype_db = action_utils.get_runnertype_by_name( action_db.runner_type['name']) try: liveaction_db.parameters = param_utils.render_live_params( runnertype_db.runner_parameters, action_db.parameters, liveaction_db.parameters, liveaction_db.context) except ParamException: # By this point the execution is already in the DB therefore need to mark it failed. _, e, tb = sys.exc_info() action_service.update_status(liveaction=liveaction_db, new_status=LIVEACTION_STATUS_FAILED, result={ 'error': str(e), 'traceback': ''.join( traceback.format_tb(tb, 20)) }) # Might be a good idea to return the actual ActionExecution rather than bubble up # the execption. raise ValueValidationException(str(e)) liveaction_db = LiveAction.add_or_update(liveaction_db, publish=False) _, actionexecution_db = action_service.publish_request( liveaction_db, actionexecution_db) execution_api = ActionExecutionAPI.from_model( actionexecution_db, mask_secrets=(not show_secrets)) return Response(json=execution_api, status=http_client.CREATED)
def test_get_value_from_datastore_through_render_live_params(self): # Register datastore value to be refered by this test-case register_kwargs = [ {'name': 'test_key', 'value': 'foo'}, {'name': 'user1:test_key', 'value': 'bar', 'scope': FULL_USER_SCOPE}, {'name': '%s:test_key' % cfg.CONF.system_user.user, 'value': 'baz', 'scope': FULL_USER_SCOPE}, ] for kwargs in register_kwargs: KeyValuePair.add_or_update(KeyValuePairDB(**kwargs)) # Assert that datastore value can be got via the Jinja expression from individual scopes. context = {'user': '******'} param = { 'system_value': {'default': '{{ st2kv.system.test_key }}'}, 'user_value': {'default': '{{ st2kv.user.test_key }}'}, } live_params = param_utils.render_live_params(runner_parameters={}, action_parameters=param, params={}, action_context=context) self.assertEqual(live_params['system_value'], 'foo') self.assertEqual(live_params['user_value'], 'bar') # Assert that datastore value in the user-scope that is registered by user1 # cannot be got by the operation of user2. context = {'user': '******'} param = {'user_value': {'default': '{{ st2kv.user.test_key }}'}} live_params = param_utils.render_live_params(runner_parameters={}, action_parameters=param, params={}, action_context=context) self.assertEqual(live_params['user_value'], '') # Assert that system-user's scope is selected when user and api_user parameter specified context = {} param = {'user_value': {'default': '{{ st2kv.user.test_key }}'}} live_params = param_utils.render_live_params(runner_parameters={}, action_parameters=param, params={}, action_context=context) self.assertEqual(live_params['user_value'], 'baz')
def get_resolved_parameters(self, action_db, runnertype_db, params, context=None, additional_contexts=None): resolved_params = param_utils.render_live_params( runner_parameters=runnertype_db.runner_parameters, action_parameters=action_db.parameters, params=params, action_context=context, additional_contexts=additional_contexts) return resolved_params
def test_get_live_params_with_additional_context(self): runner_param_info = {"r1": {"default": "some"}} action_param_info = {"r2": {"default": "{{ r1 }}"}} params = {"r3": "lolcathost", "r1": "{{ additional.stuff }}"} action_context = {"user": None} additional_contexts = {"additional": {"stuff": "generic"}} live_params = param_utils.render_live_params( runner_param_info, action_param_info, params, action_context, additional_contexts, ) expected_params = {"r1": "generic", "r2": "generic", "r3": "lolcathost"} self.assertEqual(live_params, expected_params)
def _schedule_execution(self, liveaction): # Initialize execution context if it does not exist. if not hasattr(liveaction, 'context'): liveaction.context = dict() liveaction.context['user'] = get_requester() LOG.debug('User is: %s' % liveaction.context['user']) # Retrieve other st2 context from request header. if 'st2-context' in pecan.request.headers and pecan.request.headers[ 'st2-context']: context = jsonify.try_loads(pecan.request.headers['st2-context']) if not isinstance(context, dict): raise ValueError( 'Unable to convert st2-context from the headers into JSON.' ) liveaction.context.update(context) # Schedule the action execution. liveaction_db = LiveActionAPI.to_model(liveaction) liveaction_db, actionexecution_db = action_service.create_request( liveaction_db) action_db = action_utils.get_action_by_ref(liveaction_db.action) runnertype_db = action_utils.get_runnertype_by_name( action_db.runner_type['name']) try: liveaction_db.parameters = param_utils.render_live_params( runnertype_db.runner_parameters, action_db.parameters, liveaction_db.parameters, liveaction_db.context) except ParamException as e: raise ValueValidationException(str(e)) liveaction_db = LiveAction.add_or_update(liveaction_db, publish=False) _, actionexecution_db = action_service.publish_request( liveaction_db, actionexecution_db) from_model_kwargs = self._get_from_model_kwargs_for_request( request=pecan.request) return ActionExecutionAPI.from_model(actionexecution_db, from_model_kwargs)
def _schedule_execution(self, liveaction, user=None): # Initialize execution context if it does not exist. if not hasattr(liveaction, 'context'): liveaction.context = dict() liveaction.context['user'] = user LOG.debug('User is: %s' % liveaction.context['user']) # Retrieve other st2 context from request header. if 'st2-context' in pecan.request.headers and pecan.request.headers['st2-context']: context = jsonify.try_loads(pecan.request.headers['st2-context']) if not isinstance(context, dict): raise ValueError('Unable to convert st2-context from the headers into JSON.') liveaction.context.update(context) # Schedule the action execution. liveaction_db = LiveActionAPI.to_model(liveaction) liveaction_db, actionexecution_db = action_service.create_request(liveaction_db) action_db = action_utils.get_action_by_ref(liveaction_db.action) runnertype_db = action_utils.get_runnertype_by_name(action_db.runner_type['name']) try: liveaction_db.parameters = param_utils.render_live_params( runnertype_db.runner_parameters, action_db.parameters, liveaction_db.parameters, liveaction_db.context) except ParamException: # By this point the execution is already in the DB therefore need to mark it failed. _, e, tb = sys.exc_info() action_service.update_status( liveaction=liveaction_db, new_status=LIVEACTION_STATUS_FAILED, result={'error': str(e), 'traceback': ''.join(traceback.format_tb(tb, 20))}) # Might be a good idea to return the actual ActionExecution rather than bubble up # the execption. raise ValueValidationException(str(e)) liveaction_db = LiveAction.add_or_update(liveaction_db, publish=False) _, actionexecution_db = action_service.publish_request(liveaction_db, actionexecution_db) from_model_kwargs = self._get_from_model_kwargs_for_request(request=pecan.request) return ActionExecutionAPI.from_model(actionexecution_db, from_model_kwargs)
def base(event, context, passthrough=False): # Set up logging logger = logging.getLogger() # Read DEBUG value from the environment variable debug = os.environ.get('ST2_DEBUG', False) if str(debug).lower() in ['true', '1']: debug = True if debug: logger.setLevel(logging.DEBUG) else: logger.setLevel(logging.INFO) if isinstance(event, basestring): try: event = json.loads(event) except ValueError as e: LOG.error("ERROR: Can not parse `event`: '{}'\n{}".format( str(event), str(e))) raise e LOG.info("Received event: " + json.dumps(event, indent=2)) # Special case for Lambda function being called over HTTP via API gateway # See # https://serverless.com/framework/docs/providers/aws/events/apigateway # #example-lambda-proxy-event-default # for details is_event_body_string = (isinstance(event.get('body'), basestring) is True) content_type = event.get('headers', {}).get('content-type', '').lower() if is_event_body_string: if content_type == 'application/json': try: event['body'] = json.loads(event['body']) except Exception as e: LOG.warn('`event` has `body` which is not JSON: %s', str(e.message)) elif content_type == 'application/x-www-form-urlencoded': try: event['body'] = dict( parse_qsl(['body'], keep_blank_values=True)) except Exception as e: LOG.warn('`event` has `body` which is not `%s`: %s', content_type, str(e.message)) else: LOG.warn('Unsupported event content type: %s' % (content_type)) action_name = os.environ['ST2_ACTION'] try: action_db = ACTIONS[action_name] except KeyError: raise ValueError('No action named "%s" has been installed.' % (action_name)) manager = DriverManager(namespace='st2common.runners.runner', invoke_on_load=False, name=action_db.runner_type['name']) runnertype_db = RunnerTypeAPI.to_model( RunnerTypeAPI(**manager.driver.get_metadata()[0])) if passthrough: runner = PassthroughRunner() else: runner = manager.driver.get_runner() runner._sandbox = False runner.runner_type_db = runnertype_db runner.action = action_db runner.action_name = action_db.name # runner.liveaction = liveaction_db # runner.liveaction_id = str(liveaction_db.id) # runner.execution = ActionExecution.get(liveaction__id=runner.liveaction_id) # runner.execution_id = str(runner.execution.id) runner.entry_point = content_utils.get_entry_point_abs_path( pack=action_db.pack, entry_point=action_db.entry_point) runner.context = {} # getattr(liveaction_db, 'context', dict()) # runner.callback = getattr(liveaction_db, 'callback', dict()) runner.libs_dir_path = content_utils.get_action_libs_abs_path( pack=action_db.pack, entry_point=action_db.entry_point) # For re-run, get the ActionExecutionDB in which the re-run is based on. # rerun_ref_id = runner.context.get('re-run', {}).get('ref') # runner.rerun_ex_ref = ActionExecution.get(id=rerun_ref_id) if rerun_ref_id else None config_schema = CONFIG_SCHEMAS.get(action_db.pack, None) config_values = os.environ.get('ST2_CONFIG', None) if config_schema and config_values: runner._config = validate_config_against_schema( config_schema=config_schema, config_object=json.loads(config_values), config_path=None, pack_name=action_db.pack) param_values = os.environ.get('ST2_PARAMETERS', None) try: if param_values: live_params = param_utils.render_live_params( runner_parameters=runnertype_db.runner_parameters, action_parameters=action_db.parameters, params=json.loads(param_values), action_context={}, additional_contexts={'input': event}) else: live_params = event if debug and 'log_level' not in live_params: # Set log_level runner parameter live_params['log_level'] = 'DEBUG' runner_params, action_params = param_utils.render_final_params( runner_parameters=runnertype_db.runner_parameters, action_parameters=action_db.parameters, params=live_params, action_context={}) except ParamException as e: raise actionrunner.ActionRunnerException(str(e)) runner.runner_parameters = runner_params LOG.debug('Performing pre-run for runner: %s', runner.runner_id) runner.pre_run() (status, output, context) = runner.run(action_params) output_values = os.environ.get('ST2_OUTPUT', None) if output_values: try: result = param_utils.render_live_params( runner_parameters=runnertype_db.runner_parameters, action_parameters=action_db.parameters, params=json.loads(output_values), action_context={}, additional_contexts={ 'input': event, 'output': output }) except ParamException as e: raise actionrunner.ActionRunnerException(str(e)) else: result = output # Log the logs generated by the action. We do that so the actual action logs # (action stderr) end up in CloudWatch output = output or {} if output.get('stdout', None): LOG.info('Action stdout: %s' % (output['stdout'])) if output.get('stderr', None): LOG.info('Action stderr and logs: %s' % (output['stderr'])) return { 'event': event, 'live_params': live_params, 'output': output, 'result': result }
def main(): # Read DEBUG value from the environment variable debug = os.environ.get('ST2_DEBUG', False) if str(debug).lower() in ['true', '1']: debug = True if debug: LOG.setLevel(logging.DEBUG) else: LOG.setLevel(logging.INFO) # Read input = os.environ.get('ST2_INPUT', {}) if isinstance(input, six.string_types): try: input = json.loads(input) except ValueError as e: LOG.error("ERROR: Can not parse `input`: '{}'\n{}".format(str(input), str(e))) raise e LOG.debug("Received input: " + json.dumps(input, indent=2)) # Read action name from environment variable action_name = os.environ['ST2_ACTION'] try: action_db = ACTIONS[action_name] except KeyError: raise ValueError('No action named "%s" has been installed.' % (action_name)) # Initialize runner manager = DriverManager(namespace='st2common.runners.runner', invoke_on_load=False, name=action_db.runner_type['name']) runnertype_db = RunnerTypeAPI.to_model(RunnerTypeAPI(**manager.driver.get_metadata())) runner = manager.driver.get_runner() runner._sandbox = False runner.runner_type_db = runnertype_db runner.action = action_db runner.action_name = action_db.name runner.entry_point = content_utils.get_entry_point_abs_path(pack=action_db.pack, entry_point=action_db.entry_point) runner.context = {} runner.libs_dir_path = content_utils.get_action_libs_abs_path(pack=action_db.pack, entry_point=action_db.entry_point) config_schema = CONFIG_SCHEMAS.get(action_db.pack, None) config_values = os.environ.get('ST2_CONFIG', None) if config_schema and config_values: runner._config = validate_config_against_schema(config_schema=config_schema, config_object=json.loads(config_values), config_path=None, pack_name=action_db.pack) param_values = os.environ.get('ST2_PARAMETERS', None) try: if param_values: live_params = param_utils.render_live_params( runner_parameters=runnertype_db.runner_parameters, action_parameters=action_db.parameters, params=json.loads(param_values), action_context={}, additional_contexts={ 'input': input }) else: live_params = input if debug and 'log_level' not in live_params: # Set log_level runner parameter live_params['log_level'] = 'DEBUG' runner_params, action_params = param_utils.render_final_params( runner_parameters=runnertype_db.runner_parameters, action_parameters=action_db.parameters, params=live_params, action_context={}) except ParamException as e: raise actionrunner.ActionRunnerException(str(e)) runner.runner_parameters = runner_params LOG.debug('Performing pre-run for runner: %s', runner.runner_id) runner.pre_run() (status, output, context) = runner.run(action_params) try: output['result'] = json.loads(output['result']) except Exception: pass output_values = os.environ.get('ST2_OUTPUT', None) if output_values: try: result = param_utils.render_live_params( runner_parameters={}, action_parameters={}, params=json.loads(output_values), action_context={}, additional_contexts={ 'input': input, 'output': output }) except ParamException as e: raise actionrunner.ActionRunnerException(str(e)) else: result = output output = output or {} if output.get('stdout', None): LOG.info('Action stdout: %s' % (output['stdout'])) if output.get('stderr', None): LOG.info('Action stderr and logs: %s' % (output['stderr'])) print(json.dumps(result))
def _schedule_execution(self, liveaction, requester_user, action_db, user=None, context_string=None, show_secrets=False): # Initialize execution context if it does not exist. if not hasattr(liveaction, 'context'): liveaction.context = dict() liveaction.context['user'] = user liveaction.context['pack'] = action_db.pack LOG.debug('User is: %s' % liveaction.context['user']) # Retrieve other st2 context from request header. if context_string: context = try_loads(context_string) if not isinstance(context, dict): raise ValueError('Unable to convert st2-context from the headers into JSON.') liveaction.context.update(context) # Include RBAC context (if RBAC is available and enabled) if cfg.CONF.rbac.enable: user_db = UserDB(name=user) role_dbs = rbac_service.get_roles_for_user(user_db=user_db, include_remote=True) roles = [role_db.name for role_db in role_dbs] liveaction.context['rbac'] = { 'user': user, 'roles': roles } # Schedule the action execution. liveaction_db = LiveActionAPI.to_model(liveaction) runnertype_db = action_utils.get_runnertype_by_name(action_db.runner_type['name']) try: liveaction_db.parameters = param_utils.render_live_params( runnertype_db.runner_parameters, action_db.parameters, liveaction_db.parameters, liveaction_db.context) except param_exc.ParamException: # We still need to create a request, so liveaction_db is assigned an ID liveaction_db, actionexecution_db = action_service.create_request( liveaction=liveaction_db, action_db=action_db, runnertype_db=runnertype_db) # By this point the execution is already in the DB therefore need to mark it failed. _, e, tb = sys.exc_info() action_service.update_status( liveaction=liveaction_db, new_status=action_constants.LIVEACTION_STATUS_FAILED, result={'error': six.text_type(e), 'traceback': ''.join(traceback.format_tb(tb, 20))}) # Might be a good idea to return the actual ActionExecution rather than bubble up # the exception. raise validation_exc.ValueValidationException(six.text_type(e)) # The request should be created after the above call to render_live_params # so any templates in live parameters have a chance to render. liveaction_db, actionexecution_db = action_service.create_request(liveaction=liveaction_db, action_db=action_db, runnertype_db=runnertype_db) _, actionexecution_db = action_service.publish_request(liveaction_db, actionexecution_db) mask_secrets = self._get_mask_secrets(requester_user, show_secrets=show_secrets) execution_api = ActionExecutionAPI.from_model(actionexecution_db, mask_secrets=mask_secrets) return Response(json=execution_api, status=http_client.CREATED)
def request_task_execution(wf_ex_db, task_id, task_spec, task_ctx, st2_ctx): # Create a record for task execution. task_ex_db = wf_db_models.TaskExecutionDB( workflow_execution=str(wf_ex_db.id), task_name=task_spec.name or task_id, task_id=task_id, task_spec=task_spec.serialize(), initial_context=task_ctx, status=states.REQUESTED ) # Insert new record into the database. task_ex_db = wf_db_access.TaskExecution.insert(task_ex_db, publish=False) try: # Return here if no action is specified in task spec. if task_spec.action is None: # Set the task execution to running. task_ex_db.status = states.RUNNING task_ex_db = wf_db_access.TaskExecution.update(task_ex_db, publish=False) # Fast forward task execution to completion. update_task_execution(str(task_ex_db.id), states.SUCCEEDED) update_task_flow(str(task_ex_db.id), publish=False) # Refresh and return the task execution return wf_db_access.TaskExecution.get_by_id(str(task_ex_db.id)) # Identify the action to execute. action_db = ac_db_util.get_action_by_ref(ref=task_spec.action) if not action_db: error = 'Unable to find action "%s".' % task_spec.action raise ac_exc.InvalidActionReferencedException(error) # Identify the runner for the action. runner_type_db = ac_db_util.get_runnertype_by_name(action_db.runner_type['name']) # Set context for the action execution. ac_ex_ctx = { 'parent': st2_ctx, 'orchestra': { 'workflow_execution_id': str(wf_ex_db.id), 'task_execution_id': str(task_ex_db.id), 'task_name': task_spec.name or task_id, 'task_id': task_id } } # Render action execution parameters and setup action execution object. ac_ex_params = param_utils.render_live_params( runner_type_db.runner_parameters or {}, action_db.parameters or {}, getattr(task_spec, 'input', None) or {}, ac_ex_ctx ) lv_ac_db = lv_db_models.LiveActionDB( action=task_spec.action, workflow_execution=str(wf_ex_db.id), task_execution=str(task_ex_db.id), context=ac_ex_ctx, parameters=ac_ex_params ) # Request action execution. ac_svc.request(lv_ac_db) # Set the task execution to running. task_ex_db.status = states.RUNNING task_ex_db = wf_db_access.TaskExecution.update(task_ex_db, publish=False) except Exception as e: result = {'errors': [{'message': str(e), 'task_id': task_ex_db.task_id}]} update_task_execution(str(task_ex_db.id), states.FAILED, result) raise e return task_ex_db
def request_action_execution(wf_ex_db, task_ex_db, st2_ctx, ac_ex_req, delay=None): wf_ac_ex_id = wf_ex_db.action_execution action_ref = ac_ex_req['action'] action_input = ac_ex_req['input'] item_id = ac_ex_req.get('item_id') # If the task is with items and item_id is not provided, raise exception. if task_ex_db.itemized and item_id is None: msg = 'Unable to request action execution. Identifier for the item is not provided.' raise Exception(msg) # Identify the action to execute. action_db = action_utils.get_action_by_ref(ref=action_ref) if not action_db: error = 'Unable to find action "%s".' % 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']) # Identify action pack name pack_name = action_ref.split('.')[0] if action_ref else st2_ctx.get('pack') # Set context for the action execution. ac_ex_ctx = { 'pack': pack_name, 'user': st2_ctx.get('user'), 'parent': st2_ctx, 'orquesta': { 'workflow_execution_id': str(wf_ex_db.id), 'task_execution_id': str(task_ex_db.id), 'task_name': task_ex_db.task_name, 'task_id': task_ex_db.task_id, 'task_route': task_ex_db.task_route } } if st2_ctx.get('api_user'): ac_ex_ctx['api_user'] = st2_ctx.get('api_user') if st2_ctx.get('source_channel'): ac_ex_ctx['source_channel'] = st2_ctx.get('source_channel') if item_id is not None: ac_ex_ctx['orquesta']['item_id'] = item_id # Render action execution parameters and setup action execution object. ac_ex_params = param_utils.render_live_params( runner_type_db.runner_parameters or {}, action_db.parameters or {}, action_input or {}, ac_ex_ctx) # The delay spec is in seconds and scheduler expects milliseconds. if delay is not None and delay > 0: delay = delay * 1000 # Instantiate the live action record. lv_ac_db = lv_db_models.LiveActionDB(action=action_ref, workflow_execution=str(wf_ex_db.id), task_execution=str(task_ex_db.id), delay=delay, context=ac_ex_ctx, parameters=ac_ex_params) # Set notification if instructed. if (wf_ex_db.notify and wf_ex_db.notify.get('config') and wf_ex_db.notify.get('tasks') and task_ex_db.task_name in wf_ex_db.notify['tasks']): lv_ac_db.notify = notify_api_models.NotificationsHelper.to_model( wf_ex_db.notify['config']) # Set the task execution to running first otherwise a race can occur # where the action execution finishes first and the completion handler # conflicts with this status update. task_ex_db.status = statuses.RUNNING task_ex_db = wf_db_access.TaskExecution.update(task_ex_db, publish=False) # Request action execution. lv_ac_db, ac_ex_db = ac_svc.request(lv_ac_db) msg = '[%s] Action execution "%s" requested for task "%s", route "%s".' LOG.info(msg, wf_ac_ex_id, str(ac_ex_db.id), task_ex_db.task_id, str(task_ex_db.task_route)) return ac_ex_db
def request_task_execution(wf_ex_db, task_id, task_spec, task_ctx, st2_ctx): wf_ac_ex_id = wf_ex_db.action_execution LOG.info('[%s] Processing task execution request for "%s".', wf_ac_ex_id, task_id) # Create a record for task execution. task_ex_db = wf_db_models.TaskExecutionDB( workflow_execution=str(wf_ex_db.id), task_name=task_spec.name or task_id, task_id=task_id, task_spec=task_spec.serialize(), context=task_ctx, status=states.REQUESTED) # Insert new record into the database. task_ex_db = wf_db_access.TaskExecution.insert(task_ex_db, publish=False) task_ex_id = str(task_ex_db.id) LOG.info('[%s] Task execution "%s" created for task "%s".', wf_ac_ex_id, task_ex_id, task_id) try: # Return here if no action is specified in task spec. if task_spec.action is None: # Set the task execution to running. task_ex_db.status = states.RUNNING task_ex_db = wf_db_access.TaskExecution.update(task_ex_db, publish=False) # Fast forward task execution to completion. update_task_execution(str(task_ex_db.id), states.SUCCEEDED) update_task_flow(str(task_ex_db.id), publish=False) # Refresh and return the task execution return wf_db_access.TaskExecution.get_by_id(str(task_ex_db.id)) # Identify the action to execute. action_db = action_utils.get_action_by_ref(ref=task_spec.action) if not action_db: error = 'Unable to find action "%s".' % task_spec.action 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']) # Set context for the action execution. ac_ex_ctx = { 'parent': st2_ctx, 'orquesta': { 'workflow_execution_id': str(wf_ex_db.id), 'task_execution_id': str(task_ex_db.id), 'task_name': task_spec.name or task_id, 'task_id': task_id } } # Render action execution parameters and setup action execution object. ac_ex_params = param_utils.render_live_params( runner_type_db.runner_parameters or {}, action_db.parameters or {}, getattr(task_spec, 'input', None) or {}, ac_ex_ctx) lv_ac_db = lv_db_models.LiveActionDB(action=task_spec.action, workflow_execution=str( wf_ex_db.id), task_execution=str(task_ex_db.id), context=ac_ex_ctx, parameters=ac_ex_params) # Set the task execution to running first otherwise a race can occur # where the action execution finishes first and the completion handler # conflicts with this status update. task_ex_db.status = states.RUNNING task_ex_db = wf_db_access.TaskExecution.update(task_ex_db, publish=False) # Request action execution. lv_ac_db, ac_ex_db = ac_svc.request(lv_ac_db) msg = '[%s] Action execution "%s" requested for task "%s".' LOG.info(msg, wf_ac_ex_id, str(ac_ex_db.id), task_id) except Exception as e: LOG.exception('[%s] Failed task execution for task "%s".', wf_ac_ex_id, task_id) result = { 'errors': [{ 'message': str(e), 'task_id': task_ex_db.task_id }] } update_task_execution(str(task_ex_db.id), states.FAILED, result) raise e return task_ex_db
def _schedule_execution(self, liveaction, requester_user, user=None, context_string=None, show_secrets=False, pack=None): # Initialize execution context if it does not exist. if not hasattr(liveaction, 'context'): liveaction.context = dict() liveaction.context['user'] = user liveaction.context['pack'] = pack LOG.debug('User is: %s' % liveaction.context['user']) # Retrieve other st2 context from request header. if context_string: context = try_loads(context_string) if not isinstance(context, dict): raise ValueError( 'Unable to convert st2-context from the headers into JSON.' ) liveaction.context.update(context) # Include RBAC context (if RBAC is available and enabled) if cfg.CONF.rbac.enable: user_db = UserDB(name=user) role_dbs = rbac_service.get_roles_for_user(user_db=user_db, include_remote=True) roles = [role_db.name for role_db in role_dbs] liveaction.context['rbac'] = {'user': user, 'roles': roles} # Schedule the action execution. liveaction_db = LiveActionAPI.to_model(liveaction) action_db = action_utils.get_action_by_ref(liveaction_db.action) runnertype_db = action_utils.get_runnertype_by_name( action_db.runner_type['name']) try: liveaction_db.parameters = param_utils.render_live_params( runnertype_db.runner_parameters, action_db.parameters, liveaction_db.parameters, liveaction_db.context) except param_exc.ParamException: # We still need to create a request, so liveaction_db is assigned an ID liveaction_db, actionexecution_db = action_service.create_request( liveaction_db) # By this point the execution is already in the DB therefore need to mark it failed. _, e, tb = sys.exc_info() action_service.update_status( liveaction=liveaction_db, new_status=action_constants.LIVEACTION_STATUS_FAILED, result={ 'error': str(e), 'traceback': ''.join(traceback.format_tb(tb, 20)) }) # Might be a good idea to return the actual ActionExecution rather than bubble up # the exception. raise validation_exc.ValueValidationException(str(e)) # The request should be created after the above call to render_live_params # so any templates in live parameters have a chance to render. liveaction_db, actionexecution_db = action_service.create_request( liveaction_db) liveaction_db = LiveAction.add_or_update(liveaction_db, publish=False) _, actionexecution_db = action_service.publish_request( liveaction_db, actionexecution_db) mask_secrets = self._get_mask_secrets(requester_user, show_secrets=show_secrets) execution_api = ActionExecutionAPI.from_model( actionexecution_db, mask_secrets=mask_secrets) return Response(json=execution_api, status=http_client.CREATED)
def request_action_execution(wf_ex_db, task_ex_db, st2_ctx, ac_ex_req, delay=None): wf_ac_ex_id = wf_ex_db.action_execution action_ref = ac_ex_req['action'] action_input = ac_ex_req['input'] item_id = ac_ex_req.get('item_id') # If the task is with items and item_id is not provided, raise exception. if task_ex_db.itemized and item_id is None: msg = 'Unable to request action execution. Identifier for the item is not provided.' raise Exception(msg) # Identify the action to execute. action_db = action_utils.get_action_by_ref(ref=action_ref) if not action_db: error = 'Unable to find action "%s".' % 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']) # Identify action pack name pack_name = action_ref.split('.')[0] if action_ref else st2_ctx.get('pack') # Set context for the action execution. ac_ex_ctx = { 'pack': pack_name, 'user': st2_ctx.get('user'), 'parent': st2_ctx, 'orquesta': { 'workflow_execution_id': str(wf_ex_db.id), 'task_execution_id': str(task_ex_db.id), 'task_name': task_ex_db.task_name, 'task_id': task_ex_db.task_id, 'task_route': task_ex_db.task_route } } if st2_ctx.get('api_user'): ac_ex_ctx['api_user'] = st2_ctx.get('api_user') if item_id is not None: ac_ex_ctx['orquesta']['item_id'] = item_id # Render action execution parameters and setup action execution object. ac_ex_params = param_utils.render_live_params( runner_type_db.runner_parameters or {}, action_db.parameters or {}, action_input or {}, ac_ex_ctx ) # The delay spec is in seconds and scheduler expects milliseconds. if delay is not None and delay > 0: delay = delay * 1000 # Instantiate the live action record. lv_ac_db = lv_db_models.LiveActionDB( action=action_ref, workflow_execution=str(wf_ex_db.id), task_execution=str(task_ex_db.id), delay=delay, context=ac_ex_ctx, parameters=ac_ex_params ) # Set notification if instructed. if (wf_ex_db.notify and wf_ex_db.notify.get('config') and wf_ex_db.notify.get('tasks') and task_ex_db.task_name in wf_ex_db.notify['tasks']): lv_ac_db.notify = notify_api_models.NotificationsHelper.to_model(wf_ex_db.notify['config']) # Set the task execution to running first otherwise a race can occur # where the action execution finishes first and the completion handler # conflicts with this status update. task_ex_db.status = statuses.RUNNING task_ex_db = wf_db_access.TaskExecution.update(task_ex_db, publish=False) # Request action execution. lv_ac_db, ac_ex_db = ac_svc.request(lv_ac_db) msg = '[%s] Action execution "%s" requested for task "%s", route "%s".' LOG.info(msg, wf_ac_ex_id, str(ac_ex_db.id), task_ex_db.task_id, str(task_ex_db.task_route)) return ac_ex_db