diff --git a/ceilometer/storage/__init__.py b/ceilometer/storage/__init__.py index a40c57f822..56b4e463d1 100644 --- a/ceilometer/storage/__init__.py +++ b/ceilometer/storage/__init__.py @@ -23,14 +23,16 @@ import pkg_resources from ceilometer.openstack.common import log from ceilometer.openstack.common import cfg +from urlparse import urlparse + LOG = log.getLogger(__name__) STORAGE_ENGINE_NAMESPACE = 'ceilometer.storage' STORAGE_OPTS = [ - cfg.StrOpt('metering_storage_engine', - default='mongodb', - help='The name of the storage engine to use', + cfg.StrOpt('database_connection', + default='mongodb://localhost:27017/ceilometer', + help='Database connection string', ), ] @@ -48,7 +50,7 @@ def register_opts(conf): def get_engine(conf): """Load the configured engine and return an instance. """ - engine_name = conf.metering_storage_engine + engine_name = urlparse(conf.database_connection).scheme LOG.debug('looking for %r driver in %r', engine_name, STORAGE_ENGINE_NAMESPACE) for ep in pkg_resources.iter_entry_points(STORAGE_ENGINE_NAMESPACE, diff --git a/ceilometer/storage/impl_mongodb.py b/ceilometer/storage/impl_mongodb.py index 35c5af737b..2e9ced991d 100644 --- a/ceilometer/storage/impl_mongodb.py +++ b/ceilometer/storage/impl_mongodb.py @@ -27,6 +27,9 @@ from ceilometer.storage import base import bson.code import pymongo +import re + +from urlparse import urlparse LOG = log.getLogger(__name__) @@ -57,20 +60,7 @@ class MongoDBStorage(base.StorageEngine): } """ - OPTIONS = [ - cfg.StrOpt('mongodb_dbname', - default='ceilometer', - help='Database name', - ), - cfg.StrOpt('mongodb_host', - default='localhost', - help='hostname or IP of server running MongoDB', - ), - cfg.IntOpt('mongodb_port', - default=27017, - help='port number where MongoDB is running', - ), - ] + OPTIONS = [] def register_opts(self, conf): """Register any configuration options used by this engine. @@ -169,10 +159,12 @@ class Connection(base.Connection): """) def __init__(self, conf): - LOG.info('connecting to MongoDB on %s:%s', - conf.mongodb_host, conf.mongodb_port) - self.conn = self._get_connection(conf) - self.db = getattr(self.conn, conf.mongodb_dbname) + opts = self._parse_connection_url(conf.database_connection) + LOG.info('connecting to MongoDB on %s:%s', opts['host'], opts['port']) + self.conn = self._get_connection(opts) + self.db = getattr(self.conn, opts['dbname']) + if 'username' in opts: + self.db.authenticate(opts['username'], opts['password']) # Establish indexes # @@ -195,7 +187,7 @@ class Connection(base.Connection): ]) return - def _get_connection(self, conf): + def _get_connection(self, opts): """Return a connection to the database. .. note:: @@ -203,10 +195,25 @@ class Connection(base.Connection): The tests use a subclass to override this and return an in-memory connection. """ - return pymongo.Connection(conf.mongodb_host, - conf.mongodb_port, - safe=True, - ) + return pymongo.Connection(opts['host'], opts['port'], safe=True) + + def _parse_connection_url(self, url): + opts = {} + result = urlparse(url) + opts['dbtype'] = result.scheme + opts['dbname'] = result.path.replace('/', '') + netloc_match = re.match(r'(?:(\w+:\w+)@)?(.*)', result.netloc) + auth = netloc_match.group(1) + netloc = netloc_match.group(2) + if auth: + opts['username'], opts['password'] = auth.split(':') + if ':' in netloc: + opts['host'], port = netloc.split(':') + else: + opts['host'] = netloc + port = 27017 + opts['port'] = port and int(port) or 27017 + return opts def record_metering_data(self, data): """Write the data to the backend storage system. diff --git a/ceilometer/tests/api.py b/ceilometer/tests/api.py index 4348a6c475..be835fc68c 100644 --- a/ceilometer/tests/api.py +++ b/ceilometer/tests/api.py @@ -61,9 +61,7 @@ class TestBase(unittest.TestCase): self.test_app = self.app.test_client() self.conf = mock.Mock() self.conf.metering_storage_engine = 'mongodb' - self.conf.mongodb_host = 'localhost' - self.conf.mongodb_port = 27017 - self.conf.mongodb_dbname = self.DBNAME + self.conf.database_connection = 'mongodb://localhost/%s' % self.DBNAME self.conn = Connection(self.conf) self.conn.conn.drop_database(self.DBNAME) self.conn.conn[self.DBNAME] diff --git a/tests/storage/test_get_engine.py b/tests/storage/test_get_engine.py index 984b7e1361..951ae03a85 100644 --- a/tests/storage/test_get_engine.py +++ b/tests/storage/test_get_engine.py @@ -26,14 +26,14 @@ from ceilometer.storage import impl_log def test_get_engine(): conf = mox.Mox().CreateMockAnything() - conf.metering_storage_engine = 'log' + conf.database_connection = 'log://localhost' engine = storage.get_engine(conf) assert isinstance(engine, impl_log.LogStorage) def test_get_engine_no_such_engine(): conf = mox.Mox().CreateMockAnything() - conf.metering_storage_engine = 'no-such-engine' + conf.database_connection = 'no-such-engine://localhost' try: storage.get_engine(conf) except RuntimeError as err: diff --git a/tests/storage/test_impl_mongodb.py b/tests/storage/test_impl_mongodb.py index d37e73a81b..12c672e9a7 100644 --- a/tests/storage/test_impl_mongodb.py +++ b/tests/storage/test_impl_mongodb.py @@ -89,13 +89,10 @@ class MongoDBEngineTestBase(unittest.TestCase): super(MongoDBEngineTestBase, self).setUp() self.conf = mox.Mox().CreateMockAnything() - self.conf.metering_storage_engine = 'mongodb' - self.conf.mongodb_host = 'localhost' - self.conf.mongodb_port = 27017 - self.conf.mongodb_dbname = 'testdb' + self.conf.database_connection = 'mongodb://localhost/testdb' self.conn = Connection(self.conf) - self.conn.conn.drop_database(self.conf.mongodb_dbname) - self.db = self.conn.conn[self.conf.mongodb_dbname] + self.conn.conn.drop_database('testdb') + self.db = self.conn.conn['testdb'] self.conn.db = self.db self.counter = counter.Counter(