Skip to content
Snippets Groups Projects
Forked from DM / dm-docs
261 commits behind, 710 commits ahead of the upstream repository.
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
apsUserDbManager.py 8.03 KiB
#!/usr/bin/env python

import threading
import os.path
import sqlalchemy 
from sqlalchemy.orm import sessionmaker
from sqlalchemy.orm import mapper
from sqlalchemy.orm import relationship

from dm.common.exceptions.commandFailed import CommandFailed
from dm.common.exceptions.configurationError import ConfigurationError
from dm.common.utility.loggingManager import LoggingManager
from dm.common.utility.configurationManager import ConfigurationManager
from dm.aps_user_db.entities import apsUserDbEntityMap


class ApsUserDbManager:
    """ Singleton class for db management. """

    DB_CONNECTION_POOL_SIZE = 10
    DB_CONNECTION_POOL_MAX_OVERFLOW = 2
    DB_CONNECTION_POOL_RECYCYLE_TIME = 600
    DB_CONNECTION_POOL_TIMEOUT = 60
    DB_CONNECTION_LOGGING_FLAG = False

    CONFIG_SECTION_NAME = 'ApsUserDbManager'
    DB_KEY = 'db'
    DB_USER_KEY = 'dbuser'
    DB_HOST_KEY = 'dbhost'
    DB_PORT_KEY = 'dbport'
    DB_NAME_KEY = 'dbname'
    DB_SCHEMA_KEY = 'dbschema'
    DB_PASSWORD_FILE_KEY = 'dbpasswordfile'

    # Singleton.
    __lock = threading.RLock()
    __instance = None

    @classmethod
    def getInstance(cls):
        from dm.aps_user_db.impl.apsUserDbManager import ApsUserDbManager
        try:
            mgr = ApsUserDbManager()
        except ApsUserDbManager, ex:
            mgr = ex
        return mgr 

    def __configure(self):
        cm = ConfigurationManager.getInstance()
        self.logger.debug('Configuring APS User DB Manager')
        self.db = cm.getConfigOption(ApsUserDbManager.CONFIG_SECTION_NAME, ApsUserDbManager.DB_KEY)
        self.logger.debug('Using APS DB: %s' % self.db)
        self.dbUser = cm.getConfigOption(ApsUserDbManager.CONFIG_SECTION_NAME, ApsUserDbManager.DB_USER_KEY)
        self.logger.debug('Using APS DB user: %s' % self.dbUser)
        self.dbHost = cm.getConfigOption(ApsUserDbManager.CONFIG_SECTION_NAME, ApsUserDbManager.DB_HOST_KEY)
        self.logger.debug('Using APS DB host: %s' % self.dbHost)
        self.dbPort = cm.getConfigOption(ApsUserDbManager.CONFIG_SECTION_NAME, ApsUserDbManager.DB_PORT_KEY)
        self.logger.debug('Using APS DB port: %s' % self.dbPort)
        self.dbName = cm.getConfigOption(ApsUserDbManager.CONFIG_SECTION_NAME, ApsUserDbManager.DB_NAME_KEY)
        self.logger.debug('Using APS DB name: %s' % self.dbName)
        self.dbSchema = cm.getConfigOption(ApsUserDbManager.CONFIG_SECTION_NAME, ApsUserDbManager.DB_SCHEMA_KEY)
        self.logger.debug('Using APS DB schema: %s' % self.dbSchema)
        self.dbPasswordFile = cm.getConfigOption(ApsUserDbManager.CONFIG_SECTION_NAME, ApsUserDbManager.DB_PASSWORD_FILE_KEY)
        self.logger.debug('Using APS DB password file: %s' % self.dbPasswordFile)
        self.dbPassword = open(self.dbPasswordFile, 'r').readline().strip()

    def __init__(self):
        ApsUserDbManager.__lock.acquire()
        try:
            if ApsUserDbManager.__instance is not None:
                raise ApsUserDbManager.__instance
            ApsUserDbManager.__instance = self
            self.lock = threading.RLock()
            self.logger = LoggingManager.getInstance().getLogger(self.__class__.__name__)
            self.__configure()

            engineUrl = '%s://%s:%s@%s:%s/%s' % (self.db, self.dbUser, self.dbPassword, self.dbHost, self.dbPort, self.dbName)
            #self.logger.debug('Using engine URL: %s' % engineUrl)
            self.engine = sqlalchemy.create_engine(engineUrl, 
                pool_size=ApsUserDbManager.DB_CONNECTION_POOL_SIZE, 
                max_overflow=ApsUserDbManager.DB_CONNECTION_POOL_MAX_OVERFLOW, 
                pool_recycle=ApsUserDbManager.DB_CONNECTION_POOL_RECYCYLE_TIME, 
                echo=ApsUserDbManager.DB_CONNECTION_LOGGING_FLAG, 
                pool_timeout=ApsUserDbManager.DB_CONNECTION_POOL_TIMEOUT)
            self.metadata = sqlalchemy.MetaData(engineUrl, schema=self.dbSchema)

            self.logger.debug('Mapping DB tables')
            for (dbTableName, (dbEntityClass, dbRelationDict)) in apsUserDbEntityMap.APS_USER_DB_ENTITY_MAP.items():
                self.mapTable(dbEntityClass, dbTableName, dbRelationDict)
            self.logger.debug('Initialized SQLalchemy engines')

        finally:
            ApsUserDbManager.__lock.release()

    def getLogger(self):
        return self.logger

    def inspectTables(self):
        from sqlalchemy import inspect
        inspector = inspect(self.engine)
        self.logger.debug('Inspecting tables')
        for tableName in inspector.get_table_names():
            self.logger.debug('Table: %s' % tableName)
            for column in inspector.get_columns(tableName):
                self.logger.debug('Column: %s' % column['name'])

    def inspectTables2(self):
        from sqlalchemy import MetaData
        m = MetaData()
        m.reflect(self.engine)
        self.logger.debug('Inspecting tables via metadata')
        for table in m.tables.values():
            self.logger.debug('Table: %s' % table.name)
            for column in table.c:
                self.logger.debug('Column: %s' % column.name)

    def initTable(self, tableClass, tableName):
        """ Initialize DB table. """
        self.lock.acquire()
        try:
            tbl = sqlalchemy.Table(tableName, self.metadata, autoload=True)
            tableClass.columns = tbl.columns
            return tbl
        finally:
            self.lock.release()

    def mapTable(self, tableClass, tableName, relationDict):
        """ Map DB table to a given class. """
        self.lock.acquire()
        try:
            table = sqlalchemy.Table(tableName, self.metadata, autoload=True)
            tableClass.columns = table.columns

            # Build relations from specified foreign key columns and other properties.
            tableRelations = {}
            primaryKey = None
            for (name, propertyDict) in relationDict.items():
                if name == 'self':
                    primaryKey = propertyDict.get('primary_key')
                    continue
                lazy = propertyDict.get('lazy')
                parentEntity = propertyDict.get('parentEntity')
                foreignKeyColumns = propertyDict.get('foreignKeyColumns', [])
                if len(foreignKeyColumns):
                    fkList = []
                    for fk in foreignKeyColumns:
                        fkList.append(table.columns.get(fk))
                    tableRelations[name] = relationship(parentEntity, foreign_keys=fkList, lazy=lazy)
                else:
                    tableRelations[name] = relationship(parentEntity, lazy=lazy)

            if primaryKey:
                mapper(tableClass, table, tableRelations, primary_key=table.columns.get(primaryKey))
            else:
                mapper(tableClass, table, tableRelations)
            return table
        finally:
            self.lock.release()

    def getMetadataTable(self, table):
        return self.metadata.tables[table]

    def openSession(self):
        """ Open db session. """
        self.lock.acquire()
        try:
            Session = sessionmaker(bind=self.engine)
            return Session()
        finally:
            self.lock.release()

    def closeSession(self, session):
        """ Close db session. """
        self.lock.acquire()
        try:
            session.close()
        finally:
            self.lock.release()

    def acquireConnection(self):
        """ Get db connection. """
        self.lock.acquire()
        try:
            return self.engine.connect()
        finally:
            self.lock.release()
                                                                        
    def releaseConnection(self, connection):
        """ Release db connection. """
        self.lock.acquire()
        try:
            if connection:
                connection.close()
        finally:
            self.lock.release()

#######################################################################
# Testing.
if __name__ == '__main__':
    ConfigurationManager.getInstance().setConsoleLogLevel('debug')
    mgr = ApsUserDbManager.getInstance()
    mgr.acquireConnection()
    mgr.inspectTables()
    mgr.inspectTables2()
    print 'Got connection'