Add reload_config_files function

Add reload_config_files function for ConfigOpts instance to
reload all configuration files.

Implements blueprint cfg-reload-config-files

Change-Id: Ia4d96be170d1ddfaa70b8e467b9a19ed45dc4060
This commit is contained in:
Fengqian.Gao
2013-06-08 10:56:11 +08:00
parent f0d4e34fde
commit c52d8c0a4e
2 changed files with 150 additions and 10 deletions

View File

@@ -266,6 +266,7 @@ import copy
import functools
import glob
import itertools
import logging
import os
import six
import string
@@ -274,6 +275,8 @@ import sys
from oslo.config import iniparser
from six import moves
LOG = logging.getLogger(__name__)
class Error(Exception):
"""Base class for cfg exceptions."""
@@ -1913,23 +1916,28 @@ class ConfigOpts(collections.Mapping):
"""Print the help message for the current program."""
self._oparser.print_help(file)
def _get(self, name, group=None):
def _get(self, name, group=None, namespace=None):
if isinstance(group, OptGroup):
key = (group.name, name)
else:
key = (group, name)
try:
if namespace is not None:
raise KeyError
return self.__cache[key]
except KeyError:
value = self._substitute(self._do_get(name, group))
value = self._substitute(self._do_get(name, group, namespace))
self.__cache[key] = value
return value
def _do_get(self, name, group=None):
def _do_get(self, name, group=None, namespace=None):
"""Look up an option value.
:param name: the opt name (or 'dest', more precisely)
:param group: an OptGroup
:param namespace: the namespace object that retrieves the option
value from
:returns: the option value, or a GroupAttr object
:raises: NoSuchOptError, NoSuchGroupError, ConfigFileValueError,
TemplateSubstitutionError
@@ -1946,10 +1954,12 @@ class ConfigOpts(collections.Mapping):
if 'override' in info:
return info['override']
if self._namespace is not None:
if namespace is None:
namespace = self._namespace
if namespace is not None:
group_name = group.name if group is not None else None
try:
return opt._get_from_namespace(self._namespace, group_name)
return opt._get_from_namespace(namespace, group_name)
except KeyError:
pass
except ValueError as ve:
@@ -2020,9 +2030,10 @@ class ConfigOpts(collections.Mapping):
return opts[opt_name]
def _check_required_opts(self):
def _check_required_opts(self, namespace=None):
"""Check that all opts marked as required have values specified.
:param namespace: the namespace object be checked the required options
:raises: RequiredOptError
"""
for info, group in self._all_opt_infos():
@@ -2032,7 +2043,7 @@ class ConfigOpts(collections.Mapping):
if 'default' in info or 'override' in info:
continue
if self._get(opt.dest, group) is None:
if self._get(opt.dest, group, namespace) is None:
raise RequiredOptError(opt.name, group)
def _parse_cli_opts(self, args):
@@ -2053,16 +2064,46 @@ class ConfigOpts(collections.Mapping):
key=lambda x: x[0].name):
opt._add_to_cli(self._oparser, group)
namespace = _Namespace(self)
return self._parse_config_files()
for arg in args:
def _parse_config_files(self):
"""Parse configure files options.
:raises: SystemExit, ConfigFilesNotFoundError, ConfigFileParseError,
RequiredOptError, DuplicateOptError
"""
namespace = _Namespace(self)
for arg in self._args:
if arg == '--config-file' or arg.startswith('--config-file='):
break
else:
for config_file in self.default_config_files:
ConfigParser._parse_file(config_file, namespace)
return self._oparser.parse_args(self._args, namespace)
return self._oparser.parse_args(args, namespace)
@__clear_cache
def reload_config_files(self):
"""Reload configure files and parse all options
:return False if reload configure files failed or else return True
"""
try:
namespace = self._parse_config_files()
if namespace.files_not_found:
raise ConfigFilesNotFoundError(namespace.files_not_found)
self._check_required_opts(namespace)
except SystemExit as exc:
LOG.warn("Caught SystemExit while reloading configure files \
with exit code: %d" % exc.code)
return False
except Error as err:
LOG.warn("Caught Error while reloading configure files: %s"
% err.__str__())
return False
else:
self._namespace = namespace
return True
class GroupAttr(collections.Mapping):

View File

@@ -15,6 +15,7 @@
# under the License.
import os
import shutil
import sys
import tempfile
@@ -1234,6 +1235,104 @@ class ConfigFileOptsTestCase(BaseTestCase):
self.assertEquals(self.conf.foo, 'bar-%08x')
class ConfigFileReloadTestCase(BaseTestCase):
def test_conf_files_reload(self):
self.conf.register_cli_opt(cfg.StrOpt('foo'))
paths = self.create_tempfiles([('1',
'[DEFAULT]\n'
'foo = baar\n'),
('2',
'[DEFAULT]\n'
'foo = baaar\n')])
self.conf(['--config-file', paths[0]])
self.assertTrue(hasattr(self.conf, 'foo'))
self.assertEquals(self.conf.foo, 'baar')
shutil.copy(paths[1], paths[0])
self.conf.reload_config_files()
self.assertTrue(hasattr(self.conf, 'foo'))
self.assertEquals(self.conf.foo, 'baaar')
def test_conf_files_reload_default(self):
self.conf.register_cli_opt(cfg.StrOpt('foo1'))
self.conf.register_cli_opt(cfg.StrOpt('foo2'))
paths = self.create_tempfiles([('1',
'[DEFAULT]\n'
'foo1 = default1\n'),
('2',
'[DEFAULT]\n'
'foo2 = default2\n')])
paths_change = self.create_tempfiles([('1',
'[DEFAULT]\n'
'foo1 = change_default1\n'),
('2',
'[DEFAULT]\n'
'foo2 = change_default2\n')])
self.conf(args=[], default_config_files=paths)
self.assertTrue(hasattr(self.conf, 'foo1'))
self.assertEquals(self.conf.foo1, 'default1')
self.assertTrue(hasattr(self.conf, 'foo2'))
self.assertEquals(self.conf.foo2, 'default2')
shutil.copy(paths_change[0], paths[0])
shutil.copy(paths_change[1], paths[1])
self.conf.reload_config_files()
self.assertTrue(hasattr(self.conf, 'foo1'))
self.assertEquals(self.conf.foo1, 'change_default1')
self.assertTrue(hasattr(self.conf, 'foo2'))
self.assertEquals(self.conf.foo2, 'change_default2')
def test_conf_files_reload_file_not_found(self):
self.conf.register_cli_opt(cfg.StrOpt('foo', required=True))
paths = self.create_tempfiles([('1',
'[DEFAULT]\n'
'foo = baar\n')])
self.conf(['--config-file', paths[0]])
self.assertTrue(hasattr(self.conf, 'foo'))
self.assertEquals(self.conf.foo, 'baar')
os.remove(paths[0])
self.conf.reload_config_files()
self.assertTrue(hasattr(self.conf, 'foo'))
self.assertEquals(self.conf.foo, 'baar')
def test_conf_files_reload_error(self):
self.conf.register_cli_opt(cfg.StrOpt('foo', required=True))
self.conf.register_cli_opt(cfg.StrOpt('foo1', required=True))
paths = self.create_tempfiles([('1',
'[DEFAULT]\n'
'foo = test1\n'
'foo1 = test11\n'),
('2',
'[DEFAULT]\n'
'foo2 = test2\n'
'foo3 = test22\n')])
self.conf(['--config-file', paths[0]])
self.assertTrue(hasattr(self.conf, 'foo'))
self.assertEquals(self.conf.foo, 'test1')
self.assertTrue(hasattr(self.conf, 'foo1'))
self.assertEquals(self.conf.foo1, 'test11')
shutil.copy(paths[1], paths[0])
self.conf.reload_config_files()
self.assertTrue(hasattr(self.conf, 'foo'))
self.assertEquals(self.conf.foo, 'test1')
self.assertTrue(hasattr(self.conf, 'foo1'))
self.assertEquals(self.conf.foo1, 'test11')
class OptGroupsTestCase(BaseTestCase):
def test_arg_group(self):