]> review.fuel-infra Code Review - openstack-build/neutron-build.git/commitdiff
Implements the blueprint use-common-cfg for the quantum service.
authorGary Kotton <gkotton@redhat.com>
Sun, 3 Jun 2012 11:55:09 +0000 (07:55 -0400)
committerGary Kotton <gkotton@redhat.com>
Wed, 20 Jun 2012 06:30:11 +0000 (02:30 -0400)
More specifically uses global CONF for the quantum.conf file.

Added support for the RYU plugin (similar to ovs and lb,
which use non-global conf for plugins)

patch 27: clean up find_config_file
patch 28: for config file use old paths (plugin unit tests)
          this hopefully will be replaced when we move to common
          config file
patch 30: rebase and merge (utils.py and policy.py)

Change-Id: Ic0bf5bdd44f24a557240f7afe4e070dee448c63c

37 files changed:
etc/plugins.ini [deleted file]
etc/quantum.conf
etc/quantum/plugins/ryu/ryu.ini
quantum/api/__init__.py
quantum/api/v2/base.py
quantum/api/v2/router.py
quantum/common/config.py
quantum/common/utils.py
quantum/extensions/extensions.py
quantum/manager.py
quantum/openstack/common/cfg.py
quantum/plugins/cisco/common/cisco_credentials.py
quantum/plugins/cisco/l2network_plugin_configuration.py
quantum/plugins/cisco/nexus/cisco_nexus_configuration.py
quantum/plugins/cisco/tests/unit/test_cisco_extension.py
quantum/plugins/cisco/ucs/cisco_ucs_configuration.py
quantum/plugins/cisco/ucs/cisco_ucs_inventory_configuration.py
quantum/plugins/linuxbridge/common/config.py
quantum/plugins/linuxbridge/db/l2network_db.py
quantum/plugins/openvswitch/common/config.py
quantum/plugins/openvswitch/ovs_quantum_plugin.py
quantum/plugins/ryu/agent/ryu_quantum_agent.py
quantum/plugins/ryu/common/__init__.py [new file with mode: 0644]
quantum/plugins/ryu/common/config.py [new file with mode: 0644]
quantum/plugins/ryu/ovs_quantum_plugin_base.py
quantum/plugins/ryu/ryu_quantum_plugin.py
quantum/plugins/ryu/tests/unit/fake_plugin.py
quantum/plugins/ryu/tests/unit/test_ryu_driver.py
quantum/policy.py
quantum/server/__init__.py
quantum/service.py
quantum/tests/etc/quantum.conf.test [moved from etc/quantum.conf.test with 100% similarity]
quantum/tests/unit/_test_api.py
quantum/tests/unit/test_api_v2.py
quantum/tests/unit/test_db_plugin.py
quantum/tests/unit/test_extensions.py
setup.py

diff --git a/etc/plugins.ini b/etc/plugins.ini
deleted file mode 100644 (file)
index 49c6602..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-[PLUGIN]
-# Quantum plugin provider module
-provider = quantum.plugins.sample.SamplePlugin.FakePlugin
index b19442865fca145ba6f2768d93b46b8901c46831..b96d0ef7215a65b40c433fb4a12f0b8bb89df2b8 100644 (file)
@@ -18,6 +18,9 @@ bind_port = 9696
 # extensions are in there you don't need to specify them here
 api_extensions_path =
 
+# Quantum plugin provider module
+core_plugin = quantum.plugins.sample.SamplePlugin.FakePlugin
+
 [composite:quantum]
 use = egg:Paste#urlmap
 /: quantumversions
index 2d5a2c5d7ce0b56035d1b52b8ae4efa0ce9f1293..a90e8466b9b27e2dd9da3346b9f63f59554f6370 100644 (file)
@@ -5,12 +5,12 @@
 sql_connection = sqlite://
 
 [OVS]
-integration-bridge = br-int
+integration_bridge = br-int
 
-# openflow-controller = <host IP address of ofp controller>:<port: 6633>
-# openflow-rest-api = <host IP address of ofp rest api service>:<port: 8080>
-openflow-controller = 127.0.0.1:6633
-openflow-rest-api = 127.0.0.1:8080
+# openflow_controller = <host IP address of ofp controller>:<port: 6633>
+# openflow_rest_api = <host IP address of ofp rest api service>:<port: 8080>
+openflow_controller = 127.0.0.1:6633
+openflow_rest_api = 127.0.0.1:8080
 
 [AGENT]
 # Change to "sudo quantum-rootwrap" to limit commands that can be run
index aa5a8791b1cfdd2d3018ecc3f2f53a40da45913f..813ff40ec4250d6973e5700fce522b1f17c1a57a 100644 (file)
@@ -42,23 +42,23 @@ class APIRouter(wsgi.Router):
     """
     _version = None
 
-    def __init__(self, options=None):
+    def __init__(self):
         mapper = self._mapper()
-        self._setup_routes(mapper, options)
+        self._setup_routes(mapper)
         super(APIRouter, self).__init__(mapper)
 
     def _mapper(self):
         return routes.Mapper()
 
-    def _setup_routes(self, mapper, options):
-        self._setup_base_routes(mapper, options, self._version)
+    def _setup_routes(self, mapper):
+        self._setup_base_routes(mapper, self._version)
 
-    def _setup_base_routes(self, mapper, options, version):
+    def _setup_base_routes(self, mapper, version):
         """Routes common to all versions."""
         # Loads the quantum plugin
         # Note(salvatore-orlando): Should the plugin be versioned
         # I don't think so
-        plugin = manager.QuantumManager.get_plugin(options)
+        plugin = manager.QuantumManager.get_plugin()
 
         uri_prefix = '/tenants/{tenant_id}/'
         attachment_path = (
index fbd92468c180a10c79b2f8dbf2281f86577819f8..08148087b7c8402e50a2c98fb92bb734712585e8 100644 (file)
@@ -293,7 +293,7 @@ class Controller(object):
         return body
 
 
-def create_resource(collection, resource, plugin, conf, params):
+def create_resource(collection, resource, plugin, params):
     controller = Controller(plugin, collection, resource, params)
 
     # NOTE(jkoelker) To anyone wishing to add "proper" xml support
index 04b2ff7f60407f8cc18d860540e67a73dc886d0b..0b2d7a6f8c44d72ab330dda05b532d90ed2b7b35 100644 (file)
@@ -24,6 +24,7 @@ import webob.exc
 from quantum import manager
 from quantum import wsgi
 from quantum.api.v2 import base
+from quantum.openstack.common import cfg
 
 
 LOG = logging.getLogger(__name__)
@@ -118,16 +119,14 @@ class APIRouter(wsgi.Router):
 
     @classmethod
     def factory(cls, global_config, **local_config):
-        return cls(global_config, **local_config)
+        return cls(**local_config)
 
-    def __init__(self, conf, **local_config):
+    def __init__(self, **local_config):
         mapper = routes_mapper.Mapper()
-        plugin_provider = manager.get_plugin_provider(conf)
+        plugin_provider = cfg.CONF.core_plugin
+        LOG.debug("Plugin location:%s", plugin_provider)
         plugin = manager.get_plugin(plugin_provider)
 
-        # NOTE(jkoelker) Merge local_conf into conf after the plugin
-        #                is discovered
-        conf.update(local_config)
         col_kwargs = dict(collection_actions=COLLECTION_ACTIONS,
                           member_actions=MEMBER_ACTIONS)
 
@@ -137,8 +136,7 @@ class APIRouter(wsgi.Router):
 
         def _map_resource(collection, resource, params):
             controller = base.create_resource(collection, resource,
-                                              plugin, conf,
-                                              params)
+                                              plugin, params)
             mapper_kwargs = dict(controller=controller,
                                  requirements=REQUIREMENTS,
                                  **col_kwargs)
index f426b4594ab7aeef30dcbc3c222c8171232c4a60..1e608c013e42379fe302017048687ec54fb23113 100644 (file)
@@ -20,325 +20,100 @@ Routines for configuring Quantum
 """
 
 import logging
-import logging.config
 import logging.handlers
-import optparse
 import os
-import socket
 import sys
 
 from paste import deploy
 
-from quantum.common import flags
+from quantum.openstack.common import cfg
+from quantum.version import version_string
 
 
 LOG = logging.getLogger(__name__)
-DEFAULT_LOG_FORMAT = "%(asctime)s %(levelname)8s [%(name)s] %(message)s"
-DEFAULT_LOG_DATE_FORMAT = "%Y-%m-%d %H:%M:%S"
 
-FLAGS = flags.FLAGS
+bind_opts = [
+    cfg.StrOpt('bind_host', default='0.0.0.0'),
+    cfg.IntOpt('bind_port', default=9696),
+    cfg.StrOpt('api_extensions_path', default=""),
+    cfg.StrOpt('core_plugin',
+               default='quantum.plugins.sample.SamplePlugin.FakePlugin'),
+]
 
+# Register the configuration options
+cfg.CONF.register_opts(bind_opts)
 
-def parse_options(parser, cli_args=None):
-    """
-    Returns the parsed CLI options, command to run and its arguments, merged
-    with any same-named options found in a configuration file.
-
-    The function returns a tuple of (options, args), where options is a
-    mapping of option key/str(value) pairs, and args is the set of arguments
-    (not options) supplied on the command-line.
-
-    The reason that the option values are returned as strings only is that
-    ConfigParser and paste.deploy only accept string values...
-
-    :param parser: The option parser
-    :param cli_args: (Optional) Set of arguments to process. If not present,
-                     sys.argv[1:] is used.
-    :retval tuple of (options, args)
-    """
-
-    (options, args) = parser.parse_args(cli_args)
-
-    return (vars(options), args)
-
-
-def add_common_options(parser):
-    """
-    Given a supplied optparse.OptionParser, adds an OptionGroup that
-    represents all common configuration options.
-
-    :param parser: optparse.OptionParser
-    """
-    help_text = "The following configuration options are common to "\
-                "all quantum programs."
 
