Integrate openstack-common using update.py
* Update all cfg and setup imports to point to new location * Fixes bug 987968 Change-Id: If2fbf126e0b241e80ee59fa4e43bb5af6eb879a8
This commit is contained in:
parent
621c392240
commit
8b23d4faaf
15
HACKING.rst
15
HACKING.rst
@ -184,3 +184,18 @@ For every new feature, unit tests should be created that both test and
|
||||
bug that had no unit test, a new passing unit test should be added. If a
|
||||
submitted bug fix does have a unit test, be sure to add a new one that fails
|
||||
without the patch and passes with the patch.
|
||||
|
||||
|
||||
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.
|
||||
|
@ -43,8 +43,8 @@ if os.path.exists(os.path.join(possible_topdir, 'glance', '__init__.py')):
|
||||
|
||||
gettext.install('glance', unicode=1)
|
||||
|
||||
from glance.common import cfg
|
||||
from glance.common import config
|
||||
from glance.openstack.common import cfg
|
||||
|
||||
ALL_COMMANDS = ['start', 'stop', 'shutdown', 'restart',
|
||||
'reload', 'force-reload']
|
||||
|
@ -40,9 +40,9 @@ if os.path.exists(os.path.join(possible_topdir, 'glance', '__init__.py')):
|
||||
|
||||
gettext.install('glance', unicode=1)
|
||||
|
||||
from glance.common import cfg
|
||||
from glance.common import config
|
||||
from glance.common import exception
|
||||
from glance.openstack.common import cfg
|
||||
import glance.registry.db
|
||||
import glance.registry.db.migration
|
||||
|
||||
|
@ -34,8 +34,8 @@ if os.path.exists(os.path.join(possible_topdir, 'glance', '__init__.py')):
|
||||
|
||||
gettext.install('glance', unicode=1)
|
||||
|
||||
from glance.common import cfg
|
||||
from glance.common import config
|
||||
from glance.openstack.common import cfg
|
||||
from glance.store import scrubber
|
||||
|
||||
|
||||
|
@ -20,9 +20,9 @@
|
||||
import json
|
||||
import os.path
|
||||
|
||||
from glance.common import cfg
|
||||
from glance.common import exception
|
||||
from glance.common import policy
|
||||
from glance.openstack.common import cfg
|
||||
|
||||
|
||||
class Enforcer(object):
|
||||
@ -58,7 +58,7 @@ class Enforcer(object):
|
||||
if conf.policy_file:
|
||||
return conf.policy_file
|
||||
|
||||
matches = cfg.find_config_files('glance', 'policy', 'json')
|
||||
matches = cfg.find_config_files('glance', 'policy', '.json')
|
||||
|
||||
try:
|
||||
return matches[0]
|
||||
|
@ -37,10 +37,10 @@ from glance.api import policy
|
||||
import glance.api.v1
|
||||
from glance.api.v1 import controller
|
||||
from glance.api.v1 import filters
|
||||
from glance.common import cfg
|
||||
from glance.common import exception
|
||||
from glance.common import wsgi
|
||||
from glance.common import utils
|
||||
from glance.openstack.common import cfg
|
||||
import glance.store
|
||||
import glance.store.filesystem
|
||||
import glance.store.http
|
||||
|
@ -26,8 +26,8 @@ import logging.handlers
|
||||
import os
|
||||
import sys
|
||||
|
||||
from glance.common import cfg
|
||||
from glance.common import wsgi
|
||||
from glance.openstack.common import cfg
|
||||
from glance import version
|
||||
|
||||
|
||||
|
@ -15,10 +15,9 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from glance.common import cfg
|
||||
from glance.common import exception
|
||||
from glance.common import utils
|
||||
from glance.common import wsgi
|
||||
from glance.openstack.common import cfg
|
||||
from glance.registry.db import api as db_api
|
||||
|
||||
|
||||
|
@ -40,9 +40,9 @@ import routes.middleware
|
||||
import webob.dec
|
||||
import webob.exc
|
||||
|
||||
from glance.common import cfg
|
||||
from glance.common import exception
|
||||
from glance.common import utils
|
||||
from glance.openstack.common import cfg
|
||||
|
||||
|
||||
bind_opts = [
|
||||
|
@ -21,9 +21,9 @@ LRU Cache for Image Data
|
||||
|
||||
import logging
|
||||
|
||||
from glance.common import cfg
|
||||
from glance.common import exception
|
||||
from glance.common import utils
|
||||
from glance.openstack.common import cfg
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
DEFAULT_MAX_CACHE_SIZE = 10 * 1024 * 1024 * 1024 # 10 GB
|
||||
|
@ -29,9 +29,9 @@ import time
|
||||
from eventlet import sleep, timeout
|
||||
import sqlite3
|
||||
|
||||
from glance.common import cfg
|
||||
from glance.common import exception
|
||||
from glance.image_cache.drivers import base
|
||||
from glance.openstack.common import cfg
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
DEFAULT_SQL_CALL_TIMEOUT = 2
|
||||
|
@ -20,9 +20,9 @@ import datetime
|
||||
import socket
|
||||
import uuid
|
||||
|
||||
from glance.common import cfg
|
||||
from glance.common import exception
|
||||
from glance.common import utils
|
||||
from glance.openstack.common import cfg
|
||||
|
||||
|
||||
_STRATEGIES = {
|
||||
|
@ -21,8 +21,8 @@ import time
|
||||
import kombu.connection
|
||||
import kombu.entity
|
||||
|
||||
from glance.common import cfg
|
||||
from glance.notifier import strategy
|
||||
from glance.openstack.common import cfg
|
||||
|
||||
|
||||
logger = logging.getLogger('glance.notifier.notify_kombu')
|
||||
|
@ -19,8 +19,8 @@ import logging
|
||||
|
||||
import qpid.messaging
|
||||
|
||||
from glance.common import cfg
|
||||
from glance.notifier import strategy
|
||||
from glance.openstack.common import cfg
|
||||
|
||||
|
||||
logger = logging.getLogger('glance.notifier.notify_qpid')
|
||||
|
0
glance/openstack/__init__.py
Normal file
0
glance/openstack/__init__.py
Normal file
13
glance/openstack/common/README
Normal file
13
glance/openstack/common/README
Normal 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.
|
0
glance/openstack/common/__init__.py
Normal file
0
glance/openstack/common/__init__.py
Normal file
@ -17,7 +17,9 @@
|
||||
r"""
|
||||
Configuration options which may be set on the command line or in config files.
|
||||
|
||||
The schema for each option is defined using the Opt sub-classes e.g.
|
||||
The schema for each option is defined using the Opt sub-classes, e.g.:
|
||||
|
||||
::
|
||||
|
||||
common_opts = [
|
||||
cfg.StrOpt('bind_host',
|
||||
@ -28,22 +30,20 @@ The schema for each option is defined using the Opt sub-classes e.g.
|
||||
help='Port number to listen on')
|
||||
]
|
||||
|
||||
Options can be strings, integers, floats, booleans, lists or 'multi strings':
|
||||
Options can be strings, integers, floats, booleans, lists or 'multi strings'::
|
||||
|
||||
enabled_apis_opt = \
|
||||
cfg.ListOpt('enabled_apis',
|
||||
default=['ec2', 'osapi'],
|
||||
help='List of APIs to enable by default')
|
||||
enabled_apis_opt = cfg.ListOpt('enabled_apis',
|
||||
default=['ec2', 'osapi_compute'],
|
||||
help='List of APIs to enable by default')
|
||||
|
||||
DEFAULT_EXTENSIONS = [
|
||||
'nova.api.openstack.contrib.standard_extensions'
|
||||
'nova.api.openstack.compute.contrib.standard_extensions'
|
||||
]
|
||||
osapi_extension_opt = \
|
||||
cfg.MultiStrOpt('osapi_extension',
|
||||
default=DEFAULT_EXTENSIONS)
|
||||
osapi_compute_extension_opt = cfg.MultiStrOpt('osapi_compute_extension',
|
||||
default=DEFAULT_EXTENSIONS)
|
||||
|
||||
Option schemas are registered with with the config manager at runtime, but
|
||||
before the option is referenced:
|
||||
before the option is referenced::
|
||||
|
||||
class ExtensionManager(object):
|
||||
|
||||
@ -55,11 +55,11 @@ before the option is referenced:
|
||||
...
|
||||
|
||||
def _load_extensions(self):
|
||||
for ext_factory in self.conf.osapi_extension:
|
||||
for ext_factory in self.conf.osapi_compute_extension:
|
||||
....
|
||||
|
||||
A common usage pattern is for each option schema to be defined in the module or
|
||||
class which uses the option:
|
||||
class which uses the option::
|
||||
|
||||
opts = ...
|
||||
|
||||
@ -74,7 +74,7 @@ class which uses the option:
|
||||
|
||||
An option may optionally be made available via the command line. Such options
|
||||
must registered with the config manager before the command line is parsed (for
|
||||
the purposes of --help and CLI arg validation):
|
||||
the purposes of --help and CLI arg validation)::
|
||||
|
||||
cli_opts = [
|
||||
cfg.BoolOpt('verbose',
|
||||
@ -90,21 +90,20 @@ the purposes of --help and CLI arg validation):
|
||||
def add_common_opts(conf):
|
||||
conf.register_cli_opts(cli_opts)
|
||||
|
||||
The config manager has a single CLI option defined by default, --config-file:
|
||||
The config manager has a single CLI option defined by default, --config-file::
|
||||
|
||||
class ConfigOpts(object):
|
||||
|
||||
config_file_opt = \
|
||||
MultiStrOpt('config-file',
|
||||
...
|
||||
config_file_opt = MultiStrOpt('config-file',
|
||||
...
|
||||
|
||||
def __init__(self, ...):
|
||||
...
|
||||
self.register_cli_opt(self.config_file_opt)
|
||||
|
||||
Option values are parsed from any supplied config files using SafeConfigParser.
|
||||
If none are specified, a default set is used e.g. glance-api.conf and
|
||||
glance-common.conf:
|
||||
Option values are parsed from any supplied config files using
|
||||
openstack.common.iniparser. If none are specified, a default set is used
|
||||
e.g. glance-api.conf and glance-common.conf::
|
||||
|
||||
glance-api.conf:
|
||||
[DEFAULT]
|
||||
@ -119,7 +118,7 @@ are parsed in order, with values in later files overriding those in earlier
|
||||
files.
|
||||
|
||||
The parsing of CLI args and config files is initiated by invoking the config
|
||||
manager e.g.
|
||||
manager e.g.::
|
||||
|
||||
conf = ConfigOpts()
|
||||
conf.register_opt(BoolOpt('verbose', ...))
|
||||
@ -127,34 +126,26 @@ manager e.g.
|
||||
if conf.verbose:
|
||||
...
|
||||
|
||||
Options can be registered as belonging to a group:
|
||||
Options can be registered as belonging to a group::
|
||||
|
||||
rabbit_group = cfg.OptionGroup(name='rabbit',
|
||||
title='RabbitMQ options')
|
||||
rabbit_group = cfg.OptGroup(name='rabbit',
|
||||
title='RabbitMQ options')
|
||||
|
||||
rabbit_host_opt = \
|
||||
cfg.StrOpt('host',
|
||||
group='rabbit',
|
||||
default='localhost',
|
||||
help='IP/hostname to listen on'),
|
||||
rabbit_port_opt = \
|
||||
cfg.IntOpt('port',
|
||||
default=5672,
|
||||
help='Port number to listen on')
|
||||
rabbit_ssl_opt = \
|
||||
conf.BoolOpt('use_ssl',
|
||||
default=False,
|
||||
help='Whether to support SSL connections')
|
||||
rabbit_host_opt = cfg.StrOpt('host',
|
||||
default='localhost',
|
||||
help='IP/hostname to listen on'),
|
||||
rabbit_port_opt = cfg.IntOpt('port',
|
||||
default=5672,
|
||||
help='Port number to listen on')
|
||||
|
||||
def register_rabbit_opts(conf):
|
||||
conf.register_group(rabbit_group)
|
||||
# options can be registered under a group in any of these ways:
|
||||
conf.register_opt(rabbit_host_opt)
|
||||
# options can be registered under a group in either of these ways:
|
||||
conf.register_opt(rabbit_host_opt, group=rabbit_group)
|
||||
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
|
||||
files:
|
||||
files::
|
||||
|
||||
glance-api.conf:
|
||||
[DEFAULT]
|
||||
@ -169,13 +160,14 @@ files:
|
||||
password = guest
|
||||
virtual_host = /
|
||||
|
||||
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
|
||||
the config manager; groups are also attributes on the config manager, with
|
||||
attributes for each of the options associated with the group:
|
||||
attributes for each of the options associated with the group::
|
||||
|
||||
server.start(app, conf.bind_port, conf.bind_host, conf)
|
||||
|
||||
@ -184,7 +176,7 @@ attributes for each of the options associated with the group:
|
||||
port=conf.rabbit.port,
|
||||
...)
|
||||
|
||||
Option values may reference other values using PEP 292 string substitution:
|
||||
Option values may reference other values using PEP 292 string substitution::
|
||||
|
||||
opts = [
|
||||
cfg.StrOpt('state_path',
|
||||
@ -200,6 +192,22 @@ Option values may reference other values using PEP 292 string substitution:
|
||||
|
||||
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.
|
||||
|
||||
Options may be declared as secret so that their values are not leaked into
|
||||
log files:
|
||||
|
||||
@ -211,12 +219,15 @@ log files:
|
||||
|
||||
"""
|
||||
|
||||
import sys
|
||||
import ConfigParser
|
||||
import collections
|
||||
import copy
|
||||
import functools
|
||||
import optparse
|
||||
import os
|
||||
import string
|
||||
import sys
|
||||
|
||||
from glance.openstack.common import iniparser
|
||||
|
||||
|
||||
class Error(Exception):
|
||||
@ -239,7 +250,7 @@ class ArgsAlreadyParsedError(Error):
|
||||
return ret
|
||||
|
||||
|
||||
class NoSuchOptError(Error):
|
||||
class NoSuchOptError(Error, AttributeError):
|
||||
"""Raised if an opt which doesn't exist is referenced."""
|
||||
|
||||
def __init__(self, opt_name, group=None):
|
||||
@ -288,8 +299,8 @@ class ConfigFilesNotFoundError(Error):
|
||||
self.config_files = config_files
|
||||
|
||||
def __str__(self):
|
||||
return 'Failed to read some config files: %s' % \
|
||||
string.join(self.config_files, ',')
|
||||
return ('Failed to read some config files: %s' %
|
||||
string.join(self.config_files, ','))
|
||||
|
||||
|
||||
class ConfigFileParseError(Error):
|
||||
@ -308,12 +319,16 @@ class ConfigFileValueError(Error):
|
||||
pass
|
||||
|
||||
|
||||
def find_config_files(project=None, prog=None, filetype="conf"):
|
||||
def find_config_files(project=None, prog=None, extension='.conf'):
|
||||
"""Return a list of default configuration files.
|
||||
|
||||
:param project: an optional project name
|
||||
:param prog: the program name, defaulting to the basename of sys.argv[0]
|
||||
:param extension: the type of the config file
|
||||
|
||||
We default to two config files: [${project}.conf, ${prog}.conf]
|
||||
|
||||
And we look for those config files in the following directories:
|
||||
And we look for those config files in the following directories::
|
||||
|
||||
~/.${project}/
|
||||
~/
|
||||
@ -328,9 +343,6 @@ def find_config_files(project=None, prog=None, filetype="conf"):
|
||||
'~/.foo/bar.conf']
|
||||
|
||||
If no project name is supplied, we only look for ${prog.conf}.
|
||||
|
||||
:param project: an optional project name
|
||||
:param prog: the program name, defaulting to the basename of sys.argv[0]
|
||||
"""
|
||||
if prog is None:
|
||||
prog = os.path.basename(sys.argv[0])
|
||||
@ -342,23 +354,20 @@ def find_config_files(project=None, prog=None, filetype="conf"):
|
||||
fix_path('~'),
|
||||
os.path.join('/etc', project) if project else None,
|
||||
'/etc',
|
||||
'etc',
|
||||
'etc'
|
||||
]
|
||||
cfg_dirs = filter(bool, cfg_dirs)
|
||||
|
||||
def search_dirs(dirs, basename):
|
||||
def search_dirs(dirs, basename, extension):
|
||||
for d in dirs:
|
||||
path = os.path.join(d, basename)
|
||||
path = os.path.join(d, '%s%s' % (basename, extension))
|
||||
if os.path.exists(path):
|
||||
return path
|
||||
|
||||
config_files = []
|
||||
|
||||
if project:
|
||||
project_config = search_dirs(cfg_dirs, '%s.%s' % (project, filetype))
|
||||
config_files.append(project_config)
|
||||
|
||||
config_files.append(search_dirs(cfg_dirs, '%s.%s' % (prog, filetype)))
|
||||
config_files.append(search_dirs(cfg_dirs, project, extension))
|
||||
config_files.append(search_dirs(cfg_dirs, prog, extension))
|
||||
|
||||
return filter(bool, config_files)
|
||||
|
||||
@ -403,6 +412,7 @@ class Opt(object):
|
||||
help:
|
||||
an string explaining how the options value is used
|
||||
"""
|
||||
multi = False
|
||||
|
||||
def __init__(self, name, dest=None, short=None, default=None,
|
||||
metavar=None, help=None, secret=False):
|
||||
@ -431,7 +441,7 @@ class Opt(object):
|
||||
self.secret = secret
|
||||
|
||||
def _get_from_config_parser(self, cparser, section):
|
||||
"""Retrieves the option value from a ConfigParser object.
|
||||
"""Retrieves the option value from a MultiConfigParser object.
|
||||
|
||||
This is the method ConfigOpts uses to look up the option value from
|
||||
config files. Most opt types override this method in order to perform
|
||||
@ -542,9 +552,19 @@ class BoolOpt(Opt):
|
||||
1/0, yes/no, true/false or on/off.
|
||||
"""
|
||||
|
||||
_boolean_states = {'1': True, 'yes': True, 'true': True, 'on': True,
|
||||
'0': False, 'no': False, 'false': False, 'off': False}
|
||||
|
||||
def _get_from_config_parser(self, cparser, section):
|
||||
"""Retrieve the opt value as a boolean from ConfigParser."""
|
||||
return cparser.getboolean(section, self.dest)
|
||||
def convert_bool(v):
|
||||
value = self._boolean_states.get(v.lower())
|
||||
if value is None:
|
||||
raise ValueError('Unexpected boolean value %r' % v)
|
||||
|
||||
return value
|
||||
|
||||
return [convert_bool(v) for v in cparser.get(section, self.dest)]
|
||||
|
||||
def _add_to_cli(self, parser, group=None):
|
||||
"""Extends the base class method to add the --nooptname option."""
|
||||
@ -571,7 +591,7 @@ class IntOpt(Opt):
|
||||
|
||||
def _get_from_config_parser(self, cparser, section):
|
||||
"""Retrieve the opt value as a integer from ConfigParser."""
|
||||
return cparser.getint(section, self.dest)
|
||||
return [int(v) for v in cparser.get(section, self.dest)]
|
||||
|
||||
def _get_optparse_kwargs(self, group, **kwargs):
|
||||
"""Extends the base optparse keyword dict for integer options."""
|
||||
@ -585,7 +605,7 @@ class FloatOpt(Opt):
|
||||
|
||||
def _get_from_config_parser(self, cparser, section):
|
||||
"""Retrieve the opt value as a float from ConfigParser."""
|
||||
return cparser.getfloat(section, self.dest)
|
||||
return [float(v) for v in cparser.get(section, self.dest)]
|
||||
|
||||
def _get_optparse_kwargs(self, group, **kwargs):
|
||||
"""Extends the base optparse keyword dict for float options."""
|
||||
@ -602,7 +622,7 @@ class ListOpt(Opt):
|
||||
|
||||
def _get_from_config_parser(self, cparser, section):
|
||||
"""Retrieve the opt value as a list from ConfigParser."""
|
||||
return cparser.get(section, self.dest).split(',')
|
||||
return [v.split(',') for v in cparser.get(section, self.dest)]
|
||||
|
||||
def _get_optparse_kwargs(self, group, **kwargs):
|
||||
"""Extends the base optparse keyword dict for list options."""
|
||||
@ -624,14 +644,7 @@ class MultiStrOpt(Opt):
|
||||
Multistr opt values are string opts which may be specified multiple times.
|
||||
The opt value is a list containing all the string values specified.
|
||||
"""
|
||||
|
||||
def _get_from_config_parser(self, cparser, section):
|
||||
"""Retrieve the opt value as a multistr from ConfigParser."""
|
||||
# FIXME(markmc): values spread across the CLI and multiple
|
||||
# config files should be appended
|
||||
value = \
|
||||
super(MultiStrOpt, self)._get_from_config_parser(cparser, section)
|
||||
return value if value is None else [value]
|
||||
multi = True
|
||||
|
||||
def _get_optparse_kwargs(self, group, **kwargs):
|
||||
"""Extends the base optparse keyword dict for multi str options."""
|
||||
@ -673,7 +686,7 @@ class OptGroup(object):
|
||||
self.title = title
|
||||
self.help = help
|
||||
|
||||
self._opts = {} # dict of dicts of {opt:, override:, default:)
|
||||
self._opts = {} # dict of dicts of (opt:, override:, default:)
|
||||
self._optparse_group = None
|
||||
|
||||
def _register_opt(self, opt):
|
||||
@ -693,12 +706,75 @@ class OptGroup(object):
|
||||
def _get_optparse_group(self, parser):
|
||||
"""Build an optparse.OptionGroup for this group."""
|
||||
if self._optparse_group is None:
|
||||
self._optparse_group = \
|
||||
optparse.OptionGroup(parser, self.title, self.help)
|
||||
self._optparse_group = optparse.OptionGroup(parser, self.title,
|
||||
self.help)
|
||||
return self._optparse_group
|
||||
|
||||
|
||||
class ConfigOpts(object):
|
||||
class ParseError(iniparser.ParseError):
|
||||
def __init__(self, msg, lineno, line, filename):
|
||||
super(ParseError, self).__init__(msg, lineno, line)
|
||||
self.filename = filename
|
||||
|
||||
def __str__(self):
|
||||
return 'at %s:%d, %s: %r' % (self.filename, self.lineno,
|
||||
self.msg, self.line)
|
||||
|
||||
|
||||
class ConfigParser(iniparser.BaseParser):
|
||||
def __init__(self, filename, sections):
|
||||
super(ConfigParser, self).__init__()
|
||||
self.filename = filename
|
||||
self.sections = sections
|
||||
self.section = None
|
||||
|
||||
def parse(self):
|
||||
with open(self.filename) as f:
|
||||
return super(ConfigParser, self).parse(f)
|
||||
|
||||
def new_section(self, section):
|
||||
self.section = section
|
||||
self.sections.setdefault(self.section, {})
|
||||
|
||||
def assignment(self, key, value):
|
||||
if not self.section:
|
||||
raise self.error_no_section()
|
||||
|
||||
self.sections[self.section].setdefault(key, [])
|
||||
self.sections[self.section][key].append('\n'.join(value))
|
||||
|
||||
def parse_exc(self, msg, lineno, line=None):
|
||||
return ParseError(msg, lineno, line, self.filename)
|
||||
|
||||
def error_no_section(self):
|
||||
return self.parse_exc('Section must be started before assignment',
|
||||
self.lineno)
|
||||
|
||||
|
||||
class MultiConfigParser(object):
|
||||
def __init__(self):
|
||||
self.sections = {}
|
||||
|
||||
def read(self, config_files):
|
||||
read_ok = []
|
||||
|
||||
for filename in config_files:
|
||||
parser = ConfigParser(filename, self.sections)
|
||||
|
||||
try:
|
||||
parser.parse()
|
||||
except IOError:
|
||||
continue
|
||||
|
||||
read_ok.append(filename)
|
||||
|
||||
return read_ok
|
||||
|
||||
def get(self, section, name):
|
||||
return self.sections[section][name]
|
||||
|
||||
|
||||
class ConfigOpts(collections.Mapping):
|
||||
|
||||
"""
|
||||
Config options which may be set on the command line or in config files.
|
||||
@ -748,7 +824,9 @@ class ConfigOpts(object):
|
||||
usage=self.usage)
|
||||
self._cparser = None
|
||||
|
||||
self.register_cli_opt(\
|
||||
self.__cache = {}
|
||||
|
||||
self.register_cli_opt(
|
||||
MultiStrOpt('config-file',
|
||||
default=self.default_config_files,
|
||||
metavar='PATH',
|
||||
@ -757,6 +835,15 @@ class ConfigOpts(object):
|
||||
'files taking precedence. The default files used '
|
||||
'are: %s' % (self.default_config_files, )))
|
||||
|
||||
def __clear_cache(f):
|
||||
@functools.wraps(f)
|
||||
def __inner(self, *args, **kwargs):
|
||||
if kwargs.pop('clear_cache', True):
|
||||
self.__cache.clear()
|
||||
return f(self, *args, **kwargs)
|
||||
|
||||
return __inner
|
||||
|
||||
def __call__(self, args=None):
|
||||
"""Parse command line arguments and config files.
|
||||
|
||||
@ -791,14 +878,33 @@ class ConfigOpts(object):
|
||||
:returns: the option value (after string subsititution) or a GroupAttr
|
||||
:raises: NoSuchOptError,ConfigFileValueError,TemplateSubstitutionError
|
||||
"""
|
||||
return self._substitute(self._get(name))
|
||||
return 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)
|
||||
|
||||
@__clear_cache
|
||||
def reset(self):
|
||||
"""Reset the state of the object to before it was called."""
|
||||
self._args = None
|
||||
self._cli_values = None
|
||||
self._cparser = None
|
||||
|
||||
@__clear_cache
|
||||
def register_opt(self, opt, group=None):
|
||||
"""Register an option schema.
|
||||
|
||||
@ -821,11 +927,13 @@ class ConfigOpts(object):
|
||||
|
||||
return True
|
||||
|
||||
@__clear_cache
|
||||
def register_opts(self, opts, group=None):
|
||||
"""Register multiple option schemas at once."""
|
||||
for opt in opts:
|
||||
self.register_opt(opt, group)
|
||||
self.register_opt(opt, group, clear_cache=False)
|
||||
|
||||
@__clear_cache
|
||||
def register_cli_opt(self, opt, group=None):
|
||||
"""Register a CLI option schema.
|
||||
|
||||
@ -838,10 +946,10 @@ class ConfigOpts(object):
|
||||
:return: False if the opt was already register, True otherwise
|
||||
:raises: DuplicateOptError, ArgsAlreadyParsedError
|
||||
"""
|
||||
if self._args != None:
|
||||
if self._args is not None:
|
||||
raise ArgsAlreadyParsedError("cannot register CLI option")
|
||||
|
||||
if not self.register_opt(opt, group):
|
||||
if not self.register_opt(opt, group, clear_cache=False):
|
||||
return False
|
||||
|
||||
if group is not None:
|
||||
@ -851,10 +959,11 @@ class ConfigOpts(object):
|
||||
|
||||
return True
|
||||
|
||||
@__clear_cache
|
||||
def register_cli_opts(self, opts, group=None):
|
||||
"""Register multiple CLI option schemas at once."""
|
||||
for opt in opts:
|
||||
self.register_cli_opt(opt, group)
|
||||
self.register_cli_opt(opt, group, clear_cache=False)
|
||||
|
||||
def register_group(self, group):
|
||||
"""Register an option group.
|
||||
@ -869,6 +978,7 @@ class ConfigOpts(object):
|
||||
|
||||
self._groups[group.name] = copy.copy(group)
|
||||
|
||||
@__clear_cache
|
||||
def set_override(self, name, override, group=None):
|
||||
"""Override an opt value.
|
||||
|
||||
@ -883,6 +993,7 @@ class ConfigOpts(object):
|
||||
opt_info = self._get_opt_info(name, group)
|
||||
opt_info['override'] = override
|
||||
|
||||
@__clear_cache
|
||||
def set_default(self, name, default, group=None):
|
||||
"""Override an opt's default value.
|
||||
|
||||
@ -897,6 +1008,31 @@ class ConfigOpts(object):
|
||||
opt_info = self._get_opt_info(name, group)
|
||||
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):
|
||||
"""Log the value of all registered opts.
|
||||
|
||||
@ -923,7 +1059,7 @@ class ConfigOpts(object):
|
||||
_sanitize(opt, getattr(self, opt_name)))
|
||||
|
||||
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):
|
||||
opt = self._get_opt_info(opt_name, group_name)['opt']
|
||||
logger.log(lvl, "%-30s = %s",
|
||||
@ -936,20 +1072,33 @@ class ConfigOpts(object):
|
||||
"""Print the usage message for the current program."""
|
||||
self._oparser.print_usage(file)
|
||||
|
||||
def print_help(self, file=None):
|
||||
"""Print the help message for the current program."""
|
||||
self._oparser.print_help(file)
|
||||
|
||||
def _get(self, name, group=None):
|
||||
if isinstance(group, OptGroup):
|
||||
key = (group.name, name)
|
||||
else:
|
||||
key = (group, name)
|
||||
try:
|
||||
return self.__cache[key]
|
||||
except KeyError:
|
||||
value = self._substitute(self._do_get(name, group))
|
||||
self.__cache[key] = value
|
||||
return value
|
||||
|
||||
def _do_get(self, name, group=None):
|
||||
"""Look up an option value.
|
||||
|
||||
: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
|
||||
:raises: NoSuchOptError, NoSuchGroupError, ConfigFileValueError,
|
||||
TemplateSubstitutionError
|
||||
"""
|
||||
if group is None and name in self._groups:
|
||||
return self.GroupAttr(self, name)
|
||||
|
||||
if group is not None:
|
||||
group = self._get_group(group)
|
||||
return self.GroupAttr(self, self._get_group(name))
|
||||
|
||||
info = self._get_opt_info(name, group)
|
||||
default, opt, override = map(lambda k: info[k], sorted(info.keys()))
|
||||
@ -957,20 +1106,31 @@ class ConfigOpts(object):
|
||||
if override is not None:
|
||||
return override
|
||||
|
||||
values = []
|
||||
if self._cparser is not None:
|
||||
section = group.name if group is not None else 'DEFAULT'
|
||||
try:
|
||||
return opt._get_from_config_parser(self._cparser, section)
|
||||
except (ConfigParser.NoOptionError,
|
||||
ConfigParser.NoSectionError):
|
||||
value = opt._get_from_config_parser(self._cparser, section)
|
||||
except KeyError:
|
||||
pass
|
||||
except ValueError, ve:
|
||||
except ValueError as ve:
|
||||
raise ConfigFileValueError(str(ve))
|
||||
else:
|
||||
if not opt.multi:
|
||||
# No need to continue since the last value wins
|
||||
return value[-1]
|
||||
values.extend(value)
|
||||
|
||||
name = name if group is None else group.name + '_' + name
|
||||
value = self._cli_values.get(name, None)
|
||||
value = self._cli_values.get(name)
|
||||
if value is not None:
|
||||
return value
|
||||
if not opt.multi:
|
||||
return value
|
||||
|
||||
return value + values
|
||||
|
||||
if values:
|
||||
return values
|
||||
|
||||
if default is not None:
|
||||
return default
|
||||
@ -1040,35 +1200,53 @@ class ConfigOpts(object):
|
||||
|
||||
:raises: ConfigFilesNotFoundError, ConfigFileParseError
|
||||
"""
|
||||
self._cparser = ConfigParser.SafeConfigParser()
|
||||
self._cparser = MultiConfigParser()
|
||||
|
||||
try:
|
||||
read_ok = self._cparser.read(config_files)
|
||||
except ConfigParser.ParsingError, cpe:
|
||||
raise ConfigFileParseError(cpe.filename, cpe.message)
|
||||
except iniparser.ParseError as pe:
|
||||
raise ConfigFileParseError(pe.filename, str(pe))
|
||||
|
||||
if read_ok != config_files:
|
||||
not_read_ok = filter(lambda f: f not in read_ok, config_files)
|
||||
raise ConfigFilesNotFoundError(not_read_ok)
|
||||
|
||||
class GroupAttr(object):
|
||||
class GroupAttr(collections.Mapping):
|
||||
|
||||
"""
|
||||
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):
|
||||
"""Construct a GroupAttr object.
|
||||
|
||||
:param conf: a ConfigOpts object
|
||||
:param group: a group name or OptGroup object
|
||||
:param group: an OptGroup object
|
||||
"""
|
||||
self.conf = conf
|
||||
self.group = group
|
||||
|
||||
def __getattr__(self, name):
|
||||
"""Look up an option value and perform template substitution."""
|
||||
return self.conf._substitute(self.conf._get(name, self.group))
|
||||
return 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):
|
||||
|
||||
@ -1099,8 +1277,7 @@ class ConfigOpts(object):
|
||||
|
||||
class CommonConfigOpts(ConfigOpts):
|
||||
|
||||
DEFAULT_LOG_FORMAT = ('%(asctime)s %(process)d %(levelname)8s '
|
||||
'[%(name)s] %(message)s')
|
||||
DEFAULT_LOG_FORMAT = "%(asctime)s %(levelname)8s [%(name)s] %(message)s"
|
||||
DEFAULT_LOG_DATE_FORMAT = "%Y-%m-%d %H:%M:%S"
|
||||
|
||||
common_cli_opts = [
|
126
glance/openstack/common/iniparser.py
Normal file
126
glance/openstack/common/iniparser.py
Normal file
@ -0,0 +1,126 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2012 OpenStack LLC.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
|
||||
class ParseError(Exception):
|
||||
def __init__(self, message, lineno, line):
|
||||
self.msg = message
|
||||
self.line = line
|
||||
self.lineno = lineno
|
||||
|
||||
def __str__(self):
|
||||
return 'at line %d, %s: %r' % (self.lineno, self.msg, self.line)
|
||||
|
||||
|
||||
class BaseParser(object):
|
||||
lineno = 0
|
||||
parse_exc = ParseError
|
||||
|
||||
def _assignment(self, key, value):
|
||||
self.assignment(key, value)
|
||||
return None, []
|
||||
|
||||
def _get_section(self, line):
|
||||
if line[-1] != ']':
|
||||
return self.error_no_section_end_bracket(line)
|
||||
if len(line) <= 2:
|
||||
return self.error_no_section_name(line)
|
||||
|
||||
return line[1:-1]
|
||||
|
||||
def _split_key_value(self, line):
|
||||
colon = line.find(':')
|
||||
equal = line.find('=')
|
||||
if colon < 0 and equal < 0:
|
||||
return self.error_invalid_assignment(line)
|
||||
|
||||
if colon < 0 or (equal >= 0 and equal < colon):
|
||||
key, value = line[:equal], line[equal + 1:]
|
||||
else:
|
||||
key, value = line[:colon], line[colon + 1:]
|
||||
|
||||
return key.strip(), [value.strip()]
|
||||
|
||||
def parse(self, lineiter):
|
||||
key = None
|
||||
value = []
|
||||
|
||||
for line in lineiter:
|
||||
self.lineno += 1
|
||||
|
||||
line = line.rstrip()
|
||||
if not line:
|
||||
# Blank line, ends multi-line values
|
||||
if key:
|
||||
key, value = self._assignment(key, value)
|
||||
continue
|
||||
elif line[0] in (' ', '\t'):
|
||||
# Continuation of previous assignment
|
||||
if key is None:
|
||||
self.error_unexpected_continuation(line)
|
||||
else:
|
||||
value.append(line.lstrip())
|
||||
continue
|
||||
|
||||
if key:
|
||||
# Flush previous assignment, if any
|
||||
key, value = self._assignment(key, value)
|
||||
|
||||
if line[0] == '[':
|
||||
# Section start
|
||||
section = self._get_section(line)
|
||||
if section:
|
||||
self.new_section(section)
|
||||
elif line[0] in '#;':
|
||||
self.comment(line[1:].lstrip())
|
||||
else:
|
||||
key, value = self._split_key_value(line)
|
||||
if not key:
|
||||
return self.error_empty_key(line)
|
||||
|
||||
if key:
|
||||
# Flush previous assignment, if any
|
||||
self._assignment(key, value)
|
||||
|
||||
def assignment(self, key, value):
|
||||
"""Called when a full assignment is parsed"""
|
||||
raise NotImplementedError()
|
||||
|
||||
def new_section(self, section):
|
||||
"""Called when a new section is started"""
|
||||
raise NotImplementedError()
|
||||
|
||||
def comment(self, comment):
|
||||
"""Called when a comment is parsed"""
|
||||
pass
|
||||
|
||||
def error_invalid_assignment(self, line):
|
||||
raise self.parse_exc("No ':' or '=' found in assignment",
|
||||
self.lineno, line)
|
||||
|
||||
def error_empty_key(self, line):
|
||||
raise self.parse_exc('Key cannot be empty', self.lineno, line)
|
||||
|
||||
def error_unexpected_continuation(self, line):
|
||||
raise self.parse_exc('Unexpected continuation line',
|
||||
self.lineno, line)
|
||||
|
||||
def error_no_section_end_bracket(self, line):
|
||||
raise self.parse_exc('Invalid section (must end with ])',
|
||||
self.lineno, line)
|
||||
|
||||
def error_no_section_name(self, line):
|
||||
raise self.parse_exc('Empty section name', self.lineno, line)
|
@ -37,8 +37,8 @@ def parse_mailmap(mailmap='.mailmap'):
|
||||
|
||||
|
||||
def canonicalize_emails(changelog, mapping):
|
||||
""" Takes in a string and an email alias mapping and replaces all
|
||||
instances of the aliases in the string with their real email
|
||||
"""Takes in a string and an email alias mapping and replaces all
|
||||
instances of the aliases in the string with their real email.
|
||||
"""
|
||||
for alias, email in mapping.iteritems():
|
||||
changelog = changelog.replace(alias, email)
|
||||
@ -97,7 +97,7 @@ def _run_shell_command(cmd):
|
||||
|
||||
|
||||
def write_vcsversion(location):
|
||||
""" Produce a vcsversion dict that mimics the old one produced by bzr
|
||||
"""Produce a vcsversion dict that mimics the old one produced by bzr.
|
||||
"""
|
||||
if os.path.isdir('.git'):
|
||||
branch_nick_cmd = 'git branch | grep -Ei "\* (.*)" | cut -f2 -d" "'
|
||||
@ -118,10 +118,28 @@ version_info = {
|
||||
|
||||
|
||||
def write_git_changelog():
|
||||
""" Write a changelog based on the git changelog """
|
||||
"""Write a changelog based on the git changelog."""
|
||||
if os.path.isdir('.git'):
|
||||
git_log_cmd = 'git log --stat'
|
||||
changelog = _run_shell_command(git_log_cmd)
|
||||
mailmap = parse_mailmap()
|
||||
with open("ChangeLog", "w") as changelog_file:
|
||||
changelog_file.write(canonicalize_emails(changelog, mailmap))
|
||||
|
||||
|
||||
def generate_authors():
|
||||
"""Create AUTHORS file using git commits."""
|
||||
jenkins_email = 'jenkins@review.openstack.org'
|
||||
old_authors = 'AUTHORS.in'
|
||||
new_authors = 'AUTHORS'
|
||||
if os.path.isdir('.git'):
|
||||
# don't include jenkins email address in AUTHORS file
|
||||
git_log_cmd = "git log --format='%aN <%aE>' | sort -u | " \
|
||||
"grep -v " + jenkins_email
|
||||
changelog = _run_shell_command(git_log_cmd)
|
||||
mailmap = parse_mailmap()
|
||||
with open(new_authors, 'w') as new_authors_fh:
|
||||
new_authors_fh.write(canonicalize_emails(changelog, mailmap))
|
||||
if os.path.exists(old_authors):
|
||||
with open(old_authors, "r") as old_authors_fh:
|
||||
new_authors_fh.write('\n' + old_authors_fh.read())
|
@ -22,8 +22,8 @@ Registry API
|
||||
import logging
|
||||
import os
|
||||
|
||||
from glance.common import cfg
|
||||
from glance.common import exception
|
||||
from glance.openstack.common import cfg
|
||||
from glance.registry import client
|
||||
|
||||
logger = logging.getLogger('glance.registry')
|
||||
|
@ -23,10 +23,10 @@ import logging
|
||||
|
||||
from webob import exc
|
||||
|
||||
from glance.common import cfg
|
||||
from glance.common import exception
|
||||
from glance.common import utils
|
||||
from glance.common import wsgi
|
||||
from glance.openstack.common import cfg
|
||||
from glance.registry.db import api as db_api
|
||||
|
||||
|
||||
|
@ -17,7 +17,7 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from glance.common import cfg
|
||||
from glance.openstack.common import cfg
|
||||
|
||||
|
||||
def add_options(conf):
|
||||
|
@ -34,9 +34,9 @@ from sqlalchemy.orm import joinedload
|
||||
from sqlalchemy.orm import sessionmaker
|
||||
from sqlalchemy.sql import or_, and_
|
||||
|
||||
from glance.common import cfg
|
||||
from glance.common import exception
|
||||
from glance.common import utils
|
||||
from glance.openstack.common import cfg
|
||||
from glance.registry.db import migration
|
||||
from glance.registry.db import models
|
||||
|
||||
|
@ -20,9 +20,9 @@ import os
|
||||
import sys
|
||||
import time
|
||||
|
||||
from glance.common import cfg
|
||||
from glance.common import exception
|
||||
from glance.common import utils
|
||||
from glance.openstack.common import cfg
|
||||
from glance import registry
|
||||
from glance.store import location
|
||||
|
||||
|
@ -25,9 +25,9 @@ import logging
|
||||
import os
|
||||
import urlparse
|
||||
|
||||
from glance.common import cfg
|
||||
from glance.common import exception
|
||||
from glance.common import utils
|
||||
from glance.openstack.common import cfg
|
||||
import glance.store
|
||||
import glance.store.base
|
||||
import glance.store.location
|
||||
|
@ -24,8 +24,8 @@ import hashlib
|
||||
import logging
|
||||
import math
|
||||
|
||||
from glance.common import cfg
|
||||
from glance.common import exception
|
||||
from glance.openstack.common import cfg
|
||||
import glance.store
|
||||
import glance.store.base
|
||||
import glance.store.location
|
||||
|
@ -24,9 +24,9 @@ import re
|
||||
import tempfile
|
||||
import urlparse
|
||||
|
||||
from glance.common import cfg
|
||||
from glance.common import exception
|
||||
from glance.common import utils
|
||||
from glance.openstack.common import cfg
|
||||
import glance.store
|
||||
import glance.store.base
|
||||
import glance.store.location
|
||||
|
@ -27,8 +27,8 @@ import glance.store.s3
|
||||
import glance.store.swift
|
||||
from glance import registry
|
||||
from glance import store
|
||||
from glance.common import cfg
|
||||
from glance.common import utils
|
||||
from glance.openstack.common import cfg
|
||||
from glance.registry import client
|
||||
|
||||
|
||||
|
@ -25,8 +25,8 @@ import logging
|
||||
import math
|
||||
import urlparse
|
||||
|
||||
from glance.common import cfg
|
||||
from glance.common import exception
|
||||
from glance.openstack.common import cfg
|
||||
import glance.store
|
||||
import glance.store.base
|
||||
import glance.store.location
|
||||
|
@ -1,790 +0,0 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2011 Red Hat, Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import os
|
||||
import sys
|
||||
import StringIO
|
||||
import tempfile
|
||||
import unittest
|
||||
|
||||
import stubout
|
||||
|
||||
from glance.common.cfg import *
|
||||
|
||||
|
||||
class BaseTestCase(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.conf = ConfigOpts(prog='test',
|
||||
version='1.0',
|
||||
usage='%prog FOO BAR',
|
||||
default_config_files=[])
|
||||
self.tempfiles = []
|
||||
self.stubs = stubout.StubOutForTesting()
|
||||
|
||||
def tearDown(self):
|
||||
self.remove_tempfiles()
|
||||
self.stubs.UnsetAll()
|
||||
|
||||
def create_tempfiles(self, files):
|
||||
for (basename, contents) in files:
|
||||
(fd, path) = tempfile.mkstemp(prefix=basename)
|
||||
self.tempfiles.append(path)
|
||||
try:
|
||||
os.write(fd, contents)
|
||||
finally:
|
||||
os.close(fd)
|
||||
return self.tempfiles[-len(files):]
|
||||
|
||||
def remove_tempfiles(self):
|
||||
for p in self.tempfiles:
|
||||
os.remove(p)
|
||||
|
||||
|
||||
class LeftoversTestCase(BaseTestCase):
|
||||
|
||||
def test_leftovers(self):
|
||||
self.conf.register_cli_opt(StrOpt('foo'))
|
||||
self.conf.register_cli_opt(StrOpt('bar'))
|
||||
|
||||
leftovers = self.conf(['those', '--foo', 'this',
|
||||
'thems', '--bar', 'that', 'these'])
|
||||
|
||||
self.assertEquals(leftovers, ['those', 'thems', 'these'])
|
||||
|
||||
|
||||
class FindConfigFilesTestCase(BaseTestCase):
|
||||
|
||||
def test_find_config_files(self):
|
||||
config_files = \
|
||||
[os.path.expanduser('~/.blaa/blaa.conf'), '/etc/foo.conf']
|
||||
|
||||
self.stubs.Set(os.path, 'exists', lambda p: p in config_files)
|
||||
|
||||
self.assertEquals(find_config_files(project='blaa', prog='foo'),
|
||||
config_files)
|
||||
|
||||
|
||||
class CliOptsTestCase(BaseTestCase):
|
||||
|
||||
def _do_cli_test(self, opt_class, default, cli_args, value):
|
||||
self.conf.register_cli_opt(opt_class('foo', default=default))
|
||||
|
||||
self.conf(cli_args)
|
||||
|
||||
self.assertTrue(hasattr(self.conf, 'foo'))
|
||||
self.assertEquals(self.conf.foo, value)
|
||||
|
||||
def test_str_default(self):
|
||||
self._do_cli_test(StrOpt, None, [], None)
|
||||
|
||||
def test_str_arg(self):
|
||||
self._do_cli_test(StrOpt, None, ['--foo', 'bar'], 'bar')
|
||||
|
||||
def test_bool_default(self):
|
||||
self._do_cli_test(BoolOpt, False, [], False)
|
||||
|
||||
def test_bool_arg(self):
|
||||
self._do_cli_test(BoolOpt, None, ['--foo'], True)
|
||||
|
||||
def test_bool_arg_inverse(self):
|
||||
self._do_cli_test(BoolOpt, None, ['--foo', '--nofoo'], False)
|
||||
|
||||
def test_int_default(self):
|
||||
self._do_cli_test(IntOpt, 10, [], 10)
|
||||
|
||||
def test_int_arg(self):
|
||||
self._do_cli_test(IntOpt, None, ['--foo=20'], 20)
|
||||
|
||||
def test_float_default(self):
|
||||
self._do_cli_test(FloatOpt, 1.0, [], 1.0)
|
||||
|
||||
def test_float_arg(self):
|
||||
self._do_cli_test(FloatOpt, None, ['--foo', '2.0'], 2.0)
|
||||
|
||||
def test_list_default(self):
|
||||
self._do_cli_test(ListOpt, ['bar'], [], ['bar'])
|
||||
|
||||
def test_list_arg(self):
|
||||
self._do_cli_test(ListOpt, None,
|
||||
['--foo', 'blaa,bar'], ['blaa', 'bar'])
|
||||
|
||||
def test_multistr_default(self):
|
||||
self._do_cli_test(MultiStrOpt, ['bar'], [], ['bar'])
|
||||
|
||||
def test_multistr_arg(self):
|
||||
self._do_cli_test(MultiStrOpt, None,
|
||||
['--foo', 'blaa', '--foo', 'bar'], ['blaa', 'bar'])
|
||||
|
||||
def test_help(self):
|
||||
self.stubs.Set(sys, 'stdout', StringIO.StringIO())
|
||||
self.assertRaises(SystemExit, self.conf, ['--help'])
|
||||
self.assertTrue('FOO BAR' in sys.stdout.getvalue())
|
||||
self.assertTrue('--version' in sys.stdout.getvalue())
|
||||
self.assertTrue('--help' in sys.stdout.getvalue())
|
||||
self.assertTrue('--config-file=PATH' in sys.stdout.getvalue())
|
||||
|
||||
def test_version(self):
|
||||
self.stubs.Set(sys, 'stdout', StringIO.StringIO())
|
||||
self.assertRaises(SystemExit, self.conf, ['--version'])
|
||||
self.assertTrue('1.0' in sys.stdout.getvalue())
|
||||
|
||||
def test_config_file(self):
|
||||
paths = self.create_tempfiles([('1.conf', '[DEFAULT]'),
|
||||
('2.conf', '[DEFAULT]')])
|
||||
|
||||
self.conf(['--config-file', paths[0], '--config-file', paths[1]])
|
||||
|
||||
self.assertEquals(self.conf.config_file, paths)
|
||||
|
||||
|
||||
class ConfigFileOptsTestCase(BaseTestCase):
|
||||
|
||||
def test_str_default(self):
|
||||
self.conf.register_opt(StrOpt('foo', default='bar'))
|
||||
|
||||
paths = self.create_tempfiles([('test.conf',
|
||||
'[DEFAULT]\n')])
|
||||
|
||||
self.conf(['--config-file', paths[0]])
|
||||
|
||||
self.assertTrue(hasattr(self.conf, 'foo'))
|
||||
self.assertEquals(self.conf.foo, 'bar')
|
||||
|
||||
def test_str_value(self):
|
||||
self.conf.register_opt(StrOpt('foo'))
|
||||
|
||||
paths = self.create_tempfiles([('test.conf',
|
||||
'[DEFAULT]\n'
|
||||
'foo = bar\n')])
|
||||
|
||||
self.conf(['--config-file', paths[0]])
|
||||
|
||||
self.assertTrue(hasattr(self.conf, 'foo'))
|
||||
self.assertEquals(self.conf.foo, 'bar')
|
||||
|
||||
def test_str_value_override(self):
|
||||
self.conf.register_cli_opt(StrOpt('foo'))
|
||||
|
||||
paths = self.create_tempfiles([('1.conf',
|
||||
'[DEFAULT]\n'
|
||||
'foo = baar\n'),
|
||||
('2.conf',
|
||||
'[DEFAULT]\n'
|
||||
'foo = baaar\n')])
|
||||
|
||||
self.conf(['--foo', 'bar',
|
||||
'--config-file', paths[0],
|
||||
'--config-file', paths[1]])
|
||||
|
||||
self.assertTrue(hasattr(self.conf, 'foo'))
|
||||
self.assertEquals(self.conf.foo, 'baaar')
|
||||
|
||||
def test_int_default(self):
|
||||
self.conf.register_opt(IntOpt('foo', default=666))
|
||||
|
||||
paths = self.create_tempfiles([('test.conf',
|
||||
'[DEFAULT]\n')])
|
||||
|
||||
self.conf(['--config-file', paths[0]])
|
||||
|
||||
self.assertTrue(hasattr(self.conf, 'foo'))
|
||||
self.assertEquals(self.conf.foo, 666)
|
||||
|
||||
def test_int_value(self):
|
||||
self.conf.register_opt(IntOpt('foo'))
|
||||
|
||||
paths = self.create_tempfiles([('test.conf',
|
||||
'[DEFAULT]\n'
|
||||
'foo = 666\n')])
|
||||
|
||||
self.conf(['--config-file', paths[0]])
|
||||
|
||||
self.assertTrue(hasattr(self.conf, 'foo'))
|
||||
self.assertEquals(self.conf.foo, 666)
|
||||
|
||||
def test_int_value_override(self):
|
||||
self.conf.register_cli_opt(IntOpt('foo'))
|
||||
|
||||
paths = self.create_tempfiles([('1.conf',
|
||||
'[DEFAULT]\n'
|
||||
'foo = 66\n'),
|
||||
('2.conf',
|
||||
'[DEFAULT]\n'
|
||||
'foo = 666\n')])
|
||||
|
||||
self.conf(['--foo', '6',
|
||||
'--config-file', paths[0],
|
||||
'--config-file', paths[1]])
|
||||
|
||||
self.assertTrue(hasattr(self.conf, 'foo'))
|
||||
self.assertEquals(self.conf.foo, 666)
|
||||
|
||||
def test_float_default(self):
|
||||
self.conf.register_opt(FloatOpt('foo', default=6.66))
|
||||
|
||||
paths = self.create_tempfiles([('test.conf',
|
||||
'[DEFAULT]\n')])
|
||||
|
||||
self.conf(['--config-file', paths[0]])
|
||||
|
||||
self.assertTrue(hasattr(self.conf, 'foo'))
|
||||
self.assertEquals(self.conf.foo, 6.66)
|
||||
|
||||
def test_float_value(self):
|
||||
self.conf.register_opt(FloatOpt('foo'))
|
||||
|
||||
paths = self.create_tempfiles([('test.conf',
|
||||
'[DEFAULT]\n'
|
||||
'foo = 6.66\n')])
|
||||
|
||||
self.conf(['--config-file', paths[0]])
|
||||
|
||||
self.assertTrue(hasattr(self.conf, 'foo'))
|
||||
self.assertEquals(self.conf.foo, 6.66)
|
||||
|
||||
def test_float_value_override(self):
|
||||
self.conf.register_cli_opt(FloatOpt('foo'))
|
||||
|
||||
paths = self.create_tempfiles([('1.conf',
|
||||
'[DEFAULT]\n'
|
||||
'foo = 6.6\n'),
|
||||
('2.conf',
|
||||
'[DEFAULT]\n'
|
||||
'foo = 6.66\n')])
|
||||
|
||||
self.conf(['--foo', '6',
|
||||
'--config-file', paths[0],
|
||||
'--config-file', paths[1]])
|
||||
|
||||
self.assertTrue(hasattr(self.conf, 'foo'))
|
||||
self.assertEquals(self.conf.foo, 6.66)
|
||||
|
||||
def test_list_default(self):
|
||||
self.conf.register_opt(ListOpt('foo', default=['bar']))
|
||||
|
||||
paths = self.create_tempfiles([('test.conf',
|
||||
'[DEFAULT]\n')])
|
||||
|
||||
self.conf(['--config-file', paths[0]])
|
||||
|
||||
self.assertTrue(hasattr(self.conf, 'foo'))
|
||||
self.assertEquals(self.conf.foo, ['bar'])
|
||||
|
||||
def test_list_value(self):
|
||||
self.conf.register_opt(ListOpt('foo'))
|
||||
|
||||
paths = self.create_tempfiles([('test.conf',
|
||||
'[DEFAULT]\n'
|
||||
'foo = bar\n')])
|
||||
|
||||
self.conf(['--config-file', paths[0]])
|
||||
|
||||
self.assertTrue(hasattr(self.conf, 'foo'))
|
||||
self.assertEquals(self.conf.foo, ['bar'])
|
||||
|
||||
def test_list_value_override(self):
|
||||
self.conf.register_cli_opt(ListOpt('foo'))
|
||||
|
||||
paths = self.create_tempfiles([('1.conf',
|
||||
'[DEFAULT]\n'
|
||||
'foo = bar,bar\n'),
|
||||
('2.conf',
|
||||
'[DEFAULT]\n'
|
||||
'foo = b,a,r\n')])
|
||||
|
||||
self.conf(['--foo', 'bar',
|
||||
'--config-file', paths[0],
|
||||
'--config-file', paths[1]])
|
||||
|
||||
self.assertTrue(hasattr(self.conf, 'foo'))
|
||||
self.assertEquals(self.conf.foo, ['b', 'a', 'r'])
|
||||
|
||||
def test_multistr_default(self):
|
||||
self.conf.register_opt(MultiStrOpt('foo', default=['bar']))
|
||||
|
||||
paths = self.create_tempfiles([('test.conf',
|
||||
'[DEFAULT]\n')])
|
||||
|
||||
self.conf(['--config-file', paths[0]])
|
||||
|
||||
self.assertTrue(hasattr(self.conf, 'foo'))
|
||||
self.assertEquals(self.conf.foo, ['bar'])
|
||||
|
||||
def test_multistr_value(self):
|
||||
self.conf.register_opt(MultiStrOpt('foo'))
|
||||
|
||||
paths = self.create_tempfiles([('test.conf',
|
||||
'[DEFAULT]\n'
|
||||
'foo = bar\n')])
|
||||
|
||||
self.conf(['--config-file', paths[0]])
|
||||
|
||||
self.assertTrue(hasattr(self.conf, 'foo'))
|
||||
self.assertEquals(self.conf.foo, ['bar'])
|
||||
|
||||
def test_multistr_values_append(self):
|
||||
self.conf.register_cli_opt(ListOpt('foo'))
|
||||
|
||||
paths = self.create_tempfiles([('1.conf',
|
||||
'[DEFAULT]\n'
|
||||
'foo = bar\n'),
|
||||
('2.conf',
|
||||
'[DEFAULT]\n'
|
||||
'foo = bar\n')])
|
||||
|
||||
self.conf(['--foo', 'bar',
|
||||
'--config-file', paths[0],
|
||||
'--config-file', paths[1]])
|
||||
|
||||
self.assertTrue(hasattr(self.conf, 'foo'))
|
||||
|
||||
# FIXME(markmc): values spread across the CLI and multiple
|
||||
# config files should be appended
|
||||
# self.assertEquals(self.conf.foo, ['bar', 'bar', 'bar'])
|
||||
|
||||
|
||||
class OptGroupsTestCase(BaseTestCase):
|
||||
|
||||
def test_arg_group(self):
|
||||
blaa_group = OptGroup('blaa')
|
||||
self.conf.register_group(blaa_group)
|
||||
self.conf.register_cli_opt(StrOpt('foo'), group=blaa_group)
|
||||
|
||||
self.conf(['--blaa-foo', 'bar'])
|
||||
|
||||
self.assertTrue(hasattr(self.conf, 'blaa'))
|
||||
self.assertTrue(hasattr(self.conf.blaa, 'foo'))
|
||||
self.assertEquals(self.conf.blaa.foo, 'bar')
|
||||
|
||||
def test_arg_group_by_name(self):
|
||||
self.conf.register_group(OptGroup('blaa'))
|
||||
self.conf.register_cli_opt(StrOpt('foo'), group='blaa')
|
||||
|
||||
self.conf(['--blaa-foo', 'bar'])
|
||||
|
||||
self.assertTrue(hasattr(self.conf, 'blaa'))
|
||||
self.assertTrue(hasattr(self.conf.blaa, 'foo'))
|
||||
self.assertEquals(self.conf.blaa.foo, 'bar')
|
||||
|
||||
def test_arg_group_with_default(self):
|
||||
self.conf.register_group(OptGroup('blaa'))
|
||||
self.conf.register_cli_opt(StrOpt('foo', default='bar'), group='blaa')
|
||||
|
||||
self.conf([])
|
||||
|
||||
self.assertTrue(hasattr(self.conf, 'blaa'))
|
||||
self.assertTrue(hasattr(self.conf.blaa, 'foo'))
|
||||
self.assertEquals(self.conf.blaa.foo, 'bar')
|
||||
|
||||
def test_arg_group_in_config_file(self):
|
||||
self.conf.register_group(OptGroup('blaa'))
|
||||
self.conf.register_opt(StrOpt('foo'), group='blaa')
|
||||
|
||||
paths = self.create_tempfiles([('test.conf',
|
||||
'[blaa]\n'
|
||||
'foo = bar\n')])
|
||||
|
||||
self.conf(['--config-file', paths[0]])
|
||||
|
||||
self.assertTrue(hasattr(self.conf, 'blaa'))
|
||||
self.assertTrue(hasattr(self.conf.blaa, 'foo'))
|
||||
self.assertEquals(self.conf.blaa.foo, 'bar')
|
||||
|
||||
|
||||
class TemplateSubstitutionTestCase(BaseTestCase):
|
||||
|
||||
def _prep_test_str_sub(self, foo_default=None, bar_default=None):
|
||||
self.conf.register_cli_opt(StrOpt('foo', default=foo_default))
|
||||
self.conf.register_cli_opt(StrOpt('bar', default=bar_default))
|
||||
|
||||
def _assert_str_sub(self):
|
||||
self.assertTrue(hasattr(self.conf, 'bar'))
|
||||
self.assertEquals(self.conf.bar, 'blaa')
|
||||
|
||||
def test_str_sub_default_from_default(self):
|
||||
self._prep_test_str_sub(foo_default='blaa', bar_default='$foo')
|
||||
|
||||
self.conf([])
|
||||
|
||||
self._assert_str_sub()
|
||||
|
||||
def test_str_sub_default_from_arg(self):
|
||||
self._prep_test_str_sub(bar_default='$foo')
|
||||
|
||||
self.conf(['--foo', 'blaa'])
|
||||
|
||||
self._assert_str_sub()
|
||||
|
||||
def test_str_sub_default_from_config_file(self):
|
||||
self._prep_test_str_sub(bar_default='$foo')
|
||||
|
||||
paths = self.create_tempfiles([('test.conf',
|
||||
'[DEFAULT]\n'
|
||||
'foo = blaa\n')])
|
||||
|
||||
self.conf(['--config-file', paths[0]])
|
||||
|
||||
self._assert_str_sub()
|
||||
|
||||
def test_str_sub_arg_from_default(self):
|
||||
self._prep_test_str_sub(foo_default='blaa')
|
||||
|
||||
self.conf(['--bar', '$foo'])
|
||||
|
||||
self._assert_str_sub()
|
||||
|
||||
def test_str_sub_arg_from_arg(self):
|
||||
self._prep_test_str_sub()
|
||||
|
||||
self.conf(['--foo', 'blaa', '--bar', '$foo'])
|
||||
|
||||
self._assert_str_sub()
|
||||
|
||||
def test_str_sub_arg_from_config_file(self):
|
||||
self._prep_test_str_sub()
|
||||
|
||||
paths = self.create_tempfiles([('test.conf',
|
||||
'[DEFAULT]\n'
|
||||
'foo = blaa\n')])
|
||||
|
||||
self.conf(['--config-file', paths[0], '--bar=$foo'])
|
||||
|
||||
self._assert_str_sub()
|
||||
|
||||
def test_str_sub_config_file_from_default(self):
|
||||
self._prep_test_str_sub(foo_default='blaa')
|
||||
|
||||
paths = self.create_tempfiles([('test.conf',
|
||||
'[DEFAULT]\n'
|
||||
'bar = $foo\n')])
|
||||
|
||||
self.conf(['--config-file', paths[0]])
|
||||
|
||||
self._assert_str_sub()
|
||||
|
||||
def test_str_sub_config_file_from_arg(self):
|
||||
self._prep_test_str_sub()
|
||||
|
||||
paths = self.create_tempfiles([('test.conf',
|
||||
'[DEFAULT]\n'
|
||||
'bar = $foo\n')])
|
||||
|
||||
self.conf(['--config-file', paths[0], '--foo=blaa'])
|
||||
|
||||
self._assert_str_sub()
|
||||
|
||||
def test_str_sub_config_file_from_config_file(self):
|
||||
self._prep_test_str_sub()
|
||||
|
||||
paths = self.create_tempfiles([('test.conf',
|
||||
'[DEFAULT]\n'
|
||||
'bar = $foo\n'
|
||||
'foo = blaa\n')])
|
||||
|
||||
self.conf(['--config-file', paths[0]])
|
||||
|
||||
self._assert_str_sub()
|
||||
|
||||
def test_str_sub_group_from_default(self):
|
||||
self.conf.register_cli_opt(StrOpt('foo', default='blaa'))
|
||||
self.conf.register_group(OptGroup('ba'))
|
||||
self.conf.register_cli_opt(StrOpt('r', default='$foo'), group='ba')
|
||||
|
||||
self.conf([])
|
||||
|
||||
self.assertTrue(hasattr(self.conf, 'ba'))
|
||||
self.assertTrue(hasattr(self.conf.ba, 'r'))
|
||||
self.assertEquals(self.conf.ba.r, 'blaa')
|
||||
|
||||
|
||||
class ReparseTestCase(BaseTestCase):
|
||||
|
||||
def test_reparse(self):
|
||||
self.conf.register_group(OptGroup('blaa'))
|
||||
self.conf.register_cli_opt(StrOpt('foo', default='r'), group='blaa')
|
||||
|
||||
paths = self.create_tempfiles([('test.conf',
|
||||
'[blaa]\n'
|
||||
'foo = b\n')])
|
||||
|
||||
self.conf(['--config-file', paths[0]])
|
||||
|
||||
self.assertTrue(hasattr(self.conf, 'blaa'))
|
||||
self.assertTrue(hasattr(self.conf.blaa, 'foo'))
|
||||
self.assertEquals(self.conf.blaa.foo, 'b')
|
||||
|
||||
self.conf(['--blaa-foo', 'a'])
|
||||
|
||||
self.assertTrue(hasattr(self.conf, 'blaa'))
|
||||
self.assertTrue(hasattr(self.conf.blaa, 'foo'))
|
||||
self.assertEquals(self.conf.blaa.foo, 'a')
|
||||
|
||||
self.conf([])
|
||||
|
||||
self.assertTrue(hasattr(self.conf, 'blaa'))
|
||||
self.assertTrue(hasattr(self.conf.blaa, 'foo'))
|
||||
self.assertEquals(self.conf.blaa.foo, 'r')
|
||||
|
||||
|
||||
class OverridesTestCase(BaseTestCase):
|
||||
|
||||
def test_no_default_override(self):
|
||||
self.conf.register_opt(StrOpt('foo'))
|
||||
self.conf([])
|
||||
self.assertEquals(self.conf.foo, None)
|
||||
self.conf.set_default('foo', 'bar')
|
||||
self.assertEquals(self.conf.foo, 'bar')
|
||||
|
||||
def test_default_override(self):
|
||||
self.conf.register_opt(StrOpt('foo', default='foo'))
|
||||
self.conf([])
|
||||
self.assertEquals(self.conf.foo, 'foo')
|
||||
self.conf.set_default('foo', 'bar')
|
||||
self.assertEquals(self.conf.foo, 'bar')
|
||||
self.conf.set_default('foo', None)
|
||||
self.assertEquals(self.conf.foo, 'foo')
|
||||
|
||||
def test_override(self):
|
||||
self.conf.register_opt(StrOpt('foo'))
|
||||
self.conf.set_override('foo', 'bar')
|
||||
self.conf([])
|
||||
self.assertEquals(self.conf.foo, 'bar')
|
||||
|
||||
def test_group_no_default_override(self):
|
||||
self.conf.register_group(OptGroup('blaa'))
|
||||
self.conf.register_opt(StrOpt('foo'), group='blaa')
|
||||
self.conf([])
|
||||
self.assertEquals(self.conf.blaa.foo, None)
|
||||
self.conf.set_default('foo', 'bar', group='blaa')
|
||||
self.assertEquals(self.conf.blaa.foo, 'bar')
|
||||
|
||||
def test_default_override(self):
|
||||
self.conf.register_group(OptGroup('blaa'))
|
||||
self.conf.register_opt(StrOpt('foo', default='foo'), group='blaa')
|
||||
self.conf([])
|
||||
self.assertEquals(self.conf.blaa.foo, 'foo')
|
||||
self.conf.set_default('foo', 'bar', group='blaa')
|
||||
self.assertEquals(self.conf.blaa.foo, 'bar')
|
||||
self.conf.set_default('foo', None, group='blaa')
|
||||
self.assertEquals(self.conf.blaa.foo, 'foo')
|
||||
|
||||
def test_override(self):
|
||||
self.conf.register_group(OptGroup('blaa'))
|
||||
self.conf.register_opt(StrOpt('foo'), group='blaa')
|
||||
self.conf.set_override('foo', 'bar', group='blaa')
|
||||
self.conf([])
|
||||
self.assertEquals(self.conf.blaa.foo, 'bar')
|
||||
|
||||
|
||||
class SadPathTestCase(BaseTestCase):
|
||||
|
||||
def test_unknown_attr(self):
|
||||
self.conf([])
|
||||
self.assertFalse(hasattr(self.conf, 'foo'))
|
||||
self.assertRaises(NoSuchOptError, getattr, self.conf, 'foo')
|
||||
|
||||
def test_unknown_group_attr(self):
|
||||
self.conf.register_group(OptGroup('blaa'))
|
||||
|
||||
self.conf([])
|
||||
|
||||
self.assertTrue(hasattr(self.conf, 'blaa'))
|
||||
self.assertFalse(hasattr(self.conf.blaa, 'foo'))
|
||||
self.assertRaises(NoSuchOptError, getattr, self.conf.blaa, 'foo')
|
||||
|
||||
def test_ok_duplicate(self):
|
||||
opt = StrOpt('foo')
|
||||
self.conf.register_cli_opt(opt)
|
||||
self.conf.register_cli_opt(opt)
|
||||
|
||||
self.conf([])
|
||||
|
||||
self.assertTrue(hasattr(self.conf, 'foo'))
|
||||
self.assertEquals(self.conf.foo, None)
|
||||
|
||||
def test_error_duplicate(self):
|
||||
self.conf.register_cli_opt(StrOpt('foo'))
|
||||
self.assertRaises(DuplicateOptError,
|
||||
self.conf.register_cli_opt, StrOpt('foo'))
|
||||
|
||||
def test_error_duplicate_with_different_dest(self):
|
||||
self.conf.register_cli_opt(StrOpt('foo', dest='f'))
|
||||
self.assertRaises(DuplicateOptError,
|
||||
self.conf.register_cli_opt, StrOpt('foo'))
|
||||
|
||||
def test_error_duplicate_short(self):
|
||||
self.conf.register_cli_opt(StrOpt('foo', short='f'))
|
||||
self.assertRaises(DuplicateOptError,
|
||||
self.conf.register_cli_opt, StrOpt('bar', short='f'))
|
||||
|
||||
def test_no_such_group(self):
|
||||
self.assertRaises(NoSuchGroupError, self.conf.register_cli_opt,
|
||||
StrOpt('foo'), group='blaa')
|
||||
|
||||
def test_already_parsed(self):
|
||||
self.conf([])
|
||||
|
||||
self.assertRaises(ArgsAlreadyParsedError,
|
||||
self.conf.register_cli_opt, StrOpt('foo'))
|
||||
|
||||
def test_bad_cli_arg(self):
|
||||
self.stubs.Set(sys, 'stderr', StringIO.StringIO())
|
||||
|
||||
self.assertRaises(SystemExit, self.conf, ['--foo'])
|
||||
|
||||
self.assertTrue('error' in sys.stderr.getvalue())
|
||||
self.assertTrue('--foo' in sys.stderr.getvalue())
|
||||
|
||||
def _do_test_bad_cli_value(self, opt_class):
|
||||
self.conf.register_cli_opt(opt_class('foo'))
|
||||
|
||||
self.stubs.Set(sys, 'stderr', StringIO.StringIO())
|
||||
|
||||
self.assertRaises(SystemExit, self.conf, ['--foo', 'bar'])
|
||||
|
||||
self.assertTrue('foo' in sys.stderr.getvalue())
|
||||
self.assertTrue('bar' in sys.stderr.getvalue())
|
||||
|
||||
def test_bad_int_arg(self):
|
||||
self._do_test_bad_cli_value(IntOpt)
|
||||
|
||||
def test_bad_float_arg(self):
|
||||
self._do_test_bad_cli_value(FloatOpt)
|
||||
|
||||
def test_conf_file_not_found(self):
|
||||
paths = self.create_tempfiles([('test.conf', '')])
|
||||
os.remove(paths[0])
|
||||
self.tempfiles.remove(paths[0])
|
||||
|
||||
self.assertRaises(ConfigFilesNotFoundError,
|
||||
self.conf, ['--config-file', paths[0]])
|
||||
|
||||
def test_conf_file_not_found(self):
|
||||
paths = self.create_tempfiles([('test.conf', 'foo')])
|
||||
|
||||
self.assertRaises(ConfigFileParseError,
|
||||
self.conf, ['--config-file', paths[0]])
|
||||
|
||||
def _do_test_conf_file_bad_value(self, opt_class):
|
||||
self.conf.register_opt(opt_class('foo'))
|
||||
|
||||
def test_conf_file_bad_bool(self):
|
||||
self._do_test_conf_file_bad_value(BoolOpt)
|
||||
|
||||
def test_conf_file_bad_int(self):
|
||||
self._do_test_conf_file_bad_value(IntOpt)
|
||||
|
||||
def test_conf_file_bad_float(self):
|
||||
self._do_test_conf_file_bad_value(FloatOpt)
|
||||
|
||||
def test_str_sub_from_group(self):
|
||||
self.conf.register_group(OptGroup('f'))
|
||||
self.conf.register_cli_opt(StrOpt('oo', default='blaa'), group='f')
|
||||
self.conf.register_cli_opt(StrOpt('bar', default='$f.oo'))
|
||||
|
||||
self.conf([])
|
||||
|
||||
self.assertFalse(hasattr(self.conf, 'bar'))
|
||||
self.assertRaises(TemplateSubstitutionError, getattr, self.conf, 'bar')
|
||||
|
||||
def test_set_default_unknown_attr(self):
|
||||
self.conf([])
|
||||
self.assertRaises(NoSuchOptError, self.conf.set_default, 'foo', 'bar')
|
||||
|
||||
def test_set_default_unknown_group(self):
|
||||
self.conf([])
|
||||
self.assertRaises(NoSuchGroupError,
|
||||
self.conf.set_default, 'foo', 'bar', group='blaa')
|
||||
|
||||
def test_set_override_unknown_attr(self):
|
||||
self.conf([])
|
||||
self.assertRaises(NoSuchOptError, self.conf.set_override, 'foo', 'bar')
|
||||
|
||||
def test_set_override_unknown_group(self):
|
||||
self.conf([])
|
||||
self.assertRaises(NoSuchGroupError,
|
||||
self.conf.set_override, 'foo', 'bar', group='blaa')
|
||||
|
||||
|
||||
class OptDumpingTestCase(BaseTestCase):
|
||||
|
||||
class FakeLogger:
|
||||
|
||||
def __init__(self, test_case, expected_lvl):
|
||||
self.test_case = test_case
|
||||
self.expected_lvl = expected_lvl
|
||||
self.logged = []
|
||||
|
||||
def log(self, lvl, fmt, *args):
|
||||
self.test_case.assertEquals(lvl, self.expected_lvl)
|
||||
self.logged.append(fmt % args)
|
||||
|
||||
def test_log_opt_values(self):
|
||||
self.conf.register_cli_opt(StrOpt('foo'))
|
||||
self.conf.register_cli_opt(StrOpt('passwd', secret=True))
|
||||
self.conf.register_group(OptGroup('blaa'))
|
||||
self.conf.register_cli_opt(StrOpt('bar'), 'blaa')
|
||||
self.conf.register_cli_opt(StrOpt('key', secret=True), 'blaa')
|
||||
|
||||
self.conf(['--foo', 'this', '--blaa-bar', 'that',
|
||||
'--blaa-key', 'admin', '--passwd', 'hush'])
|
||||
|
||||
logger = self.FakeLogger(self, 666)
|
||||
|
||||
self.conf.log_opt_values(logger, 666)
|
||||
|
||||
self.assertEquals(logger.logged, [
|
||||
"*" * 80,
|
||||
"Configuration options gathered from:",
|
||||
"command line args: ['--foo', 'this', '--blaa-bar', 'that', "\
|
||||
"'--blaa-key', 'admin', '--passwd', 'hush']",
|
||||
"config files: []",
|
||||
"=" * 80,
|
||||
"config_file = []",
|
||||
"foo = this",
|
||||
"passwd = ****",
|
||||
"blaa.bar = that",
|
||||
"blaa.key = *****",
|
||||
"*" * 80,
|
||||
])
|
||||
|
||||
|
||||
class CommonOptsTestCase(BaseTestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(CommonOptsTestCase, self).setUp()
|
||||
self.conf = CommonConfigOpts()
|
||||
|
||||
def test_debug_verbose(self):
|
||||
self.conf(['--debug', '--verbose'])
|
||||
|
||||
self.assertEquals(self.conf.debug, True)
|
||||
self.assertEquals(self.conf.verbose, True)
|
||||
|
||||
def test_logging_opts(self):
|
||||
self.conf([])
|
||||
|
||||
self.assertTrue(self.conf.log_config is None)
|
||||
self.assertTrue(self.conf.log_file is None)
|
||||
self.assertTrue(self.conf.log_dir is None)
|
||||
|
||||
self.assertEquals(self.conf.log_format,
|
||||
CommonConfigOpts.DEFAULT_LOG_FORMAT)
|
||||
self.assertEquals(self.conf.log_date_format,
|
||||
CommonConfigOpts.DEFAULT_LOG_DATE_FORMAT)
|
||||
|
||||
self.assertEquals(self.conf.use_syslog, False)
|
@ -25,8 +25,8 @@ import unittest
|
||||
import stubout
|
||||
|
||||
from glance import image_cache
|
||||
from glance.common import cfg
|
||||
from glance.common import utils
|
||||
from glance.openstack.common import cfg
|
||||
from glance.tests import utils as test_utils
|
||||
from glance.tests.utils import skip_if_disabled, xattr_writes_supported
|
||||
|
||||
|
@ -34,8 +34,8 @@ from migrate.versioning.repository import Repository
|
||||
from sqlalchemy import *
|
||||
from sqlalchemy.pool import NullPool
|
||||
|
||||
from glance.common import cfg
|
||||
from glance.common import exception
|
||||
from glance.openstack.common import cfg
|
||||
import glance.registry.db.migration as migration_api
|
||||
from glance.registry.db import models
|
||||
from glance.tests import utils
|
||||
|
7
openstack-common.conf
Normal file
7
openstack-common.conf
Normal file
@ -0,0 +1,7 @@
|
||||
[DEFAULT]
|
||||
|
||||
# The list of modules to copy from openstack-common
|
||||
modules=iniparser,cfg,setup
|
||||
|
||||
# The base module to hold the copy of openstack.common
|
||||
base=glance
|
4
setup.py
4
setup.py
@ -21,8 +21,8 @@ import subprocess
|
||||
from setuptools import setup, find_packages
|
||||
from setuptools.command.sdist import sdist
|
||||
|
||||
from glance.common.setup import parse_requirements
|
||||
from glance.common.setup import parse_dependency_links
|
||||
from glance.openstack.common.setup import parse_requirements
|
||||
from glance.openstack.common.setup import parse_dependency_links
|
||||
|
||||
gettext.install('glance', unicode=1)
|
||||
|
||||
|
@ -6,7 +6,8 @@ import sys
|
||||
import keystoneclient.v2_0.client
|
||||
|
||||
import glance.common.context
|
||||
import glance.common.cfg
|
||||
import glance.openstack.common.cfg
|
||||
import glance.registry.context
|
||||
import glance.registry.db.api as db_api
|
||||
|
||||
|
||||
@ -56,18 +57,18 @@ def update_image_owners(image_owner_map, db, context):
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
config = glance.common.cfg.CommonConfigOpts(project='glance',
|
||||
prog='glance-registry')
|
||||
config = glance.openstack.common.cfg.CommonConfigOpts(project='glance',
|
||||
prog='glance-registry')
|
||||
extra_cli_opts = [
|
||||
glance.common.cfg.BoolOpt('dry-run',
|
||||
glance.openstack.common.cfg.BoolOpt('dry-run',
|
||||
help='Print output but do not make db changes.'),
|
||||
glance.common.cfg.StrOpt('keystone-auth-uri',
|
||||
glance.openstack.common.cfg.StrOpt('keystone-auth-uri',
|
||||
help='Authentication endpoint'),
|
||||
glance.common.cfg.StrOpt('keystone-admin-tenant-name',
|
||||
glance.openstack.common.cfg.StrOpt('keystone-admin-tenant-name',
|
||||
help='Administrative user\'s tenant name'),
|
||||
glance.common.cfg.StrOpt('keystone-admin-user',
|
||||
glance.openstack.common.cfg.StrOpt('keystone-admin-user',
|
||||
help='Administrative user\'s id'),
|
||||
glance.common.cfg.StrOpt('keystone-admin-password',
|
||||
glance.openstack.common.cfg.StrOpt('keystone-admin-password',
|
||||
help='Administrative user\'s password'),
|
||||
]
|
||||
config.register_cli_opts(extra_cli_opts)
|
||||
|
Loading…
Reference in New Issue
Block a user