diff --git a/src/python/dm/__init__.py b/src/python/dm/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..64fb7c078e180aba8caf527978f382a31d614730 --- /dev/null +++ b/src/python/dm/__init__.py @@ -0,0 +1 @@ +__version__ = "Development Snapshot (2015.03.31)" diff --git a/src/python/dm/common/api/__init__.py b/src/python/dm/common/api/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/src/python/dm/common/api/dmApi.py b/src/python/dm/common/api/dmApi.py new file mode 100755 index 0000000000000000000000000000000000000000..4c6f46212e8a0a049da43b91a0fc666232b4d87f --- /dev/null +++ b/src/python/dm/common/api/dmApi.py @@ -0,0 +1,36 @@ +#!/usr/bin/env python + +import json +from dm.common.exceptions.dmException import DmException +from dm.common.utility.loggingManager import LoggingManager + +class DmApi(object): + """ Base dm api class. """ + def __init__(self, username = None, password = None): + self.logger = LoggingManager.getInstance().getLogger(self.__class__.__name__) + + @classmethod + def getLogger(cls): + logger = LoggingManager.getInstance().getLogger(cls.__name__) + return logger + + @classmethod + def toDmObjectList(cls, dictList, dmObjectClass): + dmObjectList = [] + for dict in dictList: + dmObjectList.append(dmObjectClass(dict)) + return dmObjectList + + # Exception decorator for all api calls + @classmethod + def execute(cls, func): + def decorate(*args, **kwargs): + try: + response = func(*args, **kwargs) + return response + except DmException, ex: + raise + except Exception, ex: + cls.getLogger().exception('%s' % ex) + raise DmException(exception=ex) + return decorate diff --git a/src/python/dm/common/api/dmRestApi.py b/src/python/dm/common/api/dmRestApi.py new file mode 100755 index 0000000000000000000000000000000000000000..0c8e18c67fc7dcd9d7b66432dbf019294b4fc6ed --- /dev/null +++ b/src/python/dm/common/api/dmRestApi.py @@ -0,0 +1,138 @@ +#!/usr/bin/env python + +import socket +import json + +from dm.common.utility.loggingManager import LoggingManager +from dm.common.client.sessionManager import SessionManager +from dm.common.utility.configurationManager import ConfigurationManager +from dm.common.exceptions.authorizationError import AuthorizationError +from dm.common.api.dmApi import DmApi + +class DmRestApi(DmApi): + """ Base dm REST api class. """ + + def __init__(self, username=None, password=None, host=None, port=None, protocol=None): + DmApi.__init__(self) + self.configurationManager = ConfigurationManager.getInstance() + if username == None and password == None: + username = self.configurationManager.getServiceUsername() + password = self.configurationManager.getServicePassword() + if host == None: + host = self.configurationManager.getServiceHost() + if port == None: + port = self.configurationManager.getServicePort() + if protocol == None: + protocol = self.configurationManager.getServiceProtocol() + self.username = username + self.password = password + self.host = host + self.port = port + self.protocol = protocol + self.sessionManager = None + + @classmethod + def toJson(cls, o): + return json.dumps(o) + + @classmethod + def fromJson(cls, s): + return json.loads(s) + + def __getWebServiceUrl(self, url): + if url.find('://') < 0: + return '%s://%s:%s' % (self.protocol, socket.gethostbyname(self.host), self.port) + + # Break the URL down into component pieces + from urlparse import urlparse + o = urlparse(url) + wsUrl = '%s://%s' % (o[0], o[1]) + return wsUrl + + def getContextRoot(self): + return self.configurationManager.getContextRoot() + + def setUsername(self, username): + self.username = username + + def getUsername(self): + return self.username + + def setPassword(self, password): + self.password = password + + def getPassword(self): + return self.password + + def setHost(self, host): + self.host = host + + def getHost(self): + return self.host + + def setPort(self, port): + self.port = port + + def getPort(self): + return self.port + + def setProtocol(self, protocol): + self.protocol = protocol + + def getProtocol(self): + return self.protocol + + def getSessionManager(self): + if not self.sessionManager: + self.sessionManager = SessionManager() + return self.sessionManager + + def getConfigManager(self): + return self.configurationManager + + def sendSessionRequest(self, url, method, contentType='html', data={}): + """ Send authorized session request. """ + sm = self.getSessionManager() + if not sm.hasSession(): + if self.username == None: + raise AuthorizationError('Username not supplied.') + if self.password == None: + raise AuthorizationError('Password not supplied.') + wsUrl = self.__getWebServiceUrl(url) + # establishSession() sets the 'wsUrl' so the explicit call + # to setHost() is not required + sm.establishSession(wsUrl, self.username, self.password) + (response, responseData) = sm.sendSessionRequest(url, method, contentType, data) + return json.loads(responseData) + + def sendRequest(self, url, method, contentType='html', data={}): + """ Send non-authorized request. """ + sm = self.getSessionManager() + # Because there's no call to establishSession(), explicitly call + # setHost() + sm.setHost(self.__getWebServiceUrl(url)) + (response, responseData) = self.getSessionManager().sendRequest(url, method, contentType, data) + return json.loads(responseData) + +####################################################################### +# Testing. + +if __name__ == '__main__': + api = DmRestApi('sveseli', 'sveseli') + #api.sendRequest('https://zagreb.svdev.net:10232/dm/directory/list', 'GET', data='') + import urllib + from dm.common.utility.configurationManager import ConfigurationManager + cm = ConfigurationManager.getInstance() + cm.setSessionCacheFile('/tmp/session') + #print 'Non-session request' + #print api.sendRequest('https://zagreb.svdev.net:10232/dm/directory/list?path=/tmp', 'GET') + print 'Session request' + data = { 'path' : '/tmp/xyz' } + #print api.sendSessionRequest('https://zagreb.svdev.net:10232/dm/file/write?path=/tmp/xyz&content=xyz', 'POST', contentType='application/x-www-form-urlencoded', data=urllib.urlencode(data)) + #print api.sendSessionRequest('https://zagreb.svdev.net:10232/dm/file/write', 'POST', data=data) + postdata='path=/tmp/xyz' + postdata+='&content=%s' % urllib.quote_plus('Hey there') + print api.sendSessionRequest('https://zagreb.svdev.net:10232/dm/file/write', 'POST', contentType='application/x-www-form-urlencoded', data=postdata) + + + diff --git a/src/python/dm/common/cli/__init__.py b/src/python/dm/common/cli/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/src/python/dm/common/cli/dmCli.py b/src/python/dm/common/cli/dmCli.py new file mode 100755 index 0000000000000000000000000000000000000000..03927efff5527d050a15f2152ff3e35cb15f1410 --- /dev/null +++ b/src/python/dm/common/cli/dmCli.py @@ -0,0 +1,293 @@ +#!/usr/bin/env python + +import sys +import os +import os.path +import stat +from optparse import OptionGroup + +import dm +from dm.common.utility.loggingManager import LoggingManager +from dm.common.utility.configurationManager import ConfigurationManager +from dm.common.utility.osUtility import OsUtility +from dm.common.objects.dmObject import DmObject +from dm.common.exceptions.dmException import DmException +from dm.common.exceptions.invalidRequest import InvalidRequest +from dm.common.exceptions.invalidArgument import InvalidArgument +from dm.common.exceptions.internalError import InternalError +from dm.common.cli.dmOptionParser import DmOptionParser +from dm.common.constants import dmStatus + +class DmCli(object): + """ Base dm command line interface class. """ + DEFAULT_SESSION_CACHE_FILE = OsUtility.getUserHomeDir() + '/.dm/.session.cache' + def __init__(self, validArgCount=0): + self.logger = LoggingManager.getInstance().getLogger(self.__class__.__name__) + # Do not log into a file for CLIs + LoggingManager.getInstance().setFileLogLevel('CRITICAL') + LoggingManager.getInstance().setConsoleLogLevel('CRITICAL') + self.parser = DmOptionParser() + self.options = {} + self.args = [] + self.validArgCount = validArgCount + self.serviceHost = None + self.servicePort = None + self.optionGroupDict = {} + + commonGroup = 'Common Options' + self.addOptionGroup(commonGroup, None) + self.addOptionToGroup(commonGroup, '-h', '--help', action='help', help='Show this help message and exit.') + self.addOptionToGroup(commonGroup, '-?', '', action='help', help='Show this help message and exit.') + self.addOptionToGroup(commonGroup, '-v', '--version', action='store_true', dest='version', default=False, help='Print version and exit.') + self.addOptionToGroup(commonGroup, '-d', '--debug', dest='consoleLogLevel', help='Set debug level (valid values: CRITICAL, ERROR, WARNING, INFO, DEBUG). Console log level can also be set via DM_CONSOLE_LOG_LEVEL environment variable,') + self.addOptionToGroup(commonGroup, '', '--display-format', dest='displayFormat', default=DmObject.TEXT_DISPLAY_FORMAT, help='Display format for output objects. Possible options are: %s, %s, and %s (default: %s).' % (DmObject.TEXT_DISPLAY_FORMAT, DmObject.DICT_DISPLAY_FORMAT, DmObject.JSON_DISPLAY_FORMAT, DmObject.TEXT_DISPLAY_FORMAT)) + self.addOptionToGroup(commonGroup, '', '--display-keys', dest='displayKeys', default=DmObject.DEFAULT_KEYS, help='List of output object keys to display. Possible options are: %s, %s, and string containing comma-separated keys (default: %s, represents class default keys).' % (DmObject.DEFAULT_KEYS, DmObject.ALL_KEYS, DmObject.DEFAULT_KEYS)) + + # These will be set via env variables + self.addOptionToGroup(commonGroup, '', '--service-host', dest='serviceHost', default=self.getDefaultServiceHost(), help='Service host (default: %s, can be set via DM_SERVICE_HOST environment variable).' % self.getDefaultServiceHost()) + self.addOptionToGroup(commonGroup, '', '--service-port', dest='servicePort', default=self.getDefaultServicePort(), help='Service port (default: %s, can be set via DM_SERVICE_PORT environment variable).' % self.getDefaultServicePort()) + self.addOptionToGroup(commonGroup, '', '--service-protocol', dest='serviceProtocol', default=self.getDefaultServiceProtocol(), help='Service protocol (default: %s, can be set via DM_SERVICE_PROTOCOL environment variable).' % self.getDefaultServiceProtocol()) + + # SSL options, disabled for now. + #self.addOptionToGroup(commonGroup, '', '--ssl-key', dest='sslKeyFile', help='SSL key file (needed if service requires peer verification, can be set via DM_SSL_KEY_FILE environment variable).') + #self.addOptionToGroup(commonGroup, '', '--ssl-cert', dest='sslCertFile', help='SSL certificate file (needed if service requires peer verification, can be set via DM_SSL_CERT_FILE environment variable).') + #self.addOptionToGroup(commonGroup, '', '--ssl-ca-cert', dest='sslCaCertFile', help='SSL CA certificate file (needed if client requires peer verification, can be set via DM_SSL_CA_CERT_FILE environment variable).') + + def getDefaultServiceHost(self): + return ConfigurationManager.getInstance().getServiceHost() + + def getDefaultServicePort(self): + return ConfigurationManager.getInstance().getServicePort() + + def getDefaultServiceProtocol(self): + return ConfigurationManager.getInstance().getServiceProtocol() + + def getUsername(self): + return None + + def getPassword(self): + return None + + def getDisplayFormat(self): + return self.options.displayFormat + + def getDisplayKeys(self): + return self.options.displayKeys + + def getLogger(self): + return self.logger + + def getParser(self): + return self.parser + + def addOption(self, *args, **kwargs): + self.parser.add_option(*args, **kwargs) + + def addOptionToGroup(self, groupName, *args, **kwargs): + """ Add group option. Group must be created using addOptionGroup(). """ + group = self.optionGroupDict.get(groupName) + group.add_option(*args, **kwargs) + + def addOptionGroup(self, groupName, desc): + group = OptionGroup(self.parser, groupName, desc) + self.parser.add_option_group(group) + self.optionGroupDict[groupName] = group + + def processArgs(self): + pass + + def parseArgs(self, usage=None): + if usage: + self.parser.usage = usage + try: + (self.options, self.args) = self.parser.parse_args() + self.processArgs() + except SystemExit, rc: + sys.stdout.flush() + sys.stderr.flush() + sys.exit(int(str(rc))) + + if self.validArgCount < len(self.args): + # Positional args are not enabled and we have some + msg = 'Invalid positional argument(s):' + for arg in self.args[self.validArgCount:]: + msg += ' ' + arg + msg += ' (This command allows %s positional arguments.)' % self.validArgCount + raise InvalidArgument(msg) + + optDict = self.options.__dict__ + if optDict.get('version'): + print 'DM Software Version: %s' % (dm.__version__) + sys.exit(0) + + # Logging level. First try from command line, then from env variable. + consoleLogLevel = optDict.get('consoleLogLevel', None) + if consoleLogLevel: + LoggingManager.getInstance().setConsoleLogLevel(consoleLogLevel) + else: + consoleLogLevel = ConfigurationManager.getInstance().getConsoleLogLevelFromEnvVar() + if consoleLogLevel: + LoggingManager.getInstance().setConsoleLogLevel(consoleLogLevel) + + # Service host, port, etc. + configManager = ConfigurationManager.getInstance() + self.serviceHost = self.options.serviceHost + configManager.setServiceHost(self.serviceHost) + self.servicePort = self.options.servicePort + configManager.setServicePort(self.servicePort) + self.serviceProtocol = self.options.serviceProtocol + configManager.setServiceProtocol(self.serviceProtocol) + + # SSL options, comment out for now + #self.sslCaCertFile = self.options.sslCaCertFile + #if self.sslCaCertFile: + # configManager.setSslCaCertFile(self.sslCaCertFile) + #self.sslCertFile = self.options.sslCertFile + #if self.sslCertFile: + # configManager.setSslCertFile(self.sslCertFile) + #self.sslKeyFile = self.options.sslKeyFile + #if self.sslKeyFile: + # configManager.setSslKeyFile(self._sslKeyFile) + + # Check session cache. + try: + self.checkSessionCache() + except Exception, ex: + self.logger.warn('Disabling session cache: %s' % ex) + configManager.setSessionCacheFile(None) + + return (self.options, self.args) + + def checkSessionCache(self): + configManager = ConfigurationManager.getInstance() + sessionCacheFile = configManager.getSessionCacheFile() + if sessionCacheFile is None: + sessionCacheFile = DmCli.DEFAULT_SESSION_CACHE_FILE + sessionCacheFile = sessionCacheFile.strip() + if len(sessionCacheFile): + sessionCacheDir = os.path.dirname(sessionCacheFile) + OsUtility.createDir(sessionCacheDir, stat.S_IRUSR|stat.S_IWUSR|stat.S_IXUSR) + configManager.setSessionCacheFile(sessionCacheFile) + configManager.setRequireSessionCredentials(True) + + def usage(self, s=None): + """ Print help provided by optparse. """ + if s: + print >>sys.stderr, 'Error: ', s, '\n' + self.parser.print_help() + sys.exit(dmStatus.DM_ERROR) + + def getOptions(self): + return self.options + + def getNArgs(self): + """ Returns the number of command line arguments. """ + return len(self.args) + + def getArgs(self): + """ Returns the command line argument list. """ + return self.args + + def getArg(self, i): + """ Returns the i-th command line argument. """ + return self.args[i] + + def getServiceHost(self): + #return self.serviceHost + return ConfigurationManager.getInstance().getServiceHost() + + def getServicePort(self): + #return self.servicePort + return ConfigurationManager.getInstance().getServicePort() + + def getServiceProtocol(self): + #return self.serviceProtocol + return ConfigurationManager.getInstance().getServiceProtocol() + + def getSslCaCertFile(self): + return self.sslCaCertFile + + def getSslCertFile(self): + return self.sslCertFile + + def getSslKeyFile(self): + return self.sslKeyFile + + def displayDmObject(self, dmObject): + if isinstance(dmObject, dmObject): + return '%s' % dmObject.getJsonRep() + else: + return '%s' % dmObject + + def runCommand(self): + """ This method must be implemented by the derived class. """ + raise InternalError('Method runCommand() must be overriden in the derived class.') + + def run(self): + """ This method invokes runCommand() and handles any exceptions. """ + try: + self.runCommand() + except DmException, ex: + self.logger.exception('%s' % ex) + print '%s' % ex.getErrorMessage() + raise SystemExit(ex.getErrorCode()) + except SystemExit, ex: + raise + except Exception, ex: + self.logger.exception('%s' % ex) + print >>sys.stderr, '%s' % ex + raise SystemExit(dmStatus.DM_ERROR) + + def getId(self): + id = self.options.id + if id == None: + raise InvalidRequest('Missing id.') + return id + + def displayDmObject(self, dmObject): + optDict = self._options.__dict__ + if isinstance(dmObject, DmObject): + if optDict.get('dict'): + return '%s' % dmObject + else: + return dmObject.display() + else: + return '%s' % dmObject + +####################################################################### +# Testing + +if __name__ == '__main__': + cli = DmCli(3) + cli.addOption("-f", "--file", dest="filename", help="write report to FILE", metavar="FILE") + cli.addOption("-q", "--quiet", action="store_false", dest="verbose", default=True, help="don't print log messages to stdout") + (options, args) = cli.parseArgs() + print 'After parse:' + print 'OPTIONS: ', options + print 'ARGS: ', args + print 'From CLI' + print 'OPTIONS: ', cli.getOptions() + print 'ARGS: ', cli.getArgs() + print + print 'FILENAME' + print 'options.filename', options.filename + print 'cli.getOptions().filename', cli.getOptions().filename + o = cli.getOptions() + print 'o.filename', o.filename + print 'cli.getArgs()', cli.getArgs() + print 'len(cli.getArgs())', len(cli.getArgs()) + + for a in cli.getArgs(): + print 'arg', a + + first_arg = cli.getArg(0) + print 'first_arg', first_arg + + second_arg = cli.getArg(1) + print 'second_arg', second_arg + + try: + third_arg = cli.getArg(2) + print 'third_arg', third_arg + except: + print 'no third arg' diff --git a/src/python/dm/common/cli/dmOptionParser.py b/src/python/dm/common/cli/dmOptionParser.py new file mode 100755 index 0000000000000000000000000000000000000000..149b94ec528543be0d35ec8b9c615d80bb385e6d --- /dev/null +++ b/src/python/dm/common/cli/dmOptionParser.py @@ -0,0 +1,57 @@ +#!/usr/bin/env python + +import sys +from optparse import OptionParser +from cStringIO import StringIO + +class DmOptionParser(OptionParser): + def __init__(self): + OptionParser.__init__(self, add_help_option=False) + + def replaceKeys(self, output): + replacementMap = { + 'usage:' : 'Usage:', + 'options:' : 'Options:', + } + result = output + for (key, value) in replacementMap.items(): + result = result.replace(key, value) + return result + + def printUsage(self, file=None): + self.print_usage(file) + + # Replaces base class method + def print_usage(self, file=None): + sysStdout = sys.stdout + cliStdout = StringIO() + sys.stdout = cliStdout + OptionParser.print_usage(self, file) + sys.stdout = sysStdout + print self.replaceKeys(cliStdout.getvalue()) + + def printHelp(self, file=None): + self.printHelp(file) + + # Replaces base class method + def print_help(self, file=None): + sysStdout = sys.stdout + cliStdout = StringIO() + sys.stdout = cliStdout + OptionParser.print_help(self, file) + sys.stdout = sysStdout + print self.replaceKeys(cliStdout.getvalue()) + +####################################################################### +# Testing + +if __name__ == '__main__': + p = DmOptionParser() + p.add_option('-f', '--file', dest='filename', + help='write report to FILE', metavar='FILE') + p.add_option('-q', '--quiet', + action='store_false', dest='verbose', default=True, + help='do not print log messages to standard output') + p.parse_args() + p.print_usage() + p.print_help() diff --git a/src/python/dm/common/cli/dmRestCli.py b/src/python/dm/common/cli/dmRestCli.py new file mode 100755 index 0000000000000000000000000000000000000000..0107fdac4d5bd9bf97fb7b013f57141689f97506 --- /dev/null +++ b/src/python/dm/common/cli/dmRestCli.py @@ -0,0 +1,10 @@ +#!/usr/bin/env python + +from dm.common.cli.dmCli import DmCli + +class DmRestCli(DmCli): + """ Base dm REST cli class. """ + + def __init__(self, validArgCount=0): + DmCli.__init__(self, validArgCount) + diff --git a/src/python/dm/common/cli/dmRestSessionCli.py b/src/python/dm/common/cli/dmRestSessionCli.py new file mode 100755 index 0000000000000000000000000000000000000000..30f93a2b8daffdd84009708d15952cea3c365747 --- /dev/null +++ b/src/python/dm/common/cli/dmRestSessionCli.py @@ -0,0 +1,37 @@ +#!/usr/bin/env python + +from dm.common.cli.dmRestCli import DmRestCli + +class DmRestSessionCli(DmRestCli): + """ Base dm session cli class. """ + + def __init__(self, validArgCount=0): + DmRestCli.__init__(self, validArgCount) + self.username = None + self.password = None + + loginGroup = 'Login Options' + self.addOptionGroup(loginGroup, None) + self.addOptionToGroup(loginGroup, '', '--username', dest='username', help='Login username.') + self.addOptionToGroup(loginGroup, '', '--password', dest='password', help='Login password.') + + def parseArgs(self, usage=None): + DmRestCli.parseArgs(self, usage) + self.username = self.options.username + self.password = self.options.password + return (self.options, self.args) + + def getUsername(self): + return self.username + + def getPassword(self): + return self.password + + def hasCredentials(self): + return (self.username != None and self.password != None) + +####################################################################### +# Testing + +if __name__ == '__main__': + pass diff --git a/src/python/dm/common/constants/__init__.py b/src/python/dm/common/constants/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/src/python/dm/common/constants/dmHttpHeaders.py b/src/python/dm/common/constants/dmHttpHeaders.py new file mode 100755 index 0000000000000000000000000000000000000000..fc8af0e6610ebe37e2811e563e04091e1338a383 --- /dev/null +++ b/src/python/dm/common/constants/dmHttpHeaders.py @@ -0,0 +1,9 @@ +#!/usr/bin/env python + +####################################################################### + +DM_SESSION_ROLE_HTTP_HEADER = 'Dm-Session-Role' +DM_STATUS_CODE_HTTP_HEADER = 'Dm-Status-Code' +DM_STATUS_MESSAGE_HTTP_HEADER = 'Dm-Status-Message' +DM_EXCEPTION_TYPE_HTTP_HEADER = 'Dm-Exception-Type' + diff --git a/src/python/dm/common/constants/dmHttpStatus.py b/src/python/dm/common/constants/dmHttpStatus.py new file mode 100755 index 0000000000000000000000000000000000000000..24460c024f5e969e465ddb0d543a077ac6764726 --- /dev/null +++ b/src/python/dm/common/constants/dmHttpStatus.py @@ -0,0 +1,6 @@ +#!/usr/bin/env python + + +DM_HTTP_OK = 200 +DM_HTTP_UNAUTHORIZED = 401 +DM_HTTP_INTERNAL_ERROR = 500 diff --git a/src/python/dm/common/constants/dmRole.py b/src/python/dm/common/constants/dmRole.py new file mode 100755 index 0000000000000000000000000000000000000000..801a9391de13d8542c93f1b839573c24028e8efa --- /dev/null +++ b/src/python/dm/common/constants/dmRole.py @@ -0,0 +1,8 @@ +#!/usr/bin/env python + +####################################################################### + +DM_ADMIN_ROLE = 'admin' +DM_USER_ROLE = 'user' + + diff --git a/src/python/dm/common/constants/dmServiceConstants.py b/src/python/dm/common/constants/dmServiceConstants.py new file mode 100755 index 0000000000000000000000000000000000000000..1a1419358cf3136cd95f1d98c844e427a38f6d7f --- /dev/null +++ b/src/python/dm/common/constants/dmServiceConstants.py @@ -0,0 +1,6 @@ +#!/usr/bin/env python + +####################################################################### + +DM_SERVICE_PROTOCOL_HTTP = 'http' +DM_SERVICE_PROTOCOL_HTTPS = 'https' diff --git a/src/python/dm/common/constants/dmStatus.py b/src/python/dm/common/constants/dmStatus.py new file mode 100755 index 0000000000000000000000000000000000000000..3a6fadd95c6af0d2130aa420a2ad51147136bbaf --- /dev/null +++ b/src/python/dm/common/constants/dmStatus.py @@ -0,0 +1,24 @@ +#!/usr/bin/env python + +####################################################################### + +DM_OK = 0 +DM_ERROR = 1 +DM_INTERNAL_ERROR = 2 +DM_COMMUNICATION_ERROR = 3 +DM_CONFIGURATION_ERROR = 4 +DM_AUTHORIZATION_ERROR = 5 +DM_AUTHENTICATION_ERROR = 6 +DM_DB_ERROR = 7 +DM_URL_ERROR = 8 +DM_TIMEOUT = 9; +DM_INVALID_ARGUMENT = 10 +DM_INVALID_REQUEST = 11 +DM_INVALID_SESSION = 12; +DM_COMMAND_FAILED =13 +DM_OBJECT_NOT_FOUND = 14 +DM_OBJECT_ALREADY_EXISTS = 15 +DM_INVALID_OBJECT_STATE = 16; + + + diff --git a/src/python/dm/common/exceptions/__init__.py b/src/python/dm/common/exceptions/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/src/python/dm/common/exceptions/authenticationError.py b/src/python/dm/common/exceptions/authenticationError.py new file mode 100755 index 0000000000000000000000000000000000000000..d905fdb62918dbd7d263fa9cd8745888af37931f --- /dev/null +++ b/src/python/dm/common/exceptions/authenticationError.py @@ -0,0 +1,16 @@ +#!/usr/bin/env python + +# +# Authentication error class. +# + +####################################################################### + +from dm.common.constants import dmStatus +from dm.common.exceptions.dmException import DmException + +####################################################################### + +class AuthenticationError(DmException): + def __init__ (self, error='', **kwargs): + DmException.__init__(self, error, dmStatus.DM_AUTHENTICATION_ERROR, **kwargs) diff --git a/src/python/dm/common/exceptions/authorizationError.py b/src/python/dm/common/exceptions/authorizationError.py new file mode 100755 index 0000000000000000000000000000000000000000..09d348851c720c03d499c4b83060c8f8b794a1b3 --- /dev/null +++ b/src/python/dm/common/exceptions/authorizationError.py @@ -0,0 +1,16 @@ +#!/usr/bin/env python + +# +# Authorization error class. +# + +####################################################################### + +from dm.common.constants import dmStatus +from dm.common.exceptions.dmException import DmException + +####################################################################### + +class AuthorizationError(DmException): + def __init__ (self, error='', **kwargs): + DmException.__init__(self, error, dmStatus.DM_AUTHORIZATION_ERROR, **kwargs) diff --git a/src/python/dm/common/exceptions/commandFailed.py b/src/python/dm/common/exceptions/commandFailed.py new file mode 100755 index 0000000000000000000000000000000000000000..3b757e5204bf0abe45f9b8d21281b440dc661087 --- /dev/null +++ b/src/python/dm/common/exceptions/commandFailed.py @@ -0,0 +1,16 @@ +#!/usr/bin/env python + +# +# Command failed exception class. +# + +####################################################################### + +from dm.common.constants import dmStatus +from dm.common.exceptions.dmException import DmException + +####################################################################### + +class CommandFailed(DmException): + def __init__ (self, error='', **kwargs): + DmException.__init__(self, error, dmStatus.DM_COMMAND_FAILED, **kwargs) diff --git a/src/python/dm/common/exceptions/communicationError.py b/src/python/dm/common/exceptions/communicationError.py new file mode 100755 index 0000000000000000000000000000000000000000..eb0e025f2bf4a1407bd4cef40aa395a976b64631 --- /dev/null +++ b/src/python/dm/common/exceptions/communicationError.py @@ -0,0 +1,16 @@ +#!/usr/bin/env python + +# +# Communication error class. +# + +####################################################################### + +from dm.common.constants import dmStatus +from dm.common.exceptions.dmException import DmException + +####################################################################### + +class CommunicationError(DmException): + def __init__ (self, error='', **kwargs): + DmException.__init__(self, error, dmStatus.DM_COMMUNICATION_ERROR, **kwargs) diff --git a/src/python/dm/common/exceptions/configurationError.py b/src/python/dm/common/exceptions/configurationError.py new file mode 100755 index 0000000000000000000000000000000000000000..cd6ae7a9113a1902ca97afcce96cd256c95ed3d0 --- /dev/null +++ b/src/python/dm/common/exceptions/configurationError.py @@ -0,0 +1,16 @@ +#!/usr/bin/env python + +# +# Configuration error class. +# + +####################################################################### + +from dm.common.constants import dmStatus +from dm.common.exceptions.dmException import DmException + +####################################################################### + +class ConfigurationError(DmException): + def __init__ (self, error='', **kwargs): + DmException.__init__(self, error, dmStatus.DM_CONFIGURATION_ERROR, **kwargs) diff --git a/src/python/dm/common/exceptions/dbError.py b/src/python/dm/common/exceptions/dbError.py new file mode 100755 index 0000000000000000000000000000000000000000..e9d498c36a1f0b2c15a6ae956071fb3adb5de56a --- /dev/null +++ b/src/python/dm/common/exceptions/dbError.py @@ -0,0 +1,16 @@ +#!/usr/bin/env python + +# +# DB error class. +# + +####################################################################### + +from dm.common.constants import dmStatus +from dm.common.exceptions.dmException import DmException + +####################################################################### + +class DbError(DmException): + def __init__ (self, error='', **kwargs): + DmException.__init__(self, error, dmStatus.DM_DB_ERROR, **kwargs) diff --git a/src/python/dm/common/exceptions/dmException.py b/src/python/dm/common/exceptions/dmException.py new file mode 100755 index 0000000000000000000000000000000000000000..517427a20e5f1d174fbf1a725ffd554659dd8d68 --- /dev/null +++ b/src/python/dm/common/exceptions/dmException.py @@ -0,0 +1,64 @@ +#!/usr/bin/env python + +# +# Base DM exception class. +# + +####################################################################### + +import exceptions +import json + +from dm.common.constants import dmStatus + +####################################################################### + +class DmException(exceptions.Exception): + """ + Base DM exception class. + + Usage: + DmException(errorMessage, errorCode) + DmException(args=errorMessage) + DmException(exception=exceptionObject) + """ + def __init__(self, error='', code=dmStatus.DM_ERROR, **kwargs): + args = error + if args == '': + args = kwargs.get('args', '') + ex = kwargs.get('exception', None) + if ex != None: + if isinstance(ex, exceptions.Exception): + exArgs = '%s' % (ex) + if args == '': + args = exArgs + else: + args = "%s (%s)" % (args, exArgs) + exceptions.Exception.__init__(self, args) + self.code = code + + def getArgs(self): + return self.args + + def getErrorCode(self): + return self.code + + def getErrorMessage(self): + return '%s' % (self.args) + + def getClassName(self): + return '%s' % (self.__class__.__name__) + + def getExceptionType(self): + return '%s' % (self.__class__.__name__).split('.')[-1] + + def getJsonRep(self): + return json.dumps({ + 'errorMessage' : self.getErrorMessage(), + 'errorCode' : self.getErrorCode(), + 'exceptionType' : self.getExceptionType(), + }) + + def getFullJsonRep(self): + return self.getJsonRep(); + diff --git a/src/python/dm/common/exceptions/dmExceptionMap.py b/src/python/dm/common/exceptions/dmExceptionMap.py new file mode 100755 index 0000000000000000000000000000000000000000..c5edee4ab46f52657f7e499f121086fc485483b5 --- /dev/null +++ b/src/python/dm/common/exceptions/dmExceptionMap.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python + +from dm.common.constants import dmStatus + +DM_EXCEPTION_MAP = { + dmStatus.DM_ERROR : 'dmException.DmException', + dmStatus.DM_INTERNAL_ERROR : 'internalError.InternalError', + dmStatus.DM_COMMUNICATION_ERROR : 'communicationError.CommunicationError', + dmStatus.DM_CONFIGURATION_ERROR : 'configurationError.ConfigurationError', + dmStatus.DM_AUTHORIZATION_ERROR : 'authorizationError.AuthorizationError', + dmStatus.DM_AUTHENTICATION_ERROR : 'authenticationError.AuthenticationError', + dmStatus.DM_DB_ERROR : 'dbError.DbError', + dmStatus.DM_URL_ERROR : 'urlError.UrlError', + dmStatus.DM_INVALID_ARGUMENT: 'invalidArgument.InvalidArgument', + dmStatus.DM_INVALID_REQUEST: 'invalidRequest.InvalidRequest', + dmStatus.DM_INVALID_SESSION: 'invalidSession.InvalidSession', + dmStatus.DM_COMMAND_FAILED: 'commandFailed.CommandFailed', + dmStatus.DM_OBJECT_NOT_FOUND : 'objectNotFound.ObjectNotFound', + dmStatus.DM_OBJECT_ALREADY_EXISTS: 'objectAlreadyExists.ObjectAlreadyExists', + dmStatus.DM_INVALID_OBJECT_STATE: 'invalidObjectState.InvalidObjectState', +} + diff --git a/src/python/dm/common/exceptions/dmHttpError.py b/src/python/dm/common/exceptions/dmHttpError.py new file mode 100755 index 0000000000000000000000000000000000000000..947369c97f96c5bc7d83b8399c99a6769b5107ba --- /dev/null +++ b/src/python/dm/common/exceptions/dmHttpError.py @@ -0,0 +1,15 @@ +#!/usr/bin/env python + +import cherrypy +from cherrypy import HTTPError + +class DmHttpError(HTTPError): + def __init__ (self, httpCode, httpError, dmEx): + HTTPError.__init__(self, httpCode, httpError) + self.dmException = dmEx + + def set_response(self): + HTTPError.set_response(self) + cherrypy.response.headers['Dm-Status-Code'] = self.dmException.getErrorCode() + cherrypy.response.headers['Dm-Status-Message'] = self.dmException.getErrorMessage() + cherrypy.response.headers['Dm-Exception-Type'] = self.dmException.getExceptionType() diff --git a/src/python/dm/common/exceptions/internalError.py b/src/python/dm/common/exceptions/internalError.py new file mode 100755 index 0000000000000000000000000000000000000000..a393f0c7f209a5c0bc63ce641ce75f9ba2c5ce01 --- /dev/null +++ b/src/python/dm/common/exceptions/internalError.py @@ -0,0 +1,16 @@ +#!/usr/bin/env python + +# +# Internal error class. +# + +####################################################################### + +from dm.common.constants import dmStatus +from dm.common.exceptions.dmException import DmException + +####################################################################### + +class InternalError(DmException): + def __init__ (self, error='', **kwargs): + DmException.__init__(self, error, dmStatus.DM_INTERNAL_ERROR, **kwargs) diff --git a/src/python/dm/common/exceptions/invalidArgument.py b/src/python/dm/common/exceptions/invalidArgument.py new file mode 100755 index 0000000000000000000000000000000000000000..8dfb9095e49796bb767dfa56847590c7e98ab7df --- /dev/null +++ b/src/python/dm/common/exceptions/invalidArgument.py @@ -0,0 +1,16 @@ +#!/usr/bin/env python + +# +# Invalid argument error class. +# + +####################################################################### + +from dm.common.constants import dmStatus +from dm.common.exceptions.dmException import DmException + +####################################################################### + +class InvalidArgument(DmException): + def __init__ (self, error='', **kwargs): + DmException.__init__(self, error, dmStatus.DM_INVALID_ARGUMENT, **kwargs) diff --git a/src/python/dm/common/exceptions/invalidObjectState.py b/src/python/dm/common/exceptions/invalidObjectState.py new file mode 100755 index 0000000000000000000000000000000000000000..74c761b0732ba96f7e4f5df27aee27027b48b463 --- /dev/null +++ b/src/python/dm/common/exceptions/invalidObjectState.py @@ -0,0 +1,16 @@ +#!/usr/bin/env python + +# +# Object not found error class. +# + +####################################################################### + +from dm.common.constants import dmStatus +from dm.common.exceptions.dmException import DmException + +####################################################################### + +class ObjectNotFound(DmException): + def __init__ (self, error='', **kwargs): + DmException.__init__(self, error, dmStatus.DM_INVALID_OBJECT_STATE, **kwargs) diff --git a/src/python/dm/common/exceptions/invalidRequest.py b/src/python/dm/common/exceptions/invalidRequest.py new file mode 100755 index 0000000000000000000000000000000000000000..b95dea05ad9a1e83013437caf3694edded23ee70 --- /dev/null +++ b/src/python/dm/common/exceptions/invalidRequest.py @@ -0,0 +1,16 @@ +#!/usr/bin/env python + +# +# Invalid request error class. +# + +####################################################################### + +from dm.common.constants import dmStatus +from dm.common.exceptions.dmException import DmException + +####################################################################### + +class InvalidRequest(DmException): + def __init__ (self, error='', **kwargs): + DmException.__init__(self, error, dmStatus.DM_INVALID_REQUEST, **kwargs) diff --git a/src/python/dm/common/exceptions/invalidSession.py b/src/python/dm/common/exceptions/invalidSession.py new file mode 100755 index 0000000000000000000000000000000000000000..420bbda2229c644f342c51581b17ace9cc913555 --- /dev/null +++ b/src/python/dm/common/exceptions/invalidSession.py @@ -0,0 +1,16 @@ +#!/usr/bin/env python + +# +# Invalid request error class. +# + +####################################################################### + +from dm.common.constants import dmStatus +from dm.common.exceptions.dmException import DmException + +####################################################################### + +class InvalidRequest(DmException): + def __init__ (self, error='', **kwargs): + DmException.__init__(self, error, dmStatus.DM_INVALID_SESSION, **kwargs) diff --git a/src/python/dm/common/exceptions/objectAlreadyExists.py b/src/python/dm/common/exceptions/objectAlreadyExists.py new file mode 100755 index 0000000000000000000000000000000000000000..de8fd390492e191533c71b3cd6f7b5dfa7adc231 --- /dev/null +++ b/src/python/dm/common/exceptions/objectAlreadyExists.py @@ -0,0 +1,16 @@ +#!/usr/bin/env python + +# +# Object already exists error class. +# + +####################################################################### + +from dm.common.constants import dmStatus +from dm.common.exceptions.dmException import DmException + +####################################################################### + +class ObjectAlreadyExists(DmException): + def __init__ (self, error='', **kwargs): + DmException.__init__(self, error, dmStatus.DM_OBJECT_ALREADY_EXISTS, **kwargs) diff --git a/src/python/dm/common/exceptions/objectNotFound.py b/src/python/dm/common/exceptions/objectNotFound.py new file mode 100755 index 0000000000000000000000000000000000000000..63590cbf2107d68bab54a20ed219c8efbb0ff0fa --- /dev/null +++ b/src/python/dm/common/exceptions/objectNotFound.py @@ -0,0 +1,16 @@ +#!/usr/bin/env python + +# +# Object not found error class. +# + +####################################################################### + +from dm.common.constants import dmStatus +from dm.common.exceptions.dmException import DmException + +####################################################################### + +class ObjectNotFound(DmException): + def __init__ (self, error='', **kwargs): + DmException.__init__(self, error, dmStatus.DM_OBJECT_NOT_FOUND, **kwargs) diff --git a/src/python/dm/common/exceptions/urlError.py b/src/python/dm/common/exceptions/urlError.py new file mode 100755 index 0000000000000000000000000000000000000000..84aae0339ea3bf0f2dc989ded2ef085d1634eec0 --- /dev/null +++ b/src/python/dm/common/exceptions/urlError.py @@ -0,0 +1,16 @@ +#!/usr/bin/env python + +# +# Url error class. +# + +####################################################################### + +from dm.common.constants import dmStatus +from dm.common.exceptions.dmException import DmException + +####################################################################### + +class UrlError(DmException): + def __init__ (self, error='', **kwargs): + DmException.__init__(self, error, dmStatus.DM_URL_ERROR, **kwargs) diff --git a/src/python/dm/common/utility/__init__.py b/src/python/dm/common/utility/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/src/python/dm/common/utility/configurationManager.py b/src/python/dm/common/utility/configurationManager.py new file mode 100755 index 0000000000000000000000000000000000000000..9f4afe20f234eed4082a75982c6434d54623677d --- /dev/null +++ b/src/python/dm/common/utility/configurationManager.py @@ -0,0 +1,713 @@ +#!/usr/bin/env python + +# +# Configuration manager singleton. +# + +####################################################################### + +import os +import socket +import pwd +import UserDict +import ConfigParser + +from dm.common.constants import dmServiceConstants +from dm.common.exceptions.configurationError import ConfigurationError + +####################################################################### + +# Defaults. + +DEFAULT_DM_ROOT_DIR = '/opt/dm' +DEFAULT_DM_INSTALL_DIR = '%s' # requires install dir +DEFAULT_DM_CONFIG_FILE = '%s/etc/%s.%s.conf' # requires install dir/db name/service name +DEFAULT_DM_SERVICE_NAME= 'web-service' + +DEFAULT_DM_LOG_FILE = '%s/var/log/%s.%s.log' # requires install dir/db name/service name +DEFAULT_DM_CONSOLE_LOG_LEVEL = 'CRITICAL' +DEFAULT_DM_FILE_LOG_LEVEL = 'INFO' +#DEFAULT_DM_LOG_RECORD_FORMAT = '%(asctime)s,%(msecs)03d [%(levelname)s] %(module)s:%(lineno)d %(user)s@%(host)s %(name)s (%(process)d): %(message)s' +#DEFAULT_DM_LOG_RECORD_FORMAT = '%(asctime)s,%(msecs)03d %(levelname)s %(module)s:%(lineno)d %(process)d: %(message)s' +DEFAULT_DM_LOG_RECORD_FORMAT = '%(asctime)s,%(msecs)03d %(levelname)s %(process)d: %(message)s' +DEFAULT_DM_LOG_DATE_FORMAT = '%Y-%m-%d %H:%M:%S' + +DEFAULT_DM_CHERRYPY_LOG_LEVEL = 'ERROR' +DEFAULT_DM_CHERRYPY_LOG_FILE = '%s/var/log/%s.%s.cherrypy.error' # requires install dir/db name/service name +DEFAULT_DM_CHERRYPY_ACCESS_FILE = '%s/var/log/%s.%s.cherrypy.access' # requires install dir/db name/service name + +DEFAULT_DM_SERVICE_PORT = 22236 # 222DM +DEFAULT_DM_SERVICE_HOST = '127.0.0.1' +DEFAULT_DM_SERVICE_PROTOCOL = dmServiceConstants.DM_SERVICE_PROTOCOL_HTTP +DEFAULT_DM_SERVICE_USERNAME = '' +DEFAULT_DM_SERVICE_PASSWORD = '' + +DEFAULT_DM_DB = 'postgresql' +DEFAULT_DM_DB_HOST = '127.0.0.1' +DEFAULT_DM_DB_PORT = 11136 +DEFAULT_DM_DB_PASSWORD = '' +DEFAULT_DM_DB_NAME = 'dm' +DEFAULT_DM_DB_SCHEMA = DEFAULT_DM_DB_NAME +DEFAULT_DM_DB_USER = DEFAULT_DM_DB_NAME +DEFAULT_DM_DB_PASSWORD_FILE = '%s/etc/%s.db.passwd' # requires install dir/db name + +DEFAULT_DM_CONTEXT_ROOT = '/dm' + +# Session cache file +DEFAULT_DM_SESSION_CACHE_FILE = None + +# Enforce session credentials. +DEFAULT_DM_REQUIRE_SESSION_CREDENTIALS = False + +# SSL variables +DEFAULT_DM_SSL_CA_CERT_FILE = None +DEFAULT_DM_SSL_CERT_FILE = None +DEFAULT_DM_SSL_KEY_FILE = None + +class ConfigurationManager(UserDict.UserDict): + """ + Singleton class used for keeping system configuration data. The class + initializes its data using predefined defaults, or from certain + environment variables. + + Usage: + from dm.common.utility import configurationManager + cm = configurationManager.getInstance() + cm.setConsoleLogLevel('info') + level = cm.getConsoleLogLevel() + cm['myKey'] = 'myValue' + value = cm.get('myKey') + """ + + # Get singleton instance. + @classmethod + def getInstance(cls): + """ Get configuration manager singleton instance. """ + from dm.common.utility.configurationManager import ConfigurationManager + try: + cm = ConfigurationManager() + except ConfigurationManager, ex: + cm = ex + return cm + + # Singleton. + __instance = None + + def __init__(self): + if ConfigurationManager.__instance: + raise ConfigurationManager.__instance + ConfigurationManager.__instance = self + UserDict.UserDict.__init__(self) + self['user'] = pwd.getpwuid(os.getuid())[0] + self['host'] = socket.gethostname() + + self['defaultRootDir'] = DEFAULT_DM_ROOT_DIR + self.__setFromEnvVar('rootDir', 'DM_ROOT_DIR') + self['defaultInstallDir'] = DEFAULT_DM_INSTALL_DIR % self.getRootDir() + self.__setFromEnvVar('installDir', 'DM_INSTALL_DIR') + self['defaultServiceName'] = DEFAULT_DM_SERVICE_NAME + self.__setFromEnvVar('serviceName', 'DM_SERVICE_NAME') + self['defaultDbName'] = DEFAULT_DM_DB_NAME + self.__setFromEnvVar('dbName', 'DM_DB_NAME') + self.__resetDynamicDefaults() + + self['defaultConsoleLogLevel'] = DEFAULT_DM_CONSOLE_LOG_LEVEL + self['defaultFileLogLevel'] = DEFAULT_DM_FILE_LOG_LEVEL + self['defaultLogRecordFormat'] = DEFAULT_DM_LOG_RECORD_FORMAT + self['defaultLogDateFormat'] = DEFAULT_DM_LOG_DATE_FORMAT + + self['defaultCherrypyLogLevel'] = DEFAULT_DM_CHERRYPY_LOG_LEVEL + + self['defaultServicePort'] = DEFAULT_DM_SERVICE_PORT + self['defaultServiceHost'] = DEFAULT_DM_SERVICE_HOST + self['defaultServiceProtocol'] = DEFAULT_DM_SERVICE_PROTOCOL + self['defaultServiceUsername'] = DEFAULT_DM_SERVICE_USERNAME + self['defaultServicePassword'] = DEFAULT_DM_SERVICE_PASSWORD + self['defaultDb'] = DEFAULT_DM_DB + self['defaultDbHost'] = DEFAULT_DM_DB_HOST + self['defaultDbPort'] = DEFAULT_DM_DB_PORT + self['defaultDbPassword'] = DEFAULT_DM_DB_PASSWORD + + self['defaultContextRoot'] = DEFAULT_DM_CONTEXT_ROOT + + self['defaultSessionCacheFile'] = DEFAULT_DM_SESSION_CACHE_FILE + self['defaultRequireSessionCredentials'] = DEFAULT_DM_REQUIRE_SESSION_CREDENTIALS + + self['defaultSslCaCertFile'] = DEFAULT_DM_SSL_CA_CERT_FILE + self['defaultSslCertFile'] = DEFAULT_DM_SSL_CERT_FILE + self['defaultSslKeyFile'] = DEFAULT_DM_SSL_KEY_FILE + # Settings that might come from environment variables. + self.__setFromEnvVar('logFile', 'DM_LOG_FILE') + self.__setFromEnvVar('consoleLogLevel', 'DM_CONSOLE_LOG_LEVEL') + self.__setFromEnvVar('fileLogLevel', 'DM_FILE_LOG_LEVEL') + self.__setFromEnvVar('logRecordFormat', 'DM_LOG_RECORD_FORMAT') + self.__setFromEnvVar('logDateFormat', 'DM_LOG_DATE_FORMAT') + + self.__setFromEnvVar('cherrypyLogLevel', 'DM_CHERRYPY_LOG_LEVEL') + self.__setFromEnvVar('cherrypyLogFile', 'DM_CHERRYPY_LOG_FILE') + self.__setFromEnvVar('cherrypyAccessFile', 'DM_CHERRYPY_ACCESS_FILE') + + self.__setFromEnvVar('serviceProtocol', 'DM_SERVICE_PROTOCOL') + self.__setFromEnvVar('serviceHost', 'DM_SERVICE_HOST') + self.__setFromEnvVar('servicePort', 'DM_SERVICE_PORT') + self.__setFromEnvVar('serviceUsername', 'DM_SERVICE_USERNAME') + self.__setFromEnvVar('servicePassword', 'DM_SERVICE_PASSWORD') + + self.__setFromEnvVar('contextRoot', 'DM_CONTEXT_ROOT') + + self.__setFromEnvVar('sessionCacheFile', 'DM_SESSION_CACHE_FILE') + + self.__setFromEnvVar('sslCaCertFile', 'DM_SSL_CA_CERT_FILE') + self.__setFromEnvVar('sslCertFile', 'DM_SSL_CERT_FILE') + self.__setFromEnvVar('sslKeyFile', 'DM_SSL_KEY_FILE') + + self.__setFromEnvVar('configFile', 'DM_CONFIG_FILE') + self.__setFromEnvVar('dbPasswordFile', 'DM_DB_PASSWORD_FILE') + + # Settings that might come from file. + self.__setFromVarFile('dbPassword', self.getDbPasswordFile()) + + # Variables we do not keep in a dictionary + self.configParser = None + + # Reset defaults that depend on install dir and service name + def __resetDynamicDefaults(self): + self['defaultConfigFile'] = DEFAULT_DM_CONFIG_FILE % (self.getInstallDir(), self.getDbName(), self.getServiceName()) + self['defaultLogFile'] = DEFAULT_DM_LOG_FILE % (self.getInstallDir(), self.getDbName(), self.getServiceName()) + self['defaultCherrypyAccessFile'] = DEFAULT_DM_CHERRYPY_ACCESS_FILE % (self.getInstallDir(), self.getDbName(), self.getServiceName()) + self['defaultCherrypyLogFile'] = DEFAULT_DM_CHERRYPY_LOG_FILE % (self.getInstallDir(), self.getDbName(), self.getServiceName()) + self['defaultDbUser'] = self.getDbName() + self['defaultDbSchema'] = self.getDbName() + self['defaultDbPasswordFile'] = DEFAULT_DM_DB_PASSWORD_FILE % (self.getInstallDir(), self.getDbName()) + + # This function will ignore errors if environment variable is not set. + def __setFromEnvVar(self, key, envVar): + """ + Set value for the specified key from a given environment variable. + This function ignores errors for env. variables that are not set. + """ + try: + self[key] = os.environ[envVar] + except: + pass + + # This function will ignore errors if variable file is not present. + def __setFromVarFile(self, key, varFile): + """ + Set value for the specified key from a given file. The first line + in the file is variable value. + This function ignores errors. + """ + try: + v = open(varFile, 'r').readline() + self[key] = v.lstrip().rstrip() + except Exception, ex: + pass + + def __getKeyValue(self, key, default='__dm_default__'): + """ + Get value for a given key. + Keys will be of the form 'logFile', and the default keys have + the form 'defaultLogFile'. + """ + defaultKey = "default" + key[0].upper() + key[1:] + defaultValue = self.get(defaultKey, None) + if default != '__dm_default__': + defaultValue = default + return self.get(key, defaultValue) + + def setOptionsFromConfigFile(self, configSection, keyList, configFile=None): + _configFile = configFile + if _configFile is None: + _configFile = self.getConfigFile() + + if _configFile is not None and os.path.exists(_configFile): + configParser = ConfigParser.RawConfigParser() + configParser.read(_configFile) + if not configParser.has_section(configSection): + return + for key in keyList: + if configParser.has_option(configSection, key): + self[key] = configParser.get(configSection, key) + + def clearConfigParser(self): + self.configParser = None + + def getConfigParser(self, defaults={}): + if self.configParser is None: + configFile = self.getConfigFile() + if os.path.exists(configFile): + self.configParser = ConfigParser.ConfigParser(defaults) + self.configParser.read(configFile) + self.configParser.defaults = defaults + return self.configParser + + def setConfigDefaults(self, defaults={}): + configParser = self.getConfigParser() + if configParser is not None: + configParser.defaults = defaults + + def getConfigOption(self, configSection, key, defaultValue=None): + configParser = self.getConfigParser() + if self.hasConfigSection(configSection): + try: + return configParser.get(configSection, key) + except ConfigParser.NoOptionError, ex: + # ok, return default value + pass + return defaultValue + + def getConfigSections(self): + configParser = self.getConfigParser() + if configParser is not None: + return configParser.sections() + return [] + + def hasConfigSection(self, name): + configSections = self.getConfigSections() + if name in configSections: + return True + return False + + def getConfigItems(self, configSection): + configParser = self.getConfigParser() + if configParser is not None and configParser.has_section(configSection): + return configParser.items(configSection) + return [] + + @classmethod + def getConfigParserFromConfigFile(cls, configFile): + if not os.path.exists(configFile): + return None + configParser = ConfigParser.RawConfigParser() + configParser.read(configFile) + return configParser + + @classmethod + def getOptionFromConfigParser(cls, configParser, configSection, key, defaultValue=None): + if configParser is not None and configParser.has_section(configSection): + return configParser.get(configSection, key) + else: + return defaultValue + + @classmethod + def getConfigSectionsFromConfigParser(cls, configParser): + if configParser is not None: + return configParser.sections() + return [] + + @classmethod + def getModuleClassConstructorTuple(cls, value): + """ Extract (module,class,constructor) tuple from the given value. """ + itemList = value.split('(') + if not itemList: + return () + itemList2 = itemList[0].split('.') + moduleNameList = itemList2[0:-1] + className = itemList2[-1] + moduleName = className[0].lower() + className[1:] + if len(moduleNameList): + moduleName = '.'.join(moduleNameList) + constructor = '%s(%s' % (className, ''.join(itemList[1:])) + return (moduleName,className,constructor) + + def getHost(self): + return self['host'] + + def getUser(self): + return self['user'] + + def getDefaultRootDir(self): + return self['defaultRootDir'] + + def setRootDir(self, rootDir): + self['rootDir'] = rootDir + + def getRootDir(self, default='__dm_default__'): + return self.__getKeyValue('rootDir', default) + + def getDefaultInstallDir(self): + return self['defaultInstallDir'] + + def setInstallDir(self, installDir): + self['installDir'] = installDir + self.__resetDynamicDefaults() + + def getInstallDir(self, default='__dm_default__'): + return self.__getKeyValue('installDir', default) + + def getDefaultServiceName(self): + return self['defaultServiceName'] + + def setServiceName(self, serviceName): + self['serviceName'] = serviceName + self.__resetDynamicDefaults() + + def getServiceName(self, default='__dm_default__'): + return self.__getKeyValue('serviceName', default) + + def getDefaultDbName(self): + return self['defaultDbName'] + + def setDbName(self, dbName): + self['dbName'] = dbName + self.__resetDynamicDefaults() + + def getDbName(self, default='__dm_default__'): + return self.__getKeyValue('dbName', default) + + def getDefaultLogFile(self): + return self['defaultLogFile'] + + def setLogFile(self, logFile): + self['logFile'] = logFile + + def getLogFile(self, default='__dm_default__'): + return self.__getKeyValue('logFile', default) + + def hasLogFile(self): + return self.has_key('logFile') + + def getDefaultConsoleLogLevel(self): + return self['defaultConsoleLogLevel'] + + def setConsoleLogLevel(self, level): + self['consoleLogLevel'] = level + + def getConsoleLogLevel(self, default='__dm_default__'): + return self.__getKeyValue('consoleLogLevel', default) + + def getConsoleLogLevelFromEnvVar(self): + return os.environ.get('DM_CONSOLE_LOG_LEVEL') + + def hasConsoleLogLevel(self): + return self.has_key('consoleLogLevel') + + def getDefaultFileLogLevel(self): + return self['defaultFileLogLevel'] + + def setFileLogLevel(self, level): + self['fileLogLevel'] = level + + def getFileLogLevel(self, default='__dm_default__'): + return self.__getKeyValue('fileLogLevel', default) + + def hasFileLogLevel(self): + return self.has_key('fileLogLevel') + + def getDefaultLogRecordFormat(self): + return self['defaultLogRecordFormat'] + + def setLogRecordFormat(self, format): + self['logRecordFormat'] = format + + def getLogRecordFormat(self, default='__dm_default__'): + return self.__getKeyValue('logRecordFormat', default) + + def hasLogRecordFormat(self): + return self.has_key('logRecordFormat') + + def getDefaultLogDateFormat(self): + return self['defaultLogDateFormat'] + + def setLogDateFormat(self, format): + self['logDateFormat'] = format + + def getLogDateFormat(self, default='__dm_default__'): + return self.__getKeyValue('logDateFormat', default) + + def hasLogDateFormat(self): + return self.has_key('logDateFormat') + + def getDefaultCherrypyLogLevel(self): + return self['defaultCherrypyLogLevel'] + + def setCherrypyLogLevel(self, level): + self['cherrypyLogLevel'] = level + + def getCherrypyLogLevel(self, default='__dm_default__'): + return self.__getKeyValue('cherrypyLogLevel', default) + + def hasCherrypyLogLevel(self): + return self.has_key('cherrypyLogLevel') + + def getDefaultCherrypyLogCherrypy(self): + return self['defaultCherrypyLogFile'] + + def setCherrypyLogFile(self, cherrypyLogFile): + self['cherrypyLogFile'] = cherrypyLogFile + + def getCherrypyLogFile(self, default='__dm_default__'): + return self.__getKeyValue('cherrypyLogFile', default) + + def hasCherrypyLogFile(self): + return self.has_key('cherrypyLogFile') + + def getDefaultCherrypyAccessFile(self): + return self['defaultCherrypyAccessFile'] + + def setCherrypyAccessFile(self, cherrypyAccessFile): + self['cherrypyAccessFile'] = cherrypyAccessFile + + def getCherrypyAccessFile(self, default='__dm_default__'): + return self.__getKeyValue('cherrypyAccessFile', default) + + def hasCherrypyAccessFile(self): + return self.has_key('cherrypyAccessFile') + + def isDbAvailable(self): + if os.access(self.getDbPasswordFile(), os.R_OK): + return True + return False + + def getDefaultServiceProtocol(self): + return self['defaultServiceProtocol'] + + def setServiceProtocol(self, serviceProtocol): + self['serviceProtocol'] = serviceProtocol + + def getServiceProtocol(self, default='__dm_default__'): + return self.__getKeyValue('serviceProtocol', default) + + def hasServiceProtocol(self): + return self.has_key('serviceProtocol') + + def getDefaultServicePort(self): + return self['defaultServicePort'] + + def setServicePort(self, servicePort): + self['servicePort'] = servicePort + + def getServicePort(self, default='__dm_default__'): + return int(self.__getKeyValue('servicePort', default)) + + def hasServicePort(self): + return self.has_key('servicePort') + + def getDefaultServiceHost(self): + return self['defaultServiceHost'] + + def setServiceHost(self, serviceHost): + self['serviceHost'] = serviceHost + + def getServiceHost(self, default='__dm_default__'): + return self.__getKeyValue('serviceHost', default) + + def hasServiceHost(self): + return self.has_key('serviceHost') + + def getDefaultServiceUsername(self): + return self['defaultServiceUsername'] + + def setServiceUsername(self, serviceUsername): + self['serviceUsername'] = serviceUsername + + def getServiceUsername(self, default='__dm_default__'): + return self.__getKeyValue('serviceUsername', default) + + def hasServiceUsername(self): + return self.has_key('serviceUsername') + + def getDefaultServicePassword(self): + return self['defaultServicePassword'] + + def setServicePassword(self, servicePassword): + self['servicePassword'] = servicePassword + + def getServicePassword(self, default='__dm_default__'): + return self.__getKeyValue('servicePassword', default) + + def hasServicePassword(self): + return self.has_key('servicePassword') + + def getDefaultDb(self): + return self['defaultDb'] + + def setDb(self, db): + self['db'] = db + + def getDb(self, default='__dm_default__'): + return self.__getKeyValue('db', default) + + def hasDb(self): + return self.has_key('db') + + def getDefaultDbHost(self): + return self['defaultDbHost'] + + def setDbHost(self, dbHost): + self['dbHost'] = dbHost + + def getDbHost(self, default='__dm_default__'): + return self.__getKeyValue('dbHost', default) + + def hasDbHost(self): + return self.has_key('dbHost') + + def getDefaultDbPort(self): + return self['defaultDbPort'] + + def setDbPort(self, dbPort): + self['dbPort'] = dbPort + + def getDbPort(self, default='__dm_default__'): + return self.__getKeyValue('dbPort', default) + + def hasDbPort(self): + return self.has_key('dbPort') + + def getDefaultDbPassword(self): + return self['defaultDbPassword'] + + def setDbPassword(self, dbPassword): + self['dbPassword'] = dbPassword + + def getDbPassword(self, default='__dm_default__'): + return self.__getKeyValue('dbPassword', default) + + def hasDbPassword(self): + return self.has_key('dbPassword') + + def getDefaultDbPasswordFile(self): + return self['defaultDbPasswordFile'] + + def getDbPasswordFile(self, default='__dm_default__'): + return self.__getKeyValue('dbPasswordFile', default) + + def setDbPasswordFile(self, f): + self['dbPasswordFile'] = f + + def hasDbPasswordFile(self): + return self.has_key('dbPasswordFile') + + def getDefaultDbUser(self): + return self['defaultDbUser'] + + def getDbUser(self, default='__dm_default__'): + return self.__getKeyValue('dbUser', default) + + def setDbUser(self, dbUser): + self['dbUser'] = dbUser + + def hasDbUser(self): + return self.has_key('dbUser') + + def getDbSchema(self, default='__dm_default__'): + return self.__getKeyValue('dbSchema', default) + + def getDefaultConfigFile(self): + return self['defaultConfigFile'] + + def setConfigFile(self, configFile): + self['configFile'] = configFile + # Must reinitialize config parser at this point + self.configParser = None + + def getConfigFile(self, default='__dm_default__'): + return self.__getKeyValue('configFile', default) + + def hasConfigFile(self): + return self.has_key('configFile') + + def getDefaultContextRoot(self): + return self['defaultContextRoot'] + + def setContextRoot(self, contextRoot): + self['contextRoot'] = contextRoot + + def getContextRoot(self, default='__dm_default__'): + return self.__getKeyValue('contextRoot', default) + + def hasContextRoot(self): + return self.has_key('contextRoot') + + def getDefaultSessionCacheFile(self): + return self['defaultSessionCacheFile'] + + def setSessionCacheFile(self, sessionCacheFile): + self['sessionCacheFile'] = sessionCacheFile + + def getSessionCacheFile(self, default='__dm_default__'): + return self.__getKeyValue('sessionCacheFile', default) + + def hasSessionCacheFile(self): + return self.has_key('sessionCacheFile') + + def getDefaultRequireSessionCredentials(self): + return self['defaultRequireSessionCredentials'] + + def setRequireSessionCredentials(self, requireSessionCredentials): + self['requireSessionCredentials'] = requireSessionCredentials + + def getRequireSessionCredentials(self, default='__dm_default__'): + return self.__getKeyValue('requireSessionCredentials', default) + + def hasRequireSessionCredentials(self): + return self.has_key('requireSessionCredentials') + + def getDefaultSslCaCertFile(self): + return self['defaultSslCaCertFile'] + + def setSslCaCertFile(self, sslCaCertFile): + self['sslCaCertFile'] = sslCaCertFile + + def getSslCaCertFile(self, default='__dm_default__'): + return self.__getKeyValue('sslCaCertFile', default) + + def hasSslCaCertFile(self): + return self.has_key('sslCaCertFile') + + def getDefaultSslCertFile(self): + return self['defaultSslCertFile'] + + def setSslCertFile(self, sslCertFile): + self['sslCertFile'] = sslCertFile + + def getSslCertFile(self, default='__dm_default__'): + return self.__getKeyValue('sslCertFile', default) + + def hasSslCertFile(self): + return self.has_key('sslCertFile') + + def getDefaultSslKeyFile(self): + return self['defaultSslKeyFile'] + + def setSslKeyFile(self, sslKeyFile): + self['sslKeyFile'] = sslKeyFile + + def getSslKeyFile(self, default='__dm_default__'): + return self.__getKeyValue('sslKeyFile', default) + + def hasSslKeyFile(self): + return self.has_key('sslKeyFile') + + def getDefaultUsername(self): + return self['defaultUsername'] + + def setUsername(self, username): + self['username'] = username + + def getUsername(self, default='__dm_default__'): + return self.__getKeyValue('username', default) + + def hasUsername(self): + return self.has_key('username') + + def getDefaultPassword(self): + return self['defaultPassword'] + + def setPassword(self, password): + self['password'] = password + + def getPassword(self, default='__dm_default__'): + return self.__getKeyValue('password', default) + + def hasPassword(self): + return self.has_key('password') + +####################################################################### +# Testing. + +if __name__ == '__main__': + cm = ConfigurationManager.getInstance() + print cm diff --git a/src/python/dm/common/utility/consoleLoggingHandler.py b/src/python/dm/common/utility/consoleLoggingHandler.py new file mode 100755 index 0000000000000000000000000000000000000000..c8353c2e812e4454b6011e2f223d6c36f7477fe9 --- /dev/null +++ b/src/python/dm/common/utility/consoleLoggingHandler.py @@ -0,0 +1,42 @@ +#!/usr/bin/env python + +# +# Console logging handler class +# + +####################################################################### + +import socket +import pwd +import os +from logging import StreamHandler + +####################################################################### + +class ConsoleLoggingHandler(StreamHandler): + """ Class that enables console logging. """ + def __init__(self, *args): + StreamHandler.__init__(self, *args) + self.user = pwd.getpwuid(os.getuid())[0] + self.host = socket.gethostname() + + def emit(self, record): + record.__dict__['user'] = self.user + record.__dict__['host'] = self.host + return StreamHandler.emit(self, record) + +####################################################################### +# Testing. + +if __name__ == '__main__': + import sys + import logging + exec 'sh = ConsoleLoggingHandler(sys.stdout,)' + sh.setLevel(logging.INFO) + rootLogger = logging.getLogger('') + logging.basicConfig(level=logging.DEBUG) + + mainLogger = logging.getLogger('main') + mainLogger.debug("main debug") + mainLogger.info("main info") + diff --git a/src/python/dm/common/utility/cryptUtility.py b/src/python/dm/common/utility/cryptUtility.py new file mode 100755 index 0000000000000000000000000000000000000000..19a722592a550fa6941e1ff6f8ef9a74ee9fe30e --- /dev/null +++ b/src/python/dm/common/utility/cryptUtility.py @@ -0,0 +1,84 @@ +#!/usr/bin/env python + +import random +import string +import crypt +#import md5 +import hashlib +import base64 + +class CryptUtility: + + CRYPT_TYPE = 6 # SHA-512 (man crypt) + SALT_CHARACTERS = string.lowercase + string.uppercase + string.digits + SALT_DELIMITER = '$' + SALT_LENGTH_IN_BYTES = 4 + + PBKDF2_ENCRYPTION = 'sha1' # use SHA-1 for compatibility with java + PBKDF2_KEY_LENGTH_IN_BYTES = 24 + PBKDF2_ITERATIONS = 1003 + + @classmethod + def getRandomWord(cls, length): + return ''.join(random.choice(CryptUtility.SALT_CHARACTERS) for i in range(length)) + + @classmethod + def cryptPassword(cls, password): + """ Return crypted password. """ + #calculator = md5.md5() + #calculator.update(salt) + #md5Salt = calculator.hexdigest() + #return crypt.crypt(cleartext, md5Salt) + + salt = CryptUtility.getRandomWord(CryptUtility.SALT_LENGTH_IN_BYTES) + salt = '%s%s%s%s%s'.format(CryptUtility.SALT_DELIMITER, CryptUtility.CRYPT_TYPE, CryptUtility.SALT_DELIMITER, salt, CryptUtility.SALT_DELIMITER) + return crypt.crypt(password, salt) + + @classmethod + def verifyPassword(cls, password, cryptedPassword): + """ Verify crypted password. """ + return cryptedPassword == crypt.crypt(password, cryptedPassword) + + @classmethod + def cryptPasswordWithPbkdf2(cls, password): + """ Crypt password with pbkdf2 package and encode with b64. """ + salt = CryptUtility.getRandomWord(CryptUtility.SALT_LENGTH_IN_BYTES) + return cls.saltAndCryptPasswordWithPbkdf2(password, salt) + + @classmethod + def saltAndCryptPasswordWithPbkdf2(cls, password, salt): + """ Crypt salted password with pbkdf2 package and encode with b64. """ + cryptedPassword = hashlib.pbkdf2_hmac( + CryptUtility.PBKDF2_ENCRYPTION, + password, salt, + CryptUtility.PBKDF2_ITERATIONS, + CryptUtility.PBKDF2_KEY_LENGTH_IN_BYTES) + encodedPassword = base64.b64encode(cryptedPassword) + return '%s%s%s' % (salt, CryptUtility.SALT_DELIMITER, encodedPassword) + + @classmethod + def verifyPasswordWithPbkdf2(cls, password, cryptedPassword): + """ Verify crypted password. """ + # Get salt + salt = '%s' % cryptedPassword.split(CryptUtility.SALT_DELIMITER)[0] + # Verify crypted password + return cryptedPassword == cls.saltAndCryptPasswordWithPbkdf2(password, salt) + +####################################################################### +# Testing. + +if __name__ == '__main__': + import sys + #password = "dm" + password = sys.argv[1] + print 'Clear text: ', password + #cryptedPassword = CryptUtility.cryptPassword(password) + #print 'Crypted: ', cryptedPassword + #isVerified = CryptUtility.verifyPassword(password, cryptedPassword) + #print 'Verify: ', isVerified + + cryptedPassword = CryptUtility.cryptPasswordWithPbkdf2(password) + print 'Crypted: ', cryptedPassword + isVerified = CryptUtility.verifyPasswordWithPbkdf2(password, cryptedPassword) + print 'Verify: ', isVerified + diff --git a/src/python/dm/common/utility/dmModuleManager.py b/src/python/dm/common/utility/dmModuleManager.py new file mode 100755 index 0000000000000000000000000000000000000000..625611b236fc1e1c1b3440ef6ec542fb458616bb --- /dev/null +++ b/src/python/dm/common/utility/dmModuleManager.py @@ -0,0 +1,82 @@ +#!/usr/bin/env python + +# +# Module manager class. +# + +####################################################################### + +import threading + +####################################################################### + +class DmModuleManager: + """ Singleton class used for managing dm modules. """ + + # Get singleton instance. + @classmethod + def getInstance(cls): + from dm.common.utility.dmModuleManager import DmModuleManager + try: + mgr = DmModuleManager() + except DmModuleManager, ex: + mgr = ex + return mgr + + # Singleton. + __instanceLock = threading.RLock() + __instance = None + + def __init__(self): + DmModuleManager.__instanceLock.acquire() + try: + if DmModuleManager.__instance: + raise DmModuleManager.__instance + DmModuleManager.__instance = self + from dm.common.utility.loggingManager import LoggingManager + self.logger = LoggingManager.getInstance().getLogger(self.__class__.__name__) + self.lock = threading.RLock() + self.moduleList = [] + self.modulesRunning = False + finally: + DmModuleManager.__instanceLock.release() + + def addModule(self, m): + self.lock.acquire() + try: + self.logger.debug('Adding dm module: %s' % m.__class__.__name__) + self.moduleList.append(m) + finally: + self.lock.release() + + def startModules(self): + self.lock.acquire() + try: + if self.modulesRunning: + return + for m in self.moduleList: + self.logger.debug('Starting dm module: %s' % m.__class__.__name__) + m.start() + self.modulesRunning = True + finally: + self.lock.release() + + def stopModules(self): + self.lock.acquire() + try: + if not self.modulesRunning: + return + n = len(self.moduleList) + for i in range(0, n): + m = self.moduleList[n-1-i] + self.logger.debug('Stopping dm module: %s' % m.__class__.__name__) + m.stop() + self.modulesRunning = False + finally: + self.lock.release() + +####################################################################### +# Testing. + +if __name__ == '__main__': + pass diff --git a/src/python/dm/common/utility/dmSubprocess.py b/src/python/dm/common/utility/dmSubprocess.py new file mode 100755 index 0000000000000000000000000000000000000000..5a4d39860ef735b3f805d3dcb809303e9d2ed73f --- /dev/null +++ b/src/python/dm/common/utility/dmSubprocess.py @@ -0,0 +1,137 @@ +#!/usr/bin/env python + +# +# Subprocess class +# + +import os +import subprocess +import platform + +from dm.common.utility.loggingManager import LoggingManager +from dm.common.exceptions.commandFailed import CommandFailed + +####################################################################### + +class DmSubprocess(subprocess.Popen): + + # Get subprocess instance. + @classmethod + def getSubprocess(cls, command): + close_fds = True + if platform.system() != 'Windows': + close_fds = False + p = DmSubprocess(command, close_fds=close_fds) + return p + + # Execute command + @classmethod + def executeCommand(cls, command): + """ Create subprocess and run it, return subprocess object. """ + p = cls.getSubprocess(command) + p.run() + return p + + # Execute command, ignore errors. + @classmethod + def executeCommandAndIgnoreFailure(cls, command): + """ Create subprocess, run it, igore any failures, and return subprocess object. """ + p = cls.getSubprocess(command) + try: + p.run() + except CommandFailed, ex: + p.getLogger().debug('Command failed, stdout: %s, stderr: %s' % (p.getStdOut(), p.getStdErr())) + return p + + @classmethod + def executeCommandAndLogToStdOut(cls, command): + """ Execute command, display output to stdout, maintain log file and return subprocess object. """ + p = cls.getSubprocess(command) + p.__commandLog() + + while True: + outp = p.stdout.readline() + if not outp: + break + print outp, + + retval = p.wait() + + p.logger.debug('Exit status: %s' % retval) + + if retval != 0: + error = '' + while True: + err = p.stderr.readline() + if not err: + break + error += err + raise CommandFailed(error) + return p + + def __init__(self, args, bufsize=0, executable=None, stdin=None, stdout=subprocess.PIPE, stderr=subprocess.PIPE, preexec_fn=None, close_fds=False, shell=True, cwd=None, env=None, universal_newlines=False, startupinfo=None, creationflags=0, useExceptions=True, quietMode=False): + """ Overrides Popen constructor with more appropriate defaults. """ + subprocess.Popen.__init__(self, args, bufsize, executable, stdin, stdout, stderr, preexec_fn, close_fds, shell, cwd, env, universal_newlines, startupinfo, creationflags) + self.logger = LoggingManager.getInstance().getLogger(self.__class__.__name__) + self._stdout = None + self._stderr = None + self._args = args + self.useExceptions = useExceptions + self.quietMode = quietMode + + def __commandLog(self): + # Not very useful to show the name of this file. + # Walk up the stack to find the caller. + import traceback + stack = traceback.extract_stack() + for i in range(2, len(stack)): + if stack[-i][0] != stack[-1][0]: + fileName, lineNumber, functionName, text = stack[-i] + break + else: + fileName = lineNumber = functionName = text = '?' + + self.logger.debug('From [%s:%s] Invoking: [%s]' % (os.path.basename(fileName), lineNumber, self._args)) + + def run(self, input=None): + """ Run subprocess. """ + if not self.quietMode: + self.__commandLog() + (self._stdout, self._stderr) = subprocess.Popen.communicate(self, input) + if not self.quietMode: + self.logger.debug('Exit status: %s' % self.returncode) + if self.returncode != 0 and self.useExceptions: + if not self.quietMode: + self.logger.debug('StdOut: %s' % self._stdout) + self.logger.debug('StdErr: %s' % self._stderr) + error = self._stderr.strip() + if error == '': + error = self._stdout.strip() + raise CommandFailed('%s' % (error)) + return (self._stdout, self._stderr) + + def getLogger(self): + return self.logger + + def getArgs(self): + return self._args + + def getStdOut(self): + return self._stdout + + def getStdErr(self): + return self._stderr + + def getExitStatus(self): + return self.returncode + +####################################################################### +# Testing. + +if __name__ == '__main__': + p = DmSubprocess('ls -l', useExceptions=False) + p.run() + print p.getStdOut() + print p.getStdErr() + print p.getExitStatus() + diff --git a/src/python/dm/common/utility/encoder.py b/src/python/dm/common/utility/encoder.py new file mode 100755 index 0000000000000000000000000000000000000000..61b0c3054574450932dd6c3412c5d1d35964cecd --- /dev/null +++ b/src/python/dm/common/utility/encoder.py @@ -0,0 +1,17 @@ +#!/usr/bin/env python + +import base64 + +class Encoder: + + @classmethod + def encode(cls, data): + # Encode twice, in order to avoid issues like '+' being + # interpreted as space after decoding + encodedData = base64.b64encode(base64.encodestring('%s' % data)) + return encodedData + + @classmethod + def decode(cls, encodedData): + data = base64.decodestring(base64.b64decode('%s' % encodedData)) + return data diff --git a/src/python/dm/common/utility/ldapUtility.py b/src/python/dm/common/utility/ldapUtility.py new file mode 100755 index 0000000000000000000000000000000000000000..b0b07a2b6c73e787444f99594ab4c92ce725e5b1 --- /dev/null +++ b/src/python/dm/common/utility/ldapUtility.py @@ -0,0 +1,43 @@ +#!/usr/bin/env python + +import ldap + +from dm.common.exceptions.authenticationError import AuthenticationError +from dm.common.exceptions.communicationError import CommunicationError + +class LdapUtility: + + def __init__(self, serverUrl, dnFormat): + self.serverUrl = serverUrl + self.dnFormat = dnFormat + + def checkCredentials(self, username, password): + """Verifies credentials for username and password. """ + ldapUsername = self.dnFormat % username + try: + # build client + ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_NEVER) + ldapClient = ldap.initialize(self.serverUrl) + ldapClient.set_option(ldap.OPT_REFERRALS,0) + ldapClient.set_option(ldap.OPT_PROTOCOL_VERSION, ldap.VERSION3) + + #ldapClient.ststart_tls_s() + #ldapClient.set_option(ldap.OPT_X_TLS,ldap.OPT_X_TLS_DEMAND) + #ldapClient.set_option( ldap.OPT_X_TLS_DEMAND, True) + #ldapClient.set_option( ldap.OPT_DEBUG_LEVEL, 255) + + # perform a synchronous bind + ldapClient.simple_bind_s(ldapUsername, password) + #ldapClient.whoami_s() + except ldap.INVALID_CREDENTIALS, ex: + ldapClient.unbind() + raise AuthenticationError('Invalid LDAP credentials for user %s' % username) + except ldap.SERVER_DOWN, ex: + raise CommunicationError('Cannot reach LDAP server %s' % self.serverUrl) + +####################################################################### +# Testing. + +if __name__ == '__main__': + ldapUtility = LdapUtility(serverUrl='ldaps://ldap.anl.gov:636', dnFormat='uid=%s,dc=anl,dc=gov') + ldapUtility.checkCredentials('sveseli', 'sv') diff --git a/src/python/dm/common/utility/loggingManager.py b/src/python/dm/common/utility/loggingManager.py new file mode 100755 index 0000000000000000000000000000000000000000..52c6021679a9b4dd5a1f31a2622075220d92017d --- /dev/null +++ b/src/python/dm/common/utility/loggingManager.py @@ -0,0 +1,305 @@ +#!/usr/bin/env python + +# +# Logging manager singleton. +# + +####################################################################### + +import re +import sys +import os.path +import logging +from dm.common.utility.configurationManager import ConfigurationManager +from dm.common.exceptions.configurationError import ConfigurationError + +####################################################################### + + +class LoggingManager: + """ + The log manager class is initialized via a configuration file + that may have the following sections: + + ConsoleLogging # Used for output on the screen + FileLogging # Used for logging into a file + + Each section in the configuration file should have the following + keys: + handler # Indicates which handler class to use + level # Indicates logging level + format # Indicates format for log messages + dateFormat # Indicates date format used for log messages + + Given below is an example of a valid configuration file: + + [ConsoleLogging] + handler=ConsoleLoggingHandler(sys.stdout,) + level=info + format=[%(levelname)s] %(message)s + dateFormat=%m/%d/%y %H:%M:%S + [FileLogging] + handler=TimedRotatingFileLoggingHandler('/tmp/dm.log') + level=debug + format=%(asctime)s,%(msecs)d [%(levelname)s] %(module)s:%(lineno)d %(user)s@%(host)s %(name)s (%(process)d): %(message)s + dateFormat=%m/%d/%y %H:%M:%S + """ + + # Get singleton instance. + @classmethod + def getInstance(cls): + from dm.common.utility.loggingManager import LoggingManager + try: + lm = LoggingManager() + except LoggingManager, ex: + lm = ex + return lm + + # Singleton. + __instance = None + + def __init__(self): + if LoggingManager.__instance: + raise LoggingManager.__instance + LoggingManager.__instance = self + self.consoleHandler = None + self.fileHandlerList = [] + self.maxIntLevel = logging.CRITICAL + self.minIntLevel = logging.NOTSET + self.levelRegExList = [] + self.logger = logging.getLogger(self.__class__.__name__) + self.initFlag = False + + def setMinLogLevel(self, minLogLevel=logging.INFO): + self.minIntLevel = minLogLevel + + def parseLevelRegEx(self, levelRegExList): + """ Parse expressions of the form <regex>=<log level>. """ + lines = levelRegExList.split('\n') + for line in lines: + try: + (regex, level) = line.rsplit('=', 1) + pattern = re.compile(regex) + tuple = (pattern, logging.getLevelName(level.upper())) + self.levelRegExList.append(tuple) + except Exception, ex: + self.logger.error('Parser error in log configuration file: %s' % line) + self.logger.exception(ex) + + # Get Log Level based on a string representation + def getIntLogLevel(self, levelStr): + level = logging.getLevelName(levelStr) + # Level should be an integer + try: + return int(level) + except ValueError, ex: + raise ConfigurationError('"%s" is not valid log level' % levelStr) + + # Configure log handlers. + def configureHandlers(self): + """ Configure log handlers from the config file. """ + cm = ConfigurationManager.getInstance() + configFile = cm.getConfigFile() + configParser = cm.getConfigParserFromConfigFile(configFile) + configSections = cm.getConfigSectionsFromConfigParser(configParser) + + # Console handler. + defaults = { + 'level' : cm.getConsoleLogLevel(), + 'format' : cm.getLogRecordFormat(), + 'dateFormat' : cm.getLogDateFormat(), + 'handler' : 'ConsoleLoggingHandler(sys.stdout,)' + } + consoleHandler = self.__configureHandler(configParser, 'ConsoleLogging', defaults) + + if consoleHandler != None: + self.consoleHandler = consoleHandler + + # File logging. + # Do not configure if log directory does not exist. + defaults['handler'] = None + defaults['level'] = cm.getFileLogLevel() + if not os.path.exists(configFile): + # No config file, we'll configure default. + defaultLogFile = cm.getLogFile() + defaultLogDir = os.path.dirname(defaultLogFile) + if os.path.exists(defaultLogDir): + handler = 'TimedRotatingFileLoggingHandler("%s")' % defaultLogFile + defaults['handler'] = handler + fileHandler = self.__configureHandler(configParser, 'FileLogging', defaults) + if fileHandler != None: + self.fileHandlerList.append(fileHandler) + + else: + # Parse all file loggers present in the config file + for configSection in configSections: + if configSection.startswith('FileLogging'): + fileHandler = self.__configureHandler(configParser, configSection, defaults) + if fileHandler != None: + self.fileHandlerList.append(fileHandler) + + # Add handlers to the root logger. Use logging class here + # to make sure we can have a logger when we parse the + # logger expressions + rootLogger = logging.getLogger('') + for handler in [self.consoleHandler] + self.fileHandlerList: + rootLogger.addHandler(handler) + + # Get a logger factory based on our current config + self.configureLoggers(configParser, defaultLevel='debug') + + def configureLoggers(self, configParser, defaultLevel='error'): + rootLogLevel = 'error' + levelRegEx = '^.*$=%s' % (defaultLevel) + if configParser is not None and configParser.has_section('LoggerLevels'): + rootLogLevel = ConfigurationManager.getOptionFromConfigParser(configParser, 'LoggerLevels', 'root', rootLogLevel) + levelRegEx = ConfigurationManager.getOptionFromConfigParser(configParser, 'LoggerLevels', 'levelregex', levelRegEx) + + rootLevelInt = logging.getLevelName(rootLogLevel.upper()) + logging.getLogger('').root.setLevel(rootLevelInt) + logging.getLogger('').debug('Set root logger to %s' % rootLevelInt) + + if not levelRegEx: + return + + # Parse expressions of the form <regex>=<log-level>. """ + lines = levelRegEx.split('\n') + for line in lines: + try: + # Use the right split so we can have '='s in the regex + (regex, level) = line.rsplit('=', 1) + pattern = re.compile(regex) + tuple = (pattern, logging.getLevelName(level.upper())) + self.levelRegExList.append(tuple) + except Exception, ex: + # Do not fail + self.logger.error('Parser error in log configuration file: %s' % line) + self.logger.exception(ex) + + # Configure particular handler with given defaults. + def __configureHandler(self, configParser, configSection, defaults): + """ Configure specified handler with a given defaults. """ + handlerOption = defaults['handler'] + try: + if configParser is not None: + handlerOption = configParser.get(configSection, 'handler') + except Exception, ex: + pass + + # If handlerOption is empty, handler cannot be instantiated. + handler = None + if handlerOption != None: + # Handler argument format: MyHandler(arg1, arg2, ...) + # Module will be in lowercase letters, but the class + # should be capitalized. + handlerName = re.sub('\(.*', '', handlerOption) + moduleName = handlerName[0].lower() + handlerName[1:] + try: + exec 'from dm.common.utility import %s' % (moduleName) + exec 'handler = %s.%s' % (moduleName, handlerOption) + except IOError, ex: + errNo, errMsg = ex + import errno + + # If the exception raised is an I/O permissions error, ignore + # it and disable this log handler. This allows non-root users + # to use the (system-wide) default log configuration + if errNo != errno.EACCES: + raise + handler = None + except Exception, ex: + raise ConfigurationError(exception=ex) + + # Only request setting from the config file if it was + # not set via environment variable, or programmatically. + cm = ConfigurationManager.getInstance() + if handler != None: + try: + level = cm.getOptionFromConfigParser(configParser, configSection, 'level', defaults['level']) + intLevel = self.getIntLogLevel(level.upper()) + handler.setLevel(intLevel) + + format = cm.getOptionFromConfigParser(configParser, configSection, 'format', defaults['format']) + dateFormat = cm.getOptionFromConfigParser(configParser, configSection, 'dateFormat', defaults['dateFormat']) + + handler.setFormatter(logging.Formatter(format, dateFormat)) + except Exception, ex: + raise ConfigurationError(exception=ex) + + # Apply filters to handler + filter = None + try: + filter = configParser.get(configSection, 'filter') + if filter: + handler.addFilter(logging.Filter(filter)) + except Exception, ex: + pass + return handler + + def getLogger(self, name='defaultLogger'): + if not self.initFlag: + self.initFlag = True + self.configureHandlers() + logger = logging.getLogger(name) + logger.setLevel(self.getLevel(name)) + return logger + + def getLevel(self, name): + # Match from the known regex list. + level = logging.NOTSET + + # The last regex is most important. + for e in reversed(self.levelRegExList): + (pattern, level) = e + + # If we return not None it is a match + if not None == pattern.match(name): + break + + if level > self.maxIntLevel: + level = self.maxIntLevel + if level < self.minIntLevel: + level = self.minIntLevel + return level + + def setConsoleLogLevel(self, level): + try: + # We need to override the logger levels and the handler + intLevel = self.getIntLogLevel(level.upper()) + self.consoleHandler.setLevel(intLevel) + self.maxIntLevel = intLevel + self.logger.setLevel(intLevel) + except Exception, ex: + raise ConfigurationError(exception=ex) + + def setFileLogLevel(self, level): + try: + # We need to override the logger levels and the handler + intLevel = self.getIntLogLevel(level.upper()) + for handler in self.fileHandlerList: + handler.setLevel(intLevel) + self.maxIntLevel = intLevel + self.logger.setLevel(intLevel) + except Exception, ex: + raise ConfigurationError(exception=ex) + +####################################################################### +# Testing. + +if __name__ == '__main__': + lm = LoggingManager.getInstance() + logger = lm.getLogger('Main') + logger.error('Error In Main') + logger.debug('Debug In Main') + logger.warn('Warn In Main') + logger.info('Info In Main') + logger = lm.getLogger('Main') + logger.info('Info In Main') + logger = lm.getLogger('') + logger.info('Info using root logger') + logger = lm.getLogger('Main.2') + logger.info('Info in Main.2') + lm.setConsoleLogLevel('info') + logger.debug('You should not see this message') + lm.setConsoleLogLevel('debug') + logger.debug('Debug in Main.2') diff --git a/src/python/dm/common/utility/objectCache.py b/src/python/dm/common/utility/objectCache.py new file mode 100755 index 0000000000000000000000000000000000000000..529717b02b810620f5e7b90cad7b813b10da14c4 --- /dev/null +++ b/src/python/dm/common/utility/objectCache.py @@ -0,0 +1,156 @@ +#!/usr/bin/env python + +import threading +import time +from collections import deque + +class ObjectCache: + """ + Cache objects identified by id. Objects are removed from cache + based on the last accessed algorithm. + """ + + # How much larger than object cache should time stamp deq be + # allowed to grow. + DEFAULT_TIME_STAMP_DEQ_SIZE_FACTOR = 2 + # Cache info expiration time. + DEFAULT_OBJECT_LIFETIME = 60 # seconds + + def __init__(self, cacheSize, objectLifetime=DEFAULT_OBJECT_LIFETIME): + self.lock = threading.RLock() + self.objectMap = {} # id/object map + self.timeStampDeq = deque() # timeStamp deq + self.cacheSize = cacheSize + self.objectLifetime = objectLifetime + self.deqSize = ObjectCache.DEFAULT_TIME_STAMP_DEQ_SIZE_FACTOR*cacheSize + + def setCacheSize(self, cacheSize): + self.cacheSize = cacheSize + + def setObjectLifetime(self, objectLifetime): + self.objectLifetime = objectLifetime + + def __purgeOne(self): + # Get rid of one cached item based on the last accessed algorithm. + while True: + deqEntry = self.timeStampDeq.popleft() + oldId = deqEntry[0] + cachedEntry = self.objectMap.get(oldId) + if cachedEntry is not None: + # Timestamp entry is valid. + if cachedEntry == deqEntry: + # Found an old item, get rid of it from the cache. + del self.objectMap[oldId] + break + # Done. + return + + def __purgeTimeStampDeq(self): + # Get rid of stale entries. + timeStampDeq = deque() + while len(self.timeStampDeq): + deqEntry = self.timeStampDeq.popleft() + id = deqEntry[0] + cachedEntry = self.objectMap.get(id) + if cachedEntry is not None: + # Timestamp entry is valid. + if cachedEntry == deqEntry: + # Found current item, keep it. + timeStampDeq.append(deqEntry) + # Done. + self.timeStampDeq = timeStampDeq + return + + def put(self, id, item, objectLifetime=None): + updateTime = time.time() + expirationTime = updateTime + self.objectLifetime + if objectLifetime is not None: + expirationTime = updateTime + objectLifetime + entry = (id, item, updateTime, expirationTime) + self.lock.acquire() + try: + self.objectMap[id] = entry + self.timeStampDeq.append(entry) + if len(self.objectMap) > self.cacheSize: + self.__purgeOne() + if len(self.timeStampDeq) > self.deqSize: + self.__purgeTimeStampDeq() + + finally: + self.lock.release() + + def get(self, id): + return self.objectMap.get(id) + + def remove(self, id): + self.lock.acquire() + try: + item = self.objectMap.get(id) + if item is not None: + del self.objectMap[id] + return item + finally: + self.lock.release() + + def isEmpty(self): + return len(self.objectMap) == 0 + + def size(self): + return len(self.objectMap) + + def __str__(self): + return '%s' % self.timeStampDeq + +####################################################################### +# Testing. +if __name__ == '__main__': + c = ObjectCache(3) + + class Item: + def __init__(self, id): + self.id = id + def getId(self): + return self.id + def __str__(self): + return '%s' % self.id + + class Item2: + def __init__(self, name): + self.name = name + def getName(self): + return self.name + def __str__(self): + return '%s' % self.name + + for i in range(0,5): + item = Item(i) + c.put(i, item) + print 'Added item: ', item + print 'Cache: ', c + time.sleep(1) + + for j in range(0,3): + item = Item(2) + c.put(2, item) + print 'Updated item: ', item + print 'Cache: ', c + time.sleep(1) + + item = c.remove(2) + print 'Deleted item 2: ', item + print 'Cache: ', c + time.sleep(1) + item = c.get(2) + print 'Got item 2: ', item + print 'Cache: ', c + print + time.sleep(1) + + print + c = ObjectCache(3) + c.put('sv', Item2('sv')) + print c + i = c.get('sv') + print i + print 'Done' + diff --git a/src/python/dm/common/utility/osUtility.py b/src/python/dm/common/utility/osUtility.py new file mode 100755 index 0000000000000000000000000000000000000000..9f9ac57e6840479451f0ea0d5264397dee9c3fdd --- /dev/null +++ b/src/python/dm/common/utility/osUtility.py @@ -0,0 +1,116 @@ +#!/usr/bin/env python + +import os + +class OsUtility: + + @classmethod + def createDir(cls, path, mode=None): + """ Create directory if it does not exist already. """ + if not os.path.isdir(path): + os.makedirs(path) + if mode is not None: + os.chmod(path, mode) + + @classmethod + def removeLink(cls, path): + """ Remove link on a given path. """ + if not os.path.islink(path): + return + os.remove(path) + + @classmethod + def removeFile(cls, path): + """ Remove file on a given path. """ + if not os.path.isfile(path): + return + os.remove(path) + + @classmethod + def removeAndIgnoreErrors(cls, path): + """ Remove file on a given path and ignore any errors. """ + try: + os.remove(path) + except Exception, ex: + pass + + @classmethod + def removeDir(cls, path): + """ Remove dir on a given path, even if it is not empty. """ + if not os.path.isdir(path): + return + files=os.listdir(path) + for f in files: + fullpath=os.path.join(path, f) + if os.path.islink(fullpath) or not os.path.isdir(fullpath): + os.remove(fullpath) + else: + removeDir(fullpath) + os.rmdir(path) + + @classmethod + def chownPath(cls, path, uid, gid): + """ Change owner on a given path recursively. """ + if os.path.isfile(path): + os.chown(path, uid, gid) + return + elif os.path.islink(path): + os.lchown(path, uid, gid) + return + elif os.path.isdir(path): + files=os.listdir(path) + for f in files: + fullpath=os.path.join(path, f) + chownPath(fullpath, uid, gid) + os.chown(path, uid, gid) + + @classmethod + def chownPathByUserName(cls, path, userName): + """ Change owner on a given path recursively. """ + import pwd + user = pwd.getpwnam(userName) + chownPath(path, user.pw_uid, user.pw_gid) + + @classmethod + def findFiles(cls, dirPath, fileList=None): + """ List files in a given directory. Return list of absolute paths. + Do not follow symbolic links. + """ + fList = fileList + if not fList: + fList = [] + if os.path.isdir(dirPath): + files = os.listdir(dirPath) + for f in files: + fullPath = os.path.join(dirPath, f) + if os.path.isfile(fullPath): + fList.append(fullPath) + elif os.path.isdir(fullPath): + fList = findFiles(fullPath, fList) + return fList + + @classmethod + def importNameFromFile(cls, name, filePath): + """ Import specified name from file. """ + import sys + import os.path + dirName = os.path.dirname(filePath) + moduleName = os.path.basename(filePath).replace('.py', '') + sys.path = [dirName] + sys.path + cmd = 'from %s import %s as tmpObject' % (moduleName, name) + exec cmd + del sys.path[0] + return tmpObject + + @classmethod + def getUserHomeDir(cls): + """ Get current user home directory. """ + from os.path import expanduser + home = expanduser('~') + return home + +####################################################################### +# Testing. + +if __name__ == '__main__': + pass diff --git a/src/python/dm/common/utility/sslUtility.py b/src/python/dm/common/utility/sslUtility.py new file mode 100755 index 0000000000000000000000000000000000000000..2ad61cbb327609e1b4424a0b5b597417e4671dab --- /dev/null +++ b/src/python/dm/common/utility/sslUtility.py @@ -0,0 +1,24 @@ +#!/usr/bin/env python + +import ssl + +class SslUtility: + + DEFAULT_SSL_CONTEXT = ssl._create_default_https_context + + @classmethod + def useUnverifiedSslContext(cls, func): + + def wrapper(*args, **kwargs): + # Disable SSL checking + ssl._create_default_https_context = ssl._create_unverified_context + + # Perform function call + result = func(*args, **kwargs) + + # Revert back to original SSL settings + ssl._create_default_https_context = SslUtility.DEFAULT_SSL_CONTEXT + return result + + return wrapper + diff --git a/src/python/dm/common/utility/timeUtility.py b/src/python/dm/common/utility/timeUtility.py new file mode 100755 index 0000000000000000000000000000000000000000..5300ff12bcc02761414fb8bf0f96f2008136bc78 --- /dev/null +++ b/src/python/dm/common/utility/timeUtility.py @@ -0,0 +1,26 @@ +#!/usr/bin/env python + +import time +class TimeUtility: + + @classmethod + def getCurrentGMTimeStamp(cls): + """ Formats GMT timestamp. """ + return time.strftime('%Y-%m-%d %H:%M:%S', time.gmtime(time.time())) + + @classmethod + def formatGMTimeStamp(cls, t): + """ Format GMT timestamp. """ + return time.strftime('%Y-%m-%d %H:%M:%S', time.gmtime(t)) + + @classmethod + def getCurrentLocalTimeStamp(cls): + """ Formats local timestamp. """ + return time.strftime('%Y/%m/%d %H:%M:%S %Z', time.localtime(time.time())) + + @classmethod + def formatLocalTimeStamp(cls, t): + """ Formats local timestamp. """ + return time.strftime('%Y/%m/%d %H:%M:%S %Z', time.localtime(t)) + + diff --git a/src/python/dm/common/utility/timedRotatingFileLoggingHandler.py b/src/python/dm/common/utility/timedRotatingFileLoggingHandler.py new file mode 100755 index 0000000000000000000000000000000000000000..04c8ffc80b661840a4a0ddc7700dc04628d7f709 --- /dev/null +++ b/src/python/dm/common/utility/timedRotatingFileLoggingHandler.py @@ -0,0 +1,28 @@ +#!/usr/bin/env python + +####################################################################### + +import socket +import pwd +import os +from logging.handlers import TimedRotatingFileHandler + +####################################################################### + +class TimedRotatingFileLoggingHandler(TimedRotatingFileHandler): + """ Class that enables logging into files. """ + def __init__(self, filename, when='D', interval=1, backupCount=0, encoding=None): + TimedRotatingFileHandler.__init__(self, filename, when, interval, backupCount, encoding) + self.user = pwd.getpwuid(os.getuid())[0] + self.host = socket.gethostname() + + def emit(self, record): + record.__dict__['user'] = self.user + record.__dict__['host'] = self.host + return TimedRotatingFileHandler.emit(self, record) + +####################################################################### +# Testing. + +if __name__ == '__main__': + pass