-    group = optparse.OptionGroup(parser, "Common Options", help_text)
-    group.add_option('-v', '--verbose', default=False, dest="verbose",
-                     action="store_true",
-                     help="Print more verbose output")
-    group.add_option('-d', '--debug', default=False, dest="debug",
-                     action="store_true",
-                     help="Print debugging output")
-    group.add_option('--config-file', default=None, metavar="PATH",
-                     help="Path to the config file to use. When not specified "
-                          "(the default), we generally look at the first "
-                          "argument specified to be a config file, and if "
-                          "that is also missing, we search standard "
-                          "directories for a config file.")
-    parser.add_option_group(group)
+def parse(args):
+    cfg.CONF(args=args, project='quantum',
+             version='%%prog %s' % version_string())
 
 
-def add_log_options(parser):
-    """
-    Given a supplied optparse.OptionParser, adds an OptionGroup that
-    represents all the configuration options around logging.
-
-    :param parser: optparse.OptionParser
-    """
-    help_text = "The following configuration options are specific to logging "\
-                "functionality for this program."
-
-    group = optparse.OptionGroup(parser, "Logging Options", help_text)
-    group.add_option('--log-config', default=None, metavar="PATH",
-                     help="If this option is specified, the logging "
-                          "configuration file specified is used and overrides "
-                          "any other logging options specified. Please see "
-                          "the Python logging module documentation for "
-                          "details on logging configuration files.")
-    group.add_option('--log-date-format', metavar="FORMAT",
-                     default=DEFAULT_LOG_DATE_FORMAT,
-                     help="Format string for %(asctime)s in log records. "
-                          "Default: %default")
-    group.add_option('--use-syslog', default=False,
-                     action="store_true",
-                     help="Output logs to syslog.")
-    group.add_option('--log-file', default=None, metavar="PATH",
-                     help="(Optional) Name of log file to output to. "
-                          "If not set, logging will go to stdout.")
-    group.add_option("--log-dir", default=None,
-                     help="(Optional) The directory to keep log files in "
-                          "(will be prepended to --logfile)")
-    parser.add_option_group(group)
-
-
-def setup_logging(options, conf):
+def setup_logging(conf):
     """
     Sets up the logging options for a log with supplied name
 
-    :param options: Mapping of typed option key/values
-    :param conf: Mapping of untyped key/values from config file
+    :param conf: a cfg.ConfOpts object
     """
 
-    if options.get('log_config', None):
+    if conf.log_config:
         # Use a logging configuration file for all settings...
-        if os.path.exists(options['log_config']):
-            logging.config.fileConfig(options['log_config'])
+        if os.path.exists(conf.log_config):
+            logging.config.fileConfig(conf.log_config)
             return
         else:
             raise RuntimeError("Unable to locate specified logging "
-                               "config file: %s" % options['log_config'])
+                               "config file: %s" % conf.log_config)
 
-    # If either the CLI option or the conf value
-    # is True, we set to True
-    debug = (options.get('debug') or
-             get_option(conf, 'debug', type='bool', default=False))
-    verbose = (options.get('verbose') or
-               get_option(conf, 'verbose', type='bool', default=False))
     root_logger = logging.root
-    if debug:
+    if conf.debug:
         root_logger.setLevel(logging.DEBUG)
-    elif verbose:
+    elif conf.verbose:
         root_logger.setLevel(logging.INFO)
     else:
         root_logger.setLevel(logging.WARNING)
 
-    # Set log configuration from options...
-    # Note that we use a hard-coded log format in the options
-    # because of Paste.Deploy bug #379
-    # http://trac.pythonpaste.org/pythonpaste/ticket/379
-    log_format = options.get('log_format', DEFAULT_LOG_FORMAT)
-    log_date_format = options.get('log_date_format', DEFAULT_LOG_DATE_FORMAT)
-    formatter = logging.Formatter(log_format, log_date_format)
+    formatter = logging.Formatter(conf.log_format, conf.log_date_format)
 
-    syslog = options.get('use_syslog')
-    if not syslog:
-        syslog = conf.get('use_syslog')
-
-    if syslog:
-        SysLogHandler = logging.handlers.SysLogHandler
+    if conf.use_syslog:
         try:
-            handler = SysLogHandler(address='/dev/log',
-                                    facility=SysLogHandler.LOG_SYSLOG)
-        except socket.error:
-            handler = SysLogHandler(address='/var/run/syslog',
-                                    facility=SysLogHandler.LOG_SYSLOG)
-        handler.setFormatter(formatter)
-        root_logger.addHandler(handler)
-
-    logfile = options.get('log_file')
-    if not logfile:
-        logfile = conf.get('log_file')
-
-    if logfile:
-        logdir = options.get('log_dir')
-        if not logdir:
-            logdir = conf.get('log_dir')
-        if logdir:
-            logfile = os.path.join(logdir, logfile)
-        logfile = logging.FileHandler(logfile)
-        logfile.setFormatter(formatter)
-        logfile.setFormatter(formatter)
-        root_logger.addHandler(logfile)
+            facility = getattr(logging.handlers.SysLogHandler,
+                               conf.syslog_log_facility)
+        except AttributeError:
+            raise ValueError(_("Invalid syslog facility"))
+
+        handler = logging.handlers.SysLogHandler(address='/dev/log',
+                                                 facility=facility)
+    elif conf.log_file:
+        logfile = conf.log_file
+        if conf.log_dir:
+            logfile = os.path.join(conf.log_dir, logfile)
+        handler = logging.handlers.WatchedFileHandler(logfile)
     else:
         handler = logging.StreamHandler(sys.stdout)
-        handler.setFormatter(formatter)
-        root_logger.addHandler(handler)
-
-
-def find_config_file(options, args, config_file='quantum.conf'):
-    """
-    Return the first config file found.
-
-    We search for the paste config file in the following order:
-    * If --config-file option is used, use that
-    * If args[0] is a file, use that
-    * Search for the configuration file in standard directories:
-        * .
-        * ~.quantum/
-        * ~
-        * $FLAGS.state_path/etc/quantum
-        * $FLAGS.state_path/etc
-
-    :retval Full path to config file, or None if no config file found
-    """
-
-    fix_path = lambda p: os.path.abspath(os.path.expanduser(p))
-    if options.get('config_file'):
-        if os.path.exists(options['config_file']):
-            return fix_path(options['config_file'])
-    elif args:
-        if os.path.exists(args[0]):
-            return fix_path(args[0])
-
-    dir_to_common = os.path.dirname(os.path.abspath(__file__))
-    root = os.path.join(dir_to_common, '..', '..', '..', '..')
-    # Handle standard directory search for the config file
-    config_file_dirs = [fix_path(os.path.join(os.getcwd(), 'etc')),
-                        fix_path(os.path.join('~', '.quantum-venv', 'etc',
-                                              'quantum')),
-                        fix_path('~'),
-                        os.path.join(FLAGS.state_path, 'etc'),
-                        os.path.join(FLAGS.state_path, 'etc', 'quantum'),
-                        fix_path(os.path.join('~', '.local',
-                                              'etc', 'quantum')),
-                        '/usr/etc/quantum',
-                        '/usr/local/etc/quantum',
-                        '/etc/quantum/',
-                        '/etc']
-
-    if 'plugin' in options:
-        config_file_dirs = [os.path.join(x, 'quantum',
-                            'plugins', options['plugin'])
-                            for x in config_file_dirs]
-
-    if os.path.exists(os.path.join(root, 'plugins')):
-        plugins = [fix_path(os.path.join(root, 'plugins', p, 'etc'))
-                   for p in os.listdir(os.path.join(root, 'plugins'))]
-        plugins = [p for p in plugins if os.path.isdir(p)]
-        config_file_dirs.extend(plugins)
-
-    for cfg_dir in config_file_dirs:
-        cfg_file = os.path.join(cfg_dir, config_file)
-        if os.path.exists(cfg_file):
-            return cfg_file
-
-
-def load_paste_config(app_name, options, args):
-    """
-    Looks for a config file to use for an app and returns the
-    config file path and a configuration mapping from a paste config file.
 
-    We search for the paste config file in the following order:
-    * If --config-file option is used, use that
-    * If args[0] is a file, use that
-    * Search for quantum.conf in standard directories:
-        * .
-        * ~.quantum/
-        * ~
-        * /etc/quantum
-        * /etc
+    handler.setFormatter(formatter)
+    root_logger.addHandler(handler)
 
-    :param app_name: Name of the application to load config for, or None.
-                     None signifies to only load the [DEFAULT] section of
-                     the config file.
-    :param options: Set of typed options returned from parse_options()
-    :param args: Command line arguments from argv[1:]
-    :retval Tuple of (conf_file, conf)
 
-    :raises RuntimeError when config file cannot be located or there was a
-            problem loading the configuration file.
-    """
-    conf_file = find_config_file(options, args)
-    if not conf_file:
-        raise RuntimeError("Unable to locate any configuration file. "
-                           "Cannot load application %s" % app_name)
-    try:
-        conf = deploy.appconfig("config:%s" % conf_file, name=app_name)
-        return conf_file, conf
-    except Exception, e:
-        raise RuntimeError("Error trying to load config %s: %s"
-                           % (conf_file, e))
-
-
-def load_paste_app(app_name, options, args):
+def load_paste_app(app_name, config_file):
     """
     Builds and returns a WSGI app from a paste config file.
 
-    We search for the paste config file in the following order:
-    * If --config-file option is used, use that
-    * If args[0] is a file, use that
-    * Search for quantum.conf in standard directories:
-        * .
-        * ~.quantum/
-        * ~
-        * /etc/quantum
-        * /etc
-
     :param app_name: Name of the application to load
-    :param options: Set of typed options returned from parse_options()
-    :param args: Command line arguments from argv[1:]
-
+    :param config_file: name of the configuration file
     :raises RuntimeError when config file cannot be located or application
             cannot be loaded from config file
     """
-    conf_file, conf = load_paste_config(app_name, options, args)
+
+    config_path = os.path.abspath(cfg.CONF.find_file(config_file))
+    LOG.info("Config paste file: %s", config_path)
 
     try:
-        app = deploy.loadapp("config:%s" % conf_file, name=app_name)
+        app = deploy.loadapp("config:%s" % config_path, name=app_name)
     except (LookupError, ImportError):
         msg = ("Unable to load %(app_name)s from "
-               "configuration file %(conf_file)s.") % locals()
+               "configuration file %(config_path)s.") % locals()
         LOG.exception(msg)
         raise RuntimeError(msg)
