mirror of
https://github.com/planetmint/planetmint.git
synced 2025-11-25 06:55:45 +00:00
new structure of connections
This commit is contained in:
parent
3ab1922dba
commit
7e5e4c3102
@ -14,4 +14,4 @@ configuration or the ``PLANETMINT_DATABASE_BACKEND`` environment variable.
|
|||||||
# Include the backend interfaces
|
# Include the backend interfaces
|
||||||
from planetmint.backend import schema, query # noqa
|
from planetmint.backend import schema, query # noqa
|
||||||
|
|
||||||
from planetmint.backend.connection_tarantool import connect # noqa
|
from planetmint.backend.connection import Connection
|
||||||
|
|||||||
@ -3,168 +3,29 @@
|
|||||||
# SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0)
|
# SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0)
|
||||||
# Code is Apache-2.0 and docs are CC-BY-4.0
|
# Code is Apache-2.0 and docs are CC-BY-4.0
|
||||||
|
|
||||||
|
import sys
|
||||||
import logging
|
import logging
|
||||||
from importlib import import_module
|
from importlib import import_module
|
||||||
from itertools import repeat
|
from itertools import repeat
|
||||||
|
|
||||||
import planetmint
|
|
||||||
from planetmint.backend.exceptions import ConnectionError
|
from planetmint.backend.exceptions import ConnectionError
|
||||||
from planetmint.backend.utils import get_planetmint_config_value, get_planetmint_config_value_or_key_error
|
from planetmint.backend.utils import get_planetmint_config_value, get_planetmint_config_value_or_key_error
|
||||||
from planetmint.common.exceptions import ConfigurationError
|
from planetmint.common.exceptions import ConfigurationError
|
||||||
|
|
||||||
BACKENDS = { # This is path to MongoDBClass
|
BACKENDS = { # This is path to MongoDBClass
|
||||||
'localmongodb': 'planetmint.backend.localmongodb.connection.LocalMongoDBConnection',
|
'tarantool_db': 'planetmint.backend.tarantool.connection.TarantoolDB',
|
||||||
|
'localmongodb': 'planetmint.backend.localmongodb.connection.LocalMongoDBConnection'
|
||||||
}
|
}
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
def connect(backend=None, host=None, port=None, name=None, max_tries=None,
|
modulename = sys.modules[__name__]
|
||||||
connection_timeout=None, replicaset=None, ssl=None, login=None, password=None,
|
backend = get_planetmint_config_value("backend")
|
||||||
ca_cert=None, certfile=None, keyfile=None, keyfile_passphrase=None,
|
current_backend = getattr(modulename, BACKENDS[backend])
|
||||||
crlfile=None):
|
|
||||||
"""Create a new connection to the database backend.
|
|
||||||
|
|
||||||
All arguments default to the current configuration's values if not
|
|
||||||
given.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
backend (str): the name of the backend to use.
|
|
||||||
host (str): the host to connect to.
|
|
||||||
port (int): the port to connect to.
|
|
||||||
name (str): the name of the database to use.
|
|
||||||
replicaset (str): the name of the replica set (only relevant for
|
|
||||||
MongoDB connections).
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
An instance of :class:`~planetmint.backend.connection.Connection`
|
|
||||||
based on the given (or defaulted) :attr:`backend`.
|
|
||||||
|
|
||||||
Raises:
|
|
||||||
:exc:`~ConnectionError`: If the connection to the database fails.
|
|
||||||
:exc:`~ConfigurationError`: If the given (or defaulted) :attr:`backend`
|
|
||||||
is not supported or could not be loaded.
|
|
||||||
:exc:`~AuthenticationError`: If there is a OperationFailure due to
|
|
||||||
Authentication failure after connecting to the database.
|
|
||||||
"""
|
|
||||||
|
|
||||||
backend = backend or get_planetmint_config_value_or_key_error('backend')
|
|
||||||
host = host or get_planetmint_config_value_or_key_error('host')
|
|
||||||
port = port or get_planetmint_config_value_or_key_error('port')
|
|
||||||
dbname = name or get_planetmint_config_value_or_key_error('name')
|
|
||||||
# Not sure how to handle this here. This setting is only relevant for
|
|
||||||
# mongodb.
|
|
||||||
# I added **kwargs for both RethinkDBConnection and MongoDBConnection
|
|
||||||
# to handle these these additional args. In case of RethinkDBConnection
|
|
||||||
# it just does not do anything with it.
|
|
||||||
#
|
|
||||||
# UPD: RethinkDBConnection is not here anymore cause we no longer support RethinkDB.
|
|
||||||
# The problem described above might be reconsidered next time we introduce a backend,
|
|
||||||
# if it ever happens.
|
|
||||||
replicaset = replicaset or get_planetmint_config_value('replicaset')
|
|
||||||
ssl = ssl if ssl is not None else get_planetmint_config_value('ssl', False)
|
|
||||||
login = login or get_planetmint_config_value('login')
|
|
||||||
password = password or get_planetmint_config_value('password')
|
|
||||||
ca_cert = ca_cert or get_planetmint_config_value('ca_cert')
|
|
||||||
certfile = certfile or get_planetmint_config_value('certfile')
|
|
||||||
keyfile = keyfile or get_planetmint_config_value('keyfile')
|
|
||||||
keyfile_passphrase = keyfile_passphrase or get_planetmint_config_value('keyfile_passphrase', None)
|
|
||||||
crlfile = crlfile or get_planetmint_config_value('crlfile')
|
|
||||||
|
|
||||||
try: # Here we get class using getattr function
|
|
||||||
module_name, _, class_name = BACKENDS[backend].rpartition('.')
|
|
||||||
Class = getattr(import_module(module_name), class_name)
|
|
||||||
except KeyError:
|
|
||||||
raise ConfigurationError('Backend `{}` is not supported. '
|
|
||||||
'Planetmint currently supports {}'.format(backend, BACKENDS.keys()))
|
|
||||||
except (ImportError, AttributeError) as exc:
|
|
||||||
raise ConfigurationError('Error loading backend `{}`'.format(backend)) from exc
|
|
||||||
|
|
||||||
logger.debug('Connection: {}'.format(Class))
|
|
||||||
return Class(host=host, port=port, dbname=dbname,
|
|
||||||
max_tries=max_tries, connection_timeout=connection_timeout,
|
|
||||||
replicaset=replicaset, ssl=ssl, login=login, password=password,
|
|
||||||
ca_cert=ca_cert, certfile=certfile, keyfile=keyfile,
|
|
||||||
keyfile_passphrase=keyfile_passphrase, crlfile=crlfile)
|
|
||||||
|
|
||||||
|
|
||||||
class Connection:
|
class Connection(current_backend):
|
||||||
"""Connection class interface.
|
pass
|
||||||
|
|
||||||
All backend implementations should provide a connection class that inherits
|
|
||||||
from and implements this class.
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, host=None, port=None, dbname=None,
|
|
||||||
connection_timeout=None, max_tries=None,
|
|
||||||
**kwargs):
|
|
||||||
"""Create a new :class:`~.Connection` instance.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
host (str): the host to connect to.
|
|
||||||
port (int): the port to connect to.
|
|
||||||
dbname (str): the name of the database to use.
|
|
||||||
connection_timeout (int, optional): the milliseconds to wait
|
|
||||||
until timing out the database connection attempt.
|
|
||||||
Defaults to 5000ms.
|
|
||||||
max_tries (int, optional): how many tries before giving up,
|
|
||||||
if 0 then try forever. Defaults to 3.
|
|
||||||
**kwargs: arbitrary keyword arguments provided by the
|
|
||||||
configuration's ``database`` settings
|
|
||||||
"""
|
|
||||||
|
|
||||||
dbconf = planetmint.config['database']
|
|
||||||
|
|
||||||
self.host = host or dbconf['host']
|
|
||||||
self.port = port or dbconf['port']
|
|
||||||
self.dbname = dbname or dbconf['name']
|
|
||||||
self.connection_timeout = connection_timeout if connection_timeout is not None \
|
|
||||||
else dbconf['connection_timeout']
|
|
||||||
self.max_tries = max_tries if max_tries is not None else dbconf['max_tries']
|
|
||||||
self.max_tries_counter = range(self.max_tries) if self.max_tries != 0 else repeat(0)
|
|
||||||
self._conn = None
|
|
||||||
|
|
||||||
@property
|
|
||||||
def conn(self):
|
|
||||||
if self._conn is None:
|
|
||||||
self.connect()
|
|
||||||
return self._conn
|
|
||||||
|
|
||||||
def run(self, query):
|
|
||||||
"""Run a query.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
query: the query to run
|
|
||||||
Raises:
|
|
||||||
:exc:`~DuplicateKeyError`: If the query fails because of a
|
|
||||||
duplicate key constraint.
|
|
||||||
:exc:`~OperationFailure`: If the query fails for any other
|
|
||||||
reason.
|
|
||||||
:exc:`~ConnectionError`: If the connection to the database
|
|
||||||
fails.
|
|
||||||
"""
|
|
||||||
|
|
||||||
raise NotImplementedError()
|
|
||||||
|
|
||||||
def connect(self):
|
|
||||||
"""Try to connect to the database.
|
|
||||||
|
|
||||||
Raises:
|
|
||||||
:exc:`~ConnectionError`: If the connection to the database
|
|
||||||
fails.
|
|
||||||
"""
|
|
||||||
|
|
||||||
attempt = 0
|
|
||||||
for i in self.max_tries_counter:
|
|
||||||
attempt += 1
|
|
||||||
try:
|
|
||||||
self._conn = self._connect()
|
|
||||||
except ConnectionError as exc:
|
|
||||||
logger.warning('Attempt %s/%s. Connection to %s:%s failed after %sms.',
|
|
||||||
attempt, self.max_tries if self.max_tries != 0 else '∞',
|
|
||||||
self.host, self.port, self.connection_timeout)
|
|
||||||
if attempt == self.max_tries:
|
|
||||||
logger.critical('Cannot connect to the Database. Giving up.')
|
|
||||||
raise ConnectionError() from exc
|
|
||||||
else:
|
|
||||||
break
|
|
||||||
|
|||||||
@ -1,160 +0,0 @@
|
|||||||
# Copyright © 2020 Interplanetary Database Association e.V.,
|
|
||||||
# Planetmint and IPDB software 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 importlib import import_module
|
|
||||||
from itertools import repeat
|
|
||||||
|
|
||||||
import tarantool
|
|
||||||
import planetmint
|
|
||||||
|
|
||||||
from planetmint.backend.exceptions import ConnectionError
|
|
||||||
from planetmint.backend.utils import get_planetmint_config_value, get_planetmint_config_value_or_key_error
|
|
||||||
from planetmint.common.exceptions import ConfigurationError
|
|
||||||
|
|
||||||
BACKENDS = { # This is path to MongoDBClass
|
|
||||||
'tarantool_db': 'planetmint.backend.connection_tarantool.TarantoolDB',
|
|
||||||
}
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
|
|
||||||
class TarantoolDB:
|
|
||||||
def __init__(self, host: str, port: int, user: str, password: str, reset_database: bool = False):
|
|
||||||
self.db_connect = tarantool.connect(host=host, port=port, user=user, password=password)
|
|
||||||
if reset_database:
|
|
||||||
self.drop_database()
|
|
||||||
self.init_database()
|
|
||||||
|
|
||||||
def get_connection(self, space_name: str = None):
|
|
||||||
return self.db_connect if space_name is None else self.db_connect.space(space_name)
|
|
||||||
|
|
||||||
def __read_commands(self, file_path):
|
|
||||||
with open(file_path, "r") as cmd_file:
|
|
||||||
commands = [line.strip() for line in cmd_file.readlines() if len(str(line)) > 1]
|
|
||||||
cmd_file.close()
|
|
||||||
return commands
|
|
||||||
|
|
||||||
def drop_database(self):
|
|
||||||
from planetmint.backend.tarantool.utils import run
|
|
||||||
config = get_planetmint_config_value_or_key_error("ctl_config")
|
|
||||||
drop_config = config["drop_config"]
|
|
||||||
f_path = "%s%s" % (drop_config["relative_path"], drop_config["drop_file"])
|
|
||||||
commands = self.__read_commands(file_path=f_path)
|
|
||||||
run(commands=commands, config=config)
|
|
||||||
|
|
||||||
def init_database(self):
|
|
||||||
from planetmint.backend.tarantool.utils import run
|
|
||||||
config = get_planetmint_config_value_or_key_error("ctl_config")
|
|
||||||
init_config = config["init_config"]
|
|
||||||
f_path = "%s%s" % (init_config["relative_path"], init_config["init_file"])
|
|
||||||
commands = self.__read_commands(file_path=f_path)
|
|
||||||
run(commands=commands, config=config)
|
|
||||||
|
|
||||||
def connect(host: str = None, port: int = None, username: str = "admin", password: str = "pass",
|
|
||||||
backend: str = None, reset_database: bool = False, name=None, max_tries=None,
|
|
||||||
connection_timeout=None, replicaset=None, ssl=None, login: str = "admin", ctl_config=None,
|
|
||||||
ca_cert=None, certfile=None, keyfile=None, keyfile_passphrase=None, reconnect_delay=None,
|
|
||||||
crlfile=None, connect_now=True, encoding=None):
|
|
||||||
backend = backend or get_planetmint_config_value_or_key_error('backend') # TODO Rewrite Configs
|
|
||||||
host = host or get_planetmint_config_value_or_key_error('host')
|
|
||||||
port = port or get_planetmint_config_value_or_key_error('port')
|
|
||||||
username = username or login or get_planetmint_config_value('login')
|
|
||||||
password = password or get_planetmint_config_value('password')
|
|
||||||
|
|
||||||
try: # Here we get class using getattr function
|
|
||||||
module_name, _, class_name = BACKENDS[backend].rpartition('.')
|
|
||||||
Class = getattr(import_module(module_name), class_name)
|
|
||||||
except KeyError:
|
|
||||||
raise ConfigurationError('Backend `{}` is not supported. '
|
|
||||||
'Planetmint currently supports {}'.format(backend, BACKENDS.keys()))
|
|
||||||
except (ImportError, AttributeError) as exc:
|
|
||||||
raise ConfigurationError('Error loading backend `{}`'.format(backend)) from exc
|
|
||||||
|
|
||||||
logger.debug('Connection: {}'.format(Class))
|
|
||||||
return Class(host=host, port=port, user=username, password=password, reset_database=reset_database)
|
|
||||||
|
|
||||||
|
|
||||||
class Connection:
|
|
||||||
"""Connection class interface.
|
|
||||||
|
|
||||||
All backend implementations should provide a connection class that inherits
|
|
||||||
from and implements this class.
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, host=None, port=None, connection_timeout=None, max_tries=None,
|
|
||||||
**kwargs):
|
|
||||||
"""Create a new :class:`~.Connection` instance.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
host (str): the host to connect to.
|
|
||||||
port (int): the port to connect to.
|
|
||||||
dbname (str): the name of the database to use.
|
|
||||||
connection_timeout (int, optional): the milliseconds to wait
|
|
||||||
until timing out the database connection attempt.
|
|
||||||
Defaults to 5000ms.
|
|
||||||
max_tries (int, optional): how many tries before giving up,
|
|
||||||
if 0 then try forever. Defaults to 3.
|
|
||||||
**kwargs: arbitrary keyword arguments provided by the
|
|
||||||
configuration's ``database`` settings
|
|
||||||
"""
|
|
||||||
|
|
||||||
dbconf = planetmint.config['database']
|
|
||||||
|
|
||||||
self.host = host or dbconf['host']
|
|
||||||
self.port = port or dbconf['port']
|
|
||||||
self.connection_timeout = connection_timeout if connection_timeout is not None \
|
|
||||||
else dbconf['connection_timeout']
|
|
||||||
self.max_tries = max_tries if max_tries is not None else dbconf['max_tries']
|
|
||||||
self.max_tries_counter = range(self.max_tries) if self.max_tries != 0 else repeat(0)
|
|
||||||
self._conn = None
|
|
||||||
|
|
||||||
@property
|
|
||||||
def conn(self):
|
|
||||||
pass
|
|
||||||
if self._conn is None:
|
|
||||||
self.connect()
|
|
||||||
return self._conn
|
|
||||||
|
|
||||||
def run(self, query):
|
|
||||||
pass
|
|
||||||
"""Run a query.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
query: the query to run
|
|
||||||
Raises:
|
|
||||||
:exc:`~DuplicateKeyError`: If the query fails because of a
|
|
||||||
duplicate key constraint.
|
|
||||||
:exc:`~OperationFailure`: If the query fails for any other
|
|
||||||
reason.
|
|
||||||
:exc:`~ConnectionError`: If the connection to the database
|
|
||||||
fails.
|
|
||||||
"""
|
|
||||||
|
|
||||||
raise NotImplementedError()
|
|
||||||
|
|
||||||
def connect(self):
|
|
||||||
pass
|
|
||||||
"""Try to connect to the database.
|
|
||||||
|
|
||||||
Raises:
|
|
||||||
:exc:`~ConnectionError`: If the connection to the database
|
|
||||||
fails.
|
|
||||||
"""
|
|
||||||
|
|
||||||
attempt = 0
|
|
||||||
for i in self.max_tries_counter:
|
|
||||||
attempt += 1
|
|
||||||
try:
|
|
||||||
self._conn = self._connect()
|
|
||||||
except ConnectionError as exc:
|
|
||||||
logger.warning('Attempt %s/%s. Connection to %s:%s failed after %sms.',
|
|
||||||
attempt, self.max_tries if self.max_tries != 0 else '∞',
|
|
||||||
self.host, self.port, self.connection_timeout)
|
|
||||||
if attempt == self.max_tries:
|
|
||||||
logger.critical('Cannot connect to the Database. Giving up.')
|
|
||||||
raise ConnectionError() from exc
|
|
||||||
else:
|
|
||||||
break
|
|
||||||
@ -4,11 +4,11 @@
|
|||||||
# Code is Apache-2.0 and docs are CC-BY-4.0
|
# Code is Apache-2.0 and docs are CC-BY-4.0
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
import bigchaindb
|
||||||
from ssl import CERT_REQUIRED
|
from ssl import CERT_REQUIRED
|
||||||
|
|
||||||
import pymongo
|
import pymongo
|
||||||
|
|
||||||
from planetmint.backend.connection import Connection
|
|
||||||
from planetmint.backend.exceptions import (DuplicateKeyError,
|
from planetmint.backend.exceptions import (DuplicateKeyError,
|
||||||
OperationError,
|
OperationError,
|
||||||
ConnectionError)
|
ConnectionError)
|
||||||
@ -19,6 +19,84 @@ from planetmint.utils import Lazy
|
|||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class Connection:
|
||||||
|
"""Connection class interface.
|
||||||
|
All backend implementations should provide a connection class that inherits
|
||||||
|
from and implements this class.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, host=None, port=None, dbname=None,
|
||||||
|
connection_timeout=None, max_tries=None,
|
||||||
|
**kwargs):
|
||||||
|
"""Create a new :class:`~.Connection` instance.
|
||||||
|
Args:
|
||||||
|
host (str): the host to connect to.
|
||||||
|
port (int): the port to connect to.
|
||||||
|
dbname (str): the name of the database to use.
|
||||||
|
connection_timeout (int, optional): the milliseconds to wait
|
||||||
|
until timing out the database connection attempt.
|
||||||
|
Defaults to 5000ms.
|
||||||
|
max_tries (int, optional): how many tries before giving up,
|
||||||
|
if 0 then try forever. Defaults to 3.
|
||||||
|
**kwargs: arbitrary keyword arguments provided by the
|
||||||
|
configuration's ``database`` settings
|
||||||
|
"""
|
||||||
|
|
||||||
|
dbconf = bigchaindb.config['database']
|
||||||
|
|
||||||
|
self.host = host or dbconf['host']
|
||||||
|
self.port = port or dbconf['port']
|
||||||
|
self.dbname = dbname or dbconf['name']
|
||||||
|
self.connection_timeout = connection_timeout if connection_timeout is not None \
|
||||||
|
else dbconf['connection_timeout']
|
||||||
|
self.max_tries = max_tries if max_tries is not None else dbconf['max_tries']
|
||||||
|
self.max_tries_counter = range(self.max_tries) if self.max_tries != 0 else repeat(0)
|
||||||
|
self._conn = None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def conn(self):
|
||||||
|
if self._conn is None:
|
||||||
|
self.connect()
|
||||||
|
return self._conn
|
||||||
|
|
||||||
|
def run(self, query):
|
||||||
|
"""Run a query.
|
||||||
|
Args:
|
||||||
|
query: the query to run
|
||||||
|
Raises:
|
||||||
|
:exc:`~DuplicateKeyError`: If the query fails because of a
|
||||||
|
duplicate key constraint.
|
||||||
|
:exc:`~OperationFailure`: If the query fails for any other
|
||||||
|
reason.
|
||||||
|
:exc:`~ConnectionError`: If the connection to the database
|
||||||
|
fails.
|
||||||
|
"""
|
||||||
|
|
||||||
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
def connect(self):
|
||||||
|
"""Try to connect to the database.
|
||||||
|
Raises:
|
||||||
|
:exc:`~ConnectionError`: If the connection to the database
|
||||||
|
fails.
|
||||||
|
"""
|
||||||
|
|
||||||
|
attempt = 0
|
||||||
|
for i in self.max_tries_counter:
|
||||||
|
attempt += 1
|
||||||
|
try:
|
||||||
|
self._conn = self._connect()
|
||||||
|
except ConnectionError as exc:
|
||||||
|
logger.warning('Attempt %s/%s. Connection to %s:%s failed after %sms.',
|
||||||
|
attempt, self.max_tries if self.max_tries != 0 else '∞',
|
||||||
|
self.host, self.port, self.connection_timeout)
|
||||||
|
if attempt == self.max_tries:
|
||||||
|
logger.critical('Cannot connect to the Database. Giving up.')
|
||||||
|
raise ConnectionError() from exc
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
|
||||||
|
|
||||||
class LocalMongoDBConnection(Connection):
|
class LocalMongoDBConnection(Connection):
|
||||||
|
|
||||||
def __init__(self, replicaset=None, ssl=None, login=None, password=None,
|
def __init__(self, replicaset=None, ssl=None, login=None, password=None,
|
||||||
|
|||||||
@ -9,8 +9,7 @@ from functools import singledispatch
|
|||||||
import logging
|
import logging
|
||||||
|
|
||||||
import planetmint
|
import planetmint
|
||||||
from planetmint.backend.connection import connect as connect_mongo
|
from planetmint.backend.connection import Connection
|
||||||
from planetmint.backend.connection_tarantool import connect
|
|
||||||
from planetmint.common.exceptions import ValidationError
|
from planetmint.common.exceptions import ValidationError
|
||||||
from planetmint.common.utils import validate_all_values_for_key_in_obj, validate_all_values_for_key_in_list
|
from planetmint.common.utils import validate_all_values_for_key_in_obj, validate_all_values_for_key_in_list
|
||||||
|
|
||||||
@ -64,7 +63,7 @@ def drop_database(connection, dbname):
|
|||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
|
|
||||||
def init_database(connection=None, dbname=None):
|
def init_database(connection=None, dbname=None): # FIXME HERE IS INIT DATABASE
|
||||||
"""Initialize the configured backend for use with Planetmint.
|
"""Initialize the configured backend for use with Planetmint.
|
||||||
|
|
||||||
Creates a database with :attr:`dbname` with any required tables
|
Creates a database with :attr:`dbname` with any required tables
|
||||||
@ -79,7 +78,7 @@ def init_database(connection=None, dbname=None):
|
|||||||
configuration.
|
configuration.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
connection = connection or connect()
|
connection = connection or Connection()
|
||||||
dbname = dbname or planetmint.config['database']['name']
|
dbname = dbname or planetmint.config['database']['name']
|
||||||
|
|
||||||
create_database(connection, dbname)
|
create_database(connection, dbname)
|
||||||
|
|||||||
0
planetmint/backend/tarantool/__init__.py
Normal file
0
planetmint/backend/tarantool/__init__.py
Normal file
55
planetmint/backend/tarantool/connection.py
Normal file
55
planetmint/backend/tarantool/connection.py
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
# Copyright © 2020 Interplanetary Database Association e.V.,
|
||||||
|
# Planetmint and IPDB software 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 importlib import import_module
|
||||||
|
from itertools import repeat
|
||||||
|
|
||||||
|
import tarantool
|
||||||
|
import planetmint
|
||||||
|
|
||||||
|
from planetmint.backend.exceptions import ConnectionError
|
||||||
|
from planetmint.backend.utils import get_planetmint_config_value, get_planetmint_config_value_or_key_error
|
||||||
|
from planetmint.common.exceptions import ConfigurationError
|
||||||
|
|
||||||
|
BACKENDS = { # This is path to MongoDBClass
|
||||||
|
'tarantool_db': 'planetmint.backend.connection_tarantool.TarantoolDB',
|
||||||
|
'localmongodb': 'planetmint.backend.localmongodb.connection.LocalMongoDBConnection'
|
||||||
|
}
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class TarantoolDB:
|
||||||
|
def __init__(self, host: str, port: int, user: str, password: str, reset_database: bool = False):
|
||||||
|
self.db_connect = tarantool.connect(host=host, port=port, user=user, password=password)
|
||||||
|
if reset_database:
|
||||||
|
self.drop_database()
|
||||||
|
self.init_database()
|
||||||
|
|
||||||
|
def get_connection(self, space_name: str = None):
|
||||||
|
return self.db_connect if space_name is None else self.db_connect.space(space_name)
|
||||||
|
|
||||||
|
def __read_commands(self, file_path):
|
||||||
|
with open(file_path, "r") as cmd_file:
|
||||||
|
commands = [line.strip() for line in cmd_file.readlines() if len(str(line)) > 1]
|
||||||
|
cmd_file.close()
|
||||||
|
return commands
|
||||||
|
|
||||||
|
def drop_database(self):
|
||||||
|
from planetmint.backend.tarantool.utils import run
|
||||||
|
config = get_planetmint_config_value_or_key_error("ctl_config")
|
||||||
|
drop_config = config["drop_config"]
|
||||||
|
f_path = "%s%s" % (drop_config["relative_path"], drop_config["drop_file"])
|
||||||
|
commands = self.__read_commands(file_path=f_path)
|
||||||
|
run(commands=commands, config=config)
|
||||||
|
|
||||||
|
def init_database(self):
|
||||||
|
from planetmint.backend.tarantool.utils import run
|
||||||
|
config = get_planetmint_config_value_or_key_error("ctl_config")
|
||||||
|
init_config = config["init_config"]
|
||||||
|
f_path = "%s%s" % (init_config["relative_path"], init_config["init_file"])
|
||||||
|
commands = self.__read_commands(file_path=f_path)
|
||||||
|
run(commands=commands, config=config)
|
||||||
@ -76,7 +76,7 @@ class Planetmint(object):
|
|||||||
else:
|
else:
|
||||||
self.validation = BaseValidationRules
|
self.validation = BaseValidationRules
|
||||||
|
|
||||||
self.connection = connection if connection else backend.connection_tarantool.connect(**planetmint.config['database'])
|
self.connection = connection if connection else planetmint.backend.tarantool.connection_tarantool.connect(**planetmint.config['database'])
|
||||||
|
|
||||||
def post_transaction(self, transaction, mode):
|
def post_transaction(self, transaction, mode):
|
||||||
"""Submit a valid transaction to the mempool."""
|
"""Submit a valid transaction to the mempool."""
|
||||||
|
|||||||
@ -180,7 +180,7 @@ def test_write_metadata():
|
|||||||
# check that 3 assets were written to the database
|
# check that 3 assets were written to the database
|
||||||
cursor = conn.db.metadata.find({}, projection={'_id': False})\
|
cursor = conn.db.metadata.find({}, projection={'_id': False})\
|
||||||
.sort('id', pymongo.ASCENDING)
|
.sort('id', pymongo.ASCENDING)
|
||||||
|
TarantoolDB
|
||||||
assert cursor.collection.count_documents({}) == 3
|
assert cursor.collection.count_documents({}) == 3
|
||||||
assert list(cursor) == metadata
|
assert list(cursor) == metadata
|
||||||
|
|
||||||
|
|||||||
@ -9,16 +9,16 @@ import pytest
|
|||||||
|
|
||||||
# import pymongo
|
# import pymongo
|
||||||
|
|
||||||
# from planetmint.backend import connect, query
|
# from planetmint.backend.connection import Connection, query
|
||||||
|
|
||||||
pytestmark = pytest.mark.bdb
|
pytestmark = pytest.mark.bdb
|
||||||
|
|
||||||
|
|
||||||
def test_get_txids_filtered(signed_create_tx, signed_transfer_tx):
|
def test_get_txids_filtered(signed_create_tx, signed_transfer_tx):
|
||||||
from planetmint.backend import connect
|
from planetmint.backend.connection import Connection
|
||||||
from planetmint.backend.tarantool import query
|
from planetmint.backend.tarantool import query
|
||||||
from planetmint.models import Transaction
|
from planetmint.models import Transaction
|
||||||
conn = connect(reset_database=True).get_connection()
|
conn = Connection(reset_database=True).get_connection()
|
||||||
# create and insert two blocks, one for the create and one for the
|
# create and insert two blocks, one for the create and one for the
|
||||||
# transfer transaction
|
# transfer transaction
|
||||||
create_tx_dict = signed_create_tx.to_dict()
|
create_tx_dict = signed_create_tx.to_dict()
|
||||||
@ -43,9 +43,9 @@ def test_get_txids_filtered(signed_create_tx, signed_transfer_tx):
|
|||||||
|
|
||||||
|
|
||||||
def test_write_assets():
|
def test_write_assets():
|
||||||
from planetmint.backend import connect
|
from planetmint.backend.connection import Connection
|
||||||
from planetmint.backend.tarantool import query
|
from planetmint.backend.tarantool import query
|
||||||
conn = connect().get_connection()
|
conn = Connection().get_connection()
|
||||||
assets = [
|
assets = [
|
||||||
{'id': "1", 'data': '1'},
|
{'id': "1", 'data': '1'},
|
||||||
{'id': "2", 'data': '2'},
|
{'id': "2", 'data': '2'},
|
||||||
@ -66,9 +66,9 @@ def test_write_assets():
|
|||||||
|
|
||||||
|
|
||||||
def test_get_assets():
|
def test_get_assets():
|
||||||
from planetmint.backend import connect
|
from planetmint.backend.connection import Connection
|
||||||
from planetmint.backend.tarantool import query
|
from planetmint.backend.tarantool import query
|
||||||
conn = connect().get_connection()
|
conn = Connection().get_connection()
|
||||||
|
|
||||||
assets = [
|
assets = [
|
||||||
{'id': "1", 'data': '1'},
|
{'id': "1", 'data': '1'},
|
||||||
@ -167,9 +167,9 @@ def test_text_search(table):
|
|||||||
|
|
||||||
|
|
||||||
def test_write_metadata():
|
def test_write_metadata():
|
||||||
from planetmint.backend import connect
|
from planetmint.backend.connection import Connection
|
||||||
from planetmint.backend.tarantool import query
|
from planetmint.backend.tarantool import query
|
||||||
conn = connect().get_connection()
|
conn = Connection().get_connection()
|
||||||
|
|
||||||
metadata = [
|
metadata = [
|
||||||
{'id': "1", 'data': '1'},
|
{'id': "1", 'data': '1'},
|
||||||
@ -194,9 +194,9 @@ def test_write_metadata():
|
|||||||
|
|
||||||
|
|
||||||
def test_get_metadata():
|
def test_get_metadata():
|
||||||
from planetmint.backend import connect
|
from planetmint.backend.connection import Connection
|
||||||
from planetmint.backend.tarantool import query
|
from planetmint.backend.tarantool import query
|
||||||
conn = connect().get_connection()
|
conn = Connection().get_connection()
|
||||||
|
|
||||||
metadata = [
|
metadata = [
|
||||||
{'id': "dd86682db39e4b424df0eec1413cfad65488fd48712097c5d865ca8e8e059b64", 'metadata': None},
|
{'id': "dd86682db39e4b424df0eec1413cfad65488fd48712097c5d865ca8e8e059b64", 'metadata': None},
|
||||||
@ -211,9 +211,9 @@ def test_get_metadata():
|
|||||||
|
|
||||||
|
|
||||||
def test_get_owned_ids(signed_create_tx, user_pk):
|
def test_get_owned_ids(signed_create_tx, user_pk):
|
||||||
from planetmint.backend import connect
|
from planetmint.backend.connection import Connection
|
||||||
from planetmint.backend.tarantool import query
|
from planetmint.backend.tarantool import query
|
||||||
conn = connect().get_connection()
|
conn = Connection().get_connection()
|
||||||
|
|
||||||
# insert a transaction
|
# insert a transaction
|
||||||
query.store_transactions(connection=conn, signed_transactions=[signed_create_tx.to_dict()])
|
query.store_transactions(connection=conn, signed_transactions=[signed_create_tx.to_dict()])
|
||||||
@ -225,9 +225,9 @@ def test_get_owned_ids(signed_create_tx, user_pk):
|
|||||||
|
|
||||||
def test_get_spending_transactions(user_pk, user_sk):
|
def test_get_spending_transactions(user_pk, user_sk):
|
||||||
from planetmint.models import Transaction
|
from planetmint.models import Transaction
|
||||||
from planetmint.backend import connect
|
from planetmint.backend.connection import Connection
|
||||||
from planetmint.backend.tarantool import query
|
from planetmint.backend.tarantool import query
|
||||||
conn = connect().get_connection()
|
conn = Connection().get_connection()
|
||||||
|
|
||||||
out = [([user_pk], 1)]
|
out = [([user_pk], 1)]
|
||||||
tx1 = Transaction.create([user_pk], out * 3)
|
tx1 = Transaction.create([user_pk], out * 3)
|
||||||
@ -249,10 +249,10 @@ def test_get_spending_transactions(user_pk, user_sk):
|
|||||||
def test_get_spending_transactions_multiple_inputs():
|
def test_get_spending_transactions_multiple_inputs():
|
||||||
from planetmint.models import Transaction
|
from planetmint.models import Transaction
|
||||||
from planetmint.common.crypto import generate_key_pair
|
from planetmint.common.crypto import generate_key_pair
|
||||||
from planetmint.backend import connect
|
from planetmint.backend.connection import Connection
|
||||||
from planetmint.backend.tarantool import query
|
from planetmint.backend.tarantool import query
|
||||||
|
|
||||||
conn = connect().get_connection()
|
conn = Connection().get_connection()
|
||||||
|
|
||||||
(alice_sk, alice_pk) = generate_key_pair()
|
(alice_sk, alice_pk) = generate_key_pair()
|
||||||
(bob_sk, bob_pk) = generate_key_pair()
|
(bob_sk, bob_pk) = generate_key_pair()
|
||||||
@ -294,10 +294,10 @@ def test_get_spending_transactions_multiple_inputs():
|
|||||||
|
|
||||||
def test_store_block():
|
def test_store_block():
|
||||||
from planetmint.lib import Block
|
from planetmint.lib import Block
|
||||||
from planetmint.backend import connect
|
from planetmint.backend.connection import Connection
|
||||||
from planetmint.backend.tarantool import query
|
from planetmint.backend.tarantool import query
|
||||||
|
|
||||||
conn = connect().get_connection()
|
conn = Connection().get_connection()
|
||||||
|
|
||||||
block = Block(app_hash='random_utxo',
|
block = Block(app_hash='random_utxo',
|
||||||
height=3,
|
height=3,
|
||||||
@ -310,10 +310,10 @@ def test_store_block():
|
|||||||
|
|
||||||
def test_get_block():
|
def test_get_block():
|
||||||
from planetmint.lib import Block
|
from planetmint.lib import Block
|
||||||
from planetmint.backend import connect
|
from planetmint.backend.connection import Connection
|
||||||
from planetmint.backend.tarantool import query
|
from planetmint.backend.tarantool import query
|
||||||
|
|
||||||
conn = connect().get_connection()
|
conn = Connection().get_connection()
|
||||||
|
|
||||||
block = Block(app_hash='random_utxo',
|
block = Block(app_hash='random_utxo',
|
||||||
height=3,
|
height=3,
|
||||||
@ -424,10 +424,10 @@ def test_get_block():
|
|||||||
|
|
||||||
|
|
||||||
def test_store_pre_commit_state(db_context):
|
def test_store_pre_commit_state(db_context):
|
||||||
from planetmint.backend import connect
|
from planetmint.backend.connection import Connection
|
||||||
from planetmint.backend.tarantool import query
|
from planetmint.backend.tarantool import query
|
||||||
|
|
||||||
conn = connect().get_connection()
|
conn = Connection().get_connection()
|
||||||
|
|
||||||
state = dict(height=3, transactions=[])
|
state = dict(height=3, transactions=[])
|
||||||
|
|
||||||
@ -440,10 +440,10 @@ def test_store_pre_commit_state(db_context):
|
|||||||
|
|
||||||
|
|
||||||
def test_get_pre_commit_state(db_context):
|
def test_get_pre_commit_state(db_context):
|
||||||
from planetmint.backend import connect
|
from planetmint.backend.connection import Connection
|
||||||
from planetmint.backend.tarantool import query
|
from planetmint.backend.tarantool import query
|
||||||
|
|
||||||
conn = connect().get_connection()
|
conn = Connection().get_connection()
|
||||||
space = conn.space("pre_commits")
|
space = conn.space("pre_commits")
|
||||||
all_pre = space.select([])
|
all_pre = space.select([])
|
||||||
for pre in all_pre.data:
|
for pre in all_pre.data:
|
||||||
@ -457,10 +457,10 @@ def test_get_pre_commit_state(db_context):
|
|||||||
|
|
||||||
|
|
||||||
def test_validator_update():
|
def test_validator_update():
|
||||||
from planetmint.backend import connect
|
from planetmint.backend.connection import Connection
|
||||||
from planetmint.backend.tarantool import query
|
from planetmint.backend.tarantool import query
|
||||||
|
|
||||||
conn = connect().get_connection()
|
conn = Connection().get_connection()
|
||||||
|
|
||||||
def gen_validator_update(height):
|
def gen_validator_update(height):
|
||||||
return {'validators': [], 'height': height, 'election_id': f'election_id_at_height_{height}'}
|
return {'validators': [], 'height': height, 'election_id': f'election_id_at_height_{height}'}
|
||||||
@ -519,10 +519,10 @@ def test_validator_update():
|
|||||||
),
|
),
|
||||||
])
|
])
|
||||||
def test_store_abci_chain(description, stores, expected):
|
def test_store_abci_chain(description, stores, expected):
|
||||||
from planetmint.backend import connect
|
from planetmint.backend.connection import Connection
|
||||||
from planetmint.backend.tarantool import query
|
from planetmint.backend.tarantool import query
|
||||||
|
|
||||||
conn = connect().get_connection()
|
conn = Connection().get_connection()
|
||||||
|
|
||||||
for store in stores:
|
for store in stores:
|
||||||
query.store_abci_chain(conn, **store)
|
query.store_abci_chain(conn, **store)
|
||||||
|
|||||||
76
tests/backend/tarantool/test_schema.py
Normal file
76
tests/backend/tarantool/test_schema.py
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
# Copyright © 2020 Interplanetary Database Association e.V.,
|
||||||
|
# Planetmint and IPDB software contributors.
|
||||||
|
# SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0)
|
||||||
|
# Code is Apache-2.0 and docs are CC-BY-4.0
|
||||||
|
|
||||||
|
|
||||||
|
def test_init_database_is_graceful_if_db_exists():
|
||||||
|
import planetmint
|
||||||
|
from planetmint import backend
|
||||||
|
from planetmint.backend.schema import init_database
|
||||||
|
|
||||||
|
conn = backend.connect()
|
||||||
|
dbname = planetmint.config['database']['name']
|
||||||
|
|
||||||
|
# The db is set up by the fixtures
|
||||||
|
assert dbname in conn.conn.list_database_names()
|
||||||
|
|
||||||
|
init_database()
|
||||||
|
|
||||||
|
|
||||||
|
def test_create_tables():
|
||||||
|
import planetmint
|
||||||
|
from planetmint import backend
|
||||||
|
from planetmint.backend import schema
|
||||||
|
|
||||||
|
conn = backend.connect()
|
||||||
|
dbname = planetmint.config['database']['name']
|
||||||
|
|
||||||
|
# The db is set up by the fixtures so we need to remove it
|
||||||
|
conn.conn.drop_database(dbname)
|
||||||
|
schema.create_database(conn, dbname)
|
||||||
|
schema.create_tables(conn, dbname)
|
||||||
|
|
||||||
|
collection_names = conn.conn[dbname].list_collection_names()
|
||||||
|
assert set(collection_names) == {
|
||||||
|
'transactions', 'assets', 'metadata', 'blocks', 'utxos', 'validators', 'elections',
|
||||||
|
'pre_commit', 'abci_chains',
|
||||||
|
}
|
||||||
|
|
||||||
|
indexes = conn.conn[dbname]['assets'].index_information().keys()
|
||||||
|
assert set(indexes) == {'_id_', 'asset_id', 'text'}
|
||||||
|
|
||||||
|
index_info = conn.conn[dbname]['transactions'].index_information()
|
||||||
|
indexes = index_info.keys()
|
||||||
|
assert set(indexes) == {
|
||||||
|
'_id_', 'transaction_id', 'asset_id', 'outputs', 'inputs'}
|
||||||
|
assert index_info['transaction_id']['unique']
|
||||||
|
|
||||||
|
index_info = conn.conn[dbname]['blocks'].index_information()
|
||||||
|
indexes = index_info.keys()
|
||||||
|
assert set(indexes) == {'_id_', 'height'}
|
||||||
|
assert index_info['height']['unique']
|
||||||
|
|
||||||
|
index_info = conn.conn[dbname]['utxos'].index_information()
|
||||||
|
assert set(index_info.keys()) == {'_id_', 'utxo'}
|
||||||
|
assert index_info['utxo']['unique']
|
||||||
|
assert index_info['utxo']['key'] == [('transaction_id', 1),
|
||||||
|
('output_index', 1)]
|
||||||
|
|
||||||
|
indexes = conn.conn[dbname]['elections'].index_information()
|
||||||
|
assert set(indexes.keys()) == {'_id_', 'election_id_height'}
|
||||||
|
assert indexes['election_id_height']['unique']
|
||||||
|
|
||||||
|
indexes = conn.conn[dbname]['pre_commit'].index_information()
|
||||||
|
assert set(indexes.keys()) == {'_id_', 'height'}
|
||||||
|
assert indexes['height']['unique']
|
||||||
|
|
||||||
|
|
||||||
|
def test_drop(dummy_db):
|
||||||
|
from planetmint import backend
|
||||||
|
from planetmint.backend import schema
|
||||||
|
|
||||||
|
conn = backend.connect()
|
||||||
|
assert dummy_db in conn.conn.list_database_names()
|
||||||
|
schema.drop_database(conn, dummy_db)
|
||||||
|
assert dummy_db not in conn.conn.list_database_names()
|
||||||
Loading…
x
Reference in New Issue
Block a user