#
# TransferMonitor()
# author  Maurizio Nagni
# version 1.0 - 20 April 2006
#
# This is the main class for the managements of the Yoda monitoring.
#
# Parameters:
# - scriptHost     The directory where the ROOT scritps are stored  (required)
# - pitHost        The monitored directory for "new" files          (required)
# - sourceHost     The directory where to the "new" files are moved (optional)
#

import os, sys, signal, traceback, time, ROOT
from ConfigParser import *
from ngn.utils.SSH import SSH
from ngn.utils.benchmark import Benchmark

class TransferMonitor:
    def __init__(self, logger, configFile):
	self.__logger 		= logger
	self.__configFile 	= configFile
	self.__config 		= ConfigParser()
	self.__config.read(configFile)
        self.__conn	        = None
        self.__transferActive   = False
        self.__benchmarkOn      = False

	try:
            if (self.__config.has_option('TransferMonitor', 'benchmarkFile')):
                self.__bench = Benchmark(self.__config.get('TransferMonitor', 'benchmarkFile'))
                self.__benchmarkOn      = True

            if (self.__config.has_option('TransferMonitor', 'dbConnectionFile') and (os.path.exists(self.__config.get('TransferMonitor', 'dbConnectionFile')))):
                # In case of a database connection install the
                self.__conn = self.__doConnection(self.__config.get('TransferMonitor', 'dbConnectionFile'))
               
            if (self.__config.has_option('TransferMonitor', 'remoteConnectionFile')  and (os.path.exists(self.__config.get('TransferMonitor', 'remoteConnectionFile')))):
                self.__prepareTransfers(self.__config.get('TransferMonitor', 'remoteConnectionFile'))

            if (self.__config.has_option('TransferMonitor', 'pollingDelay') and (os.path.exists(self.__config.get('TransferMonitor', 'pollingDelay')))):
                self.__pollingDelay = self.__config.get('TransferMonitor', 'pollingDelay')
            else:
                self.__pollingDelay = 60    
    
	except NoSectionError, detail:
		print 'Section missing in configuration file: ', detail
		sys.exit(1)
	except NoOptionError, detail:
		print 'Wrong option in configuration file: ', detail
		sys.exit(1)

    def __del__(self):
        if (self.__conn != None):
            self.__conn.Query('UPDATE FILES SET transit_flag = 1 WHERE transit_flag = 2')
            self.__logger.info('UPDATE FILES SET transit_flag = 1 WHERE transit_flag = 2')
            self.__conn.Close()
            if (self.__benchmarkOn):
                self.__bench.close()


    def execute(self):
	# The ConnectionFile exists?
	if (self.__conn != None):
            self.__monitorDB()
        else:
            self.__logger.info('Stopping TransferMonitor. DB connection not active.')
            sys.exit(1)
                
    def __monitorDB(self):
       self.__conn.Query('UPDATE FILES SET transit_flag = 1 WHERE transit_flag = 2')
       self.__logger.info('UPDATE FILES SET transit_flag = 1 WHERE transit_flag = 2')
       while True:
           time.sleep(self.__pollingDelay)
           result = self.__conn.Query("""SELECT path, cln2_name FROM FILES WHERE transit_flag = 1""")
	   row = result.Next()
           
    	   while (not (row == None) and not (row == 0)):
               fileName = row.GetField(0) + row.GetField(1)
               if (self.__benchmarkOn):
                   self.__bench.start(row.GetField(0) + '/', row.GetField(1), 'TransferToMephi')
               if (os.path.exists(fileName)):
                   sourceHost = row.GetField(0)
                   fileName  = row.GetField(1)
                   self.__logger.info( "Starting new transfer to MEPHI for file '%s' .\n", sourceHost + '/' + fileName)
                   if (self.__transferActive):
                       try:
                           if (self.__transferToMephi(sourceHost, fileName)):
                               self.__conn.Query('UPDATE FILES SET transit_flag = 3 WHERE path = \'' +  sourceHost + '\' AND cln2_name = \'' + fileName + '\'')
                               self.__logger.info('UPDATE FILES SET transit_flag = 3 WHERE path = \'' + sourceHost  + '\' AND cln2_name = \'' + fileName + '\'')
                       except Exception, detail:
                           self.__logger.error('Error in transmission: ' + detail)
                   else:
                       self.__logger.info('Data will not be transferred: Wrong remoteConnectionFile parameters.')
               if (self.__benchmarkOn):
                   self.__bench.end()
               row = result.Next()


    def __doConnection(self, dbConf):
        dbConfig = ConfigParser()
        dbConfig.read(dbConf)
        if (dbConfig.has_option('db', 'host') and dbConfig.has_option('db', 'user') and dbConfig.has_option('db', 'password')):
            try:
                return ROOT.TSQLServer.Connect(dbConfig.get('db', 'host'), dbConfig.get('db', 'user'), dbConfig.get('db', 'password'))
            except NoSectionError, detail:
                raise Exception('Section missing in configuration file: ', detail)
            except NoOptionError:
                raise Exception ('Wrong option in configuration file: ', detail)

    def __prepareTransfers(self, transferConf):
        remoteConfig = ConfigParser()
        remoteConfig.read(transferConf)
        if (remoteConfig.has_option('sshWEB', 'host') and remoteConfig.has_option('sshWEB', 'user') and remoteConfig.has_option('sshWEB', 'password') and remoteConfig.has_option('sshWEB', 'port') and remoteConfig.has_option('sshWEB', 'tunnelTo')):
            if (remoteConfig.has_option('sshMEPHI', 'host') and remoteConfig.has_option('sshMEPHI', 'user') and remoteConfig.has_option('sshMEPHI', 'path') and remoteConfig.has_option('sshMEPHI', 'password')):
                self.__mUser    = remoteConfig.get('sshMEPHI', 'user')
                self.__mHost    = remoteConfig.get('sshMEPHI', 'host')
                self.__mPath 	= remoteConfig.get('sshMEPHI', 'path')
                self.__mPwd     = remoteConfig.get('sshMEPHI', 'password')
                
                self.__wUser    = remoteConfig.get('sshWEB', 'user')
                self.__wHost 	= remoteConfig.get('sshWEB', 'host')
                self.__wPwd 	= remoteConfig.get('sshWEB', 'password')
                self.__wPort 	= remoteConfig.get('sshWEB', 'port')
                self.__wTunnelTo= remoteConfig.get('sshWEB', 'tunnelTo')
                self.__operator = SSH()
                #Tunneling to MEPHI through PamelaWEB
                #Check if already exists
                try:
                    if (self.__operator.ssh(' -p ' + self.__wPort + ' ' + self.__mUser + '@' + self.__mHost + ' ping -c 1 pamela.ntsomz.ru ', self.__mPwd, '.*1 packets transmitted, 1 received, 0% packet loss*')):
                        self.__transferActive = True
                        
                except Exception:
                    self.__operator.ssh(' -fgNL ' + self.__wPort + ':' + self.__wTunnelTo + ':22 ' + self.__wUser + '@' + self.__wHost, self.__wPwd)
                    self.__logger.info('ssh ' + ' -fgNL ' + self.__wPort + ':' + self.__wTunnelTo + ':22 ' + self.__wUser + '@' + self.__wHost)
                    #Check if it have been activated correctly
                    if (self.__operator.ssh(' -p ' + self.__wPort + ' ' + self.__mUser + '@' + self.__mHost + ' ping -c 1 pamela.ntsomz.ru ', self.__mPwd, '.*1 packets transmitted, 1 received, 0% packet loss*')):
                        self.__transferActive = True
                            

    def __transferToMephi(self, filePath, fileName):
        self.__conn.Query('UPDATE FILES SET transit_flag = 2 WHERE path = \'' +  filePath + '\' AND cln2_name = \'' + fileName + '\'')
        self.__logger.info('UPDATE FILES SET transit_flag = 2 WHERE path = \'' + filePath + '\' AND cln2_name = \'' + fileName + '\'')
        val = False       
        #Generate the SHA control file
        pos = os.getcwd()
        if (os.path.exists(filePath)):
            os.chdir(filePath)
            if (os.path.exists(fileName)):
                os.system('sha1sum ' + fileName + ' > ' + fileName + '.sha')
                os.chdir(pos)
                #Transfer to MEPHI the data file (bnotice the 'timeout = 21600' seconds)
                self.__logger.info('scp -P ' + self.__wPort + ' ' + filePath + fileName + ' ' + self.__mUser + '@' + self.__mHost + ':' + self.__mPath + '.')
                self.__operator.scp(' -P ' + self.__wPort + ' ' + filePath + fileName + ' ' + self.__mUser + '@' + self.__mHost + ':' + self.__mPath + '.', self.__mPwd, 21600)
                #Transfer to MEPHI the SHA control file
                self.__logger.info('scp -P ' + self.__wPort + ' ' + filePath + fileName + '.sha ' + self.__mUser + '@' + self.__mHost + ':' + self.__mPath + '.')
                self.__operator.scp(' -P ' + self.__wPort + ' ' + filePath + fileName + '.sha ' + self.__mUser + '@' + self.__mHost + ':' + self.__mPath + '.', self.__mPwd, 21600)
                #Check if data file have been corrupted during the transfer
                if not self.__operator.ssh(' -p ' + self.__wPort + ' ' + self.__mUser + '@' + self.__mHost + ' /usr/bin/sha1sum --check ' + fileName + '.sha', self.__mPwd, '.*: OK' ,21600):
                    msg = "The file %s transferred to %s is corrupted." % (filePath + fileName, self.__mUser + '@' + self.__mHost + ':' + path, self.__mPwd, 21600)
                    raise Exception(msg)
                else:
                    self.__logger.info("The file %s transferred to %s correctly." % (filePath + fileName, self.__mUser + '@' + self.__mHost))
                    val = True
	os.chdir(pos)		
        return val