-    return conf, app
-
-
-def get_option(options, option, **kwargs):
-    if option in options:
-        value = options[option]
-        type_ = kwargs.get('type', 'str')
-        if type_ == 'bool':
-            if hasattr(value, 'lower'):
-                return value.lower() == 'true'
-            else:
-                return value
-        elif type_ == 'int':
-            return int(value)
-        elif type_ == 'float':
-            return float(value)
-        else:
-            return value
-    elif 'default' in kwargs:
-        return kwargs['default']
-    else:
-        raise KeyError("option '%s' not found" % option)
+    return app
index 4a355bdf92b0a31cec36eda8a01dafffdd8a8f9a..4ac2c328bedf647cd02efa23d94681f663220954 100644 (file)
@@ -21,7 +21,8 @@
 """Utilities and helper functions."""
 
 
-import ConfigParser
+import datetime
+import inspect
 import logging
 import os
 import subprocess
@@ -75,12 +76,6 @@ def execute(cmd, process_input=None, addl_env=None, check_exit_code=True):
     return result
 
 
-def get_plugin_from_config(file="config.ini"):
-    Config = ConfigParser.ConfigParser()
-    Config.read(file)
-    return Config.get("PLUGIN", "provider")
-
-
 class LazyPluggable(object):
     """A pluggable backend loaded lazily based on some value."""
 
@@ -110,3 +105,51 @@ class LazyPluggable(object):
     def __getattr__(self, key):
         backend = self.__get_backend()
         return getattr(backend, key)
+
+
+def find_config_file(options, config_file):
+    """
+    Return the first config file found.
+
+    We search for the paste config file in the following order:
+    * If --config-file option is used, use that
+    * Search for the configuration files via common cfg directories
+    :retval Full path to config file, or None if no config file found
+    """
+    fix_path = lambda p: os.path.abspath(os.path.expanduser(p))
+    if options.get('config_file'):
+        if os.path.exists(options['config_file']):
+            return fix_path(options['config_file'])
+
+    dir_to_common = os.path.dirname(os.path.abspath(__file__))
+    root = os.path.join(dir_to_common, '..', '..', '..', '..')
+    # Handle standard directory search for the config file
+    config_file_dirs = [fix_path(os.path.join(os.getcwd(), 'etc')),
+                        fix_path(os.path.join('~', '.quantum-venv', 'etc',
+                                              'quantum')),
+                        fix_path('~'),
+                        os.path.join(FLAGS.state_path, 'etc'),
+                        os.path.join(FLAGS.state_path, 'etc', 'quantum'),
+                        fix_path(os.path.join('~', '.local',
+                                              'etc', 'quantum')),
+                        '/usr/etc/quantum',
+                        '/usr/local/etc/quantum',
+                        '/etc/quantum/',
+                        '/etc']
+
+    if 'plugin' in options:
+        config_file_dirs = [
+            os.path.join(x, 'quantum', 'plugins', options['plugin'])
+            for x in config_file_dirs
+        ]
+
+    if os.path.exists(os.path.join(root, 'plugins')):
+        plugins = [fix_path(os.path.join(root, 'plugins', p, 'etc'))
+                   for p in os.listdir(os.path.join(root, 'plugins'))]
+        plugins = [p for p in plugins if os.path.isdir(p)]
+        config_file_dirs.extend(plugins)
+
+    for cfg_dir in config_file_dirs:
+        cfg_file = os.path.join(cfg_dir, config_file)
+        if os.path.exists(cfg_file):
+            return cfg_file
index 26aebc246efccf567a35466f607ed53142c3898c..1f5dc5d4ca042617ae4844167f3a2040540054cb 100644 (file)
@@ -29,6 +29,7 @@ import webob.exc
 from quantum.common import exceptions
 import quantum.extensions
 from quantum.manager import QuantumManager
+from quantum.openstack.common import cfg
 from quantum import wsgi
 
 
@@ -217,12 +218,12 @@ class ExtensionController(wsgi.Controller):
 
 class ExtensionMiddleware(wsgi.Middleware):
     """Extensions middleware for WSGI."""
-    def __init__(self, application, config_params,
+    def __init__(self, application,
                  ext_mgr=None):
 
         self.ext_mgr = (ext_mgr
                         or ExtensionManager(
-                        get_extensions_path(config_params)))
+                        get_extensions_path()))
         mapper = routes.Mapper()
 
         # extended resources
@@ -339,10 +340,10 @@ class ExtensionMiddleware(wsgi.Middleware):
 def plugin_aware_extension_middleware_factory(global_config, **local_config):
     """Paste factory."""
     def _factory(app):
-        extensions_path = get_extensions_path(global_config)
+        extensions_path = get_extensions_path()
         ext_mgr = PluginAwareExtensionManager(extensions_path,
                                               QuantumManager.get_plugin())
-        return ExtensionMiddleware(app, global_config, ext_mgr=ext_mgr)
+        return ExtensionMiddleware(app, ext_mgr=ext_mgr)
     return _factory
 
 
@@ -539,9 +540,9 @@ class ResourceExtension(object):
 
 # Returns the extention paths from a config entry and the __path__
 # of quantum.extensions
-def get_extensions_path(config=None):
+def get_extensions_path():
     paths = ':'.join(quantum.extensions.__path__)
-    if config:
-        paths = ':'.join([config.get('api_extensions_path', ''), paths])
+    if cfg.CONF.api_extensions_path:
+        paths = ':'.join([cfg.CONF.api_extensions_path, paths])
 
     return paths
index 1f5f4f8f87f7a6ca59cd4dd4868ed07161ab28f9..2d833c30e1311f7f3f43e4023a780a6819267f54 100644 (file)
@@ -24,27 +24,15 @@ The caller should make sure that QuantumManager is a singleton.
 """
 
 import logging
-import os
 
-from quantum.common import utils
-from quantum.common.config import find_config_file
 from quantum.common.exceptions import ClassNotFound
+from quantum.openstack.common import cfg
 from quantum.openstack.common import importutils
 
 
 LOG = logging.getLogger(__name__)
 
 
-CONFIG_FILE = "plugins.ini"
-
-
-def find_config(basepath):
-    for root, dirs, files in os.walk(basepath):
-        if CONFIG_FILE in files:
-            return os.path.join(root, CONFIG_FILE)
-    return None
-
-
 def get_plugin(plugin_provider):
     # If the plugin can't be found let them know gracefully
     try:
@@ -58,16 +46,6 @@ def get_plugin(plugin_provider):
     return plugin_klass()
 
 
-def get_plugin_provider(options, config_file=None):
-    if config_file:
-        config_file = [config_file]
-
-    if not 'plugin_provider' in options:
-        cf = find_config_file(options, config_file, CONFIG_FILE)
-        options['plugin_provider'] = utils.get_plugin_from_config(cf)
-    return options['plugin_provider']
-
-
 class QuantumManager(object):
 
     _instance = None
@@ -81,12 +59,12 @@ class QuantumManager(object):
         #                breaks tach monitoring. It has been removed
         #                intentianally to allow v2 plugins to be monitored
         #                for performance metrics.
-        plugin_provider = get_plugin_provider(options, config_file)
+        plugin_provider = cfg.CONF.core_plugin
         LOG.debug("Plugin location:%s", plugin_provider)
         self.plugin = get_plugin(plugin_provider)
 
     @classmethod
-    def get_plugin(cls, options=None, config_file=None):
+    def get_plugin(cls):
         if cls._instance is None:
-            cls._instance = cls(options, config_file)
+            cls._instance = cls()
         return cls._instance.plugin
index 80345a6d2ad1a58f182e7247d635a205c16d499c..b1493a31c0508da4f30842243ceec0edcbe581f2 100644 (file)
@@ -95,7 +95,7 @@ and --config-dir::
 
     class ConfigOpts(object):
 
-        def __init__(self, ...):
+        def __call__(self, ...):
 
             opts = [
                 MultiStrOpt('config-file',
@@ -233,6 +233,22 @@ log files:
         ...
      ]
 
+This module also contains a global instance of the CommonConfigOpts class
+in order to support a common usage pattern in OpenStack:
+
+  from openstack.common import cfg
+
+  opts = [
+    cfg.StrOpt('bind_host' default='0.0.0.0'),
+    cfg.IntOpt('bind_port', default=9292),
+  ]
+
+  CONF = cfg.CONF
+  CONF.register_opts(opts)
+
+  def start(server, app):
+      server.start(app, CONF.bind_port, CONF.bind_host)
+
 """
 
 import collections
@@ -478,7 +494,8 @@ class Opt(object):
     multi = False
 
     def __init__(self, name, dest=None, short=None, default=None,
-                 metavar=None, help=None, secret=False, required=False):
+                 metavar=None, help=None, secret=False, required=False,
+                 deprecated_name=None):
         """Construct an Opt object.
 
         The only required parameter is the option's name. However, it is
@@ -492,6 +509,7 @@ class Opt(object):
         :param help: an explanation of how the option is used
         :param secret: true iff the value should be obfuscated in log output
         :param required: true iff a value must be supplied for this option
+        :param deprecated_name: deprecated name option.  Acts like an alias
         """
         self.name = name
         if dest is None:
@@ -504,6 +522,10 @@ class Opt(object):
         self.help = help
         self.secret = secret
         self.required = required
+        if deprecated_name is not None:
+            self.deprecated_name = deprecated_name.replace('-', '_')
+        else:
+            self.deprecated_name = None
 
     def _get_from_config_parser(self, cparser, section):
         """Retrieves the option value from a MultiConfigParser object.
@@ -515,7 +537,13 @@ class Opt(object):
         :param cparser: a ConfigParser object
         :param section: a section name
         """
