Update cfg from openstack-common

Use openstack-common's update.py script to pull in some recent changes:

 * Add the Mapping interface to cfg.ConfigOpts
 * Add support to cfg for disabling interspersed args

Make use of both of these in nova/flags.py.

Add some dire warnings to HACKING about directly modifying the copy of
openstack-common code. I'm confident they won't be ignored :-)

Change-Id: I7ef75d18922c0bbb8844453b48cad0418034bc11
This commit is contained in:
Mark McLoughlin 2012-02-03 00:50:58 +00:00
parent 16882ad36b
commit 259d3e356b
5 changed files with 132 additions and 25 deletions

View File

@ -179,3 +179,18 @@ without the patch and passes with the patch.
For more information on creating unit tests and utilizing the testing For more information on creating unit tests and utilizing the testing
infrastructure in OpenStack Nova, please read nova/testing/README.rst. infrastructure in OpenStack Nova, please read nova/testing/README.rst.
openstack-common
----------------
A number of modules from openstack-common are imported into the project.
These modules are "incubating" in openstack-common and are kept in sync
with the help of openstack-common's update.py script. See:
http://wiki.openstack.org/CommonLibrary#Incubation
The copy of the code should never be directly modified here. Please
always update openstack-common first and then run the script to copy
the changes across.

View File

@ -69,7 +69,7 @@ class FlagValues(object):
def __init__(self): def __init__(self):
self._conf = cfg.ConfigOpts() self._conf = cfg.ConfigOpts()
self._conf._oparser.disable_interspersed_args() self._conf.disable_interspersed_args()
self._opts = {} self._opts = {}
self.Reset() self.Reset()
@ -128,7 +128,7 @@ class FlagValues(object):
self._conf.set_default(name, default) self._conf.set_default(name, default)
def __iter__(self): def __iter__(self):
return self.FlagValuesDict().iterkeys() return self._conf.iterkeys()
def __getitem__(self, name): def __getitem__(self, name):
self._parse() self._parse()
@ -147,12 +147,12 @@ class FlagValues(object):
def FlagValuesDict(self): def FlagValuesDict(self):
self._parse() self._parse()
ret = {} ret = {}
for opt in self._opts.values(): for name in self._conf:
ret[opt.dest] = getattr(self, opt.dest) ret[name] = getattr(self, name)
return ret return ret
def add_option(self, opt): def add_option(self, opt):
if opt.dest in self._opts: if opt.dest in self._conf:
return return
self._opts[opt.dest] = opt self._opts[opt.dest] = opt

View File

@ -0,0 +1,13 @@
openstack-common
----------------
A number of modules from openstack-common are imported into this project.
These modules are "incubating" in openstack-common and are kept in sync
with the help of openstack-common's update.py script. See:
http://wiki.openstack.org/CommonLibrary#Incubation
The copy of the code should never be directly modified here. Please
always update openstack-common first and then run the script to copy
the changes across.

View File

