Allow cfg values to be stored in a templated format
This commit is contained in:
parent
f0de6f3dbd
commit
249d4f1355
55
anvil/cfg.py
55
anvil/cfg.py
@ -34,6 +34,9 @@ LOG = logging.getLogger(__name__)
|
|||||||
|
|
||||||
|
|
||||||
class StringiferMixin(object):
|
class StringiferMixin(object):
|
||||||
|
def __init__(self):
|
||||||
|
pass
|
||||||
|
|
||||||
def stringify(self, fn=None):
|
def stringify(self, fn=None):
|
||||||
contents = ''
|
contents = ''
|
||||||
with io.BytesIO() as outputstream:
|
with io.BytesIO() as outputstream:
|
||||||
@ -43,16 +46,19 @@ class StringiferMixin(object):
|
|||||||
return contents
|
return contents
|
||||||
|
|
||||||
|
|
||||||
class IgnoreMissingMixin(object):
|
class ConfigHelperMixin(object):
|
||||||
DEF_INT = 0
|
DEF_INT = 0
|
||||||
DEF_FLOAT = 0.0
|
DEF_FLOAT = 0.0
|
||||||
DEF_BOOLEAN = False
|
DEF_BOOLEAN = False
|
||||||
DEF_BASE = None
|
DEF_BASE = None
|
||||||
|
|
||||||
|
def __init__(self, templatize_values=False):
|
||||||
|
self.templatize_values = templatize_values
|
||||||
|
|
||||||
def get(self, section, option):
|
def get(self, section, option):
|
||||||
value = self.DEF_BASE
|
value = self.DEF_BASE
|
||||||
try:
|
try:
|
||||||
value = super(IgnoreMissingMixin, self).get(section, option)
|
value = super(ConfigHelperMixin, self).get(section, option)
|
||||||
except NoSectionError:
|
except NoSectionError:
|
||||||
pass
|
pass
|
||||||
except NoOptionError:
|
except NoOptionError:
|
||||||
@ -62,32 +68,41 @@ class IgnoreMissingMixin(object):
|
|||||||
def set(self, section, option, value):
|
def set(self, section, option, value):
|
||||||
if not self.has_section(section) and section.lower() != 'default':
|
if not self.has_section(section) and section.lower() != 'default':
|
||||||
self.add_section(section)
|
self.add_section(section)
|
||||||
super(IgnoreMissingMixin, self).set(section, option, value)
|
if self.templatize_values:
|
||||||
|
real_value = "%" + str(option) + "%"
|
||||||
|
for c in ['-', ' ', '\t', ':']:
|
||||||
|
real_value = real_value.replace(c, '_')
|
||||||
|
value = real_value
|
||||||
|
super(ConfigHelperMixin, self).set(section, option, value)
|
||||||
|
|
||||||
def remove_option(self, section, option):
|
def remove_option(self, section, option):
|
||||||
if self.has_option(section, option):
|
if self.has_option(section, option):
|
||||||
super(IgnoreMissingMixin, self).remove_option(section, option)
|
super(ConfigHelperMixin, self).remove_option(section, option)
|
||||||
|
|
||||||
def getboolean(self, section, option):
|
def getboolean(self, section, option):
|
||||||
if not self.has_option(section, option):
|
if not self.has_option(section, option):
|
||||||
return self.DEF_BOOLEAN
|
return self.DEF_BOOLEAN
|
||||||
return super(IgnoreMissingMixin, self).getboolean(section, option)
|
return super(ConfigHelperMixin, self).getboolean(section, option)
|
||||||
|
|
||||||
def getfloat(self, section, option):
|
def getfloat(self, section, option):
|
||||||
if not self.has_option(section, option):
|
if not self.has_option(section, option):
|
||||||
return self.DEF_FLOAT
|
return self.DEF_FLOAT
|
||||||
return super(IgnoreMissingMixin, self).getfloat(section, option)
|
return super(ConfigHelperMixin, self).getfloat(section, option)
|
||||||
|
|
||||||
def getint(self, section, option):
|
def getint(self, section, option):
|
||||||
if not self.has_option(section, option):
|
if not self.has_option(section, option):
|
||||||
return self.DEF_INT
|
return self.DEF_INT
|
||||||
return super(IgnoreMissingMixin, self).getint(section, option)
|
return super(ConfigHelperMixin, self).getint(section, option)
|
||||||
|
|
||||||
|
def getlist(self, section, option):
|
||||||
|
return self.get(section, option).split(",")
|
||||||
|
|
||||||
|
|
||||||
class BuiltinConfigParser(IgnoreMissingMixin, ConfigParser.RawConfigParser, StringiferMixin):
|
class BuiltinConfigParser(ConfigHelperMixin, ConfigParser.RawConfigParser, StringiferMixin):
|
||||||
def __init__(self, cs=True, fns=None, defaults=None):
|
def __init__(self, fns=None, templatize_values=False):
|
||||||
ConfigParser.RawConfigParser.__init__(self, defaults=defaults)
|
ConfigHelperMixin.__init__(self, templatize_values)
|
||||||
if cs:
|
ConfigParser.RawConfigParser.__init__(self)
|
||||||
|
StringiferMixin.__init__(self)
|
||||||
# Make option names case sensitive
|
# Make option names case sensitive
|
||||||
# See: http://docs.python.org/library/configparser.html#ConfigParser.RawConfigParser.optionxform
|
# See: http://docs.python.org/library/configparser.html#ConfigParser.RawConfigParser.optionxform
|
||||||
self.optionxform = str
|
self.optionxform = str
|
||||||
@ -96,10 +111,11 @@ class BuiltinConfigParser(IgnoreMissingMixin, ConfigParser.RawConfigParser, Stri
|
|||||||
self.read(f)
|
self.read(f)
|
||||||
|
|
||||||
|
|
||||||
class RewritableConfigParser(IgnoreMissingMixin, iniparse.RawConfigParser, StringiferMixin):
|
class RewritableConfigParser(ConfigHelperMixin, iniparse.RawConfigParser, StringiferMixin):
|
||||||
def __init__(self, cs=True, fns=None, defaults=None):
|
def __init__(self, fns=None, templatize_values=False):
|
||||||
iniparse.RawConfigParser.__init__(self, defaults=defaults)
|
ConfigHelperMixin.__init__(self, templatize_values)
|
||||||
if cs:
|
iniparse.RawConfigParser.__init__(self)
|
||||||
|
StringiferMixin.__init__(self)
|
||||||
# Make option names case sensitive
|
# Make option names case sensitive
|
||||||
# See: http://docs.python.org/library/configparser.html#ConfigParser.RawConfigParser.optionxform
|
# See: http://docs.python.org/library/configparser.html#ConfigParser.RawConfigParser.optionxform
|
||||||
self.optionxform = str
|
self.optionxform = str
|
||||||
@ -226,3 +242,12 @@ class YamlInterpolator(object):
|
|||||||
self.interpolated[root] = self.included[root]
|
self.interpolated[root] = self.included[root]
|
||||||
self.interpolated[root] = self._interpolate(self.interpolated[root])
|
self.interpolated[root] = self._interpolate(self.interpolated[root])
|
||||||
return self.interpolated[root]
|
return self.interpolated[root]
|
||||||
|
|
||||||
|
|
||||||
|
def create_parser(cfg_cls, component, fns=None):
|
||||||
|
templatize_values = component.get_bool_option('template_config')
|
||||||
|
cfg_opts = {
|
||||||
|
'fns': fns,
|
||||||
|
'templatize_values': templatize_values,
|
||||||
|
}
|
||||||
|
return cfg_cls(**cfg_opts)
|
||||||
|
@ -111,7 +111,7 @@ class GlanceInstaller(comp.PythonInstallComponent):
|
|||||||
def _config_adjust_registry(self, contents, fn):
|
def _config_adjust_registry(self, contents, fn):
|
||||||
params = ghelper.get_shared_params(**self.options)
|
params = ghelper.get_shared_params(**self.options)
|
||||||
with io.BytesIO(contents) as stream:
|
with io.BytesIO(contents) as stream:
|
||||||
config = cfg.RewritableConfigParser()
|
config = cfg.create_parser(cfg.RewritableConfigParser, self)
|
||||||
config.readfp(stream)
|
config.readfp(stream)
|
||||||
config.set('DEFAULT', 'debug', self.get_bool_option('verbose'))
|
config.set('DEFAULT', 'debug', self.get_bool_option('verbose'))
|
||||||
config.set('DEFAULT', 'verbose', self.get_bool_option('verbose'))
|
config.set('DEFAULT', 'verbose', self.get_bool_option('verbose'))
|
||||||
@ -132,7 +132,7 @@ class GlanceInstaller(comp.PythonInstallComponent):
|
|||||||
**utils.merge_dicts(self.get_option('keystone'),
|
**utils.merge_dicts(self.get_option('keystone'),
|
||||||
khelper.get_shared_passwords(self)))
|
khelper.get_shared_passwords(self)))
|
||||||
with io.BytesIO(contents) as stream:
|
with io.BytesIO(contents) as stream:
|
||||||
config = cfg.RewritableConfigParser()
|
config = cfg.create_parser(cfg.RewritableConfigParser, self)
|
||||||
config.readfp(stream)
|
config.readfp(stream)
|
||||||
config.set('filter:authtoken', 'auth_host', params['endpoints']['admin']['host'])
|
config.set('filter:authtoken', 'auth_host', params['endpoints']['admin']['host'])
|
||||||
config.set('filter:authtoken', 'auth_port', params['endpoints']['admin']['port'])
|
config.set('filter:authtoken', 'auth_port', params['endpoints']['admin']['port'])
|
||||||
@ -150,7 +150,7 @@ class GlanceInstaller(comp.PythonInstallComponent):
|
|||||||
def _config_adjust_api(self, contents, fn):
|
def _config_adjust_api(self, contents, fn):
|
||||||
params = ghelper.get_shared_params(**self.options)
|
params = ghelper.get_shared_params(**self.options)
|
||||||
with io.BytesIO(contents) as stream:
|
with io.BytesIO(contents) as stream:
|
||||||
config = cfg.RewritableConfigParser()
|
config = cfg.create_parser(cfg.RewritableConfigParser, self)
|
||||||
config.readfp(stream)
|
config.readfp(stream)
|
||||||
img_store_dir = sh.joinpths(self.get_option('component_dir'), 'images')
|
img_store_dir = sh.joinpths(self.get_option('component_dir'), 'images')
|
||||||
config.set('DEFAULT', 'debug', self.get_bool_option('verbose',))
|
config.set('DEFAULT', 'debug', self.get_bool_option('verbose',))
|
||||||
@ -172,7 +172,7 @@ class GlanceInstaller(comp.PythonInstallComponent):
|
|||||||
|
|
||||||
def _config_adjust_logging(self, contents, fn):
|
def _config_adjust_logging(self, contents, fn):
|
||||||
with io.BytesIO(contents) as stream:
|
with io.BytesIO(contents) as stream:
|
||||||
config = cfg.RewritableConfigParser()
|
config = cfg.create_parser(cfg.RewritableConfigParser, self)
|
||||||
config.readfp(stream)
|
config.readfp(stream)
|
||||||
config.set('logger_root', 'level', 'DEBUG')
|
config.set('logger_root', 'level', 'DEBUG')
|
||||||
config.set('logger_root', 'handlers', "devel,production")
|
config.set('logger_root', 'handlers', "devel,production")
|
||||||
|
@ -144,7 +144,7 @@ class ConfConfigurator(object):
|
|||||||
def generate(self, fn):
|
def generate(self, fn):
|
||||||
|
|
||||||
# Everything built goes in here
|
# Everything built goes in here
|
||||||
nova_conf = Conf(fn)
|
nova_conf = Conf(fn, self.installer)
|
||||||
|
|
||||||
# Used more than once so we calculate it ahead of time
|
# Used more than once so we calculate it ahead of time
|
||||||
hostip = self.installer.get_option('ip')
|
hostip = self.installer.get_option('ip')
|
||||||
@ -387,8 +387,9 @@ class ConfConfigurator(object):
|
|||||||
|
|
||||||
# This class represents the data/format of the nova config file
|
# This class represents the data/format of the nova config file
|
||||||
class Conf(object):
|
class Conf(object):
|
||||||
def __init__(self, name):
|
def __init__(self, name, installer):
|
||||||
self.backing = cfg.BuiltinConfigParser()
|
self.installer = installer
|
||||||
|
self.backing = cfg.create_parser(cfg.BuiltinConfigParser, self.installer)
|
||||||
self.name = name
|
self.name = name
|
||||||
|
|
||||||
def add(self, key, value, *values):
|
def add(self, key, value, *values):
|
||||||
|
@ -132,7 +132,7 @@ class KeystoneInstaller(comp.PythonInstallComponent):
|
|||||||
|
|
||||||
def _config_adjust_logging(self, contents, fn):
|
def _config_adjust_logging(self, contents, fn):
|
||||||
with io.BytesIO(contents) as stream:
|
with io.BytesIO(contents) as stream:
|
||||||
config = cfg.RewritableConfigParser()
|
config = cfg.create_parser(cfg.RewritableConfigParser, self)
|
||||||
config.readfp(stream)
|
config.readfp(stream)
|
||||||
config.set('logger_root', 'level', 'DEBUG')
|
config.set('logger_root', 'level', 'DEBUG')
|
||||||
config.set('logger_root', 'handlers', "devel,production")
|
config.set('logger_root', 'handlers', "devel,production")
|
||||||
@ -150,7 +150,7 @@ class KeystoneInstaller(comp.PythonInstallComponent):
|
|||||||
params = khelper.get_shared_params(**utils.merge_dicts(self.options,
|
params = khelper.get_shared_params(**utils.merge_dicts(self.options,
|
||||||
khelper.get_shared_passwords(self)))
|
khelper.get_shared_passwords(self)))
|
||||||
with io.BytesIO(contents) as stream:
|
with io.BytesIO(contents) as stream:
|
||||||
config = cfg.RewritableConfigParser()
|
config = cfg.create_parser(cfg.RewritableConfigParser, self)
|
||||||
config.readfp(stream)
|
config.readfp(stream)
|
||||||
config.set('DEFAULT', 'admin_token', params['service_token'])
|
config.set('DEFAULT', 'admin_token', params['service_token'])
|
||||||
config.set('DEFAULT', 'admin_port', params['endpoints']['admin']['port'])
|
config.set('DEFAULT', 'admin_port', params['endpoints']['admin']['port'])
|
||||||
|
@ -204,7 +204,7 @@ class NovaInstaller(comp.PythonInstallComponent):
|
|||||||
khelper.get_shared_passwords(self)))
|
khelper.get_shared_passwords(self)))
|
||||||
|
|
||||||
with io.BytesIO(contents) as stream:
|
with io.BytesIO(contents) as stream:
|
||||||
config = cfg.RewritableConfigParser()
|
config = cfg.create_parser(cfg.RewritableConfigParser, self)
|
||||||
config.readfp(stream)
|
config.readfp(stream)
|
||||||
|
|
||||||
config.set('filter:authtoken', 'auth_host', params['endpoints']['admin']['host'])
|
config.set('filter:authtoken', 'auth_host', params['endpoints']['admin']['host'])
|
||||||
@ -224,7 +224,7 @@ class NovaInstaller(comp.PythonInstallComponent):
|
|||||||
|
|
||||||
def _config_adjust_logging(self, contents, fn):
|
def _config_adjust_logging(self, contents, fn):
|
||||||
with io.BytesIO(contents) as stream:
|
with io.BytesIO(contents) as stream:
|
||||||
config = cfg.RewritableConfigParser()
|
config = cfg.create_parser(cfg.RewritableConfigParser, self)
|
||||||
config.readfp(stream)
|
config.readfp(stream)
|
||||||
config.set('logger_root', 'level', 'DEBUG')
|
config.set('logger_root', 'level', 'DEBUG')
|
||||||
config.set('logger_root', 'handlers', "stdout")
|
config.set('logger_root', 'handlers', "stdout")
|
||||||
|
@ -25,7 +25,7 @@ LOG = logging.getLogger(__name__)
|
|||||||
|
|
||||||
class PhaseRecorder(object):
|
class PhaseRecorder(object):
|
||||||
def __init__(self, fn):
|
def __init__(self, fn):
|
||||||
self.fn = fn
|
self.filename = fn
|
||||||
self.state = None
|
self.state = None
|
||||||
|
|
||||||
def _format_contents(self, contents):
|
def _format_contents(self, contents):
|
||||||
@ -36,12 +36,12 @@ class PhaseRecorder(object):
|
|||||||
contents = self.list_phases()
|
contents = self.list_phases()
|
||||||
contents[what] = utils.iso8601()
|
contents[what] = utils.iso8601()
|
||||||
yield what
|
yield what
|
||||||
sh.write_file(self.fn, self._format_contents(contents))
|
sh.write_file(self.filename, self._format_contents(contents))
|
||||||
|
|
||||||
def unmark(self, what):
|
def unmark(self, what):
|
||||||
contents = self.list_phases()
|
contents = self.list_phases()
|
||||||
contents.pop(what, None)
|
contents.pop(what, None)
|
||||||
sh.write_file(self.fn, self._format_contents(contents))
|
sh.write_file(self.filename, self._format_contents(contents))
|
||||||
|
|
||||||
def __contains__(self, what):
|
def __contains__(self, what):
|
||||||
phases = self.list_phases()
|
phases = self.list_phases()
|
||||||
@ -55,10 +55,10 @@ class PhaseRecorder(object):
|
|||||||
state = {}
|
state = {}
|
||||||
# Shell not used to avoid dry-run capturing
|
# Shell not used to avoid dry-run capturing
|
||||||
try:
|
try:
|
||||||
with open(self.fn, 'r') as fh:
|
with open(self.filename, 'r') as fh:
|
||||||
state = utils.load_yaml_text(fh.read())
|
state = utils.load_yaml_text(fh.read())
|
||||||
if not isinstance(state, (dict)):
|
if not isinstance(state, (dict)):
|
||||||
raise TypeError("Phase file %s expected dictionary root type" % (self.fn))
|
raise TypeError("Phase file %s expected dictionary root type" % (self.filename))
|
||||||
except IOError:
|
except IOError:
|
||||||
pass
|
pass
|
||||||
self.state = state
|
self.state = state
|
||||||
|
Loading…
Reference in New Issue
Block a user