# @package      hubzero-submit-monitors
# @file         JobExecuter.py
# @copyright    Copyright (c) 2012-2020 The Regents of the University of California.
# @license      http://opensource.org/licenses/MIT MIT
#
# Copyright (c) 2012-2020 The Regents of the University of California.
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#
# HUBzero is a registered trademark of The Regents of the University of California.
#
import os
import pwd
import re
import logging

from hubzero.submit.LogMessage import getLogIDMessage as getLogMessage
from hubzero.submit.JobWSCore  import JobWSCore

SUBMITSTAGEDJOB       = 'submitstagedjob.sh'
SUBMITBATCHJOBCOMMAND = 'submitbatchjob.sh'

class JobExecuter(JobWSCore):
   def __init__(self,
                daemonsDirectory,
                daemonsConfigurationFile,
                infosDirectory,
                infosConfigurationFile,
                previousState,
                nextState):
      JobWSCore.__init__(self,daemonsDirectory,daemonsConfigurationFile,
                              infosDirectory,infosConfigurationFile,
                              'execute',previousState,nextState)

      self.logger = logging.getLogger(__name__)


   def processWSRequest(self,
                        wsJobId):
      uuidPattern = re.compile(".*([0-9,a-f]{8}-[0-9,a-f]{4}-[0-9,a-f]{4}-[0-9,a-f]{4}-[0-9,a-f]{12}(-[0-9,a-f]{3})?).*")

      jobExecuted = False
      stagedActiveJob = self.remoteJobMonitor.getActiveJobStaged(wsJobId)
      commandArgs = []
      siteName = stagedActiveJob['siteName']
      siteInfo = self.sitesInfo.getSiteInfo(siteName)
      if siteInfo['fileMover']:
         fileMoverInfo = self.fileMoversInfo.getFileMoverInfo(siteInfo['fileMover'])
         if   fileMoverInfo['fileMoverType'] == 'tapis2':
            tapisSiteInfo = self.tapis2SitesInfo.getTapisSiteInfo(siteInfo['tapisSite'])
            remoteBinDirectory = tapisSiteInfo['remoteBinDirectory']
            submitStagedJobCommand = os.path.join(remoteBinDirectory,SUBMITSTAGEDJOB)
            commandArgs.append(submitStagedJobCommand)
            commandArgs.append(fileMoverInfo['tapisStorageSystem'])
            commandArgs.append(stagedActiveJob['instanceToken'])
            commandArgs.append(stagedActiveJob['stagingHandle'])
         elif fileMoverInfo['fileMoverType'] == 'tapis3':
            tapisSiteInfo = self.tapis3SitesInfo.getTapisSiteInfo(siteInfo['tapisSite'])
            remoteBinDirectory = tapisSiteInfo['remoteBinDirectory']
            submitStagedJobCommand = os.path.join(remoteBinDirectory,SUBMITSTAGEDJOB)
            commandArgs.append(submitStagedJobCommand)
            commandArgs.append(fileMoverInfo['tapisStorageSystem'])
            commandArgs.append(stagedActiveJob['instanceToken'])
            commandArgs.append(stagedActiveJob['stagingHandle'])
         elif fileMoverInfo['fileMoverType'] == 'ssh':
            if   siteInfo['remoteBatchSystem'] == 'BGSCRIPT':
               jobSubmissionScript = os.path.join('.',"%s.sh" % (stagedActiveJob['stagingHandle']))
            elif siteInfo['remoteBatchSystem'] == 'SLURM':
               jobSubmissionScript = os.path.join('.',"%s.slurm" % (stagedActiveJob['stagingHandle']))
            elif siteInfo['remoteBatchSystem'] == 'PBS':
               jobSubmissionScript = os.path.join('.',"%s.pbs" % (stagedActiveJob['stagingHandle']))

            commandArgs += "ssh -T -x -a".split()
            commandArgs += siteInfo['sshOptions'].split()
            identityPaths = self.remoteIdentityManager.queryUserIdentities(siteInfo['identityManagers'],
                                                                           pwd.getpwuid(os.getuid()).pw_name)
            commandArgs += ['-i',identityPaths['individualSSH']]
            commandArgs += ['-p',str(siteInfo['venuePort'])]
            commandArgs.append("%s@%s" % (siteInfo['remoteUser'],siteInfo['venues'][0]))
            remoteWorkingDirectory = os.path.join(siteInfo['remoteScratchDirectory'],"%s_%s" % \
                                               (stagedActiveJob['stagingHandle'],stagedActiveJob['instanceToken']))
            remoteScratchDirectory = remoteWorkingDirectory
            remoteBinDirectory = siteInfo['remoteBinDirectory']
            submitJobInputCommand = " ".join([os.path.join(remoteBinDirectory,SUBMITBATCHJOBCOMMAND),
                                              remoteWorkingDirectory,
                                              remoteScratchDirectory,
                                              jobSubmissionScript])
            commandArgs.append(submitJobInputCommand)

         del fileMoverInfo

         exitStatus,stdOutput,stdError = self.executeCommand(commandArgs)
         if exitStatus == 0:
            self.logger.log(logging.DEBUG,getLogMessage(stdOutput))
            self.logger.log(logging.DEBUG,getLogMessage(stdError))
         else:
            self.logger.log(logging.ERROR,getLogMessage(stdOutput))
            self.logger.log(logging.ERROR,getLogMessage(stdError))

         remoteJobIdNumber = "-1"
         for record in stdOutput.split('\n'):
            remoteJobId = record.strip()
            remoteJobIdNumber = "-1"
            try:
               uuidMatch = uuidPattern.match(remoteJobId)
               if uuidMatch:
                  remoteJobIdNumber = uuidMatch.group(1)
            except:
               pass

            if remoteJobIdNumber != "-1":
               requestParameters = {'remoteJobIdNumber':remoteJobIdNumber}
               self.remoteJobMonitor.updateActiveJobState(wsJobId,'EXECUTING',requestParameters)
               break
         self.logger.log(logging.INFO,getLogMessage("remoteJobIdNumber = %s" % (remoteJobIdNumber)))

         if exitStatus == 0:
            jobExecuted = True
      del siteInfo

      return(jobExecuted)


