fix(bootstrap): Logging CLI options don't work

In the current implementation, Bootstrap creates the config option
inside its initializer. That means that common options such as
those registered by openstack.common.log, are not registered.

This patch modifies the Bootstrap initializer to take a config
instance from the caller, rather than trying to build one
itself. This does two things for us:

1. Avoids "magic" marconi configuration; the caller has full
   control and visibility into how marconi is configured.
2. Allows for passing in the global CONF object from the
   marconi-server command and the reference WSGI app module
   so that common options registered by oslo modules on the
   global CONF instance are picked up.

Hopefully openstack.common.log will be modified at some point
so that it isn't tightly coupled with cfg.CONF.

Implements: blueprint remove-global-config
Change-Id: Ibb6638f99ca2ce4a2a6025f6cd41939bb30fa85a
This commit is contained in:
kgriffs 2013-10-16 15:12:32 -05:00
parent e0892978cd
commit e6f42d55f8
6 changed files with 47 additions and 45 deletions

View File

@ -13,7 +13,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
import sys
from oslo.config import cfg
from marconi.common import cli
from marconi.queues import bootstrap
@ -21,5 +21,11 @@ from marconi.queues import bootstrap
@cli.runnable
def run():
server = bootstrap.Bootstrap(cli_args=sys.argv[1:])
# TODO(kgriffs): For now, we have to use the global config
# to pick up common options from openstack.common.log, since
# that module uses the global CONF instance exclusively.
conf = cfg.CONF
conf(project='marconi', prog='marconi-queues')
server = bootstrap.Bootstrap(conf)
server.run()

View File

@ -48,19 +48,12 @@ class Bootstrap(object):
manages their lifetimes.
"""
def __init__(self, config_file=None, cli_args=None):
default_file = None
if config_file is not None:
default_file = [config_file]
self.conf = cfg.ConfigOpts()
def __init__(self, conf):
self.conf = conf
self.conf.register_opts(_GENERAL_OPTIONS)
self.conf.register_opts(_DRIVER_OPTIONS, group=_DRIVER_GROUP)
self.driver_conf = self.conf[_DRIVER_GROUP]
self.conf(project='marconi', prog='marconi-queues',
args=cli_args or [], default_config_files=default_file)
log.setup('marconi')
@decorators.lazy_property(write=False)

View File

@ -26,6 +26,14 @@ no common way to specify / pass configuration files
to the WSGI app when it is called from other apps.
"""
from oslo.config import cfg
from marconi.queues import bootstrap
app = bootstrap.Bootstrap().transport.app
# TODO(kgriffs): For now, we have to use the global config
# to pick up common options from openstack.common.log, since
# that module uses the global CONF instance exclusively.
conf = cfg.CONF
conf(project='marconi', prog='marconi-queues', args=[])
app = bootstrap.Bootstrap(conf).transport.app

View File

@ -46,13 +46,13 @@ class FunctionalTestBase(testing.TestBase):
if not self.cfg.run_tests:
self.skipTest("Functional tests disabled")
self.mconf = self.load_conf(self.cfg.marconi.config)
# NOTE(flaper87): Use running instances.
if (self.cfg.marconi.run_server and not
self.server):
self.server = self.server_class()
self.server.start(self.conf_path(self.cfg.marconi.config))
self.mconf = self.load_conf(self.cfg.marconi.config)
self.server.start(self.mconf)
validator = validation.Validator(self.mconf)
self.limits = validator._limits_conf
@ -124,28 +124,28 @@ class Server(object):
self.process = None
@abc.abstractmethod
def get_target(self, config_file):
def get_target(self, conf):
"""Prepares the target object
This method is meant to initialize server's
bootstrap and return a callable to run the
server.
:param config_file: The configuration file
for the bootstrap class
:returns: A callable object.
:param conf: The config instance for the
bootstrap class
:returns: A callable object
"""
def start(self, config_file):
def start(self, conf):
"""Starts the server process.
:param config_file: The configuration file
to use for the new process
:param conf: The config instance to use for
the new process
:returns: A `multiprocessing.Process` instance
"""
# TODO(flaper87): Re-use running instances.
target = self.get_target(config_file)
target = self.get_target(conf)
if not callable(target):
raise RuntimeError("Target not callable")
@ -175,6 +175,6 @@ class MarconiServer(Server):
name = "marconi-wsgiref-test-server"
def get_target(self, config_file):
server = bootstrap.Bootstrap(config_file)
def get_target(self, conf):
server = bootstrap.Bootstrap(conf)
return server.run

View File

@ -33,11 +33,13 @@ class TestBase(testing.TestBase):
super(TestBase, self).setUp()
conf_file = self.conf_path(self.config_filename)
self.boot = marconi.Bootstrap(conf_file)
self.boot.conf.register_opts(driver._WSGI_OPTIONS,
group=driver._WSGI_GROUP)
self.wsgi_cfg = self.boot.conf[driver._WSGI_GROUP]
conf = cfg.ConfigOpts()
conf(default_config_files=[self.conf_path(self.config_filename)])
conf.register_opts(driver._WSGI_OPTIONS,
group=driver._WSGI_GROUP)
self.wsgi_cfg = conf[driver._WSGI_GROUP]
self.boot = marconi.Bootstrap(conf)
self.app = self.boot.transport.app
self.srmock = ftest.StartResponseMock()

View File

@ -13,8 +13,6 @@
# See the License for the specific language governing permissions and
# limitations under the License.
from oslo.config import cfg
from marconi.common import exceptions
import marconi.queues
from marconi.queues.storage import pipeline
@ -26,35 +24,30 @@ from marconi.tests import base
class TestBootstrap(base.TestBase):
def test_config_missing(self):
self.assertRaises(cfg.ConfigFilesNotFoundError, marconi.Bootstrap, '')
def _bootstrap(self, conf_file):
conf = self.load_conf(conf_file)
return marconi.Bootstrap(conf)
def test_storage_invalid(self):
conf_file = 'etc/drivers_storage_invalid.conf'
bootstrap = marconi.Bootstrap(conf_file)
bootstrap = self._bootstrap('etc/drivers_storage_invalid.conf')
self.assertRaises(exceptions.InvalidDriver,
lambda: bootstrap.storage)
def test_storage_sqlite(self):
conf_file = 'etc/wsgi_sqlite.conf'
bootstrap = marconi.Bootstrap(conf_file)
bootstrap = self._bootstrap('etc/wsgi_sqlite.conf')
self.assertIsInstance(bootstrap.storage, pipeline.Driver)
self.assertIsInstance(bootstrap.storage._storage, sqlite.Driver)
def test_storage_sqlite_sharded(self):
"""Makes sure we can load the shard driver."""
conf_file = 'etc/wsgi_sqlite_sharded.conf'
bootstrap = marconi.Bootstrap(conf_file)
bootstrap = self._bootstrap('etc/wsgi_sqlite_sharded.conf')
self.assertIsInstance(bootstrap.storage._storage, sharding.Driver)
def test_transport_invalid(self):
conf_file = 'etc/drivers_transport_invalid.conf'
bootstrap = marconi.Bootstrap(conf_file)
bootstrap = self._bootstrap('etc/drivers_transport_invalid.conf')
self.assertRaises(exceptions.InvalidDriver,
lambda: bootstrap.transport)
def test_transport_wsgi(self):
bootstrap = marconi.Bootstrap('etc/wsgi_sqlite.conf')
bootstrap = self._bootstrap('etc/wsgi_sqlite.conf')
self.assertIsInstance(bootstrap.transport, wsgi.Driver)