Commit e91b32e5 authored by sveseli's avatar sveseli
Browse files

Merge branch '0.9.5' into release/0.9

parents e19a3e71 625b5e01
#!/bin/sh
# Run command
if [ -z $DM_ROOT_DIR ]; then
cd `dirname $0` && myDir=`pwd`
setupFile=$myDir/../setup.sh
if [ ! -f $setupFile ]; then
echo "Cannot find setup file: $setupFile"
exit 1
fi
source $setupFile > /dev/null
fi
source dm_command_setup.sh
eval "$DM_ROOT_DIR/src/python/dm/aps_user_db/cli/updateUserFromApsDbCli.py $DM_COMMAND_ARGS"
#!/bin/sh
# Run command
if [ -z $DM_ROOT_DIR ]; then
cd `dirname $0` && myDir=`pwd`
setupFile=$myDir/../setup.sh
if [ ! -f $setupFile ]; then
echo "Cannot find setup file: $setupFile"
exit 1
fi
source $setupFile > /dev/null
fi
source dm_command_setup.sh
eval "$DM_ROOT_DIR/src/python/dm/aps_user_db/cli/updateUsersFromApsDbCli.py $DM_COMMAND_ARGS"
Release 0.14 (10/14/2016)
=============================
- Introduced new framework and utilities for synchronizing users with
APS DB
- Resolved several issues with special characters in file names for
gridftp transfer plugin
Release 0.13 (05/27/2016)
=============================
......
......@@ -15,5 +15,5 @@ DM_DAQ_WEB_SERVICE_HOST=DM_HOSTNAME
DM_DAQ_WEB_SERVICE_PORT=33336
DM_CAT_WEB_SERVICE_HOST=DM_HOSTNAME
DM_CAT_WEB_SERVICE_PORT=44436
DM_SOFTWARE_VERSION="0.13 (DM_DATE)"
DM_SOFTWARE_VERSION="0.14 (DM_DATE)"
#!/bin/sh
#
# Script used for syncing APS user accounts
# Usage:
#
# $0
#
CURRENT_DIR=`pwd`
MY_DIR=`dirname $0` && cd $MY_DIR && MY_DIR=`pwd`
cd $CURRENT_DIR
DM_ROOT_DIR=$MY_DIR/..
DM_ENV_FILE=${DM_ROOT_DIR}/setup.sh
if [ ! -f ${DM_ENV_FILE} ]; then
echo "Environment file ${DM_ENV_FILE} does not exist."
exit 2
fi
. ${DM_ENV_FILE} > /dev/null
DM_CONFIG_FILE=$DM_ROOT_DIR/../etc/dm.aps-user-update-utilities.conf
# Simply run update command after sourcing setup file
dm-update-users-from-aps-db --config-file=$DM_CONFIG_FILE --quiet
......@@ -105,6 +105,13 @@ if [ -d $postgresqlDir ]; then
export DM_POSTGRESQL_DIR=$postgresqlDir
fi
# Setup oracle libraries.
oracleDir=$DM_SUPPORT_DIR/opt/oracle-client/$DM_HOST_ARCH
if [ -d $oracleDir ]; then
LD_LIBRARY_PATH=$oracleDir:$LD_LIBRARY_PATH
PATH=$oracleDir:$PATH
fi
# Get back to where we were before invoking the setup script
cd $currentDir
......
__version__ = "0.13 (2016.05.27)"
__version__ = "0.14 (2016.10.13)"
#!/usr/bin/env python
from dm.aps_user_db.api.apsUserDbApiBase import ApsUserDbApiBase
from dm.aps_user_db.impl.apsUserInfoHandler import ApsUserInfoHandler
class ApsUserDbApi(ApsUserDbApiBase):
""" APS User DB API class. """
def __init__(self):
ApsUserDbApiBase.__init__(self)
self.userInfoHandler = ApsUserInfoHandler()
@ApsUserDbApiBase.executeQuery
def getApsUsers(self, **kwargs):
session = kwargs['session']
dbUsers = self.userInfoHandler.getApsUsers(session)
return self.toDmObjectList(dbUsers)
@ApsUserDbApiBase.executeQuery
def getApsUserByBadgeNumber(self, badgeNumber, **kwargs):
session = kwargs['session']
dbUserInfo = self.userInfoHandler.getApsUserByBadgeNumber(session, badgeNumber)
return dbUserInfo.getDmObject()
#######################################################################
# Testing.
if __name__ == '__main__':
api = ApsUserDbApi()
#users = api.getApsUsers()
#for u in users:
# print u
print api.getApsUserByBadgeNumber(225159)
#!/usr/bin/env python
from dm.common.exceptions.dmException import DmException
from dm.common.exceptions.internalError import InternalError
from dm.common.utility.loggingManager import LoggingManager
from dm.aps_user_db.impl.apsUserDbManager import ApsUserDbManager
class ApsUserDbApiBase:
""" APS User DB API base class. """
def __init__(self):
self.logger = LoggingManager.getInstance().getLogger(self.__class__.__name__)
self.dbManager = ApsUserDbManager.getInstance()
# Decorator for all DB queries
@classmethod
def executeQuery(cls, func):
def query(*args, **kwargs):
try:
dbManager = ApsUserDbManager.getInstance()
session = dbManager.openSession()
kwargs['session'] = session
try:
return func(*args, **kwargs)
except DmException, ex:
raise
except Exception, ex:
cls.getLogger().exception('%s' % ex)
raise DmException(exception=ex)
finally:
dbManager.closeSession(session)
return query
# Decorator for all DB transactions
@classmethod
def executeTransaction(cls, func):
def transaction(*args, **kwargs):
try:
dbManager = ApsUserDbManager.getInstance()
session = dbManager.openSession()
kwargs['session'] = session
try:
result = func(*args, **kwargs)
session.commit()
return result
except DmException, ex:
session.rollback()
raise
except Exception, ex:
session.rollback()
cls.getLogger().exception('%s' % ex)
raise DmException(exception=ex)
finally:
dbManager.closeSession(session)
return transaction
@classmethod
def getLogger(cls):
logger = LoggingManager.getInstance().getLogger(cls.__name__)
return logger
@classmethod
def executeConnectionQuery(cls, query):
connection = None
try:
connection = ApsUserDbManager.getInstance().acquireConnection()
try:
return connection.execute(query)
except DmException, ex:
raise
except Exception, ex:
cls.getLogger().exception('%s' % ex)
raise
finally:
ApsUserDbManager.getInstance().releaseConnection(connection)
def loadRelation(self, dbObject, relationName):
if not relationName in dir(dbObject):
raise InternalError('Relation %s not valid for class %s'
% (relationName, dbObject.__class__.__name__))
o = None
exec 'o = dbObject.%s' % (relationName)
return o
def loadRelations(self, dbObject, optionDict):
for k in optionDict.keys():
# The optionDict contains key-value pairs of relation name
# and a boolean to indicate whether to load that relation
if not optionDict[k]:
continue
try:
self.loadRelation(dbObject, k)
except InternalError, ex:
self.logger.error(ex)
def toDmObjectList(self, dbEntityList):
dmObjectList = []
for dbEntity in dbEntityList:
dmObjectList.append(dbEntity.getDmObject())
return dmObjectList
#######################################################################
# Testing.
if __name__ == '__main__':
api = ApsUserDbApiBase()
#!/usr/bin/env python
import os
from dm.common.exceptions.invalidRequest import InvalidRequest
from dm.common.exceptions.objectNotFound import ObjectNotFound
from dm.common.exceptions.invalidArgument import InvalidArgument
from dm.common.cli.dmCli import DmCli
from dm.common.utility.ldapUserManager import LdapUserManager
from dm.common.utility.configurationManager import ConfigurationManager
from dm.common.utility.loggingManager import LoggingManager
from dm.aps_user_db.api.apsUserDbApi import ApsUserDbApi
class UpdateUserFromApsDbCli(DmCli):
def __init__(self):
DmCli.__init__(self)
self.addOption('', '--badge', dest='badge', help='User badge number.')
self.addOption('', '--config-file', dest='configFile', help='Utility configuration file.')
def checkArgs(self):
if self.options.badge is None:
raise InvalidRequest('Badge number must be provided.')
configFile = self.options.configFile
if configFile is None:
raise InvalidRequest('Config file must be provided.')
if not os.path.exists(configFile):
raise InvalidArgument('Invalid config file: %s.' % configFile)
def getBadge(self):
return self.options.badge
def runCommand(self):
self.parseArgs(usage="""
dm-update-user-from-aps-db --badge=BADGE --config-file=CONFIGFILE
Description:
Updates single user in DM LDAP using information from APS DB. This command will not update DM DB.
""")
ConfigurationManager.getInstance().setConfigFile(self.options.configFile)
LoggingManager.getInstance().configure()
self.checkArgs()
apsUserDbApi = ApsUserDbApi()
badge = self.getBadge()
username = 'd%s' % badge
self.logger.debug('Retrieving APS user with badge %s' % badge)
apsUser = apsUserDbApi.getApsUserByBadgeNumber(badge)
#self.logger.info('APS User Info: %s' % apsUser)
print('APS User Info: %s\n' % apsUser)
ldapUserManager = LdapUserManager.createInstance()
try:
self.logger.debug('Modifying LDAP user with badge %s: %s' % (badge, apsUser['name']))
ldapUser = ldapUserManager.getUserInfo(username)
#self.logger.info('LDAP User Info (before update): %s' % ldapUser)
#self.logger.info('LDAP User Password Hash (before update): %s\n' % ldapUserManager.decodePasswordHash(ldapUser.getUserPassword()))
print('LDAP User Info (before update): %s' % ldapUser)
print('LDAP User Password Hash (before update): %s\n' % ldapUserManager.decodePasswordHash(ldapUser.getUserPassword()))
ldapUserManager.modifyUserInfo(username, apsUser)
ldapUser = ldapUserManager.getUserInfo(username)
except ObjectNotFound, ex:
self.logger.debug('User with badge %s does not exist, creating it' % (badge))
ldapUser = ldapUserManager.createUserInfo(username, apsUser)
#self.logger.info('LDAP User Info (after update): %s' % ldapUser)
#self.logger.info('LDAP User Password Hash (after update): %s\n' % ldapUserManager.decodePasswordHash(ldapUser.getUserPassword()))
print('LDAP User Info (after update): %s' % ldapUser)
print('LDAP User Password Hash (after update): %s\n' % ldapUserManager.decodePasswordHash(ldapUser.getUserPassword()))
#######################################################################
# Run command.
if __name__ == '__main__':
cli = UpdateUserFromApsDbCli()
cli.run()
#!/usr/bin/env python
import datetime
import time
import os
from dm.common.exceptions.invalidRequest import InvalidRequest
from dm.common.exceptions.invalidArgument import InvalidArgument
from dm.common.exceptions.objectAlreadyExists import ObjectAlreadyExists
from dm.common.cli.dmCli import DmCli
from dm.common.db.api.userDbApi import UserDbApi
from dm.common.utility.configurationManager import ConfigurationManager
from dm.common.utility.loggingManager import LoggingManager
from dm.common.utility.ldapUserManager import LdapUserManager
from dm.aps_user_db.api.apsUserDbApi import ApsUserDbApi
from dm.ds_web_service.api.dsRestApiFactory import DsRestApiFactory
class UpdateUsersFromApsDbCli(DmCli):
def __init__(self):
DmCli.__init__(self)
self.addOption('', '--config-file', dest='configFile', help='Utility configuration file.')
self.addOption('', '--without-dm-db', dest='withoutDmDb', action='store_true', default=False, help='Do not use DM DB for synchronizing user information.')
self.addOption('', '--use-dm-rest-api', dest='useDmRestApi', action='store_true', default=False, help='Use DM REST API for accessing user information. This option does not have any effect if --without-dm-db is set.')
self.addOption('', '--quiet', dest='quiet', action='store_true', default=False, help='Do not print any output to console.')
def checkArgs(self):
configFile = self.options.configFile
if configFile is None:
raise InvalidRequest('Config file must be provided.')
if not os.path.exists(configFile):
raise InvalidArgument('Invalid config file: %s.' % configFile)
def runCommand(self):
self.parseArgs(usage="""
dm-update-users-from-aps-db --config-file=CONFIGFILE
[--without-dm-db]
[--use-dm-rest-api]
[--quiet]
Description:
Updates all users in DM LDAP and database using information from APS DB. This command by default uses DM DB to determine whether or not user needs to be created or updated. If the --without-dm-db flag is set, DM DB will not be used nor it will be updated.
""")
startTime = time.time()
ConfigurationManager.getInstance().setConfigFile(self.options.configFile)
LoggingManager.getInstance().configure()
self.checkArgs()
self.logger.debug('Starting sync process')
apsUserDbApi = ApsUserDbApi()
ldapUserManager = LdapUserManager.createInstance()
# Get DM user API
dmUserApi = None
if not self.options.withoutDmDb:
try:
if self.options.useDmRestApi:
self.logger.debug('Using DM REST API')
dmUserApi = DsRestApiFactory.getUserRestApi()
else:
self.logger.debug('Using DM DB API')
dmUserApi = UserDbApi()
except Exception, ex:
self.logger.error('Cannot use DM DB: %s' % ex)
self.logger.debug('Retrieving APS users')
apsUsers = apsUserDbApi.getApsUsers()
self.logger.debug('Number of APS Users: %s' % len(apsUsers))
# Retrieve DM users from DB if we got DM user API
dmUserMap = {}
if dmUserApi:
self.logger.debug('Retrieving DM users from DB')
try:
nDmUsersWithBadge = 0
dmUsers = dmUserApi.getUsers()
self.logger.debug('Number of DM Users: %s' % len(dmUsers))
for dmUser in dmUsers:
username = dmUser.get('username')
if dmUser.get('badge'):
nDmUsersWithBadge += 1
dmUserMap[username] = dmUser
self.logger.debug('Number of DM Users with badge: %s' % nDmUsersWithBadge)
except Exception, ex:
self.logger.error('Error retrieving users from DM DB: %s' % ex)
dmUserApi = None
# We cannot use DM user API, retrieve users from LDAP
if not dmUserApi:
self.logger.debug('Retrieving DM users using LDAP client')
dmUserMap = ldapUserManager.getUserInfoMapByUid()
self.logger.debug('Number of DM LDAP Users: %s' % len(dmUserMap))
nCreatedUsers = 0
nUpdatedUsers = 0
nErrors = 0
for apsUser in apsUsers:
apsLastChangeDate = apsUser.get('lastChangeDate')
# DM DB attributes
badge = apsUser['badgeNumber']
username = 'd%s' % badge
firstName = apsUser.get('firstName')
middleName = apsUser.get('middleName')
lastName = apsUser.get('lastName')
email = apsUser.get('email')
isLocalUser = 0
lastUpdate = str(apsLastChangeDate)
globusUsername = None
description = None
password = None
# LDAP attributes
ldapModAttrDict = {}
ldapModAttrDict['gecos'] = apsUser['name']
ldapModAttrDict['userPassword'] = apsUser['passwordHashValue']
dmUser = dmUserMap.get(username)
if not dmUser:
# We must create user in LDAP/DM DB
try:
try:
self.logger.debug('Creating LDAP user with badge %s: %s' % (badge, apsUser['name']))
ldapUser = ldapUserManager.createUserInfo(username, apsUser)
except ObjectAlreadyExists, ex:
# LDAP user already exists, simply update it.
self.logger.debug('LDAP user with badge %s already exists, attempting to modify it' % (badge))
ldapUserManager.modifyUserInfo(username, ldapModAttrDict)
except Exception, ex:
self.logger.error('LDAP problem caught while creating user with badge %s: %s' % (badge, str(ex)))
nErrors += 1
continue
if dmUserApi:
try:
self.logger.debug('Creating DM DB user with badge %s: %s' % (badge, apsUser['name']))
dmUserApi.addUser(username, firstName, lastName, middleName, email, badge, globusUsername, description, password, isLocalUser, lastUpdate)
nCreatedUsers += 1
except Exception, ex:
self.logger.error('DM DB problem caught while creating user with badge %s: %s' % (badge, str(ex)))
nErrors += 1
continue
else:
# User already exists, simply update it.
if dmUserApi:
# We have DM DB API
dmLastUpdate = str(dmUser.get('lastUpdate'))
if dmLastUpdate:
# need to convert DM last update time to datetime object
# datetime cannot handle time zone at the moment
timeZonePos = dmLastUpdate.rfind('-')
dmLastUpdate = dmLastUpdate[0:timeZonePos]
# remove microseconds from the timestamp
secondPos = dmLastUpdate.rfind('.')
if secondPos > 0:
dmLastUpdate = dmLastUpdate[0:secondPos]
dmLastUpdate = datetime.datetime.strptime(dmLastUpdate, '%Y-%m-%d %H:%M:%S')
if not dmLastUpdate or dmLastUpdate < apsLastChangeDate:
# User needs update
try:
self.logger.debug('Modifying LDAP user with badge %s, username %s' % (badge, username))
ldapUserManager.modifyUserInfo(username, ldapModAttrDict)
except Exception, ex:
self.logger.error('LDAP problem caught while modifying user with badge %s: %s' % (badge, str(ex)))
nErrors += 1
continue
try:
id = dmUser.get('id')
self.logger.debug('Modifying DM DB user with badge %s: %s (DM id: %s)' % (badge, apsUser['name'], id))
dmUserApi.updateUser(id, username, firstName, lastName, middleName, email, badge, globusUsername, description, password, isLocalUser, lastUpdate)
nUpdatedUsers += 1
except Exception, ex:
self.logger.error('DM DB problem caught while modifying user with badge %s: %s' % (badge, str(ex)))
nErrors += 1
continue
else:
# User is up to date
continue
else:
# No DM DB API
apsPasswordHash = apsUser['passwordHashValue']
dmPasswordHash = ldapUserManager.decodePasswordHash(dmUser['userAttrs']['userPassword'][0])
if apsPasswordHash != dmPasswordHash:
# User needs update
try:
self.logger.debug('Modifying LDAP user with badge %s, username %s' % (badge, username))
#self.logger.debug('APS password hash: %s, DM password hash: %s' % (apsPasswordHash, dmPasswordHash))
#self.logger.debug('Encoded DM password hash: %s' % (dmUser['userAttrs']['userPassword'][0]))
ldapUserManager.modifyUserInfo(username, ldapModAttrDict)
nUpdatedUsers += 1
except Exception, ex:
self.logger.error('LDAP problem caught while modifying user with badge %s: %s' % (badge, str(ex)))
nErrors += 1
continue
else:
# User is up to date
continue
endTime = time.time()
runTime = endTime - startTime
self.logger.debug('Number of new DM users: %s' % (nCreatedUsers))
self.logger.debug('Number of updated DM users: %s' % (nUpdatedUsers))
self.logger.debug('Number of update errors: %s' % (nErrors))
self.logger.debug('Completed sync process in %.3f seconds' % runTime)
if not self.options.quiet:
print('Number of new DM users: %s' % (nCreatedUsers))
print('Number of updated DM users: %s' % (nUpdatedUsers))
print('Number of update errors: %s' % (nErrors))
print('Sync process runtime: %.3f seconds' % (runTime))
#######################################################################
# Run command.
if __name__ == '__main__':
cli = UpdateUsersFromApsDbCli()
cli.run()
#!/usr/bin/env python
from dm.aps_user_db.entities.apsUserInfo import ApsUserInfo
# Map db table/db entity class
# Use generic 'self' key as name for primary key mapping (needed by sqlalchemy)
APS_USER_DB_ENTITY_MAP = {
'FL$03_BL_APV_VIEW_V2' : (ApsUserInfo, {'self' : {'primary_key' : 'badge_no'}}),
}
#!/usr/bin/env python
from dm.common.db.entities.dmDbEntity import DmDbEntity
from dm.common.objects import apsUserInfo
class ApsUserInfo(DmDbEntity):
mappedColumnDict = {
'badge_no' : 'badgeNumber',
'first_name' : 'firstName',
'middle_name' : 'middleName',
'last_name' : 'lastName',
'last_change_date' : 'lastChangeDate',
'pwd_hash_value' : 'passwordHashValue',
'is_usr_not_anl_emp' : 'isUserNotAnlEmployee',
}
dmObjectClass = apsUserInfo.ApsUserInfo
def __init__(self, **kwargs):
DmDbEntity.__init__(self, **kwargs)
#!/usr/bin/env python
import threading
import os.path
import sqlalchemy
</