def test_try_loads(self): # The function json.loads will fail and the function should return the original value. values = ['abc', 123, True, object()] for value in values: self.assertEqual(jsonify.try_loads(value), value) # The function json.loads succeed. d = '{"a": 1, "b": true}' expected = {'a': 1, 'b': True} self.assertDictEqual(jsonify.try_loads(d), expected)
def _schedule_execution(self, liveaction): # Initialize execution context if it does not exist. if not hasattr(liveaction, 'context'): liveaction.context = dict() # Retrieve username of the authed user (note - if auth is disabled, user will not be # set so we fall back to the system user name) request_token = pecan.request.context.get('token', None) if request_token: user = request_token.user else: user = cfg.CONF.system_user.user liveaction.context['user'] = user LOG.debug('User is: %s' % 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. liveactiondb = LiveActionAPI.to_model(liveaction) _, actionexecutiondb = action_service.request(liveactiondb) from_model_kwargs = self._get_from_model_kwargs_for_request( request=pecan.request) return ActionExecutionAPI.from_model(actionexecutiondb, from_model_kwargs)
def _do_resume(self, runner): try: extra = {'runner': runner} LOG.debug('Performing resume for runner: %s', (runner.runner_id), extra=extra) (status, result, context) = runner.resume() result = jsonify.try_loads(result) action_completed = status in action_constants.LIVEACTION_COMPLETED_STATES if (isinstance(runner, PollingAsyncActionRunner) and runner.is_polling_enabled() and not action_completed): queries.setup_query(runner.liveaction.id, runner.runner_type, context) except: _, ex, tb = sys.exc_info() # include the error message and traceback to try and provide some hints. status = action_constants.LIVEACTION_STATUS_FAILED result = {'error': str(ex), 'traceback': ''.join(traceback.format_tb(tb, 20))} context = runner.liveaction.context LOG.exception('Failed to resume action %s.' % (runner.liveaction.id), extra=result) finally: # Update the final status of liveaction and corresponding action execution. runner.liveaction = self._update_status(runner.liveaction.id, status, result, context) # Always clean-up the auth_token # This method should be called in the finally block to ensure post_run is not impacted. self._clean_up_auth_token(runner=runner, status=runner.liveaction.status) LOG.debug('Performing post_run for runner: %s', runner.runner_id) runner.post_run(status=status, result=result) LOG.debug('Runner do_run result', extra={'result': runner.liveaction.result}) LOG.audit('Liveaction completed', extra={'liveaction_db': runner.liveaction}) return runner.liveaction
def _schedule_execution(self, liveaction): # Initialize execution context if it does not exist. if not hasattr(liveaction, 'context'): liveaction.context = dict() liveaction.context['user'] = self._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. liveactiondb = LiveActionAPI.to_model(liveaction) _, actionexecutiondb = action_service.request(liveactiondb) from_model_kwargs = self._get_from_model_kwargs_for_request( request=pecan.request) return ActionExecutionAPI.from_model(actionexecutiondb, from_model_kwargs)
def _get_workflow_result(self, st2_exec_id, mistral_exec_id): """ Returns the workflow status and output. Mistral workflow status will be converted to st2 action status. :param st2_exec_id: st2 execution ID :type st2_exec_id: ``str`` :param mistral_exec_id: Mistral execution ID :type mistral_exec_id: ``str`` :rtype: (``str``, ``dict``) """ try: jitter = random.uniform(0, self._jitter) eventlet.sleep(jitter) execution = self._client.executions.get(mistral_exec_id) except mistralclient_base.APIException as mistral_exc: if 'not found' in mistral_exc.message: raise exceptions.ReferenceNotFoundError(mistral_exc.message) raise mistral_exc result = jsonify.try_loads( execution.output) if execution.state in DONE_STATES else {} result['extra'] = { 'state': execution.state, 'state_info': execution.state_info } LOG.info('[%s] Query returned status "%s" for mistral execution %s.', st2_exec_id, execution.state, mistral_exec_id) return result
def _schedule_execution(self, execution): # Initialize execution context if it does not exist. if not hasattr(execution, 'context'): execution.context = dict() # Retrieve username of the authed user (note - if auth is disabled, user will not be # set so we fall back to the system user name) request_token = pecan.request.context.get('token', None) if request_token: user = request_token.user else: user = cfg.CONF.system_user.user execution.context['user'] = 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.') execution.context.update(context) # Schedule the action execution. liveactiondb = LiveActionAPI.to_model(execution) _, actionexecutiondb = action_service.request(liveactiondb) return ActionExecutionAPI.from_model(actionexecutiondb)
def _get_workflow_result(self, exec_id): """ Returns the workflow status and output. Mistral workflow status will be converted to st2 action status. :param exec_id: Mistral execution ID :type exec_id: ``str`` :rtype: (``str``, ``dict``) """ url = self._get_execution_url(exec_id) resp = requests.get(url) execution = resp.json() workflow_state = execution.get('state', None) if not workflow_state: raise Exception( 'Workflow status unknown for mistral execution id %s.' % exec_id) if workflow_state in DONE_STATES: workflow_output = jsonify.try_loads(execution.get('output', {})) return (DONE_STATES[workflow_state], workflow_output) return (ACTIONEXEC_STATUS_RUNNING, None)
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 _get_workflow_result(self, st2_exec_id, mistral_exec_id): """ Returns the workflow status and output. Mistral workflow status will be converted to st2 action status. :param st2_exec_id: st2 execution ID :type st2_exec_id: ``str`` :param mistral_exec_id: Mistral execution ID :type mistral_exec_id: ``str`` :rtype: (``str``, ``dict``) """ try: jitter = random.uniform(0, self._jitter) eventlet.sleep(jitter) execution = self._client.executions.get(mistral_exec_id) except mistralclient_base.APIException as mistral_exc: if 'not found' in str(mistral_exc): raise exceptions.ReferenceNotFoundError(str(mistral_exc)) raise mistral_exc result = jsonify.try_loads(execution.output) if execution.state in DONE_STATES else {} result['extra'] = { 'state': execution.state, 'state_info': execution.state_info } LOG.info( '[%s] Query returned status "%s" for mistral execution %s.', st2_exec_id, execution.state, mistral_exec_id ) return result
def _get_workflow_result(self, exec_id): """ Returns the workflow status and output. Mistral workflow status will be converted to st2 action status. :param exec_id: Mistral execution ID :type exec_id: ``str`` :rtype: (``str``, ``dict``) """ try: execution = self._client.executions.get(exec_id) except mistralclient_base.APIException as mistral_exc: if 'not found' in mistral_exc.message: raise exceptions.ReferenceNotFoundError(mistral_exc.message) raise mistral_exc params = json.loads(execution.params) result = jsonify.try_loads( execution.output) if execution.state in DONE_STATES else {} result['extra'] = { 'params': params, 'state': execution.state, 'state_info': execution.state_info } return result
def _schedule_execution(self, liveaction): # Initialize execution context if it does not exist. if not hasattr(liveaction, "context"): liveaction.context = dict() # Retrieve username of the authed user (note - if auth is disabled, user will not be # set so we fall back to the system user name) request_token = pecan.request.context.get("token", None) if request_token: user = request_token.user else: user = cfg.CONF.system_user.user liveaction.context["user"] = user LOG.debug("User is: %s" % 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. liveactiondb = LiveActionAPI.to_model(liveaction) _, actionexecutiondb = action_service.request(liveactiondb) from_model_kwargs = self._get_from_model_kwargs_for_request(request=pecan.request) return ActionExecutionAPI.from_model(actionexecutiondb, from_model_kwargs)
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 _get_workflow_result(self, exec_id): """ Returns the workflow status and output. Mistral workflow status will be converted to st2 action status. :param exec_id: Mistral execution ID :type exec_id: ``str`` :rtype: (``str``, ``dict``) """ execution = executions.ExecutionManager(self._client).get(exec_id) output = jsonify.try_loads(execution.output) if execution.state in DONE_STATES else None return (execution.state, output)
def _get_workflow_result(self, exec_id): """ Returns the workflow status and output. Mistral workflow status will be converted to st2 action status. :param exec_id: Mistral execution ID :type exec_id: ``str`` :rtype: (``str``, ``dict``) """ execution = executions.ExecutionManager(self._client).get(exec_id) if execution.state in DONE_STATES: return (DONE_STATES[execution.state], jsonify.try_loads(execution.output)) return (LIVEACTION_STATUS_RUNNING, None)
def _format_task_result(self, task): """ Format task result to follow the unified workflow result format. """ result = {} result['id'] = task['id'] result['name'] = task['name'] result['workflow_execution_id'] = task.get('workflow_execution_id', None) result['workflow_name'] = task['workflow_name'] result['created_at'] = task.get('created_at', None) result['updated_at'] = task.get('updated_at', None) result['state'] = task.get('state', None) for attr in ['result', 'input', 'published']: result[attr] = jsonify.try_loads(task.get(attr, None)) return result
def _get_workflow_result(self, exec_id): """ Returns the workflow status and output. Mistral workflow status will be converted to st2 action status. :param exec_id: Mistral execution ID :type exec_id: ``str`` :rtype: (``str``, ``dict``) """ execution = self._client.executions.get(exec_id) result = jsonify.try_loads(execution.output) if execution.state in DONE_STATES else {} result['extra'] = { 'state': execution.state, 'state_info': execution.state_info } return result
def _get_workflow_result(self, exec_id): """ Returns the workflow status and output. Mistral workflow status will be converted to st2 action status. :param exec_id: Mistral execution ID :type exec_id: ``str`` :rtype: (``str``, ``dict``) """ execution = self._client.executions.get(exec_id) result = jsonify.try_loads( execution.output) if execution.state in DONE_STATES else {} result['extra'] = { 'state': execution.state, 'state_info': execution.state_info } return result
def _get_workflow_tasks(self, exec_id): """ Returns the list of tasks for a workflow execution. :param exec_id: Mistral execution ID :type exec_id: ``str`` :rtype: ``list`` """ url = self._get_execution_tasks_url(exec_id) resp = requests.get(url) result = resp.json() tasks = result.get('tasks', []) for task in tasks: for attr in ['result', 'input', 'output']: task[attr] = jsonify.try_loads(task.get(attr, None)) return tasks
def post(self, execution): try: # Initialize execution context if it does not exist. if not hasattr(execution, 'context'): execution.context = dict() # Retrieve username of the authed user (note - if auth is disabled, user will not be # set so we fall back to the system user name) request_token = pecan.request.context.get('token', None) if request_token: user = request_token.user else: user = cfg.CONF.system_user.user execution.context['user'] = 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.' ) execution.context.update(context) # Schedule the action execution. liveactiondb = LiveActionAPI.to_model(execution) _, actionexecutiondb = action_service.schedule(liveactiondb) return ActionExecutionAPI.from_model(actionexecutiondb) except ValueError as e: LOG.exception('Unable to execute action.') abort(http_client.BAD_REQUEST, str(e)) except jsonschema.ValidationError as e: LOG.exception( 'Unable to execute action. Parameter validation failed.') abort(http_client.BAD_REQUEST, str(e)) except Exception as e: LOG.exception( 'Unable to execute action. Unexpected error encountered.') abort(http_client.INTERNAL_SERVER_ERROR, str(e))
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 _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): # Initialize execution context if it does not exist. if not hasattr(liveaction, 'context'): liveaction.context = dict() liveaction.context['user'] = self._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. liveactiondb = LiveActionAPI.to_model(liveaction) _, actionexecutiondb = action_service.request(liveactiondb) from_model_kwargs = self._get_from_model_kwargs_for_request(request=pecan.request) return ActionExecutionAPI.from_model(actionexecutiondb, from_model_kwargs)
def _get_workflow_result(self, exec_id): """ Returns the workflow status and output. Mistral workflow status will be converted to st2 action status. :param exec_id: Mistral execution ID :type exec_id: ``str`` :rtype: (``str``, ``dict``) """ url = self._get_execution_url(exec_id) resp = requests.get(url) execution = resp.json() workflow_state = execution.get('state', None) if not workflow_state: raise Exception('Workflow status unknown for mistral execution id %s. %s' % (exec_id, execution)) if workflow_state in DONE_STATES: workflow_output = jsonify.try_loads(execution.get('output', {})) return (DONE_STATES[workflow_state], workflow_output) return (LIVEACTION_STATUS_RUNNING, None)
def post(self, execution): try: # Initialize execution context if it does not exist. if not hasattr(execution, 'context'): execution.context = dict() # Retrieve username of the authed user (note - if auth is disabled, user will not be # set so we fall back to the system user name) request_token = pecan.request.context.get('token', None) if request_token: user = request_token.user else: user = cfg.CONF.system_user.user execution.context['user'] = 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.') execution.context.update(context) # Schedule the action execution. liveactiondb = LiveActionAPI.to_model(execution) _, actionexecutiondb = action_service.schedule(liveactiondb) return ActionExecutionAPI.from_model(actionexecutiondb) except ValueError as e: LOG.exception('Unable to execute action.') abort(http_client.BAD_REQUEST, str(e)) except jsonschema.ValidationError as e: LOG.exception('Unable to execute action. Parameter validation failed.') abort(http_client.BAD_REQUEST, str(e)) except Exception as e: LOG.exception('Unable to execute action. Unexpected error encountered.') abort(http_client.INTERNAL_SERVER_ERROR, str(e))
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 _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 _do_run(self, runner): # Create a temporary auth token which will be available # for the duration of the action execution. runner.auth_token = self._create_auth_token( context=runner.context, action_db=runner.action, liveaction_db=runner.liveaction) try: # Finalized parameters are resolved and then rendered. This process could # fail. Handle the exception and report the error correctly. try: runner_params, action_params = param_utils.render_final_params( runner.runner_type.runner_parameters, runner.action.parameters, runner.liveaction.parameters, runner.liveaction.context) runner.runner_parameters = runner_params except ParamException as e: raise actionrunner.ActionRunnerException(six.text_type(e)) LOG.debug('Performing pre-run for runner: %s', runner.runner_id) runner.pre_run() # Mask secret parameters in the log context resolved_action_params = ResolvedActionParameters( action_db=runner.action, runner_type_db=runner.runner_type, runner_parameters=runner_params, action_parameters=action_params) extra = {'runner': runner, 'parameters': resolved_action_params} LOG.debug('Performing run for runner: %s' % (runner.runner_id), extra=extra) with CounterWithTimer(key='action.executions'): with CounterWithTimer(key='action.%s.executions' % (runner.action.ref)): (status, result, context) = runner.run(action_params) result = jsonify.try_loads(result) action_completed = status in action_constants.LIVEACTION_COMPLETED_STATES if (isinstance(runner, PollingAsyncActionRunner) and runner.is_polling_enabled() and not action_completed): queries.setup_query(runner.liveaction.id, runner.runner_type, context) except: LOG.exception('Failed to run action.') _, ex, tb = sys.exc_info() # mark execution as failed. status = action_constants.LIVEACTION_STATUS_FAILED # include the error message and traceback to try and provide some hints. result = {'error': str(ex), 'traceback': ''.join(traceback.format_tb(tb, 20))} context = None finally: # Log action completion extra = {'result': result, 'status': status} LOG.debug('Action "%s" completed.' % (runner.action.name), extra=extra) # Update the final status of liveaction and corresponding action execution. runner.liveaction = self._update_status(runner.liveaction.id, status, result, context) # Always clean-up the auth_token # This method should be called in the finally block to ensure post_run is not impacted. self._clean_up_auth_token(runner=runner, status=status) LOG.debug('Performing post_run for runner: %s', runner.runner_id) runner.post_run(status=status, result=result) LOG.debug('Runner do_run result', extra={'result': runner.liveaction.result}) LOG.audit('Liveaction completed', extra={'liveaction_db': runner.liveaction}) return runner.liveaction