mirror of
https://github.com/bigchaindb/bigchaindb.git
synced 2024-10-13 13:34:05 +00:00
Solution: Remove un-necessary code. Deployment of MongoDB with or without replicaSet should be the responsibility of MongoDB admin which can and cannot be a BigchainDB node operator. As far as BigchainDB is concerned replicaset, if provided in bigchaindb configs, should be used to establish connection with MongoDB.
136 lines
5.9 KiB
Python
136 lines
5.9 KiB
Python
# Copyright BigchainDB GmbH and BigchainDB contributors
|
|
# SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0)
|
|
# Code is Apache-2.0 and docs are CC-BY-4.0
|
|
|
|
import logging
|
|
from ssl import CERT_REQUIRED
|
|
|
|
import pymongo
|
|
|
|
import bigchaindb
|
|
from bigchaindb.utils import Lazy
|
|
from bigchaindb.common.exceptions import ConfigurationError
|
|
from bigchaindb.backend.exceptions import (DuplicateKeyError,
|
|
OperationError,
|
|
ConnectionError)
|
|
from bigchaindb.backend.connection import Connection
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
class LocalMongoDBConnection(Connection):
|
|
|
|
def __init__(self, replicaset=None, ssl=None, login=None, password=None,
|
|
ca_cert=None, certfile=None, keyfile=None,
|
|
keyfile_passphrase=None, crlfile=None, **kwargs):
|
|
"""Create a new Connection instance.
|
|
|
|
Args:
|
|
replicaset (str, optional): the name of the replica set to
|
|
connect to.
|
|
**kwargs: arbitrary keyword arguments provided by the
|
|
configuration's ``database`` settings
|
|
"""
|
|
|
|
super().__init__(**kwargs)
|
|
self.replicaset = replicaset or bigchaindb.config['database'].get('replicaset')
|
|
self.ssl = ssl if ssl is not None else bigchaindb.config['database'].get('ssl', False)
|
|
self.login = login or bigchaindb.config['database'].get('login')
|
|
self.password = password or bigchaindb.config['database'].get('password')
|
|
self.ca_cert = ca_cert or bigchaindb.config['database'].get('ca_cert', None)
|
|
self.certfile = certfile or bigchaindb.config['database'].get('certfile', None)
|
|
self.keyfile = keyfile or bigchaindb.config['database'].get('keyfile', None)
|
|
self.keyfile_passphrase = keyfile_passphrase or bigchaindb.config['database'].get('keyfile_passphrase', None)
|
|
self.crlfile = crlfile or bigchaindb.config['database'].get('crlfile', None)
|
|
|
|
@property
|
|
def db(self):
|
|
return self.conn[self.dbname]
|
|
|
|
def query(self):
|
|
return Lazy()
|
|
|
|
def collection(self, name):
|
|
"""Return a lazy object that can be used to compose a query.
|
|
|
|
Args:
|
|
name (str): the name of the collection to query.
|
|
"""
|
|
return self.query()[self.dbname][name]
|
|
|
|
def run(self, query):
|
|
try:
|
|
try:
|
|
return query.run(self.conn)
|
|
except pymongo.errors.AutoReconnect as exc:
|
|
logger.warning('Lost connection to the database, '
|
|
'retrying query.')
|
|
return query.run(self.conn)
|
|
except pymongo.errors.AutoReconnect as exc:
|
|
raise ConnectionError from exc
|
|
except pymongo.errors.DuplicateKeyError as exc:
|
|
raise DuplicateKeyError from exc
|
|
except pymongo.errors.OperationFailure as exc:
|
|
print(f'DETAILS: {exc.details}')
|
|
raise OperationError from exc
|
|
|
|
def _connect(self):
|
|
"""Try to connect to the database.
|
|
|
|
Raises:
|
|
:exc:`~ConnectionError`: If the connection to the database
|
|
fails.
|
|
:exc:`~AuthenticationError`: If there is a OperationFailure due to
|
|
Authentication failure after connecting to the database.
|
|
:exc:`~ConfigurationError`: If there is a ConfigurationError while
|
|
connecting to the database.
|
|
"""
|
|
|
|
try:
|
|
# FYI: the connection process might raise a
|
|
# `ServerSelectionTimeoutError`, that is a subclass of
|
|
# `ConnectionFailure`.
|
|
# The presence of ca_cert, certfile, keyfile, crlfile implies the
|
|
# use of certificates for TLS connectivity.
|
|
if self.ca_cert is None or self.certfile is None or \
|
|
self.keyfile is None or self.crlfile is None:
|
|
client = pymongo.MongoClient(self.host,
|
|
self.port,
|
|
replicaset=self.replicaset,
|
|
serverselectiontimeoutms=self.connection_timeout,
|
|
ssl=self.ssl,
|
|
**MONGO_OPTS)
|
|
if self.login is not None and self.password is not None:
|
|
client[self.dbname].authenticate(self.login, self.password)
|
|
else:
|
|
logger.info('Connecting to MongoDB over TLS/SSL...')
|
|
client = pymongo.MongoClient(self.host,
|
|
self.port,
|
|
replicaset=self.replicaset,
|
|
serverselectiontimeoutms=self.connection_timeout,
|
|
ssl=self.ssl,
|
|
ssl_ca_certs=self.ca_cert,
|
|
ssl_certfile=self.certfile,
|
|
ssl_keyfile=self.keyfile,
|
|
ssl_pem_passphrase=self.keyfile_passphrase,
|
|
ssl_crlfile=self.crlfile,
|
|
ssl_cert_reqs=CERT_REQUIRED,
|
|
**MONGO_OPTS)
|
|
if self.login is not None:
|
|
client[self.dbname].authenticate(self.login,
|
|
mechanism='MONGODB-X509')
|
|
|
|
return client
|
|
|
|
except (pymongo.errors.ConnectionFailure,
|
|
pymongo.errors.OperationFailure) as exc:
|
|
logger.info('Exception in _connect(): {}'.format(exc))
|
|
raise ConnectionError(str(exc)) from exc
|
|
except pymongo.errors.ConfigurationError as exc:
|
|
raise ConfigurationError from exc
|
|
|
|
|
|
MONGO_OPTS = {
|
|
'socketTimeoutMS': 20000,
|
|
}
|