Changed section/parameter reference schema in Configuration class, added template substitution

This commit is contained in:
Maxim Kulkin 2013-10-14 12:24:40 +04:00
parent 841264e185
commit 4ceec12865
6 changed files with 176 additions and 107 deletions

View File

@ -1,3 +1,5 @@
import string
from ostack_validator.common import Mark
class ConfigurationSection(object):
@ -6,29 +8,35 @@ class ConfigurationSection(object):
self.config = config
self.section = section
def get(self, *args, **kwargs):
return self.config.get(self.section, *args, **kwargs)
def _combine_names(self, section, param):
if section == 'DEFAULT':
return param
def set(self, *args, **kwargs):
self.config.set(self.section, *args, **kwargs)
return '%s.%s' % (section, param)
def set_default(self, *args, **kwargs):
self.config.set_default(self.section, *args, **kwargs)
def get(self, name, *args, **kwargs):
return self.config.get(self._combine_names(self.section, name), *args, **kwargs)
def contains(self, *args, **kwargs):
return self.config.contains(self.section, *args, **kwargs)
def set(self, name, *args, **kwargs):
self.config.set(self._combine_names(self.section, name), *args, **kwargs)
def is_default(self, *args, **kwargs):
return self.config.is_default(self.section, *args, **kwargs)
def set_default(self, name, *args, **kwargs):
self.config.set_default(self._combine_names(self.section, name), *args, **kwargs)
def contains(self, name, *args, **kwargs):
return self.config.contains(self._combine_names(self.section, name), *args, **kwargs)
def is_default(self, name, *args, **kwargs):
return self.config.is_default(self._combine_names(self.section, name), *args, **kwargs)
def __getitem__(self, key):
return self.config.get(self.section, key)
return self.config.get(self._combine_names(self.section, key))
def __setitem__(self, key, value):
return self.config.set(self.section, key, value)
return self.config.set(self._combine_names(self.section, key), value)
def __contains__(self, key):
return self.config.contains(self.section, key)
return self.config.contains(self._combine_names(self.section, key))
def keys(self):
return self.config.keys(self.section)
@ -36,6 +44,18 @@ class ConfigurationSection(object):
def items(self, *args, **kwargs):
return self.config.items(self.section, *args, **kwargs)
class ConfigurationWrapper(object):
def __init__(self, config, state):
super(ConfigurationWrapper, self).__init__()
self.config = config
self.state = state
def __getitem__(self, key):
if key in self.state:
return ''
return self.config.get(key, _state=self.state)
class Configuration(object):
def __init__(self):
@ -43,16 +63,39 @@ class Configuration(object):
self._defaults = dict()
self._normal = dict()
def get(self, section, name, default=None):
def _normalize_name(self, name):
if name.find('.') == -1:
section = 'DEFAULT'
else:
section, name = name.split('.', 1)
return (section, name)
def _combine_names(self, section, param):
if section == 'DEFAULT':
return param
return '%s.%s' % (section, param)
def get(self, name, default=None, _state=[]):
section, name = self._normalize_name(name)
if section in self._normal and name in self._normal[section]:
return self._normal[section][name]
value = self._normal[section][name]
elif section in self._defaults and name in self._defaults[section]:
value = self._defaults[section][name]
else:
value = default
if section in self._defaults and name in self._defaults[section]:
return self._defaults[section][name]
if not isinstance(value, str):
return value
return default
tmpl = string.Template(value)
return tmpl.safe_substitute(ConfigurationWrapper(self, _state + [name]))
def contains(self, name, ignoreDefault=False):
section, name = self._normalize_name(name)
def contains(self, section, name, ignoreDefault=False):
if section in self._normal and name in self._normal[section]:
return True
@ -61,16 +104,22 @@ class Configuration(object):
return False
def is_default(self, section, name):
def is_default(self, name):
section, name = self._normalize_name(name)
return not (section in self._normal and name in self._normal[section]) and (section in self._defaults and name in self._defaults[section])
def set_default(self, section, name, value):
def set_default(self, name, value):
section, name = self._normalize_name(name)
if not section in self._defaults:
self._defaults[section] = dict()
self._defaults[section][name] = value
def set(self, section, name, value):
def set(self, name, value):
section, name = self._normalize_name(name)
if not section in self._normal:
self._normal[section] = dict()
@ -80,18 +129,10 @@ class Configuration(object):
return ConfigurationSection(self, section)
def __getitem__(self, key):
if not isinstance(key, tuple) == 1:
return self.section(key)
elif isinstance(key, tuple) and len(key) == 2:
return self.get(key[0], key[1])
else:
raise TypeError, "expectes 1 or 2 arguments, %d given" % len(key)
return self.get(key)
def __setitem__(self, key, value):
if isinstance(key, tuple) and len(key) == 2:
self.set(key[0], key[1], value)
else:
raise TypeError, "key expected to be section + parameter names, got %s" % key
self.set(key, value)
def __contains__(self, section):
return (section in self._defaults) or (section in self._normal)
@ -119,7 +160,7 @@ class Configuration(object):
def items(self, section=None):
if section:
return [(name, self.get(section, name)) for name in self.keys(section)]
return [(name, self.get(self._combine_names(section, name))) for name in self.keys(section)]
else:
return [(name, ConfigurationSection(self, name)) for name in self.keys()]

