def test_init(self): # mappings should be list of ConfigMapping. config_merger.ConfigMerger(mappings=[]) config_merger.ConfigMerger(mappings=[ config_merger.ConfigMapping(path_list=['1/2/3', '/4/5/6']) ]) self.assertRaises( TypeError, config_merger.ConfigMerger, mapping={'hello': config_merger.ConfigMapping(path_list=[])}) self.assertRaises(TypeError, config_merger.ConfigMerger, mapping=config_merger.ConfigMapping(path_list=[])) self.assertRaises(TypeError, config_merger.ConfigMerger, mapping='config_merger.ConfigMapping(path_list=[])') self.assertRaises(TypeError, config_merger.ConfigMerger, mapping=[{ 'hello': config_merger.ConfigMapping(path_list=[]) }]) self.assertRaises( TypeError, config_merger.ConfigMerger, mapping=['config_merger.ConfigMapping(path_list=[])'])
def test_init_to_key(self): # to_key type should be string. config_merger.ConfigMapping(path_list=['1/2/3', '/4/5/6'], to_key='hello') config_merger.ConfigMapping(path_list=['1/2/3', '/4/5/6'], to_key=u'hello') self.assertRaises(TypeError, config_merger.ConfigMapping, path_list=['1/2/3', '/4/5/6'], to_key=['hello']) self.assertRaises(TypeError, config_merger.ConfigMapping, path_list=['1/2/3', '/4/5/6'], to_key=123)
def test_init(self): # path_list should be list of string. config_merger.ConfigMapping(path_list=['1/2/3', '/4/5/6']) config_merger.ConfigMapping(path_list=[u'1/2/3', u'/4/5/6']) self.assertRaises(TypeError, config_merger.ConfigMapping, path_list={'1/2/3': '4'}) self.assertRaises(TypeError, config_merger.ConfigMapping, path_list='1234') self.assertRaises(TypeError, config_merger.ConfigMapping, path_list=[{ '1/2/3': '4' }])
def test_merge_value_set_by_callback(self): # key in lower config is called a callback to expected value . upper_config = {'key': 'abc', 'key2': 'def'} upper_ref = config_reference.ConfigReference(upper_config) lower_configs = {1: {}, 2: {}, 3: {}} lower_refs = {} for lower_key, lower_config in lower_configs.items(): lower_refs[lower_key] = config_reference.ConfigReference( lower_config) def _merge_value(sub_ref, ref_key, lower_sub_refs, to_key): values = {} for lower_key, lower_sub_ref in lower_sub_refs.items(): values[lower_key] = '%s.%s' % (sub_ref.config, lower_key) return values merger = config_merger.ConfigMapping(path_list=['key'], value=_merge_value) merger.merge(upper_ref, lower_refs) self.assertEqual(lower_configs, { 1: { 'key': 'abc.1' }, 2: { 'key': 'abc.2' }, 3: { 'key': 'abc.3' } })
def test_merge_all_matching_keys_copied(self): # all the keys matching the pattern will be copied # from upper config to lower configs. upper_config = {'key': 'abc', 'key2': 'def'} upper_ref = config_reference.ConfigReference(upper_config) lower_configs = {1: {}, 2: {}, 3: {}} lower_refs = {} for lower_key, lower_config in lower_configs.items(): lower_refs[lower_key] = config_reference.ConfigReference( lower_config) merger = config_merger.ConfigMapping(path_list=['key*']) merger.merge(upper_ref, lower_refs) self.assertEqual( lower_configs, { 1: { 'key': 'abc', 'key2': 'def' }, 2: { 'key': 'abc', 'key2': 'def' }, 3: { 'key': 'abc', 'key2': 'def' } })
def test_merge_multikey_to_sam_tokey_override(self): # if multi key in upper config writes the same dest key, # the later one will override the former one if override is True. upper_config = {'key1': 'abc', 'key2': 'bcd'} upper_ref = config_reference.ConfigReference(upper_config) lower_configs = {1: {}, 2: {}, 3: {}} lower_refs = {} for lower_key, lower_config in lower_configs.items(): lower_refs[lower_key] = config_reference.ConfigReference( lower_config) merger = config_merger.ConfigMapping(path_list=['key1', 'key2'], to_key='/key', override=True) merger.merge(upper_ref, lower_refs) self.assertEqual( lower_configs, { 1: { 'key': 'bcd', 'key1': None, 'key2': None }, 2: { 'key': 'bcd', 'key1': None, 'key2': None }, 3: { 'key': 'bcd', 'key1': None, 'key2': None } })
def test_merge_from_upper_and_lower_configs(self): # set lower configs from some keys of upper config and lower configs. upper_config = {'key': 'abc', 'key_prefix': 'A', 'key_suffix': 'B'} upper_ref = config_reference.ConfigReference(upper_config) lower_configs = { 1: { 'name': 'hello' }, 2: { 'name': 'hi' }, 3: { 'name': 'today' } } lower_refs = {} for lower_key, lower_config in lower_configs.items(): lower_refs[lower_key] = config_reference.ConfigReference( lower_config) def _merge_value2(sub_ref, ref_key, lower_sub_refs, to_key, prefix='', suffix='', names={}): values = {} for lower_key, lower_sub_ref in lower_sub_refs.items(): values[lower_key] = '%s%s%s' % (prefix, names.get( lower_key, ''), suffix) return values merger = config_merger.ConfigMapping( path_list=['key'], value=_merge_value2, from_upper_keys={ 'prefix': '/key_prefix', 'suffix': '/key_suffix' }, from_lower_keys={'names': '/name'}) merger.merge(upper_ref, lower_refs) self.assertEqual( lower_configs, { 1: { 'name': 'hello', 'key': 'AhelloB' }, 2: { 'name': 'hi', 'key': 'AhiB' }, 3: { 'name': 'today', 'key': 'AtodayB' } })
def test_merge_override_callback(self): # override param can be set from callback. upper_config = { 'key1': 'abc', 'key2': 'bcd', 'key3': 'def', 'key_prefix': 'b', 'key_suffix': 'd' } upper_ref = config_reference.ConfigReference(upper_config) lower_configs = {1: {}, 2: {}, 3: {}} lower_refs = {} for lower_key, lower_config in lower_configs.items(): lower_refs[lower_key] = config_reference.ConfigReference( lower_config) def _generate_override(sub_ref, ref_key, lower_ref, to_key, prefix='', suffix=''): return (sub_ref.config.startswith(prefix) and sub_ref.config.endswith(suffix)) merger = config_merger.ConfigMapping( path_list=['key1', 'key2', 'key3'], to_key='/key', override=_generate_override, override_conditions={ 'prefix': '/key_prefix', 'suffix': '/key_suffix' }) merger.merge(upper_ref, lower_refs) self.assertEqual( lower_configs, { 1: { 'key': 'bcd', 'key1': None, 'key2': None, 'key3': None }, 2: { 'key': 'bcd', 'key1': None, 'key2': None, 'key3': None }, 3: { 'key': 'bcd', 'key1': None, 'key2': None, 'key3': None } })
def test_merge(self): # if multi ConfigMapping updates the same key and no override is set # for the later one, the later one will be ignored. config = {'key1': 'abc', 'key2': 'bcd'} lower_configs = {1: {}, 2: {}, 3: {}} merger = config_merger.ConfigMerger(mappings=[ config_merger.ConfigMapping(path_list=['key1'], to_key='/mkey'), config_merger.ConfigMapping(path_list=['key2'], to_key='/mkey') ]) merger.merge(config, lower_configs) self.assertEqual(lower_configs, { 1: { 'mkey': 'abc' }, 2: { 'mkey': 'abc' }, 3: { 'mkey': 'abc' } })
def test_init_from_lower_keys(self): # from_lower_keys should be dict of string to string. config_merger.ConfigMapping(path_list=['1/2/3', '/4/5/6'], from_lower_keys={'4': '4'}) config_merger.ConfigMapping(path_list=['1/2/3', '/4/5/6'], from_lower_keys={u'4': u'4'}) self.assertRaises(TypeError, config_merger.ConfigMapping, path_list=['1/2/3', '/4/5/6'], from_lower_keys=['4']) self.assertRaises(TypeError, config_merger.ConfigMapping, path_list=['1/2/3', '/4/5/6'], from_lower_keys='4') self.assertRaises(TypeError, config_merger.ConfigMapping, path_list=['1/2/3', '/4/5/6'], from_lower_keys={4: '4'}) self.assertRaises(TypeError, config_merger.ConfigMapping, path_list=['1/2/3', '/4/5/6'], from_lower_keys={'4': 4})
def test_merge_multi_mapping_to_same_tokey(self): # if multi ConfigMapping updates the same key and override is set # for the later one, the later one will override the former one. config = {'key1': 'abc', 'key2': 'bcd'} lower_configs = {1: {}, 2: {}, 3: {}} merger = config_merger.ConfigMerger(mappings=[ config_merger.ConfigMapping(path_list=['key1'], to_key='/mkey'), config_merger.ConfigMapping( path_list=['key2'], to_key='/mkey', override=True) ]) merger.merge(config, lower_configs) self.assertEqual(lower_configs, { 1: { 'mkey': 'bcd' }, 2: { 'mkey': 'bcd' }, 3: { 'mkey': 'bcd' } })
def test_merge_override_callback(self): # override param can be callback. config = {'key1': 'abc', 'key2': 'bcd'} lower_configs = {1: {}, 2: {}, 3: {}} def _merge_value(sub_ref, ref_key, lower_sub_refs, to_key): values = {} for lower_key, lower_sub_ref in lower_sub_refs.items(): values[lower_key] = None return values merger = config_merger.ConfigMerger(mappings=[ config_merger.ConfigMapping( path_list=['key1'], value=_merge_value, to_key='/mkey') ]) merger.merge(config, lower_configs) self.assertEqual(lower_configs, {1: None, 2: None, 3: None})
def test_init_override_conditions(self): # override_conditions type should be dict of string to string. config_merger.ConfigMapping(path_list=['1/2/3', '/4/5/6'], override_conditions={'hello': 'hi'}) self.assertRaises(TypeError, config_merger.ConfigMapping, path_list=['1/2/3', '/4/5/6'], override_conditions=['hello', 'hi']) self.assertRaises(TypeError, config_merger.ConfigMapping, path_list=['1/2/3', '/4/5/6'], override_conditions='hello') self.assertRaises(TypeError, config_merger.ConfigMapping, path_list=['1/2/3', '/4/5/6'], override_conditions={5: 'hi'}) self.assertRaises(TypeError, config_merger.ConfigMapping, path_list=['1/2/3', '/4/5/6'], override_conditions={'hello': 5})
def test_init_overlap_upper_keys_lower_keys(self): # there should be overlap between from_upper_keys and from_lower_keys. self.assertRaises(KeyError, config_merger.ConfigMapping, path_list=['1/2/3', '/4/5/6'], from_upper_keys={ '1': '1', '2': '2' }, from_lower_keys={ '1': '1', '3': '3' }) config_merger.ConfigMapping(path_list=['1/2/3', '/4/5/6'], from_upper_keys={ '1': '1', '2': '2' }, from_lower_keys={ '3': '3', '4': '4' })
def test_merge_value_set_explictly(self): # key in lower configs are set to expected value. upper_config = {'key': 'abc', 'key2': 'def'} upper_ref = config_reference.ConfigReference(upper_config) lower_configs = {1: {}, 2: {}, 3: {}} lower_refs = {} for lower_key, lower_config in lower_configs.items(): lower_refs[lower_key] = config_reference.ConfigReference( lower_config) merger = config_merger.ConfigMapping(path_list=['key'], value='def') merger.merge(upper_ref, lower_refs) self.assertEqual(lower_configs, { 1: { 'key': 'def' }, 2: { 'key': 'def' }, 3: { 'key': 'def' } })
def test_merge_to_key(self): # set lower configs expected key from the key in upper config. upper_config = {'key': 'abc', 'key2': 'def'} upper_ref = config_reference.ConfigReference(upper_config) lower_configs = {1: {}, 2: {}, 3: {}} lower_refs = {} for lower_key, lower_config in lower_configs.items(): lower_refs[lower_key] = config_reference.ConfigReference( lower_config) def _merge_value(sub_ref, ref_key, lower_sub_refs, to_key): values = {} for lower_key, lower_sub_ref in lower_sub_refs.items(): values[lower_key] = '%s.%s' % (sub_ref.config, lower_key) return values merger = config_merger.ConfigMapping(path_list=['key'], value=_merge_value, to_key='/key2') merger.merge(upper_ref, lower_refs) self.assertEqual( lower_configs, { 1: { 'key': None, 'key2': 'abc.1' }, 2: { 'key': None, 'key2': 'abc.2' }, 3: { 'key': None, 'key2': 'abc.3' } })
def test_merge(self): upper_config = { 'networking': { 'interfaces': { 'management': { 'ip_start': '192.168.1.1', 'ip_end': '192.168.1.100', 'netmask': '255.255.255.0', 'dns_pattern': '%(hostname)s.%(clustername)s.%(search_path)s', }, 'floating': { 'ip_start': '172.16.0.1', 'ip_end': '172.16.0.100', 'netmask': '0.0.0.0', 'dns_pattern': 'public-%(hostname)s.%(clustername)s.%(search_path)s', }, }, 'global': { 'search_path': 'ods.com', 'default_no_proxy': ['127.0.0.1', 'localhost'], }, }, 'clustername': 'cluster1', 'dashboard_roles': ['os-single-controller'], 'role_assign_policy': { 'policy_by_host_numbers': {}, 'default': { 'roles': ['os-single-controller', 'os-network', 'os-compute-worker'], 'default_min': 1, }, }, } lower_configs = { 1: { 'hostname': 'host1', }, 2: { 'hostname': 'host2', 'networking': { 'interfaces': { 'management': { 'ip': '192.168.1.50', }, }, }, 'roles': ['os-single-controller', 'os-network'], } } expected_lower_configs = { 1: { 'networking': { 'interfaces': { 'floating': { 'ip': '172.16.0.1', 'netmask': '0.0.0.0', 'dns_alias': 'public-host1.cluster1.ods.com' }, 'management': { 'ip': '192.168.1.1', 'netmask': '255.255.255.0', 'dns_alias': 'host1.cluster1.ods.com' } }, 'global': { 'search_path': 'ods.com', 'default_no_proxy': ['127.0.0.1', 'localhost'], 'ignore_proxy': '127.0.0.1,localhost,host1,192.168.1.1,host2,192.168.1.50' } }, 'hostname': 'host1', 'has_dashboard_roles': False, 'roles': ['os-compute-worker'] }, 2: { 'networking': { 'interfaces': { 'floating': { 'ip': '172.16.0.2', 'netmask': '0.0.0.0', 'dns_alias': 'public-host2.cluster1.ods.com' }, 'management': { 'ip': '192.168.1.50', 'netmask': '255.255.255.0', 'dns_alias': 'host2.cluster1.ods.com' } }, 'global': { 'search_path': 'ods.com', 'default_no_proxy': ['127.0.0.1', 'localhost'], 'ignore_proxy': '127.0.0.1,localhost,host1,192.168.1.1,host2,192.168.1.50' } }, 'hostname': 'host2', 'has_dashboard_roles': True, 'roles': ['os-single-controller', 'os-network'] } } mappings=[ config_merger.ConfigMapping( path_list=['/networking/interfaces/*'], from_upper_keys={'ip_start': 'ip_start', 'ip_end': 'ip_end'}, to_key='ip', value=config_merger_callbacks.assign_ips ), config_merger.ConfigMapping( path_list=['/role_assign_policy'], from_upper_keys={ 'policy_by_host_numbers': 'policy_by_host_numbers', 'default': 'default'}, to_key='/roles', value=config_merger_callbacks.assign_roles_by_host_numbers ), config_merger.ConfigMapping( path_list=['/dashboard_roles'], from_lower_keys={'lower_values': '/roles'}, to_key='/has_dashboard_roles', value=config_merger_callbacks.has_intersection ), config_merger.ConfigMapping( path_list=[ '/networking/global', '/networking/interfaces/*/netmask', '/networking/interfaces/*/nic', '/networking/interfaces/*/promisc', '/security/*', '/partition', ] ), config_merger.ConfigMapping( path_list=['/networking/interfaces/*'], from_upper_keys={'pattern': 'dns_pattern', 'clustername': '/clustername', 'search_path': '/networking/global/search_path'}, from_lower_keys={'hostname': '/hostname'}, to_key='dns_alias', value=functools.partial(config_merger_callbacks.assign_from_pattern, upper_keys=['search_path', 'clustername'], lower_keys=['hostname']) ), config_merger.ConfigMapping( path_list=['/networking/global'], from_upper_keys={'default': 'default_no_proxy'}, from_lower_keys={'hostnames': '/hostname', 'ips': '/networking/interfaces/management/ip'}, to_key='ignore_proxy', value=config_merger_callbacks.assign_noproxy ) ] merger = config_merger.ConfigMerger(mappings) merger.merge(upper_config, lower_configs) self.assertEqual(lower_configs, expected_lower_configs)