-        return cparser.get(section, self.dest)
+        return self._cparser_get_with_deprecated(cparser, section)
+
+    def _cparser_get_with_deprecated(self, cparser, section):
+        """If cannot find option as dest try deprecated_name alias."""
+        if self.deprecated_name is not None:
+            return cparser.get(section, [self.dest, self.deprecated_name])
+        return cparser.get(section, [self.dest])
 
     def _add_to_cli(self, parser, group=None):
         """Makes the option available in the command line interface.
@@ -530,9 +558,11 @@ class Opt(object):
         container = self._get_optparse_container(parser, group)
         kwargs = self._get_optparse_kwargs(group)
         prefix = self._get_optparse_prefix('', group)
-        self._add_to_optparse(container, self.name, self.short, kwargs, prefix)
+        self._add_to_optparse(container, self.name, self.short, kwargs, prefix,
+                              self.deprecated_name)
 
-    def _add_to_optparse(self, container, name, short, kwargs, prefix=''):
+    def _add_to_optparse(self, container, name, short, kwargs, prefix='',
+                         deprecated_name=None):
         """Add an option to an optparse parser or group.
 
         :param container: an optparse.OptionContainer object
@@ -545,6 +575,8 @@ class Opt(object):
         args = ['--' + prefix + name]
         if short:
             args += ['-' + short]
+        if deprecated_name:
+            args += ['--' + prefix + deprecated_name]
         for a in args:
             if container.has_option(a):
                 raise DuplicateOptError(a)
@@ -577,7 +609,7 @@ class Opt(object):
             dest = group.name + '_' + dest
         kwargs.update({'dest': dest,
                        'metavar': self.metavar,
-                       'help': self.help})
+                       'help': self.help})
         return kwargs
 
     def _get_optparse_prefix(self, prefix, group):
@@ -627,7 +659,8 @@ class BoolOpt(Opt):
 
             return value
 
-        return [convert_bool(v) for v in cparser.get(section, self.dest)]
+        return [convert_bool(v) for v in
+                self._cparser_get_with_deprecated(cparser, section)]
 
     def _add_to_cli(self, parser, group=None):
         """Extends the base class method to add the --nooptname option."""
@@ -640,7 +673,8 @@ class BoolOpt(Opt):
         kwargs = self._get_optparse_kwargs(group, action='store_false')
         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,
+                              self.deprecated_name)
 
     def _get_optparse_kwargs(self, group, action='store_true', **kwargs):
         """Extends the base optparse keyword dict for boolean options."""
@@ -654,7 +688,8 @@ class IntOpt(Opt):
 
     def _get_from_config_parser(self, cparser, section):
         """Retrieve the opt value as a integer from ConfigParser."""
-        return [int(v) for v in cparser.get(section, self.dest)]
+        return [int(v) for v in self._cparser_get_with_deprecated(cparser,
+                section)]
 
     def _get_optparse_kwargs(self, group, **kwargs):
         """Extends the base optparse keyword dict for integer options."""
@@ -668,7 +703,8 @@ class FloatOpt(Opt):
 
     def _get_from_config_parser(self, cparser, section):
         """Retrieve the opt value as a float from ConfigParser."""
-        return [float(v) for v in cparser.get(section, self.dest)]
+        return [float(v) for v in
+                self._cparser_get_with_deprecated(cparser, section)]
 
     def _get_optparse_kwargs(self, group, **kwargs):
         """Extends the base optparse keyword dict for float options."""
@@ -685,7 +721,8 @@ class ListOpt(Opt):
 
     def _get_from_config_parser(self, cparser, section):
         """Retrieve the opt value as a list from ConfigParser."""
-        return [v.split(',') for v in cparser.get(section, self.dest)]
+        return [v.split(',') for v in
+                self._cparser_get_with_deprecated(cparser, section)]
 
     def _get_optparse_kwargs(self, group, **kwargs):
         """Extends the base optparse keyword dict for list options."""
@@ -714,6 +751,13 @@ class MultiStrOpt(Opt):
         return super(MultiStrOpt,
                      self)._get_optparse_kwargs(group, action='append')
 
+    def _cparser_get_with_deprecated(self, cparser, section):
+        """If cannot find option as dest try deprecated_name alias."""
+        if self.deprecated_name is not None:
+            return cparser.get(section, [self.dest, self.deprecated_name],
+                               multi=True)
+        return cparser.get(section, [self.dest], multi=True)
+
 
 class OptGroup(object):
 
@@ -766,6 +810,14 @@ class OptGroup(object):
 
         return True
 
+    def _unregister_opt(self, opt):
+        """Remove an opt from this group.
+
+        :param opt: an Opt object
+        """
+        if opt.dest in self._opts:
+            del self._opts[opt.dest]
+
     def _get_optparse_group(self, parser):
         """Build an optparse.OptionGroup for this group."""
         if self._optparse_group is None:
@@ -773,6 +825,10 @@ class OptGroup(object):
                                                         self.help)
         return self._optparse_group
 
+    def _clear(self):
+        """Clear this group's option parsing state."""
+        self._optparse_group = None
+
 
 class ParseError(iniparser.ParseError):
     def __init__(self, msg, lineno, line, filename):
@@ -816,25 +872,38 @@ class ConfigParser(iniparser.BaseParser):
 
 class MultiConfigParser(object):
     def __init__(self):
-        self.sections = {}
+        self.parsed = []
 
     def read(self, config_files):
         read_ok = []
 
         for filename in config_files:
-            parser = ConfigParser(filename, self.sections)
+            sections = {}
+            parser = ConfigParser(filename, sections)
 
             try:
                 parser.parse()
             except IOError:
                 continue
-
+            self.parsed.insert(0, sections)
             read_ok.append(filename)
 
         return read_ok
 
-    def get(self, section, name):
-        return self.sections[section][name]
+    def get(self, section, names, multi=False):
+        rvalue = []
+        for sections in self.parsed:
+            if section not in sections:
+                continue
+            for name in names:
+                if name in sections[section]:
+                    if multi:
+                        rvalue = sections[section][name] + rvalue
+                    else:
+                        return sections[section][name]
+        if multi and rvalue != []:
+            return rvalue
+        raise KeyError
 
 
 class ConfigOpts(collections.Mapping):
@@ -847,57 +916,41 @@ class ConfigOpts(collections.Mapping):
     the values of options.
     """
 
-    def __init__(self,
-                 project=None,
-                 prog=None,
-                 version=None,
-                 usage=None,
-                 default_config_files=None):
-        """Construct a ConfigOpts object.
+    def __init__(self):
+        """Construct a ConfigOpts object."""
+        self._opts = {}  # dict of dicts of (opt:, override:, default:)
+        self._groups = {}
 
-        Automatically registers the --config-file option with either a supplied
-        list of default config files, or a list from find_config_files().
+        self._args = None
+        self._oparser = None
+        self._cparser = None
+        self._cli_values = {}
+        self.__cache = {}
+        self._config_opts = []
+        self._disable_interspersed_args = False
 
-        :param project: the toplevel project name, used to locate config files
-        :param prog: the name of the program (defaults to sys.argv[0] basename)
-        :param version: the program version (for --version)
-        :param usage: a usage string (%prog will be expanded)
-        :param default_config_files: config files to use by default
-        """
+    def _setup(self, project, prog, version, usage, default_config_files):
+        """Initialize a ConfigOpts object for option parsing."""
         if prog is None:
             prog = os.path.basename(sys.argv[0])
 
         if default_config_files is None:
             default_config_files = find_config_files(project, prog)
 
-        self.project = project
-        self.prog = prog
-        self.version = version
-        self.usage = usage
-        self.default_config_files = default_config_files
-
-        self._opts = {}  # dict of dicts of (opt:, override:, default:)
-        self._groups = {}
-
-        self._args = None
-        self._cli_values = {}
-
-        self._oparser = optparse.OptionParser(prog=self.prog,
-                                              version=self.version,
-                                              usage=self.usage)
-        self._cparser = None
+        self._oparser = optparse.OptionParser(prog=prog,
+                                              version=version,
+                                              usage=usage)
+        if self._disable_interspersed_args:
+            self._oparser.disable_interspersed_args()
 
-        self.__cache = {}
-
-        opts = [
+        self._config_opts = [
             MultiStrOpt('config-file',
-                        default=self.default_config_files,
+                        default=default_config_files,
                         metavar='PATH',
                         help='Path to a config file to use. Multiple config '
                              'files can be specified, with values in later '
                              'files taking precedence. The default files '
-                             ' used are: %s' %
-                             (self.default_config_files)),
+                             ' used are: %s' % (default_config_files, )),
             StrOpt('config-dir',
                    metavar='DIR',
                    help='Path to a config directory to pull *.conf '
@@ -908,7 +961,13 @@ class ConfigOpts(collections.Mapping):
                         'hence over-ridden options in the directory take '
                         'precedence.'),
         ]
-        self.register_cli_opts(opts)
+        self.register_cli_opts(self._config_opts)
+
+        self.project = project
+        self.prog = prog
+        self.version = version
+        self.usage = usage
+        self.default_config_files = default_config_files
 
     def __clear_cache(f):
         @functools.wraps(f)
@@ -919,7 +978,13 @@ class ConfigOpts(collections.Mapping):
 
         return __inner
 
-    def __call__(self, args=None):
+    def __call__(self,
+                 args=None,
+                 project=None,
+                 prog=None,
+                 version=None,
+                 usage=None,
+                 default_config_files=None):
         """Parse command line arguments and config files.
 
         Calling a ConfigOpts object causes the supplied command line arguments
@@ -929,35 +994,34 @@ class ConfigOpts(collections.Mapping):
         The object may be called multiple times, each time causing the previous
         set of values to be overwritten.
 
+        Automatically registers the --config-file option with either a supplied
+        list of default config files, or a list from find_config_files().
+
         If the --config-dir option is set, any *.conf files from this
         directory are pulled in, after all the file(s) specified by the
         --config-file option.
 
-        :params args: command line arguments (defaults to sys.argv[1:])
+        :param args: command line arguments (defaults to sys.argv[1:])
+        :param project: the toplevel project name, used to locate config files
+        :param prog: the name of the program (defaults to sys.argv[0] basename)
+        :param version: the program version (for --version)
+        :param usage: a usage string (%prog will be expanded)
+        :param default_config_files: config files to use by default
         :returns: the list of arguments left over after parsing options
         :raises: SystemExit, ConfigFilesNotFoundError, ConfigFileParseError,
