Enable Ceilometer to support mongodb replication set

At present, ceilometer does not support mongodb replication set.
As a result, when the primary mongod node is down, ceilometer can
not write or read meters.

Use pymongo.Connection object's replicaSet param and allowing to connect
with a host seed list will let the mongodb connection support replication set.

Change-Id: I8404ca5b08b6e73366161c07b3815f75bed7e0eb
Fixes: Bug 1188649
This commit is contained in:
xingzhou 2013-06-20 04:37:58 -04:00
parent 04bbab3971
commit a2b6dc4ed2

View File

@ -32,11 +32,12 @@ import bson.code
import bson.objectid import bson.objectid
import pymongo import pymongo
from oslo.config import cfg
from ceilometer.openstack.common import log from ceilometer.openstack.common import log
from ceilometer.storage import base from ceilometer.storage import base
from ceilometer.storage import models from ceilometer.storage import models
LOG = log.getLogger(__name__) LOG = log.getLogger(__name__)
@ -66,13 +67,26 @@ class MongoDBStorage(base.StorageEngine):
} }
""" """
OPTIONS = [] OPTIONS = [
cfg.StrOpt('replica_set_name',
default='',
help='Used to identify the replication set name',
),
]
OPTION_GROUP = cfg.OptGroup(name='storage_mongodb',
title='Options for the mongodb storage')
def register_opts(self, conf): def register_opts(self, conf):
"""Register any configuration options used by this engine. """Register any configuration options used by this engine.
""" """
conf.register_opts(self.OPTIONS) conf.register_group(self.OPTION_GROUP)
conf.register_opts(self.OPTIONS, self.OPTION_GROUP)
# FIXME(xingzhou): ceilometer-api will create a Connection object for
# each request. As pymongo.Connection has already maintained a db
# connection pool for client, it is better to use a cached Connection
# object to connect to mongodb.
def get_connection(self, conf): def get_connection(self, conf):
"""Return a Connection instance based on the configuration settings. """Return a Connection instance based on the configuration settings.
""" """
@ -197,15 +211,15 @@ class Connection(base.Connection):
def __init__(self, conf): def __init__(self, conf):
opts = self._parse_connection_url(conf.database.connection) opts = self._parse_connection_url(conf.database.connection)
LOG.info('connecting to MongoDB on %s:%s', opts['host'], opts['port']) LOG.info('connecting to MongoDB replicaset "%s" on %s',
conf.storage_mongodb.replica_set_name,
opts['netloc'])
if opts['host'] == '__test__': if opts['netloc'] == '__test__':
url = os.environ.get('CEILOMETER_TEST_MONGODB_URL') url = os.environ.get('CEILOMETER_TEST_MONGODB_URL')
if url: if url:
opts = self._parse_connection_url(url) opts = self._parse_connection_url(url)
self.conn = pymongo.Connection(opts['host'], self.conn = pymongo.Connection(opts['netloc'], safe=True)
opts['port'],
safe=True)
else: else:
# MIM will die if we have too many connections, so use a # MIM will die if we have too many connections, so use a
# Singleton # Singleton
@ -220,9 +234,10 @@ class Connection(base.Connection):
self.conn = Connection._mim_instance self.conn = Connection._mim_instance
LOG.debug('Using MIM for test connection') LOG.debug('Using MIM for test connection')
else: else:
self.conn = pymongo.Connection(opts['host'], self.conn = pymongo.Connection(
opts['port'], opts['netloc'],
safe=True) replicaSet=conf.storage_mongodb.replica_set_name,
safe=True)
self.db = getattr(self.conn, opts['dbname']) self.db = getattr(self.conn, opts['dbname'])
if 'username' in opts: if 'username' in opts:
@ -269,15 +284,9 @@ class Connection(base.Connection):
opts['dbname'] = result.path.replace('/', '') opts['dbname'] = result.path.replace('/', '')
netloc_match = re.match(r'(?:(\w+:\w+)@)?(.*)', result.netloc) netloc_match = re.match(r'(?:(\w+:\w+)@)?(.*)', result.netloc)
auth = netloc_match.group(1) auth = netloc_match.group(1)
netloc = netloc_match.group(2) opts['netloc'] = netloc_match.group(2)
if auth: if auth:
opts['username'], opts['password'] = auth.split(':') 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 return opts
def record_metering_data(self, data): def record_metering_data(self, data):