Implements the blueprint use-common-cfg for the quantum service.
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
This commit is contained in:
parent
b6cb4316da
commit
0c0d8f00a9
@ -1,3 +0,0 @@
|
|||||||
[PLUGIN]
|
|
||||||
# Quantum plugin provider module
|
|
||||||
provider = quantum.plugins.sample.SamplePlugin.FakePlugin
|
|
@ -18,6 +18,9 @@ bind_port = 9696
|
|||||||
# extensions are in there you don't need to specify them here
|
# extensions are in there you don't need to specify them here
|
||||||
api_extensions_path =
|
api_extensions_path =
|
||||||
|
|
||||||
|
# Quantum plugin provider module
|
||||||
|
core_plugin = quantum.plugins.sample.SamplePlugin.FakePlugin
|
||||||
|
|
||||||
[composite:quantum]
|
[composite:quantum]
|
||||||
use = egg:Paste#urlmap
|
use = egg:Paste#urlmap
|
||||||
/: quantumversions
|
/: quantumversions
|
||||||
|
@ -5,12 +5,12 @@
|
|||||||
sql_connection = sqlite://
|
sql_connection = sqlite://
|
||||||
|
|
||||||
[OVS]
|
[OVS]
|
||||||
integration-bridge = br-int
|
integration_bridge = br-int
|
||||||
|
|
||||||
# openflow-controller = <host IP address of ofp controller>:<port: 6633>
|
# openflow_controller = <host IP address of ofp controller>:<port: 6633>
|
||||||
# openflow-rest-api = <host IP address of ofp rest api service>:<port: 8080>
|
# openflow_rest_api = <host IP address of ofp rest api service>:<port: 8080>
|
||||||
openflow-controller = 127.0.0.1:6633
|
openflow_controller = 127.0.0.1:6633
|
||||||
openflow-rest-api = 127.0.0.1:8080
|
openflow_rest_api = 127.0.0.1:8080
|
||||||
|
|
||||||
[AGENT]
|
[AGENT]
|
||||||
# Change to "sudo quantum-rootwrap" to limit commands that can be run
|
# Change to "sudo quantum-rootwrap" to limit commands that can be run
|
||||||
|
@ -42,23 +42,23 @@ class APIRouter(wsgi.Router):
|
|||||||
"""
|
"""
|
||||||
_version = None
|
_version = None
|
||||||
|
|
||||||
def __init__(self, options=None):
|
def __init__(self):
|
||||||
mapper = self._mapper()
|
mapper = self._mapper()
|
||||||
self._setup_routes(mapper, options)
|
self._setup_routes(mapper)
|
||||||
super(APIRouter, self).__init__(mapper)
|
super(APIRouter, self).__init__(mapper)
|
||||||
|
|
||||||
def _mapper(self):
|
def _mapper(self):
|
||||||
return routes.Mapper()
|
return routes.Mapper()
|
||||||
|
|
||||||
def _setup_routes(self, mapper, options):
|
def _setup_routes(self, mapper):
|
||||||
self._setup_base_routes(mapper, options, self._version)
|
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."""
|
"""Routes common to all versions."""
|
||||||
# Loads the quantum plugin
|
# Loads the quantum plugin
|
||||||
# Note(salvatore-orlando): Should the plugin be versioned
|
# Note(salvatore-orlando): Should the plugin be versioned
|
||||||
# I don't think so
|
# I don't think so
|
||||||
plugin = manager.QuantumManager.get_plugin(options)
|
plugin = manager.QuantumManager.get_plugin()
|
||||||
|
|
||||||
uri_prefix = '/tenants/{tenant_id}/'
|
uri_prefix = '/tenants/{tenant_id}/'
|
||||||
attachment_path = (
|
attachment_path = (
|
||||||
|
@ -293,7 +293,7 @@ class Controller(object):
|
|||||||
return body
|
return body
|
||||||
|
|
||||||
|
|
||||||
def create_resource(collection, resource, plugin, conf, params):
|
def create_resource(collection, resource, plugin, params):
|
||||||
controller = Controller(plugin, collection, resource, params)
|
controller = Controller(plugin, collection, resource, params)
|
||||||
|
|
||||||
# NOTE(jkoelker) To anyone wishing to add "proper" xml support
|
# NOTE(jkoelker) To anyone wishing to add "proper" xml support
|
||||||
|
@ -24,6 +24,7 @@ import webob.exc
|
|||||||
from quantum import manager
|
from quantum import manager
|
||||||
from quantum import wsgi
|
from quantum import wsgi
|
||||||
from quantum.api.v2 import base
|
from quantum.api.v2 import base
|
||||||
|
from quantum.openstack.common import cfg
|
||||||
|
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
@ -118,16 +119,14 @@ class APIRouter(wsgi.Router):
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def factory(cls, global_config, **local_config):
|
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()
|
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)
|
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,
|
col_kwargs = dict(collection_actions=COLLECTION_ACTIONS,
|
||||||
member_actions=MEMBER_ACTIONS)
|
member_actions=MEMBER_ACTIONS)
|
||||||
|
|
||||||
@ -137,8 +136,7 @@ class APIRouter(wsgi.Router):
|
|||||||
|
|
||||||
def _map_resource(collection, resource, params):
|
def _map_resource(collection, resource, params):
|
||||||
controller = base.create_resource(collection, resource,
|
controller = base.create_resource(collection, resource,
|
||||||
plugin, conf,
|
plugin, params)
|
||||||
params)
|
|
||||||
mapper_kwargs = dict(controller=controller,
|
mapper_kwargs = dict(controller=controller,
|
||||||
requirements=REQUIREMENTS,
|
requirements=REQUIREMENTS,
|
||||||
**col_kwargs)
|
**col_kwargs)
|
||||||
|
@ -20,325 +20,100 @@ Routines for configuring Quantum
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
import logging.config
|
|
||||||
import logging.handlers
|
import logging.handlers
|
||||||
import optparse
|
|
||||||
import os
|
import os
|
||||||
import socket
|
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
from paste import deploy
|
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__)
|
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):
|
def parse(args):
|
||||||
"""
|
cfg.CONF(args=args, project='quantum',
|
||||||
Returns the parsed CLI options, command to run and its arguments, merged
|
version='%%prog %s' % version_string())
|
||||||
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):
|
def setup_logging(conf):
|
||||||
"""
|
|
||||||
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 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):
|
|
||||||
"""
|
"""
|
||||||
Sets up the logging options for a log with supplied name
|
Sets up the logging options for a log with supplied name
|
||||||
|
|
||||||
:param options: Mapping of typed option key/values
|
:param conf: a cfg.ConfOpts object
|
||||||
:param conf: Mapping of untyped key/values from config file
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if options.get('log_config', None):
|
if conf.log_config:
|
||||||
# Use a logging configuration file for all settings...
|
# Use a logging configuration file for all settings...
|
||||||
if os.path.exists(options['log_config']):
|
if os.path.exists(conf.log_config):
|
||||||
logging.config.fileConfig(options['log_config'])
|
logging.config.fileConfig(conf.log_config)
|
||||||
return
|
return
|
||||||
else:
|
else:
|
||||||
raise RuntimeError("Unable to locate specified logging "
|
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
|
root_logger = logging.root
|
||||||
if debug:
|
if conf.debug:
|
||||||
root_logger.setLevel(logging.DEBUG)
|
root_logger.setLevel(logging.DEBUG)
|
||||||
elif verbose:
|
elif conf.verbose:
|
||||||
root_logger.setLevel(logging.INFO)
|
root_logger.setLevel(logging.INFO)
|
||||||
else:
|
else:
|
||||||
root_logger.setLevel(logging.WARNING)
|
root_logger.setLevel(logging.WARNING)
|
||||||
|
|
||||||
# Set log configuration from options...
|
formatter = logging.Formatter(conf.log_format, conf.log_date_format)
|
||||||
# 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)
|
|
||||||
|
|
||||||
syslog = options.get('use_syslog')
|
if conf.use_syslog:
|
||||||
if not syslog:
|
|
||||||
syslog = conf.get('use_syslog')
|
|
||||||
|
|
||||||
if syslog:
|
|
||||||
SysLogHandler = logging.handlers.SysLogHandler
|
|
||||||
try:
|
try:
|
||||||
handler = SysLogHandler(address='/dev/log',
|
facility = getattr(logging.handlers.SysLogHandler,
|
||||||
facility=SysLogHandler.LOG_SYSLOG)
|
conf.syslog_log_facility)
|
||||||
except socket.error:
|
except AttributeError:
|
||||||
handler = SysLogHandler(address='/var/run/syslog',
|
raise ValueError(_("Invalid syslog facility"))
|
||||||
facility=SysLogHandler.LOG_SYSLOG)
|
|
||||||
handler.setFormatter(formatter)
|
|
||||||
root_logger.addHandler(handler)
|
|
||||||
|
|
||||||
logfile = options.get('log_file')
|
handler = logging.handlers.SysLogHandler(address='/dev/log',
|
||||||
if not logfile:
|
facility=facility)
|
||||||
logfile = conf.get('log_file')
|
elif conf.log_file:
|
||||||
|
logfile = conf.log_file
|
||||||
if logfile:
|
if conf.log_dir:
|
||||||
logdir = options.get('log_dir')
|
logfile = os.path.join(conf.log_dir, logfile)
|
||||||
if not logdir:
|
handler = logging.handlers.WatchedFileHandler(logfile)
|
||||||
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)
|
|
||||||
else:
|
else:
|
||||||
handler = logging.StreamHandler(sys.stdout)
|
handler = logging.StreamHandler(sys.stdout)
|
||||||
handler.setFormatter(formatter)
|
|
||||||
root_logger.addHandler(handler)
|
handler.setFormatter(formatter)
|
||||||
|
root_logger.addHandler(handler)
|
||||||
|
|
||||||
|
|
||||||
def find_config_file(options, args, config_file='quantum.conf'):
|
def load_paste_app(app_name, 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
|
|
||||||
* 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
|
|
||||||
|
|
||||||
: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):
|
|
||||||
"""
|
"""
|
||||||
Builds and returns a WSGI app from a paste 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 app_name: Name of the application to load
|
||||||
:param options: Set of typed options returned from parse_options()
|
:param config_file: name of the configuration file
|
||||||
:param args: Command line arguments from argv[1:]
|
|
||||||
|
|
||||||
:raises RuntimeError when config file cannot be located or application
|
:raises RuntimeError when config file cannot be located or application
|
||||||
cannot be loaded from config file
|
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:
|
try:
|
||||||
app = deploy.loadapp("config:%s" % conf_file, name=app_name)
|
app = deploy.loadapp("config:%s" % config_path, name=app_name)
|
||||||
except (LookupError, ImportError):
|
except (LookupError, ImportError):
|
||||||
msg = ("Unable to load %(app_name)s from "
|
msg = ("Unable to load %(app_name)s from "
|
||||||
"configuration file %(conf_file)s.") % locals()
|
"configuration file %(config_path)s.") % locals()
|
||||||
LOG.exception(msg)
|
LOG.exception(msg)
|
||||||
raise RuntimeError(msg)
|
raise RuntimeError(msg)
|
||||||
return conf, app
|
return 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)
|
|
||||||
|
@ -21,7 +21,8 @@
|
|||||||
"""Utilities and helper functions."""
|
"""Utilities and helper functions."""
|
||||||
|
|
||||||
|
|
||||||
import ConfigParser
|
import datetime
|
||||||
|
import inspect
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
import subprocess
|
import subprocess
|
||||||
@ -75,12 +76,6 @@ def execute(cmd, process_input=None, addl_env=None, check_exit_code=True):
|
|||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
def get_plugin_from_config(file="config.ini"):
|
|
||||||
Config = ConfigParser.ConfigParser()
|
|
||||||
Config.read(file)
|
|
||||||
return Config.get("PLUGIN", "provider")
|
|
||||||
|
|
||||||
|
|
||||||
class LazyPluggable(object):
|
class LazyPluggable(object):
|
||||||
"""A pluggable backend loaded lazily based on some value."""
|
"""A pluggable backend loaded lazily based on some value."""
|
||||||
|
|
||||||
@ -110,3 +105,51 @@ class LazyPluggable(object):
|
|||||||
def __getattr__(self, key):
|
def __getattr__(self, key):
|
||||||
backend = self.__get_backend()
|
backend = self.__get_backend()
|
||||||
return getattr(backend, key)
|
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
|
||||||
|
@ -29,6 +29,7 @@ import webob.exc
|
|||||||
from quantum.common import exceptions
|
from quantum.common import exceptions
|
||||||
import quantum.extensions
|
import quantum.extensions
|
||||||
from quantum.manager import QuantumManager
|
from quantum.manager import QuantumManager
|
||||||
|
from quantum.openstack.common import cfg
|
||||||
from quantum import wsgi
|
from quantum import wsgi
|
||||||
|
|
||||||
|
|
||||||
@ -217,12 +218,12 @@ class ExtensionController(wsgi.Controller):
|
|||||||
|
|
||||||
class ExtensionMiddleware(wsgi.Middleware):
|
class ExtensionMiddleware(wsgi.Middleware):
|
||||||
"""Extensions middleware for WSGI."""
|
"""Extensions middleware for WSGI."""
|
||||||
def __init__(self, application, config_params,
|
def __init__(self, application,
|
||||||
ext_mgr=None):
|
ext_mgr=None):
|
||||||
|
|
||||||
self.ext_mgr = (ext_mgr
|
self.ext_mgr = (ext_mgr
|
||||||
or ExtensionManager(
|
or ExtensionManager(
|
||||||
get_extensions_path(config_params)))
|
get_extensions_path()))
|
||||||
mapper = routes.Mapper()
|
mapper = routes.Mapper()
|
||||||
|
|
||||||
# extended resources
|
# extended resources
|
||||||
@ -339,10 +340,10 @@ class ExtensionMiddleware(wsgi.Middleware):
|
|||||||
def plugin_aware_extension_middleware_factory(global_config, **local_config):
|
def plugin_aware_extension_middleware_factory(global_config, **local_config):
|
||||||
"""Paste factory."""
|
"""Paste factory."""
|
||||||
def _factory(app):
|
def _factory(app):
|
||||||
extensions_path = get_extensions_path(global_config)
|
extensions_path = get_extensions_path()
|
||||||
ext_mgr = PluginAwareExtensionManager(extensions_path,
|
ext_mgr = PluginAwareExtensionManager(extensions_path,
|
||||||
QuantumManager.get_plugin())
|
QuantumManager.get_plugin())
|
||||||
return ExtensionMiddleware(app, global_config, ext_mgr=ext_mgr)
|
return ExtensionMiddleware(app, ext_mgr=ext_mgr)
|
||||||
return _factory
|
return _factory
|
||||||
|
|
||||||
|
|
||||||
@ -539,9 +540,9 @@ class ResourceExtension(object):
|
|||||||
|
|
||||||
# Returns the extention paths from a config entry and the __path__
|
# Returns the extention paths from a config entry and the __path__
|
||||||
# of quantum.extensions
|
# of quantum.extensions
|
||||||
def get_extensions_path(config=None):
|
def get_extensions_path():
|
||||||
paths = ':'.join(quantum.extensions.__path__)
|
paths = ':'.join(quantum.extensions.__path__)
|
||||||
if config:
|
if cfg.CONF.api_extensions_path:
|
||||||
paths = ':'.join([config.get('api_extensions_path', ''), paths])
|
paths = ':'.join([cfg.CONF.api_extensions_path, paths])
|
||||||
|
|
||||||
return paths
|
return paths
|
||||||
|
@ -24,27 +24,15 @@ The caller should make sure that QuantumManager is a singleton.
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
import logging
|
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.common.exceptions import ClassNotFound
|
||||||
|
from quantum.openstack.common import cfg
|
||||||
from quantum.openstack.common import importutils
|
from quantum.openstack.common import importutils
|
||||||
|
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
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):
|
def get_plugin(plugin_provider):
|
||||||
# If the plugin can't be found let them know gracefully
|
# If the plugin can't be found let them know gracefully
|
||||||
try:
|
try:
|
||||||
@ -58,16 +46,6 @@ def get_plugin(plugin_provider):
|
|||||||
return plugin_klass()
|
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):
|
class QuantumManager(object):
|
||||||
|
|
||||||
_instance = None
|
_instance = None
|
||||||
@ -81,12 +59,12 @@ class QuantumManager(object):
|
|||||||
# breaks tach monitoring. It has been removed
|
# breaks tach monitoring. It has been removed
|
||||||
# intentianally to allow v2 plugins to be monitored
|
# intentianally to allow v2 plugins to be monitored
|
||||||
# for performance metrics.
|
# for performance metrics.
|
||||||
plugin_provider = get_plugin_provider(options, config_file)
|
plugin_provider = cfg.CONF.core_plugin
|
||||||
LOG.debug("Plugin location:%s", plugin_provider)
|
LOG.debug("Plugin location:%s", plugin_provider)
|
||||||
self.plugin = get_plugin(plugin_provider)
|
self.plugin = get_plugin(plugin_provider)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_plugin(cls, options=None, config_file=None):
|
def get_plugin(cls):
|
||||||
if cls._instance is None:
|
if cls._instance is None:
|
||||||
cls._instance = cls(options, config_file)
|
cls._instance = cls()
|
||||||
return cls._instance.plugin
|
return cls._instance.plugin
|
||||||
|
@ -95,7 +95,7 @@ and --config-dir::
|
|||||||
|
|
||||||
class ConfigOpts(object):
|
class ConfigOpts(object):
|
||||||
|
|
||||||
def __init__(self, ...):
|
def __call__(self, ...):
|
||||||
|
|
||||||
opts = [
|
opts = [
|
||||||
MultiStrOpt('config-file',
|
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
|
import collections
|
||||||
@ -478,7 +494,8 @@ class Opt(object):
|
|||||||
multi = False
|
multi = False
|
||||||
|
|
||||||
def __init__(self, name, dest=None, short=None, default=None,
|
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.
|
"""Construct an Opt object.
|
||||||
|
|
||||||
The only required parameter is the option's name. However, it is
|
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 help: an explanation of how the option is used
|
||||||
:param secret: true iff the value should be obfuscated in log output
|
: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 required: true iff a value must be supplied for this option
|
||||||
|
:param deprecated_name: deprecated name option. Acts like an alias
|
||||||
"""
|
"""
|
||||||
self.name = name
|
self.name = name
|
||||||
if dest is None:
|
if dest is None:
|
||||||
@ -504,6 +522,10 @@ class Opt(object):
|
|||||||
self.help = help
|
self.help = help
|
||||||
self.secret = secret
|
self.secret = secret
|
||||||
self.required = required
|
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):
|
def _get_from_config_parser(self, cparser, section):
|
||||||
"""Retrieves the option value from a MultiConfigParser object.
|
"""Retrieves the option value from a MultiConfigParser object.
|
||||||
@ -515,7 +537,13 @@ class Opt(object):
|
|||||||
:param cparser: a ConfigParser object
|
:param cparser: a ConfigParser object
|
||||||
:param section: a section name
|
: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):
|
def _add_to_cli(self, parser, group=None):
|
||||||
"""Makes the option available in the command line interface.
|
"""Makes the option available in the command line interface.
|
||||||
@ -530,9 +558,11 @@ class Opt(object):
|
|||||||
container = self._get_optparse_container(parser, group)
|
container = self._get_optparse_container(parser, group)
|
||||||
kwargs = self._get_optparse_kwargs(group)
|
kwargs = self._get_optparse_kwargs(group)
|
||||||
prefix = self._get_optparse_prefix('', 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.
|
"""Add an option to an optparse parser or group.
|
||||||
|
|
||||||
:param container: an optparse.OptionContainer object
|
:param container: an optparse.OptionContainer object
|
||||||
@ -545,6 +575,8 @@ class Opt(object):
|
|||||||
args = ['--' + prefix + name]
|
args = ['--' + prefix + name]
|
||||||
if short:
|
if short:
|
||||||
args += ['-' + short]
|
args += ['-' + short]
|
||||||
|
if deprecated_name:
|
||||||
|
args += ['--' + prefix + deprecated_name]
|
||||||
for a in args:
|
for a in args:
|
||||||
if container.has_option(a):
|
if container.has_option(a):
|
||||||
raise DuplicateOptError(a)
|
raise DuplicateOptError(a)
|
||||||
@ -577,7 +609,7 @@ class Opt(object):
|
|||||||
dest = group.name + '_' + dest
|
dest = group.name + '_' + dest
|
||||||
kwargs.update({'dest': dest,
|
kwargs.update({'dest': dest,
|
||||||
'metavar': self.metavar,
|
'metavar': self.metavar,
|
||||||
'help': self.help})
|
'help': self.help, })
|
||||||
return kwargs
|
return kwargs
|
||||||
|
|
||||||
def _get_optparse_prefix(self, prefix, group):
|
def _get_optparse_prefix(self, prefix, group):
|
||||||
@ -627,7 +659,8 @@ class BoolOpt(Opt):
|
|||||||
|
|
||||||
return value
|
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):
|
def _add_to_cli(self, parser, group=None):
|
||||||
"""Extends the base class method to add the --nooptname option."""
|
"""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')
|
kwargs = self._get_optparse_kwargs(group, action='store_false')
|
||||||
prefix = self._get_optparse_prefix('no', group)
|
prefix = self._get_optparse_prefix('no', group)
|
||||||
kwargs["help"] = "The inverse of --" + self.name
|
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):
|
def _get_optparse_kwargs(self, group, action='store_true', **kwargs):
|
||||||
"""Extends the base optparse keyword dict for boolean options."""
|
"""Extends the base optparse keyword dict for boolean options."""
|
||||||
@ -654,7 +688,8 @@ class IntOpt(Opt):
|
|||||||
|
|
||||||
def _get_from_config_parser(self, cparser, section):
|
def _get_from_config_parser(self, cparser, section):
|
||||||
"""Retrieve the opt value as a integer from ConfigParser."""
|
"""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):
|
def _get_optparse_kwargs(self, group, **kwargs):
|
||||||
"""Extends the base optparse keyword dict for integer options."""
|
"""Extends the base optparse keyword dict for integer options."""
|
||||||
@ -668,7 +703,8 @@ class FloatOpt(Opt):
|
|||||||
|
|
||||||
def _get_from_config_parser(self, cparser, section):
|
def _get_from_config_parser(self, cparser, section):
|
||||||
"""Retrieve the opt value as a float from ConfigParser."""
|
"""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):
|
def _get_optparse_kwargs(self, group, **kwargs):
|
||||||
"""Extends the base optparse keyword dict for float options."""
|
"""Extends the base optparse keyword dict for float options."""
|
||||||
@ -685,7 +721,8 @@ class ListOpt(Opt):
|
|||||||
|
|
||||||
def _get_from_config_parser(self, cparser, section):
|
def _get_from_config_parser(self, cparser, section):
|
||||||
"""Retrieve the opt value as a list from ConfigParser."""
|
"""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):
|
def _get_optparse_kwargs(self, group, **kwargs):
|
||||||
"""Extends the base optparse keyword dict for list options."""
|
"""Extends the base optparse keyword dict for list options."""
|
||||||
@ -714,6 +751,13 @@ class MultiStrOpt(Opt):
|
|||||||
return super(MultiStrOpt,
|
return super(MultiStrOpt,
|
||||||
self)._get_optparse_kwargs(group, action='append')
|
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):
|
class OptGroup(object):
|
||||||
|
|
||||||
@ -766,6 +810,14 @@ class OptGroup(object):
|
|||||||
|
|
||||||
return True
|
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):
|
def _get_optparse_group(self, parser):
|
||||||
"""Build an optparse.OptionGroup for this group."""
|
"""Build an optparse.OptionGroup for this group."""
|
||||||
if self._optparse_group is None:
|
if self._optparse_group is None:
|
||||||
@ -773,6 +825,10 @@ class OptGroup(object):
|
|||||||
self.help)
|
self.help)
|
||||||
return self._optparse_group
|
return self._optparse_group
|
||||||
|
|
||||||
|
def _clear(self):
|
||||||
|
"""Clear this group's option parsing state."""
|
||||||
|
self._optparse_group = None
|
||||||
|
|
||||||
|
|
||||||
class ParseError(iniparser.ParseError):
|
class ParseError(iniparser.ParseError):
|
||||||
def __init__(self, msg, lineno, line, filename):
|
def __init__(self, msg, lineno, line, filename):
|
||||||
@ -816,25 +872,38 @@ class ConfigParser(iniparser.BaseParser):
|
|||||||
|
|
||||||
class MultiConfigParser(object):
|
class MultiConfigParser(object):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.sections = {}
|
self.parsed = []
|
||||||
|
|
||||||
def read(self, config_files):
|
def read(self, config_files):
|
||||||
read_ok = []
|
read_ok = []
|
||||||
|
|
||||||
for filename in config_files:
|
for filename in config_files:
|
||||||
parser = ConfigParser(filename, self.sections)
|
sections = {}
|
||||||
|
parser = ConfigParser(filename, sections)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
parser.parse()
|
parser.parse()
|
||||||
except IOError:
|
except IOError:
|
||||||
continue
|
continue
|
||||||
|
self.parsed.insert(0, sections)
|
||||||
read_ok.append(filename)
|
read_ok.append(filename)
|
||||||
|
|
||||||
return read_ok
|
return read_ok
|
||||||
|
|
||||||
def get(self, section, name):
|
def get(self, section, names, multi=False):
|
||||||
return self.sections[section][name]
|
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):
|
class ConfigOpts(collections.Mapping):
|
||||||
@ -847,57 +916,41 @@ class ConfigOpts(collections.Mapping):
|
|||||||
the values of options.
|
the values of options.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(self):
|
||||||
project=None,
|
"""Construct a ConfigOpts object."""
|
||||||
prog=None,
|
self._opts = {} # dict of dicts of (opt:, override:, default:)
|
||||||
version=None,
|
self._groups = {}
|
||||||
usage=None,
|
|
||||||
default_config_files=None):
|
|
||||||
"""Construct a ConfigOpts object.
|
|
||||||
|
|
||||||
Automatically registers the --config-file option with either a supplied
|
self._args = None
|
||||||
list of default config files, or a list from find_config_files().
|
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
|
def _setup(self, project, prog, version, usage, default_config_files):
|
||||||
:param prog: the name of the program (defaults to sys.argv[0] basename)
|
"""Initialize a ConfigOpts object for option parsing."""
|
||||||
: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
|
|
||||||
"""
|
|
||||||
if prog is None:
|
if prog is None:
|
||||||
prog = os.path.basename(sys.argv[0])
|
prog = os.path.basename(sys.argv[0])
|
||||||
|
|
||||||
if default_config_files is None:
|
if default_config_files is None:
|
||||||
default_config_files = find_config_files(project, prog)
|
default_config_files = find_config_files(project, prog)
|
||||||
|
|
||||||
self.project = project
|
self._oparser = optparse.OptionParser(prog=prog,
|
||||||
self.prog = prog
|
version=version,
|
||||||
self.version = version
|
usage=usage)
|
||||||
self.usage = usage
|
if self._disable_interspersed_args:
|
||||||
self.default_config_files = default_config_files
|
self._oparser.disable_interspersed_args()
|
||||||
|
|
||||||
self._opts = {} # dict of dicts of (opt:, override:, default:)
|
self._config_opts = [
|
||||||
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.__cache = {}
|
|
||||||
|
|
||||||
opts = [
|
|
||||||
MultiStrOpt('config-file',
|
MultiStrOpt('config-file',
|
||||||
default=self.default_config_files,
|
default=default_config_files,
|
||||||
metavar='PATH',
|
metavar='PATH',
|
||||||
help='Path to a config file to use. Multiple config '
|
help='Path to a config file to use. Multiple config '
|
||||||
'files can be specified, with values in later '
|
'files can be specified, with values in later '
|
||||||
'files taking precedence. The default files '
|
'files taking precedence. The default files '
|
||||||
' used are: %s' %
|
' used are: %s' % (default_config_files, )),
|
||||||
(self.default_config_files)),
|
|
||||||
StrOpt('config-dir',
|
StrOpt('config-dir',
|
||||||
metavar='DIR',
|
metavar='DIR',
|
||||||
help='Path to a config directory to pull *.conf '
|
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 '
|
'hence over-ridden options in the directory take '
|
||||||
'precedence.'),
|
'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):
|
def __clear_cache(f):
|
||||||
@functools.wraps(f)
|
@functools.wraps(f)
|
||||||
@ -919,7 +978,13 @@ class ConfigOpts(collections.Mapping):
|
|||||||
|
|
||||||
return __inner
|
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.
|
"""Parse command line arguments and config files.
|
||||||
|
|
||||||
Calling a ConfigOpts object causes the supplied command line arguments
|
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
|
The object may be called multiple times, each time causing the previous
|
||||||
set of values to be overwritten.
|
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
|
If the --config-dir option is set, any *.conf files from this
|
||||||
directory are pulled in, after all the file(s) specified by the
|
directory are pulled in, after all the file(s) specified by the
|
||||||
--config-file option.
|
--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
|
:returns: the list of arguments left over after parsing options
|
||||||
:raises: SystemExit, ConfigFilesNotFoundError, ConfigFileParseError,
|
:raises: SystemExit, ConfigFilesNotFoundError, ConfigFileParseError,
|
||||||
RequiredOptError
|
RequiredOptError, DuplicateOptError
|
||||||
"""
|
"""
|
||||||
self.clear()
|
self.clear()
|
||||||
|
|
||||||
self._args = args
|
self._setup(project, prog, version, usage, default_config_files)
|
||||||
|
|
||||||
(values, args) = self._oparser.parse_args(self._args)
|
self._cli_values, leftovers = self._parse_cli_opts(args)
|
||||||
|
|
||||||
self._cli_values = vars(values)
|
self._parse_config_files()
|
||||||
|
|
||||||
def _list_config_dir():
|
|
||||||
return sorted(glob.glob(os.path.join(self.config_dir, '*.conf')))
|
|
||||||
|
|
||||||
from_file = list(self.config_file)
|
|
||||||
|
|
||||||
from_dir = _list_config_dir() if self.config_dir else []
|
|
||||||
|
|
||||||
self._parse_config_files(from_file + from_dir)
|
|
||||||
|
|
||||||
self._check_required_opts()
|
self._check_required_opts()
|
||||||
|
|
||||||
return args
|
return leftovers
|
||||||
|
|
||||||
def __getattr__(self, name):
|
def __getattr__(self, name):
|
||||||
"""Look up an option value and perform string substitution.
|
"""Look up an option value and perform string substitution.
|
||||||
@ -994,8 +1058,12 @@ class ConfigOpts(collections.Mapping):
|
|||||||
def clear(self):
|
def clear(self):
|
||||||
"""Clear the state of the object to before it was called."""
|
"""Clear the state of the object to before it was called."""
|
||||||
self._args = None
|
self._args = None
|
||||||
self._cli_values = {}
|
self._cli_values.clear()
|
||||||
|
self._oparser = None
|
||||||
self._cparser = None
|
self._cparser = None
|
||||||
|
self.unregister_opts(self._config_opts)
|
||||||
|
for group in self._groups.values():
|
||||||
|
group._clear()
|
||||||
|
|
||||||
@__clear_cache
|
@__clear_cache
|
||||||
def register_opt(self, opt, group=None):
|
def register_opt(self, opt, group=None):
|
||||||
@ -1042,15 +1110,7 @@ class ConfigOpts(collections.Mapping):
|
|||||||
if self._args is not None:
|
if self._args is not None:
|
||||||
raise ArgsAlreadyParsedError("cannot register CLI option")
|
raise ArgsAlreadyParsedError("cannot register CLI option")
|
||||||
|
|
||||||
if not self.register_opt(opt, group, clear_cache=False):
|
return 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
|
|
||||||
|
|
||||||
@__clear_cache
|
@__clear_cache
|
||||||
def register_cli_opts(self, opts, group=None):
|
def register_cli_opts(self, opts, group=None):
|
||||||
@ -1071,6 +1131,28 @@ class ConfigOpts(collections.Mapping):
|
|||||||
|
|
||||||
self._groups[group.name] = copy.copy(group)
|
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
|
@__clear_cache
|
||||||
def set_override(self, name, override, group=None):
|
def set_override(self, name, override, group=None):
|
||||||
"""Override an opt value.
|
"""Override an opt value.
|
||||||
@ -1101,16 +1183,24 @@ class ConfigOpts(collections.Mapping):
|
|||||||
opt_info = self._get_opt_info(name, group)
|
opt_info = self._get_opt_info(name, group)
|
||||||
opt_info['default'] = default
|
opt_info['default'] = default
|
||||||
|
|
||||||
|
def _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):
|
def _unset_defaults_and_overrides(self):
|
||||||
"""Unset any default or override on all options."""
|
"""Unset any default or override on all options."""
|
||||||
def unset(opts):
|
for info, group in self._all_opt_infos():
|
||||||
for info in opts.values():
|
info['default'] = None
|
||||||
info['default'] = None
|
info['override'] = None
|
||||||
info['override'] = None
|
|
||||||
|
|
||||||
unset(self._opts)
|
|
||||||
for group in self._groups.values():
|
|
||||||
unset(group._opts)
|
|
||||||
|
|
||||||
def disable_interspersed_args(self):
|
def disable_interspersed_args(self):
|
||||||
"""Set parsing to stop on the first non-option.
|
"""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.
|
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):
|
def enable_interspersed_args(self):
|
||||||
"""Set parsing to not stop on the first non-option.
|
"""Set parsing to not stop on the first non-option.
|
||||||
|
|
||||||
This it the default behaviour."""
|
This it the default behaviour."""
|
||||||
self._oparser.enable_interspersed_args()
|
self._disable_interspersed_args = False
|
||||||
|
|
||||||
def find_file(self, name):
|
def find_file(self, name):
|
||||||
"""Locate a file located alongside the config files.
|
"""Locate a file located alongside the config files.
|
||||||
@ -1272,7 +1362,7 @@ class ConfigOpts(collections.Mapping):
|
|||||||
def _substitute(self, value):
|
def _substitute(self, value):
|
||||||
"""Perform string template substitution.
|
"""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.
|
string value(s) with opt values.
|
||||||
|
|
||||||
:param value: the string value, or list of string values
|
:param value: the string value, or list of string values
|
||||||
@ -1329,11 +1419,17 @@ class ConfigOpts(collections.Mapping):
|
|||||||
|
|
||||||
return opts[opt_name]
|
return opts[opt_name]
|
||||||
|
|
||||||
def _parse_config_files(self, config_files):
|
def _parse_config_files(self):
|
||||||
"""Parse the supplied configuration files.
|
"""Parse the config files from --config-file and --config-dir.
|
||||||
|
|
||||||
:raises: ConfigFilesNotFoundError, ConfigFileParseError
|
: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()
|
self._cparser = MultiConfigParser()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@ -1345,8 +1441,12 @@ class ConfigOpts(collections.Mapping):
|
|||||||
not_read_ok = filter(lambda f: f not in read_ok, config_files)
|
not_read_ok = filter(lambda f: f not in read_ok, config_files)
|
||||||
raise ConfigFilesNotFoundError(not_read_ok)
|
raise ConfigFilesNotFoundError(not_read_ok)
|
||||||
|
|
||||||
def _do_check_required_opts(self, opts, group=None):
|
def _check_required_opts(self):
|
||||||
for info in opts.values():
|
"""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())]
|
default, opt, override = [info[k] for k in sorted(info.keys())]
|
||||||
|
|
||||||
if opt.required:
|
if opt.required:
|
||||||
@ -1356,15 +1456,25 @@ class ConfigOpts(collections.Mapping):
|
|||||||
if self._get(opt.name, group) is None:
|
if self._get(opt.name, group) is None:
|
||||||
raise RequiredOptError(opt.name, group)
|
raise RequiredOptError(opt.name, group)
|
||||||
|
|
||||||
def _check_required_opts(self):
|
def _parse_cli_opts(self, args):
|
||||||
"""Check that all opts marked as required have values specified.
|
"""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():
|
for opt, group in self._all_opts():
|
||||||
self._do_check_required_opts(group._opts, group)
|
opt._add_to_cli(self._oparser, group)
|
||||||
|
|
||||||
|
values, leftovers = self._oparser.parse_args(args)
|
||||||
|
|
||||||
|
return vars(values), leftovers
|
||||||
|
|
||||||
class GroupAttr(collections.Mapping):
|
class GroupAttr(collections.Mapping):
|
||||||
|
|
||||||
@ -1480,7 +1590,10 @@ class CommonConfigOpts(ConfigOpts):
|
|||||||
help='syslog facility to receive log lines')
|
help='syslog facility to receive log lines')
|
||||||
]
|
]
|
||||||
|
|
||||||
def __init__(self, **kwargs):
|
def __init__(self):
|
||||||
super(CommonConfigOpts, self).__init__(**kwargs)
|
super(CommonConfigOpts, self).__init__()
|
||||||
self.register_cli_opts(self.common_cli_opts)
|
self.register_cli_opts(self.common_cli_opts)
|
||||||
self.register_cli_opts(self.logging_cli_opts)
|
self.register_cli_opts(self.logging_cli_opts)
|
||||||
|
|
||||||
|
|
||||||
|
CONF = CommonConfigOpts()
|
||||||
|
@ -18,7 +18,7 @@
|
|||||||
|
|
||||||
import logging as LOG
|
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_configparser as confp
|
||||||
from quantum.plugins.cisco.common import cisco_constants as const
|
from quantum.plugins.cisco.common import cisco_constants as const
|
||||||
from quantum.plugins.cisco.common import cisco_exceptions as cexc
|
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.basicConfig(level=LOG.WARN)
|
||||||
LOG.getLogger(const.LOGGER_COMPONENT_NAME)
|
LOG.getLogger(const.LOGGER_COMPONENT_NAME)
|
||||||
|
|
||||||
CREDENTIALS_FILE = find_config_file({'plugin': 'cisco'}, None,
|
CREDENTIALS_FILE = find_config_file({'plugin': 'cisco'},
|
||||||
"credentials.ini")
|
"credentials.ini")
|
||||||
TENANT = const.NETWORK_ADMIN
|
TENANT = const.NETWORK_ADMIN
|
||||||
|
|
||||||
|
@ -17,11 +17,11 @@
|
|||||||
# @author: Sumit Naiksatam, Cisco Systems, Inc.
|
# @author: Sumit Naiksatam, Cisco Systems, Inc.
|
||||||
# @author: Rohit Agarwalla, 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
|
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)
|
CONF_PARSER_OBJ = confp.CiscoConfigParser(CONF_FILE)
|
||||||
|
|
||||||
|
|
||||||
@ -43,7 +43,7 @@ MAX_NETWORKS = SECTION_CONF['max_networks']
|
|||||||
SECTION_CONF = CONF_PARSER_OBJ['MODEL']
|
SECTION_CONF = CONF_PARSER_OBJ['MODEL']
|
||||||
MODEL_CLASS = SECTION_CONF['model_class']
|
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']
|
SECTION_CONF = CONF_PARSER_OBJ['SEGMENTATION']
|
||||||
MANAGER_CLASS = SECTION_CONF['manager_class']
|
MANAGER_CLASS = SECTION_CONF['manager_class']
|
||||||
@ -55,7 +55,7 @@ CONF_PARSER_OBJ = confp.CiscoConfigParser(CONF_FILE)
|
|||||||
# Read the config for the device plugins
|
# Read the config for the device plugins
|
||||||
PLUGINS = CONF_PARSER_OBJ.walk(CONF_PARSER_OBJ.dummy)
|
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)
|
CONF_PARSER_OBJ = confp.CiscoConfigParser(CONF_FILE)
|
||||||
|
|
||||||
|
@ -23,11 +23,11 @@ This module will export the configuration parameters
|
|||||||
from the nexus.ini file
|
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
|
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"))
|
"nexus.ini"))
|
||||||
|
|
||||||
SECTION = CP['SWITCH']
|
SECTION = CP['SWITCH']
|
||||||
|
@ -52,7 +52,7 @@ from quantum import wsgi
|
|||||||
LOG = logging.getLogger('quantum.plugins.cisco.tests.test_cisco_extensions')
|
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')
|
'quantum.conf.ciscoext')
|
||||||
EXTENSIONS_PATH = os.path.join(os.path.dirname(__file__), os.pardir, os.pardir,
|
EXTENSIONS_PATH = os.path.join(os.path.dirname(__file__), os.pardir, os.pardir,
|
||||||
os.pardir, os.pardir, "extensions")
|
os.pardir, os.pardir, "extensions")
|
||||||
@ -1256,8 +1256,8 @@ def setup_extensions_middleware(extension_manager=None):
|
|||||||
PluginAwareExtensionManager(EXTENSIONS_PATH,
|
PluginAwareExtensionManager(EXTENSIONS_PATH,
|
||||||
L2Network()))
|
L2Network()))
|
||||||
options = {'config_file': TEST_CONF_FILE}
|
options = {'config_file': TEST_CONF_FILE}
|
||||||
conf, app = config.load_paste_app('extensions_test_app', options, None)
|
app = config.load_paste_app('extensions_test_app', options, None)
|
||||||
return ExtensionMiddleware(app, conf, ext_mgr=extension_manager)
|
return ExtensionMiddleware(app, ext_mgr=extension_manager)
|
||||||
|
|
||||||
|
|
||||||
def setup_extensions_test_app(extension_manager=None):
|
def setup_extensions_test_app(extension_manager=None):
|
||||||
|
@ -17,11 +17,11 @@
|
|||||||
# @author: Sumit Naiksatam, Cisco Systems, Inc.
|
# @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
|
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'))
|
'ucs.ini'))
|
||||||
|
|
||||||
SECTION = CP['UCSM']
|
SECTION = CP['UCSM']
|
||||||
@ -34,7 +34,7 @@ PROFILE_NAME_PREFIX = SECTION['profile_name_prefix']
|
|||||||
SECTION = CP['DRIVER']
|
SECTION = CP['DRIVER']
|
||||||
UCSM_DRIVER = SECTION['name']
|
UCSM_DRIVER = SECTION['name']
|
||||||
|
|
||||||
CP = confp.CiscoConfigParser(find_config_file({'plugin': 'cisco'}, [],
|
CP = confp.CiscoConfigParser(find_config_file({'plugin': 'cisco'},
|
||||||
'ucs_inventory.ini'))
|
'ucs_inventory.ini'))
|
||||||
|
|
||||||
INVENTORY = CP.walk(CP.dummy)
|
INVENTORY = CP.walk(CP.dummy)
|
||||||
|
@ -17,11 +17,11 @@
|
|||||||
# @author: Sumit Naiksatam, Cisco Systems, Inc.
|
# @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
|
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)
|
CP = confp.CiscoConfigParser(CONF_FILE)
|
||||||
|
|
||||||
INVENTORY = CP.walk(CP.dummy)
|
INVENTORY = CP.walk(CP.dummy)
|
||||||
|
@ -41,8 +41,8 @@ agent_opts = [
|
|||||||
|
|
||||||
|
|
||||||
def parse(config_file):
|
def parse(config_file):
|
||||||
conf = cfg.ConfigOpts(default_config_files=[config_file])
|
conf = cfg.ConfigOpts()
|
||||||
conf(args=[])
|
conf(args=[], default_config_files=[config_file])
|
||||||
conf.register_opts(vlan_opts, "VLANS")
|
conf.register_opts(vlan_opts, "VLANS")
|
||||||
conf.register_opts(database_opts, "DATABASE")
|
conf.register_opts(database_opts, "DATABASE")
|
||||||
conf.register_opts(bridge_opts, "LINUX_BRIDGE")
|
conf.register_opts(bridge_opts, "LINUX_BRIDGE")
|
||||||
|
@ -21,14 +21,14 @@ from sqlalchemy import func
|
|||||||
from sqlalchemy.orm import exc
|
from sqlalchemy.orm import exc
|
||||||
|
|
||||||
from quantum.common import exceptions as q_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
|
import quantum.db.api as db
|
||||||
from quantum.plugins.linuxbridge.common import exceptions as c_exc
|
from quantum.plugins.linuxbridge.common import exceptions as c_exc
|
||||||
from quantum.plugins.linuxbridge.db import l2network_models
|
from quantum.plugins.linuxbridge.db import l2network_models
|
||||||
from quantum.plugins.linuxbridge.common import config
|
from quantum.plugins.linuxbridge.common import config
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
CONF_FILE = find_config_file({'plugin': 'linuxbridge'}, None,
|
CONF_FILE = find_config_file({'plugin': 'linuxbridge'},
|
||||||
"linuxbridge_conf.ini")
|
"linuxbridge_conf.ini")
|
||||||
CONF = config.parse(CONF_FILE)
|
CONF = config.parse(CONF_FILE)
|
||||||
|
|
||||||
|
@ -38,8 +38,8 @@ agent_opts = [
|
|||||||
|
|
||||||
|
|
||||||
def parse(config_file):
|
def parse(config_file):
|
||||||
conf = cfg.ConfigOpts(default_config_files=[config_file])
|
conf = cfg.ConfigOpts()
|
||||||
conf(args=[])
|
conf(args=[], default_config_files=[config_file])
|
||||||
conf.register_opts(database_opts, "DATABASE")
|
conf.register_opts(database_opts, "DATABASE")
|
||||||
conf.register_opts(ovs_opts, "OVS")
|
conf.register_opts(ovs_opts, "OVS")
|
||||||
conf.register_opts(agent_opts, "AGENT")
|
conf.register_opts(agent_opts, "AGENT")
|
||||||
|
@ -23,7 +23,7 @@ import os
|
|||||||
|
|
||||||
from quantum.api.api_common import OperationalStatus
|
from quantum.api.api_common import OperationalStatus
|
||||||
from quantum.common import exceptions as q_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
|
import quantum.db.api as db
|
||||||
from quantum.plugins.openvswitch import ovs_db
|
from quantum.plugins.openvswitch import ovs_db
|
||||||
from quantum.plugins.openvswitch.common import config
|
from quantum.plugins.openvswitch.common import config
|
||||||
@ -33,7 +33,7 @@ LOG = logging.getLogger("ovs_quantum_plugin")
|
|||||||
|
|
||||||
|
|
||||||
CONF_FILE = find_config_file({"plugin": "openvswitch"},
|
CONF_FILE = find_config_file({"plugin": "openvswitch"},
|
||||||
None, "ovs_quantum_plugin.ini")
|
"ovs_quantum_plugin.ini")
|
||||||
|
|
||||||
|
|
||||||
# Exception thrown if no more VLANs are available
|
# Exception thrown if no more VLANs are available
|
||||||
|
@ -20,7 +20,6 @@
|
|||||||
# under the License.
|
# under the License.
|
||||||
# @author: Isaku Yamahata
|
# @author: Isaku Yamahata
|
||||||
|
|
||||||
import ConfigParser
|
|
||||||
import logging as LOG
|
import logging as LOG
|
||||||
from optparse import OptionParser
|
from optparse import OptionParser
|
||||||
import shlex
|
import shlex
|
||||||
@ -34,6 +33,7 @@ from ryu.app.client import OFPClient
|
|||||||
from sqlalchemy.ext.sqlsoup import SqlSoup
|
from sqlalchemy.ext.sqlsoup import SqlSoup
|
||||||
|
|
||||||
from quantum.agent.linux import utils
|
from quantum.agent.linux import utils
|
||||||
|
from quantum.plugins.ryu.common import config
|
||||||
|
|
||||||
OP_STATUS_UP = "UP"
|
OP_STATUS_UP = "UP"
|
||||||
OP_STATUS_DOWN = "DOWN"
|
OP_STATUS_DOWN = "DOWN"
|
||||||
@ -286,18 +286,10 @@ def main():
|
|||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
config_file = args[0]
|
config_file = args[0]
|
||||||
config = ConfigParser.ConfigParser()
|
conf = config.parse(config_file)
|
||||||
try:
|
integ_br = conf.OVS.integration_bridge
|
||||||
config.read(config_file)
|
root_helper = conf.AGENT.root_helper
|
||||||
except Exception, e:
|
options = {"sql_connection": conf.DATABASE.sql_connection}
|
||||||
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")}
|
|
||||||
db = SqlSoup(options["sql_connection"])
|
db = SqlSoup(options["sql_connection"])
|
||||||
|
|
||||||
LOG.info("Connecting to database \"%s\" on %s",
|
LOG.info("Connecting to database \"%s\" on %s",
|
||||||
|
15
quantum/plugins/ryu/common/__init__.py
Normal file
15
quantum/plugins/ryu/common/__init__.py
Normal file
@ -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.
|
43
quantum/plugins/ryu/common/config.py
Normal file
43
quantum/plugins/ryu/common/config.py
Normal file
@ -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
|
@ -16,15 +16,14 @@
|
|||||||
# under the License.
|
# under the License.
|
||||||
# @author: Isaku Yamahata
|
# @author: Isaku Yamahata
|
||||||
|
|
||||||
import ConfigParser
|
|
||||||
from abc import ABCMeta, abstractmethod
|
from abc import ABCMeta, abstractmethod
|
||||||
import logging as LOG
|
import logging as LOG
|
||||||
import os
|
import os
|
||||||
|
|
||||||
from quantum.api.api_common import OperationalStatus
|
from quantum.api.api_common import OperationalStatus
|
||||||
from quantum.common import exceptions as q_exc
|
from quantum.common import exceptions as q_exc
|
||||||
|
from quantum.plugins.ryu.common import config
|
||||||
import quantum.db.api as db
|
import quantum.db.api as db
|
||||||
from quantum.manager import find_config
|
|
||||||
from quantum.quantum_plugin_base import QuantumPluginBase
|
from quantum.quantum_plugin_base import QuantumPluginBase
|
||||||
|
|
||||||
|
|
||||||
@ -55,24 +54,23 @@ class OVSQuantumPluginBase(QuantumPluginBase):
|
|||||||
"""
|
"""
|
||||||
def __init__(self, conf_file, mod_file, configfile=None):
|
def __init__(self, conf_file, mod_file, configfile=None):
|
||||||
super(OVSQuantumPluginBase, self).__init__()
|
super(OVSQuantumPluginBase, self).__init__()
|
||||||
config = ConfigParser.ConfigParser()
|
|
||||||
if configfile is None:
|
if configfile is None:
|
||||||
if conf_file and os.path.exists(conf_file):
|
if os.path.exists(conf_file):
|
||||||
configfile = conf_file
|
configfile = conf_file
|
||||||
else:
|
else:
|
||||||
configfile = (
|
configfile = find_config(os.path.abspath(
|
||||||
find_config(os.path.abspath(os.path.dirname(mod_file))))
|
os.path.dirname(__file__)))
|
||||||
if configfile is None:
|
if configfile is None:
|
||||||
raise Exception("Configuration file \"%s\" doesn't exist" %
|
raise Exception("Configuration file \"%s\" doesn't exist" %
|
||||||
(configfile))
|
(configfile))
|
||||||
LOG.debug("Using configuration file: %s", configfile)
|
LOG.debug("Using configuration file: %s" % configfile)
|
||||||
config.read(configfile)
|
conf = config.parse(configfile)
|
||||||
LOG.debug("Config: %s", config)
|
options = {"sql_connection": conf.DATABASE.sql_connection}
|
||||||
|
reconnect_interval = conf.DATABASE.reconnect_interval
|
||||||
options = {"sql_connection": config.get("DATABASE", "sql_connection")}
|
options.update({"reconnect_interval": reconnect_interval})
|
||||||
db.configure_db(options)
|
db.configure_db(options)
|
||||||
|
|
||||||
self.config = config
|
self.conf = conf
|
||||||
# Subclass must set self.driver to its own OVSQuantumPluginDriverBase
|
# Subclass must set self.driver to its own OVSQuantumPluginDriverBase
|
||||||
self.driver = None
|
self.driver = None
|
||||||
|
|
||||||
|
@ -19,7 +19,7 @@
|
|||||||
from ryu.app import client
|
from ryu.app import client
|
||||||
from ryu.app import rest_nw_id
|
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
|
from quantum.common import exceptions as q_exc
|
||||||
import quantum.db.api as db
|
import quantum.db.api as db
|
||||||
from quantum.plugins.ryu import ofp_service_type
|
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
|
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):
|
class OFPRyuDriver(ovs_quantum_plugin_base.OVSQuantumPluginDriverBase):
|
||||||
def __init__(self, config):
|
def __init__(self, conf):
|
||||||
super(OFPRyuDriver, self).__init__()
|
super(OFPRyuDriver, self).__init__()
|
||||||
ofp_con_host = config.get("OVS", "openflow-controller")
|
ofp_con_host = conf.OVS.openflow_controller
|
||||||
ofp_api_host = config.get("OVS", "openflow-rest-api")
|
ofp_api_host = conf.OVS.openflow_rest_api
|
||||||
|
|
||||||
if ofp_con_host is None or ofp_api_host is None:
|
if ofp_con_host is None or ofp_api_host is None:
|
||||||
raise q_exc.Invalid("invalid configuration. check ryu.ini")
|
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):
|
class RyuQuantumPlugin(ovs_quantum_plugin_base.OVSQuantumPluginBase):
|
||||||
def __init__(self, configfile=None):
|
def __init__(self, configfile=None):
|
||||||
super(RyuQuantumPlugin, self).__init__(CONF_FILE, __file__, configfile)
|
super(RyuQuantumPlugin, self).__init__(CONF_FILE, __file__, configfile)
|
||||||
self.driver = OFPRyuDriver(self.config)
|
self.driver = OFPRyuDriver(self.conf)
|
||||||
|
@ -21,6 +21,8 @@ from quantum.plugins.ryu import ovs_quantum_plugin_base
|
|||||||
class FakePluginDriver(ovs_quantum_plugin_base.OVSQuantumPluginDriverBase):
|
class FakePluginDriver(ovs_quantum_plugin_base.OVSQuantumPluginDriverBase):
|
||||||
def __init__(self, config):
|
def __init__(self, config):
|
||||||
super(FakePluginDriver, self).__init__()
|
super(FakePluginDriver, self).__init__()
|
||||||
|
conf = config.parse(config)
|
||||||
|
self.conf = conf
|
||||||
|
|
||||||
def create_network(self, net):
|
def create_network(self, net):
|
||||||
pass
|
pass
|
||||||
@ -32,4 +34,4 @@ class FakePluginDriver(ovs_quantum_plugin_base.OVSQuantumPluginDriverBase):
|
|||||||
class FakePlugin(ovs_quantum_plugin_base.OVSQuantumPluginBase):
|
class FakePlugin(ovs_quantum_plugin_base.OVSQuantumPluginBase):
|
||||||
def __init__(self, configfile=None):
|
def __init__(self, configfile=None):
|
||||||
super(FakePlugin, self).__init__(None, __file__, configfile)
|
super(FakePlugin, self).__init__(None, __file__, configfile)
|
||||||
self.driver = FakePluginDriver(self.config)
|
self.driver = FakePluginDriver(self.conf)
|
||||||
|
@ -18,16 +18,21 @@
|
|||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
import quantum.db.api as db
|
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.basetest import BaseRyuTest
|
||||||
from quantum.plugins.ryu.tests.unit import utils
|
from quantum.plugins.ryu.tests.unit import utils
|
||||||
from quantum.plugins.ryu.tests.unit.utils import patch_fake_ryu_client
|
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 RyuDriverTest(BaseRyuTest):
|
||||||
"""Class conisting of OFPRyuDriver unit tests"""
|
"""Class conisting of OFPRyuDriver unit tests"""
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(RyuDriverTest, self).setUp()
|
super(RyuDriverTest, self).setUp()
|
||||||
|
self.conf = config.parse(CONF_FILE)
|
||||||
# fake up ryu.app.client and ryu.app.rest_nw_id
|
# fake up ryu.app.client and ryu.app.rest_nw_id
|
||||||
# With those, plugin can be tested without ryu installed
|
# With those, plugin can be tested without ryu installed
|
||||||
self.module_patcher = patch_fake_ryu_client()
|
self.module_patcher = patch_fake_ryu_client()
|
||||||
@ -65,7 +70,7 @@ class RyuDriverTest(BaseRyuTest):
|
|||||||
db.network_create('test', uuid0)
|
db.network_create('test', uuid0)
|
||||||
|
|
||||||
from quantum.plugins.ryu import ryu_quantum_plugin
|
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.create_network(net1)
|
||||||
ryu_driver.delete_network(net1)
|
ryu_driver.delete_network(net1)
|
||||||
self.mox.VerifyAll()
|
self.mox.VerifyAll()
|
||||||
|
@ -21,7 +21,7 @@ Policy engine for quantum. Largely copied from nova.
|
|||||||
|
|
||||||
import os.path
|
import os.path
|
||||||
|
|
||||||
from quantum.common import config
|
from quantum.common.utils import find_config_file
|
||||||
from quantum.common import exceptions
|
from quantum.common import exceptions
|
||||||
from quantum.openstack.common import policy
|
from quantum.openstack.common import policy
|
||||||
|
|
||||||
@ -38,7 +38,7 @@ def reset():
|
|||||||
def init():
|
def init():
|
||||||
global _POLICY_PATH
|
global _POLICY_PATH
|
||||||
if not _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:
|
if not _POLICY_PATH:
|
||||||
raise exceptions.PolicyNotFound(path=FLAGS.policy_file)
|
raise exceptions.PolicyNotFound(path=FLAGS.policy_file)
|
||||||
with open(_POLICY_PATH) as f:
|
with open(_POLICY_PATH) as f:
|
||||||
|
@ -25,28 +25,19 @@ import sys
|
|||||||
|
|
||||||
from quantum import service
|
from quantum import service
|
||||||
from quantum.common import config
|
from quantum.common import config
|
||||||
|
from quantum.openstack.common import cfg
|
||||||
from quantum.version import version_string
|
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():
|
def main():
|
||||||
oparser = optparse.OptionParser(version='%prog ' + version_string())
|
# the configuration will be read into the cfg.CONF global data structure
|
||||||
create_options(oparser)
|
config.parse(sys.argv)
|
||||||
(options, args) = config.parse_options(oparser)
|
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:
|
try:
|
||||||
quantum_service = service.serve_wsgi(service.QuantumApiService,
|
quantum_service = service.serve_wsgi(service.QuantumApiService)
|
||||||
options=options,
|
|
||||||
args=args)
|
|
||||||
quantum_service.wait()
|
quantum_service.wait()
|
||||||
except RuntimeError, e:
|
except RuntimeError, e:
|
||||||
sys.exit("ERROR: %s" % e)
|
sys.exit("ERROR: %s" % e)
|
||||||
|
@ -18,7 +18,7 @@
|
|||||||
import logging
|
import logging
|
||||||
|
|
||||||
from quantum.common import config
|
from quantum.common import config
|
||||||
from quantum.common import exceptions as exception
|
from quantum.openstack.common import cfg
|
||||||
from quantum import wsgi
|
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.app_name = app_name
|
||||||
self.conf_file = conf_file
|
|
||||||
self.conf = conf
|
|
||||||
self.wsgi_app = None
|
self.wsgi_app = None
|
||||||
|
|
||||||
def start(self):
|
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):
|
def wait(self):
|
||||||
self.wsgi_app.wait()
|
self.wsgi_app.wait()
|
||||||
@ -51,13 +49,8 @@ class QuantumApiService(WsgiService):
|
|||||||
"""Class for quantum-api service."""
|
"""Class for quantum-api service."""
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def create(cls, conf=None, options=None, args=None):
|
def create(cls):
|
||||||
app_name = "quantum"
|
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
|
# Setup logging early, supplying both the CLI options and the
|
||||||
# configuration mapping from the config file
|
# configuration mapping from the config file
|
||||||
@ -65,32 +58,24 @@ class QuantumApiService(WsgiService):
|
|||||||
# flags. Everything else must be set up in the conf file...
|
# flags. Everything else must be set up in the conf file...
|
||||||
# Log the options used when starting if we're in debug mode...
|
# Log the options used when starting if we're in debug mode...
|
||||||
|
|
||||||
config.setup_logging(options, conf)
|
config.setup_logging(cfg.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
|
|
||||||
LOG.debug("*" * 80)
|
LOG.debug("*" * 80)
|
||||||
LOG.debug("Configuration options gathered from config file:")
|
LOG.debug("Configuration options gathered from config file:")
|
||||||
LOG.debug(conf_file)
|
|
||||||
LOG.debug("================================================")
|
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')])
|
if k not in ('__file__', 'here')])
|
||||||
for key, value in sorted(items.items()):
|
for key, value in sorted(items.items()):
|
||||||
LOG.debug("%(key)-30s %(value)s" % {'key': key,
|
LOG.debug("%(key)-30s %(value)s" % {'key': key,
|
||||||
'value': value,
|
'value': value,
|
||||||
})
|
})
|
||||||
LOG.debug("*" * 80)
|
LOG.debug("*" * 80)
|
||||||
service = cls(app_name, conf_file, conf)
|
service = cls(app_name)
|
||||||
return service
|
return service
|
||||||
|
|
||||||
|
|
||||||
def serve_wsgi(cls, conf=None, options=None, args=None):
|
def serve_wsgi(cls):
|
||||||
try:
|
try:
|
||||||
service = cls.create(conf, options, args)
|
service = cls.create()
|
||||||
except Exception:
|
except Exception:
|
||||||
logging.exception('in WsgiService.create()')
|
logging.exception('in WsgiService.create()')
|
||||||
raise
|
raise
|
||||||
@ -100,15 +85,11 @@ def serve_wsgi(cls, conf=None, options=None, args=None):
|
|||||||
return service
|
return service
|
||||||
|
|
||||||
|
|
||||||
def _run_wsgi(app_name, paste_conf, paste_config_file):
|
def _run_wsgi(app_name):
|
||||||
LOG.info(_('Using paste.deploy config at: %s'), paste_config_file)
|
app = config.load_paste_app(app_name, "quantum.conf")
|
||||||
conf, app = config.load_paste_app(app_name,
|
|
||||||
{'config_file': paste_config_file},
|
|
||||||
None)
|
|
||||||
if not app:
|
if not app:
|
||||||
LOG.error(_('No known API applications configured in %s.'),
|
LOG.error(_('No known API applications configured.'))
|
||||||
paste_config_file)
|
|
||||||
return
|
return
|
||||||
server = wsgi.Server("Quantum")
|
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
|
return server
|
||||||
|
@ -21,19 +21,30 @@ import logging
|
|||||||
import unittest2 as unittest
|
import unittest2 as unittest
|
||||||
|
|
||||||
import mock
|
import mock
|
||||||
|
import os
|
||||||
|
|
||||||
from quantum.api.api_common import APIFaultWrapper
|
from quantum.api.api_common import APIFaultWrapper
|
||||||
from quantum.api.networks import Controller
|
from quantum.api.networks import Controller
|
||||||
from quantum.common.test_lib import test_config
|
from quantum.common.test_lib import test_config
|
||||||
|
from quantum.common import config
|
||||||
from quantum.db import api as db
|
from quantum.db import api as db
|
||||||
from quantum.openstack.common import importutils
|
from quantum.openstack.common import importutils
|
||||||
import quantum.tests.unit.testlib_api as testlib
|
import quantum.tests.unit.testlib_api as testlib
|
||||||
|
from quantum.openstack.common import cfg
|
||||||
from quantum.wsgi import XMLDeserializer, JSONDeserializer
|
from quantum.wsgi import XMLDeserializer, JSONDeserializer
|
||||||
|
|
||||||
|
|
||||||
LOG = logging.getLogger('quantum.tests.test_api')
|
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"
|
NETS = "networks"
|
||||||
PORTS = "ports"
|
PORTS = "ports"
|
||||||
ATTS = "attachments"
|
ATTS = "attachments"
|
||||||
@ -105,10 +116,13 @@ class AbstractAPITest(unittest.TestCase):
|
|||||||
self.assertEqual(put_attachment_res.status_int, expected_res_status)
|
self.assertEqual(put_attachment_res.status_int, expected_res_status)
|
||||||
|
|
||||||
def setUp(self, api_router_klass, xml_metadata_dict):
|
def setUp(self, api_router_klass, xml_metadata_dict):
|
||||||
options = {}
|
# Create the default configurations
|
||||||
options['plugin_provider'] = test_config['plugin_name']
|
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)
|
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.tenant_id = "test_tenant"
|
||||||
self.network_name = "test_network"
|
self.network_name = "test_network"
|
||||||
|
|
||||||
@ -136,6 +150,7 @@ class AbstractAPITest(unittest.TestCase):
|
|||||||
"""Clear the test environment"""
|
"""Clear the test environment"""
|
||||||
# Remove database contents
|
# Remove database contents
|
||||||
db.clear_db()
|
db.clear_db()
|
||||||
|
cfg.CONF.reset()
|
||||||
|
|
||||||
|
|
||||||
class BaseAPIOperationsTest(AbstractAPITest):
|
class BaseAPIOperationsTest(AbstractAPITest):
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
# License for the spec
|
# License for the spec
|
||||||
|
|
||||||
|
import os
|
||||||
import logging
|
import logging
|
||||||
import unittest
|
import unittest
|
||||||
import uuid
|
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 resource as wsgi_resource
|
||||||
from quantum.api.v2 import router
|
from quantum.api.v2 import router
|
||||||
from quantum.api.v2 import views
|
from quantum.api.v2 import views
|
||||||
|
from quantum.common import config
|
||||||
|
from quantum.openstack.common import cfg
|
||||||
|
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
@ -34,6 +37,13 @@ LOG = logging.getLogger(__name__)
|
|||||||
def _uuid():
|
def _uuid():
|
||||||
return str(uuid.uuid4())
|
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):
|
def _get_path(resource, id=None, fmt=None):
|
||||||
path = '/%s' % resource
|
path = '/%s' % resource
|
||||||
@ -123,16 +133,23 @@ class APIv2TestCase(unittest.TestCase):
|
|||||||
# will get around this.
|
# will get around this.
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
plugin = 'quantum.quantum_plugin_base_v2.QuantumPluginBaseV2'
|
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_patcher = mock.patch(plugin, autospec=True)
|
||||||
self.plugin = self._plugin_patcher.start()
|
self.plugin = self._plugin_patcher.start()
|
||||||
|
|
||||||
api = router.APIRouter({'plugin_provider': plugin})
|
api = router.APIRouter()
|
||||||
self.api = webtest.TestApp(api)
|
self.api = webtest.TestApp(api)
|
||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
self._plugin_patcher.stop()
|
self._plugin_patcher.stop()
|
||||||
self.api = None
|
self.api = None
|
||||||
self.plugin = None
|
self.plugin = None
|
||||||
|
cfg.CONF.reset()
|
||||||
|
|
||||||
def test_verbose_attr(self):
|
def test_verbose_attr(self):
|
||||||
instance = self.plugin.return_value
|
instance = self.plugin.return_value
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
|
import os
|
||||||
import logging
|
import logging
|
||||||
import unittest
|
import unittest
|
||||||
import contextlib
|
import contextlib
|
||||||
@ -22,12 +23,21 @@ import quantum
|
|||||||
from quantum.api.v2.router import APIRouter
|
from quantum.api.v2.router import APIRouter
|
||||||
from quantum.common import exceptions as q_exc
|
from quantum.common import exceptions as q_exc
|
||||||
from quantum.db import api as db
|
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.tests.unit.testlib_api import create_request
|
||||||
from quantum.wsgi import Serializer, JSONDeserializer
|
from quantum.wsgi import Serializer, JSONDeserializer
|
||||||
|
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
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):
|
class QuantumDbPluginV2TestCase(unittest.TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
@ -46,7 +56,12 @@ class QuantumDbPluginV2TestCase(unittest.TestCase):
|
|||||||
}
|
}
|
||||||
|
|
||||||
plugin = 'quantum.db.db_base_plugin_v2.QuantumDbPluginV2'
|
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):
|
def tearDown(self):
|
||||||
super(QuantumDbPluginV2TestCase, self).tearDown()
|
super(QuantumDbPluginV2TestCase, self).tearDown()
|
||||||
@ -54,6 +69,7 @@ class QuantumDbPluginV2TestCase(unittest.TestCase):
|
|||||||
# doesn't like when the plugin changes ;)
|
# doesn't like when the plugin changes ;)
|
||||||
db._ENGINE = None
|
db._ENGINE = None
|
||||||
db._MAKER = None
|
db._MAKER = None
|
||||||
|
cfg.CONF.reset()
|
||||||
|
|
||||||
def _req(self, method, resource, data=None, fmt='json', id=None):
|
def _req(self, method, resource, data=None, fmt='json', id=None):
|
||||||
if id:
|
if id:
|
||||||
|
@ -14,6 +14,8 @@
|
|||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
import routes
|
import routes
|
||||||
@ -41,8 +43,15 @@ from quantum.tests.unit.extension_stubs import (
|
|||||||
import quantum.tests.unit.extensions
|
import quantum.tests.unit.extensions
|
||||||
from quantum import wsgi
|
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__)
|
extensions_path = ':'.join(quantum.tests.unit.extensions.__path__)
|
||||||
|
|
||||||
|
|
||||||
@ -455,8 +464,10 @@ def app_factory(global_conf, **local_conf):
|
|||||||
|
|
||||||
|
|
||||||
def setup_base_app():
|
def setup_base_app():
|
||||||
options = {'config_file': test_conf_file}
|
config_file = 'quantum.conf.test'
|
||||||
conf, app = config.load_paste_app('extensions_test_app', options, None)
|
args = ['--config-file', etcdir(config_file)]
|
||||||
|
config.parse(args=args)
|
||||||
|
app = config.load_paste_app('extensions_test_app', config_file)
|
||||||
return app
|
return app
|
||||||
|
|
||||||
|
|
||||||
@ -464,9 +475,11 @@ def setup_extensions_middleware(extension_manager=None):
|
|||||||
extension_manager = (extension_manager or
|
extension_manager = (extension_manager or
|
||||||
PluginAwareExtensionManager(extensions_path,
|
PluginAwareExtensionManager(extensions_path,
|
||||||
QuantumEchoPlugin()))
|
QuantumEchoPlugin()))
|
||||||
options = {'config_file': test_conf_file}
|
config_file = 'quantum.conf.test'
|
||||||
conf, app = config.load_paste_app('extensions_test_app', options, None)
|
args = ['--config-file', etcdir(config_file)]
|
||||||
return ExtensionMiddleware(app, conf, ext_mgr=extension_manager)
|
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):
|
def setup_extensions_test_app(extension_manager=None):
|
||||||
|
2
setup.py
2
setup.py
@ -51,7 +51,7 @@ ryu_plugin_config_path = 'etc/quantum/plugins/ryu'
|
|||||||
|
|
||||||
DataFiles = [
|
DataFiles = [
|
||||||
(config_path,
|
(config_path,
|
||||||
['etc/quantum.conf', 'etc/quantum.conf.test', 'etc/plugins.ini']),
|
['etc/quantum.conf']),
|
||||||
(init_path, ['etc/init.d/quantum-server']),
|
(init_path, ['etc/init.d/quantum-server']),
|
||||||
(ovs_plugin_config_path,
|
(ovs_plugin_config_path,
|
||||||
['etc/quantum/plugins/openvswitch/ovs_quantum_plugin.ini']),
|
['etc/quantum/plugins/openvswitch/ovs_quantum_plugin.ini']),
|
||||||
|
Loading…
Reference in New Issue
Block a user