def setUpClass(cls): super(ExecutionCancellationTestCase, cls).setUpClass() for _, fixture in six.iteritems(FIXTURES['actions']): instance = ActionAPI(**fixture) Action.add_or_update(ActionAPI.to_model(instance)) runners_registrar.register_runners()
def setup_action_models(cls): action_db = ActionDB() action_db.name = 'action-1' action_db.description = 'awesomeness' action_db.enabled = True action_db.pack = 'wolfpack' action_db.entry_point = '' action_db.runner_type = {'name': 'test-runner'} action_db.parameters = { 'actionstr': {'type': 'string', 'required': True}, 'actionint': {'type': 'number', 'default': 10}, 'runnerdummy': {'type': 'string', 'default': 'actiondummy'}, 'runnerimmutable': {'type': 'string', 'default': 'failed_override'}, 'actionimmutable': {'type': 'string', 'default': 'actionimmutable', 'immutable': True} } RunnerContainerTest.action_db = Action.add_or_update(action_db) action_db = ActionDB() action_db.name = 'action-2' action_db.description = 'awesomeness' action_db.enabled = True action_db.pack = 'wolfpack' action_db.entry_point = '' action_db.runner_type = {'name': 'test-failingrunner'} action_db.parameters = {} RunnerContainerTest.failingaction_db = Action.add_or_update(action_db)
def test_parameter_schema(self): runnertype = self._create_save_runnertype(metadata=True) saved = self._create_save_action(runnertype, metadata=True) retrieved = Action.get_by_id(saved.id) # validate generated schema schema = util_schema.get_schema_for_action_parameters(retrieved) self.assertDictEqual(schema, PARAM_SCHEMA) validator = util_schema.get_validator() validator.check_schema(schema) # use schema to validate parameters jsonschema.validate({"r2": "abc", "p1": "def"}, schema, validator) jsonschema.validate({"r2": "abc", "p1": "def", "r1": {"r1a": "ghi"}}, schema, validator) self.assertRaises(jsonschema.ValidationError, jsonschema.validate, '{"r2": "abc", "p1": "def"}', schema, validator) self.assertRaises(jsonschema.ValidationError, jsonschema.validate, {"r2": "abc"}, schema, validator) self.assertRaises(jsonschema.ValidationError, jsonschema.validate, {"r2": "abc", "p1": "def", "r1": 123}, schema, validator) # cleanup self._delete([retrieved]) try: retrieved = Action.get_by_id(saved.id) except ValueError: retrieved = None self.assertIsNone(retrieved, 'managed to retrieve after failure.')
def _register_action(self, pack, action): with open(action, 'r') as fd: try: content = json.load(fd) except ValueError: LOG.exception('Failed loading action json from %s.', action) raise try: model = Action.get_by_name(str(content['name'])) except ValueError: model = ActionDB() model.name = content['name'] model.description = content['description'] model.enabled = content['enabled'] model.pack = pack model.entry_point = content['entry_point'] model.parameters = content.get('parameters', {}) runner_type = str(content['runner_type']) valid_runner_type, runner_type_db = self._has_valid_runner_type(runner_type) if valid_runner_type: model.runner_type = {'name': runner_type_db.name} else: LOG.exception('Runner type %s doesn\'t exist.') raise try: model = Action.add_or_update(model) LOG.audit('Action created. Action %s from %s.', model, action) except Exception: LOG.exception('Failed to write action to db %s.', model.name) raise
def delete(self, action_ref_or_id): """ Delete an action. Handles requests: POST /actions/1?_method=delete DELETE /actions/1 DELETE /actions/mypack.myaction """ action_db = self._get_by_ref_or_id(ref_or_id=action_ref_or_id) action_id = action_db.id try: validate_not_part_of_system_pack(action_db) except ValueValidationException as e: abort(http_client.BAD_REQUEST, str(e)) LOG.debug('DELETE /actions/ lookup with ref_or_id=%s found object: %s', action_ref_or_id, action_db) try: Action.delete(action_db) except Exception as e: LOG.error('Database delete encountered exception during delete of id="%s". ' 'Exception was %s', action_id, e) abort(http_client.INTERNAL_SERVER_ERROR, str(e)) return extra = {'action_db': action_db} LOG.audit('Action deleted. Action.id=%s' % (action_db.id), extra=extra) return None
def setUpClass(cls): super(TestMistralRunner, cls).setUpClass() runners_registrar.register_runner_types() for _, fixture in six.iteritems(FIXTURES['actions']): instance = ActionAPI(**fixture) Action.add_or_update(ActionAPI.to_model(instance))
def test_action_with_notify_crud(self): runnertype = self._create_save_runnertype(metadata=False) saved = self._create_save_action(runnertype, metadata=False) # Update action with notification settings on_complete = NotificationSubSchema(message='Action complete.') saved.notify = NotificationSchema(on_complete=on_complete) saved = Action.add_or_update(saved) # Check if notification settings were set correctly. retrieved = Action.get_by_id(saved.id) self.assertEqual(retrieved.notify.on_complete.message, on_complete.message) # Now reset notify in action to empty and validate it's gone. retrieved.notify = NotificationSchema(on_complete=None) saved = Action.add_or_update(retrieved) retrieved = Action.get_by_id(saved.id) self.assertEqual(retrieved.notify.on_complete, None) # cleanup self._delete([retrieved]) try: retrieved = Action.get_by_id(saved.id) except ValueError: retrieved = None self.assertIsNone(retrieved, 'managed to retrieve after failure.')
def tearDownClass(cls): for actiondb in cls.actiondbs.values(): Action.delete(actiondb) RunnerType.delete(cls.runnerdb) super(TestActionExecutionService, cls).tearDownClass()
def setUpClass(cls): super(TestStreamController, cls).setUpClass() instance = RunnerTypeAPI(**RUNNER_TYPE_1) RunnerType.add_or_update(RunnerTypeAPI.to_model(instance)) instance = ActionAPI(**ACTION_1) Action.add_or_update(ActionAPI.to_model(instance))
def setUp(self): RUNNER_TYPE.id = None RunnerType.add_or_update(RUNNER_TYPE) ACTION.id = None ACTION.runner_type = {'name': RUNNER_TYPE.name} Action.add_or_update(ACTION) TRIGGER.id = None Trigger.add_or_update(TRIGGER)
def setUpClass(cls): super(TestActionExecutionHistoryWorker, cls).setUpClass() runners_registrar.register_runner_types() action_local = ActionAPI(**copy.deepcopy(fixture.ARTIFACTS['actions']['local'])) Action.add_or_update(ActionAPI.to_model(action_local)) action_chain = ActionAPI(**copy.deepcopy(fixture.ARTIFACTS['actions']['chain'])) action_chain.entry_point = fixture.PATH + '/chain.yaml' Action.add_or_update(ActionAPI.to_model(action_chain))
def test_request_disabled_action(self): self.actiondb.enabled = False Action.add_or_update(self.actiondb) parameters = {'hosts': 'localhost', 'cmd': 'uname -a'} execution = LiveActionDB(action=ACTION_REF, parameters=parameters) self.assertRaises(ValueError, action_service.request, execution) self.actiondb.enabled = True Action.add_or_update(self.actiondb)
def setUpClass(cls): super(TestMistralRunner, cls).setUpClass() runners_registrar.register_runner_types() metadata = fixture.ARTIFACTS['metadata'] action_local = ActionAPI(**copy.deepcopy(metadata['actions']['local'])) Action.add_or_update(ActionAPI.to_model(action_local)) action_wkflow = ActionAPI(**copy.deepcopy(metadata['actions']['workflow-v2'])) Action.add_or_update(ActionAPI.to_model(action_wkflow))
def setUpClass(cls): super(TestActionExecutionHistoryWorker, cls).setUpClass() runners_registrar.register_runners() action_local = ActionAPI(**copy.deepcopy(fixture.ARTIFACTS["actions"]["local"])) Action.add_or_update(ActionAPI.to_model(action_local)) action_chain = ActionAPI(**copy.deepcopy(fixture.ARTIFACTS["actions"]["chain"])) action_chain.entry_point = fixture.PATH + "/chain.yaml" Action.add_or_update(ActionAPI.to_model(action_chain))
def test_register_all_actions(self): try: packs_base_path = os.path.join(tests_base.get_fixtures_path()) all_actions_in_db = Action.get_all() actions_registrar.register_actions(packs_base_path=packs_base_path) all_actions_in_db = Action.get_all() self.assertTrue(len(all_actions_in_db) > 0) except Exception as e: print(str(e)) self.fail('All actions must be registered without exceptions.')
def setUpClass(cls): super(MistralValidationControllerTest, cls).setUpClass() for _, fixture in six.iteritems(FIXTURES['runners']): instance = RunnerTypeAPI(**fixture) RunnerType.add_or_update(RunnerTypeAPI.to_model(instance)) for _, fixture in six.iteritems(FIXTURES['actions']): instance = ActionAPI(**fixture) Action.add_or_update(ActionAPI.to_model(instance))
def setUpClass(cls): super(DSLTransformTestCase, cls).setUpClass() for _, fixture in six.iteritems(FIXTURES['runners']): instance = RunnerTypeAPI(**fixture) RunnerType.add_or_update(RunnerTypeAPI.to_model(instance)) for _, fixture in six.iteritems(FIXTURES['actions']): instance = ActionAPI(**fixture) Action.add_or_update(ActionAPI.to_model(instance))
def test_register_all_actions(self): try: packs_base_path = fixtures_loader.get_fixtures_base_path() all_actions_in_db = Action.get_all() actions_registrar.register_actions(packs_base_paths=[packs_base_path]) except Exception as e: print(str(e)) self.fail('All actions must be registered without exceptions.') else: all_actions_in_db = Action.get_all() self.assertTrue(len(all_actions_in_db) > 0)
def setUpClass(cls): super(MistralValidationTest, cls).setUpClass() for _, fixture in six.iteritems(FIXTURES["runners"]): instance = RunnerTypeAPI(**fixture) RunnerType.add_or_update(RunnerTypeAPI.to_model(instance)) for _, fixture in six.iteritems(FIXTURES["actions"]): instance = ActionAPI(**fixture) Action.add_or_update(ActionAPI.to_model(instance)) cls.validator = wf_validation_utils.get_validator()
def test_run(self): pack = 'dummy_pack_1' # Verify all the resources are there pack_dbs = Pack.query(ref=pack) action_dbs = Action.query(pack=pack) alias_dbs = ActionAlias.query(pack=pack) rule_dbs = Rule.query(pack=pack) sensor_dbs = Sensor.query(pack=pack) trigger_type_dbs = TriggerType.query(pack=pack) policy_dbs = Policy.query(pack=pack) config_schema_dbs = ConfigSchema.query(pack=pack) config_dbs = Config.query(pack=pack) self.assertEqual(len(pack_dbs), 1) self.assertEqual(len(action_dbs), 1) self.assertEqual(len(alias_dbs), 2) self.assertEqual(len(rule_dbs), 1) self.assertEqual(len(sensor_dbs), 3) self.assertEqual(len(trigger_type_dbs), 4) self.assertEqual(len(policy_dbs), 2) self.assertEqual(len(config_schema_dbs), 1) self.assertEqual(len(config_dbs), 1) # Run action action = self.get_action_instance() action.run(packs=[pack]) # Make sure all resources have been removed from the db pack_dbs = Pack.query(ref=pack) action_dbs = Action.query(pack=pack) alias_dbs = ActionAlias.query(pack=pack) rule_dbs = Rule.query(pack=pack) sensor_dbs = Sensor.query(pack=pack) trigger_type_dbs = TriggerType.query(pack=pack) policy_dbs = Policy.query(pack=pack) config_schema_dbs = ConfigSchema.query(pack=pack) config_dbs = Config.query(pack=pack) self.assertEqual(len(pack_dbs), 0) self.assertEqual(len(action_dbs), 0) self.assertEqual(len(alias_dbs), 0) self.assertEqual(len(rule_dbs), 0) self.assertEqual(len(sensor_dbs), 0) self.assertEqual(len(trigger_type_dbs), 0) self.assertEqual(len(policy_dbs), 0) self.assertEqual(len(config_schema_dbs), 0) self.assertEqual(len(config_dbs), 0)
def setUpClass(cls): super(DSLTransformTestCase, cls).setUpClass() runners_registrar.register_runner_types() action_local = ActionAPI(**copy.deepcopy(FIXTURES['actions']['local.yaml'])) Action.add_or_update(ActionAPI.to_model(action_local)) for action_name in ['action1', 'action2', 'action3']: metadata = copy.deepcopy(FIXTURES['actions']['local.yaml']) metadata['name'] = action_name metadata['pack'] = 'demo' action = ActionAPI(**metadata) Action.add_or_update(ActionAPI.to_model(action))
def test_pack_name_missing(self): registrar = actions_registrar.ActionsRegistrar() action_file = os.path.join(tests_base.get_fixtures_path(), 'wolfpack/actions/action_3_pack_missing.json') registrar._register_action('dummy', action_file) action_name = None with open(action_file, 'r') as fd: content = json.load(fd) action_name = str(content['name']) action_db = Action.get_by_name(action_name) self.assertEqual(action_db.pack, 'dummy', 'Content pack must be ' + 'set to dummy') Action.delete(action_db)
def test_request_disabled_action(self): actiondb = self.actiondbs[ACTION['name']] actiondb.enabled = False Action.add_or_update(actiondb) try: parameters = {'hosts': 'localhost', 'cmd': 'uname -a'} execution = LiveActionDB(action=ACTION_REF, parameters=parameters) self.assertRaises(ValueError, action_service.request, execution) except Exception as e: raise e finally: actiondb.enabled = True Action.add_or_update(actiondb)
def test_pack_name_missing(self): registrar = actions_registrar.ActionsRegistrar() loader = fixtures_loader.FixturesLoader() action_file = loader.get_fixture_file_path_abs( 'generic', 'actions', 'action_3_pack_missing.yaml') registrar._register_action('dummy', action_file) action_name = None with open(action_file, 'r') as fd: content = yaml.safe_load(fd) action_name = str(content['name']) action_db = Action.get_by_name(action_name) self.assertEqual(action_db.pack, 'dummy', 'Content pack must be ' + 'set to dummy') Action.delete(action_db)
def test_register_all_actions(self): try: packs_base_path = fixtures_loader.get_fixtures_base_path() all_actions_in_db = Action.get_all() actions_registrar.register_actions(packs_base_paths=[packs_base_path]) except Exception as e: print(six.text_type(e)) self.fail('All actions must be registered without exceptions.') else: all_actions_in_db = Action.get_all() self.assertTrue(len(all_actions_in_db) > 0) # Assert metadata_file field is populated expected_path = 'actions/action-with-no-parameters.yaml' self.assertEqual(all_actions_in_db[0].metadata_file, expected_path)
def post(self, action): """ Create a new action. Handles requests: POST /actions/ """ # Perform validation validate_not_part_of_system_pack(action) action_validator.validate_action(action) # Write pack data files to disk (if any are provided) data_files = getattr(action, 'data_files', []) written_data_files = [] if data_files: written_data_files = self._handle_data_files(pack_name=action.pack, data_files=data_files) action_model = ActionAPI.to_model(action) LOG.debug('/actions/ POST verified ActionAPI object=%s', action) action_db = Action.add_or_update(action_model) LOG.debug('/actions/ POST saved ActionDB object=%s', action_db) # Dispatch an internal trigger for each written data file. This way user # automate comitting this files to git using StackStorm rule if written_data_files: self._dispatch_trigger_for_written_data_files(action_db=action_db, written_data_files=written_data_files) extra = {'acion_db': action_db} LOG.audit('Action created. Action.id=%s' % (action_db.id), extra=extra) action_api = ActionAPI.from_model(action_db) return action_api
def setUpClass(cls): super(TestActionExecutionService, cls).setUpClass() cls.runner = RunnerTypeAPI(**RUNNER) cls.runnerdb = RunnerType.add_or_update(RunnerTypeAPI.to_model(cls.runner)) cls.action = ActionAPI(**ACTION) cls.actiondb = Action.add_or_update(ActionAPI.to_model(cls.action)) cls.container = RunnerContainer()
def post(self, action): """ Create a new action. Handles requests: POST /actions/ """ if not hasattr(action, 'pack'): setattr(action, 'pack', DEFAULT_PACK_NAME) try: action_validator.validate_action(action) except ValueValidationException as e: abort(http_client.BAD_REQUEST, str(e)) return # ActionsController._validate_action_parameters(action, runnertype_db) action_model = ActionAPI.to_model(action) LOG.debug('/actions/ POST verified ActionAPI object=%s', action) action_db = Action.add_or_update(action_model) LOG.debug('/actions/ POST saved ActionDB object=%s', action_db) extra = {'action_db': action_db} LOG.audit('Action created. Action.id=%s' % (action_db.id), extra=extra) action_api = ActionAPI.from_model(action_db) return action_api
def _register_action(self, pack, action): content = self._meta_loader.load(action) action_ref = ResourceReference(pack=pack, name=str(content['name'])) model = action_utils.get_action_by_ref(action_ref) if not model: model = ActionDB() model.name = content['name'] model.description = content['description'] model.enabled = content['enabled'] model.pack = pack model.entry_point = content['entry_point'] model.parameters = content.get('parameters', {}) runner_type = str(content['runner_type']) valid_runner_type, runner_type_db = self._has_valid_runner_type(runner_type) if valid_runner_type: model.runner_type = {'name': runner_type_db.name} else: LOG.exception('Runner type %s doesn\'t exist.', runner_type) raise try: model = Action.add_or_update(model) LOG.audit('Action created. Action %s from %s.', model, action) except Exception: LOG.exception('Failed to write action to db %s.', model.name) raise
def test_action_update(self): registrar = actions_registrar.ActionsRegistrar() loader = fixtures_loader.FixturesLoader() action_file = loader.get_fixture_file_path_abs( 'generic', 'actions', 'action1.yaml') registrar._register_action('wolfpack', action_file) # try registering again. this should not throw errors. registrar._register_action('wolfpack', action_file) action_name = None with open(action_file, 'r') as fd: content = yaml.safe_load(fd) action_name = str(content['name']) action_db = Action.get_by_name(action_name) self.assertEqual(action_db.pack, 'wolfpack', 'Content pack must be ' + 'set to wolfpack') Action.delete(action_db)
def post(self, action): """ Create a new action. Handles requests: POST /actions/ """ try: # Perform validation validate_not_part_of_system_pack(action) action_validator.validate_action(action) except (ValidationError, ValueError, ValueValidationException, InvalidActionParameterException) as e: LOG.exception('Unable to create action data=%s', action) abort(http_client.BAD_REQUEST, str(e)) return # Write pack data files to disk (if any are provided) data_files = getattr(action, 'data_files', []) written_data_files = [] if data_files: written_data_files = self._handle_data_files(pack_name=action.pack, data_files=data_files) action_model = ActionAPI.to_model(action) LOG.debug('/actions/ POST verified ActionAPI object=%s', action) action_db = Action.add_or_update(action_model) LOG.debug('/actions/ POST saved ActionDB object=%s', action_db) # Dispatch an internal trigger for each written data file. This way user # automate comitting this files to git using StackStorm rule if written_data_files: self._dispatch_trigger_for_written_data_files( action_db=action_db, written_data_files=written_data_files) extra = {'acion_db': action_db} LOG.audit('Action created. Action.id=%s' % (action_db.id), extra=extra) action_api = ActionAPI.from_model(action_db) return action_api
def test_post_duplicate(self): action_ids = [] post_resp = self.__do_post(ACTION_1) self.assertEqual(post_resp.status_int, 201) action_in_db = Action.get_by_name(ACTION_1.get('name')) self.assertTrue(action_in_db is not None, 'Action must be in db.') action_ids.append(self.__get_action_id(post_resp)) post_resp = self.__do_post(ACTION_1, expect_errors=True) # Verify name conflict self.assertEqual(post_resp.status_int, 409) post_resp = self.__do_post(ACTION_10) action_ids.append(self.__get_action_id(post_resp)) # Verify action with same name but different pack is written. self.assertEqual(post_resp.status_int, 201) for i in action_ids: self.__do_delete(i)
def _create_save_action(runnertype, metadata=False): name = "action-1" pack = "wolfpack" ref = ResourceReference(pack=pack, name=name).ref created = ActionDB( name=name, description="awesomeness", enabled=True, entry_point="/tmp/action.py", pack=pack, ref=ref, runner_type={"name": runnertype.name}, ) if not metadata: created.parameters = { "p1": None, "p2": None, "p3": None, "p4": None } else: created.parameters = { "p1": { "type": "string", "required": True }, "p2": { "type": "number", "default": 2868 }, "p3": { "type": "boolean", "default": False }, "p4": { "type": "string", "secret": True }, } return Action.add_or_update(created)
def put(self, action_ref_or_id, action): action_db = self._get_by_ref_or_id(ref_or_id=action_ref_or_id) # Assert permissions action_id = action_db.id if not getattr(action, 'pack', None): action.pack = action_db.pack # Perform validation validate_not_part_of_system_pack(action) action_validator.validate_action(action) # Write pack data files to disk (if any are provided) data_files = getattr(action, 'data_files', []) written_data_files = [] if data_files: written_data_files = self._handle_data_files(pack_name=action.pack, data_files=data_files) try: action_db = ActionAPI.to_model(action) LOG.debug('/actions/ PUT incoming action: %s', action_db) action_db.id = action_id action_db = Action.add_or_update(action_db) LOG.debug('/actions/ PUT after add_or_update: %s', action_db) except (ValidationError, ValueError) as e: LOG.exception('Unable to update action data=%s', action) abort(http_client.BAD_REQUEST, str(e)) return # Dispatch an internal trigger for each written data file. This way user # automate comitting this files to git using StackStorm rule if written_data_files: self._dispatch_trigger_for_written_data_files( action_db=action_db, written_data_files=written_data_files) action_api = ActionAPI.from_model(action_db) LOG.debug('PUT /actions/ client_result=%s', action_api) return action_api
def setup_action_models(cls): pack = 'wolfpack' name = 'action-1' parameters = { 'actionstr': { 'type': 'string', 'position': 1, 'required': True }, 'actionint': { 'type': 'number', 'default': 10, 'position': 0 }, 'runnerdummy': { 'type': 'string', 'default': 'actiondummy' } } action_db = ActionDB(pack=pack, name=name, description='awesomeness', enabled=True, ref=ResourceReference(name=name, pack=pack).ref, entry_point='', runner_type={'name': 'test-runner'}, parameters=parameters) ActionDBUtilsTestCase.action_db = Action.add_or_update(action_db) liveaction_db = LiveActionDB() liveaction_db.status = 'initializing' liveaction_db.start_timestamp = get_datetime_utc_now() liveaction_db.action = ActionDBUtilsTestCase.action_db.ref params = { 'actionstr': 'foo', 'some_key_that_aint_exist_in_action_or_runner': 'bar', 'runnerint': 555 } liveaction_db.parameters = params ActionDBUtilsTestCase.liveaction_db = LiveAction.add_or_update( liveaction_db)
def test_uid_is_populated_on_save(self): pack_1_db = PackDB(ref='test_pack', name='test', description='foo', version='1.0.0', author='dev', email='*****@*****.**') pack_1_db = Pack.add_or_update(pack_1_db) pack_1_db.reload() self.assertEqual(pack_1_db.uid, 'pack:test_pack') action_1_db = ActionDB(name='local', pack='core', ref='core.local', entry_point='', runner_type={'name': 'local-shell-cmd'}) action_1_db = Action.add_or_update(action_1_db) action_1_db.reload() self.assertEqual(action_1_db.uid, 'action:core:local')
def get_action_by_id(action_id): """ Get Action by id. On error, raise StackStormDBObjectNotFoundError """ action = None try: action = Action.get_by_id(action_id) except (ValueError, ValidationError) as e: LOG.warning( 'Database lookup for action with id="%s" resulted in ' "exception: %s", action_id, e, ) raise StackStormDBObjectNotFoundError( "Unable to find action with " 'id="%s"' % action_id ) return action
def setup_action_models(cls): action_db = ActionDB() action_db.name = 'action-1' action_db.description = 'awesomeness' action_db.enabled = True action_db.pack = 'wolfpack' action_db.entry_point = '' action_db.runner_type = {'name': 'test-runner'} action_db.parameters = { 'actionstr': { 'type': 'string', 'position': 1, 'required': True }, 'actionint': { 'type': 'number', 'default': 10, 'position': 0 }, 'runnerdummy': { 'type': 'string', 'default': 'actiondummy' } } ActionDBUtilsTestCase.action_db = Action.add_or_update(action_db) actionexec_db = ActionExecutionDB() actionexec_db.status = 'initializing' actionexec_db.start_timestamp = datetime.datetime.utcnow() actionexec_db.action = ResourceReference( name=ActionDBUtilsTestCase.action_db.name, pack=ActionDBUtilsTestCase.action_db.pack).ref params = { 'actionstr': 'foo', 'some_key_that_aint_exist_in_action_or_runner': 'bar', 'runnerint': 555 } actionexec_db.parameters = params ActionDBUtilsTestCase.actionexec_db = ActionExecution.add_or_update( actionexec_db)
def _transform_action(spec, action_key, input_key): if action_key not in spec or spec.get(action_key) == 'st2.action': return if spec.get(action_key) == 'st2.callback': raise Exception('st2.callback is deprecated.') # Convert parameters that are inline (i.e. action: some_action var1={$.value1} var2={$.value2}) # and split it to action name and input dict as illustrated below. # # action: some_action # input: # var1: $.value1 # var2: $.value2 # # This step to separate the action name and the input parameters is required # to wrap them with the st2.action proxy. # # action: st2.action # input: # ref: some_action # parameters: # var1: $.value1 # var2: $.value2 _eval_inline_params(spec, action_key, input_key) action_ref = spec.get(action_key) if ResourceReference.is_resource_reference(action_ref): ref = ResourceReference.from_string_reference(ref=action_ref) actions = Action.query(name=ref.name, pack=ref.pack) action = actions.first() if actions else None else: action = None if action: spec[action_key] = 'st2.action' spec[input_key] = {'ref': action_ref, 'parameters': spec[input_key]}
def setUpClass(cls): super(TestActionExecutionService, cls).setUpClass() cls.runner = RunnerTypeAPI(**RUNNER) cls.runnerdb = RunnerType.add_or_update(RunnerTypeAPI.to_model(cls.runner)) runner_api = RunnerTypeAPI(**RUNNER_ACTION_CHAIN) RunnerType.add_or_update(RunnerTypeAPI.to_model(runner_api)) cls.actions = { ACTION['name']: ActionAPI(**ACTION), ACTION_WORKFLOW['name']: ActionAPI(**ACTION_WORKFLOW), ACTION_OVR_PARAM['name']: ActionAPI(**ACTION_OVR_PARAM), ACTION_OVR_PARAM_MUTABLE['name']: ActionAPI(**ACTION_OVR_PARAM_MUTABLE), ACTION_OVR_PARAM_IMMUTABLE['name']: ActionAPI(**ACTION_OVR_PARAM_IMMUTABLE), ACTION_OVR_PARAM_BAD_ATTR['name']: ActionAPI(**ACTION_OVR_PARAM_BAD_ATTR), ACTION_OVR_PARAM_BAD_ATTR_NOOP['name']: ActionAPI(**ACTION_OVR_PARAM_BAD_ATTR_NOOP) } cls.actiondbs = {name: Action.add_or_update(ActionAPI.to_model(action)) for name, action in six.iteritems(cls.actions)} cls.container = RunnerContainer()
def _create_save_action(runnertype, metadata=False): name = 'action-1' pack = 'wolfpack' ref = ResourceReference(pack=pack, name=name).ref created = ActionDB(name=name, description='awesomeness', enabled=True, entry_point='/tmp/action.py', pack=pack, ref=ref, runner_type={'name': runnertype.name}) if not metadata: created.parameters = { 'p1': None, 'p2': None, 'p3': None, 'p4': None } else: created.parameters = { 'p1': { 'type': 'string', 'required': True }, 'p2': { 'type': 'number', 'default': 2868 }, 'p3': { 'type': 'boolean', 'default': False }, 'p4': { 'type': 'string', 'secret': True } } return Action.add_or_update(created)
def get_action_by_ref(ref, only_fields: Optional[List[str]] = None): """ Returns the action object from db given a string ref. :param ref: Reference to the trigger type db object. :type ref: ``str`` :param: only_field: Optional lists if fields to retrieve. If not specified, it defaults to all fields. :rtype action: ``object`` """ try: return Action.get_by_ref(ref, only_fields=only_fields) except ValueError as e: LOG.debug( 'Database lookup for ref="%s" resulted ' + "in exception : %s.", ref, e, exc_info=True, ) return None
def post(self, action): """ Create a new action. Handles requests: POST /actions/ """ if not hasattr(action, 'pack'): setattr(action, 'pack', DEFAULT_PACK_NAME) # Perform validation validate_not_part_of_system_pack(action) action_validator.validate_action(action) # Write pack data files to disk (if any are provided) data_files = getattr(action, 'data_files', []) written_data_files = [] if data_files: written_data_files = self._handle_data_files(pack_name=action.pack, data_files=data_files) action_model = ActionAPI.to_model(action) LOG.debug('/actions/ POST verified ActionAPI object=%s', action) action_db = Action.add_or_update(action_model) LOG.debug('/actions/ POST saved ActionDB object=%s', action_db) # Dispatch an internal trigger for each written data file. This way user # automate comitting this files to git using StackStorm rule if written_data_files: self._dispatch_trigger_for_written_data_files(action_db=action_db, written_data_files=written_data_files) extra = {'acion_db': action_db} LOG.audit('Action created. Action.id=%s' % (action_db.id), extra=extra) action_api = ActionAPI.from_model(action_db) return action_api
def _register_action(self, pack, action): content = self._meta_loader.load(action) pack_field = content.get('pack', None) if not pack_field: content['pack'] = pack pack_field = pack if pack_field != pack: raise Exception( 'Model is in pack "%s" but field "pack" is different: %s' % (pack, pack_field)) action_api = ActionAPI(**content) action_api.validate() action_validator.validate_action(action_api) model = ActionAPI.to_model(action_api) action_ref = ResourceReference.to_string_reference( pack=pack, name=str(content['name'])) existing = action_utils.get_action_by_ref(action_ref) if not existing: LOG.debug('Action %s not found. Creating new one with: %s', action_ref, content) else: LOG.debug('Action %s found. Will be updated from: %s to: %s', action_ref, existing, model) model.id = existing.id try: model = Action.add_or_update(model) extra = {'action_db': model} LOG.audit('Action updated. Action %s from %s.', model, action, extra=extra) except Exception: LOG.exception('Failed to write action to db %s.', model.name) raise
def put(self, action_ref_or_id, action): try: action_db = self._get_by_ref_or_id(ref_or_id=action_ref_or_id) except Exception as e: LOG.exception(e.message) abort(http_client.NOT_FOUND, e.message) return action_id = action_db.id try: validate_not_part_of_system_pack(action_db) except ValueValidationException as e: abort(http_client.BAD_REQUEST, str(e)) if not getattr(action, 'pack', None): action.pack = action_db.pack try: action_validator.validate_action(action) except ValueValidationException as e: abort(http_client.BAD_REQUEST, str(e)) return try: action_db = ActionAPI.to_model(action) action_db.id = action_id action_db = Action.add_or_update(action_db) except (ValidationError, ValueError) as e: LOG.exception('Unable to update action data=%s', action) abort(http_client.BAD_REQUEST, str(e)) return action_api = ActionAPI.from_model(action_db) LOG.debug('PUT /actions/ client_result=%s', action_api) return action_api
def setUp(self): super(ExecutionPermissionsResolverTestCase, self).setUp() # Create some mock users user_1_db = UserDB(name='custom_role_unrelated_pack_action_grant') user_1_db = User.add_or_update(user_1_db) self.users['custom_role_unrelated_pack_action_grant'] = user_1_db user_2_db = UserDB( name='custom_role_pack_action_grant_unrelated_permission') user_2_db = User.add_or_update(user_2_db) self.users[ 'custom_role_pack_action_grant_unrelated_permission'] = user_2_db user_3_db = UserDB(name='custom_role_pack_action_view_grant') user_3_db = User.add_or_update(user_3_db) self.users['custom_role_pack_action_view_grant'] = user_3_db user_4_db = UserDB(name='custom_role_action_view_grant') user_4_db = User.add_or_update(user_4_db) self.users['custom_role_action_view_grant'] = user_4_db user_5_db = UserDB(name='custom_role_pack_action_execute_grant') user_5_db = User.add_or_update(user_5_db) self.users['custom_role_pack_action_execute_grant'] = user_5_db user_6_db = UserDB(name='custom_role_action_execute_grant') user_6_db = User.add_or_update(user_6_db) self.users['custom_role_action_execute_grant'] = user_6_db user_7_db = UserDB(name='custom_role_pack_action_all_grant') user_7_db = User.add_or_update(user_7_db) self.users['custom_role_pack_action_all_grant'] = user_7_db user_8_db = UserDB(name='custom_role_action_all_grant') user_8_db = User.add_or_update(user_8_db) self.users['custom_role_action_all_grant'] = user_8_db user_9_db = UserDB(name='custom_role_execution_list_grant') user_9_db = User.add_or_update(user_5_db) self.users['custom_role_execution_list_grant'] = user_9_db # Create some mock resources on which permissions can be granted action_1_db = ActionDB(pack='test_pack_2', name='action1', entry_point='', runner_type={'name': 'run-local'}) action_1_db = Action.add_or_update(action_1_db) self.resources['action_1'] = action_1_db runner = {'name': 'run-python'} liveaction = {'action': 'test_pack_2.action1'} status = action_constants.LIVEACTION_STATUS_REQUESTED action = {'uid': action_1_db.get_uid(), 'pack': 'test_pack_2'} exec_1_db = ActionExecutionDB(action=action, runner=runner, liveaction=liveaction, status=status) exec_1_db = ActionExecution.add_or_update(exec_1_db) self.resources['exec_1'] = exec_1_db # Create some mock roles with associated permission grants # Custom role - one grant to an unrelated pack grant_db = PermissionGrantDB( resource_uid=self.resources['pack_1'].get_uid(), resource_type=ResourceType.PACK, permission_types=[PermissionType.ACTION_VIEW]) grant_db = PermissionGrant.add_or_update(grant_db) permission_grants = [str(grant_db.id)] role_db = RoleDB(name='custom_role_unrelated_pack_action_grant', permission_grants=permission_grants) role_db = Role.add_or_update(role_db) self.roles['custom_role_unrelated_pack_action_grant'] = role_db # Custom role - one grant of unrelated permission type to parent action pack grant_db = PermissionGrantDB( resource_uid=self.resources['pack_2'].get_uid(), resource_type=ResourceType.PACK, permission_types=[PermissionType.RULE_VIEW]) grant_db = PermissionGrant.add_or_update(grant_db) permission_grants = [str(grant_db.id)] role_db = RoleDB( name='custom_role_pack_action_grant_unrelated_permission', permission_grants=permission_grants) role_db = Role.add_or_update(role_db) self.roles[ 'custom_role_pack_action_grant_unrelated_permission'] = role_db # Custom role - one grant of "action_view" to the parent pack of the action the execution # belongs to grant_db = PermissionGrantDB( resource_uid=self.resources['pack_2'].get_uid(), resource_type=ResourceType.PACK, permission_types=[PermissionType.ACTION_VIEW]) grant_db = PermissionGrant.add_or_update(grant_db) permission_grants = [str(grant_db.id)] role_db = RoleDB(name='custom_role_pack_action_view_grant', permission_grants=permission_grants) role_db = Role.add_or_update(role_db) self.roles['custom_role_pack_action_view_grant'] = role_db # Custom role - one grant of "action_view" to the action the execution belongs to grant_db = PermissionGrantDB( resource_uid=self.resources['action_1'].get_uid(), resource_type=ResourceType.ACTION, permission_types=[PermissionType.ACTION_VIEW]) grant_db = PermissionGrant.add_or_update(grant_db) permission_grants = [str(grant_db.id)] role_db = RoleDB(name='custom_role_action_view_grant', permission_grants=permission_grants) role_db = Role.add_or_update(role_db) self.roles['custom_role_action_view_grant'] = role_db # Custom role - one grant of "action_execute" to the parent pack of the action the # execution belongs to grant_db = PermissionGrantDB( resource_uid=self.resources['pack_2'].get_uid(), resource_type=ResourceType.PACK, permission_types=[PermissionType.ACTION_EXECUTE]) grant_db = PermissionGrant.add_or_update(grant_db) permission_grants = [str(grant_db.id)] role_db = RoleDB(name='custom_role_pack_action_execute_grant', permission_grants=permission_grants) role_db = Role.add_or_update(role_db) self.roles['custom_role_pack_action_execute_grant'] = role_db # Custom role - one grant of "action_execute" to the the action the execution belongs to grant_db = PermissionGrantDB( resource_uid=self.resources['action_1'].get_uid(), resource_type=ResourceType.ACTION, permission_types=[PermissionType.ACTION_EXECUTE]) grant_db = PermissionGrant.add_or_update(grant_db) permission_grants = [str(grant_db.id)] role_db = RoleDB(name='custom_role_action_execute_grant', permission_grants=permission_grants) role_db = Role.add_or_update(role_db) self.roles['custom_role_action_execute_grant'] = role_db # Custom role - "action_all" grant on a parent action pack the execution belongs to grant_db = PermissionGrantDB( resource_uid=self.resources['pack_2'].get_uid(), resource_type=ResourceType.PACK, permission_types=[PermissionType.ACTION_ALL]) grant_db = PermissionGrant.add_or_update(grant_db) permission_grants = [str(grant_db.id)] role_4_db = RoleDB(name='custom_role_pack_action_all_grant', permission_grants=permission_grants) role_4_db = Role.add_or_update(role_4_db) self.roles['custom_role_pack_action_all_grant'] = role_4_db # Custom role - "action_all" grant on action the execution belongs to grant_db = PermissionGrantDB( resource_uid=self.resources['action_1'].get_uid(), resource_type=ResourceType.ACTION, permission_types=[PermissionType.ACTION_ALL]) grant_db = PermissionGrant.add_or_update(grant_db) permission_grants = [str(grant_db.id)] role_4_db = RoleDB(name='custom_role_action_all_grant', permission_grants=permission_grants) role_4_db = Role.add_or_update(role_4_db) self.roles['custom_role_action_all_grant'] = role_4_db # Custom role - "execution_list" grant grant_db = PermissionGrantDB( resource_uid=None, resource_type=None, permission_types=[PermissionType.EXECUTION_LIST]) grant_db = PermissionGrant.add_or_update(grant_db) permission_grants = [str(grant_db.id)] role_5_db = RoleDB(name='custom_role_execution_list_grant', permission_grants=permission_grants) role_5_db = Role.add_or_update(role_5_db) self.roles['custom_role_execution_list_grant'] = role_5_db # Create some mock role assignments user_db = self.users['custom_role_unrelated_pack_action_grant'] role_assignment_db = UserRoleAssignmentDB( user=user_db.name, role=self.roles['custom_role_unrelated_pack_action_grant'].name, source='assignments/%s.yaml' % user_db.name) UserRoleAssignment.add_or_update(role_assignment_db) user_db = self.users[ 'custom_role_pack_action_grant_unrelated_permission'] role_assignment_db = UserRoleAssignmentDB( user=user_db.name, role=self. roles['custom_role_pack_action_grant_unrelated_permission'].name, source='assignments/%s.yaml' % user_db.name) UserRoleAssignment.add_or_update(role_assignment_db) user_db = self.users['custom_role_pack_action_view_grant'] role_assignment_db = UserRoleAssignmentDB( user=user_db.name, role=self.roles['custom_role_pack_action_view_grant'].name, source='assignments/%s.yaml' % user_db.name) UserRoleAssignment.add_or_update(role_assignment_db) user_db = self.users['custom_role_action_view_grant'] role_assignment_db = UserRoleAssignmentDB( user=user_db.name, role=self.roles['custom_role_action_view_grant'].name, source='assignments/%s.yaml' % user_db.name) UserRoleAssignment.add_or_update(role_assignment_db) user_db = self.users['custom_role_pack_action_execute_grant'] role_assignment_db = UserRoleAssignmentDB( user=user_db.name, role=self.roles['custom_role_pack_action_execute_grant'].name, source='assignments/%s.yaml' % user_db.name) UserRoleAssignment.add_or_update(role_assignment_db) user_db = self.users['custom_role_action_execute_grant'] role_assignment_db = UserRoleAssignmentDB( user=user_db.name, role=self.roles['custom_role_action_execute_grant'].name, source='assignments/%s.yaml' % user_db.name) UserRoleAssignment.add_or_update(role_assignment_db) user_db = self.users['custom_role_pack_action_all_grant'] role_assignment_db = UserRoleAssignmentDB( user=user_db.name, role=self.roles['custom_role_pack_action_all_grant'].name, source='assignments/%s.yaml' % user_db.name) UserRoleAssignment.add_or_update(role_assignment_db) user_db = self.users['custom_role_action_all_grant'] role_assignment_db = UserRoleAssignmentDB( user=user_db.name, role=self.roles['custom_role_action_all_grant'].name, source='assignments/%s.yaml' % user_db.name) UserRoleAssignment.add_or_update(role_assignment_db) user_db = self.users['custom_role_execution_list_grant'] role_assignment_db = UserRoleAssignmentDB( user=user_db.name, role=self.roles['custom_role_execution_list_grant'].name, source='assignments/%s.yaml' % user_db.name) UserRoleAssignment.add_or_update(role_assignment_db)
def setUp(self): super(InquiryPermissionsResolverTestCase, self).setUp() # Create some mock users user_1_db = UserDB(name='custom_role_inquiry_list_grant') user_1_db = User.add_or_update(user_1_db) self.users['custom_role_inquiry_list_grant'] = user_1_db user_2_db = UserDB(name='custom_role_inquiry_view_grant') user_2_db = User.add_or_update(user_2_db) self.users['custom_role_inquiry_view_grant'] = user_2_db user_3_db = UserDB(name='custom_role_inquiry_respond_grant') user_3_db = User.add_or_update(user_3_db) self.users['custom_role_inquiry_respond_grant'] = user_3_db user_4_db = UserDB(name='custom_role_inquiry_all_grant') user_4_db = User.add_or_update(user_4_db) self.users['custom_role_inquiry_all_grant'] = user_4_db user_5_db = UserDB(name='custom_role_inquiry_inherit') user_5_db = User.add_or_update(user_5_db) self.users['custom_role_inquiry_inherit'] = user_5_db # Create a workflow for testing inheritance of action_execute permission # to inquiry_respond permission wf_db = ActionDB(pack='examples', name='mistral-ask-basic', entry_point='', runner_type={'name': 'mistral-v2'}) wf_db = Action.add_or_update(wf_db) self.resources['wf'] = wf_db runner = {'name': 'mistral-v2'} liveaction = {'action': 'examples.mistral-ask-basic'} status = action_constants.LIVEACTION_STATUS_PAUSED # Spawn workflow action = {'uid': wf_db.get_uid(), 'pack': 'examples'} wf_exc_db = ActionExecutionDB(action=action, runner=runner, liveaction=liveaction, status=status) wf_exc_db = ActionExecution.add_or_update(wf_exc_db) # Create an Inquiry on which permissions can be granted action_1_db = ActionDB(pack='core', name='ask', entry_point='', runner_type={'name': 'inquirer'}) action_1_db = Action.add_or_update(action_1_db) self.resources['action_1'] = action_1_db runner = {'name': 'inquirer'} liveaction = {'action': 'core.ask'} status = action_constants.LIVEACTION_STATUS_PENDING # For now, Inquiries are "borrowing" the ActionExecutionDB model, # so we have to test with that model action = {'uid': action_1_db.get_uid(), 'pack': 'core'} inquiry_1_db = ActionExecutionDB(action=action, runner=runner, liveaction=liveaction, status=status) # A separate inquiry that has a parent (so we can test workflow permission inheritance) inquiry_2_db = ActionExecutionDB(action=action, runner=runner, liveaction=liveaction, status=status, parent=str(wf_exc_db.id)) # A bit gross, but it's what we have to do since Inquiries # don't yet have their own data model def get_uid(): return "inquiry" inquiry_1_db.get_uid = get_uid inquiry_2_db.get_uid = get_uid inquiry_1_db = ActionExecution.add_or_update(inquiry_1_db) inquiry_2_db = ActionExecution.add_or_update(inquiry_2_db) self.resources['inquiry_1'] = inquiry_1_db self.resources['inquiry_2'] = inquiry_2_db ############################################################ # Create some mock roles with associated permission grants # ############################################################ # Custom role - "inquiry_list" grant grant_db = PermissionGrantDB( resource_uid=self.resources['inquiry_1'].get_uid(), resource_type=ResourceType.INQUIRY, permission_types=[PermissionType.INQUIRY_LIST]) grant_db = PermissionGrant.add_or_update(grant_db) permission_grants = [str(grant_db.id)] role_db = RoleDB(name='custom_role_inquiry_list_grant', permission_grants=permission_grants) role_db = Role.add_or_update(role_db) self.roles['custom_role_inquiry_list_grant'] = role_db # Custom role - "inquiry_view" grant grant_db = PermissionGrantDB( resource_uid=self.resources['inquiry_1'].get_uid(), resource_type=ResourceType.INQUIRY, permission_types=[PermissionType.INQUIRY_VIEW]) grant_db = PermissionGrant.add_or_update(grant_db) permission_grants = [str(grant_db.id)] role_db = RoleDB(name='custom_role_inquiry_view_grant', permission_grants=permission_grants) role_db = Role.add_or_update(role_db) self.roles['custom_role_inquiry_view_grant'] = role_db # Custom role - "inquiry_respond" grant grant_db = PermissionGrantDB( resource_uid=self.resources['inquiry_1'].get_uid(), resource_type=ResourceType.INQUIRY, permission_types=[PermissionType.INQUIRY_RESPOND]) grant_db = PermissionGrant.add_or_update(grant_db) permission_grants = [str(grant_db.id)] role_db = RoleDB(name='custom_role_inquiry_respond_grant', permission_grants=permission_grants) role_db = Role.add_or_update(role_db) self.roles['custom_role_inquiry_respond_grant'] = role_db # Custom role - "inquiry_all" grant grant_db = PermissionGrantDB( resource_uid=self.resources['inquiry_1'].get_uid(), resource_type=ResourceType.INQUIRY, permission_types=[PermissionType.INQUIRY_ALL]) grant_db = PermissionGrant.add_or_update(grant_db) permission_grants = [str(grant_db.id)] role_db = RoleDB(name='custom_role_inquiry_all_grant', permission_grants=permission_grants) role_db = Role.add_or_update(role_db) self.roles['custom_role_inquiry_all_grant'] = role_db # Custom role - inheritance grant grant_db = PermissionGrantDB( resource_uid=self.resources['wf'].get_uid(), resource_type=ResourceType.ACTION, permission_types=[PermissionType.ACTION_EXECUTE]) grant_db = PermissionGrant.add_or_update(grant_db) permission_grants = [str(grant_db.id)] role_db = RoleDB(name='custom_role_inquiry_inherit', permission_grants=permission_grants) role_db = Role.add_or_update(role_db) self.roles['custom_role_inquiry_inherit'] = role_db ##################################### # Create some mock role assignments # ##################################### user_db = self.users['custom_role_inquiry_list_grant'] role_assignment_db = UserRoleAssignmentDB( user=user_db.name, role=self.roles['custom_role_inquiry_list_grant'].name, source='assignments/%s.yaml' % user_db.name) UserRoleAssignment.add_or_update(role_assignment_db) user_db = self.users['custom_role_inquiry_view_grant'] role_assignment_db = UserRoleAssignmentDB( user=user_db.name, role=self.roles['custom_role_inquiry_view_grant'].name, source='assignments/%s.yaml' % user_db.name) UserRoleAssignment.add_or_update(role_assignment_db) user_db = self.users['custom_role_inquiry_respond_grant'] role_assignment_db = UserRoleAssignmentDB( user=user_db.name, role=self.roles['custom_role_inquiry_respond_grant'].name, source='assignments/%s.yaml' % user_db.name) UserRoleAssignment.add_or_update(role_assignment_db) user_db = self.users['custom_role_inquiry_all_grant'] role_assignment_db = UserRoleAssignmentDB( user=user_db.name, role=self.roles['custom_role_inquiry_all_grant'].name, source='assignments/%s.yaml' % user_db.name) UserRoleAssignment.add_or_update(role_assignment_db) user_db = self.users['custom_role_inquiry_inherit'] role_assignment_db = UserRoleAssignmentDB( user=user_db.name, role=self.roles['custom_role_inquiry_inherit'].name, source='assignments/%s.yaml' % user_db.name) UserRoleAssignment.add_or_update(role_assignment_db)
def setUpClass(cls): super(DSLTransformTestCase, cls).setUpClass() runners_registrar.register_runner_types() action_local = ActionAPI( **copy.deepcopy(FIXTURES['actions']['local.json'])) Action.add_or_update(ActionAPI.to_model(action_local))
def setUp(self): super(ActionPermissionsResolverTestCase, self).setUp() # Create some mock users user_1_db = UserDB(name='1_role_action_pack_grant') user_1_db = User.add_or_update(user_1_db) self.users['custom_role_action_pack_grant'] = user_1_db user_2_db = UserDB(name='1_role_action_grant') user_2_db = User.add_or_update(user_2_db) self.users['custom_role_action_grant'] = user_2_db user_3_db = UserDB(name='custom_role_pack_action_all_grant') user_3_db = User.add_or_update(user_3_db) self.users['custom_role_pack_action_all_grant'] = user_3_db user_4_db = UserDB(name='custom_role_action_all_grant') user_4_db = User.add_or_update(user_4_db) self.users['custom_role_action_all_grant'] = user_4_db user_5_db = UserDB(name='custom_role_action_execute_grant') user_5_db = User.add_or_update(user_5_db) self.users['custom_role_action_execute_grant'] = user_5_db user_6_db = UserDB(name='action_pack_action_create_grant') user_6_db = User.add_or_update(user_6_db) self.users['action_pack_action_create_grant'] = user_6_db user_7_db = UserDB(name='action_pack_action_all_grant') user_7_db = User.add_or_update(user_7_db) self.users['action_pack_action_all_grant'] = user_7_db user_8_db = UserDB(name='action_action_create_grant') user_8_db = User.add_or_update(user_8_db) self.users['action_action_create_grant'] = user_8_db user_9_db = UserDB(name='action_action_all_grant') user_9_db = User.add_or_update(user_9_db) self.users['action_action_all_grant'] = user_9_db user_10_db = UserDB(name='custom_role_action_list_grant') user_10_db = User.add_or_update(user_10_db) self.users['custom_role_action_list_grant'] = user_10_db # Create some mock resources on which permissions can be granted action_1_db = ActionDB(pack='test_pack_1', name='action1', entry_point='', runner_type={'name': 'local-shell-cmd'}) action_1_db = Action.add_or_update(action_1_db) self.resources['action_1'] = action_1_db action_2_db = ActionDB(pack='test_pack_1', name='action2', entry_point='', runner_type={'name': 'local-shell-cmd'}) action_2_db = Action.add_or_update(action_1_db) self.resources['action_2'] = action_2_db action_3_db = ActionDB(pack='test_pack_2', name='action3', entry_point='', runner_type={'name': 'local-shell-cmd'}) action_3_db = Action.add_or_update(action_3_db) self.resources['action_3'] = action_3_db # Create some mock roles with associated permission grants # Custom role 2 - one grant on parent pack # "action_view" on pack_1 grant_db = PermissionGrantDB(resource_uid=self.resources['pack_1'].get_uid(), resource_type=ResourceType.PACK, permission_types=[PermissionType.ACTION_VIEW]) grant_db = PermissionGrant.add_or_update(grant_db) permission_grants = [str(grant_db.id)] role_3_db = RoleDB(name='custom_role_action_pack_grant', permission_grants=permission_grants) role_3_db = Role.add_or_update(role_3_db) self.roles['custom_role_action_pack_grant'] = role_3_db # Custom role 4 - one grant on action # "action_view" on action_3 grant_db = PermissionGrantDB(resource_uid=self.resources['action_3'].get_uid(), resource_type=ResourceType.ACTION, permission_types=[PermissionType.ACTION_VIEW]) grant_db = PermissionGrant.add_or_update(grant_db) permission_grants = [str(grant_db.id)] role_4_db = RoleDB(name='custom_role_action_grant', permission_grants=permission_grants) role_4_db = Role.add_or_update(role_4_db) self.roles['custom_role_action_grant'] = role_4_db # Custom role - "action_all" grant on a parent action pack grant_db = PermissionGrantDB(resource_uid=self.resources['pack_1'].get_uid(), resource_type=ResourceType.PACK, permission_types=[PermissionType.ACTION_ALL]) grant_db = PermissionGrant.add_or_update(grant_db) permission_grants = [str(grant_db.id)] role_4_db = RoleDB(name='custom_role_pack_action_all_grant', permission_grants=permission_grants) role_4_db = Role.add_or_update(role_4_db) self.roles['custom_role_pack_action_all_grant'] = role_4_db # Custom role - "action_all" grant on action grant_db = PermissionGrantDB(resource_uid=self.resources['action_1'].get_uid(), resource_type=ResourceType.ACTION, permission_types=[PermissionType.ACTION_ALL]) grant_db = PermissionGrant.add_or_update(grant_db) permission_grants = [str(grant_db.id)] role_4_db = RoleDB(name='custom_role_action_all_grant', permission_grants=permission_grants) role_4_db = Role.add_or_update(role_4_db) self.roles['custom_role_action_all_grant'] = role_4_db # Custom role - "action_execute" on action_1 grant_db = PermissionGrantDB(resource_uid=self.resources['action_1'].get_uid(), resource_type=ResourceType.ACTION, permission_types=[PermissionType.ACTION_EXECUTE]) grant_db = PermissionGrant.add_or_update(grant_db) permission_grants = [str(grant_db.id)] role_5_db = RoleDB(name='custom_role_action_execute_grant', permission_grants=permission_grants) role_5_db = Role.add_or_update(role_5_db) self.roles['custom_role_action_execute_grant'] = role_5_db # Custom role - "action_create" grant on pack_1 grant_db = PermissionGrantDB(resource_uid=self.resources['pack_1'].get_uid(), resource_type=ResourceType.PACK, permission_types=[PermissionType.ACTION_CREATE]) grant_db = PermissionGrant.add_or_update(grant_db) permission_grants = [str(grant_db.id)] role_6_db = RoleDB(name='action_pack_action_create_grant', permission_grants=permission_grants) role_6_db = Role.add_or_update(role_6_db) self.roles['action_pack_action_create_grant'] = role_6_db # Custom role - "action_all" grant on pack_1 grant_db = PermissionGrantDB(resource_uid=self.resources['pack_1'].get_uid(), resource_type=ResourceType.PACK, permission_types=[PermissionType.ACTION_ALL]) grant_db = PermissionGrant.add_or_update(grant_db) permission_grants = [str(grant_db.id)] role_7_db = RoleDB(name='action_pack_action_all_grant', permission_grants=permission_grants) role_7_db = Role.add_or_update(role_7_db) self.roles['action_pack_action_all_grant'] = role_7_db # Custom role - "action_create" grant on action_1 grant_db = PermissionGrantDB(resource_uid=self.resources['action_1'].get_uid(), resource_type=ResourceType.ACTION, permission_types=[PermissionType.ACTION_CREATE]) grant_db = PermissionGrant.add_or_update(grant_db) permission_grants = [str(grant_db.id)] role_8_db = RoleDB(name='action_action_create_grant', permission_grants=permission_grants) role_8_db = Role.add_or_update(role_8_db) self.roles['action_action_create_grant'] = role_8_db # Custom role - "action_all" grant on action_1 grant_db = PermissionGrantDB(resource_uid=self.resources['action_1'].get_uid(), resource_type=ResourceType.ACTION, permission_types=[PermissionType.ACTION_ALL]) grant_db = PermissionGrant.add_or_update(grant_db) permission_grants = [str(grant_db.id)] role_9_db = RoleDB(name='action_action_all_grant', permission_grants=permission_grants) role_9_db = Role.add_or_update(role_9_db) self.roles['action_action_all_grant'] = role_9_db # Custom role - "action_list" grant grant_db = PermissionGrantDB(resource_uid=None, resource_type=None, permission_types=[PermissionType.ACTION_LIST]) grant_db = PermissionGrant.add_or_update(grant_db) permission_grants = [str(grant_db.id)] role_10_db = RoleDB(name='custom_role_action_list_grant', permission_grants=permission_grants) role_10_db = Role.add_or_update(role_10_db) self.roles['custom_role_action_list_grant'] = role_10_db # Create some mock role assignments user_db = self.users['custom_role_action_pack_grant'] role_assignment_db = UserRoleAssignmentDB( user=user_db.name, role=self.roles['custom_role_action_pack_grant'].name, source='assignments/%s.yaml' % user_db.name) UserRoleAssignment.add_or_update(role_assignment_db) user_db = self.users['custom_role_action_grant'] role_assignment_db = UserRoleAssignmentDB( user=user_db.name, role=self.roles['custom_role_action_grant'].name, source='assignments/%s.yaml' % user_db.name) UserRoleAssignment.add_or_update(role_assignment_db) user_db = self.users['custom_role_pack_action_all_grant'] role_assignment_db = UserRoleAssignmentDB( user=user_db.name, role=self.roles['custom_role_pack_action_all_grant'].name, source='assignments/%s.yaml' % user_db.name) UserRoleAssignment.add_or_update(role_assignment_db) user_db = self.users['custom_role_action_all_grant'] role_assignment_db = UserRoleAssignmentDB( user=user_db.name, role=self.roles['custom_role_action_all_grant'].name, source='assignments/%s.yaml' % user_db.name) UserRoleAssignment.add_or_update(role_assignment_db) user_db = self.users['custom_role_action_execute_grant'] role_assignment_db = UserRoleAssignmentDB( user=user_db.name, role=self.roles['custom_role_action_execute_grant'].name, source='assignments/%s.yaml' % user_db.name) UserRoleAssignment.add_or_update(role_assignment_db) user_db = self.users['action_pack_action_create_grant'] role_assignment_db = UserRoleAssignmentDB( user=user_db.name, role=self.roles['action_pack_action_create_grant'].name, source='assignments/%s.yaml' % user_db.name) UserRoleAssignment.add_or_update(role_assignment_db) user_db = self.users['action_pack_action_all_grant'] role_assignment_db = UserRoleAssignmentDB( user=user_db.name, role=self.roles['action_pack_action_all_grant'].name, source='assignments/%s.yaml' % user_db.name) UserRoleAssignment.add_or_update(role_assignment_db) user_db = self.users['action_action_create_grant'] role_assignment_db = UserRoleAssignmentDB( user=user_db.name, role=self.roles['action_action_create_grant'].name, source='assignments/%s.yaml' % user_db.name) UserRoleAssignment.add_or_update(role_assignment_db) user_db = self.users['action_action_all_grant'] role_assignment_db = UserRoleAssignmentDB( user=user_db.name, role=self.roles['action_action_all_grant'].name, source='assignments/%s.yaml' % user_db.name) UserRoleAssignment.add_or_update(role_assignment_db) user_db = self.users['custom_role_action_list_grant'] role_assignment_db = UserRoleAssignmentDB( user=user_db.name, role=self.roles['custom_role_action_list_grant'].name, source='assignments/%s.yaml' % user_db.name) UserRoleAssignment.add_or_update(role_assignment_db)
def setUpClass(cls): super(ExecutionCancellationTest, cls).setUpClass() runners_registrar.register_runners() action_local = ActionAPI( **copy.deepcopy(fixture.ARTIFACTS['actions']['local'])) Action.add_or_update(ActionAPI.to_model(action_local))
def _get_runner(self, action_ref): action = Action.get_by_ref(action_ref) return action['runner_type']['name']
def tearDownClass(cls): Action.delete(cls.actiondb) RunnerType.delete(cls.runnerdb) super(TestActionExecutionService, cls).tearDownClass()
def test_packs_register_endpoint(self, mock_get_packs): # Register resources from all packs - make sure the count values are correctly added # together # Note: We only register a couple of packs and not all on disk to speed # things up. Registering all the packs takes a long time. fixtures_base_path = get_fixtures_base_path() packs_base_path = os.path.join(fixtures_base_path, "packs") pack_names = [ "dummy_pack_1", "dummy_pack_10", ] mock_return_value = {} for pack_name in pack_names: mock_return_value[pack_name] = os.path.join( packs_base_path, pack_name) mock_get_packs.return_value = mock_return_value resp = self.app.post_json("/v1/packs/register", {"fail_on_failure": False}) self.assertEqual(resp.status_int, 200) self.assertIn("runners", resp.json) self.assertIn("actions", resp.json) self.assertIn("triggers", resp.json) self.assertIn("sensors", resp.json) self.assertIn("rules", resp.json) self.assertIn("rule_types", resp.json) self.assertIn("aliases", resp.json) self.assertIn("policy_types", resp.json) self.assertIn("policies", resp.json) self.assertIn("configs", resp.json) self.assertTrue(resp.json["actions"] >= 3) self.assertTrue(resp.json["configs"] >= 1) # Register resources from a specific pack resp = self.app.post_json("/v1/packs/register", { "packs": ["dummy_pack_1"], "fail_on_failure": False }) self.assertEqual(resp.status_int, 200) self.assertTrue(resp.json["actions"] >= 1) self.assertTrue(resp.json["sensors"] >= 1) self.assertTrue(resp.json["configs"] >= 1) # Verify metadata_file attribute is set action_dbs = Action.query(pack="dummy_pack_1") self.assertEqual(action_dbs[0].metadata_file, "actions/my_action.yaml") # Register 'all' resource types should try include any possible content for the pack resp = self.app.post_json( "/v1/packs/register", { "packs": ["dummy_pack_1"], "fail_on_failure": False, "types": ["all"] }, ) self.assertEqual(resp.status_int, 200) self.assertIn("runners", resp.json) self.assertIn("actions", resp.json) self.assertIn("triggers", resp.json) self.assertIn("sensors", resp.json) self.assertIn("rules", resp.json) self.assertIn("rule_types", resp.json) self.assertIn("aliases", resp.json) self.assertIn("policy_types", resp.json) self.assertIn("policies", resp.json) self.assertIn("configs", resp.json) # Registering single resource type should also cause dependent resources # to be registered # * actions -> runners # * rules -> rule types # * policies -> policy types resp = self.app.post_json( "/v1/packs/register", { "packs": ["dummy_pack_1"], "fail_on_failure": False, "types": ["actions"] }, ) self.assertEqual(resp.status_int, 200) self.assertTrue(resp.json["runners"] >= 1) self.assertTrue(resp.json["actions"] >= 1) resp = self.app.post_json( "/v1/packs/register", { "packs": ["dummy_pack_1"], "fail_on_failure": False, "types": ["rules"] }, ) self.assertEqual(resp.status_int, 200) self.assertTrue(resp.json["rule_types"] >= 1) self.assertTrue(resp.json["rules"] >= 1) resp = self.app.post_json( "/v1/packs/register", { "packs": ["dummy_pack_2"], "fail_on_failure": False, "types": ["policies"], }, ) self.assertEqual(resp.status_int, 200) self.assertTrue(resp.json["policy_types"] >= 1) self.assertTrue(resp.json["policies"] >= 0) # Register specific type for all packs resp = self.app.post_json("/v1/packs/register", { "types": ["sensor"], "fail_on_failure": False }) self.assertEqual(resp.status_int, 200) self.assertEqual(resp.json, {"sensors": 3}) # Verify that plural name form also works resp = self.app.post_json("/v1/packs/register", { "types": ["sensors"], "fail_on_failure": False }) self.assertEqual(resp.status_int, 200) # Register specific type for a single packs resp = self.app.post_json("/v1/packs/register", { "packs": ["dummy_pack_1"], "types": ["action"] }) self.assertEqual(resp.status_int, 200) # 13 real plus 1 mock runner self.assertEqual(resp.json, {"actions": 3, "runners": 14}) # Verify that plural name form also works resp = self.app.post_json("/v1/packs/register", { "packs": ["dummy_pack_1"], "types": ["actions"] }) self.assertEqual(resp.status_int, 200) # 13 real plus 1 mock runner self.assertEqual(resp.json, {"actions": 3, "runners": 14}) # Register single resource from a single pack specified multiple times - verify that # resources from the same pack are only registered once resp = self.app.post_json( "/v1/packs/register", { "packs": ["dummy_pack_1", "dummy_pack_1", "dummy_pack_1"], "types": ["actions"], "fail_on_failure": False, }, ) self.assertEqual(resp.status_int, 200) # 13 real plus 1 mock runner self.assertEqual(resp.json, {"actions": 3, "runners": 14}) # Register resources from a single (non-existent pack) resp = self.app.post_json("/v1/packs/register", {"packs": ["doesntexist"]}, expect_errors=True) self.assertEqual(resp.status_int, 400) self.assertIn('Pack "doesntexist" not found on disk:', resp.json["faultstring"]) # Fail on failure is enabled by default resp = self.app.post_json("/v1/packs/register", expect_errors=True) expected_msg = 'Failed to register pack "dummy_pack_10":' self.assertEqual(resp.status_int, 400) self.assertIn(expected_msg, resp.json["faultstring"]) # Fail on failure (broken pack metadata) resp = self.app.post_json("/v1/packs/register", {"packs": ["dummy_pack_1"]}, expect_errors=True) expected_msg = 'Referenced policy_type "action.mock_policy_error" doesnt exist' self.assertEqual(resp.status_int, 400) self.assertIn(expected_msg, resp.json["faultstring"]) # Fail on failure (broken action metadata) resp = self.app.post_json("/v1/packs/register", {"packs": ["dummy_pack_15"]}, expect_errors=True) expected_msg = "Failed to register action" self.assertEqual(resp.status_int, 400) self.assertIn(expected_msg, resp.json["faultstring"]) expected_msg = "'stringa' is not valid under any of the given schemas" self.assertEqual(resp.status_int, 400) self.assertIn(expected_msg, resp.json["faultstring"])
def _register_action(self, pack, action): content = self._meta_loader.load(action) pack_field = content.get("pack", None) if not pack_field: content["pack"] = pack pack_field = pack if pack_field != pack: raise Exception( 'Model is in pack "%s" but field "pack" is different: %s' % (pack, pack_field)) # Add in "metadata_file" attribute which stores path to the pack metadata file relative to # the pack directory metadata_file = content_utils.get_relative_path_to_pack_file( pack_ref=pack, file_path=action, use_pack_cache=True) content["metadata_file"] = metadata_file action_api = ActionAPI(**content) try: action_api.validate() except jsonschema.ValidationError as e: # We throw a more user-friendly exception on invalid parameter name msg = six.text_type(e) is_invalid_parameter_name = "does not match any of the regexes: " in msg if is_invalid_parameter_name: match = re.search("'(.+?)' does not match any of the regexes", msg) if match: parameter_name = match.groups()[0] else: parameter_name = "unknown" new_msg = ( 'Parameter name "%s" is invalid. Valid characters for parameter name ' "are [a-zA-Z0-0_]." % (parameter_name)) new_msg += "\n\n" + msg raise jsonschema.ValidationError(new_msg) raise e # Use in-memory cached RunnerTypeDB objects to reduce load on the database if self._use_runners_cache: runner_type_db = self._runner_type_db_cache.get( action_api.runner_type, None) if not runner_type_db: runner_type_db = action_validator.get_runner_model(action_api) self._runner_type_db_cache[ action_api.runner_type] = runner_type_db else: runner_type_db = None action_validator.validate_action(action_api, runner_type_db=runner_type_db) model = ActionAPI.to_model(action_api) action_ref = ResourceReference.to_string_reference( pack=pack, name=str(content["name"])) # NOTE: Here we only retrieve existing object to perform an upsert if it already exists in # the database. To do that, we only need access to the "id" attribute (and ref and pack # for our ActionDB abstraction). Retrieving only those fields is fast and much efficient # especially for actions like aws pack ones which contain a lot of parameters. existing = action_utils.get_action_by_ref( action_ref, only_fields=["id", "ref", "pack"]) if not existing: LOG.debug("Action %s not found. Creating new one with: %s", action_ref, content) else: LOG.debug( "Action %s found. Will be updated from: %s to: %s", action_ref, existing, model, ) model.id = existing.id try: model = Action.add_or_update(model) extra = {"action_db": model} LOG.audit("Action updated. Action %s from %s.", model, action, extra=extra) except Exception: LOG.exception("Failed to write action to db %s.", model.name) raise
def setup_action_models(cls): pack = "wolfpack" name = "action-1" parameters = { "actionint": { "type": "number", "default": 10, "position": 0 }, "actionfloat": { "type": "float", "required": False, "position": 1 }, "actionstr": { "type": "string", "required": True, "position": 2 }, "actionbool": { "type": "boolean", "required": False, "position": 3 }, "actionarray": { "type": "array", "required": False, "position": 4 }, "actionlist": { "type": "list", "required": False, "position": 5 }, "actionobject": { "type": "object", "required": False, "position": 6 }, "actionnull": { "type": "null", "required": False, "position": 7 }, "runnerdummy": { "type": "string", "default": "actiondummy" }, } action_db = ActionDB( pack=pack, name=name, description="awesomeness", enabled=True, ref=ResourceReference(name=name, pack=pack).ref, entry_point="", runner_type={"name": "test-runner"}, parameters=parameters, ) ActionDBUtilsTestCase.action_db = Action.add_or_update(action_db) liveaction_db = LiveActionDB() liveaction_db.status = "initializing" liveaction_db.start_timestamp = get_datetime_utc_now() liveaction_db.action = ActionDBUtilsTestCase.action_db.ref params = { "actionstr": "foo", "some_key_that_aint_exist_in_action_or_runner": "bar", "runnerint": 555, } liveaction_db.parameters = params ActionDBUtilsTestCase.liveaction_db = LiveAction.add_or_update( liveaction_db)
def _register_action(self, pack, action): content = self._meta_loader.load(action) pack_field = content.get('pack', None) if not pack_field: content['pack'] = pack pack_field = pack if pack_field != pack: raise Exception( 'Model is in pack "%s" but field "pack" is different: %s' % (pack, pack_field)) action_api = ActionAPI(**content) try: action_api.validate() except jsonschema.ValidationError as e: # We throw a more user-friendly exception on invalid parameter name msg = str(e) is_invalid_parameter_name = 'does not match any of the regexes: ' in msg if is_invalid_parameter_name: match = re.search( '\'(.+?)\' does not match any of the regexes', msg) if match: parameter_name = match.groups()[0] else: parameter_name = 'unknown' new_msg = ( 'Parameter name "%s" is invalid. Valid characters for parameter name ' 'are [a-zA-Z0-0_].' % (parameter_name)) new_msg += '\n\n' + msg raise jsonschema.ValidationError(new_msg) raise e action_validator.validate_action(action_api) model = ActionAPI.to_model(action_api) action_ref = ResourceReference.to_string_reference( pack=pack, name=str(content['name'])) existing = action_utils.get_action_by_ref(action_ref) if not existing: LOG.debug('Action %s not found. Creating new one with: %s', action_ref, content) else: LOG.debug('Action %s found. Will be updated from: %s to: %s', action_ref, existing, model) model.id = existing.id try: model = Action.add_or_update(model) extra = {'action_db': model} LOG.audit('Action updated. Action %s from %s.', model, action, extra=extra) except Exception: LOG.exception('Failed to write action to db %s.', model.name) raise
def _register_action(self, pack, action): content = self._meta_loader.load(action) pack_field = content.get('pack', None) if not pack_field: content['pack'] = pack pack_field = pack if pack_field != pack: raise Exception( 'Model is in pack "%s" but field "pack" is different: %s' % (pack, pack_field)) # Add in "metadata_file" attribute which stores path to the pack metadata file relative to # the pack directory metadata_file = content_utils.get_relative_path_to_pack_file( pack_ref=pack, file_path=action, use_pack_cache=True) content['metadata_file'] = metadata_file action_api = ActionAPI(**content) try: action_api.validate() except jsonschema.ValidationError as e: # We throw a more user-friendly exception on invalid parameter name msg = six.text_type(e) is_invalid_parameter_name = 'does not match any of the regexes: ' in msg if is_invalid_parameter_name: match = re.search( '\'(.+?)\' does not match any of the regexes', msg) if match: parameter_name = match.groups()[0] else: parameter_name = 'unknown' new_msg = ( 'Parameter name "%s" is invalid. Valid characters for parameter name ' 'are [a-zA-Z0-0_].' % (parameter_name)) new_msg += '\n\n' + msg raise jsonschema.ValidationError(new_msg) raise e # Use in-memory cached RunnerTypeDB objects to reduce load on the database if self._use_runners_cache: runner_type_db = self._runner_type_db_cache.get( action_api.runner_type, None) if not runner_type_db: runner_type_db = action_validator.get_runner_model(action_api) self._runner_type_db_cache[ action_api.runner_type] = runner_type_db else: runner_type_db = None action_validator.validate_action(action_api, runner_type_db=runner_type_db) model = ActionAPI.to_model(action_api) action_ref = ResourceReference.to_string_reference( pack=pack, name=str(content['name'])) existing = action_utils.get_action_by_ref(action_ref) if not existing: LOG.debug('Action %s not found. Creating new one with: %s', action_ref, content) else: LOG.debug('Action %s found. Will be updated from: %s to: %s', action_ref, existing, model) model.id = existing.id try: model = Action.add_or_update(model) extra = {'action_db': model} LOG.audit('Action updated. Action %s from %s.', model, action, extra=extra) except Exception: LOG.exception('Failed to write action to db %s.', model.name) raise
def test_packs_register_endpoint(self, mock_get_packs): # Register resources from all packs - make sure the count values are correctly added # together # Note: We only register a couple of packs and not all on disk to speed # things up. Registering all the packs takes a long time. fixtures_base_path = get_fixtures_base_path() packs_base_path = os.path.join(fixtures_base_path, 'packs') pack_names = [ 'dummy_pack_1', 'dummy_pack_2', 'dummy_pack_3', 'dummy_pack_10', ] mock_return_value = {} for pack_name in pack_names: mock_return_value[pack_name] = os.path.join( packs_base_path, pack_name) mock_get_packs.return_value = mock_return_value resp = self.app.post_json('/v1/packs/register', {'fail_on_failure': False}) self.assertEqual(resp.status_int, 200) self.assertTrue('runners' in resp.json) self.assertTrue('actions' in resp.json) self.assertTrue('triggers' in resp.json) self.assertTrue('sensors' in resp.json) self.assertTrue('rules' in resp.json) self.assertTrue('rule_types' in resp.json) self.assertTrue('aliases' in resp.json) self.assertTrue('policy_types' in resp.json) self.assertTrue('policies' in resp.json) self.assertTrue('configs' in resp.json) self.assertTrue(resp.json['actions'] >= 3) self.assertTrue(resp.json['configs'] >= 1) # Register resources from a specific pack resp = self.app.post_json('/v1/packs/register', { 'packs': ['dummy_pack_1'], 'fail_on_failure': False }) self.assertEqual(resp.status_int, 200) self.assertTrue(resp.json['actions'] >= 1) self.assertTrue(resp.json['sensors'] >= 1) self.assertTrue(resp.json['configs'] >= 1) # Verify metadata_file attribute is set action_dbs = Action.query(pack='dummy_pack_1') self.assertEqual(action_dbs[0].metadata_file, 'actions/my_action.yaml') # Register 'all' resource types should try include any possible content for the pack resp = self.app.post_json('/v1/packs/register', { 'packs': ['dummy_pack_1'], 'fail_on_failure': False, 'types': ['all'] }) self.assertEqual(resp.status_int, 200) self.assertTrue('runners' in resp.json) self.assertTrue('actions' in resp.json) self.assertTrue('triggers' in resp.json) self.assertTrue('sensors' in resp.json) self.assertTrue('rules' in resp.json) self.assertTrue('rule_types' in resp.json) self.assertTrue('aliases' in resp.json) self.assertTrue('policy_types' in resp.json) self.assertTrue('policies' in resp.json) self.assertTrue('configs' in resp.json) # Registering single resource type should also cause dependent resources # to be registered # * actions -> runners # * rules -> rule types # * policies -> policy types resp = self.app.post_json( '/v1/packs/register', { 'packs': ['dummy_pack_1'], 'fail_on_failure': False, 'types': ['actions'] }) self.assertEqual(resp.status_int, 200) self.assertTrue(resp.json['runners'] >= 1) self.assertTrue(resp.json['actions'] >= 1) resp = self.app.post_json( '/v1/packs/register', { 'packs': ['dummy_pack_1'], 'fail_on_failure': False, 'types': ['rules'] }) self.assertEqual(resp.status_int, 200) self.assertTrue(resp.json['rule_types'] >= 1) self.assertTrue(resp.json['rules'] >= 1) resp = self.app.post_json( '/v1/packs/register', { 'packs': ['dummy_pack_2'], 'fail_on_failure': False, 'types': ['policies'] }) self.assertEqual(resp.status_int, 200) self.assertTrue(resp.json['policy_types'] >= 1) self.assertTrue(resp.json['policies'] >= 0) # Register specific type for all packs resp = self.app.post_json('/v1/packs/register', { 'types': ['sensor'], 'fail_on_failure': False }) self.assertEqual(resp.status_int, 200) self.assertEqual(resp.json, {'sensors': 3}) # Verify that plural name form also works resp = self.app.post_json('/v1/packs/register', { 'types': ['sensors'], 'fail_on_failure': False }) self.assertEqual(resp.status_int, 200) # Register specific type for a single packs resp = self.app.post_json('/v1/packs/register', { 'packs': ['dummy_pack_1'], 'types': ['action'] }) self.assertEqual(resp.status_int, 200) self.assertEqual(resp.json, {'actions': 1, 'runners': 15}) # Verify that plural name form also works resp = self.app.post_json('/v1/packs/register', { 'packs': ['dummy_pack_1'], 'types': ['actions'] }) self.assertEqual(resp.status_int, 200) self.assertEqual(resp.json, {'actions': 1, 'runners': 15}) # Register single resource from a single pack specified multiple times - verify that # resources from the same pack are only registered once resp = self.app.post_json( '/v1/packs/register', { 'packs': ['dummy_pack_1', 'dummy_pack_1', 'dummy_pack_1'], 'types': ['actions'], 'fail_on_failure': False }) self.assertEqual(resp.status_int, 200) self.assertEqual(resp.json, {'actions': 1, 'runners': 15}) # Register resources from a single (non-existent pack) resp = self.app.post_json('/v1/packs/register', {'packs': ['doesntexist']}, expect_errors=True) self.assertEqual(resp.status_int, 400) self.assertTrue('Pack "doesntexist" not found on disk:' in resp.json['faultstring']) # Fail on failure is enabled by default resp = self.app.post_json('/v1/packs/register', expect_errors=True) expected_msg = 'Failed to register pack "dummy_pack_10":' self.assertEqual(resp.status_int, 400) self.assertTrue(expected_msg in resp.json['faultstring']) # Fail on failure (broken pack metadata) resp = self.app.post_json('/v1/packs/register', {'packs': ['dummy_pack_1']}, expect_errors=True) expected_msg = 'Referenced policy_type "action.mock_policy_error" doesnt exist' self.assertEqual(resp.status_int, 400) self.assertTrue(expected_msg in resp.json['faultstring']) # Fail on failure (broken action metadata) resp = self.app.post_json('/v1/packs/register', {'packs': ['dummy_pack_15']}, expect_errors=True) expected_msg = 'Failed to register action' self.assertEqual(resp.status_int, 400) self.assertTrue(expected_msg in resp.json['faultstring']) expected_msg = '\'stringa\' is not valid under any of the given schemas' self.assertEqual(resp.status_int, 400) self.assertTrue(expected_msg in resp.json['faultstring'])
def clone(self, dest_data, ref_or_id, requester_user): """ Clone an action from source pack to destination pack. Handles requests: POST /actions/{ref_or_id}/clone """ source_action_db = self._get_by_ref_or_id(ref_or_id=ref_or_id) if not source_action_db: msg = "The requested source for cloning operation doesn't exists" abort(http_client.BAD_REQUEST, six.text_type(msg)) extra = {"action_db": source_action_db} LOG.audit("Source action found. Action.id=%s" % (source_action_db.id), extra=extra) try: permission_type = PermissionType.ACTION_VIEW rbac_utils = get_rbac_backend().get_utils_class() rbac_utils.assert_user_has_resource_db_permission( user_db=requester_user, resource_db=source_action_db, permission_type=permission_type, ) except ResourceAccessDeniedError as e: abort(http_client.UNAUTHORIZED, six.text_type(e)) cloned_dest_action_db = clone_action_db( source_action_db=source_action_db, dest_pack=dest_data.dest_pack, dest_action=dest_data.dest_action, ) cloned_action_api = ActionAPI.from_model(cloned_dest_action_db) try: permission_type = PermissionType.ACTION_CREATE rbac_utils.assert_user_has_resource_api_permission( user_db=requester_user, resource_api=cloned_action_api, permission_type=permission_type, ) except ResourceAccessDeniedError as e: abort(http_client.UNAUTHORIZED, six.text_type(e)) dest_pack_base_path = get_pack_base_path(pack_name=dest_data.dest_pack) if not os.path.isdir(dest_pack_base_path): msg = "Destination pack '%s' doesn't exist" % (dest_data.dest_pack) abort(http_client.BAD_REQUEST, six.text_type(msg)) dest_pack_base_path = get_pack_base_path(pack_name=dest_data.dest_pack) dest_ref = ".".join([dest_data.dest_pack, dest_data.dest_action]) dest_action_db = self._get_by_ref(resource_ref=dest_ref) try: validate_not_part_of_system_pack_by_name(dest_data.dest_pack) except ValueValidationException as e: abort(http_client.BAD_REQUEST, six.text_type(e)) if dest_action_db: if not dest_data.overwrite: msg = "The requested destination action already exists" abort(http_client.BAD_REQUEST, six.text_type(msg)) try: permission_type = PermissionType.ACTION_DELETE rbac_utils.assert_user_has_resource_db_permission( user_db=requester_user, resource_db=dest_action_db, permission_type=permission_type, ) options = GenericRequestParam(remove_files=True) dest_metadata_file = dest_action_db["metadata_file"] dest_entry_point = dest_action_db["entry_point"] temp_sub_dir = str(uuid.uuid4()) temp_backup_action_files( dest_pack_base_path, dest_metadata_file, dest_entry_point, temp_sub_dir, ) self.delete(options, dest_ref, requester_user) except ResourceAccessDeniedError as e: abort(http_client.UNAUTHORIZED, six.text_type(e)) except Exception as e: LOG.debug( "Exception encountered during deleting existing destination action. " "Exception was: %s", e, ) abort(http_client.INTERNAL_SERVER_ERROR, six.text_type(e)) try: post_response = self.post(cloned_action_api, requester_user) if post_response.status_code != http_client.CREATED: raise Exception("Could not add cloned action to database.") cloned_dest_action_db["id"] = post_response.json["id"] clone_action_files( source_action_db=source_action_db, dest_action_db=cloned_dest_action_db, dest_pack_base_path=dest_pack_base_path, ) extra = {"cloned_acion_db": cloned_dest_action_db} LOG.audit("Action cloned. Action.id=%s" % (cloned_dest_action_db.id), extra=extra) if dest_action_db: remove_temp_action_files(temp_sub_dir) return post_response except PermissionError as e: LOG.error("No permission to clone the action. Exception was %s", e) delete_action_files_from_pack( pack_name=cloned_dest_action_db["pack"], entry_point=cloned_dest_action_db["entry_point"], metadata_file=cloned_dest_action_db["metadata_file"], ) if post_response.status_code == http_client.CREATED: Action.delete(cloned_dest_action_db) if dest_action_db: self._restore_action(dest_action_db, dest_pack_base_path, temp_sub_dir) abort(http_client.FORBIDDEN, six.text_type(e)) except Exception as e: LOG.error( "Exception encountered during cloning action. Exception was %s", e, ) delete_action_files_from_pack( pack_name=cloned_dest_action_db["pack"], entry_point=cloned_dest_action_db["entry_point"], metadata_file=cloned_dest_action_db["metadata_file"], ) if post_response.status_code == http_client.CREATED: Action.delete(cloned_dest_action_db) if dest_action_db: self._restore_action(dest_action_db, dest_pack_base_path, temp_sub_dir) abort(http_client.INTERNAL_SERVER_ERROR, six.text_type(e))
def delete(self, options, ref_or_id, requester_user): """ Delete an action. Handles requests: POST /actions/1?_method=delete DELETE /actions/1 DELETE /actions/mypack.myaction """ action_db = self._get_by_ref_or_id(ref_or_id=ref_or_id) action_id = action_db.id permission_type = PermissionType.ACTION_DELETE rbac_utils = get_rbac_backend().get_utils_class() rbac_utils.assert_user_has_resource_db_permission( user_db=requester_user, resource_db=action_db, permission_type=permission_type, ) try: validate_not_part_of_system_pack(action_db) except ValueValidationException as e: abort(http_client.BAD_REQUEST, six.text_type(e)) LOG.debug( "DELETE /actions/ lookup with ref_or_id=%s found object: %s", ref_or_id, action_db, ) pack_name = action_db["pack"] entry_point = action_db["entry_point"] metadata_file = action_db["metadata_file"] try: Action.delete(action_db) except Exception as e: LOG.error( 'Database delete encountered exception during delete of id="%s". ' "Exception was %s", action_id, e, ) abort(http_client.INTERNAL_SERVER_ERROR, six.text_type(e)) return if options.remove_files: try: delete_action_files_from_pack( pack_name=pack_name, entry_point=entry_point, metadata_file=metadata_file, ) except PermissionError as e: LOG.error("No permission to delete resource files from disk.") action_db.id = None Action.add_or_update(action_db) abort(http_client.FORBIDDEN, six.text_type(e)) return except Exception as e: LOG.error( "Exception encountered during deleting resource files from disk. " "Exception was %s", e, ) action_db.id = None Action.add_or_update(action_db) abort(http_client.INTERNAL_SERVER_ERROR, six.text_type(e)) return extra = {"action_db": action_db} LOG.audit("Action deleted. Action.id=%s" % (action_db.id), extra=extra) return Response(status=http_client.NO_CONTENT)