def test_get_config_some_values_overriden_in_datastore(self): # Test a scenario where some values are overriden in datastore via pack # flobal config kvp_db = set_datastore_value_for_config_key(pack_name='dummy_pack_5', key_name='api_secret', value='some_api_secret', secret=True, user='******') # This is a secret so a value should be encrypted self.assertTrue(kvp_db.value != 'some_api_secret') self.assertTrue(len(kvp_db.value) > len('some_api_secret') * 2) self.assertTrue(kvp_db.secret) kvp_db = set_datastore_value_for_config_key(pack_name='dummy_pack_5', key_name='private_key_path', value='some_private_key') self.assertEqual(kvp_db.value, 'some_private_key') self.assertFalse(kvp_db.secret) loader = ContentPackConfigLoader(pack_name='dummy_pack_5', user='******') config = loader.get_config() # regions is provided in the pack global config # api_secret is dynamically loaded from the datastore for a particular user expected_config = { 'api_key': 'some_api_key', 'api_secret': 'some_api_secret', 'regions': ['us-west-1'], 'region': 'default-region-value', 'private_key_path': 'some_private_key' } self.assertEqual(config, expected_config)
def _get_action_instance(self): try: actions_cls = action_loader.register_plugin(Action, self._file_path) except Exception as e: tb_msg = traceback.format_exc() msg = ('Failed to load action class from file "%s" (action file most likely doesn\'t ' 'exist or contains invalid syntax): %s' % (self._file_path, str(e))) msg += '\n\n' + tb_msg exc_cls = type(e) raise exc_cls(msg) action_cls = actions_cls[0] if actions_cls and len(actions_cls) > 0 else None if not action_cls: raise Exception('File "%s" has no action class or the file doesn\'t exist.' % (self._file_path)) self._class_name = action_cls.__class__.__name__ config_loader = ContentPackConfigLoader(pack_name=self._pack, user=self._user) config = config_loader.get_config() if config: LOG.info('Found config for action "%s"' % (self._file_path)) else: LOG.info('No config found for action "%s"' % (self._file_path)) config = None action_service = ActionService(action_wrapper=self) action_instance = get_action_class_instance(action_cls=action_cls, config=config, action_service=action_service) return action_instance
def test_get_config_dynamic_config_item_list(self): pack_name = 'dummy_pack_schema_with_nested_object_7' loader = ContentPackConfigLoader(pack_name=pack_name) KeyValuePair.add_or_update(KeyValuePairDB(name='k0', value='v0')) KeyValuePair.add_or_update(KeyValuePairDB(name='k1', value='v1')) #################### # values in list values = { 'level0_key': [ 'a', '{{st2kv.system.k0}}', 'b', '{{st2kv.system.k1}}', ] } config_db = ConfigDB(pack=pack_name, values=values) config_db = Config.add_or_update(config_db) config_rendered = loader.get_config() self.assertEquals(config_rendered, { 'level0_key': [ 'a', 'v0', 'b', 'v1' ] }) config_db.delete()
def test_empty_config_object_in_the_database(self): pack_name = 'dummy_pack_empty_config' config_db = ConfigDB(pack=pack_name) config_db = Config.add_or_update(config_db) loader = ContentPackConfigLoader(pack_name=pack_name) config = loader.get_config() self.assertEqual(config, {})
def test_ensure_local_pack_config_feature_removed(self): # Test a scenario where all the values are loaded from pack local # config and pack global config (pack name.yaml) doesn't exist. # Test a scenario where no values are overridden in the datastore loader = ContentPackConfigLoader(pack_name='dummy_pack_4') config = loader.get_config() expected_config = {} self.assertDictEqual(config, expected_config)
def test_get_config_dynamic_config_item_nested_list(self): pack_name = "dummy_pack_schema_with_nested_object_8" loader = ContentPackConfigLoader(pack_name=pack_name) KeyValuePair.add_or_update(KeyValuePairDB(name="k0", value="v0")) KeyValuePair.add_or_update(KeyValuePairDB(name="k1", value="v1")) KeyValuePair.add_or_update(KeyValuePairDB(name="k2", value="v2")) #################### # values in objects embedded in lists and nested lists values = { "level0_key": [ { "level1_key0": "{{st2kv.system.k0}}" }, "{{st2kv.system.k1}}", [ "{{st2kv.system.k0}}", "{{st2kv.system.k1}}", "{{st2kv.system.k2}}", ], { "level1_key2": [ "{{st2kv.system.k2}}", ] }, ] } config_db = ConfigDB(pack=pack_name, values=values) config_db = Config.add_or_update(config_db) config_rendered = loader.get_config() self.assertEqual( config_rendered, { "level0_key": [ { "level1_key0": "v0" }, "v1", [ "v0", "v1", "v2", ], { "level1_key2": [ "v2", ] }, ] }, ) config_db.delete()
def _get_sensor_config(self): config_loader = ContentPackConfigLoader(pack_name=self._pack) config = config_loader.get_config() if config: self._logger.info('Found config for sensor "%s"' % (self._class_name)) else: self._logger.info('No config found for sensor "%s"' % (self._class_name)) return config
def test_get_config_dynamic_config_item_nested_list(self): pack_name = 'dummy_pack_schema_with_nested_object_8' loader = ContentPackConfigLoader(pack_name=pack_name) KeyValuePair.add_or_update(KeyValuePairDB(name='k0', value='v0')) KeyValuePair.add_or_update(KeyValuePairDB(name='k1', value='v1')) KeyValuePair.add_or_update(KeyValuePairDB(name='k2', value='v2')) #################### # values in objects embedded in lists and nested lists values = { 'level0_key': [ { 'level1_key0': '{{st2kv.system.k0}}' }, '{{st2kv.system.k1}}', [ '{{st2kv.system.k0}}', '{{st2kv.system.k1}}', '{{st2kv.system.k2}}', ], { 'level1_key2': [ '{{st2kv.system.k2}}', ] } ] } config_db = ConfigDB(pack=pack_name, values=values) config_db = Config.add_or_update(config_db) config_rendered = loader.get_config() self.assertEquals(config_rendered, { 'level0_key': [ { 'level1_key0': 'v0' }, 'v1', [ 'v0', 'v1', 'v2', ], { 'level1_key2': [ 'v2', ] } ] }) config_db.delete()
def test_get_config_dynamic_config_item_under_additional_properties(self): pack_name = "dummy_pack_schema_with_additional_properties_1" loader = ContentPackConfigLoader(pack_name=pack_name) encrypted_value = crypto.symmetric_encrypt(KeyValuePairAPI.crypto_key, "v1_encrypted") KeyValuePair.add_or_update( KeyValuePairDB(name="k1_encrypted", value=encrypted_value, secret=True)) #################### # values in objects under an object with additionalProperties values = { "profiles": { "dev": { # no host or port to test default value "token": "hard-coded-secret", }, "prod": { "host": "127.1.2.7", "port": 8282, # encrypted in datastore "token": "{{st2kv.system.k1_encrypted}}", # schema declares `secret: true` which triggers auto-decryption. # If this were not encrypted, it would try to decrypt it and fail. }, } } config_db = ConfigDB(pack=pack_name, values=values) config_db = Config.add_or_update(config_db) config_rendered = loader.get_config() self.assertEqual( config_rendered, { "region": "us-east-1", "profiles": { "dev": { "host": "127.0.0.3", "port": 8080, "token": "hard-coded-secret", }, "prod": { "host": "127.1.2.7", "port": 8282, "token": "v1_encrypted", }, }, }, ) config_db.delete()
def test_default_values_from_schema_are_used_when_no_config_exists(self): pack_name = 'dummy_pack_5' config_db = Config.get_by_pack(pack_name) # Delete the existing config loaded in setUp config_db = Config.get_by_pack(pack_name) config_db.delete() # Verify config has been deleted from the database self.assertRaises(StackStormDBObjectNotFoundError, Config.get_by_pack, pack_name) loader = ContentPackConfigLoader(pack_name=pack_name) config = loader.get_config() self.assertEqual(config['region'], 'default-region-value')
def test_get_config_default_value_from_config_schema_is_used(self): # No value is provided for "region" in the config, default value from config schema # should be used loader = ContentPackConfigLoader(pack_name='dummy_pack_5') config = loader.get_config() self.assertEqual(config['region'], 'default-region-value') # Here a default value is specified in schema but an explicit value is provided in the # config loader = ContentPackConfigLoader(pack_name='dummy_pack_1') config = loader.get_config() self.assertEqual(config['region'], 'us-west-1') # Config item attribute has required: false # Value is provided in the config - it should be used as provided pack_name = 'dummy_pack_5' loader = ContentPackConfigLoader(pack_name=pack_name) config = loader.get_config() self.assertEqual(config['non_required_with_default_value'], 'config value') config_db = Config.get_by_pack(pack_name) del config_db['values']['non_required_with_default_value'] Config.add_or_update(config_db) # No value in the config - default value should be used config_db = Config.get_by_pack(pack_name) config_db.delete() # No config exists for that pack - default value should be used loader = ContentPackConfigLoader(pack_name=pack_name) config = loader.get_config() self.assertEqual(config['non_required_with_default_value'], 'some default value')
def test_get_config_all_values_are_loaded_from_local_config(self): # Test a scenario where all the values are loaded from pack local config and pack global # config (pack name.yaml) doesn't exist # Test a scenario where no values are overridden in the datastore loader = ContentPackConfigLoader(pack_name='dummy_pack_4') config = loader.get_config() expected_config = { 'api_key': '', 'api_secret': '', 'regions': ['us-west-1', 'us-east-1'], 'private_key_path': None } self.assertEqual(config, expected_config)
def test_get_config_dynamic_config_item(self): pack_name = "dummy_pack_schema_with_nested_object_6" loader = ContentPackConfigLoader(pack_name=pack_name) #################### # value in top level item KeyValuePair.add_or_update(KeyValuePairDB(name="k1", value="v1")) values = {"level0_key": "{{st2kv.system.k1}}"} config_db = ConfigDB(pack=pack_name, values=values) config_db = Config.add_or_update(config_db) config_rendered = loader.get_config() self.assertEqual(config_rendered, {"level0_key": "v1"}) config_db.delete()
def test_get_config_dynamic_config_item(self): pack_name = 'dummy_pack_schema_with_nested_object_6' loader = ContentPackConfigLoader(pack_name=pack_name) #################### # value in top level item KeyValuePair.add_or_update(KeyValuePairDB(name='k1', value='v1')) values = {'level0_key': '{{st2kv.system.k1}}'} config_db = ConfigDB(pack=pack_name, values=values) config_db = Config.add_or_update(config_db) config_rendered = loader.get_config() self.assertEqual(config_rendered, {'level0_key': 'v1'}) config_db.delete()
def test_get_config_dynamic_config_item(self): pack_name = 'dummy_pack_schema_with_nested_object_6' loader = ContentPackConfigLoader(pack_name=pack_name) #################### # value in top level item KeyValuePair.add_or_update(KeyValuePairDB(name='k1', value='v1')) values = { 'level0_key': '{{st2kv.system.k1}}' } config_db = ConfigDB(pack=pack_name, values=values) config_db = Config.add_or_update(config_db) config_rendered = loader.get_config() self.assertEquals(config_rendered, {'level0_key': 'v1'}) config_db.delete()
def _get_action_instance(self): actions_cls = action_loader.register_plugin(Action, self._file_path) action_cls = actions_cls[0] if actions_cls and len(actions_cls) > 0 else None if not action_cls: raise Exception('File "%s" has no action or the file doesn\'t exist.' % (self._file_path)) config_loader = ContentPackConfigLoader(pack_name=self._pack, user=self._user) config = config_loader.get_config() if config: LOG.info('Found config for action "%s"' % (self._file_path)) else: LOG.info('No config found for action "%s"' % (self._file_path)) config = None action_service = ActionService(action_wrapper=self) action_instance = get_action_class_instance(action_cls=action_cls, config=config, action_service=action_service) return action_instance
def _get_runner(self, runnertype_db, action_db, liveaction_db): resolved_entry_point = self._get_entry_point_abs_path( action_db.pack, action_db.entry_point) context = getattr(liveaction_db, 'context', dict()) user = context.get('user', cfg.CONF.system_user.user) # Note: Right now configs are only supported by the Python runner actions if runnertype_db.runner_module == 'python_runner': LOG.debug('Loading config for pack') config_loader = ContentPackConfigLoader(pack_name=action_db.pack, user=user) config = config_loader.get_config() else: config = None runner = get_runner(package_name=runnertype_db.runner_package, module_name=runnertype_db.runner_module, config=config) # TODO: Pass those arguments to the constructor instead of late # assignment, late assignment is awful runner.runner_type_db = runnertype_db runner.action = action_db runner.action_name = action_db.name runner.liveaction = liveaction_db runner.liveaction_id = str(liveaction_db.id) runner.execution = ActionExecution.get( liveaction__id=runner.liveaction_id) runner.execution_id = str(runner.execution.id) runner.entry_point = resolved_entry_point runner.context = context runner.callback = getattr(liveaction_db, 'callback', dict()) runner.libs_dir_path = self._get_action_libs_abs_path( action_db.pack, action_db.entry_point) # For re-run, get the ActionExecutionDB in which the re-run is based on. rerun_ref_id = runner.context.get('re-run', {}).get('ref') runner.rerun_ex_ref = ActionExecution.get( id=rerun_ref_id) if rerun_ref_id else None return runner
def _get_action_instance(self): try: actions_cls = action_loader.register_plugin( Action, self._file_path) except Exception as e: tb_msg = traceback.format_exc() msg = ( 'Failed to load action class from file "%s" (action file most likely doesn\'t ' 'exist or contains invalid syntax): %s' % (self._file_path, str(e))) msg += '\n\n' + tb_msg exc_cls = type(e) raise exc_cls(msg) action_cls = actions_cls[0] if actions_cls and len( actions_cls) > 0 else None if not action_cls: raise Exception( 'File "%s" has no action class or the file doesn\'t exist.' % (self._file_path)) self._class_name = action_cls.__class__.__name__ config_loader = ContentPackConfigLoader(pack_name=self._pack, user=self._user) config = config_loader.get_config() if config: LOG.info('Found config for action "%s"' % (self._file_path)) else: LOG.info('No config found for action "%s"' % (self._file_path)) config = None action_service = ActionService(action_wrapper=self) action_instance = get_action_class_instance( action_cls=action_cls, config=config, action_service=action_service) return action_instance
def test_default_values_are_used_when_default_values_are_falsey(self): pack_name = 'dummy_pack_17' loader = ContentPackConfigLoader(pack_name=pack_name) config = loader.get_config() # 1. Default values are used self.assertEqual(config['key_with_default_falsy_value_1'], False) self.assertEqual(config['key_with_default_falsy_value_2'], None) self.assertEqual(config['key_with_default_falsy_value_3'], {}) self.assertEqual(config['key_with_default_falsy_value_4'], '') self.assertEqual(config['key_with_default_falsy_value_5'], 0) self.assertEqual(config['key_with_default_falsy_value_6']['key_1'], False) self.assertEqual(config['key_with_default_falsy_value_6']['key_2'], 0) # 2. Default values are overwrriten with config values which are also falsey values = { 'key_with_default_falsy_value_1': 0, 'key_with_default_falsy_value_2': '', 'key_with_default_falsy_value_3': False, 'key_with_default_falsy_value_4': None, 'key_with_default_falsy_value_5': {}, 'key_with_default_falsy_value_6': { 'key_2': False } } config_db = ConfigDB(pack=pack_name, values=values) config_db = Config.add_or_update(config_db) loader = ContentPackConfigLoader(pack_name=pack_name) config = loader.get_config() self.assertEqual(config['key_with_default_falsy_value_1'], 0) self.assertEqual(config['key_with_default_falsy_value_2'], '') self.assertEqual(config['key_with_default_falsy_value_3'], False) self.assertEqual(config['key_with_default_falsy_value_4'], None) self.assertEqual(config['key_with_default_falsy_value_5'], {}) self.assertEqual(config['key_with_default_falsy_value_6']['key_1'], False) self.assertEqual(config['key_with_default_falsy_value_6']['key_2'], False)
def _get_runner(self, runner_type_db, action_db, liveaction_db): resolved_entry_point = self._get_entry_point_abs_path( action_db.pack, action_db.entry_point) context = getattr(liveaction_db, "context", dict()) user = context.get("user", cfg.CONF.system_user.user) config = None # Note: Right now configs are only supported by the Python runner actions if (runner_type_db.name == "python-script" or runner_type_db.runner_module == "python_runner"): LOG.debug("Loading config from pack for python runner.") config_loader = ContentPackConfigLoader(pack_name=action_db.pack, user=user) config = config_loader.get_config() runner = get_runner(name=runner_type_db.name, config=config) # TODO: Pass those arguments to the constructor instead of late # assignment, late assignment is awful runner.runner_type = runner_type_db runner.action = action_db runner.action_name = action_db.name runner.liveaction = liveaction_db runner.liveaction_id = str(liveaction_db.id) runner.execution = ActionExecution.get( liveaction__id=runner.liveaction_id) runner.execution_id = str(runner.execution.id) runner.entry_point = resolved_entry_point runner.context = context runner.callback = getattr(liveaction_db, "callback", dict()) runner.libs_dir_path = self._get_action_libs_abs_path( action_db.pack, action_db.entry_point) # For re-run, get the ActionExecutionDB in which the re-run is based on. rerun_ref_id = runner.context.get("re-run", {}).get("ref") runner.rerun_ex_ref = (ActionExecution.get( id=rerun_ref_id) if rerun_ref_id else None) return runner
def test_get_config_some_values_overriden_in_datastore(self): # Test a scenario where some values are overriden in datastore via pack # global config kvp_db = set_datastore_value_for_config_key( pack_name="dummy_pack_5", key_name="api_secret", value="some_api_secret", secret=True, user="******", ) # This is a secret so a value should be encrypted self.assertTrue(kvp_db.value != "some_api_secret") self.assertTrue(len(kvp_db.value) > len("some_api_secret") * 2) self.assertTrue(kvp_db.secret) kvp_db = set_datastore_value_for_config_key( pack_name="dummy_pack_5", key_name="private_key_path", value="some_private_key", ) self.assertEqual(kvp_db.value, "some_private_key") self.assertFalse(kvp_db.secret) loader = ContentPackConfigLoader(pack_name="dummy_pack_5", user="******") config = loader.get_config() # regions is provided in the pack global config # api_secret is dynamically loaded from the datastore for a particular user expected_config = { "api_key": "some_api_key", "api_secret": "some_api_secret", "regions": ["us-west-1"], "region": "default-region-value", "private_key_path": "some_private_key", "non_required_with_default_value": "config value", } self.assertEqual(config, expected_config)
def test_get_config_dynamic_config_item_nested_dict(self): pack_name = "dummy_pack_schema_with_nested_object_7" loader = ContentPackConfigLoader(pack_name=pack_name) KeyValuePair.add_or_update(KeyValuePairDB(name="k0", value="v0")) KeyValuePair.add_or_update(KeyValuePairDB(name="k1", value="v1")) KeyValuePair.add_or_update(KeyValuePairDB(name="k2", value="v2")) #################### # values nested dictionaries values = { "level0_key": "{{st2kv.system.k0}}", "level0_object": { "level1_key": "{{st2kv.system.k1}}", "level1_object": { "level2_key": "{{st2kv.system.k2}}" }, }, } config_db = ConfigDB(pack=pack_name, values=values) config_db = Config.add_or_update(config_db) config_rendered = loader.get_config() self.assertEqual( config_rendered, { "level0_key": "v0", "level0_object": { "level1_key": "v1", "level1_object": { "level2_key": "v2" }, }, }, ) config_db.delete()
def _get_runner(self, runner_type_db, action_db, liveaction_db): resolved_entry_point = self._get_entry_point_abs_path(action_db.pack, action_db.entry_point) context = getattr(liveaction_db, 'context', dict()) user = context.get('user', cfg.CONF.system_user.user) config = None # Note: Right now configs are only supported by the Python runner actions if (runner_type_db.name == 'python-script' or runner_type_db.runner_module == 'python_runner'): LOG.debug('Loading config from pack for python runner.') config_loader = ContentPackConfigLoader(pack_name=action_db.pack, user=user) config = config_loader.get_config() runner = get_runner( name=runner_type_db.name, config=config) # TODO: Pass those arguments to the constructor instead of late # assignment, late assignment is awful runner.runner_type = runner_type_db runner.action = action_db runner.action_name = action_db.name runner.liveaction = liveaction_db runner.liveaction_id = str(liveaction_db.id) runner.execution = ActionExecution.get(liveaction__id=runner.liveaction_id) runner.execution_id = str(runner.execution.id) runner.entry_point = resolved_entry_point runner.context = context runner.callback = getattr(liveaction_db, 'callback', dict()) runner.libs_dir_path = self._get_action_libs_abs_path(action_db.pack, action_db.entry_point) # For re-run, get the ActionExecutionDB in which the re-run is based on. rerun_ref_id = runner.context.get('re-run', {}).get('ref') runner.rerun_ex_ref = ActionExecution.get(id=rerun_ref_id) if rerun_ref_id else None return runner
def test_get_config_dynamic_config_item_nested_dict(self): pack_name = 'dummy_pack_schema_with_nested_object_7' loader = ContentPackConfigLoader(pack_name=pack_name) KeyValuePair.add_or_update(KeyValuePairDB(name='k0', value='v0')) KeyValuePair.add_or_update(KeyValuePairDB(name='k1', value='v1')) KeyValuePair.add_or_update(KeyValuePairDB(name='k2', value='v2')) #################### # values nested dictionaries values = { 'level0_key': '{{st2kv.system.k0}}', 'level0_object': { 'level1_key': '{{st2kv.system.k1}}', 'level1_object': { 'level2_key': '{{st2kv.system.k2}}' } } } config_db = ConfigDB(pack=pack_name, values=values) config_db = Config.add_or_update(config_db) config_rendered = loader.get_config() self.assertEqual( config_rendered, { 'level0_key': 'v0', 'level0_object': { 'level1_key': 'v1', 'level1_object': { 'level2_key': 'v2' } } }) config_db.delete()
def test_get_config_some_values_overriden_in_datastore(self): # Test a scenario where some values are overriden in datastore via pack # flobal config kvp_db = set_datastore_value_for_config_key(pack_name='dummy_pack_5', key_name='api_secret', value='some_api_secret', secret=True, user='******') # This is a secret so a value should be encrypted self.assertTrue(kvp_db.value != 'some_api_secret') self.assertTrue(len(kvp_db.value) > len('some_api_secret') * 2) self.assertTrue(kvp_db.secret) kvp_db = set_datastore_value_for_config_key( pack_name='dummy_pack_5', key_name='private_key_path', value='some_private_key') self.assertEqual(kvp_db.value, 'some_private_key') self.assertFalse(kvp_db.secret) loader = ContentPackConfigLoader(pack_name='dummy_pack_5', user='******') config = loader.get_config() # regions is provided in the pack global config # api_secret is dynamically loaded from the datastore for a particular user expected_config = { 'api_key': 'some_api_key', 'api_secret': 'some_api_secret', 'regions': ['us-west-1'], 'region': 'default-region-value', 'private_key_path': 'some_private_key', 'non_required_with_default_value': 'config value' } self.assertEqual(config, expected_config)
def test_get_config_dynamic_config_item_nested_dict(self): pack_name = 'dummy_pack_schema_with_nested_object_7' loader = ContentPackConfigLoader(pack_name=pack_name) KeyValuePair.add_or_update(KeyValuePairDB(name='k0', value='v0')) KeyValuePair.add_or_update(KeyValuePairDB(name='k1', value='v1')) KeyValuePair.add_or_update(KeyValuePairDB(name='k2', value='v2')) #################### # values nested dictionaries values = { 'level0_key': '{{st2kv.system.k0}}', 'level0_object': { 'level1_key': '{{st2kv.system.k1}}', 'level1_object': { 'level2_key': '{{st2kv.system.k2}}' } } } config_db = ConfigDB(pack=pack_name, values=values) config_db = Config.add_or_update(config_db) config_rendered = loader.get_config() self.assertEquals(config_rendered, { 'level0_key': 'v0', 'level0_object': { 'level1_key': 'v1', 'level1_object': { 'level2_key': 'v2' } } }) config_db.delete()
def test_get_config_dynamic_config_item_render_fails_user_friendly_exception_is_thrown(self): pack_name = 'dummy_pack_schema_with_nested_object_5' loader = ContentPackConfigLoader(pack_name=pack_name) # Render fails on top-level item values = { 'level0_key': '{{st2kvXX.invalid}}' } config_db = ConfigDB(pack=pack_name, values=values) config_db = Config.add_or_update(config_db) expected_msg = ('Failed to render dynamic configuration value for key "level0_key" with ' 'value "{{st2kvXX.invalid}}" for pack ".*?" config: ' '\'st2kvXX\' is undefined') self.assertRaisesRegexp(Exception, expected_msg, loader.get_config) config_db.delete() # Renders fails on fist level item values = { 'level0_object': { 'level1_key': '{{st2kvXX.invalid}}' } } config_db = ConfigDB(pack=pack_name, values=values) Config.add_or_update(config_db) expected_msg = ('Failed to render dynamic configuration value for key ' '"level0_object.level1_key" with value "{{st2kvXX.invalid}}"' ' for pack ".*?" config: \'st2kvXX\' is undefined') self.assertRaisesRegexp(Exception, expected_msg, loader.get_config) config_db.delete() # Renders fails on second level item values = { 'level0_object': { 'level1_object': { 'level2_key': '{{st2kvXX.invalid}}' } } } config_db = ConfigDB(pack=pack_name, values=values) Config.add_or_update(config_db) expected_msg = ('Failed to render dynamic configuration value for key ' '"level0_object.level1_object.level2_key" with value "{{st2kvXX.invalid}}"' ' for pack ".*?" config: \'st2kvXX\' is undefined') self.assertRaisesRegexp(Exception, expected_msg, loader.get_config) config_db.delete()
def test_get_config_default_value_from_config_schema_is_used(self): # No value is provided for "region" in the config, default value from config schema # should be used loader = ContentPackConfigLoader(pack_name='dummy_pack_5') config = loader.get_config() self.assertEqual(config['region'], 'default-region-value') # Here a default value is specified in schema but an explicit value is provided in the # config loader = ContentPackConfigLoader(pack_name='dummy_pack_1') config = loader.get_config() self.assertEqual(config['region'], 'us-west-1')
def test_default_values_are_used_when_default_values_are_falsey(self): pack_name = "dummy_pack_17" loader = ContentPackConfigLoader(pack_name=pack_name) config = loader.get_config() # 1. Default values are used self.assertEqual(config["key_with_default_falsy_value_1"], False) self.assertEqual(config["key_with_default_falsy_value_2"], None) self.assertEqual(config["key_with_default_falsy_value_3"], {}) self.assertEqual(config["key_with_default_falsy_value_4"], "") self.assertEqual(config["key_with_default_falsy_value_5"], 0) self.assertEqual(config["key_with_default_falsy_value_6"]["key_1"], False) self.assertEqual(config["key_with_default_falsy_value_6"]["key_2"], 0) # 2. Default values are overwrriten with config values which are also falsey values = { "key_with_default_falsy_value_1": 0, "key_with_default_falsy_value_2": "", "key_with_default_falsy_value_3": False, "key_with_default_falsy_value_4": None, "key_with_default_falsy_value_5": {}, "key_with_default_falsy_value_6": { "key_2": False }, } config_db = ConfigDB(pack=pack_name, values=values) config_db = Config.add_or_update(config_db) loader = ContentPackConfigLoader(pack_name=pack_name) config = loader.get_config() self.assertEqual(config["key_with_default_falsy_value_1"], 0) self.assertEqual(config["key_with_default_falsy_value_2"], "") self.assertEqual(config["key_with_default_falsy_value_3"], False) self.assertEqual(config["key_with_default_falsy_value_4"], None) self.assertEqual(config["key_with_default_falsy_value_5"], {}) self.assertEqual(config["key_with_default_falsy_value_6"]["key_1"], False) self.assertEqual(config["key_with_default_falsy_value_6"]["key_2"], False)
def test_get_config_dynamic_config_item_render_fails_user_friendly_exception_is_thrown( self, ): pack_name = "dummy_pack_schema_with_nested_object_5" loader = ContentPackConfigLoader(pack_name=pack_name) # Render fails on top-level item values = {"level0_key": "{{st2kvXX.invalid}}"} config_db = ConfigDB(pack=pack_name, values=values) config_db = Config.add_or_update(config_db) expected_msg = ( 'Failed to render dynamic configuration value for key "level0_key" with ' 'value "{{st2kvXX.invalid}}" for pack ".*?" config: ' "<class 'jinja2.exceptions.UndefinedError'> " "'st2kvXX' is undefined") self.assertRaisesRegexp(RuntimeError, expected_msg, loader.get_config) config_db.delete() # Renders fails on fist level item values = {"level0_object": {"level1_key": "{{st2kvXX.invalid}}"}} config_db = ConfigDB(pack=pack_name, values=values) Config.add_or_update(config_db) expected_msg = ( "Failed to render dynamic configuration value for key " '"level0_object.level1_key" with value "{{st2kvXX.invalid}}"' " for pack \".*?\" config: <class 'jinja2.exceptions.UndefinedError'>" " 'st2kvXX' is undefined") self.assertRaisesRegexp(RuntimeError, expected_msg, loader.get_config) config_db.delete() # Renders fails on second level item values = { "level0_object": { "level1_object": { "level2_key": "{{st2kvXX.invalid}}" } } } config_db = ConfigDB(pack=pack_name, values=values) Config.add_or_update(config_db) expected_msg = ( "Failed to render dynamic configuration value for key " '"level0_object.level1_object.level2_key" with value "{{st2kvXX.invalid}}"' " for pack \".*?\" config: <class 'jinja2.exceptions.UndefinedError'>" " 'st2kvXX' is undefined") self.assertRaisesRegexp(RuntimeError, expected_msg, loader.get_config) config_db.delete() # Renders fails on list item values = {"level0_object": ["abc", "{{st2kvXX.invalid}}"]} config_db = ConfigDB(pack=pack_name, values=values) Config.add_or_update(config_db) expected_msg = ( "Failed to render dynamic configuration value for key " '"level0_object.1" with value "{{st2kvXX.invalid}}"' " for pack \".*?\" config: <class 'jinja2.exceptions.UndefinedError'>" " 'st2kvXX' is undefined") self.assertRaisesRegexp(RuntimeError, expected_msg, loader.get_config) config_db.delete() # Renders fails on nested object in list item values = {"level0_object": [{"level2_key": "{{st2kvXX.invalid}}"}]} config_db = ConfigDB(pack=pack_name, values=values) Config.add_or_update(config_db) expected_msg = ( "Failed to render dynamic configuration value for key " '"level0_object.0.level2_key" with value "{{st2kvXX.invalid}}"' " for pack \".*?\" config: <class 'jinja2.exceptions.UndefinedError'>" " 'st2kvXX' is undefined") self.assertRaisesRegexp(RuntimeError, expected_msg, loader.get_config) config_db.delete() # Renders fails on invalid syntax values = {"level0_key": "{{ this is some invalid Jinja }}"} config_db = ConfigDB(pack=pack_name, values=values) Config.add_or_update(config_db) expected_msg = ( "Failed to render dynamic configuration value for key " '"level0_key" with value "{{ this is some invalid Jinja }}"' " for pack \".*?\" config: <class 'jinja2.exceptions.TemplateSyntaxError'>" " expected token 'end of print statement', got 'Jinja'") self.assertRaisesRegexp(RuntimeError, expected_msg, loader.get_config) config_db.delete()
def test_get_config_nested_schema_default_values_from_config_schema_are_used( self): # Special case for more complex config schemas with attributes ntesting. # Validate that the default values are also used for one level nested object properties. pack_name = "dummy_pack_schema_with_nested_object_1" # 1. None of the nested object values are provided loader = ContentPackConfigLoader(pack_name=pack_name) config = loader.get_config() expected_config = { "api_key": "", "api_secret": "", "regions": ["us-west-1", "us-east-1"], "auth_settings": { "host": "127.0.0.3", "port": 8080, "device_uids": ["a", "b", "c"], }, } self.assertEqual(config, expected_config) # 2. Some of the nested object values are provided (host, port) pack_name = "dummy_pack_schema_with_nested_object_2" loader = ContentPackConfigLoader(pack_name=pack_name) config = loader.get_config() expected_config = { "api_key": "", "api_secret": "", "regions": ["us-west-1", "us-east-1"], "auth_settings": { "host": "127.0.0.6", "port": 9090, "device_uids": ["a", "b", "c"], }, } self.assertEqual(config, expected_config) # 3. Nested attribute (auth_settings.token) references a non-secret datastore value pack_name = "dummy_pack_schema_with_nested_object_3" kvp_db = set_datastore_value_for_config_key( pack_name=pack_name, key_name="auth_settings_token", value="some_auth_settings_token", ) self.assertEqual(kvp_db.value, "some_auth_settings_token") self.assertFalse(kvp_db.secret) loader = ContentPackConfigLoader(pack_name=pack_name) config = loader.get_config() expected_config = { "api_key": "", "api_secret": "", "regions": ["us-west-1", "us-east-1"], "auth_settings": { "host": "127.0.0.10", "port": 8080, "device_uids": ["a", "b", "c"], "token": "some_auth_settings_token", }, } self.assertEqual(config, expected_config) # 4. Nested attribute (auth_settings.token) references a secret datastore value pack_name = "dummy_pack_schema_with_nested_object_4" kvp_db = set_datastore_value_for_config_key( pack_name=pack_name, key_name="auth_settings_token", value="joe_token_secret", secret=True, user="******", ) self.assertTrue(kvp_db.value != "joe_token_secret") self.assertTrue(len(kvp_db.value) > len("joe_token_secret") * 2) self.assertTrue(kvp_db.secret) kvp_db = set_datastore_value_for_config_key( pack_name=pack_name, key_name="auth_settings_token", value="alice_token_secret", secret=True, user="******", ) self.assertTrue(kvp_db.value != "alice_token_secret") self.assertTrue(len(kvp_db.value) > len("alice_token_secret") * 2) self.assertTrue(kvp_db.secret) loader = ContentPackConfigLoader(pack_name=pack_name, user="******") config = loader.get_config() expected_config = { "api_key": "", "api_secret": "", "regions": ["us-west-1", "us-east-1"], "auth_settings": { "host": "127.0.0.11", "port": 8080, "device_uids": ["a", "b", "c"], "token": "joe_token_secret", }, } self.assertEqual(config, expected_config) loader = ContentPackConfigLoader(pack_name=pack_name, user="******") config = loader.get_config() expected_config = { "api_key": "", "api_secret": "", "regions": ["us-west-1", "us-east-1"], "auth_settings": { "host": "127.0.0.11", "port": 8080, "device_uids": ["a", "b", "c"], "token": "alice_token_secret", }, } self.assertEqual(config, expected_config)
def test_get_config_nested_schema_default_values_from_config_schema_are_used( self): # Special case for more complex config schemas with attributes ntesting. # Validate that the default values are also used for one level nested object properties. pack_name = 'dummy_pack_schema_with_nested_object_1' # 1. None of the nested object values are provided loader = ContentPackConfigLoader(pack_name=pack_name) config = loader.get_config() expected_config = { 'api_key': '', 'api_secret': '', 'regions': ['us-west-1', 'us-east-1'], 'auth_settings': { 'host': '127.0.0.3', 'port': 8080, 'device_uids': ['a', 'b', 'c'] } } self.assertEqual(config, expected_config) # 2. Some of the nested object values are provided (host, port) pack_name = 'dummy_pack_schema_with_nested_object_2' loader = ContentPackConfigLoader(pack_name=pack_name) config = loader.get_config() expected_config = { 'api_key': '', 'api_secret': '', 'regions': ['us-west-1', 'us-east-1'], 'auth_settings': { 'host': '127.0.0.6', 'port': 9090, 'device_uids': ['a', 'b', 'c'] } } self.assertEqual(config, expected_config) # 3. Nested attribute (auth_settings.token) references a non-secret datastore value pack_name = 'dummy_pack_schema_with_nested_object_3' kvp_db = set_datastore_value_for_config_key( pack_name=pack_name, key_name='auth_settings_token', value='some_auth_settings_token') self.assertEqual(kvp_db.value, 'some_auth_settings_token') self.assertFalse(kvp_db.secret) loader = ContentPackConfigLoader(pack_name=pack_name) config = loader.get_config() expected_config = { 'api_key': '', 'api_secret': '', 'regions': ['us-west-1', 'us-east-1'], 'auth_settings': { 'host': '127.0.0.10', 'port': 8080, 'device_uids': ['a', 'b', 'c'], 'token': 'some_auth_settings_token' } } self.assertEqual(config, expected_config) # 4. Nested attribute (auth_settings.token) references a secret datastore value pack_name = 'dummy_pack_schema_with_nested_object_4' kvp_db = set_datastore_value_for_config_key( pack_name=pack_name, key_name='auth_settings_token', value='joe_token_secret', secret=True, user='******') self.assertTrue(kvp_db.value != 'joe_token_secret') self.assertTrue(len(kvp_db.value) > len('joe_token_secret') * 2) self.assertTrue(kvp_db.secret) kvp_db = set_datastore_value_for_config_key( pack_name=pack_name, key_name='auth_settings_token', value='alice_token_secret', secret=True, user='******') self.assertTrue(kvp_db.value != 'alice_token_secret') self.assertTrue(len(kvp_db.value) > len('alice_token_secret') * 2) self.assertTrue(kvp_db.secret) loader = ContentPackConfigLoader(pack_name=pack_name, user='******') config = loader.get_config() expected_config = { 'api_key': '', 'api_secret': '', 'regions': ['us-west-1', 'us-east-1'], 'auth_settings': { 'host': '127.0.0.11', 'port': 8080, 'device_uids': ['a', 'b', 'c'], 'token': 'joe_token_secret' } } self.assertEqual(config, expected_config) loader = ContentPackConfigLoader(pack_name=pack_name, user='******') config = loader.get_config() expected_config = { 'api_key': '', 'api_secret': '', 'regions': ['us-west-1', 'us-east-1'], 'auth_settings': { 'host': '127.0.0.11', 'port': 8080, 'device_uids': ['a', 'b', 'c'], 'token': 'alice_token_secret' } } self.assertEqual(config, expected_config)
def test_get_config_dynamic_config_item_render_fails_user_friendly_exception_is_thrown( self): pack_name = 'dummy_pack_schema_with_nested_object_5' loader = ContentPackConfigLoader(pack_name=pack_name) # Render fails on top-level item values = {'level0_key': '{{st2kvXX.invalid}}'} config_db = ConfigDB(pack=pack_name, values=values) config_db = Config.add_or_update(config_db) expected_msg = ( 'Failed to render dynamic configuration value for key "level0_key" with ' 'value "{{st2kvXX.invalid}}" for pack ".*?" config: ' '<class \'jinja2.exceptions.UndefinedError\'> ' '\'st2kvXX\' is undefined') self.assertRaisesRegexp(RuntimeError, expected_msg, loader.get_config) config_db.delete() # Renders fails on fist level item values = {'level0_object': {'level1_key': '{{st2kvXX.invalid}}'}} config_db = ConfigDB(pack=pack_name, values=values) Config.add_or_update(config_db) expected_msg = ( 'Failed to render dynamic configuration value for key ' '"level0_object.level1_key" with value "{{st2kvXX.invalid}}"' ' for pack ".*?" config: <class \'jinja2.exceptions.UndefinedError\'>' ' \'st2kvXX\' is undefined') self.assertRaisesRegexp(RuntimeError, expected_msg, loader.get_config) config_db.delete() # Renders fails on second level item values = { 'level0_object': { 'level1_object': { 'level2_key': '{{st2kvXX.invalid}}' } } } config_db = ConfigDB(pack=pack_name, values=values) Config.add_or_update(config_db) expected_msg = ( 'Failed to render dynamic configuration value for key ' '"level0_object.level1_object.level2_key" with value "{{st2kvXX.invalid}}"' ' for pack ".*?" config: <class \'jinja2.exceptions.UndefinedError\'>' ' \'st2kvXX\' is undefined') self.assertRaisesRegexp(RuntimeError, expected_msg, loader.get_config) config_db.delete() # Renders fails on list item values = {'level0_object': ['abc', '{{st2kvXX.invalid}}']} config_db = ConfigDB(pack=pack_name, values=values) Config.add_or_update(config_db) expected_msg = ( 'Failed to render dynamic configuration value for key ' '"level0_object.1" with value "{{st2kvXX.invalid}}"' ' for pack ".*?" config: <class \'jinja2.exceptions.UndefinedError\'>' ' \'st2kvXX\' is undefined') self.assertRaisesRegexp(RuntimeError, expected_msg, loader.get_config) config_db.delete() # Renders fails on nested object in list item values = {'level0_object': [{'level2_key': '{{st2kvXX.invalid}}'}]} config_db = ConfigDB(pack=pack_name, values=values) Config.add_or_update(config_db) expected_msg = ( 'Failed to render dynamic configuration value for key ' '"level0_object.0.level2_key" with value "{{st2kvXX.invalid}}"' ' for pack ".*?" config: <class \'jinja2.exceptions.UndefinedError\'>' ' \'st2kvXX\' is undefined') self.assertRaisesRegexp(RuntimeError, expected_msg, loader.get_config) config_db.delete() # Renders fails on invalid syntax values = {'level0_key': '{{ this is some invalid Jinja }}'} config_db = ConfigDB(pack=pack_name, values=values) Config.add_or_update(config_db) expected_msg = ( 'Failed to render dynamic configuration value for key ' '"level0_key" with value "{{ this is some invalid Jinja }}"' ' for pack ".*?" config: <class \'jinja2.exceptions.TemplateSyntaxError\'>' ' expected token \'end of print statement\', got \'Jinja\'') self.assertRaisesRegexp(RuntimeError, expected_msg, loader.get_config) config_db.delete()
def test_get_config_nested_schema_default_values_from_config_schema_are_used(self): # Special case for more complex config schemas with attributes ntesting. # Validate that the default values are also used for one level nested object properties. pack_name = 'dummy_pack_schema_with_nested_object_1' # 1. None of the nested object values are provided loader = ContentPackConfigLoader(pack_name=pack_name) config = loader.get_config() expected_config = { 'api_key': '', 'api_secret': '', 'regions': ['us-west-1', 'us-east-1'], 'auth_settings': { 'host': '127.0.0.3', 'port': 8080, 'device_uids': ['a', 'b', 'c'] } } self.assertEqual(config, expected_config) # 2. Some of the nested object values are provided (host, port) pack_name = 'dummy_pack_schema_with_nested_object_2' loader = ContentPackConfigLoader(pack_name=pack_name) config = loader.get_config() expected_config = { 'api_key': '', 'api_secret': '', 'regions': ['us-west-1', 'us-east-1'], 'auth_settings': { 'host': '127.0.0.6', 'port': 9090, 'device_uids': ['a', 'b', 'c'] } } self.assertEqual(config, expected_config) # 3. Nested attribute (auth_settings.token) references a non-secret datastore value pack_name = 'dummy_pack_schema_with_nested_object_3' kvp_db = set_datastore_value_for_config_key(pack_name=pack_name, key_name='auth_settings_token', value='some_auth_settings_token') self.assertEqual(kvp_db.value, 'some_auth_settings_token') self.assertFalse(kvp_db.secret) loader = ContentPackConfigLoader(pack_name=pack_name) config = loader.get_config() expected_config = { 'api_key': '', 'api_secret': '', 'regions': ['us-west-1', 'us-east-1'], 'auth_settings': { 'host': '127.0.0.10', 'port': 8080, 'device_uids': ['a', 'b', 'c'], 'token': 'some_auth_settings_token' } } self.assertEqual(config, expected_config) # 4. Nested attribute (auth_settings.token) references a secret datastore value pack_name = 'dummy_pack_schema_with_nested_object_4' kvp_db = set_datastore_value_for_config_key(pack_name=pack_name, key_name='auth_settings_token', value='joe_token_secret', secret=True, user='******') self.assertTrue(kvp_db.value != 'joe_token_secret') self.assertTrue(len(kvp_db.value) > len('joe_token_secret') * 2) self.assertTrue(kvp_db.secret) kvp_db = set_datastore_value_for_config_key(pack_name=pack_name, key_name='auth_settings_token', value='alice_token_secret', secret=True, user='******') self.assertTrue(kvp_db.value != 'alice_token_secret') self.assertTrue(len(kvp_db.value) > len('alice_token_secret') * 2) self.assertTrue(kvp_db.secret) loader = ContentPackConfigLoader(pack_name=pack_name, user='******') config = loader.get_config() expected_config = { 'api_key': '', 'api_secret': '', 'regions': ['us-west-1', 'us-east-1'], 'auth_settings': { 'host': '127.0.0.11', 'port': 8080, 'device_uids': ['a', 'b', 'c'], 'token': 'joe_token_secret' } } self.assertEqual(config, expected_config) loader = ContentPackConfigLoader(pack_name=pack_name, user='******') config = loader.get_config() expected_config = { 'api_key': '', 'api_secret': '', 'regions': ['us-west-1', 'us-east-1'], 'auth_settings': { 'host': '127.0.0.11', 'port': 8080, 'device_uids': ['a', 'b', 'c'], 'token': 'alice_token_secret' } } self.assertEqual(config, expected_config)