-                 RequiredOptError
+                 RequiredOptError, DuplicateOptError
         """
         self.clear()
 
-        self._args = args
-
-        (values, args) = self._oparser.parse_args(self._args)
-
-        self._cli_values = vars(values)
-
-        def _list_config_dir():
-            return sorted(glob.glob(os.path.join(self.config_dir, '*.conf')))
-
-        from_file = list(self.config_file)
+        self._setup(project, prog, version, usage, default_config_files)
 
-        from_dir = _list_config_dir() if self.config_dir else []
+        self._cli_values, leftovers = self._parse_cli_opts(args)
 
-        self._parse_config_files(from_file + from_dir)
+        self._parse_config_files()
 
         self._check_required_opts()
 
-        return args
+        return leftovers
 
     def __getattr__(self, name):
         """Look up an option value and perform string substitution.
@@ -994,8 +1058,12 @@ class ConfigOpts(collections.Mapping):
     def clear(self):
         """Clear the state of the object to before it was called."""
         self._args = None
-        self._cli_values = {}
+        self._cli_values.clear()
+        self._oparser = None
         self._cparser = None
+        self.unregister_opts(self._config_opts)
+        for group in self._groups.values():
+            group._clear()
 
     @__clear_cache
     def register_opt(self, opt, group=None):
@@ -1042,15 +1110,7 @@ class ConfigOpts(collections.Mapping):
         if self._args is not None:
             raise ArgsAlreadyParsedError("cannot register CLI option")
 
-        if not self.register_opt(opt, group, clear_cache=False):
-            return False
-
-        if group is not None:
-            group = self._get_group(group, autocreate=True)
-
-        opt._add_to_cli(self._oparser, group)
-
-        return True
+        return self.register_opt(opt, group, clear_cache=False)
 
     @__clear_cache
     def register_cli_opts(self, opts, group=None):
@@ -1071,6 +1131,28 @@ class ConfigOpts(collections.Mapping):
 
         self._groups[group.name] = copy.copy(group)
 
+    @__clear_cache
+    def unregister_opt(self, opt, group=None):
+        """Unregister an option.
+
+        :param opt: an Opt object
+        :param group: an optional OptGroup object or group name
+        :raises: ArgsAlreadyParsedError, NoSuchGroupError
+        """
+        if self._args is not None:
+            raise ArgsAlreadyParsedError("reset before unregistering options")
+
+        if group is not None:
+            self._get_group(group)._unregister_opt(opt)
+        elif opt.dest in self._opts:
+            del self._opts[opt.dest]
+
+    @__clear_cache
+    def unregister_opts(self, opts, group=None):
+        """Unregister multiple CLI option schemas at once."""
+        for opt in opts:
+            self.unregister_opt(opt, group, clear_cache=False)
+
     @__clear_cache
     def set_override(self, name, override, group=None):
         """Override an opt value.
@@ -1101,16 +1183,24 @@ class ConfigOpts(collections.Mapping):
         opt_info = self._get_opt_info(name, group)
         opt_info['default'] = default
 
+    def _all_opt_infos(self):
+        """A generator function for iteration opt infos."""
+        for info in self._opts.values():
+            yield info, None
+        for group in self._groups.values():
+            for info in group._opts.values():
+                yield info, group
+
+    def _all_opts(self):
+        """A generator function for iteration opts."""
+        for info, group in self._all_opt_infos():
+            yield info['opt'], group
+
     def _unset_defaults_and_overrides(self):
         """Unset any default or override on all options."""
-        def unset(opts):
-            for info in opts.values():
-                info['default'] = None
-                info['override'] = None
-
-        unset(self._opts)
-        for group in self._groups.values():
-            unset(group._opts)
+        for info, group in self._all_opt_infos():
+            info['default'] = None
+            info['override'] = None
 
     def disable_interspersed_args(self):
         """Set parsing to stop on the first non-option.
@@ -1129,13 +1219,13 @@ class ConfigOpts(collections.Mapping):
 
         i.e. argument parsing is stopped at the first non-option argument.
         """
-        self._oparser.disable_interspersed_args()
+        self._disable_interspersed_args = True
 
     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()
+        self._disable_interspersed_args = False
 
     def find_file(self, name):
         """Locate a file located alongside the config files.
@@ -1272,7 +1362,7 @@ class ConfigOpts(collections.Mapping):
     def _substitute(self, value):
         """Perform string template substitution.
 
-        Substititue any template variables (e.g. $foo, ${bar}) in the supplied
+        Substitute any template variables (e.g. $foo, ${bar}) in the supplied
         string value(s) with opt values.
 
         :param value: the string value, or list of string values
@@ -1329,11 +1419,17 @@ class ConfigOpts(collections.Mapping):
 
         return opts[opt_name]
 
-    def _parse_config_files(self, config_files):
-        """Parse the supplied configuration files.
+    def _parse_config_files(self):
+        """Parse the config files from --config-file and --config-dir.
 
         :raises: ConfigFilesNotFoundError, ConfigFileParseError
         """
+        config_files = list(self.config_file)
+
+        if self.config_dir:
+            config_dir_glob = os.path.join(self.config_dir, '*.conf')
+            config_files += sorted(glob.glob(config_dir_glob))
+
         self._cparser = MultiConfigParser()
 
         try:
@@ -1345,8 +1441,12 @@ class ConfigOpts(collections.Mapping):
             not_read_ok = filter(lambda f: f not in read_ok, config_files)
             raise ConfigFilesNotFoundError(not_read_ok)
 
-    def _do_check_required_opts(self, opts, group=None):
-        for info in opts.values():
+    def _check_required_opts(self):
+        """Check that all opts marked as required have values specified.
+
+        :raises: RequiredOptError
+        """
+        for info, group in self._all_opt_infos():
             default, opt, override = [info[k] for k in sorted(info.keys())]
 
             if opt.required:
@@ -1356,15 +1456,25 @@ class ConfigOpts(collections.Mapping):
                 if self._get(opt.name, group) is None:
                     raise RequiredOptError(opt.name, group)
 
-    def _check_required_opts(self):
-        """Check that all opts marked as required have values specified.
+    def _parse_cli_opts(self, args):
+        """Parse command line options.
+
+        Initializes the command line option parser and parses the supplied
+        command line arguments.
+
+        :param args: the command line arguments
+        :returns: a dict of parsed option values
+        :raises: SystemExit, DuplicateOptError
 
-        :raises: RequiredOptError
         """
-        self._do_check_required_opts(self._opts)
+        self._args = args
 
-        for group in self._groups.values():
-            self._do_check_required_opts(group._opts, group)
+        for opt, group in self._all_opts():
+            opt._add_to_cli(self._oparser, group)
+
+        values, leftovers = self._oparser.parse_args(args)
+
+        return vars(values), leftovers
 
     class GroupAttr(collections.Mapping):
 
@@ -1480,7 +1590,10 @@ class CommonConfigOpts(ConfigOpts):
                help='syslog facility to receive log lines')
     ]
 
-    def __init__(self, **kwargs):
-        super(CommonConfigOpts, self).__init__(**kwargs)
+    def __init__(self):
+        super(CommonConfigOpts, self).__init__()
         self.register_cli_opts(self.common_cli_opts)
         self.register_cli_opts(self.logging_cli_opts)
+
+
+CONF = CommonConfigOpts()
index 7c6302ae6264bcfe33d0729285cac8a8506e28d8..0e5eb0d3dbf7b727f1f9b55945c4d110fc7d3b5c 100644 (file)
@@ -18,7 +18,7 @@
 
 import logging as LOG
 
-from quantum.common.config import find_config_file
+from quantum.common.utils import find_config_file
 from quantum.plugins.cisco.common import cisco_configparser as confp
 from quantum.plugins.cisco.common import cisco_constants as const
 from quantum.plugins.cisco.common import cisco_exceptions as cexc
@@ -28,7 +28,7 @@ from quantum.plugins.cisco.db import l2network_db as cdb
 LOG.basicConfig(level=LOG.WARN)
 LOG.getLogger(const.LOGGER_COMPONENT_NAME)
 
-CREDENTIALS_FILE = find_config_file({'plugin': 'cisco'}, None,
+CREDENTIALS_FILE = find_config_file({'plugin': 'cisco'},
                                     "credentials.ini")
 TENANT = const.NETWORK_ADMIN
 
index 59196156c1c8b34c0aa34553cb2d08a246498e03..fdd4191bc58a1a77478d028be77c0354feb36326 100644 (file)
 # @author: Sumit Naiksatam, Cisco Systems, Inc.
 # @author: Rohit Agarwalla, Cisco Systems, Inc.
 
-from quantum.common.config import find_config_file
+from quantum.common.utils import find_config_file
 from quantum.plugins.cisco.common import cisco_configparser as confp
 
 
-CONF_FILE = find_config_file({'plugin': 'cisco'}, None, "l2network_plugin.ini")
+CONF_FILE = find_config_file({'plugin': 'cisco'}, "l2network_plugin.ini")
 CONF_PARSER_OBJ = confp.CiscoConfigParser(CONF_FILE)
 
 
@@ -43,7 +43,7 @@ MAX_NETWORKS = SECTION_CONF['max_networks']
 SECTION_CONF = CONF_PARSER_OBJ['MODEL']
 MODEL_CLASS = SECTION_CONF['model_class']
 
-CONF_FILE = find_config_file({'plugin': 'cisco'}, None, "cisco_plugins.ini")
+CONF_FILE = find_config_file({'plugin': 'cisco'}, "cisco_plugins.ini")
 
 SECTION_CONF = CONF_PARSER_OBJ['SEGMENTATION']
 MANAGER_CLASS = SECTION_CONF['manager_class']
@@ -55,7 +55,7 @@ CONF_PARSER_OBJ = confp.CiscoConfigParser(CONF_FILE)
 # Read the config for the device plugins
 PLUGINS = CONF_PARSER_OBJ.walk(CONF_PARSER_OBJ.dummy)
 
-CONF_FILE = find_config_file({'plugin': 'cisco'}, None, "db_conn.ini")
+CONF_FILE = find_config_file({'plugin': 'cisco'}, "db_conn.ini")
 
 CONF_PARSER_OBJ = confp.CiscoConfigParser(CONF_FILE)
 
index 449924ed2fa4878be45c5b6bf64b6025ec8a8c21..790a351ab08745d337dc403b70ab76fc5f969c80 100644 (file)
@@ -23,11 +23,11 @@ This module will export the configuration parameters
 from the nexus.ini file
 """
 