@ -134,24 +134,18 @@ Options can be registered as belonging to a group:
rabbit_host_opt = \ rabbit_host_opt = \
cfg.StrOpt('host', cfg.StrOpt('host',
group='rabbit',
default='localhost', default='localhost',
help='IP/hostname to listen on'), help='IP/hostname to listen on'),
rabbit_port_opt = \ rabbit_port_opt = \
cfg.IntOpt('port', cfg.IntOpt('port',
default=5672, default=5672,
help='Port number to listen on') help='Port number to listen on')
rabbit_ssl_opt = \
conf.BoolOpt('use_ssl',
default=False,
help='Whether to support SSL connections')
def register_rabbit_opts(conf): def register_rabbit_opts(conf):
conf.register_group(rabbit_group) conf.register_group(rabbit_group)
# options can be registered under a group in any of these ways: # options can be registered under a group in either of these ways:
conf.register_opt(rabbit_host_opt) conf.register_opt(rabbit_host_opt, group=rabbit_group)
conf.register_opt(rabbit_port_opt, group='rabbit') conf.register_opt(rabbit_port_opt, group='rabbit')
conf.register_opt(rabbit_ssl_opt, group=rabbit_group)
If no group is specified, options belong to the 'DEFAULT' section of config If no group is specified, options belong to the 'DEFAULT' section of config
files: files:
@ -171,7 +165,7 @@ files:
Command-line options in a group are automatically prefixed with the group name: Command-line options in a group are automatically prefixed with the group name:
--rabbit-host localhost --rabbit-use-ssl False --rabbit-host localhost --rabbit-port 9999
Option values in the default group are referenced as attributes/properties on Option values in the default group are referenced as attributes/properties on
the config manager; groups are also attributes on the config manager, with the config manager; groups are also attributes on the config manager, with
@ -199,14 +193,31 @@ Option values may reference other values using PEP 292 string substitution:
] ]
Note that interpolation can be avoided by using '$$'. Note that interpolation can be avoided by using '$$'.
For command line utilities that dispatch to other command line utilities, the
disable_interspersed_args() method is available. If this this method is called,
then parsing e.g.
script --verbose cmd --debug /tmp/mything
will no longer return:
['cmd', '/tmp/mything']
as the leftover arguments, but will instead return:
['cmd', '--debug', '/tmp/mything']
i.e. argument parsing is stopped at the first non-option argument.
""" """
import sys import collections
import ConfigParser import ConfigParser
import copy import copy
import optparse import optparse
import os import os
import string import string
import sys
class Error(Exception): class Error(Exception):
@ -540,6 +551,7 @@ class BoolOpt(Opt):
container = self._get_optparse_container(parser, group) container = self._get_optparse_container(parser, group)
kwargs = self._get_optparse_kwargs(group, action='store_false') kwargs = self._get_optparse_kwargs(group, action='store_false')
prefix = self._get_optparse_prefix('no', group) prefix = self._get_optparse_prefix('no', group)
kwargs["help"] = "The inverse of --" + self.name
self._add_to_optparse(container, self.name, None, kwargs, prefix) self._add_to_optparse(container, self.name, None, kwargs, prefix)
def _get_optparse_kwargs(self, group, action='store_true', **kwargs): def _get_optparse_kwargs(self, group, action='store_true', **kwargs):
@ -681,7 +693,7 @@ class OptGroup(object):
return self._optparse_group return self._optparse_group
class ConfigOpts(object): class ConfigOpts(collections.Mapping, object):
""" """
Config options which may be set on the command line or in config files. Config options which may be set on the command line or in config files.
@ -776,6 +788,23 @@ class ConfigOpts(object):
""" """
return self._substitute(self._get(name)) return self._substitute(self._get(name))
def __getitem__(self, key):
"""Look up an option value and perform string substitution."""
return self.__getattr__(key)
def __contains__(self, key):
"""Return True if key is the name of a registered opt or group."""
return key in self._opts or key in self._groups
def __iter__(self):
"""Iterate over all registered opt and group names."""
for key in self._opts.keys() + self._groups.keys():
yield key
def __len__(self):
"""Return the number of options and option groups."""
return len(self._opts) + len(self._groups)
def reset(self): def reset(self):
"""Reset the state of the object to before it was called.""" """Reset the state of the object to before it was called."""
self._args = None self._args = None
@ -880,6 +909,31 @@ class ConfigOpts(object):
opt_info = self._get_opt_info(name, group) opt_info = self._get_opt_info(name, group)
opt_info['default'] = default opt_info['default'] = default
def disable_interspersed_args(self):
"""Set parsing to stop on the first non-option.
If this this method is called, then parsing e.g.
script --verbose cmd --debug /tmp/mything
will no longer return:
['cmd', '/tmp/mything']
as the leftover arguments, but will instead return:
['cmd', '--debug', '/tmp/mything']
i.e. argument parsing is stopped at the first non-option argument.
"""
self._oparser.disable_interspersed_args()
def enable_interspersed_args(self):
"""Set parsing to not stop on the first non-option.
This it the default behaviour."""
self._oparser.enable_interspersed_args()
def log_opt_values(self, logger, lvl): def log_opt_values(self, logger, lvl):
"""Log the value of all registered opts. """Log the value of all registered opts.
@ -900,7 +954,7 @@ class ConfigOpts(object):
logger.log(lvl, "%-30s = %s", opt_name, getattr(self, opt_name)) logger.log(lvl, "%-30s = %s", opt_name, getattr(self, opt_name))
for group_name in self._groups: for group_name in self._groups:
group_attr = self.GroupAttr(self, group_name) group_attr = self.GroupAttr(self, self._get_group(group_name))
for opt_name in sorted(self._groups[group_name]._opts): for opt_name in sorted(self._groups[group_name]._opts):
logger.log(lvl, "%-30s = %s", logger.log(lvl, "%-30s = %s",
"%s.%s" % (group_name, opt_name), "%s.%s" % (group_name, opt_name),
@ -916,16 +970,13 @@ class ConfigOpts(object):
"""Look up an option value. """Look up an option value.
:param name: the opt name (or 'dest', more precisely) :param name: the opt name (or 'dest', more precisely)
:param group: an option OptGroup :param group: an OptGroup
:returns: the option value, or a GroupAttr object :returns: the option value, or a GroupAttr object
:raises: NoSuchOptError, NoSuchGroupError, ConfigFileValueError, :raises: NoSuchOptError, NoSuchGroupError, ConfigFileValueError,
TemplateSubstitutionError TemplateSubstitutionError
""" """
if group is None and name in self._groups: if group is None and name in self._groups:
return self.GroupAttr(self, name) return self.GroupAttr(self, self._get_group(name))
if group is not None:
group = self._get_group(group)
info = self._get_opt_info(name, group) info = self._get_opt_info(name, group)
default, opt, override = map(lambda k: info[k], sorted(info.keys())) default, opt, override = map(lambda k: info[k], sorted(info.keys()))
@ -1027,17 +1078,18 @@ class ConfigOpts(object):
not_read_ok = filter(lambda f: f not in read_ok, config_files) not_read_ok = filter(lambda f: f not in read_ok, config_files)
raise ConfigFilesNotFoundError(not_read_ok) raise ConfigFilesNotFoundError(not_read_ok)
class GroupAttr(object): class GroupAttr(collections.Mapping, object):
""" """
A helper class representing the option values of a group as attributes. A helper class representing the option values of a group as a mapping
and attributes.
""" """
def __init__(self, conf, group): def __init__(self, conf, group):
"""Construct a GroupAttr object. """Construct a GroupAttr object.
:param conf: a ConfigOpts object :param conf: a ConfigOpts object
:param group: a group name or OptGroup object :param group: an OptGroup object
""" """
self.conf = conf self.conf = conf
self.group = group self.group = group
@ -1046,6 +1098,23 @@ class ConfigOpts(object):
"""Look up an option value and perform template substitution.""" """Look up an option value and perform template substitution."""
return self.conf._substitute(self.conf._get(name, self.group)) return self.conf._substitute(self.conf._get(name, self.group))
def __getitem__(self, key):
"""Look up an option value and perform string substitution."""
return self.__getattr__(key)
def __contains__(self, key):
"""Return True if key is the name of a registered opt or group."""
return key in self.group._opts
def __iter__(self):
"""Iterate over all registered opt and group names."""
for key in self.group._opts.keys():
yield key
def __len__(self):
"""Return the number of options and option groups."""
return len(self.group._opts)
class StrSubWrapper(object): class StrSubWrapper(object):
""" """
@ -1118,6 +1187,9 @@ class CommonConfigOpts(ConfigOpts):
BoolOpt('use-syslog', BoolOpt('use-syslog',
default=False, default=False,
help='Use syslog for logging.'), help='Use syslog for logging.'),
StrOpt('syslog-log-facility',
default='LOG_USER',
help='syslog facility to receive log lines')
] ]
def __init__(self, **kwargs): def __init__(self, **kwargs):

7
openstack-common.conf Normal file
View File

@ -0,0 +1,7 @@
[DEFAULT]
# The list of modules to copy from openstack-common
modules=cfg
# The base module to hold the copy of openstack.common
base=nova