View File

@ -204,11 +204,11 @@ class OpenstackDiscovery(object):
keystone.version = self._find_python_package_version(client, 'keystone')
keystone.config_file = self._collect_file(client, config_path)
token = keystone.config['DEFAULT']['admin_token']
host = keystone.config['DEFAULT']['bind_host']
token = keystone.config['admin_token']
host = keystone.config['bind_host']
if host == '0.0.0.0':
host = '127.0.0.1'
port = int(keystone.config['DEFAULT']['admin_port'])
port = int(keystone.config['admin_port'])
keystone_env = {
'OS_SERVICE_TOKEN': token,
@ -238,7 +238,7 @@ class OpenstackDiscovery(object):
nova_api.version = self._find_python_package_version(client, 'nova')
nova_api.config_file = self._collect_file(client, config_path)
paste_config_path = path_relative_to(nova_api.config['DEFAULT']['api_paste_config'], os.path.dirname(config_path))
paste_config_path = path_relative_to(nova_api.config['api_paste_config'], os.path.dirname(config_path))
nova_api.paste_config_file = self._collect_file(client, paste_config_path)
return nova_api
@ -326,7 +326,7 @@ class OpenstackDiscovery(object):
cinder_api.version = self._find_python_package_version(client, 'cinder')
cinder_api.config_file = self._collect_file(client, config_path)
paste_config_path = path_relative_to(cinder_api.config['DEFAULT']['api_paste_config'], os.path.dirname(config_path))
paste_config_path = path_relative_to(cinder_api.config['api_paste_config'], os.path.dirname(config_path))
cinder_api.paste_config_file = self._collect_file(client, paste_config_path)
return cinder_api
@ -346,7 +346,7 @@ class OpenstackDiscovery(object):
cinder_volume.version = self._find_python_package_version(client, 'cinder')
cinder_volume.config_file = self._collect_file(client, config_path)
rootwrap_config_path = path_relative_to(cinder_volume.config['DEFAULT']['rootwrap_config'], os.path.dirname(config_path))
rootwrap_config_path = path_relative_to(cinder_volume.config['rootwrap_config'], os.path.dirname(config_path))
cinder_volume.rootwrap_config = self._collect_file(client, rootwrap_config_path)
return cinder_volume
@ -400,3 +400,4 @@ class OpenstackDiscovery(object):
return None
return None

View File

@ -18,12 +18,12 @@ class KeystoneAuthtokenSettingsInspection(Inspection):
return
keystone = keystones[0]
keystone_addresses = [keystone.config['DEFAULT']['bind_host']]
keystone_addresses = [keystone.config['bind_host']]
if keystone_addresses == ['0.0.0.0']:
keystone_addresses = keystone.host.network_addresses
for nova in [c for c in components if c.name == 'nova-api']:
if nova.config['DEFAULT']['auth_strategy'] != 'keystone':
if nova.config['auth_strategy'] != 'keystone':
continue
(authtoken_section,_) = find(
@ -33,11 +33,11 @@ class KeystoneAuthtokenSettingsInspection(Inspection):
if not authtoken_section: continue
authtoken_settings = nova.paste_config[authtoken_section]
authtoken_settings = nova.paste_config.section(authtoken_section)
def get_value(name):
return authtoken_settings[name] or nova.config['keystone_authtoken', name]
return authtoken_settings[name] or nova.config['keystone_authtoken.%s' % name]
auth_host = get_value('auth_host')
auth_port = get_value('auth_port')
@ -56,7 +56,7 @@ class KeystoneAuthtokenSettingsInspection(Inspection):
if not auth_port:
nova.report_issue(Issue(Issue.ERROR, msg_prefix + ' miss "auth_port" setting in keystone authtoken config'))
elif auth_port != keystone.config['DEFAULT']['admin_port']:
elif auth_port != keystone.config['admin_port']:
nova.report_issue(Issue(Issue.ERROR, msg_prefix + ' has incorrect "auth_port" setting in keystone authtoken config'))
if not auth_protocol:

View File

@ -31,7 +31,7 @@ class KeystoneEndpointsInspection(Inspection):
for c in host.components:
if c.name != 'nova-compute': continue
if c.config['DEFAULT', 'osapi_compute_listen'] in ['0.0.0.0', url.hostname] and c.config['DEFAULT', 'osapi_compute_listen_port'] == url.port:
if c.config['osapi_compute_listen'] in ['0.0.0.0', url.hostname] and c.config['osapi_compute_listen_port'] == url.port:
nova_compute = c
break

View File

@ -139,7 +139,10 @@ class OpenstackComponent(Service):
# Apply defaults
if schema:
for parameter in filter(lambda p: p.default, schema.parameters):
_config.set_default(parameter.section, parameter.name, parameter.default)
if parameter.section == 'DEFAULT':
_config.set_default(parameter.name, parameter.default)
else:
_config.set_default('%s.%s' % (parameter.section, parameter.name), parameter.default)
# Parse config file
@ -182,6 +185,10 @@ class OpenstackComponent(Service):
else:
seen_parameters.add(parameter.name.text)
parameter_fullname = parameter.name.text
if section_name != 'DEFAULT':
parameter_fullname = section_name + '.' + parameter_fullname
if parameter_schema:
type_validator = TypeValidatorRegistry.get_validator(parameter_schema.type)
type_validation_result = type_validator.validate(parameter.value.text)
@ -193,14 +200,14 @@ class OpenstackComponent(Service):
else:
value = type_validation_result
_config.set(section_name, parameter.name.text, value)
_config.set(parameter_fullname, value)
# if value == parameter_schema.default:
# report_issue(MarkedIssue(Issue.INFO, 'Explicit value equals default: section "%s" parameter "%s"' % (section_name, parameter.name.text), parameter.start_mark))
if parameter_schema.deprecation_message:
report_issue(MarkedIssue(Issue.WARNING, 'Deprecated parameter: section "%s" name "%s". %s' % (section_name, parameter.name.text, parameter_schema.deprecation_message), parameter.start_mark))
else:
_config.set(section_name, parameter.name.text, parameter.value.text)
_config.set(parameter_fullname, parameter.value.text)
return _config

View File

@ -5,173 +5,193 @@ from ostack_validator.config_model import Configuration
class ConfigurationTests(unittest.TestCase):
section = 'section1'
param = 'param1'
fullparam = '%s.%s' % (section, param)
value = 'foobar'
default_value = 'bar123'
def test_empty(self):
c = Configuration()
self.assertIsNone(c.get('section1', 'param1'))
self.assertIsNone(c.get('section1.param1'))
def test_storage(self):
c = Configuration()
c.set(self.section, self.param, self.value)
c.set(self.fullparam, self.value)
self.assertEqual(self.value, c.get(self.section, self.param))
self.assertEqual(self.value, c.get(self.fullparam))
def test_parameter_names_containing_sections(self):
c = Configuration()
c.set(self.fullparam, self.value)
self.assertEqual(self.value, c.get('%s.%s' % (self.section, self.param)))
def test_parameter_with_default_section(self):
c = Configuration()
c.set(self.param, self.value)
self.assertEqual(self.value, c.get(self.param))
def test_explicit_default_on_get(self):
c = Configuration()
override_value = '12345'
self.assertEqual(override_value, c.get(self.section, self.param, default=override_value))
self.assertEqual(override_value, c.get(self.fullparam, default=override_value))
def test_default(self):
c = Configuration()
c.set_default(self.section, self.param, self.default_value)
c.set_default(self.fullparam, self.default_value)
self.assertEqual(self.default_value, c.get(self.section, self.param))
self.assertEqual(self.default_value, c.get(self.fullparam))
def test_normal_overrides_default(self):
c = Configuration()
c.set(self.section, self.param, self.value)
c.set_default(self.section, self.param, self.default_value)
c.set(self.fullparam, self.value)
c.set_default(self.fullparam, self.default_value)
self.assertEqual(self.value, c.get(self.section, self.param))
self.assertEqual(self.value, c.get(self.fullparam))
def test_contains(self):
c = Configuration()
self.assertFalse(c.contains(self.section, self.param))
self.assertFalse(c.contains(self.fullparam))
def test_contains_default(self):
c = Configuration()
c.set_default(self.section, self.param, self.default_value)
c.set_default(self.fullparam, self.default_value)
self.assertTrue(c.contains(self.section, self.param))
self.assertFalse(c.contains(self.section, self.param, ignoreDefault=True))
self.assertTrue(c.contains(self.fullparam))
self.assertFalse(c.contains(self.fullparam, ignoreDefault=True))
def test_contains_normal(self):
c = Configuration()
c.set(self.section, self.param, self.value)
c.set(self.fullparam, self.value)
self.assertTrue(c.contains(self.section, self.param))
self.assertTrue(c.contains(self.section, self.param, ignoreDefault=True))
self.assertTrue(c.contains(self.fullparam))
self.assertTrue(c.contains(self.fullparam, ignoreDefault=True))
def test_is_default_returns_false_if_param_missing(self):
c = Configuration()
self.assertFalse(c.is_default(self.section, self.param))
self.assertFalse(c.is_default(self.fullparam))
def test_is_default_returns_true_if_only_default_value_set(self):
c = Configuration()
c.set_default(self.section, self.param, self.default_value)
c.set_default(self.fullparam, self.default_value)
self.assertTrue(c.is_default(self.section, self.param))
self.assertTrue(c.is_default(self.fullparam))
def test_is_default_returns_false_if_normal_value_set(self):
c = Configuration()
c.set(self.section, self.param, self.value)
c.set(self.fullparam, self.value)
self.assertFalse(c.is_default(self.section, self.param))
self.assertFalse(c.is_default(self.fullparam))
def test_is_default_returns_false_if_both_values_set(self):
c = Configuration()
c.set_default(self.section, self.param, self.default_value)
c.set(self.section, self.param, self.value)
c.set_default(self.fullparam, self.default_value)
c.set(self.fullparam, self.value)
self.assertFalse(c.is_default(self.section, self.param))
self.assertFalse(c.is_default(self.fullparam))
def test_subsection_set(self):
c = Configuration()
c[self.section].set(self.param, self.value)
c.section(self.section).set(self.param, self.value)
self.assertEqual(self.value, c.get(self.section, self.param))
self.assertEqual(self.value, c.get(self.fullparam))
def test_keys(self):
c = Configuration()
c.set_default('section1', 'param1', '123')
c.set('section2', 'param1', '456')
c.set_default('section1.param1', '123')
c.set('section2.param1', '456')
self.assertEqual(['section1', 'section2'], sorted(c.keys()))
def test_subsection_keys(self):
c = Configuration()
c.set_default(self.section, 'param1', '123')
c.set(self.section, 'param2', '456')
c.set_default('%s.param1' % self.section, '123')
c.set('%s.param2' % self.section, '456')
self.assertEqual(['param1', 'param2'], sorted(c[self.section].keys()))
self.assertEqual(['param1', 'param2'], sorted(c.section(self.section).keys()))
def test_subsection_items(self):
c = Configuration()
c.set(self.section, 'param1', 'value1')
c.set_default(self.section, 'param2', 'value2')
c.set('%s.param1' % self.section, 'value1')
c.set_default('%s.param2' % self.section, 'value2')
self.assertEqual([('param1', 'value1'), ('param2', 'value2')], sorted(c[self.section].items()))
self.assertEqual([('param1', 'value1'), ('param2', 'value2')], sorted(c.section(self.section).items()))
def test_subsection_get(self):
c = Configuration()
c.set(self.section, self.param, self.value)
c.set(self.fullparam, self.value)
cs = c.section(self.section)
self.assertEqual(self.value, cs.get(self.param))
def test_subsection_through_indexer(self):
c = Configuration()
c.set(self.section, self.param, self.value)
cs = c[self.section]
self.assertEqual(self.value, cs.get(self.param))
def test_getitem(self):
c = Configuration()
c.set(self.section, self.param, self.value)
c.set(self.fullparam, self.value)
self.assertEqual(self.value, c[self.section, self.param])
self.assertEqual(self.value, c[self.fullparam])
def test_subsection_getitem(self):
c = Configuration()
c.set(self.section, self.param, self.value)
c.set(self.fullparam, self.value)
cs = c[self.section]
cs = c.section(self.section)
self.assertEqual(self.value, cs[self.param])
def test_setitem(self):
c = Configuration()
c[self.section, self.param] = self.value
c[self.fullparam] = self.value
self.assertEqual(self.value, c.get(self.section, self.param))
self.assertEqual(self.value, c.get(self.fullparam))
def test_subsection_setitem(self):
c = Configuration()
cs = c[self.section]
cs = c.section(self.section)
cs[self.param] = self.value
self.assertEqual(self.value, c.get(self.section, self.param))
self.assertEqual(self.value, c.get(self.fullparam))
def test_contains(self):
c = Configuration()
self.assertFalse(self.section in c)
c.set(self.section, self.param, self.value)
c.set(self.fullparam, self.value)
self.assertTrue(self.section in c)
def test_subsection_contains(self):
c = Configuration()
c.set('section1', 'param1', '123')
c.set_default('section2', 'param2', '234')
c.set('section1.param1', '123')
c.set_default('section2.param2', '234')
self.assertTrue('param1' in c['section1'])
self.assertTrue('param2' in c['section2'])
self.assertFalse('param1' in c['section2'])
self.assertTrue('param1' in c.section('section1'))
self.assertTrue('param2' in c.section('section2'))
self.assertFalse('param1' in c.section('section2'))
def test_returns_section_object_even_if_section_doesnot_exist(self):
c = Configuration()
self.assertIsNotNone(c['foo'])
self.assertIsNotNone(c.section('foo'))
def test_template_substitution(self):
c = Configuration()
c.set('a', 'x')
c.set('b', '$a')
c.set('c', '$b')
self.assertEqual('x', c.get('c'))
def test_cycle_template_substitution_resolves_in_empty_string(self):
c = Configuration()
c.set('a', 'a$c')
c.set('b', 'b$a')
c.set('c', 'c$b')
self.assertEqual('cba', c.get('c'))