import subprocess , json , psutil , time , os , win32security , sys #Get input argument
from . import Server
from . import Timer
from . import Processor
from . import BackwardCompatibility # Backward compatibility from v1.1.13
from . import Core
# ATTENTION! HERE IS NO Relative import because it will be imported dynamically
# All function check the flag SessionIsWindowResponsibleBool == True else no cammand is processed
# All functions can return None, Bool or Dict { "IsSuccessful": True }
from . RobotRDPActive import CMDStr # Create CMD Strings
from . RobotRDPActive import Connector # RDP API
from . RobotRDPActive import ConnectorExceptions # Exceptions
#from .Settings import Settings
import importlib
from importlib import util
import threading # Multi-threading for RobotRDPActive
from . RobotRDPActive import RobotRDPActive #Start robot rdp active
from . RobotScreenActive import Monitor #Start robot screen active
import uuid # Generate uuid
import datetime # datetime
#Единый глобальный словарь (З а основу взять из Settings.py)
global gSettingsDict
# Defs to use in orchestrator
def OSCredentialsVerify ( inUserStr , inPasswordStr , inDomainStr = " " ) : ## Verify credentials in windows
try :
hUser = win32security . LogonUser (
inUserStr , inDomainStr , inPasswordStr ,
win32security . LOGON32_LOGON_NETWORK , win32security . LOGON32_PROVIDER_DEFAULT
)
except win32security . error :
return False
else :
return True
def OSCMD ( inCMDStr ) : ## OS send command in shell locally
lCMDCode = " cmd /c " + inCMDStr
subprocess . Popen ( lCMDCode )
lResultCMDRun = 1 # os.system(lCMDCode)
return lResultCMDRun
def OrchestratorRestart ( inGSettings = None ) : ## Orchestrator restart
OrchestratorSessionSave ( inGSettings = inGSettings ) # Dump RDP List in file json
if inGSettings is not None :
lL = inGSettings [ " Logger " ]
if lL : lL . info ( f " Do restart " )
# Restart session
os . execl ( sys . executable , os . path . abspath ( __file__ ) , * sys . argv )
sys . exit ( 0 )
def OrchestratorSessionSave ( inGSettings = None ) : ## Orchestrator session save
# Dump RDP List in file json
lFile = open ( " _SessionLast_RDPList.json " , " w " , encoding = " utf-8 " )
lFile . write ( json . dumps ( inGSettings [ " RobotRDPActive " ] [ " RDPList " ] ) ) # dump json to file
lFile . close ( ) # Close the file
if inGSettings is not None :
lL = inGSettings [ " Logger " ]
if lL : lL . info (
f " Orchestrator has dump the RDP list before the restart. The RDP List is { inGSettings [ ' RobotRDPActive ' ] [ ' RDPList ' ] } " )
return True
# Update user access
def OrchestratorAccessUserUpdate ( inGSettings , inADLoginStr , inADStr = " " , inADIsDefaultBool = True , inURLList = [ ] , inCPAllowKeyList = [ ] ) :
# Backward compatibility
if inURLList == [ ] :
inURLList = [
{
" Method " : " GET " ,
" MatchType " : " Beginwith " ,
" URL " : " / " ,
# "FlagAccessDefRequestGlobalAuthenticate": TestDef
" FlagAccess " : True
} ,
{
" Method " : " POST " ,
" MatchType " : " Beginwith " ,
" URL " : " / " ,
# "FlagAccessDefRequestGlobalAuthenticate": TestDef
" FlagAccess " : True
}
]
# Create Access item
lRuleDomainUserDict = {
" MethodMatchURLBeforeList " : inURLList ,
" ControlPanelKeyAllowedList " : inCPAllowKeyList , #["TestControlPanel", "RobotRDPActive","RobotScreenActive", "ControlPanel_Template"] # If empty - all is allowed
}
# Case add domain + user
inGSettings [ " Server " ] [ " AccessUsers " ] [ " RuleDomainUserDict " ] . update ( { ( inADStr . upper ( ) , inADLoginStr . upper ( ) ) : lRuleDomainUserDict } )
if inADIsDefaultBool :
# Case add default domain + user
inGSettings [ " Server " ] [ " AccessUsers " ] [ " RuleDomainUserDict " ] . update ( { ( " " , inADLoginStr . upper ( ) ) : lRuleDomainUserDict } )
# Add supertoken for the all access (it is need for the robot communication without human)
def OrchestratorAccessSuperTokenAdd ( inGSettings , inSuperTokenStr ) :
lLoginStr = " SUPERTOKEN "
OrchestratorAccessUserUpdate ( inGSettings = inGSettings , inADLoginStr = lLoginStr )
inGSettings [ " Server " ] [ " AccessUsers " ] [ " AuthTokensDict " ] . update (
{ inSuperTokenStr : { " User " : lLoginStr , " Domain " : " " , " TokenDatetime " : datetime . datetime . now ( ) , " FlagDoNotExpire " : True } }
)
## GSettings defs
def GSettingsKeyListValueSet ( inGSettings , inValue , inKeyList = [ ] ) : # Set value in GSettings by the key list
lDict = inGSettings
for lItem2 in inKeyList [ : - 1 ] :
#Check if key - value exists
if lItem2 in lDict :
pass
else :
lDict [ lItem2 ] = { }
lDict = lDict [ lItem2 ]
lDict [ inKeyList [ - 1 ] ] = inValue #Set value
return True
def GSettingsKeyListValueGet ( inGSettings , inKeyList = [ ] ) : # Get the value from the GSettings by the key list
lDict = inGSettings
for lItem2 in inKeyList [ : - 1 ] :
#Check if key - value exists
if lItem2 in lDict :
pass
else :
lDict [ lItem2 ] = { }
lDict = lDict [ lItem2 ]
return lDict . get ( inKeyList [ - 1 ] , None )
def GSettingsKeyListValueAppend ( inGSettings , inValue , inKeyList = [ ] ) : # Append value in GSettings by the key list
lDict = inGSettings
for lItem2 in inKeyList [ : - 1 ] :
#Check if key - value exists
if lItem2 in lDict :
pass
else :
lDict [ lItem2 ] = { }
lDict = lDict [ lItem2 ]
lDict [ inKeyList [ - 1 ] ] . append ( inValue ) #Set value
return True
def GSettingsKeyListValueOperatorPlus ( inGSettings , inValue , inKeyList = [ ] ) : # Operator plus value in GSettings by the key list
lDict = inGSettings
for lItem2 in inKeyList [ : - 1 ] :
#Check if key - value exists
if lItem2 in lDict :
pass
else :
lDict [ lItem2 ] = { }
lDict = lDict [ lItem2 ]
lDict [ inKeyList [ - 1 ] ] + = inValue #Set value
return True
## Process defs
def ProcessIsStarted ( inProcessNameWOExeStr ) : # Check if process is started
'''
Check if there is any running process that contains the given name processName .
'''
#Iterate over the all the running process
for proc in psutil . process_iter ( ) :
try :
# Check if process name contains the given name string.
if inProcessNameWOExeStr . lower ( ) in proc . name ( ) . lower ( ) :
return True
except ( psutil . NoSuchProcess , psutil . AccessDenied , psutil . ZombieProcess ) :
pass
return False ;
def ProcessStart ( inPathStr , inArgList , inStopProcessNameWOExeStr = None ) : # Start process locally [optional: if task name is not started]
lStartProcessBool = True
if inStopProcessNameWOExeStr is not None : #Check if process running
lCheckTaskName = inStopProcessNameWOExeStr
if len ( lCheckTaskName ) > 4 :
if lCheckTaskName [ - 4 : ] . upper ( ) != " .EXE " :
lCheckTaskName = lCheckTaskName + " .exe "
else :
lCheckTaskName = lCheckTaskName + " .exe "
#Check if process exist
if not ProcessIsStarted ( inProcessNameWOExeStr = lCheckTaskName ) : lStartProcessBool = True
if lStartProcessBool == True : # Start if flag is true
lItemArgs = [ inPathStr ]
lItemArgs . extend ( inArgList )
subprocess . Popen ( lItemArgs , shell = True )
def ProcessStop ( inProcessNameWOExeStr , inCloseForceBool , inUserNameStr = " %u sername % " ) : # Stop process
# Support input arg if with .exe
lProcessNameWExeStr = inProcessNameWOExeStr
if len ( lProcessNameWExeStr ) > 4 :
if lProcessNameWExeStr [ - 4 : ] . upper ( ) != " .EXE " :
lProcessNameWExeStr = lProcessNameWExeStr + " .exe "
else :
lProcessNameWExeStr = lProcessNameWExeStr + " .exe "
# Flag Force
lActivityCloseCommand = ' taskkill /im ' + lProcessNameWExeStr
if inCloseForceBool == True :
lActivityCloseCommand + = " /F "
# None - all users, %username% - current user, another str - another user
if inUserNameStr is not None :
lActivityCloseCommand + = f ' /fi " username eq { inUserNameStr } " '
# Kill process
os . system ( lActivityCloseCommand )
#Check activity of the list of processes
def ProcessListGet ( inProcessNameWOExeList = [ ] ) :
''' Get list of running process sorted by Memory Usage and filtered by inProcessNameWOExeList '''
lMapUPPERInput = { } # Mapping for processes WO exe
lResult = { " ProcessWOExeList " : [ ] , " ProcessDetailList " : [ ] }
# Create updated list for quick check
lProcessNameWOExeList = [ ]
for lItem in inProcessNameWOExeList :
if lItem is not None :
lProcessNameWOExeList . append ( f " { lItem . upper ( ) } .EXE " )
lMapUPPERInput [ f " { lItem . upper ( ) } .EXE " ] = lItem
# #
# Iterate over the list
for proc in psutil . process_iter ( ) :
try :
# Fetch process details as dict
pinfo = proc . as_dict ( attrs = [ ' pid ' , ' name ' , ' username ' ] )
pinfo [ ' vms ' ] = proc . memory_info ( ) . vms / ( 1024 * 1024 )
pinfo [ ' NameWOExeUpperStr ' ] = pinfo [ ' name ' ] [ : - 4 ] . upper ( )
# Add if empty inProcessNameWOExeList or if process in inProcessNameWOExeList
if len ( lProcessNameWOExeList ) == 0 or pinfo [ ' name ' ] . upper ( ) in lProcessNameWOExeList :
pinfo [ ' NameWOExeStr ' ] = lMapUPPERInput [ pinfo [ ' name ' ] . upper ( ) ]
lResult [ " ProcessDetailList " ] . append ( pinfo ) # Append dict to list
lResult [ " ProcessWOExeList " ] . append ( pinfo [ ' NameWOExeStr ' ] )
except ( psutil . NoSuchProcess , psutil . AccessDenied , psutil . ZombieProcess ) :
pass
return lResult
# Python def - start module function
def PythonStart ( inModulePathStr , inDefNameStr , inArgList = [ ] , inArgDict = { } , inLogger = None ) : # Python import module and start def
try :
lModule = importlib . import_module ( inModulePathStr ) #Подключить модуль для вызова
lFunction = getattr ( lModule , inDefNameStr ) #Найти функцию
return lFunction ( * inArgList , * * inArgDict )
except Exception as e :
if inLogger : inLogger . exception ( " Loop activity error: module/function not founded " )
# # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # #
# RDPSession
# # # # # # # # # # # # # # # # # # # # # # #
# Create new RDPSession in RobotRDPActive
def RDPSessionConnect ( inGSettings , inRDPSessionKeyStr , inHostStr , inPortStr , inLoginStr , inPasswordStr ) :
# Check thread
if not Core . IsProcessorThread ( inGSettings = inGSettings ) :
if inGSettings [ " Logger " ] : inGSettings [ " Logger " ] . warning ( f " RDP def was called not from processor queue - activity will be append in the processor queue. " )
lResult = {
" Def " : RDPSessionConnect , # def link or def alias (look gSettings["Processor"]["AliasDefDict"])
" ArgList " : [ ] , # Args list
" ArgDict " : { " inRDPSessionKeyStr " : inRDPSessionKeyStr , " inHostStr " : inHostStr , " inPortStr " : inPortStr ,
" inLoginStr " : inLoginStr , " inPasswordStr " : inPasswordStr , } , # Args dictionary
" ArgGSettings " : " inGSettings " , # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
" ArgLogger " : None # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
}
inGSettings [ " ProcessorDict " ] [ " ActivityList " ] . append ( lResult )
else : # In processor - do execution
# ATTENTION - dont connect if RDP session is exist
if inRDPSessionKeyStr not in inGSettings [ " RobotRDPActive " ] [ " RDPList " ] :
lRDPConfigurationItem = { # Init the configuration item
" Host " : inHostStr , # Host address, example "77.77.22.22"
" Port " : inPortStr , # RDP Port, example "3389"
" Login " : inLoginStr , # Login, example "test"
" Password " : inPasswordStr , # Password, example "test"
" Screen " : {
" Width " : 1680 , # Width of the remote desktop in pixels, example 1680
" Height " : 1050 , # Height of the remote desktop in pixels, example 1050
# "640x480" or "1680x1050" or "FullScreen". If Resolution not exists set full screen, example
" FlagUseAllMonitors " : False , # True or False, example False
" DepthBit " : " 32 " # "32" or "24" or "16" or "15", example "32"
} ,
" SharedDriveList " : [ " c " ] , # List of the Root sesion hard drives, example ["c"]
###### Will updated in program ############
" SessionHex " : " 77777sdfsdf77777dsfdfsf77777777 " , # Hex is created when robot runs, example ""
" SessionIsWindowExistBool " : False , # Flag if the RDP window is exist, old name "FlagSessionIsActive". Check every n seconds , example False
" SessionIsWindowResponsibleBool " : False , # Flag if RDP window is responsible (recieve commands). Check every nn seconds. If window is Responsible - window is Exist too , example False
" SessionIsIgnoredBool " : False # Flag to ignore RDP window False - dont ignore, True - ignore, example False
}
inGSettings [ " RobotRDPActive " ] [ " RDPList " ] [ inRDPSessionKeyStr ] = lRDPConfigurationItem # Add item in RDPList
Connector . Session ( lRDPConfigurationItem ) # Create the RDP session
Connector . SystemRDPWarningClickOk ( ) # Click all warning messages
return True
# Disconnect the RDP session
def RDPSessionDisconnect ( inGSettings , inRDPSessionKeyStr , inBreakTriggerProcessWOExeList = [ ] ) :
# Check thread
if not Core . IsProcessorThread ( inGSettings = inGSettings ) :
if inGSettings [ " Logger " ] : inGSettings [ " Logger " ] . warning ( f " RDP def was called not from processor queue - activity will be append in the processor queue. " )
lResult = {
" Def " : RDPSessionDisconnect , # def link or def alias (look gSettings["Processor"]["AliasDefDict"])
" ArgList " : [ ] , # Args list
" ArgDict " : { " inRDPSessionKeyStr " : inRDPSessionKeyStr , " inBreakTriggerProcessWOExeList " : inBreakTriggerProcessWOExeList } , # Args dictionary
" ArgGSettings " : " inGSettings " , # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
" ArgLogger " : None # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
}
inGSettings [ " ProcessorDict " ] [ " ActivityList " ] . append ( lResult )
else : # In processor - do execution
lSessionHex = inGSettings [ " RobotRDPActive " ] [ " RDPList " ] . get ( inRDPSessionKeyStr , { } ) . get ( " SessionHex " , None )
if lSessionHex :
lProcessListResult = { " ProcessWOExeList " : [ ] , " ProcessDetailList " : [ ] }
if len ( inBreakTriggerProcessWOExeList ) > 0 :
lProcessListResult = ProcessListGet ( inProcessNameWOExeList = inBreakTriggerProcessWOExeList ) # Run the task manager monitor
if len ( lProcessListResult [ " ProcessWOExeList " ] ) == 0 : # Start disconnect if no process exist
inGSettings [ " RobotRDPActive " ] [ " RDPList " ] . pop ( inRDPSessionKeyStr , None )
Connector . SessionClose ( inSessionHexStr = lSessionHex )
Connector . SystemRDPWarningClickOk ( ) # Click all warning messages
return True
# RDP Session reconnect
def RDPSessionReconnect ( inGSettings , inRDPSessionKeyStr ) :
# Check thread
if not Core . IsProcessorThread ( inGSettings = inGSettings ) :
if inGSettings [ " Logger " ] : inGSettings [ " Logger " ] . warning ( f " RDP def was called not from processor queue - activity will be append in the processor queue. " )
lResult = {
" Def " : RDPSessionReconnect , # def link or def alias (look gSettings["Processor"]["AliasDefDict"])
" ArgList " : [ ] , # Args list
" ArgDict " : { " inRDPSessionKeyStr " : inRDPSessionKeyStr } , # Args dictionary
" ArgGSettings " : " inGSettings " , # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
" ArgLogger " : None # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
}
inGSettings [ " ProcessorDict " ] [ " ActivityList " ] . append ( lResult )
else :
lRDPConfigurationItem = inGSettings [ " RobotRDPActive " ] [ " RDPList " ] [ inRDPSessionKeyStr ]
RDPSessionDisconnect ( inRDPSessionKeyStr = inRDPSessionKeyStr ) # Disconnect the RDP
# Add item in RDPList
inGSettings [ " RobotRDPActive " ] [ " RDPList " ] [ inRDPSessionKeyStr ] = lRDPConfigurationItem
# Create the RDP session
Connector . Session ( lRDPConfigurationItem )
return True
# Stop track the RDP session. Current def dont kill RDP session - only stop to track it (it can give )
def RDPSessionMonitorStop ( inGSettings , inRDPSessionKeyStr ) :
lResult = True
inGSettings [ " RobotRDPActive " ] [ " RDPList " ] . pop ( inRDPSessionKeyStr , None ) # Remove item from RDPList
return lResult
# Logoff the RDP session
def RDPSessionLogoff ( inGSettings , inRDPSessionKeyStr , inBreakTriggerProcessWOExeList = [ ] ) :
lResult = True
# Check thread
if not Core . IsProcessorThread ( inGSettings = inGSettings ) :
if inGSettings [ " Logger " ] : inGSettings [ " Logger " ] . warning ( f " RDP def was called not from processor queue - activity will be append in the processor queue. " )
lResult = {
" Def " : RDPSessionLogoff , # def link or def alias (look gSettings["Processor"]["AliasDefDict"])
" ArgList " : [ ] , # Args list
" ArgDict " : { " inRDPSessionKeyStr " : inRDPSessionKeyStr , " inBreakTriggerProcessWOExeList " : inBreakTriggerProcessWOExeList } , # Args dictionary
" ArgGSettings " : " inGSettings " , # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
" ArgLogger " : None # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
}
inGSettings [ " ProcessorDict " ] [ " ActivityList " ] . append ( lResult )
else :
lCMDStr = " shutdown -L " # CMD logoff command
# Calculate the session Hex
lSessionHex = inGSettings [ " RobotRDPActive " ] [ " RDPList " ] . get ( inRDPSessionKeyStr , { } ) . get ( " SessionHex " , None )
if lSessionHex :
lProcessListResult = { " ProcessWOExeList " : [ ] , " ProcessDetailList " : [ ] }
if len ( inBreakTriggerProcessWOExeList ) > 0 :
lProcessListResult = ProcessListGet ( inProcessNameWOExeList = inBreakTriggerProcessWOExeList ) # Run the task manager monitor
if len ( lProcessListResult [ " ProcessWOExeList " ] ) == 0 : # Start logoff if no process exist
# Run CMD - dont crosscheck because CMD dont return value to the clipboard when logoff
Connector . SessionCMDRun ( inSessionHex = lSessionHex , inCMDCommandStr = lCMDStr , inModeStr = " RUN " , inLogger = inGSettings [ " Logger " ] , inRDPConfigurationItem = inGSettings [ " RobotRDPActive " ] [ " RDPList " ] [ inRDPSessionKeyStr ] )
inGSettings [ " RobotRDPActive " ] [ " RDPList " ] . pop ( inRDPSessionKeyStr , None ) # Remove item from RDPList
return lResult
# Check RDP Session responsibility TODO NEED DEV + TEST
def RDPSessionResponsibilityCheck ( inGSettings , inRDPSessionKeyStr ) :
# Check thread
if not Core . IsProcessorThread ( inGSettings = inGSettings ) :
if inGSettings [ " Logger " ] : inGSettings [ " Logger " ] . warning ( f " RDP def was called not from processor queue - activity will be append in the processor queue. " )
lResult = {
" Def " : RDPSessionResponsibilityCheck , # def link or def alias (look gSettings["Processor"]["AliasDefDict"])
" ArgList " : [ ] , # Args list
" ArgDict " : { " inRDPSessionKeyStr " : inRDPSessionKeyStr } , # Args dictionary
" ArgGSettings " : " inGSettings " , # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
" ArgLogger " : None # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
}
inGSettings [ " ProcessorDict " ] [ " ActivityList " ] . append ( lResult )
else :
lRDPConfigurationItem = inGSettings [ " RobotRDPActive " ] [ " RDPList " ] [ inRDPSessionKeyStr ] # Get the alias
# set the fullscreen
# ATTENTION!!! Session hex can be updated!!!
Connector . SessionScreenFull ( inSessionHex = lRDPConfigurationItem [ " SessionHex " ] , inLogger = inGSettings [ " Logger " ] , inRDPConfigurationItem = inGSettings [ " RobotRDPActive " ] [ " RDPList " ] [ inRDPSessionKeyStr ] )
time . sleep ( 1 )
# Check RDP responsibility
lDoCheckResponsibilityBool = True
lDoCheckResponsibilityCountMax = 20
lDoCheckResponsibilityCountCurrent = 0
while lDoCheckResponsibilityBool :
# Check if counter is exceed - raise exception
if lDoCheckResponsibilityCountCurrent > = lDoCheckResponsibilityCountMax :
pass
#raise ConnectorExceptions.SessionWindowNotResponsibleError("Error when initialize the RDP session - RDP window is not responding!")
# Check responding
lDoCheckResponsibilityBool = not Connector . SystemRDPIsResponsible ( inSessionHexStr = lRDPConfigurationItem [ " SessionHex " ] )
# Wait if is not responding
if lDoCheckResponsibilityBool :
time . sleep ( 3 )
# increase the couter
lDoCheckResponsibilityCountCurrent + = 1
return True
# Start process if it is not running
def RDPSessionProcessStartIfNotRunning ( inGSettings , inRDPSessionKeyStr , inProcessNameWEXEStr , inFilePathStr , inFlagGetAbsPathBool = True ) :
# Check thread
if not Core . IsProcessorThread ( inGSettings = inGSettings ) :
if inGSettings [ " Logger " ] : inGSettings [ " Logger " ] . warning ( f " RDP def was called not from processor queue - activity will be append in the processor queue. " )
lResult = {
" Def " : RDPSessionProcessStartIfNotRunning , # def link or def alias (look gSettings["Processor"]["AliasDefDict"])
" ArgList " : [ ] , # Args list
" ArgDict " : { " inRDPSessionKeyStr " : inRDPSessionKeyStr , " inProcessNameWEXEStr " : inProcessNameWEXEStr , " inFilePathStr " : inFilePathStr , " inFlagGetAbsPathBool " : inFlagGetAbsPathBool } , # Args dictionary
" ArgGSettings " : " inGSettings " , # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
" ArgLogger " : None # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
}
inGSettings [ " ProcessorDict " ] [ " ActivityList " ] . append ( lResult )
else :
lResult = True
lCMDStr = CMDStr . ProcessStartIfNotRunning ( inProcessNameWEXEStr , inFilePathStr , inFlagGetAbsPath = inFlagGetAbsPathBool )
# Calculate the session Hex
lSessionHex = inGSettings [ " RobotRDPActive " ] [ " RDPList " ] . get ( inRDPSessionKeyStr , { } ) . get ( " SessionHex " , None )
# Run CMD
if lSessionHex :
Connector . SessionCMDRun ( inSessionHex = lSessionHex , inCMDCommandStr = lCMDStr , inModeStr = " CROSSCHECK " , inLogger = inGSettings [ " Logger " ] ,
inRDPConfigurationItem = inGSettings [ " RobotRDPActive " ] [ " RDPList " ] [ inRDPSessionKeyStr ] )
return lResult
def RDPSessionCMDRun ( inGSettings , inRDPSessionKeyStr , inCMDStr , inModeStr = " CROSSCHECK " ) :
# Check thread
if not Core . IsProcessorThread ( inGSettings = inGSettings ) :
if inGSettings [ " Logger " ] : inGSettings [ " Logger " ] . warning ( f " RDP def was called not from processor queue - activity will be append in the processor queue. " )
lResult = {
" Def " : RDPSessionCMDRun , # def link or def alias (look gSettings["Processor"]["AliasDefDict"])
" ArgList " : [ ] , # Args list
" ArgDict " : { " inRDPSessionKeyStr " : inRDPSessionKeyStr , " inCMDStr " : inCMDStr , " inModeStr " : inModeStr } , # Args dictionary
" ArgGSettings " : " inGSettings " , # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
" ArgLogger " : None # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
}
inGSettings [ " ProcessorDict " ] [ " ActivityList " ] . append ( lResult )
else :
lResult = True
# Calculate the session Hex
lSessionHex = inGSettings [ " RobotRDPActive " ] [ " RDPList " ] . get ( inRDPSessionKeyStr , { } ) . get ( " SessionHex " , None )
# Run CMD
if lSessionHex :
Connector . SessionCMDRun ( inSessionHex = lSessionHex , inCMDCommandStr = inCMDStr , inModeStr = inModeStr , inLogger = inGSettings [ " Logger " ] ,
inRDPConfigurationItem = inGSettings [ " RobotRDPActive " ] [ " RDPList " ] [ inRDPSessionKeyStr ] )
return lResult
# Create CMD str to stop process
def RDPSessionProcessStop ( inGSettings , inRDPSessionKeyStr , inProcessNameWEXEStr , inFlagForceCloseBool ) :
# Check thread
if not Core . IsProcessorThread ( inGSettings = inGSettings ) :
if inGSettings [ " Logger " ] : inGSettings [ " Logger " ] . warning ( f " RDP def was called not from processor queue - activity will be append in the processor queue. " )
lResult = {
" Def " : RDPSessionProcessStop , # def link or def alias (look gSettings["Processor"]["AliasDefDict"])
" ArgList " : [ ] , # Args list
" ArgDict " : { " inRDPSessionKeyStr " : inRDPSessionKeyStr , " inProcessNameWEXEStr " : inProcessNameWEXEStr , " inFlagForceCloseBool " : inFlagForceCloseBool } , # Args dictionary
" ArgGSettings " : " inGSettings " , # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
" ArgLogger " : None # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
}
inGSettings [ " ProcessorDict " ] [ " ActivityList " ] . append ( lResult )
else :
lResult = True
lCMDStr = f ' taskkill /im " { inProcessNameWEXEStr } " /fi " username eq %USERNAME% " '
if inFlagForceCloseBool :
lCMDStr + = " /F "
# Calculate the session Hex
lSessionHex = inGSettings [ " RobotRDPActive " ] [ " RDPList " ] . get ( inRDPSessionKeyStr , { } ) . get ( " SessionHex " , None )
# Run CMD
if lSessionHex :
Connector . SessionCMDRun ( inSessionHex = lSessionHex , inCMDCommandStr = lCMDStr , inModeStr = " CROSSCHECK " , inLogger = inGSettings [ " Logger " ] , inRDPConfigurationItem = inGSettings [ " RobotRDPActive " ] [ " RDPList " ] [ inRDPSessionKeyStr ] )
return lResult
# Send file from Host to Session RDP using shared drive in RDP
def RDPSessionFileStoredSend ( inGSettings , inRDPSessionKeyStr , inHostFilePathStr , inRDPFilePathStr ) :
# Check thread
if not Core . IsProcessorThread ( inGSettings = inGSettings ) :
if inGSettings [ " Logger " ] : inGSettings [ " Logger " ] . warning ( f " RDP def was called not from processor queue - activity will be append in the processor queue. " )
lResult = {
" Def " : RDPSessionFileStoredSend , # def link or def alias (look gSettings["Processor"]["AliasDefDict"])
" ArgList " : [ ] , # Args list
" ArgDict " : { " inRDPSessionKeyStr " : inRDPSessionKeyStr , " inHostFilePathStr " : inHostFilePathStr , " inRDPFilePathStr " : inRDPFilePathStr } , # Args dictionary
" ArgGSettings " : " inGSettings " , # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
" ArgLogger " : None # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
}
inGSettings [ " ProcessorDict " ] [ " ActivityList " ] . append ( lResult )
else :
lResult = True
lCMDStr = CMDStr . FileStoredSend ( inHostFilePath = inHostFilePathStr , inRDPFilePath = inRDPFilePathStr )
# Calculate the session Hex
lSessionHex = inGSettings [ " RobotRDPActive " ] [ " RDPList " ] . get ( inRDPSessionKeyStr , { } ) . get ( " SessionHex " , None )
#lSessionHex = inGlobalDict["RobotRDPActive"]["RDPList"][inRDPSessionKeyStr]["SessionHex"]
# Run CMD
if lSessionHex :
Connector . SessionCMDRun ( inSessionHex = lSessionHex , inCMDCommandStr = lCMDStr , inModeStr = " LISTEN " , inClipboardTimeoutSec = 120 , inLogger = inGSettings [ " Logger " ] , inRDPConfigurationItem = inGSettings [ " RobotRDPActive " ] [ " RDPList " ] [ inRDPSessionKeyStr ] )
return lResult
# Recieve file from Session RDP to Host using shared drive in RDP
def RDPSessionFileStoredRecieve ( inGSettings , inRDPSessionKeyStr , inRDPFilePathStr , inHostFilePathStr ) :
# Check thread
if not Core . IsProcessorThread ( inGSettings = inGSettings ) :
if inGSettings [ " Logger " ] : inGSettings [ " Logger " ] . warning ( f " RDP def was called not from processor queue - activity will be append in the processor queue. " )
lResult = {
" Def " : RDPSessionFileStoredRecieve , # def link or def alias (look gSettings["Processor"]["AliasDefDict"])
" ArgList " : [ ] , # Args list
" ArgDict " : { " inRDPSessionKeyStr " : inRDPSessionKeyStr , " inRDPFilePathStr " : inRDPFilePathStr , " inHostFilePathStr " : inHostFilePathStr } , # Args dictionary
" ArgGSettings " : " inGSettings " , # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
" ArgLogger " : None # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
}
inGSettings [ " ProcessorDict " ] [ " ActivityList " ] . append ( lResult )
else :
lResult = True
lCMDStr = CMDStr . FileStoredRecieve ( inRDPFilePath = inRDPFilePathStr , inHostFilePath = inHostFilePathStr )
# Calculate the session Hex
lSessionHex = inGSettings [ " RobotRDPActive " ] [ " RDPList " ] . get ( inRDPSessionKeyStr , { } ) . get ( " SessionHex " , None )
# Run CMD
if lSessionHex :
Connector . SessionCMDRun ( inSessionHex = lSessionHex , inCMDCommandStr = lCMDStr , inModeStr = " LISTEN " , inClipboardTimeoutSec = 120 , inLogger = inGSettings [ " Logger " ] , inRDPConfigurationItem = inGSettings [ " RobotRDPActive " ] [ " RDPList " ] [ inRDPSessionKeyStr ] )
return lResult
# # # # # # # # # # # # # # # # # # # # # # #
# # # # # Start orchestrator
# # # # # # # # # # # # # # # # # # # # # # #
# Interval gsettings auto cleaner
def GSettingsAutocleaner ( inGSettings ) :
while True :
time . sleep ( inGSettings [ " Autocleaner " ] [ " IntervalSecFloat " ] ) # Wait for the next iteration
lL = inGSettings [ " Logger " ]
if lL : lL . info ( f " Autocleaner is running " ) # Info
lNowDatetime = datetime . datetime . now ( ) # Get now time
# Clean old items in Client > Session > TechnicalSessionGUIDCache
lTechnicalSessionGUIDCacheNew = { }
for lItemKeyStr in inGSettings [ " Client " ] [ " Session " ] [ " TechnicalSessionGUIDCache " ] :
lItemValue = inGSettings [ " Client " ] [ " Session " ] [ " TechnicalSessionGUIDCache " ] [ lItemKeyStr ]
if ( lNowDatetime - lItemValue [ " InitDatetime " ] ) . total_seconds ( ) < inGSettings [ " Client " ] [ " Session " ] [ " LifetimeSecFloat " ] : # Add if lifetime is ok
lTechnicalSessionGUIDCacheNew [ lItemKeyStr ] = lItemValue # Lifetime is ok - set
else :
if lL : lL . debug ( f " Client > Session > TechnicalSessionGUIDCache > lItemKeyStr: Lifetime is expired. Remove from gSettings " ) # Info
inGSettings [ " Client " ] [ " Session " ] [ " TechnicalSessionGUIDCache " ] = lTechnicalSessionGUIDCacheNew # Set updated Cache
# # # # # # # # # # # # # # # # # # # # # # # # # #
from . . import __version__ # Get version from the package
# Main def for orchestrator
def Orchestrator ( inGSettings ) :
#mGlobalDict = Settings.Settings(sys.argv[1])
gSettingsDict = inGSettings # Alias for old name in alg
inGSettings [ " VersionStr " ] = __version__
#Logger alias
lL = gSettingsDict [ " Logger " ]
if lL : lL . info ( " Link the gSettings in submodules " ) #Logging
Processor . gSettingsDict = gSettingsDict
Timer . gSettingsDict = gSettingsDict
Timer . Processor . gSettingsDict = gSettingsDict
Server . gSettingsDict = gSettingsDict
Server . ProcessorOld . gSettingsDict = gSettingsDict # Backward compatibility
# Check _SessionLast_RDPList.json in working directory. if exist - load into gsettings
# GSettings
#"RobotRDPActive": {
# "RDPList": {
if os . path . exists ( " _SessionLast_RDPList.json " ) :
lFile = open ( " _SessionLast_RDPList.json " , " r " , encoding = " utf-8 " )
lSessionLastRDPList = json . loads ( lFile . read ( ) )
lFile . close ( ) # Close the file
os . remove ( " _SessionLast_RDPList.json " ) # remove the temp file
gSettingsDict [ " RobotRDPActive " ] [ " RDPList " ] = lSessionLastRDPList # Set the last session dict
if lL : lL . warning ( f " RDP Session List was restored from previous Orchestrator session " )
#Инициализация настроечных параметров
lDaemonLoopSeconds = gSettingsDict [ " Scheduler " ] [ " ActivityTimeCheckLoopSeconds " ]
lDaemonActivityLogDict = { } #Словарь отработанных активностей, ключ - кортеж (<activityType>, <datetime>, <processPath || processName>, <processArgs>)
lDaemonLastDateTime = datetime . datetime . now ( )
gSettingsDict [ " Server " ] [ " WorkingDirectoryPathStr " ] = os . getcwd ( ) # Set working directory in g settings
# Init SettingsUpdate defs from file list (after RDP restore)
lSettingsUpdateFilePathList = gSettingsDict . get ( " OrchestratorStart " , { } ) . get ( " DefSettingsUpdatePathList " , [ ] )
lSubmoduleFunctionName = " SettingsUpdate "
lSettingsPath = " \\ " . join ( os . path . join ( os . getcwd ( ) , __file__ ) . split ( " \\ " ) [ : - 1 ] )
for lModuleFilePathItem in lSettingsUpdateFilePathList : # Import defs with try catch
try : # Try to init - go next if error and log in logger
lModuleName = lModuleFilePathItem [ 0 : - 3 ]
lFileFullPath = os . path . join ( lSettingsPath , lModuleFilePathItem )
lTechSpecification = importlib . util . spec_from_file_location ( lModuleName , lFileFullPath )
lTechModuleFromSpec = importlib . util . module_from_spec ( lTechSpecification )
lTechSpecificationModuleLoader = lTechSpecification . loader . exec_module ( lTechModuleFromSpec )
if lSubmoduleFunctionName in dir ( lTechModuleFromSpec ) :
# Run SettingUpdate function in submodule
getattr ( lTechModuleFromSpec , lSubmoduleFunctionName ) ( gSettingsDict )
except Exception as e :
if lL : lL . exception ( f " Error when init .py file in orchestrator ' { lModuleFilePathItem } ' . Exception is below: " )
# Turn on backward compatibility
BackwardCompatibility . Update ( inGSettings = gSettingsDict )
#Инициализация сервера
lThreadServer = Server . RobotDaemonServer ( " ServerThread " , gSettingsDict )
lThreadServer . start ( )
if lL : lL . info ( " Web server has been started " ) #Logging
# Init the RobotScreenActive in another thread
lRobotScreenActiveThread = threading . Thread ( target = Monitor . CheckScreen )
lRobotScreenActiveThread . daemon = True # Run the thread in daemon mode.
lRobotScreenActiveThread . start ( ) # Start the thread execution.
if lL : lL . info ( " Robot Screen active has been started " ) #Logging
# Init the RobotRDPActive in another thread
lRobotRDPActiveThread = threading . Thread ( target = RobotRDPActive . RobotRDPActive , kwargs = { " inGSettings " : gSettingsDict } )
lRobotRDPActiveThread . daemon = True # Run the thread in daemon mode.
lRobotRDPActiveThread . start ( ) # Start the thread execution.
if lL : lL . info ( " Robot RDP active has been started " ) #Logging
# Init autocleaner in another thread
lAutocleanerThread = threading . Thread ( target = GSettingsAutocleaner , kwargs = { " inGSettings " : gSettingsDict } )
lAutocleanerThread . daemon = True # Run the thread in daemon mode.
lAutocleanerThread . start ( ) # Start the thread execution.
if lL : lL . info ( " Autocleaner thread has been started " ) #Logging
# Orchestrator start activity
if lL : lL . info ( " Orchestrator start activity run " ) #Logging
for lActivityItem in gSettingsDict [ " OrchestratorStart " ] [ " ActivityList " ] :
Processor . ActivityListOrDict ( lActivityItem )
if lL : lL . info ( " Scheduler loop start " ) #Logging
gDaemonActivityLogDictRefreshSecInt = 10 # The second period for clear lDaemonActivityLogDict from old items
gDaemonActivityLogDictLastTime = time . time ( ) # The second perioad for clean lDaemonActivityLogDict from old items
while True :
lCurrentDateTime = datetime . datetime . now ( )
#Циклический обход правил
lFlagSearchActivityType = True
# Periodically clear the lDaemonActivityLogDict
if time . time ( ) - gDaemonActivityLogDictLastTime > = gDaemonActivityLogDictRefreshSecInt :
gDaemonActivityLogDictLastTime = time . time ( ) # Update the time
for lIndex , lItem in enumerate ( lDaemonActivityLogDict ) :
if lItem [ " ActivityEndDateTime " ] and lCurrentDateTime < = lItem [ " ActivityEndDateTime " ] :
pass
# Activity is actual - do not delete now
else :
# remove the activity - not actual
lDaemonActivityLogDict . pop ( lIndex , None )
lIterationLastDateTime = lDaemonLastDateTime # Get current datetime before iterator (need for iterate all activities in loop)
# Iterate throught the activity list
for lIndex , lItem in enumerate ( gSettingsDict [ " Scheduler " ] [ " ActivityTimeList " ] ) :
# Prepare GUID of the activity
lGUID = None
if " GUID " in lItem and lItem [ " GUID " ] :
lGUID = lItem [ " GUID " ]
else :
lGUID = str ( uuid . uuid4 ( ) )
lItem [ " GUID " ] = lGUID
#Проверка дней недели, в рамках которых можно запускать активность
lItemWeekdayList = lItem . get ( " WeekdayList " , [ 0 , 1 , 2 , 3 , 4 , 5 , 6 ] )
if lCurrentDateTime . weekday ( ) in lItemWeekdayList :
if lFlagSearchActivityType :
#######################################################################
#Branch 1 - if has TimeHH:MM
#######################################################################
if " TimeHH:MM " in lItem :
#Вид активности - запуск процесса
#Сформировать временной штамп, относительно которого надо будет проверять время
#часовой пояс пока не учитываем
lActivityDateTime = datetime . datetime . strptime ( lItem [ " TimeHH:MM " ] , " % H: % M " )
lActivityDateTime = lActivityDateTime . replace ( year = lCurrentDateTime . year , month = lCurrentDateTime . month , day = lCurrentDateTime . day )
#Убедиться в том, что время наступило
if (
lActivityDateTime > = lDaemonLastDateTime and
lCurrentDateTime > = lActivityDateTime ) :
# Log info about activity
if lL : lL . info ( f " Scheduler:: Activity is started. Scheduler item: { lItem } " ) #Logging
# Do the activity
Processor . ActivityListOrDict ( lItem [ " Activity " ] )
lIterationLastDateTime = datetime . datetime . now ( ) # Set the new datetime for the new processor activity
#######################################################################
#Branch 2 - if TimeHH:MMStart, TimeHH:MMStop, ActivityIntervalSeconds
#######################################################################
if " TimeHH:MMStart " in lItem and " TimeHH:MMStop " in lItem and " ActivityIntervalSeconds " in lItem :
#Сформировать временной штамп, относительно которого надо будет проверять время
#часовой пояс пока не учитываем
lActivityDateTime = datetime . datetime . strptime ( lItem [ " TimeHH:MMStart " ] , " % H: % M " )
lActivityDateTime = lActivityDateTime . replace ( year = lCurrentDateTime . year , month = lCurrentDateTime . month , day = lCurrentDateTime . day )
lActivityTimeEndDateTime = datetime . datetime . strptime ( lItem [ " TimeHH:MMStop " ] , " % H: % M " )
lActivityTimeEndDateTime = lActivityTimeEndDateTime . replace ( year = lCurrentDateTime . year , month = lCurrentDateTime . month , day = lCurrentDateTime . day )
#Убедиться в том, что время наступило
if (
lCurrentDateTime < lActivityTimeEndDateTime and
lCurrentDateTime > = lActivityDateTime and
( lGUID , lActivityDateTime ) not in lDaemonActivityLogDict ) :
#Запись в массив отработанных активностей
lDaemonActivityLogDict [ ( lGUID , lActivityDateTime ) ] = { " ActivityStartDateTime " : lCurrentDateTime , " ActivityEndDateTime " : lActivityTimeEndDateTime }
#Запуск циклической процедуры
Timer . activityLoopStart ( lItem [ " ActivityIntervalSeconds " ] , lActivityTimeEndDateTime , lItem [ " Activity " ] )
lDaemonLastDateTime = lIterationLastDateTime # Set the new datetime for the new processor activity
#Уснуть до следующего прогона
time . sleep ( lDaemonLoopSeconds )
# Backward compatibility below to 1.2.0
def __deprecated_orchestrator_start__ ( ) :
#Call Settings function from argv[1] file
################################################
lSubmoduleFunctionName = " Settings "
lFileFullPath = sys . argv [ 1 ]
lModuleName = ( lFileFullPath . split ( " \\ " ) [ - 1 ] ) [ 0 : - 3 ]
lTechSpecification = importlib . util . spec_from_file_location ( lModuleName , lFileFullPath )
lTechModuleFromSpec = importlib . util . module_from_spec ( lTechSpecification )
lTechSpecificationModuleLoader = lTechSpecification . loader . exec_module ( lTechModuleFromSpec )
gSettingsDict = None
if lSubmoduleFunctionName in dir ( lTechModuleFromSpec ) :
# Run SettingUpdate function in submodule
gSettingsDict = getattr ( lTechModuleFromSpec , lSubmoduleFunctionName ) ( )
#################################################
Orchestrator ( inGSettings = gSettingsDict ) # Call the orchestrator