Migrate to stevedore
Use stevedore to load both transport and storage drivers. It will allow other users to extend Marconi with their own storages / transports more easily. Stevedore also covers most of the cases around managing plugins. Change-Id: Ic417c29cef41bdb72c8c446937905509db5ba8cd
This commit is contained in:
parent
13470f4b2f
commit
2bba034d67
@ -13,18 +13,19 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from stevedore import driver
|
||||
|
||||
from marconi.common import config
|
||||
from marconi.common import decorators
|
||||
from marconi.common import exceptions
|
||||
from marconi.openstack.common import importutils
|
||||
from marconi.openstack.common import log
|
||||
from marconi import transport # NOQA.
|
||||
|
||||
|
||||
cfg_handle = config.project('marconi')
|
||||
cfg = config.namespace('drivers').from_options(
|
||||
transport='marconi.transport.wsgi',
|
||||
storage='marconi.storage.sqlite')
|
||||
transport='wsgi',
|
||||
storage='sqlite')
|
||||
|
||||
LOG = log.getLogger(__name__)
|
||||
|
||||
@ -42,25 +43,26 @@ class Bootstrap(object):
|
||||
|
||||
@decorators.lazy_property(write=False)
|
||||
def storage(self):
|
||||
msg = _("Loading Storage Driver")
|
||||
LOG.debug(msg)
|
||||
storage_module = import_driver(cfg.storage)
|
||||
return storage_module.Driver()
|
||||
LOG.debug(_("Loading Storage Driver"))
|
||||
try:
|
||||
mgr = driver.DriverManager('marconi.storage',
|
||||
cfg.storage,
|
||||
invoke_on_load=True)
|
||||
return mgr.driver
|
||||
except RuntimeError as exc:
|
||||
raise exceptions.InvalidDriver(exc)
|
||||
|
||||
@decorators.lazy_property(write=False)
|
||||
def transport(self):
|
||||
msg = _("Loading Transport Driver")
|
||||
LOG.debug(msg)
|
||||
transport_module = import_driver(cfg.transport)
|
||||
return transport_module.Driver(self.storage)
|
||||
LOG.debug(_("Loading Transport Driver"))
|
||||
try:
|
||||
mgr = driver.DriverManager('marconi.transport',
|
||||
cfg.transport,
|
||||
invoke_on_load=True,
|
||||
invoke_args=[self.storage])
|
||||
return mgr.driver
|
||||
except RuntimeError as exc:
|
||||
raise exceptions.InvalidDriver(exc)
|
||||
|
||||
def run(self):
|
||||
self.transport.listen()
|
||||
|
||||
|
||||
def import_driver(module_name):
|
||||
try:
|
||||
return importutils.import_module(module_name)
|
||||
except ImportError:
|
||||
raise exceptions.InvalidDriver(
|
||||
'No module named %s' % module_name)
|
||||
|
@ -1,67 +0,0 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2011 OpenStack Foundation.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
"""
|
||||
Import related utilities and helper functions.
|
||||
"""
|
||||
|
||||
import sys
|
||||
import traceback
|
||||
|
||||
|
||||
def import_class(import_str):
|
||||
"""Returns a class from a string including module and class"""
|
||||
mod_str, _sep, class_str = import_str.rpartition('.')
|
||||
try:
|
||||
__import__(mod_str)
|
||||
return getattr(sys.modules[mod_str], class_str)
|
||||
except (ValueError, AttributeError):
|
||||
raise ImportError('Class %s cannot be found (%s)' %
|
||||
(class_str,
|
||||
traceback.format_exception(*sys.exc_info())))
|
||||
|
||||
|
||||
def import_object(import_str, *args, **kwargs):
|
||||
"""Import a class and return an instance of it."""
|
||||
return import_class(import_str)(*args, **kwargs)
|
||||
|
||||
|
||||
def import_object_ns(name_space, import_str, *args, **kwargs):
|
||||
"""
|
||||
Import a class and return an instance of it, first by trying
|
||||
to find the class in a default namespace, then failing back to
|
||||
a full path if not found in the default namespace.
|
||||
"""
|
||||
import_value = "%s.%s" % (name_space, import_str)
|
||||
try:
|
||||
return import_class(import_value)(*args, **kwargs)
|
||||
except ImportError:
|
||||
return import_class(import_str)(*args, **kwargs)
|
||||
|
||||
|
||||
def import_module(import_str):
|
||||
"""Import a module."""
|
||||
__import__(import_str)
|
||||
return sys.modules[import_str]
|
||||
|
||||
|
||||
def try_import(import_str, default=None):
|
||||
"""Try to import a module and if it fails return default."""
|
||||
try:
|
||||
return import_module(import_str)
|
||||
except ImportError:
|
||||
return default
|
@ -1,5 +1,9 @@
|
||||
[DEFAULT]
|
||||
debug = False
|
||||
verbose = False
|
||||
|
||||
[drivers]
|
||||
transport = marconi.transport.wsgi
|
||||
transport = wsgi
|
||||
storage = invalid
|
||||
|
||||
[drivers:transport:wsgi]
|
||||
|
@ -1,6 +1,10 @@
|
||||
[DEFAULT]
|
||||
debug = False
|
||||
verbose = False
|
||||
|
||||
[drivers]
|
||||
transport = invalid
|
||||
storage = marconi.storage.sqlite
|
||||
storage = sqlite
|
||||
|
||||
[drivers:transport:wsgi]
|
||||
port = 8888
|
||||
|
@ -1,10 +1,12 @@
|
||||
[DEFAULT]
|
||||
auth_strategy = keystone
|
||||
|
||||
debug = False
|
||||
verbose = False
|
||||
|
||||
[drivers]
|
||||
transport = marconi.transport.wsgi
|
||||
storage = marconi.storage.sqlite
|
||||
transport = wsgi
|
||||
storage = sqlite
|
||||
|
||||
[drivers:transport:wsgi]
|
||||
bind = 0.0.0.0:8888
|
||||
|
@ -1,6 +1,10 @@
|
||||
[DEFAULT]
|
||||
debug = False
|
||||
verbose = False
|
||||
|
||||
[drivers]
|
||||
transport = marconi.transport.wsgi
|
||||
storage = marconi.tests.util.faulty_storage
|
||||
transport = wsgi
|
||||
storage = sqlite
|
||||
|
||||
[drivers:transport:wsgi]
|
||||
port = 8888
|
||||
|
@ -1,6 +1,10 @@
|
||||
[DEFAULT]
|
||||
debug = False
|
||||
verbose = False
|
||||
|
||||
[drivers]
|
||||
transport = marconi.transport.wsgi
|
||||
storage = marconi.storage.mongodb
|
||||
transport = wsgi
|
||||
storage = mongodb
|
||||
|
||||
[drivers:transport:wsgi]
|
||||
port = 8888
|
||||
|
@ -1,6 +1,10 @@
|
||||
[DEFAULT]
|
||||
debug = False
|
||||
verbose = False
|
||||
|
||||
[drivers]
|
||||
transport = marconi.transport.wsgi
|
||||
storage = marconi.storage.sqlite
|
||||
transport = wsgi
|
||||
storage = sqlite
|
||||
|
||||
[drivers:transport:wsgi]
|
||||
bind = 0.0.0.0
|
||||
|
@ -18,6 +18,7 @@ from falcon import testing
|
||||
|
||||
import marconi
|
||||
from marconi.tests import util
|
||||
from marconi.tests.util import faulty_storage
|
||||
|
||||
|
||||
class TestBase(util.TestBase):
|
||||
@ -35,3 +36,16 @@ class TestBase(util.TestBase):
|
||||
|
||||
self.app = boot.transport.app
|
||||
self.srmock = testing.StartResponseMock()
|
||||
|
||||
|
||||
class TestBaseFaulty(TestBase):
|
||||
|
||||
def setUp(self):
|
||||
self._storage_backup = marconi.Bootstrap.storage
|
||||
faulty = faulty_storage.Driver()
|
||||
setattr(marconi.Bootstrap, "storage", faulty)
|
||||
super(TestBaseFaulty, self).setUp()
|
||||
|
||||
def tearDown(self):
|
||||
setattr(marconi.Bootstrap, "storage", self._storage_backup)
|
||||
super(TestBaseFaulty, self).tearDown()
|
||||
|
@ -220,7 +220,7 @@ class ClaimsSQLiteTests(ClaimsBaseTest):
|
||||
config_filename = 'wsgi_sqlite.conf'
|
||||
|
||||
|
||||
class ClaimsFaultyDriverTests(base.TestBase):
|
||||
class ClaimsFaultyDriverTests(base.TestBaseFaulty):
|
||||
|
||||
config_filename = 'wsgi_faulty.conf'
|
||||
|
||||
|
@ -244,7 +244,7 @@ class MessagesMongoDBTests(MessagesBaseTest):
|
||||
super(MessagesMongoDBTests, self).setUp()
|
||||
|
||||
|
||||
class MessagesFaultyDriverTests(base.TestBase):
|
||||
class MessagesFaultyDriverTests(base.TestBaseFaulty):
|
||||
|
||||
config_filename = 'wsgi_faulty.conf'
|
||||
|
||||
|
@ -230,7 +230,7 @@ class QueueLifecycleSQLiteTests(QueueLifecycleBaseTest):
|
||||
config_filename = 'wsgi_sqlite.conf'
|
||||
|
||||
|
||||
class QueueFaultyDriverTests(base.TestBase):
|
||||
class QueueFaultyDriverTests(base.TestBaseFaulty):
|
||||
|
||||
config_filename = 'wsgi_faulty.conf'
|
||||
|
||||
|
@ -13,6 +13,7 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import fixtures
|
||||
import os
|
||||
import testtools
|
||||
|
||||
@ -29,6 +30,16 @@ class TestBase(testtools.TestCase):
|
||||
test method.
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
super(TestBase, self).setUp()
|
||||
self.useFixture(fixtures.FakeLogger('marconi'))
|
||||
|
||||
stdout = self.useFixture(fixtures.StringStream('stdout')).stream
|
||||
self.useFixture(fixtures.MonkeyPatch('sys.stdout', stdout))
|
||||
|
||||
stderr = self.useFixture(fixtures.StringStream('stderr')).stream
|
||||
self.useFixture(fixtures.MonkeyPatch('sys.stderr', stderr))
|
||||
|
||||
def conf_path(self, filename):
|
||||
"""Returns the full path to the specified Marconi conf file.
|
||||
|
||||
|
@ -10,3 +10,4 @@ pymongo
|
||||
python-keystoneclient
|
||||
simplejson
|
||||
WebOb
|
||||
stevedore>=0.9
|
||||
|
@ -27,8 +27,15 @@ setup-hooks =
|
||||
|
||||
[entry_points]
|
||||
console_scripts =
|
||||
marconi-server = marconi.cmd.server:run
|
||||
marconi-gc = marconi.cmd.gc:run
|
||||
marconi-server = marconi.cmd.server:run
|
||||
|
||||
marconi.storage =
|
||||
sqlite = marconi.storage.sqlite.driver:Driver
|
||||
mongodb = marconi.storage.mongodb.driver:Driver
|
||||
|
||||
marconi.transport =
|
||||
wsgi = marconi.transport.wsgi.driver:Driver
|
||||
|
||||
[nosetests]
|
||||
where=marconi/tests
|
||||
|
Loading…
x
Reference in New Issue
Block a user