class ActionExecutionsController(ResourceController): """ Implements the RESTful web endpoint that handles the lifecycle of ActionExecutions in the system. """ model = ActionExecutionAPI access = ActionExecution views = ExecutionViewsController() query_options = {'sort': ['-start_timestamp', 'action']} supported_filters = { 'timestamp_gt': 'start_timestamp.gt', 'timestamp_lt': 'start_timestamp.lt' } filter_transform_functions = { 'timestamp_gt': lambda value: isotime.parse(value=value), 'timestamp_lt': lambda value: isotime.parse(value=value) } def __init__(self): super(ActionExecutionsController, self).__init__() # Add common execution view supported filters self.supported_filters.update(SUPPORTED_FILTERS) @jsexpose(str) def get_one(self, id, *args, **kwargs): if args or kwargs: if args[0] == 'children': return self._get_children(id, **kwargs) else: msg = 'Unsupported id : %s, args: %s, kwargs: %s' % (id, args, kwargs) abort(http_client.BAD_REQUEST, msg) else: return super(ActionExecutionsController, self)._get_one(id) @jsexpose() def get_all(self, **kw): """ List all actionexecutions. Handles requests: GET /actionexecutions/ """ LOG.info('GET all /actionexecutions/ with filters=%s', kw) return self._get_action_executions(**kw) @jsexpose(body=LiveActionAPI, status_code=http_client.CREATED) def post(self, execution): try: # Initialize execution context if it does not exist. if not hasattr(execution, 'context'): execution.context = dict() # Retrieve user context from the request header. user = pecan.request.headers.get('X-User-Name') if not user: 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)) @jsexpose() def options(self, *args, **kw): return def _get_action_executions(self, **kw): kw['limit'] = int(kw.get('limit', 100)) LOG.debug('Retrieving all action liveactions with filters=%s', kw) return super(ActionExecutionsController, self)._get_all(**kw) def _get_children(self, id_, depth=-1): # make sure depth is int. Url encoding will make it a string and needs to # be converted back in that case. depth = int(depth) LOG.debug('retrieving children for id: %s with depth: %s', id_, depth) descendants = execution_service.get_descendants(actionexecution_id=id_, descendant_depth=depth) return [ self.model.from_model(descendant) for descendant in descendants ]
class ActionExecutionsController(ActionExecutionsControllerMixin, ResourceController): """ Implements the RESTful web endpoint that handles the lifecycle of ActionExecutions in the system. """ # Nested controllers views = ExecutionViewsController() children = ActionExecutionChildrenController() attribute = ActionExecutionAttributeController() re_run = ActionExecutionReRunController() # ResourceController attributes query_options = { 'sort': ['-start_timestamp', 'action.ref'] } supported_filters = SUPPORTED_EXECUTIONS_FILTERS filter_transform_functions = { 'timestamp_gt': lambda value: isotime.parse(value=value), 'timestamp_lt': lambda value: isotime.parse(value=value) } @request_user_has_permission(permission_type=PermissionType.EXECUTION_LIST) @jsexpose() def get_all(self, exclude_attributes=None, **kw): """ List all executions. Handles requests: GET /executions[?exclude_attributes=result,trigger_instance] :param exclude_attributes: Comma delimited string of attributes to exclude from the object. :type exclude_attributes: ``str`` """ if exclude_attributes: exclude_fields = exclude_attributes.split(',') else: exclude_fields = None exclude_fields = self._validate_exclude_fields(exclude_fields=exclude_fields) # Use a custom sort order when filtering on a timestamp so we return a correct result as # expected by the user if 'timestamp_lt' in kw or 'sort_desc' in kw: query_options = {'sort': ['-start_timestamp', 'action.ref']} kw['query_options'] = query_options elif 'timestamp_gt' in kw or 'sort_asc' in kw: query_options = {'sort': ['+start_timestamp', 'action.ref']} kw['query_options'] = query_options return self._get_action_executions(exclude_fields=exclude_fields, **kw) @request_user_has_resource_db_permission(permission_type=PermissionType.EXECUTION_VIEW) @jsexpose(arg_types=[str]) def get_one(self, id, exclude_attributes=None, **kwargs): """ Retrieve a single execution. Handles requests: GET /executions/<id>[?exclude_attributes=result,trigger_instance] :param exclude_attributes: Comma delimited string of attributes to exclude from the object. :type exclude_attributes: ``str`` """ if exclude_attributes: exclude_fields = exclude_attributes.split(',') else: exclude_fields = None exclude_fields = self._validate_exclude_fields(exclude_fields=exclude_fields) return self._get_one(id=id, exclude_fields=exclude_fields) @jsexpose(body_cls=LiveActionCreateAPI, status_code=http_client.CREATED) def post(self, liveaction_api): return self._handle_schedule_execution(liveaction_api=liveaction_api) @request_user_has_resource_db_permission(permission_type=PermissionType.EXECUTION_STOP) @jsexpose(arg_types=[str]) def delete(self, exec_id): """ Stops a single execution. Handles requests: DELETE /executions/<id> """ execution_api = self._get_one(id=exec_id) if not execution_api: abort(http_client.NOT_FOUND, 'Execution with id %s not found.' % exec_id) liveaction_id = execution_api.liveaction['id'] if not liveaction_id: abort(http_client.INTERNAL_SERVER_ERROR, 'Execution object missing link to liveaction %s.' % liveaction_id) try: liveaction_db = LiveAction.get_by_id(liveaction_id) except: abort(http_client.INTERNAL_SERVER_ERROR, 'Execution object missing link to liveaction %s.' % liveaction_id) if liveaction_db.status == LIVEACTION_STATUS_CANCELED: abort(http_client.OK, 'Action is already in "canceled" state.') if liveaction_db.status not in LIVEACTION_CANCELABLE_STATES: abort(http_client.OK, 'Action cannot be canceled. State = %s.' % liveaction_db.status) try: (liveaction_db, execution_db) = action_service.request_cancellation( liveaction_db, get_requester()) except: LOG.exception('Failed requesting cancellation for liveaction %s.', liveaction_db.id) abort(http_client.INTERNAL_SERVER_ERROR, 'Failed canceling execution.') from_model_kwargs = self._get_from_model_kwargs_for_request(request=pecan.request) return ActionExecutionAPI.from_model(execution_db, from_model_kwargs) @jsexpose() def options(self, *args, **kw): return def _get_action_executions(self, exclude_fields=None, **kw): """ :param exclude_fields: A list of object fields to exclude. :type exclude_fields: ``list`` """ kw['limit'] = int(kw.get('limit', self.default_limit)) LOG.debug('Retrieving all action executions with filters=%s', kw) return super(ActionExecutionsController, self)._get_all(exclude_fields=exclude_fields, **kw)
class ActionExecutionsController(ActionExecutionsControllerMixin, ResourceController): """ Implements the RESTful web endpoint that handles the lifecycle of ActionExecutions in the system. """ # Nested controllers views = ExecutionViewsController() children = ActionExecutionChildrenController() attribute = ActionExecutionAttributeController() re_run = ActionExecutionReRunController() # ResourceController attributes query_options = {'sort': ['-start_timestamp', 'action.ref']} supported_filters = SUPPORTED_EXECUTIONS_FILTERS filter_transform_functions = { 'timestamp_gt': lambda value: isotime.parse(value=value), 'timestamp_lt': lambda value: isotime.parse(value=value) } @jsexpose() def get_all(self, exclude_attributes=None, **kw): """ List all actionexecutions. Handles requests: GET /actionexecutions[?exclude_attributes=result,trigger_instance] :param exclude_attributes: Comma delimited string of attributes to exclude from the object. :type exclude_attributes: ``str`` """ if exclude_attributes: exclude_fields = exclude_attributes.split(',') else: exclude_fields = None exclude_fields = self._validate_exclude_fields( exclude_fields=exclude_fields) return self._get_action_executions(exclude_fields=exclude_fields, **kw) @jsexpose(arg_types=[str]) def get_one(self, id, exclude_attributes=None, **kwargs): """ Retrieve a single execution. Handles requests: GET /actionexecutions/<id>[?exclude_attributes=result,trigger_instance] :param exclude_attributes: Comma delimited string of attributes to exclude from the object. :type exclude_attributes: ``str`` """ if exclude_attributes: exclude_fields = exclude_attributes.split(',') else: exclude_fields = None exclude_fields = self._validate_exclude_fields( exclude_fields=exclude_fields) return self._get_one(id=id, exclude_fields=exclude_fields) @jsexpose(body_cls=LiveActionAPI, status_code=http_client.CREATED) def post(self, liveaction): return self._handle_schedule_execution(liveaction=liveaction) @jsexpose(arg_types=[str]) def delete(self, exec_id): """ Stops a single execution. Handles requests: DELETE /actionexecutions/<id> """ execution_api = self._get_one(id=exec_id) if not execution_api: abort(http_client.NOT_FOUND, 'Execution with id %s not found.' % exec_id) return liveaction_id = execution_api.liveaction['id'] if not liveaction_id: abort( http_client.INTERNAL_SERVER_ERROR, 'Execution object missing link to liveaction %s.' % liveaction_id) try: liveaction_db = LiveAction.get_by_id(liveaction_id) except: abort( http_client.INTERNAL_SERVER_ERROR, 'Execution object missing link to liveaction %s.' % liveaction_id) return if liveaction_db.status == LIVEACTION_STATUS_CANCELED: abort(http_client.OK, 'Action is already in "canceled" state.') if liveaction_db.status not in CANCELABLE_STATES: abort( http_client.OK, 'Action cannot be canceled. State = %s.' % liveaction_db.status) return liveaction_db.status = 'canceled' liveaction_db.end_timestamp = date_utils.get_datetime_utc_now() liveaction_db.result = {'message': 'Action canceled by user.'} try: LiveAction.add_or_update(liveaction_db) except: LOG.exception( 'Failed updating status to canceled for liveaction %s.', liveaction_db.id) abort(http_client.INTERNAL_SERVER_ERROR, 'Failed canceling execution.') return execution_db = execution_service.update_execution(liveaction_db) from_model_kwargs = self._get_from_model_kwargs_for_request( request=pecan.request) return ActionExecutionAPI.from_model(execution_db, from_model_kwargs) @jsexpose() def options(self, *args, **kw): return def _get_action_executions(self, exclude_fields=None, **kw): """ :param exclude_fields: A list of object fields to exclude. :type exclude_fields: ``list`` """ kw['limit'] = int(kw.get('limit', 100)) LOG.debug('Retrieving all action executions with filters=%s', kw) return super(ActionExecutionsController, self)._get_all(exclude_fields=exclude_fields, **kw)
class ActionExecutionsController(ActionExecutionsControllerMixin, ResourceController): """ Implements the RESTful web endpoint that handles the lifecycle of ActionExecutions in the system. """ # Nested controllers views = ExecutionViewsController() children = ActionExecutionChildrenController() attribute = ActionExecutionAttributeController() re_run = ActionExecutionReRunController() # ResourceController attributes query_options = {'sort': ['-start_timestamp', 'action.ref']} supported_filters = SUPPORTED_EXECUTIONS_FILTERS filter_transform_functions = { 'timestamp_gt': lambda value: isotime.parse(value=value), 'timestamp_lt': lambda value: isotime.parse(value=value) } def get_all(self, requester_user, exclude_attributes=None, sort=None, offset=0, limit=None, show_secrets=False, include_attributes=None, advanced_filters=None, **raw_filters): """ List all executions. Handles requests: GET /executions[?exclude_attributes=result,trigger_instance] :param exclude_attributes: List of attributes to exclude from the object. :type exclude_attributes: ``list`` """ exclude_fields = self._validate_exclude_fields( exclude_fields=exclude_attributes) # Use a custom sort order when filtering on a timestamp so we return a correct result as # expected by the user query_options = None if raw_filters.get('timestamp_lt', None) or raw_filters.get( 'sort_desc', None): query_options = {'sort': ['-start_timestamp', 'action.ref']} elif raw_filters.get('timestamp_gt', None) or raw_filters.get( 'sort_asc', None): query_options = {'sort': ['+start_timestamp', 'action.ref']} from_model_kwargs = { 'mask_secrets': self._get_mask_secrets(requester_user, show_secrets=show_secrets) } return self._get_action_executions(exclude_fields=exclude_fields, include_fields=include_attributes, from_model_kwargs=from_model_kwargs, sort=sort, offset=offset, limit=limit, query_options=query_options, raw_filters=raw_filters, advanced_filters=advanced_filters, requester_user=requester_user) def get_one(self, id, requester_user, exclude_attributes=None, show_secrets=False): """ Retrieve a single execution. Handles requests: GET /executions/<id>[?exclude_attributes=result,trigger_instance] :param exclude_attributes: List of attributes to exclude from the object. :type exclude_attributes: ``list`` """ exclude_fields = self._validate_exclude_fields( exclude_fields=exclude_attributes) from_model_kwargs = { 'mask_secrets': self._get_mask_secrets(requester_user, show_secrets=show_secrets) } # Special case for id == "last" if id == 'last': execution_db = ActionExecution.query().order_by('-id').limit( 1).only('id').first() id = str(execution_db.id) return self._get_one_by_id( id=id, exclude_fields=exclude_fields, requester_user=requester_user, from_model_kwargs=from_model_kwargs, permission_type=PermissionType.EXECUTION_VIEW) def post(self, liveaction_api, requester_user, context_string=None, show_secrets=False): return self._handle_schedule_execution(liveaction_api=liveaction_api, requester_user=requester_user, context_string=context_string, show_secrets=show_secrets) def put(self, id, liveaction_api, requester_user, show_secrets=False): """ Updates a single execution. Handles requests: PUT /executions/<id> """ if not requester_user: requester_user = UserDB(cfg.CONF.system_user.user) from_model_kwargs = { 'mask_secrets': self._get_mask_secrets(requester_user, show_secrets=show_secrets) } execution_api = self._get_one_by_id( id=id, requester_user=requester_user, from_model_kwargs=from_model_kwargs, permission_type=PermissionType.EXECUTION_STOP) if not execution_api: abort(http_client.NOT_FOUND, 'Execution with id %s not found.' % id) liveaction_id = execution_api.liveaction['id'] if not liveaction_id: abort( http_client.INTERNAL_SERVER_ERROR, 'Execution object missing link to liveaction %s.' % liveaction_id) try: liveaction_db = LiveAction.get_by_id(liveaction_id) except: abort( http_client.INTERNAL_SERVER_ERROR, 'Execution object missing link to liveaction %s.' % liveaction_id) if liveaction_db.status in action_constants.LIVEACTION_COMPLETED_STATES: abort(http_client.BAD_REQUEST, 'Execution is already in completed state.') def update_status(liveaction_api, liveaction_db): status = liveaction_api.status result = getattr(liveaction_api, 'result', None) liveaction_db = action_service.update_status( liveaction_db, status, result) actionexecution_db = ActionExecution.get( liveaction__id=str(liveaction_db.id)) return (liveaction_db, actionexecution_db) try: if (liveaction_db.status == action_constants.LIVEACTION_STATUS_CANCELING and liveaction_api.status == action_constants.LIVEACTION_STATUS_CANCELED): if action_service.is_children_active(liveaction_id): liveaction_api.status = action_constants.LIVEACTION_STATUS_CANCELING liveaction_db, actionexecution_db = update_status( liveaction_api, liveaction_db) elif (liveaction_api.status == action_constants.LIVEACTION_STATUS_CANCELING or liveaction_api.status == action_constants.LIVEACTION_STATUS_CANCELED): liveaction_db, actionexecution_db = action_service.request_cancellation( liveaction_db, requester_user.name or cfg.CONF.system_user.user) elif (liveaction_db.status == action_constants.LIVEACTION_STATUS_PAUSING and liveaction_api.status == action_constants.LIVEACTION_STATUS_PAUSED): if action_service.is_children_active(liveaction_id): liveaction_api.status = action_constants.LIVEACTION_STATUS_PAUSING liveaction_db, actionexecution_db = update_status( liveaction_api, liveaction_db) elif (liveaction_api.status == action_constants.LIVEACTION_STATUS_PAUSING or liveaction_api.status == action_constants.LIVEACTION_STATUS_PAUSED): liveaction_db, actionexecution_db = action_service.request_pause( liveaction_db, requester_user.name or cfg.CONF.system_user.user) elif liveaction_api.status == action_constants.LIVEACTION_STATUS_RESUMING: liveaction_db, actionexecution_db = action_service.request_resume( liveaction_db, requester_user.name or cfg.CONF.system_user.user) else: liveaction_db, actionexecution_db = update_status( liveaction_api, liveaction_db) except runner_exc.InvalidActionRunnerOperationError as e: LOG.exception('Failed updating liveaction %s. %s', liveaction_db.id, str(e)) abort(http_client.BAD_REQUEST, 'Failed updating execution. %s' % str(e)) except runner_exc.UnexpectedActionExecutionStatusError as e: LOG.exception('Failed updating liveaction %s. %s', liveaction_db.id, str(e)) abort(http_client.BAD_REQUEST, 'Failed updating execution. %s' % str(e)) except Exception as e: LOG.exception('Failed updating liveaction %s. %s', liveaction_db.id, str(e)) abort(http_client.INTERNAL_SERVER_ERROR, 'Failed updating execution due to unexpected error.') mask_secrets = self._get_mask_secrets(requester_user, show_secrets=show_secrets) execution_api = ActionExecutionAPI.from_model( actionexecution_db, mask_secrets=mask_secrets) return execution_api def delete(self, id, requester_user, show_secrets=False): """ Stops a single execution. Handles requests: DELETE /executions/<id> """ if not requester_user: requester_user = UserDB(cfg.CONF.system_user.user) from_model_kwargs = { 'mask_secrets': self._get_mask_secrets(requester_user, show_secrets=show_secrets) } execution_api = self._get_one_by_id( id=id, requester_user=requester_user, from_model_kwargs=from_model_kwargs, permission_type=PermissionType.EXECUTION_STOP) if not execution_api: abort(http_client.NOT_FOUND, 'Execution with id %s not found.' % id) liveaction_id = execution_api.liveaction['id'] if not liveaction_id: abort( http_client.INTERNAL_SERVER_ERROR, 'Execution object missing link to liveaction %s.' % liveaction_id) try: liveaction_db = LiveAction.get_by_id(liveaction_id) except: abort( http_client.INTERNAL_SERVER_ERROR, 'Execution object missing link to liveaction %s.' % liveaction_id) if liveaction_db.status == action_constants.LIVEACTION_STATUS_CANCELED: LOG.info('Action %s already in "canceled" state; \ returning execution object.' % liveaction_db.id) return execution_api if liveaction_db.status not in action_constants.LIVEACTION_CANCELABLE_STATES: abort( http_client.OK, 'Action cannot be canceled. State = %s.' % liveaction_db.status) try: (liveaction_db, execution_db) = action_service.request_cancellation( liveaction_db, requester_user.name or cfg.CONF.system_user.user) except: LOG.exception('Failed requesting cancellation for liveaction %s.', liveaction_db.id) abort(http_client.INTERNAL_SERVER_ERROR, 'Failed canceling execution.') return ActionExecutionAPI.from_model( execution_db, mask_secrets=from_model_kwargs['mask_secrets']) def _get_action_executions(self, exclude_fields=None, include_fields=None, sort=None, offset=0, limit=None, advanced_filters=None, query_options=None, raw_filters=None, from_model_kwargs=None, requester_user=None): """ :param exclude_fields: A list of object fields to exclude. :type exclude_fields: ``list`` """ if limit is None: limit = self.default_limit limit = int(limit) LOG.debug('Retrieving all action executions with filters=%s', raw_filters) return super(ActionExecutionsController, self)._get_all(exclude_fields=exclude_fields, include_fields=include_fields, from_model_kwargs=from_model_kwargs, sort=sort, offset=offset, limit=limit, query_options=query_options, raw_filters=raw_filters, advanced_filters=advanced_filters, requester_user=requester_user)
class ActionExecutionsController(ActionExecutionsControllerMixin, ResourceController): """ Implements the RESTful web endpoint that handles the lifecycle of ActionExecutions in the system. """ # Nested controllers views = ExecutionViewsController() children = ActionExecutionChildrenController() attribute = ActionExecutionAttributeController() re_run = ActionExecutionReRunController() # ResourceController attributes query_options = {'sort': ['-start_timestamp', 'action.ref']} supported_filters = SUPPORTED_EXECUTIONS_FILTERS filter_transform_functions = { 'timestamp_gt': lambda value: isotime.parse(value=value), 'timestamp_lt': lambda value: isotime.parse(value=value) } def get_all(self, exclude_attributes=None, sort=None, offset=0, limit=None, **raw_filters): """ List all executions. Handles requests: GET /executions[?exclude_attributes=result,trigger_instance] :param exclude_attributes: Comma delimited string of attributes to exclude from the object. :type exclude_attributes: ``str`` """ if exclude_attributes: exclude_fields = exclude_attributes.split(',') else: exclude_fields = None exclude_fields = self._validate_exclude_fields( exclude_fields=exclude_fields) # Use a custom sort order when filtering on a timestamp so we return a correct result as # expected by the user query_options = None if raw_filters.get('timestamp_lt', None) or raw_filters.get( 'sort_desc', None): query_options = {'sort': ['-start_timestamp', 'action.ref']} elif raw_filters.get('timestamp_gt', None) or raw_filters.get( 'sort_asc', None): query_options = {'sort': ['+start_timestamp', 'action.ref']} return self._get_action_executions(exclude_fields=exclude_fields, sort=sort, offset=offset, limit=limit, query_options=query_options, raw_filters=raw_filters) def get_one(self, id, requester_user, exclude_attributes=None): """ Retrieve a single execution. Handles requests: GET /executions/<id>[?exclude_attributes=result,trigger_instance] :param exclude_attributes: Comma delimited string of attributes to exclude from the object. :type exclude_attributes: ``str`` """ if exclude_attributes: exclude_fields = exclude_attributes.split(',') else: exclude_fields = None exclude_fields = self._validate_exclude_fields( exclude_fields=exclude_fields) return self._get_one_by_id( id=id, exclude_fields=exclude_fields, requester_user=requester_user, permission_type=PermissionType.EXECUTION_VIEW) def post(self, liveaction_api, requester_user=None, context_string=None, show_secrets=False): return self._handle_schedule_execution(liveaction_api=liveaction_api, requester_user=requester_user, context_string=context_string, show_secrets=show_secrets) def delete(self, id, requester_user, show_secrets=False): """ Stops a single execution. Handles requests: DELETE /executions/<id> """ if not requester_user: requester_user = UserDB(cfg.CONF.system_user.user) execution_api = self._get_one_by_id( id=id, requester_user=requester_user, permission_type=PermissionType.EXECUTION_STOP) if not execution_api: abort(http_client.NOT_FOUND, 'Execution with id %s not found.' % id) liveaction_id = execution_api.liveaction['id'] if not liveaction_id: abort( http_client.INTERNAL_SERVER_ERROR, 'Execution object missing link to liveaction %s.' % liveaction_id) try: liveaction_db = LiveAction.get_by_id(liveaction_id) except: abort( http_client.INTERNAL_SERVER_ERROR, 'Execution object missing link to liveaction %s.' % liveaction_id) if liveaction_db.status == LIVEACTION_STATUS_CANCELED: LOG.info('Action %s already in "canceled" state; \ returning execution object.' % liveaction_db.id) return execution_api if liveaction_db.status not in LIVEACTION_CANCELABLE_STATES: abort( http_client.OK, 'Action cannot be canceled. State = %s.' % liveaction_db.status) try: (liveaction_db, execution_db) = action_service.request_cancellation( liveaction_db, requester_user.name or cfg.CONF.system_user.user) except: LOG.exception('Failed requesting cancellation for liveaction %s.', liveaction_db.id) abort(http_client.INTERNAL_SERVER_ERROR, 'Failed canceling execution.') return ActionExecutionAPI.from_model(execution_db, mask_secrets=(not show_secrets)) def _get_action_executions(self, exclude_fields=None, sort=None, offset=0, limit=None, query_options=None, raw_filters=None): """ :param exclude_fields: A list of object fields to exclude. :type exclude_fields: ``list`` """ if limit is None: limit = self.default_limit limit = int(limit) LOG.debug('Retrieving all action executions with filters=%s', raw_filters) return super(ActionExecutionsController, self)._get_all(exclude_fields=exclude_fields, sort=sort, offset=offset, limit=limit, query_options=query_options, raw_filters=raw_filters)
class ActionExecutionsController(ActionExecutionsControllerMixin, ResourceController): """ Implements the RESTful web endpoint that handles the lifecycle of ActionExecutions in the system. """ # Nested controllers views = ExecutionViewsController() children = ActionExecutionChildrenController() attribute = ActionExecutionAttributeController() query_options = {'sort': ['-start_timestamp', 'action']} supported_filters = { 'timestamp_gt': 'start_timestamp.gt', 'timestamp_lt': 'start_timestamp.lt' } filter_transform_functions = { 'timestamp_gt': lambda value: isotime.parse(value=value), 'timestamp_lt': lambda value: isotime.parse(value=value) } def __init__(self): super(ActionExecutionsController, self).__init__() # Add common execution view supported filters self.supported_filters.update(SUPPORTED_FILTERS) @jsexpose() def get_all(self, exclude_attributes=None, **kw): """ List all actionexecutions. Handles requests: GET /actionexecutions/[?exclude_attributes=result,trigger_instance] :param exclude_attributes: Comma delimited string of attributes to exclude from the object. :type exclude_attributes: ``str`` """ if exclude_attributes: exclude_fields = exclude_attributes.split(',') else: exclude_fields = None exclude_fields = self._validate_exclude_fields( exclude_fields=exclude_fields) return self._get_action_executions(exclude_fields=exclude_fields, **kw) @jsexpose(arg_types=[str]) def get_one(self, id, exclude_attributes=None, **kwargs): """ Retrieve a single execution. Handles requests: GET /actionexecutions/<id>[?exclude_attributes=result,trigger_instance] :param exclude_attributes: Comma delimited string of attributes to exclude from the object. :type exclude_attributes: ``str`` """ if exclude_attributes: exclude_fields = exclude_attributes.split(',') else: exclude_fields = None exclude_fields = self._validate_exclude_fields( exclude_fields=exclude_fields) return self._get_one(id=id, exclude_fields=exclude_fields) @jsexpose(body_cls=LiveActionAPI, status_code=http_client.CREATED) 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)) @jsexpose(arg_types=[str]) def delete(self, exec_id): """ Stops a single execution. Handles requests: DELETE /actionexecutions/<id> """ execution_api = self._get_one(id=exec_id) if not execution_api: abort(http_client.NOT_FOUND, 'Execution with id %s not found.' % exec_id) return liveaction_id = execution_api.liveaction['id'] if not liveaction_id: abort( http_client.INTERNAL_SERVER_ERROR, 'Execution object missing link to liveaction %s.' % liveaction_id) try: liveaction_db = LiveAction.get_by_id(liveaction_id) except: abort( http_client.INTERNAL_SERVER_ERROR, 'Execution object missing link to liveaction %s.' % liveaction_id) return if liveaction_db.status == LIVEACTION_STATUS_CANCELED: abort(http_client.OK, 'Action is already in "canceled" state.') if liveaction_db.status not in CANCELABLE_STATES: abort( http_client.OK, 'Action cannot be canceled. State = %s.' % liveaction_db.status) return liveaction_db.status = 'canceled' liveaction_db.end_timestamp = isotime.add_utc_tz( datetime.datetime.utcnow()) liveaction_db.result = {'message': 'Action canceled by user.'} try: LiveAction.add_or_update(liveaction_db) except: LOG.exception( 'Failed updating status to canceled for liveaction %s.', liveaction_db.id) abort(http_client.INTERNAL_SERVER_ERROR, 'Failed canceling execution.') return execution_db = execution_service.update_execution(liveaction_db) return ActionExecutionAPI.from_model(execution_db) @jsexpose() def options(self, *args, **kw): return def _get_action_executions(self, exclude_fields=None, **kw): """ :param exclude_fields: A list of object fields to exclude. :type exclude_fields: ``list`` """ kw['limit'] = int(kw.get('limit', 100)) LOG.debug('Retrieving all action liveactions with filters=%s', kw) return super(ActionExecutionsController, self)._get_all(exclude_fields=exclude_fields, **kw)