-from quantum.common.config import find_config_file
+from quantum.common.utils import find_config_file
 from quantum.plugins.cisco.common import cisco_configparser as confp
 
 
-CP = confp.CiscoConfigParser(find_config_file({'plugin': 'cisco'}, None,
+CP = confp.CiscoConfigParser(find_config_file({'plugin': 'cisco'},
                              "nexus.ini"))
 
 SECTION = CP['SWITCH']
index f0d92496f70287e08785925bdb0942067400c8ce..94c2c7788ad5e00b13aa7f92007be8810a6d102c 100644 (file)
@@ -52,7 +52,7 @@ from quantum import wsgi
 LOG = logging.getLogger('quantum.plugins.cisco.tests.test_cisco_extensions')
 
 
-TEST_CONF_FILE = config.find_config_file({'plugin': 'cisco'}, None,
+TEST_CONF_FILE = config.find_config_file({'plugin': 'cisco'},
                                          'quantum.conf.ciscoext')
 EXTENSIONS_PATH = os.path.join(os.path.dirname(__file__), os.pardir, os.pardir,
                                os.pardir, os.pardir, "extensions")
@@ -1256,8 +1256,8 @@ def setup_extensions_middleware(extension_manager=None):
                          PluginAwareExtensionManager(EXTENSIONS_PATH,
                                                      L2Network()))
     options = {'config_file': TEST_CONF_FILE}
-    conf, app = config.load_paste_app('extensions_test_app', options, None)
-    return ExtensionMiddleware(app, conf, ext_mgr=extension_manager)
+    app = config.load_paste_app('extensions_test_app', options, None)
+    return ExtensionMiddleware(app, ext_mgr=extension_manager)
 
 
 def setup_extensions_test_app(extension_manager=None):
index b065ddfc2a2962d0c410dbfbbbb44dbbba562caf..ff512c7741b4e432688277ab08077cb7ef79deff 100644 (file)
 # @author: Sumit Naiksatam, Cisco Systems, Inc.
 #
 
-from quantum.common.config import find_config_file
+from quantum.common.utils import find_config_file
 from quantum.plugins.cisco.common import cisco_configparser as confp
 
 
-CP = confp.CiscoConfigParser(find_config_file({'plugin': 'cisco'}, [],
+CP = confp.CiscoConfigParser(find_config_file({'plugin': 'cisco'},
                                               'ucs.ini'))
 
 SECTION = CP['UCSM']
@@ -34,7 +34,7 @@ PROFILE_NAME_PREFIX = SECTION['profile_name_prefix']
 SECTION = CP['DRIVER']
 UCSM_DRIVER = SECTION['name']
 
-CP = confp.CiscoConfigParser(find_config_file({'plugin': 'cisco'}, [],
+CP = confp.CiscoConfigParser(find_config_file({'plugin': 'cisco'},
                                               'ucs_inventory.ini'))
 
 INVENTORY = CP.walk(CP.dummy)
index e8474f6728017fd3c843c88d180035b137b9f1d5..81662335218bb22b963e1a2bbe5850405beabe18 100644 (file)
 # @author: Sumit Naiksatam, Cisco Systems, Inc.
 #
 
-from quantum.common.config import find_config_file
+from quantum.common.utils import find_config_file
 from quantum.plugins.cisco.common import cisco_configparser as confp
 
 
-CONF_FILE = find_config_file({'plugin': 'cisco'}, None, "ucs_inventory.ini")
+CONF_FILE = find_config_file({'plugin': 'cisco'}, "ucs_inventory.ini")
 CP = confp.CiscoConfigParser(CONF_FILE)
 
 INVENTORY = CP.walk(CP.dummy)
index c4f51f7bc00caf35953a59fc5d1c9dbdeaeafbcc..85cc907bc1d05c765d0ac375658b6597e3faad7b 100644 (file)
@@ -41,8 +41,8 @@ agent_opts = [
 
 
 def parse(config_file):
-    conf = cfg.ConfigOpts(default_config_files=[config_file])
-    conf(args=[])
+    conf = cfg.ConfigOpts()
+    conf(args=[], default_config_files=[config_file])
     conf.register_opts(vlan_opts, "VLANS")
     conf.register_opts(database_opts, "DATABASE")
     conf.register_opts(bridge_opts, "LINUX_BRIDGE")
index effb268febed1b5f640981a3818c057dc63cb632..8160142a738b3c1801041d127b2de9b3dcdc1c20 100644 (file)
@@ -21,14 +21,14 @@ from sqlalchemy import func
 from sqlalchemy.orm import exc
 
 from quantum.common import exceptions as q_exc
-from quantum.common.config import find_config_file
+from quantum.common.utils import find_config_file
 import quantum.db.api as db
 from quantum.plugins.linuxbridge.common import exceptions as c_exc
 from quantum.plugins.linuxbridge.db import l2network_models
 from quantum.plugins.linuxbridge.common import config
 
 LOG = logging.getLogger(__name__)
-CONF_FILE = find_config_file({'plugin': 'linuxbridge'}, None,
+CONF_FILE = find_config_file({'plugin': 'linuxbridge'},
                              "linuxbridge_conf.ini")
 CONF = config.parse(CONF_FILE)
 
index 16ff7d9cf627069b774e3a4bd2a9c0b260f33901..c0f7680f639195a187e25d29afd3f3e07ced97f9 100644 (file)
@@ -38,8 +38,8 @@ agent_opts = [
 
 
 def parse(config_file):
-    conf = cfg.ConfigOpts(default_config_files=[config_file])
-    conf(args=[])
+    conf = cfg.ConfigOpts()
+    conf(args=[], default_config_files=[config_file])
     conf.register_opts(database_opts, "DATABASE")
     conf.register_opts(ovs_opts, "OVS")
     conf.register_opts(agent_opts, "AGENT")
index 059451af4ee629c5db764a541134721c554a5791..572a0c8fcdd4c292976f052d4dcc966c611fe389 100644 (file)
@@ -23,7 +23,7 @@ import os
 
 from quantum.api.api_common import OperationalStatus
 from quantum.common import exceptions as q_exc
-from quantum.common.config import find_config_file
+from quantum.common.utils import find_config_file
 import quantum.db.api as db
 from quantum.plugins.openvswitch import ovs_db
 from quantum.plugins.openvswitch.common import config
@@ -33,7 +33,7 @@ LOG = logging.getLogger("ovs_quantum_plugin")
 
 
 CONF_FILE = find_config_file({"plugin": "openvswitch"},
-                             None, "ovs_quantum_plugin.ini")
+                             "ovs_quantum_plugin.ini")
 
 
 # Exception thrown if no more VLANs are available
index 3fa8b507c7d5e88bc78c67319b81ec366e14ca4a..74513e18947d52d44fc70d0ea0387f7ee1759669 100755 (executable)
@@ -20,7 +20,6 @@
 #    under the License.
 # @author: Isaku Yamahata
 
-import ConfigParser
 import logging as LOG
 from optparse import OptionParser
 import shlex
@@ -34,6 +33,7 @@ from ryu.app.client import OFPClient
 from sqlalchemy.ext.sqlsoup import SqlSoup
 
 from quantum.agent.linux import utils
+from quantum.plugins.ryu.common import config
 
 OP_STATUS_UP = "UP"
 OP_STATUS_DOWN = "DOWN"
@@ -286,18 +286,10 @@ def main():
         sys.exit(1)
 
     config_file = args[0]
-    config = ConfigParser.ConfigParser()
-    try:
-        config.read(config_file)
-    except Exception, e:
-        LOG.error("Unable to parse config file \"%s\": %s",
-                  config_file, str(e))
-
-    integ_br = config.get("OVS", "integration-bridge")
-
-    root_helper = config.get("AGENT", "root_helper")
-
-    options = {"sql_connection": config.get("DATABASE", "sql_connection")}
+    conf = config.parse(config_file)
+    integ_br = conf.OVS.integration_bridge
+    root_helper = conf.AGENT.root_helper
+    options = {"sql_connection": conf.DATABASE.sql_connection}
     db = SqlSoup(options["sql_connection"])
 
     LOG.info("Connecting to database \"%s\" on %s",
diff --git a/quantum/plugins/ryu/common/__init__.py b/quantum/plugins/ryu/common/__init__.py
new file mode 100644 (file)
index 0000000..e5f41ad
--- /dev/null
@@ -0,0 +1,15 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2012 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.
diff --git a/quantum/plugins/ryu/common/config.py b/quantum/plugins/ryu/common/config.py
new file mode 100644 (file)
index 0000000..871ef54
--- /dev/null
@@ -0,0 +1,43 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2012 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.
+
+from quantum.openstack.common import cfg
+
+
+database_opts = [
+    cfg.StrOpt('sql_connection', default='sqlite://'),
+    cfg.IntOpt('reconnect_interval', default=2),
+]
+
+ovs_opts = [
+    cfg.StrOpt('integration_bridge', default='br-int'),
+    cfg.StrOpt('openflow_controller', default='127.0.0.1:6633'),
+    cfg.StrOpt('openflow_rest_api', default='127.0.0.1:8080'),
+]
+
+agent_opts = [
+    cfg.IntOpt('polling_interval', default=2),
+    cfg.StrOpt('root_helper', default='sudo'),
+]
+
+
+def parse(config_file):
+    conf = cfg.ConfigOpts()
+    conf(args=[], default_config_files=[config_file])
+    conf.register_opts(database_opts, "DATABASE")
+    conf.register_opts(ovs_opts, "OVS")
+    conf.register_opts(agent_opts, "AGENT")
+    return conf
index 91841928fabcf545a7d0e44f1643522414ecf038..fd9a5dfde0988a6362705f89ed5ac908f70306ca 100644 (file)
 #    under the License.
 # @author: Isaku Yamahata
 
-import ConfigParser
 from abc import ABCMeta, abstractmethod
 import logging as LOG
 import os
 
 from quantum.api.api_common import OperationalStatus
 from quantum.common import exceptions as q_exc
+from quantum.plugins.ryu.common import config
 import quantum.db.api as db
-from quantum.manager import find_config
 from quantum.quantum_plugin_base import QuantumPluginBase
 
 
@@ -55,24 +54,23 @@ class OVSQuantumPluginBase(QuantumPluginBase):
     """
     def __init__(self, conf_file, mod_file, configfile=None):
         super(OVSQuantumPluginBase, self).__init__()
-        config = ConfigParser.ConfigParser()
         if configfile is None:
-            if conf_file and os.path.exists(conf_file):
+            if os.path.exists(conf_file):
                 configfile = conf_file
             else:
-                configfile = (
-                    find_config(os.path.abspath(os.path.dirname(mod_file))))
+                configfile = find_config(os.path.abspath(
+                    os.path.dirname(__file__)))
         if configfile is None:
             raise Exception("Configuration file \"%s\" doesn't exist" %
                             (configfile))
-        LOG.debug("Using configuration file: %s", configfile)
-        config.read(configfile)
-        LOG.debug("Config: %s", config)
-
-        options = {"sql_connection": config.get("DATABASE", "sql_connection")}
+        LOG.debug("Using configuration file: %s" % configfile)
+        conf = config.parse(configfile)
+        options = {"sql_connection": conf.DATABASE.sql_connection}
+        reconnect_interval = conf.DATABASE.reconnect_interval
+        options.update({"reconnect_interval": reconnect_interval})
         db.configure_db(options)
 
-        self.config = config
+        self.conf = conf
         # Subclass must set self.driver to its own OVSQuantumPluginDriverBase
         self.driver = None
 
index a08fb591ee21338018316ba118f48d9ff5088931..c6af60f3b46ed43b0e15cf6dce568a5463cfbce4 100644 (file)
@@ -19,7 +19,7 @@
 from ryu.app import client
 from ryu.app import rest_nw_id
 
-from quantum.common.config import find_config_file
+from quantum.common.utils import find_config_file
 from quantum.common import exceptions as q_exc
 import quantum.db.api as db
 from quantum.plugins.ryu import ofp_service_type
@@ -27,14 +27,14 @@ from quantum.plugins.ryu import ovs_quantum_plugin_base
 from quantum.plugins.ryu.db import api as db_api
 
 
-CONF_FILE = find_config_file({"plugin": "ryu"}, None, "ryu.ini")
+CONF_FILE = find_config_file({"plugin": "ryu"}, "ryu.ini")
 
 
 class OFPRyuDriver(ovs_quantum_plugin_base.OVSQuantumPluginDriverBase):
-    def __init__(self, config):
+    def __init__(self, conf):
         super(OFPRyuDriver, self).__init__()
-        ofp_con_host = config.get("OVS", "openflow-controller")
-        ofp_api_host = config.get("OVS", "openflow-rest-api")
+        ofp_con_host = conf.OVS.openflow_controller
+        ofp_api_host = conf.OVS.openflow_rest_api
 
         if ofp_con_host is None or ofp_api_host is None:
             raise q_exc.Invalid("invalid configuration. check ryu.ini")
@@ -64,4 +64,4 @@ class OFPRyuDriver(ovs_quantum_plugin_base.OVSQuantumPluginDriverBase):
 class RyuQuantumPlugin(ovs_quantum_plugin_base.OVSQuantumPluginBase):
     def __init__(self, configfile=None):
         super(RyuQuantumPlugin, self).__init__(CONF_FILE, __file__, configfile)
-        self.driver = OFPRyuDriver(self.config)
+        self.driver = OFPRyuDriver(self.conf)
index 55c4853ed20b21249a603f5b8e54215fc5f61cae..3d521b4f77d5fe1f28662b8955b01f6a09ca90cd 100644 (file)
@@ -21,6 +21,8 @@ from quantum.plugins.ryu import ovs_quantum_plugin_base
 class FakePluginDriver(ovs_quantum_plugin_base.OVSQuantumPluginDriverBase):
     def __init__(self, config):
         super(FakePluginDriver, self).__init__()
+        conf = config.parse(config)
+        self.conf = conf
 
     def create_network(self, net):
         pass
@@ -32,4 +34,4 @@ class FakePluginDriver(ovs_quantum_plugin_base.OVSQuantumPluginDriverBase):
 class FakePlugin(ovs_quantum_plugin_base.OVSQuantumPluginBase):
     def __init__(self, configfile=None):
         super(FakePlugin, self).__init__(None, __file__, configfile)
-        self.driver = FakePluginDriver(self.config)
+        self.driver = FakePluginDriver(self.conf)
index ad113e74be1f8cea4baae885eaad0d5db3d8f2ba..c3a10a308cf11ba14024a52dc7fccdb784a51731 100644 (file)
 import uuid
 
 import quantum.db.api as db
+from quantum.common.utils import find_config_file
+from quantum.plugins.ryu.common import config
 from quantum.plugins.ryu.tests.unit.basetest import BaseRyuTest
 from quantum.plugins.ryu.tests.unit import utils
 from quantum.plugins.ryu.tests.unit.utils import patch_fake_ryu_client
 
 
+CONF_FILE = find_config_file({"plugin": "ryu"}, "ryu.ini")
+
+
 class RyuDriverTest(BaseRyuTest):
     """Class conisting of OFPRyuDriver unit tests"""
     def setUp(self):
         super(RyuDriverTest, self).setUp()
-
+        self.conf = config.parse(CONF_FILE)
         # fake up ryu.app.client and ryu.app.rest_nw_id
         # With those, plugin can be tested without ryu installed
         self.module_patcher = patch_fake_ryu_client()
@@ -65,7 +70,7 @@ class RyuDriverTest(BaseRyuTest):
         db.network_create('test', uuid0)
 
         from quantum.plugins.ryu import ryu_quantum_plugin
-        ryu_driver = ryu_quantum_plugin.OFPRyuDriver(self.config)
+        ryu_driver = ryu_quantum_plugin.OFPRyuDriver(self.conf)
         ryu_driver.create_network(net1)
         ryu_driver.delete_network(net1)
         self.mox.VerifyAll()
index cc656456f0e8be047b34c500560327b10038d53d..702d1cc51219d3353af24c45ecc9cd634c6a8ed3 100644 (file)
@@ -21,7 +21,7 @@ Policy engine for quantum.  Largely copied from nova.
 
 import os.path
 
-from quantum.common import config
+from quantum.common.utils import find_config_file
 from quantum.common import exceptions
 from quantum.openstack.common import policy
 
@@ -38,7 +38,7 @@ def reset():
 def init():
     global _POLICY_PATH
     if not _POLICY_PATH:
-        _POLICY_PATH = config.find_config_file({}, [], 'policy.json')
+        _POLICY_PATH = find_config_file({}, 'policy.json')
         if not _POLICY_PATH:
             raise exceptions.PolicyNotFound(path=FLAGS.policy_file)
     with open(_POLICY_PATH) as f:
index c8820c1a998d502a94b8ebf58a34e2ec54a182c4..2388944e399ba9376833ae42fe1c0d5a9ceba00d 100755 (executable)
@@ -25,28 +25,19 @@ import sys
 
 from quantum import service
 from quantum.common import config
+from quantum.openstack.common import cfg
 from quantum.version import version_string
 
 
-def create_options(parser):
-    """
-    Sets up the CLI and config-file options that may be
-    parsed and program commands.
-    :param parser: The option parser
-    """
-    config.add_common_options(parser)
-    config.add_log_options(parser)
-
-
 def main():
-    oparser = optparse.OptionParser(version='%prog ' + version_string())
-    create_options(oparser)
-    (options, args) = config.parse_options(oparser)
-
+    # the configuration will be read into the cfg.CONF global data structure
+    config.parse(sys.argv)
+    if not cfg.CONF.config_file:
+        sys.exit("ERROR: Unable to find configuration file via the default"
+                 " search paths (~/.quantum/, ~/, /etc/quantum/, /etc/) and"
+                 " the '--config-file' option!")
     try:
-        quantum_service = service.serve_wsgi(service.QuantumApiService,
-                                             options=options,
-                                             args=args)
+        quantum_service = service.serve_wsgi(service.QuantumApiService)
         quantum_service.wait()
     except RuntimeError, e:
         sys.exit("ERROR: %s" % e)
index ea2855c6c7214fbf8fa0c5af6cbc1fd8423cfa5b..d6432ac15fafd21d7d06348378a9074f015f40c6 100644 (file)
@@ -18,7 +18,7 @@
 import logging
 
 from quantum.common import config
-from quantum.common import exceptions as exception
+from quantum.openstack.common import cfg
 from quantum import wsgi
 
 
@@ -34,14 +34,12 @@ class WsgiService(object):
 
     """
 
-    def __init__(self, app_name, conf_file, conf):
+    def __init__(self, app_name):
         self.app_name = app_name
-        self.conf_file = conf_file
-        self.conf = conf
         self.wsgi_app = None
 
     def start(self):
-        self.wsgi_app = _run_wsgi(self.app_name, self.conf, self.conf_file)
+        self.wsgi_app = _run_wsgi(self.app_name)
 
     def wait(self):
         self.wsgi_app.wait()
@@ -51,13 +49,8 @@ class QuantumApiService(WsgiService):
     """Class for quantum-api service."""
 
     @classmethod
-    def create(cls, conf=None, options=None, args=None):
+    def create(cls):
         app_name = "quantum"
-        if not conf:
-            conf_file, conf = config.load_paste_config(app_name, options, args)
-            if not conf:
-                message = (_('No paste configuration found for: %s'), app_name)
-                raise exception.Error(message)
 
         # Setup logging early, supplying both the CLI options and the
         # configuration mapping from the config file
@@ -65,32 +58,24 @@ class QuantumApiService(WsgiService):
         # flags. Everything else must be set up in the conf file...
         # Log the options used when starting if we're in debug mode...
 
-        config.setup_logging(options, conf)
-        debug = (options.get('debug') or
-                 config.get_option(conf, 'debug', type='bool', default=False))
-        verbose = (options.get('verbose') or
-                   config.get_option(conf, 'verbose', type='bool',
-                                     default=False))
-        conf['debug'] = debug
-        conf['verbose'] = verbose
+        config.setup_logging(cfg.CONF)
         LOG.debug("*" * 80)
         LOG.debug("Configuration options gathered from config file:")
-        LOG.debug(conf_file)
         LOG.debug("================================================")
-        items = dict([(k, v) for k, v in conf.items()
+        items = dict([(k, v) for k, v in cfg.CONF.items()
                       if k not in ('__file__', 'here')])
         for key, value in sorted(items.items()):
             LOG.debug("%(key)-30s %(value)s" % {'key': key,
                                                 'value': value,
                                                 })
         LOG.debug("*" * 80)
-        service = cls(app_name, conf_file, conf)
+        service = cls(app_name)
         return service
 
 
-def serve_wsgi(cls, conf=None, options=None, args=None):
+def serve_wsgi(cls):
     try:
-        service = cls.create(conf, options, args)
+        service = cls.create()
     except Exception:
         logging.exception('in WsgiService.create()')
         raise
@@ -100,15 +85,11 @@ def serve_wsgi(cls, conf=None, options=None, args=None):
     return service
 
 
-def _run_wsgi(app_name, paste_conf, paste_config_file):
-    LOG.info(_('Using paste.deploy config at: %s'), paste_config_file)
-    conf, app = config.load_paste_app(app_name,
-                                      {'config_file': paste_config_file},
-                                      None)
+def _run_wsgi(app_name):
+    app = config.load_paste_app(app_name, "quantum.conf")
     if not app:
-        LOG.error(_('No known API applications configured in %s.'),
-                  paste_config_file)
+        LOG.error(_('No known API applications configured.'))
         return
     server = wsgi.Server("Quantum")
-    server.start(app, int(paste_conf['bind_port']), paste_conf['bind_host'])
+    server.start(app, cfg.CONF.bind_port, cfg.CONF.bind_host)
     return server
index 46f77f2437d8ad5b8bbcaa4eefe12514422ad520..08b0ca2f1014de0a9f62e348e16deed93d6826ab 100644 (file)
@@ -21,19 +21,30 @@ import logging
 import unittest2 as unittest
 
 import mock
+import os
 
 from quantum.api.api_common import APIFaultWrapper
 from quantum.api.networks import Controller
 from quantum.common.test_lib import test_config
+from quantum.common import config
 from quantum.db import api as db
 from quantum.openstack.common import importutils
 import quantum.tests.unit.testlib_api as testlib
+from quantum.openstack.common import cfg
 from quantum.wsgi import XMLDeserializer, JSONDeserializer
 
 
 LOG = logging.getLogger('quantum.tests.test_api')
 
 
+ROOTDIR = os.path.dirname(os.path.dirname(__file__))
+ETCDIR = os.path.join(ROOTDIR, 'etc')
+
+
+def etcdir(*p):
+    return os.path.join(ETCDIR, *p)
+
+
 NETS = "networks"
 PORTS = "ports"
 ATTS = "attachments"
@@ -105,10 +116,13 @@ class AbstractAPITest(unittest.TestCase):
         self.assertEqual(put_attachment_res.status_int, expected_res_status)
 
     def setUp(self, api_router_klass, xml_metadata_dict):
-        options = {}
-        options['plugin_provider'] = test_config['plugin_name']
+        # Create the default configurations
+        args = ['--config-file', etcdir('quantum.conf.test')]
+        config.parse(args=args)
+        # Update the plugin
+        cfg.CONF.set_override('core_plugin', test_config['plugin_name'])
         api_router_cls = importutils.import_class(api_router_klass)
-        self.api = api_router_cls(options)
+        self.api = api_router_cls()
         self.tenant_id = "test_tenant"
         self.network_name = "test_network"
 
@@ -136,6 +150,7 @@ class AbstractAPITest(unittest.TestCase):
         """Clear the test environment"""
         # Remove database contents
         db.clear_db()
+        cfg.CONF.reset()
 
 
 class BaseAPIOperationsTest(AbstractAPITest):
index 06e8c4148fc88f17824ba0fcb660afc3fc387437..90f1082f6e538fe2439890aa16f6114784c9e9e4 100644 (file)
@@ -12,6 +12,7 @@
 #  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 #  License for the spec
 
+import os
 import logging
 import unittest
 import uuid
@@ -26,6 +27,8 @@ from quantum.common import exceptions as q_exc
 from quantum.api.v2 import resource as wsgi_resource
 from quantum.api.v2 import router
 from quantum.api.v2 import views
+from quantum.common import config
+from quantum.openstack.common import cfg
 
 
 LOG = logging.getLogger(__name__)
@@ -34,6 +37,13 @@ LOG = logging.getLogger(__name__)
 def _uuid():
     return str(uuid.uuid4())
 
+ROOTDIR = os.path.dirname(os.path.dirname(__file__))
+ETCDIR = os.path.join(ROOTDIR, 'etc')
+
+
+def etcdir(*p):
+    return os.path.join(ETCDIR, *p)
+
 
 def _get_path(resource, id=None, fmt=None):
     path = '/%s' % resource
@@ -123,16 +133,23 @@ class APIv2TestCase(unittest.TestCase):
     #                will get around this.
     def setUp(self):
         plugin = 'quantum.quantum_plugin_base_v2.QuantumPluginBaseV2'
+        # Create the default configurations
+        args = ['--config-file', etcdir('quantum.conf.test')]
+        config.parse(args=args)
+        # Update the plugin
+        cfg.CONF.set_override('core_plugin', plugin)
+
         self._plugin_patcher = mock.patch(plugin, autospec=True)
         self.plugin = self._plugin_patcher.start()
 
-        api = router.APIRouter({'plugin_provider': plugin})
+        api = router.APIRouter()
         self.api = webtest.TestApp(api)
 
     def tearDown(self):
         self._plugin_patcher.stop()
         self.api = None
         self.plugin = None
+        cfg.CONF.reset()
 
     def test_verbose_attr(self):
         instance = self.plugin.return_value
index 46a22f95302ab24a86a8597b03d0056e9b9a7a8e..d3e89d1d71b769650f8396ee2ecb1fe2057275d1 100644 (file)
@@ -13,6 +13,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+import os
 import logging
 import unittest
 import contextlib
@@ -22,12 +23,21 @@ import quantum
 from quantum.api.v2.router import APIRouter
 from quantum.common import exceptions as q_exc
 from quantum.db import api as db
+from quantum.common import config
+from quantum.openstack.common import cfg
 from quantum.tests.unit.testlib_api import create_request
 from quantum.wsgi import Serializer, JSONDeserializer
 
 
 LOG = logging.getLogger(__name__)
 
+ROOTDIR = os.path.dirname(os.path.dirname(__file__))
+ETCDIR = os.path.join(ROOTDIR, 'etc')
+
+
+def etcdir(*p):
+    return os.path.join(ETCDIR, *p)
+
 
 class QuantumDbPluginV2TestCase(unittest.TestCase):
     def setUp(self):
@@ -46,7 +56,12 @@ class QuantumDbPluginV2TestCase(unittest.TestCase):
         }
 
         plugin = 'quantum.db.db_base_plugin_v2.QuantumDbPluginV2'
-        self.api = APIRouter({'plugin_provider': plugin})
+        # Create the default configurations
+        args = ['--config-file', etcdir('quantum.conf.test')]
+        config.parse(args=args)
+        # Update the plugin
+        cfg.CONF.set_override('core_plugin', plugin)
+        self.api = APIRouter()
 
     def tearDown(self):
         super(QuantumDbPluginV2TestCase, self).tearDown()
@@ -54,6 +69,7 @@ class QuantumDbPluginV2TestCase(unittest.TestCase):
         #                doesn't like when the plugin changes ;)
         db._ENGINE = None
         db._MAKER = None
+        cfg.CONF.reset()
 
     def _req(self, method, resource, data=None, fmt='json', id=None):
         if id:
index ecda049ea2d13ca366daee71b488a7063ed53aad..9c64d36cd73b5d2dc7bc79f5db50e4b476d1a53c 100644 (file)
@@ -14,6 +14,8 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+import logging
+import os
 import unittest
 
 import routes
@@ -41,8 +43,15 @@ from quantum.tests.unit.extension_stubs import (
 import quantum.tests.unit.extensions
 from quantum import wsgi
 
+LOG = logging.getLogger('quantum.tests.test_extensions')
+
+ROOTDIR = os.path.dirname(os.path.dirname(__file__))
+ETCDIR = os.path.join(ROOTDIR, 'etc')
+
+
+def etcdir(*p):
+    return os.path.join(ETCDIR, *p)
 
-test_conf_file = config.find_config_file({}, None, "quantum.conf.test")
 extensions_path = ':'.join(quantum.tests.unit.extensions.__path__)
 
 
@@ -455,8 +464,10 @@ def app_factory(global_conf, **local_conf):
 
 
 def setup_base_app():
-    options = {'config_file': test_conf_file}
-    conf, app = config.load_paste_app('extensions_test_app', options, None)
+    config_file = 'quantum.conf.test'
+    args = ['--config-file', etcdir(config_file)]
+    config.parse(args=args)
+    app = config.load_paste_app('extensions_test_app', config_file)
     return app
 
 
@@ -464,9 +475,11 @@ def setup_extensions_middleware(extension_manager=None):
     extension_manager = (extension_manager or
                          PluginAwareExtensionManager(extensions_path,
                                                      QuantumEchoPlugin()))
-    options = {'config_file': test_conf_file}
-    conf, app = config.load_paste_app('extensions_test_app', options, None)
-    return ExtensionMiddleware(app, conf, ext_mgr=extension_manager)
+    config_file = 'quantum.conf.test'
+    args = ['--config-file', etcdir(config_file)]
+    config.parse(args=args)
+    app = config.load_paste_app('extensions_test_app', config_file)
+    return ExtensionMiddleware(app, ext_mgr=extension_manager)
 
 
 def setup_extensions_test_app(extension_manager=None):
index fe4f5fafdfb59e9284aa328d2ba0b34bfade92f3..4d2854279419029ffa8ced758c2b7a6b764760d1 100644 (file)
--- a/setup.py
+++ b/setup.py
@@ -51,7 +51,7 @@ ryu_plugin_config_path = 'etc/quantum/plugins/ryu'
 
 DataFiles = [
     (config_path,
-        ['etc/quantum.conf', 'etc/quantum.conf.test', 'etc/plugins.ini']),
+        ['etc/quantum.conf']),
     (init_path, ['etc/init.d/quantum-server']),
     (ovs_plugin_config_path,
         ['etc/quantum/plugins/openvswitch/ovs_quantum_plugin.ini']),