def test_crud_partial(self): # Create the DB record. obj = ActionExecutionAPI( **copy.deepcopy(self.fake_history_subtasks[0])) ActionExecution.add_or_update(ActionExecutionAPI.to_model(obj)) model = ActionExecution.get_by_id(obj.id) self.assertEqual(str(model.id), obj.id) self.assertDictEqual(model.trigger, {}) self.assertDictEqual(model.trigger_type, {}) self.assertDictEqual(model.trigger_instance, {}) self.assertDictEqual(model.rule, {}) self.assertDictEqual(model.action, self.fake_history_subtasks[0]['action']) self.assertDictEqual(model.runner, self.fake_history_subtasks[0]['runner']) doc = copy.deepcopy(self.fake_history_subtasks[0]['liveaction']) doc['start_timestamp'] = doc['start_timestamp'] doc['end_timestamp'] = doc['end_timestamp'] self.assertDictEqual(model.liveaction, doc) self.assertEqual(model.parent, self.fake_history_subtasks[0]['parent']) self.assertListEqual(model.children, []) # Update the DB record. children = [str(bson.ObjectId()), str(bson.ObjectId())] model.children = children ActionExecution.add_or_update(model) model = ActionExecution.get_by_id(obj.id) self.assertListEqual(model.children, children) # Delete the DB record. ActionExecution.delete(model) self.assertRaises(StackStormDBObjectNotFoundError, ActionExecution.get_by_id, obj.id)
def test_crud_complete(self): # Create the DB record. obj = ActionExecutionAPI(**copy.deepcopy(self.fake_history_workflow)) ActionExecution.add_or_update(ActionExecutionAPI.to_model(obj)) model = ActionExecution.get_by_id(obj.id) self.assertEqual(str(model.id), obj.id) self.assertDictEqual(model.trigger, self.fake_history_workflow['trigger']) self.assertDictEqual(model.trigger_type, self.fake_history_workflow['trigger_type']) self.assertDictEqual(model.trigger_instance, self.fake_history_workflow['trigger_instance']) self.assertDictEqual(model.rule, self.fake_history_workflow['rule']) self.assertDictEqual(model.action, self.fake_history_workflow['action']) self.assertDictEqual(model.runner, self.fake_history_workflow['runner']) doc = copy.deepcopy(self.fake_history_workflow['liveaction']) doc['start_timestamp'] = doc['start_timestamp'] doc['end_timestamp'] = doc['end_timestamp'] self.assertDictEqual(model.liveaction, doc) self.assertIsNone(getattr(model, 'parent', None)) self.assertListEqual(model.children, self.fake_history_workflow['children']) # Update the DB record. children = [str(bson.ObjectId()), str(bson.ObjectId())] model.children = children ActionExecution.add_or_update(model) model = ActionExecution.get_by_id(obj.id) self.assertListEqual(model.children, children) # Delete the DB record. ActionExecution.delete(model) self.assertRaises(ValueError, ActionExecution.get_by_id, obj.id)
def test_model_complete(self): # Create API object. obj = ActionExecutionAPI(**copy.deepcopy(self.fake_history_workflow)) self.assertDictEqual(obj.trigger, self.fake_history_workflow['trigger']) self.assertDictEqual(obj.trigger_type, self.fake_history_workflow['trigger_type']) self.assertDictEqual(obj.trigger_instance, self.fake_history_workflow['trigger_instance']) self.assertDictEqual(obj.rule, self.fake_history_workflow['rule']) self.assertDictEqual(obj.action, self.fake_history_workflow['action']) self.assertDictEqual(obj.runner, self.fake_history_workflow['runner']) self.assertEquals(obj.liveaction, self.fake_history_workflow['liveaction']) self.assertIsNone(getattr(obj, 'parent', None)) self.assertListEqual(obj.children, self.fake_history_workflow['children']) # Convert API object to DB model. model = ActionExecutionAPI.to_model(obj) self.assertEqual(str(model.id), obj.id) self.assertDictEqual(model.trigger, self.fake_history_workflow['trigger']) self.assertDictEqual(model.trigger_type, self.fake_history_workflow['trigger_type']) self.assertDictEqual(model.trigger_instance, self.fake_history_workflow['trigger_instance']) self.assertDictEqual(model.rule, self.fake_history_workflow['rule']) self.assertDictEqual(model.action, self.fake_history_workflow['action']) self.assertDictEqual(model.runner, self.fake_history_workflow['runner']) doc = copy.deepcopy(self.fake_history_workflow['liveaction']) doc['start_timestamp'] = doc['start_timestamp'] doc['end_timestamp'] = doc['end_timestamp'] self.assertDictEqual(model.liveaction, doc) self.assertIsNone(getattr(model, 'parent', None)) self.assertListEqual(model.children, self.fake_history_workflow['children']) # Convert DB model to API object. obj = ActionExecutionAPI.from_model(model) self.assertEqual(str(model.id), obj.id) self.assertDictEqual(obj.trigger, self.fake_history_workflow['trigger']) self.assertDictEqual(obj.trigger_type, self.fake_history_workflow['trigger_type']) self.assertDictEqual(obj.trigger_instance, self.fake_history_workflow['trigger_instance']) self.assertDictEqual(obj.rule, self.fake_history_workflow['rule']) self.assertDictEqual(obj.action, self.fake_history_workflow['action']) self.assertDictEqual(obj.runner, self.fake_history_workflow['runner']) self.assertDictEqual(obj.liveaction, self.fake_history_workflow['liveaction']) self.assertIsNone(getattr(obj, 'parent', None)) self.assertListEqual(obj.children, self.fake_history_workflow['children'])
def test_model_complete(self): # Create API object. obj = ActionExecutionAPI(**copy.deepcopy(self.fake_history_workflow)) self.assertDictEqual(obj.trigger, self.fake_history_workflow["trigger"]) self.assertDictEqual(obj.trigger_type, self.fake_history_workflow["trigger_type"]) self.assertDictEqual(obj.trigger_instance, self.fake_history_workflow["trigger_instance"]) self.assertDictEqual(obj.rule, self.fake_history_workflow["rule"]) self.assertDictEqual(obj.action, self.fake_history_workflow["action"]) self.assertDictEqual(obj.runner, self.fake_history_workflow["runner"]) self.assertEqual(obj.liveaction, self.fake_history_workflow["liveaction"]) self.assertIsNone(getattr(obj, "parent", None)) self.assertListEqual(obj.children, self.fake_history_workflow["children"]) # Convert API object to DB model. model = ActionExecutionAPI.to_model(obj) self.assertEqual(str(model.id), obj.id) self.assertDictEqual(model.trigger, self.fake_history_workflow["trigger"]) self.assertDictEqual(model.trigger_type, self.fake_history_workflow["trigger_type"]) self.assertDictEqual(model.trigger_instance, self.fake_history_workflow["trigger_instance"]) self.assertDictEqual(model.rule, self.fake_history_workflow["rule"]) self.assertDictEqual(model.action, self.fake_history_workflow["action"]) self.assertDictEqual(model.runner, self.fake_history_workflow["runner"]) doc = copy.deepcopy(self.fake_history_workflow["liveaction"]) doc["start_timestamp"] = doc["start_timestamp"] doc["end_timestamp"] = doc["end_timestamp"] self.assertDictEqual(model.liveaction, doc) self.assertIsNone(getattr(model, "parent", None)) self.assertListEqual(model.children, self.fake_history_workflow["children"]) # Convert DB model to API object. obj = ActionExecutionAPI.from_model(model) self.assertEqual(str(model.id), obj.id) self.assertDictEqual(obj.trigger, self.fake_history_workflow["trigger"]) self.assertDictEqual(obj.trigger_type, self.fake_history_workflow["trigger_type"]) self.assertDictEqual(obj.trigger_instance, self.fake_history_workflow["trigger_instance"]) self.assertDictEqual(obj.rule, self.fake_history_workflow["rule"]) self.assertDictEqual(obj.action, self.fake_history_workflow["action"]) self.assertDictEqual(obj.runner, self.fake_history_workflow["runner"]) self.assertDictEqual(obj.liveaction, self.fake_history_workflow["liveaction"]) self.assertIsNone(getattr(obj, "parent", None)) self.assertListEqual(obj.children, self.fake_history_workflow["children"])
def setUpClass(cls): super(TestActionExecutionFilters, cls).setUpClass() cls.dt_base = date_utils.add_utc_tz(datetime.datetime(2014, 12, 25, 0, 0, 0)) cls.num_records = 100 cls.refs = {} cls.start_timestamps = [] cls.fake_types = [ { "trigger": copy.deepcopy(fixture.ARTIFACTS["trigger"]), "trigger_type": copy.deepcopy(fixture.ARTIFACTS["trigger_type"]), "trigger_instance": copy.deepcopy( fixture.ARTIFACTS["trigger_instance"] ), "rule": copy.deepcopy(fixture.ARTIFACTS["rule"]), "action": copy.deepcopy(fixture.ARTIFACTS["actions"]["chain"]), "runner": copy.deepcopy(fixture.ARTIFACTS["runners"]["action-chain"]), "liveaction": copy.deepcopy( fixture.ARTIFACTS["liveactions"]["workflow"] ), "context": copy.deepcopy(fixture.ARTIFACTS["context"]), "children": [], }, { "action": copy.deepcopy(fixture.ARTIFACTS["actions"]["local"]), "runner": copy.deepcopy(fixture.ARTIFACTS["runners"]["run-local"]), "liveaction": copy.deepcopy(fixture.ARTIFACTS["liveactions"]["task1"]), }, ] def assign_parent(child): candidates = [v for k, v in cls.refs.items() if v.action["name"] == "chain"] if candidates: parent = random.choice(candidates) child["parent"] = str(parent.id) parent.children.append(child["id"]) cls.refs[str(parent.id)] = ActionExecution.add_or_update(parent) for i in range(cls.num_records): obj_id = str(bson.ObjectId()) timestamp = cls.dt_base + datetime.timedelta(seconds=i) fake_type = random.choice(cls.fake_types) data = copy.deepcopy(fake_type) data["id"] = obj_id data["start_timestamp"] = isotime.format(timestamp, offset=False) data["end_timestamp"] = isotime.format(timestamp, offset=False) data["status"] = data["liveaction"]["status"] data["result"] = data["liveaction"]["result"] if fake_type["action"]["name"] == "local" and random.choice([True, False]): assign_parent(data) wb_obj = ActionExecutionAPI(**data) db_obj = ActionExecutionAPI.to_model(wb_obj) cls.refs[obj_id] = ActionExecution.add_or_update(db_obj) cls.start_timestamps.append(timestamp) cls.start_timestamps = sorted(cls.start_timestamps)
def setUpClass(cls): super(TestActionExecutionFilters, cls).setUpClass() cls.dt_base = date_utils.add_utc_tz(datetime.datetime(2014, 12, 25, 0, 0, 0)) cls.num_records = 100 cls.refs = {} cls.start_timestamps = [] cls.fake_types = [ { 'trigger': copy.deepcopy(fixture.ARTIFACTS['trigger']), 'trigger_type': copy.deepcopy(fixture.ARTIFACTS['trigger_type']), 'trigger_instance': copy.deepcopy(fixture.ARTIFACTS['trigger_instance']), 'rule': copy.deepcopy(fixture.ARTIFACTS['rule']), 'action': copy.deepcopy(fixture.ARTIFACTS['actions']['chain']), 'runner': copy.deepcopy(fixture.ARTIFACTS['runners']['action-chain']), 'liveaction': copy.deepcopy(fixture.ARTIFACTS['liveactions']['workflow']), 'context': copy.deepcopy(fixture.ARTIFACTS['context']), 'children': [] }, { 'action': copy.deepcopy(fixture.ARTIFACTS['actions']['local']), 'runner': copy.deepcopy(fixture.ARTIFACTS['runners']['run-local']), 'liveaction': copy.deepcopy(fixture.ARTIFACTS['liveactions']['task1']) } ] def assign_parent(child): candidates = [v for k, v in cls.refs.items() if v.action['name'] == 'chain'] if candidates: parent = random.choice(candidates) child['parent'] = str(parent.id) parent.children.append(child['id']) cls.refs[str(parent.id)] = ActionExecution.add_or_update(parent) for i in range(cls.num_records): obj_id = str(bson.ObjectId()) timestamp = cls.dt_base + datetime.timedelta(seconds=i) fake_type = random.choice(cls.fake_types) data = copy.deepcopy(fake_type) data['id'] = obj_id data['start_timestamp'] = isotime.format(timestamp, offset=False) data['end_timestamp'] = isotime.format(timestamp, offset=False) data['status'] = data['liveaction']['status'] data['result'] = data['liveaction']['result'] if fake_type['action']['name'] == 'local' and random.choice([True, False]): assign_parent(data) wb_obj = ActionExecutionAPI(**data) db_obj = ActionExecutionAPI.to_model(wb_obj) cls.refs[obj_id] = ActionExecution.add_or_update(db_obj) cls.start_timestamps.append(timestamp) cls.start_timestamps = sorted(cls.start_timestamps)
def test_model_partial(self): # Create API object. obj = ActionExecutionAPI( **copy.deepcopy(self.fake_history_subtasks[0])) self.assertIsNone(getattr(obj, 'trigger', None)) self.assertIsNone(getattr(obj, 'trigger_type', None)) self.assertIsNone(getattr(obj, 'trigger_instance', None)) self.assertIsNone(getattr(obj, 'rule', None)) self.assertDictEqual(obj.action, self.fake_history_subtasks[0]['action']) self.assertDictEqual(obj.runner, self.fake_history_subtasks[0]['runner']) self.assertDictEqual(obj.liveaction, self.fake_history_subtasks[0]['liveaction']) self.assertEqual(obj.parent, self.fake_history_subtasks[0]['parent']) self.assertIsNone(getattr(obj, 'children', None)) # Convert API object to DB model. model = ActionExecutionAPI.to_model(obj) self.assertEqual(str(model.id), obj.id) self.assertDictEqual(model.trigger, {}) self.assertDictEqual(model.trigger_type, {}) self.assertDictEqual(model.trigger_instance, {}) self.assertDictEqual(model.rule, {}) self.assertDictEqual(model.action, self.fake_history_subtasks[0]['action']) self.assertDictEqual(model.runner, self.fake_history_subtasks[0]['runner']) doc = copy.deepcopy(self.fake_history_subtasks[0]['liveaction']) doc['start_timestamp'] = doc['start_timestamp'] doc['end_timestamp'] = doc['end_timestamp'] self.assertDictEqual(model.liveaction, doc) self.assertEqual(model.parent, self.fake_history_subtasks[0]['parent']) self.assertListEqual(model.children, []) # Convert DB model to API object. obj = ActionExecutionAPI.from_model(model) self.assertEqual(str(model.id), obj.id) self.assertIsNone(getattr(obj, 'trigger', None)) self.assertIsNone(getattr(obj, 'trigger_type', None)) self.assertIsNone(getattr(obj, 'trigger_instance', None)) self.assertIsNone(getattr(obj, 'rule', None)) self.assertDictEqual(obj.action, self.fake_history_subtasks[0]['action']) self.assertDictEqual(obj.runner, self.fake_history_subtasks[0]['runner']) self.assertDictEqual(obj.liveaction, self.fake_history_subtasks[0]['liveaction']) self.assertEqual(obj.parent, self.fake_history_subtasks[0]['parent']) self.assertIsNone(getattr(obj, 'children', None))
def test_crud_partial(self): # Create the DB record. obj = ActionExecutionAPI(**copy.deepcopy(self.fake_history_subtasks[0])) ActionExecution.add_or_update(ActionExecutionAPI.to_model(obj)) model = ActionExecution.get_by_id(obj.id) self.assertEqual(str(model.id), obj.id) self.assertDictEqual(model.trigger, {}) self.assertDictEqual(model.trigger_type, {}) self.assertDictEqual(model.trigger_instance, {}) self.assertDictEqual(model.rule, {}) self.assertDictEqual(model.action, self.fake_history_subtasks[0]['action']) self.assertDictEqual(model.runner, self.fake_history_subtasks[0]['runner']) doc = copy.deepcopy(self.fake_history_subtasks[0]['liveaction']) doc['start_timestamp'] = doc['start_timestamp'] doc['end_timestamp'] = doc['end_timestamp'] self.assertDictEqual(model.liveaction, doc) self.assertEqual(model.parent, self.fake_history_subtasks[0]['parent']) self.assertListEqual(model.children, []) # Update the DB record. children = [str(bson.ObjectId()), str(bson.ObjectId())] model.children = children ActionExecution.add_or_update(model) model = ActionExecution.get_by_id(obj.id) self.assertListEqual(model.children, children) # Delete the DB record. ActionExecution.delete(model) self.assertRaises(StackStormDBObjectNotFoundError, ActionExecution.get_by_id, obj.id)
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 process(self, execution): LOG.debug('Got execution from queue: %s', execution) if execution.status not in COMPLETION_STATUSES: return execution_api = ActionExecutionAPI.from_model(execution, mask_secrets=True) self.pending_executions.put_nowait(execution_api) LOG.debug("Added execution to queue.")
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, action_alias_db, params, notify, context, requester_user, show_secrets): action_ref = action_alias_db.action_ref action_db = action_utils.get_action_by_ref(action_ref) if not action_db: raise StackStormDBObjectNotFoundError('Action with ref "%s" not found ' % (action_ref)) assert_user_has_resource_db_permission(user_db=requester_user, resource_db=action_db, permission_type=PermissionType.ACTION_EXECUTE) try: # prior to shipping off the params cast them to the right type. params = action_param_utils.cast_params(action_ref=action_alias_db.action_ref, params=params, cast_overrides=CAST_OVERRIDES) if not context: context = { 'action_alias_ref': reference.get_ref_from_model(action_alias_db), 'user': get_system_username() } liveaction = LiveActionDB(action=action_alias_db.action_ref, context=context, parameters=params, notify=notify) _, action_execution_db = action_service.request(liveaction) mask_secrets = self._get_mask_secrets(requester_user, show_secrets=show_secrets) return ActionExecutionAPI.from_model(action_execution_db, mask_secrets=mask_secrets) 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, action_alias_db, params, notify, context): action_ref = action_alias_db.action_ref action_db = action_utils.get_action_by_ref(action_ref) if not action_db: raise StackStormDBObjectNotFoundError('Action with ref "%s" not found ' % (action_ref)) assert_request_user_has_resource_db_permission(request=pecan.request, resource_db=action_db, permission_type=PermissionType.ACTION_EXECUTE) try: # prior to shipping off the params cast them to the right type. params = action_param_utils.cast_params(action_ref=action_alias_db.action_ref, params=params, cast_overrides=CAST_OVERRIDES) if not context: context = { 'action_alias_ref': reference.get_ref_from_model(action_alias_db), 'user': get_system_username() } liveaction = LiveActionDB(action=action_alias_db.action_ref, context=context, parameters=params, notify=notify) _, action_execution_db = action_service.request(liveaction) return ActionExecutionAPI.from_model(action_execution_db) except ValueError as e: LOG.exception('Unable to execute action.') pecan.abort(http_client.BAD_REQUEST, str(e)) except jsonschema.ValidationError as e: LOG.exception('Unable to execute action. Parameter validation failed.') pecan.abort(http_client.BAD_REQUEST, str(e)) except Exception as e: LOG.exception('Unable to execute action. Unexpected error encountered.') pecan.abort(http_client.INTERNAL_SERVER_ERROR, str(e))
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, 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 _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 delete(self, id, requester_user, **kwargs): """ 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.') from_model_kwargs = self._get_from_model_kwargs_for_request(**kwargs) return ActionExecutionAPI.from_model(execution_db, from_model_kwargs)
def test_install(self, _handle_schedule_execution): _handle_schedule_execution.return_value = ActionExecutionAPI(id='123') payload = {'packs': ['some']} resp = self.app.post_json('/v1/packs/install', payload) self.assertEqual(resp.status_int, 202) self.assertEqual(resp.json, {'execution_id': '123'})
def test_datetime_range(self): base = date_utils.add_utc_tz(datetime.datetime(2014, 12, 25, 0, 0, 0)) for i in range(60): timestamp = base + datetime.timedelta(seconds=i) doc = copy.deepcopy(self.fake_history_subtasks[0]) doc['id'] = str(bson.ObjectId()) doc['start_timestamp'] = isotime.format(timestamp) obj = ActionExecutionAPI(**doc) ActionExecution.add_or_update(ActionExecutionAPI.to_model(obj)) dt_range = '2014-12-25T00:00:10Z..2014-12-25T00:00:19Z' objs = ActionExecution.query(start_timestamp=dt_range) self.assertEqual(len(objs), 10) dt_range = '2014-12-25T00:00:19Z..2014-12-25T00:00:10Z' objs = ActionExecution.query(start_timestamp=dt_range) self.assertEqual(len(objs), 10)
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 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)
def test_sort_by_start_timestamp(self): base = date_utils.add_utc_tz(datetime.datetime(2014, 12, 25, 0, 0, 0)) for i in range(60): timestamp = base + datetime.timedelta(seconds=i) doc = copy.deepcopy(self.fake_history_subtasks[0]) doc["id"] = str(bson.ObjectId()) doc["start_timestamp"] = isotime.format(timestamp) obj = ActionExecutionAPI(**doc) ActionExecution.add_or_update(ActionExecutionAPI.to_model(obj)) dt_range = "2014-12-25T00:00:10Z..2014-12-25T00:00:19Z" objs = ActionExecution.query(start_timestamp=dt_range, order_by=["start_timestamp"]) self.assertLess(objs[0]["start_timestamp"], objs[9]["start_timestamp"]) dt_range = "2014-12-25T00:00:19Z..2014-12-25T00:00:10Z" objs = ActionExecution.query(start_timestamp=dt_range, order_by=["-start_timestamp"]) self.assertLess(objs[9]["start_timestamp"], objs[0]["start_timestamp"])
def test_model_partial(self): # Create API object. obj = ActionExecutionAPI(**copy.deepcopy(self.fake_history_subtasks[0])) self.assertIsNone(getattr(obj, 'trigger', None)) self.assertIsNone(getattr(obj, 'trigger_type', None)) self.assertIsNone(getattr(obj, 'trigger_instance', None)) self.assertIsNone(getattr(obj, 'rule', None)) self.assertDictEqual(obj.action, self.fake_history_subtasks[0]['action']) self.assertDictEqual(obj.runner, self.fake_history_subtasks[0]['runner']) self.assertDictEqual(obj.liveaction, self.fake_history_subtasks[0]['liveaction']) self.assertEqual(obj.parent, self.fake_history_subtasks[0]['parent']) self.assertIsNone(getattr(obj, 'children', None)) # Convert API object to DB model. model = ActionExecutionAPI.to_model(obj) self.assertEqual(str(model.id), obj.id) self.assertDictEqual(model.trigger, {}) self.assertDictEqual(model.trigger_type, {}) self.assertDictEqual(model.trigger_instance, {}) self.assertDictEqual(model.rule, {}) self.assertDictEqual(model.action, self.fake_history_subtasks[0]['action']) self.assertDictEqual(model.runner, self.fake_history_subtasks[0]['runner']) doc = copy.deepcopy(self.fake_history_subtasks[0]['liveaction']) doc['start_timestamp'] = doc['start_timestamp'] doc['end_timestamp'] = doc['end_timestamp'] self.assertDictEqual(model.liveaction, doc) self.assertEqual(model.parent, self.fake_history_subtasks[0]['parent']) self.assertListEqual(model.children, []) # Convert DB model to API object. obj = ActionExecutionAPI.from_model(model) self.assertEqual(str(model.id), obj.id) self.assertIsNone(getattr(obj, 'trigger', None)) self.assertIsNone(getattr(obj, 'trigger_type', None)) self.assertIsNone(getattr(obj, 'trigger_instance', None)) self.assertIsNone(getattr(obj, 'rule', None)) self.assertDictEqual(obj.action, self.fake_history_subtasks[0]['action']) self.assertDictEqual(obj.runner, self.fake_history_subtasks[0]['runner']) self.assertDictEqual(obj.liveaction, self.fake_history_subtasks[0]['liveaction']) self.assertEqual(obj.parent, self.fake_history_subtasks[0]['parent']) self.assertIsNone(getattr(obj, 'children', None))
def test_get_one(self): obj_id = random.choice(self.refs.keys()) response = self.app.get('/v1/executions/%s' % obj_id) self.assertEqual(response.status_int, 200) self.assertIsInstance(response.json, dict) record = response.json fake_record = ActionExecutionAPI.from_model(self.refs[obj_id]) self.assertEqual(record['id'], obj_id) self.assertDictEqual(record['action'], fake_record.action) self.assertDictEqual(record['runner'], fake_record.runner) self.assertDictEqual(record['liveaction'], fake_record.liveaction)
def test_get_one(self): obj_id = random.choice(list(self.refs.keys())) response = self.app.get('/v1/executions/%s' % obj_id) self.assertEqual(response.status_int, 200) self.assertIsInstance(response.json, dict) record = response.json fake_record = ActionExecutionAPI.from_model(self.refs[obj_id]) self.assertEqual(record['id'], obj_id) self.assertDictEqual(record['action'], fake_record.action) self.assertDictEqual(record['runner'], fake_record.runner) self.assertDictEqual(record['liveaction'], fake_record.liveaction)
def setUpClass(cls): super(TestActionExecutionFilters, cls).setUpClass() cls.dt_base = date_utils.add_utc_tz(datetime.datetime(2014, 12, 25, 0, 0, 0)) cls.num_records = 100 cls.refs = {} cls.start_timestamps = [] cls.fake_types = [ { "trigger": copy.deepcopy(fixture.ARTIFACTS["trigger"]), "trigger_type": copy.deepcopy(fixture.ARTIFACTS["trigger_type"]), "trigger_instance": copy.deepcopy(fixture.ARTIFACTS["trigger_instance"]), "rule": copy.deepcopy(fixture.ARTIFACTS["rule"]), "action": copy.deepcopy(fixture.ARTIFACTS["actions"]["chain"]), "runner": copy.deepcopy(fixture.ARTIFACTS["runners"]["action-chain"]), "liveaction": copy.deepcopy(fixture.ARTIFACTS["liveactions"]["workflow"]), "context": copy.deepcopy(fixture.ARTIFACTS["context"]), "children": [], }, { "action": copy.deepcopy(fixture.ARTIFACTS["actions"]["local"]), "runner": copy.deepcopy(fixture.ARTIFACTS["runners"]["run-local"]), "liveaction": copy.deepcopy(fixture.ARTIFACTS["liveactions"]["task1"]), }, ] def assign_parent(child): candidates = [v for k, v in cls.refs.iteritems() if v.action["name"] == "chain"] if candidates: parent = random.choice(candidates) child["parent"] = str(parent.id) parent.children.append(child["id"]) cls.refs[str(parent.id)] = ActionExecution.add_or_update(parent) for i in range(cls.num_records): obj_id = str(bson.ObjectId()) timestamp = cls.dt_base + datetime.timedelta(seconds=i) fake_type = random.choice(cls.fake_types) data = copy.deepcopy(fake_type) data["id"] = obj_id data["start_timestamp"] = isotime.format(timestamp, offset=False) data["end_timestamp"] = isotime.format(timestamp, offset=False) data["status"] = data["liveaction"]["status"] data["result"] = data["liveaction"]["result"] if fake_type["action"]["name"] == "local" and random.choice([True, False]): assign_parent(data) wb_obj = ActionExecutionAPI(**data) db_obj = ActionExecutionAPI.to_model(wb_obj) cls.refs[obj_id] = ActionExecution.add_or_update(db_obj) cls.start_timestamps.append(timestamp) cls.start_timestamps = sorted(cls.start_timestamps)
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 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 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, self._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)
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)
class TestDumper(DbTestCase): fixtures_loader = FixturesLoader() loaded_fixtures = fixtures_loader.load_fixtures(fixtures_pack=DESCENDANTS_PACK, fixtures_dict=DESCENDANTS_FIXTURES) loaded_executions = loaded_fixtures['executions'] execution_apis = [] for execution in loaded_executions.values(): execution_apis.append(ActionExecutionAPI(**execution)) def get_queue(self): executions_queue = queue.Queue() for execution in self.execution_apis: executions_queue.put(execution) return executions_queue @mock.patch.object(os.path, 'exists', mock.MagicMock(return_value=True)) def test_write_marker_to_db(self): executions_queue = self.get_queue() dumper = Dumper(queue=executions_queue, export_dir='/tmp', batch_size=5, max_files_per_sleep=1, file_prefix='st2-stuff-', file_format='json') timestamps = [isotime.parse(execution.end_timestamp) for execution in self.execution_apis] max_timestamp = max(timestamps) marker_db = dumper._write_marker_to_db(max_timestamp) persisted_marker = marker_db.marker self.assertTrue(isinstance(persisted_marker, six.string_types)) self.assertEqual(isotime.parse(persisted_marker), max_timestamp) @mock.patch.object(os.path, 'exists', mock.MagicMock(return_value=True)) def test_write_marker_to_db_marker_exists(self): executions_queue = self.get_queue() dumper = Dumper(queue=executions_queue, export_dir='/tmp', batch_size=5, max_files_per_sleep=1, file_prefix='st2-stuff-', file_format='json') timestamps = [isotime.parse(execution.end_timestamp) for execution in self.execution_apis] max_timestamp = max(timestamps) first_marker_db = dumper._write_marker_to_db(max_timestamp) second_marker_db = dumper._write_marker_to_db(max_timestamp + datetime.timedelta(hours=1)) markers = DumperMarker.get_all() self.assertEqual(len(markers), 1) final_marker_id = markers[0].id self.assertEqual(first_marker_db.id, final_marker_id) self.assertEqual(second_marker_db.id, final_marker_id) self.assertEqual(markers[0].marker, second_marker_db.marker) self.assertTrue(second_marker_db.updated_at > first_marker_db.updated_at)
def test_crud_complete(self): # Create the DB record. obj = ActionExecutionAPI(**copy.deepcopy(self.fake_history_workflow)) ActionExecution.add_or_update(ActionExecutionAPI.to_model(obj)) model = ActionExecution.get_by_id(obj.id) self.assertEqual(str(model.id), obj.id) self.assertDictEqual(model.trigger, self.fake_history_workflow["trigger"]) self.assertDictEqual(model.trigger_type, self.fake_history_workflow["trigger_type"]) self.assertDictEqual(model.trigger_instance, self.fake_history_workflow["trigger_instance"]) self.assertDictEqual(model.rule, self.fake_history_workflow["rule"]) self.assertDictEqual(model.action, self.fake_history_workflow["action"]) self.assertDictEqual(model.runner, self.fake_history_workflow["runner"]) doc = copy.deepcopy(self.fake_history_workflow["liveaction"]) doc["start_timestamp"] = doc["start_timestamp"] doc["end_timestamp"] = doc["end_timestamp"] self.assertDictEqual(model.liveaction, doc) self.assertIsNone(getattr(model, "parent", None)) self.assertListEqual(model.children, self.fake_history_workflow["children"]) # Update the DB record. children = [str(bson.ObjectId()), str(bson.ObjectId())] model.children = children ActionExecution.add_or_update(model) model = ActionExecution.get_by_id(obj.id) self.assertListEqual(model.children, children) # Delete the DB record. ActionExecution.delete(model) self.assertRaises(StackStormDBObjectNotFoundError, ActionExecution.get_by_id, obj.id)
def _bootstrap(self): marker = self._get_export_marker_from_db() LOG.info('Using marker %s...' % marker) missed_executions = self._get_missed_executions_from_db(export_marker=marker) LOG.info('Found %d executions not exported yet...', len(missed_executions)) for missed_execution in missed_executions: if missed_execution.status not in COMPLETION_STATUSES: continue execution_api = ActionExecutionAPI.from_model(missed_execution, mask_secrets=True) try: LOG.debug('Missed execution %s', execution_api) self.pending_executions.put_nowait(execution_api) except: LOG.exception('Failed adding execution to in-memory queue.') continue LOG.info('Bootstrapped executions...')
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: 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, 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)
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 test_sort_by_start_timestamp(self): base = isotime.add_utc_tz(datetime.datetime(2014, 12, 25, 0, 0, 0)) for i in range(60): timestamp = base + datetime.timedelta(seconds=i) doc = copy.deepcopy(self.fake_history_subtasks[0]) doc['id'] = str(bson.ObjectId()) doc['start_timestamp'] = isotime.format(timestamp) obj = ActionExecutionAPI(**doc) ActionExecution.add_or_update(ActionExecutionAPI.to_model(obj)) dt_range = '2014-12-25T00:00:10Z..2014-12-25T00:00:19Z' objs = ActionExecution.query(start_timestamp=dt_range, order_by=['start_timestamp']) self.assertLess(objs[0]['start_timestamp'], objs[9]['start_timestamp']) dt_range = '2014-12-25T00:00:19Z..2014-12-25T00:00:10Z' objs = ActionExecution.query(start_timestamp=dt_range, order_by=['-start_timestamp']) self.assertLess(objs[9]['start_timestamp'], objs[0]['start_timestamp'])
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))
class TestDumper(EventletTestCase): fixtures_loader = FixturesLoader() loaded_fixtures = fixtures_loader.load_fixtures( fixtures_pack=DESCENDANTS_PACK, fixtures_dict=DESCENDANTS_FIXTURES) loaded_executions = loaded_fixtures['executions'] execution_apis = [] for execution in loaded_executions.values(): execution_apis.append(ActionExecutionAPI(**execution)) def get_queue(self): executions_queue = queue.Queue() for execution in self.execution_apis: executions_queue.put(execution) return executions_queue @mock.patch.object(os.path, 'exists', mock.MagicMock(return_value=True)) def test_get_batch_batch_size_greater_than_actual(self): executions_queue = self.get_queue() qsize = executions_queue.qsize() self.assertTrue(qsize > 0) dumper = Dumper(queue=executions_queue, batch_size=2 * qsize, export_dir='/tmp') batch = dumper._get_batch() self.assertEqual(len(batch), qsize) @mock.patch.object(os.path, 'exists', mock.MagicMock(return_value=True)) def test_get_batch_batch_size_lesser_than_actual(self): executions_queue = self.get_queue() qsize = executions_queue.qsize() self.assertTrue(qsize > 0) expected_batch_size = int(qsize / 2) dumper = Dumper(queue=executions_queue, batch_size=expected_batch_size, export_dir='/tmp') batch = dumper._get_batch() self.assertEqual(len(batch), expected_batch_size) @mock.patch.object(os.path, 'exists', mock.MagicMock(return_value=True)) def test_get_file_name(self): dumper = Dumper(queue=self.get_queue(), export_dir='/tmp', file_prefix='st2-stuff-', file_format='json') file_name = dumper._get_file_name() export_date = date_utils.get_datetime_utc_now().strftime('%Y-%m-%d') self.assertTrue( file_name.startswith('/tmp/' + export_date + '/st2-stuff-')) self.assertTrue(file_name.endswith('json')) @mock.patch.object(os.path, 'exists', mock.MagicMock(return_value=True)) def test_write_to_disk_empty_queue(self): dumper = Dumper(queue=queue.Queue(), export_dir='/tmp', file_prefix='st2-stuff-', file_format='json') # We just make sure this doesn't blow up. ret = dumper._write_to_disk() self.assertEqual(ret, 0) @mock.patch.object(TextFileWriter, 'write_text', mock.MagicMock(return_value=True)) @mock.patch.object(Dumper, '_update_marker', mock.MagicMock(return_value=None)) @mock.patch.object(os.path, 'exists', mock.MagicMock(return_value=True)) def test_write_to_disk(self): executions_queue = self.get_queue() max_files_per_sleep = 5 dumper = Dumper(queue=executions_queue, export_dir='/tmp', batch_size=1, max_files_per_sleep=max_files_per_sleep, file_prefix='st2-stuff-', file_format='json') # We just make sure this doesn't blow up. ret = dumper._write_to_disk() self.assertEqual(ret, max_files_per_sleep) @mock.patch.object(os.path, 'exists', mock.MagicMock(return_value=True)) @mock.patch.object(TextFileWriter, 'write_text', mock.MagicMock(return_value=True)) def test_start_stop_dumper(self): executions_queue = self.get_queue() sleep_interval = 0.01 dumper = Dumper(queue=executions_queue, sleep_interval=sleep_interval, export_dir='/tmp', batch_size=1, max_files_per_sleep=5, file_prefix='st2-stuff-', file_format='json') dumper.start() # Call stop after at least one batch was written to disk. eventlet.sleep(10 * sleep_interval) dumper.stop() @mock.patch.object(os.path, 'exists', mock.MagicMock(return_value=True)) @mock.patch.object(Dumper, '_write_marker_to_db', mock.MagicMock(return_value=True)) def test_update_marker(self): executions_queue = self.get_queue() dumper = Dumper(queue=executions_queue, export_dir='/tmp', batch_size=5, max_files_per_sleep=1, file_prefix='st2-stuff-', file_format='json') # Batch 1 batch = self.execution_apis[0:5] new_marker = dumper._update_marker(batch) self.assertTrue(new_marker is not None) timestamps = [ isotime.parse(execution.end_timestamp) for execution in batch ] max_timestamp = max(timestamps) self.assertEqual(new_marker, max_timestamp) # Batch 2 batch = self.execution_apis[0:5] new_marker = dumper._update_marker(batch) timestamps = [ isotime.parse(execution.end_timestamp) for execution in batch ] max_timestamp = max(timestamps) self.assertEqual(new_marker, max_timestamp) dumper._write_marker_to_db.assert_called_with(new_marker) @mock.patch.object(os.path, 'exists', mock.MagicMock(return_value=True)) @mock.patch.object(Dumper, '_write_marker_to_db', mock.MagicMock(return_value=True)) def test_update_marker_out_of_order_batch(self): executions_queue = self.get_queue() dumper = Dumper(queue=executions_queue, export_dir='/tmp', batch_size=5, max_files_per_sleep=1, file_prefix='st2-stuff-', file_format='json') timestamps = [ isotime.parse(execution.end_timestamp) for execution in self.execution_apis ] max_timestamp = max(timestamps) # set dumper persisted timestamp to something less than min timestamp in the batch test_timestamp = max_timestamp + datetime.timedelta(hours=1) dumper._persisted_marker = test_timestamp new_marker = dumper._update_marker(self.execution_apis) self.assertTrue(new_marker < test_timestamp) # Assert we rolled back the marker. self.assertEqual(dumper._persisted_marker, max_timestamp) self.assertEqual(new_marker, max_timestamp) dumper._write_marker_to_db.assert_called_with(new_marker)
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 _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 delete(self, id, requester_user, show_secrets=False): """ Stops a single execution. Handles requests: DELETE /executions/<id> """ if not requester_user: requester_user = UserDB(name=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 _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 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, six.text_type(e)) abort(http_client.BAD_REQUEST, 'Failed updating execution. %s' % six.text_type(e)) except runner_exc.UnexpectedActionExecutionStatusError as e: LOG.exception('Failed updating liveaction %s. %s', liveaction_db.id, six.text_type(e)) abort(http_client.BAD_REQUEST, 'Failed updating execution. %s' % six.text_type(e)) except Exception as e: LOG.exception('Failed updating liveaction %s. %s', liveaction_db.id, six.text_type(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 _append_view_properties(self, rule_enforcement_apis): """ Method which appends corresponding execution (if available) and trigger instance object properties. """ trigger_instance_ids = set([]) execution_ids = [] for rule_enforcement_api in rule_enforcement_apis: if rule_enforcement_api.get('trigger_instance_id', None): trigger_instance_ids.add(str(rule_enforcement_api['trigger_instance_id'])) if rule_enforcement_api.get('execution_id', None): execution_ids.append(rule_enforcement_api['execution_id']) # 1. Retrieve corresponding execution objects # NOTE: Executions contain a lot of field and could contain a lot of data so we only # retrieve fields we need only_fields = [ 'id', 'action.ref', 'action.parameters', 'runner.name', 'runner.runner_parameters', 'parameters', 'status' ] execution_dbs = ActionExecution.query(id__in=execution_ids, only_fields=only_fields) execution_dbs_by_id = {} for execution_db in execution_dbs: execution_dbs_by_id[str(execution_db.id)] = execution_db # 2. Retrieve corresponding trigger instance objects trigger_instance_dbs = TriggerInstance.query(id__in=list(trigger_instance_ids)) trigger_instance_dbs_by_id = {} for trigger_instance_db in trigger_instance_dbs: trigger_instance_dbs_by_id[str(trigger_instance_db.id)] = trigger_instance_db # Ammend rule enforcement objects with additional data for rule_enforcement_api in rule_enforcement_apis: rule_enforcement_api['trigger_instance'] = {} rule_enforcement_api['execution'] = {} trigger_instance_id = rule_enforcement_api.get('trigger_instance_id', None) execution_id = rule_enforcement_api.get('execution_id', None) trigger_instance_db = trigger_instance_dbs_by_id.get(trigger_instance_id, None) execution_db = execution_dbs_by_id.get(execution_id, None) if trigger_instance_db: trigger_instance_api = TriggerInstanceAPI.from_model(trigger_instance_db) rule_enforcement_api['trigger_instance'] = trigger_instance_api if execution_db: execution_api = ActionExecutionAPI.from_model(execution_db) rule_enforcement_api['execution'] = execution_api return rule_enforcement_apis