From d145cec21d45a546dc6c2388d0cd6b3cc36b9ddc Mon Sep 17 00:00:00 2001 From: Ivan Maslov Date: Fri, 1 Nov 2019 22:33:05 +0300 Subject: [PATCH] #OrchestratorDraftCommit (BigRefactoring, ProcessingConsolidation) Signed-off-by: Ivan Maslov --- Orchestrator/Settings/Settings.py | 94 +++------ Orchestrator/Web/Index.xhtml | 86 +++++--- Orchestrator/orchestratorMain.py | 80 +++----- Orchestrator/orchestratorProcessor.py | 279 +++++++++++++++----------- Orchestrator/orchestratorServer.py | 4 +- Orchestrator/orchestratorTimer.py | 31 +-- RobotLogout.bat | 5 + 7 files changed, 294 insertions(+), 285 deletions(-) create mode 100644 RobotLogout.bat diff --git a/Orchestrator/Settings/Settings.py b/Orchestrator/Settings/Settings.py index 703a3436..e452fc47 100644 --- a/Orchestrator/Settings/Settings.py +++ b/Orchestrator/Settings/Settings.py @@ -48,6 +48,7 @@ def RenderRobotR01(inGlobalConfiguration): #Process not running lResultDict["FooterText"]=f'Дата изменения: {datetime.datetime.now().strftime("%H:%M:%S %d.%m.%Y")}' return lResultDict + def CheckIfProcessRunning(processName): ''' Check if there is any running process that contains the given name processName. @@ -76,78 +77,45 @@ mDict = { ] }, "Scheduler":{ - "ActivityTimeCheckLoopSeconds_":"Количество секунд, между циклами проверки действий", - "ActivityTimeCheckLoopSeconds":5, + "ActivityTimeCheckLoopSeconds":5, #Количество секунд, между циклами проверки действий "ActivityTimeList":[ { - "description":"Запуск Python консоли", - "__processCode":"Код процесса в openRPA daemon. Данные код может использоваться в дальнейшем для того, чтобы завершить именно тот процесс, который пораждался этой программой", - "processCode":"PythonDebug", - "__activityType":"processStart/processStop", - "activityType":"processStart", - "__time":"__Время запуска активности", - "time":"22:57", - "__timeZone":"Часовой пояс, в рамках которого указано время. По-умолчанию часовой пояс МСК (GMT+4). Формат UTC offset in the form ±HHMM[SS[.ffffff]] ", - "timeZone":"+0400", - "__processPath":"Полный путь/наименование процесса. Запуск производится через subprocess. Идентификатор процесса в дальнейшем сохраняется и его можно будет закрыть с помощью параметра processCode", - "____processPath":"C:\\Abs\\Archive\\scopeSrcUL\\OpenRPA\\OpenRPA_32.cmd", - "processPath":"C:\\Abs\\Archive\\scopeSrcUL\\OpenRPA\\Orchestrator\\RobotDaemon\\runProcessOpenRPARobotDaemon_x32.cmd", - "__processArgs":"Аргументы, передаваемые при запуске процесса", - "processArgs":"", - "__weekdayNumList":"Список номеров дней недели, по которым выполнять инициализаци активности. Отсчет ведется от 0 до 6", - "weekdayNumList":[1,2,3] - }, - { - "description":"Запуск Python консоли", - "__activityType":"processStart/processStop", - "activityType":"processStart", - "__time":"__Время запуска активности", - "time":"23:24", - "__timeZone":"Часовой пояс, в рамках которого указано время. По-умолчанию часовой пояс МСК (GMT+4). Формат UTC offset in the form ±HHMM[SS[.ffffff]] ", - "timeZone":"+0400", - "__processPath":"Полный путь/наименование процесса. Запуск производится через subprocess. Идентификатор процесса в дальнейшем сохраняется и его можно будет закрыть с помощью параметра processCode", - "processPath":"notepad", - "processArgs":"" + "TimeHH:MM":"19:25", #Time [HH:MM] to trigger activity + "WeekdayList":[1,2,3], #List of the weekday index when activity is applicable, Default [1,2,3,4,5,6,7] + "Activity":{ + "Type":"ProcessStart", #Activity type + "Path":"Notepad", #Executable file path + "ArgList": [] #List of the arguments + } }, { - "description":"Остановка Python консоли", - "activityType":"processStop", - "time":"19:20", - "timeZone":"4", - "processName":"OpenRPARobotDaemon.exe", - "_flagCloseForce":"Признак, что процесс нужно принудительно закрыть (если флага нет, то на процесс просто посылается команда terminate)", - "flagCloseForce":True, - "_flagCloseOnlyCurrentUser":"Признак, что процесс нужно закрыть только у текущего пользователя", - "flagCloseOnlyCurrentUser":True + "TimeHH:MM":"19:20", #Time [HH:MM] to trigger activity + "WeekdayList":[1,2,3], #List of the weekday index when activity is applicable, Default [1,2,3,4,5,6,7] + "Activity":{ + "Type":"ProcessStop", #Activity type + "Name":"OpenRPARobotDaemon.exe", #Process name + "FlagForce":True, #Force process close + "User": "%username%" #Empty, user or %username% + } }, { - "activityType":"loopActivity", - "loopSeconds":6, - "loopTimeStart":"21:45", - "loopTimeEnd":"21:46", - "pythonPackageName":"CheckActivity", - "pythonFunctionName":"test_activity", - "pythonFunctionArgList":["TestArg1","TestArg2"], - "processPath":"notepad", - "processArgs":"" + "TimeHH:MMStart":"19:20", #Time [HH:MM] to trigger activity + "TimeHH:MMStop":"19:20", + "ActivityIntervalSeconds":5, + "WeekdayList":[1,2,3], #List of the weekday index when activity is applicable, Default [1,2,3,4,5,6,7] + "Activity":{ + "Type": "PythonStart", #Activity type + "ModuleName": "CheckActivity", #Python function module name + "FunctionName": "test_activity", #Python function name + "ArgList": ["TestArg1","TestArg2"] #Input python function args + } } - - ] + ], + "LogList":[] }, "Processor":{ - "LogList_":"Fill list when orchestrator is running", - "TransactionList_":"List of processor activity, whick was executed", - "TransactionList__":[ - { - "DateTimeStart":"2009-09-01T00:00:00.000Z", - "DateTimeEnd":"2009-09-01T00:00:00.000Z", - "ActivityList":[] - } - ], - "TransactionList":[], - "TransactionTrace_":" if Trace for command is selected for False, the tracing will be off for such activity type", - "TransactionTrace_ActivityCMDRun":True, - + "LogType_CMDStart":True, #LogType_: if Trace for command is selected for False, the tracing will be off for such activity type. Default True + "LogList":[] #List of processor activity, which was executed. Fill list when orchestrator is running }, "ControlPanelDict":{ "RefreshSeconds": 5, diff --git a/Orchestrator/Web/Index.xhtml b/Orchestrator/Web/Index.xhtml index c477c009..b9332158 100644 --- a/Orchestrator/Web/Index.xhtml +++ b/Orchestrator/Web/Index.xhtml @@ -72,11 +72,15 @@ ////////////////////////// mGlobal.Controller={}; mGlobal.Controller.CMDRunText=function(inCMDText) { + ///Подготовить конфигурацию + lData = [ + {"Type":"CMDStart", "Command": inCMDText} + ] ///Обнулить таблицу $.ajax({ type: "POST", - url: 'ProcessingRun', - data: '{"actionList":[{"type":"ActivityCMDRun", "code":"'+inCMDText+'"}]}', + url: 'Utils/Processor', + data: JSON.stringify(lData), success: function(lData,l2,l3){}, dataType: "text" @@ -85,10 +89,14 @@ mGlobal.Controller.CMDRun=function() { ///Обнулить таблицу lCMDCode=$(".openrpa-controller-cmd-run-input")[0].value + ///Подготовить конфигурацию + lData = [ + {"Type":"CMDStart", "Command": lCMDCode } + ] $.ajax({ type: "POST", - url: 'ProcessingRun', - data: '{"actionList":[{"type":"ActivityCMDRun", "code":"'+lCMDCode+'"}]}', + url: 'Utils/Processor', + data: JSON.stringify(lData), success: function(lData,l2,l3) { @@ -102,19 +110,23 @@ mGlobal.Controller.CMDRunGUILogout=function() { ///Обнулить таблицу lCMDCode="for /f \"skip=1 tokens=2\" %s in ('query user %USERNAME%') do (tscon \\dest:console)" - lCMDCode = lCMDCode.replace(/\\n/g, "\\n") - .replace(/\\'/g, "\\'") - .replace(/\\"/g, '\\"') - .replace(/\\&/g, "\\&") - .replace(/\\r/g, "\\r") - .replace(/\\t/g, "\\t") - .replace(/\\b/g, "\\b") - .replace(/\\f/g, "\\f") - .replace('"', "\\\""); + //lCMDCode = lCMDCode.replace(/\\n/g, "\\n") + // .replace(/\\'/g, "\\'") + // .replace(/\\"/g, '\\"') + // .replace(/\\&/g, "\\&") + // .replace(/\\r/g, "\\r") + // .replace(/\\t/g, "\\t") + // .replace(/\\b/g, "\\b") + // .replace(/\\f/g, "\\f") + // .replace('"', "\\\""); + ///Подготовить конфигурацию + lData = [ + {"Type":"CMDStart", "Command": lCMDCode } + ] $.ajax({ type: "POST", - url: 'ProcessingRun', - data: '{"actionList":[{"type":"ActivityCMDRun", "code":"'+lCMDCode+'"}]}', + url: 'Utils/Processor', + data: JSON.stringify(lData), success: function(lData,l2,l3) { @@ -129,10 +141,14 @@ ///Перезагрузить Orchestrator mGlobal.Controller.OrchestratorRestart=function() { + ///Подготовить конфигурацию + lData = [ + {"Type":"OrchestratorRestart"} + ] $.ajax({ type: "POST", - url: 'ProcessingRun', - data: '{"actionList":[{"type":"ActivityRestartOrchestrator"}]}', + url: 'Utils/Processor', + data: JSON.stringify(lData), success: function(lData,l2,l3) { @@ -233,11 +249,21 @@ mGlobal.Test=function() { ///Обнулить таблицу - + lData = [ + { + "Type":"GlobalDictKeyListValueSet", + "key_list":["Storage","Robot_R01"], + "value":{ + "RunDateTimeString":"Test1", + "StepCurrentName":"Test2", + "StepCurrentDuration":"Test3" + } + } + ] $.ajax({ type: "POST", - url: 'ProcessingRun', - data: '{"actionList":[{"type":"AdministrationGlobalDictSetKeyListValue","key_list":["Storage","Robot_R01"],"value":{"RunDateTimeString":"Test1","StepCurrentName":"Test2","StepCurrentDuration":"Test3"}}]}', + url: 'Utils/Processor', + data: JSON.stringify(lData), success: function(lData,l2,l3) { @@ -253,10 +279,16 @@ mGlobal.Scheduler = {} mGlobal.Scheduler.ActivityTimeListShow = function() { + lData = [ + { + "Type":"GlobalDictKeyListValueGet", + "KeyList":["Scheduler","ActivityTimeList"] + } + ] $.ajax({ type: "POST", - url: 'ProcessingRun', - data: '{"actionList":[{"type":"PlanLogListGet"}]}', + url: 'Utils/Processor', + data: JSON.stringify(lData), success: function(lData,l2,l3) { @@ -278,12 +310,18 @@ mGlobal.Processor = {} mGlobal.Processor.LogListShow = function() { + lData = [ + { + "Type":"GlobalDictKeyListValueGet", + "KeyList":["Processor","LogList"] + } + ] ///Обнулить таблицу $('.ui.modal.basic .content').html(""); $.ajax({ type: "POST", - url: 'ProcessingRun', - data: '{"actionList":[{"type":"ActivityLogScheduleListGet"}]}', + url: 'Utils/Processor', + data: JSON.stringify(lData), success: function(lData,l2,l3) { diff --git a/Orchestrator/orchestratorMain.py b/Orchestrator/orchestratorMain.py index 1e6cb267..043e82ea 100644 --- a/Orchestrator/orchestratorMain.py +++ b/Orchestrator/orchestratorMain.py @@ -8,6 +8,7 @@ import signal import pdb import orchestratorServer import orchestratorTimer +import orchestratorProcessor import logging from Settings import Settings @@ -24,6 +25,10 @@ lGlobalDict={} lDaemonConfigurationObject=Settings.mDict +#Единый глобальный словарь (За основу взять из Settings.py) +global mGlobalDict +mGlobalDict = Settings.Dict + #Инициализация настроечных параметров lDaemonLoopSeconds=lDaemonConfigurationObject["Scheduler"]["ActivityTimeCheckLoopSeconds"] lDaemonActivityLogDict={} #Словарь отработанных активностей, ключ - кортеж (, , , ) @@ -44,82 +49,53 @@ while True: lCurrentDateTime=datetime.datetime.now() #Циклический обход правил lFlagSearchActivityType=True - for lItem in lDaemonConfigurationObject["Scheduler"]["ActivityTimeList"]: + for lIndex, lItem in enumerate(lDaemonConfigurationObject["Scheduler"]["ActivityTimeList"]): #Проверка дней недели, в рамках которых можно запускать активность - lItemWeekdayList=lItem.get("weekdayNumList",[0,1,2,3,4,5,6]) + lItemWeekdayList=lItem.get("WeekdayList",[0,1,2,3,4,5,6]) if lCurrentDateTime.weekday() in lItemWeekdayList: if lFlagSearchActivityType: - #Определить вид активности - if lItem["activityType"]=="processStart": + #Лог + lItemCopy = copy.deepcopy(lItem) + lItemCopy["DateTimeUTCStringStart"]=datetime.datetime.strftime(datetime.datetime.now(),"%Y-%m-%dT%H:%M:%S.%f") + mGlobalDict["Scheduler"]["LogList"].append(lItemCopy) + ####################################################################### + #Branch 1 - if has TimeHH:MM + ####################################################################### + if "TimeHH:MM" in lItem: #Вид активности - запуск процесса #Сформировать временной штамп, относительно которого надо будет проверять время #часовой пояс пока не учитываем - lActivityDateTime=datetime.datetime.strptime(lItem["time"],"%H:%M") + lActivityDateTime=datetime.datetime.strptime(lItem["TimeHH:MM"],"%H:%M") lActivityDateTime=lActivityDateTime.replace(year=lCurrentDateTime.year,month=lCurrentDateTime.month,day=lCurrentDateTime.day) #Убедиться в том, что время наступило if ( lActivityDateTime>=lDaemonStartDateTime and lCurrentDateTime>=lActivityDateTime and - (lItem["activityType"],lActivityDateTime,lItem["processPath"]) not in lDaemonActivityLogDict): + (lIndex,lActivityDateTime) not in lDaemonActivityLogDict): #Выполнить операцию - print(datetime.datetime.now().isoformat()+":: ProcessStart:"+lItem["processPath"]) - logging.info("ProcessStart:"+lItem["processPath"]) #Запись в массив отработанных активностей - lDaemonActivityLogDict[(lItem["activityType"],lActivityDateTime,lItem["processPath"])]={"ActivityStartDateTime":lCurrentDateTime} - #Лог - lGlobalDict["ActivityLogScheduleList"].append({"activityType":lItem["activityType"], "activityDateTime":str(lActivityDateTime), "processPath":lItem["processPath"], "activityStartDateTime":str(lCurrentDateTime)}) + lDaemonActivityLogDict[(lIndex,lActivityDateTime)]={"ActivityStartDateTime":lCurrentDateTime} #Запустить процесс - lItemArgs=[lItem["processPath"]] - lItemArgs.extend(lItem["processArgs"]) - subprocess.Popen(lItemArgs,shell=True) - #Определить вид активности - if lItem["activityType"]=="processStop": - #Вид активности - остановка процесса - #Сформировать временной штамп, относительно которого надо будет проверять время - #часовой пояс пока не учитываем - lActivityDateTime=datetime.datetime.strptime(lItem["time"],"%H:%M") - lActivityDateTime=lActivityDateTime.replace(year=lCurrentDateTime.year,month=lCurrentDateTime.month,day=lCurrentDateTime.day) - #Убедиться в том, что время наступило - if ( - lActivityDateTime>=lDaemonStartDateTime and - lCurrentDateTime>=lActivityDateTime and - (lItem["activityType"],lActivityDateTime,lItem["processName"]) not in lDaemonActivityLogDict): - #Запись в массив отработанных активностей - lDaemonActivityLogDict[(lItem["activityType"],lActivityDateTime,lItem["processName"])]={"ActivityStartDateTime":lCurrentDateTime} - #Сформировать команду на завершение - lActivityCloseCommand='taskkill /im '+lItem["processName"] - #TODO Сделать безопасную обработку,если параметра нет в конфигурации - if lItem.get('flagCloseForce',False): - lActivityCloseCommand+=" /F" - #Завершить процессы только текущего пользоваиеля - if lItem.get('flagCloseOnlyCurrentUser',False): - lActivityCloseCommand+=' /fi "username eq %username%"' - #Лог - lGlobalDict["ActivityLogScheduleList"].append({"activityType":lItem["activityType"], "activityDateTime":str(lActivityDateTime), "processPath":lItem["processName"], "activityStartDateTime":str(lCurrentDateTime)}) - #Завершить процесс - os.system(lActivityCloseCommand) - print(datetime.datetime.now().isoformat()+":: ProcessStop "+lItem["processName"]) - logging.info("ProcessStop "+lItem["processName"]) - #Вид активности - запуск отдельного потока с циклическим вызовом - if lItem["activityType"]=="loopActivity": + orchestratorProcessor.ActivityListOrDict(lItem["Activity"]) + ####################################################################### + #Banch 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["loopTimeStart"],"%H:%M") + 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["loopTimeEnd"],"%H:%M") + lActivityTimeEndDateTime=datetime.datetime.strptime(lItem["TimeHH:MMStop"],"%H:%M") lActivityTimeEndDateTime=lActivityTimeEndDateTime.replace(year=lCurrentDateTime.year,month=lCurrentDateTime.month,day=lCurrentDateTime.day) #Убедиться в том, что время наступило if ( lCurrentDateTime=lActivityDateTime and - (lItem["activityType"],lActivityDateTime,lItem["processPath"]) not in lDaemonActivityLogDict): - logging.info("ActivityLoop Start ") + (lIndex,lActivityDateTime) not in lDaemonActivityLogDict): #Запись в массив отработанных активностей - lDaemonActivityLogDict[(lItem["activityType"],lActivityDateTime,lItem["processPath"])]={"ActivityStartDateTime":lCurrentDateTime} - #Лог - lGlobalDict["ActivityLogScheduleList"].append({"activityType":lItem["activityType"], "activityDateTime":str(lActivityDateTime), "processPath":lItem["processPath"], "activityStartDateTime":str(lCurrentDateTime)}) + lDaemonActivityLogDict[(lIndex,lActivityDateTime)]={"ActivityStartDateTime":lCurrentDateTime} #Запуск циклической процедуры - orchestratorTimer.activityLoopStart(lItem["loopSeconds"],lItem["processPath"],lItem["processArgs"],lActivityTimeEndDateTime,lItem["pythonPackageName"],lItem["pythonFunctionName"],lItem["pythonFunctionArgList"]) + orchestratorTimer.activityLoopStart(lItem["ActivityIntervalSeconds"],lActivityTimeEndDateTime, lItem["Activity"]) #Уснуть до следующего прогона time.sleep(lDaemonLoopSeconds) diff --git a/Orchestrator/orchestratorProcessor.py b/Orchestrator/orchestratorProcessor.py index f1de9aef..74912ca4 100644 --- a/Orchestrator/orchestratorProcessor.py +++ b/Orchestrator/orchestratorProcessor.py @@ -6,143 +6,184 @@ import os import sys import subprocess import copy -import win32ts -#Глобальная переменная - все глобальные значения программы -global mGlobalDict - -#Включить WTS (WIN32TS) -mWTSServer = lWTSServer = win32ts.WTSOpenServer("localhost") -#{ -# actionList: +import importlib +#Input arg # [ # { -# type: , +# "Type": , # host: , # port: , # bodyObject: # }, # { -# type: +# "Type": "CMDStart", +# "Command": "" # }, # { -# type: , -# code: +# "Type": "OrchestratorRestart" # }, # { -# type: +# "Type": "GlobalDictKeyListValueSet", +# "KeyList": ["key1","key2",...], +# "Value": # }, # { -# type: +# "Type": "GlobalDictKeyListValueGet", +# "KeyList": ["key1","key2",...] # }, # { -# type: -# key_list: ["key1","key2",...] -# value: +# "Type":"ProcessStart", +# "Path":"", +# "ArgList":[] +# # }, # { -# type: -# key_list: ["key1","key2",...] +# "Type":"ProcessStop", +# "Name":"", +# "FlagForce":True, +# "User":"" #Empty, user or %username% # }, +# { +# "Type":"PythonStart", +# "ModuleName":"", +# "FunctionName":"", +# "ArgList":[], +# "ArgDict":{} +# } # ] -# -#} - -def ProcessingRun(inConfigurationDict): - #print(mGlobalDict) - lDateTimeString=datetime.datetime.strftime(datetime.datetime.now(),"%Y.%m.%d %H:%M:%S::%f") - lResult={"dateTime":lDateTimeString, "state":"connected", "actionListResult":[]} - lTransactionItem={} - #Transaction start - lTransactionItem["DateTimeStart"] = datetime.datetime.now().strftime("%Y-%m-%dT%H:%M:%S.%f") - lTransactionItem["ActivityList"]=[] - for lItem in inConfigurationDict["actionList"]: - #Добавить входные значения - lResult["actionListResult"].append({"inArgs":lItem}) - #Обработка запроса на отправку команды на удаленную машину - if lItem["type"]=="RemoteMachineProcessingRun": - lHTTPConnection = http.client.HTTPConnection(lItem["host"], lItem["port"], timeout=5) - try: - lHTTPConnection.request("POST","/ProcessingRun",json.dumps(lItem["bodyObject"])) - except Exception as e: - #Объединение словарей - lResult["actionListResult"][-1] = {**lResult["actionListResult"][-1], **{"state":"disconnected","errorMessage":str(e)}} - #lResult["actionListResult"][-1].join({"state":"disconnected","errorMessage":str(e)}) +################################## +#Output result +# with attributes: +# "DateTimeUTCStringStart" +# "DateTimeUTCStringStop" +# "Result" +def Activity(inActivity): + #Глобальная переменная - глобальный словарь унаследованный от Settings.py + global mGlobalDict + #Fill DateTimeUTCStringStart + inActivity["DateTimeUTCStringStart"] = datetime.datetime.strftime(datetime.datetime.now(),"%Y-%m-%dT%H:%M:%S.%f") + #Alias (compatibility) + lItem = inActivity + ########################################################### + #Обработка запроса на отправку команды на удаленную машину + ########################################################### + if lItem["Type"]=="RemoteMachineProcessingRun": + lHTTPConnection = http.client.HTTPConnection(lItem["host"], lItem["port"], timeout=5) + try: + lHTTPConnection.request("POST","/ProcessingRun",json.dumps(lItem["bodyObject"])) + except Exception as e: + #Объединение словарей + lItem["Result"] = {"State":"disconnected","ExceptionString":str(e)} + else: + lHTTPResponse=lHTTPConnection.getresponse() + lHTTPResponseByteArray=lHTTPResponse.read() + lItem["Result"] = json.loads(lHTTPResponseByteArray.decode('utf8')) + ########################################################### + #Обработка команды CMDStart + ########################################################### + if lItem["Type"]=="CMDStart": + lCMDCode="cmd /c "+lItem["code"] + subprocess.Popen(lCMDCode) + lResultCMDRun=1#os.system(lCMDCode) + lItem["Result"] = str(lResultCMDRun) + ########################################################### + #Обработка команды OrchestratorRestart + ########################################################### + if lItem["Type"]=="OrchestratorRestart": + os.execl(sys.executable,os.path.abspath(__file__),*sys.argv) + lItem["Result"] = True + sys.exit(0) + ########################################################### + #Обработка команды GlobalDictKeyListValueSet + ########################################################### + if lItem["Type"]=="GlobalDictKeyListValueSet": + for lItem2 in lItem["KeyList"][:-1]: + #Check if key - value exists + if lItem2 in mGlobalDict: + pass else: - lHTTPResponse=lHTTPConnection.getresponse() - lHTTPResponseByteArray=lHTTPResponse.read() - lResult["actionListResult"][-1] = {**lResult["actionListResult"][-1], **json.loads(lHTTPResponseByteArray.decode('utf8'))} - #Обработка команды ActivityLogScheduleListGet - if lItem["type"]=="ActivityLogScheduleListGet": - #pdb.set_trace() - lResult["actionListResult"][-1] = {**lResult["actionListResult"][-1], **{"result":mGlobalDict["ActivityLogScheduleList"]}} - #Обработка команды PlanLogListGet - if lItem["type"]=="PlanLogListGet": - #pdb.set_trace() - lResult["actionListResult"][-1] = {**lResult["actionListResult"][-1], **{"result":mGlobalDict["JSONConfigurationDict"]["Scheduler"]["ActivityTimeList"]}} - #Обработка команды ActivityCMDRun - if lItem["type"]=="ActivityCMDRun": - lCMDCode="cmd /c "+lItem["code"] - subprocess.Popen(lCMDCode) - lResultCMDRun=1#os.system(lCMDCode) - lResult["actionListResult"][-1] = {**lResult["actionListResult"][-1], **{"result":str(lResultCMDRun)}} - #Обработка команды ActivityRestartOrchestrator - if lItem["type"]=="ActivityRestartOrchestrator": - os.execl(sys.executable,os.path.abspath(__file__),*sys.argv) - sys.exit(0) - #Обработка команды ActivitySessionCheckSetActive - if lItem["type"]=="ActivitySessionCheckSetActive": - lResult["actionListResult"][-1] = {**lResult["actionListResult"][-1], **{"result":{"IsActivated":False}}} - lPID = os.getpid() - #pdb.set_trace() - lSessionId = win32ts.ProcessIdToSessionId(lPID) - lSessionList = win32ts.WTSEnumerateSessions(lWTSServer) - #При попытке закрыть сервер возникает ошибка - #win32ts.WTSCloseServer(lWTSServer) - #Наложить фильтр - lSessionFiltered = [d for d in lSessionList if d["SessionId"]==lSessionId] - #Выполнить переход в активное состояние , если State != 0 - if lSessionFiltered[0]["State"] != 0: - lCMDCodeTSCON = "tscon " + str(lSeessionId) + " /dest:console" - lCMDCode="cmd /c "+lCMDCodeTSCON - subprocess.Popen(lCMDCode) - lResult["actionListResult"][-1] = {**lResult["actionListResult"][-1], **{"result":{"IsActivated":True}}} - #Выключить соединение - #Обработка команды AdministrationGlobalDictSetKeyListValue - if lItem["type"]=="AdministrationGlobalDictSetKeyListValue": - lGlobalDict=mGlobalDict["JSONConfigurationDict"] - for lItem2 in lItem["key_list"][:-1]: - #Check if key - value exists - if lItem2 in lGlobalDict: - pass - else: - lGlobalDict[lItem2]={} - lGlobalDict=lGlobalDict[lItem2] - #Set value - #pdb.set_trace() - lGlobalDict[lItem["key_list"][-1]]=lItem["value"] - #Обработка команды AdministrationGlobalDictGetKeyListValue - if lItem["type"]=="AdministrationGlobalDictGetKeyListValue": - lGlobalDict=mGlobalDict["JSONConfigurationDict"] - for lItem2 in lItem["key_list"][:-1]: - #Check if key - value exists - if lItem2 in lGlobalDict: - pass - else: - lGlobalDict[lItem2]={} - lGlobalDict=lGlobalDict[lItem2] - #Set value - #pdb.set_trace() - lResult["actionListResult"][-1]["key_list"]=lItem["key_list"] - lResult["actionListResult"][-1]["value"]=lGlobalDict.get(lItem["key_list"][-1],None) - ################## - #Trace activity - ################## - if mGlobalDict["Processor"].get(f"TransactionTrace_{lItem['type']}",True): - #Add activity in TransactionList if it is applicable - lTransactionItem["ActivityList"].append(copy.deepcopy(lItem)) - #Transaction end - lTransactionItem["DateTimeEnd"] = datetime.datetime.now().strftime("%Y-%m-%dT%H:%M:%S.%f") - #Перенос результатов в TransactionList - mGlobalDict["Processor"]["TransactionList"].append(lTransactionItem) + mGlobalDict[lItem2]={} + mGlobalDict=mGlobalDict[lItem2] + #Set value + mGlobalDict[lItem["KeyList"][-1]]=lItem["value"] + ########################################################### + #Обработка команды GlobalDictKeyListValueGet + ########################################################### + if lItem["type"]=="GlobalDictKeyListValueGet": + for lItem2 in lItem["KeyList"][:-1]: + #Check if key - value exists + if lItem2 in mGlobalDict: + pass + else: + mGlobalDict[lItem2]={} + mGlobalDict=mGlobalDict[lItem2] + #Return value + lItem["Result"]==mGlobalDict.get(lItem["KeyList"][-1],None) + #Определить вид активности + lActivityDateTime=inActivity["DateTimeUTCStringStart"] + ##################################### + #ProcessStart + ##################################### + if lItem["Type"]=="ProcessStart": + #Вид активности - запуск процесса + #Запись в массив отработанных активностей + lDaemonActivityLogDict[(lItem["activityType"],lActivityDateTime,lItem["processPath"])]={"ActivityStartDateTime":lCurrentDateTime} + #Лог + mGlobalDict["Processor"]["LogList"].append({"activityType":lItem["activityType"], "activityDateTime":str(lActivityDateTime), "processPath":lItem["processPath"], "activityStartDateTime":str(lCurrentDateTime)}) + #Запустить процесс + lItemArgs=[lItem["processPath"]] + lItemArgs.extend(lItem["processArgs"]) + subprocess.Popen(lItemArgs,shell=True) + ################################# + #ProcessStop + ################################# + if lItem["Type"]=="ProcessStop": + #Вид активности - остановка процесса + #часовой пояс пока не учитываем + #Запись в массив отработанных активностей + lDaemonActivityLogDict[(lItem["Type"],lActivityDateTime,lItem["Name"])]={"ActivityStartDateTime":lCurrentDateTime} + #Сформировать команду на завершение + lActivityCloseCommand='taskkill /im '+lItem["processName"] + #TODO Сделать безопасную обработку,если параметра нет в конфигурации + if lItem.get('FlagForce',False): + lActivityCloseCommand+=" /F" + #Завершить процессы только текущего пользоваиеля + if lItem.get('User',"")!="": + lActivityCloseCommand+=f' /fi "username eq {lItem["User"]}"' + #Лог + mGlobalDict["Processor"]["LogList"].append({"activityType":lItem["activityType"], "activityDateTime":str(lActivityDateTime), "processPath":lItem["processName"], "activityStartDateTime":str(lCurrentDateTime)}) + #Завершить процесс + os.system(lActivityCloseCommand) + ################################# + #PythonStart + ################################# + if lItem["Type"]=="PythonStart": + try: + #Подключить модуль для вызова + lModule=importlib.import_module(lItem["ModuleName"]) + #Найти функцию + lFunction=getattr(lModule,lItem["FunctionName"]) + lItem["Result"]=lFunction(*lItem.get("ArgList",[]),**lItem.get("ArgDict",{})) + except Exception as e: + logging.exception("Loop activity error: module/function not founded") + #Set datetime stop + lItem["DateTimeUTCStringStop"] = datetime.datetime.now().strftime("%Y-%m-%dT%H:%M:%S.%f") + ################## + #Trace activity + ################## + if mGlobalDict["Processor"].get(f"LogType_{lItem['Type']}",True): + #Add activity in TransactionList if it is applicable + mGlobalDict["Processor"]["LogList"].append(copy.deepcopy(lItem)) #Вернуть результат - return lResult + return lItem + +def ActivityListOrDict(inActivityListOrDict): + #Check arg type (list or dict) + if type(inActivityListOrDict)==list: + #List activity + for lItem in inActivityListOrDict: + lResult.append(Activity(lItem)) + return lResult + if type(inActivityListOrDict)==dict: + #Dict activity + return Activity(inActivityListOrDict) \ No newline at end of file diff --git a/Orchestrator/orchestratorServer.py b/Orchestrator/orchestratorServer.py index a2cadb13..abafd4a8 100644 --- a/Orchestrator/orchestratorServer.py +++ b/Orchestrator/orchestratorServer.py @@ -162,7 +162,7 @@ class testHTTPServer_RequestHandler(BaseHTTPRequestHandler): # POST def do_POST(self): #Централизованная функция получения запросов/отправки - if self.path == '/ProcessingRun': + if self.path == '/Utils/Processor': #ReadRequest lInputObject={} if self.headers.get('Content-Length') is not None: @@ -176,7 +176,7 @@ class testHTTPServer_RequestHandler(BaseHTTPRequestHandler): self.send_header('Content-type','application/json') self.end_headers() # Send message back to client - message = json.dumps(orchestratorProcessor.ProcessingRun(lInputObject)) + message = json.dumps(orchestratorProcessor.ActivityListOrDict(lInputObject)) # Write content as utf-8 data self.wfile.write(bytes(message, "utf8")) return diff --git a/Orchestrator/orchestratorTimer.py b/Orchestrator/orchestratorTimer.py index 7c86ba22..f42fc01f 100644 --- a/Orchestrator/orchestratorTimer.py +++ b/Orchestrator/orchestratorTimer.py @@ -3,6 +3,7 @@ import datetime import subprocess import importlib import logging +import orchestratorProcessor class RepeatedTimer(object): def __init__(self, interval, function, *args, **kwargs): self._timer = None @@ -31,31 +32,11 @@ class RepeatedTimer(object): ############################################################ ####Техническая функция обработки таймера - потока ############################################################ -def activityLoopExecution(inProcessPath,inProcessArgList,inLoopTimeEndDateTime,inPythonPackageName,inPythonFunctionName,inPythonFunctionArgList=[]): +def activityLoopExecution(inLoopTimeEndDateTime, inActivity): lResultGoLoop=True lCurrentDateTime=datetime.datetime.now() - print (datetime.datetime.now().isoformat()+":: Loop activity check") - logging.info("Loop activity check") - #Запустить процесс, если установлен inProcessPath - if inProcessPath is not None: - if inProcessPath != "": - lItemArgs=[inProcessPath] - lItemArgs.extend(inProcessArgList) - subprocess.Popen(lItemArgs,stdin=subprocess.PIPE,stdout=subprocess.PIPE,stderr=subprocess.PIPE) - - #Импорт Python пакета и запуск функции из него - if inPythonPackageName is not None: - if inPythonPackageName != "": - try: - #Подключить модуль для вызова - lModule=importlib.import_module(inPythonPackageName) - #Найти функцию - lFunction=getattr(lModule,inPythonFunctionName) - lFunction(*inPythonFunctionArgList) - except Exception as e: - print (datetime.datetime.now().isoformat()+":: Loop activity error: module/function not founded") - logging.info("Loop activity error: module/function not founded") - + #Запустить актитвость через процессор (orchestratorProcessor) + orchestratorProcessor.ActivityListOrDict(inActivity) #Выключить таймер, если время наступило if lCurrentDateTime>=inLoopTimeEndDateTime: lResultGoLoop=False @@ -64,6 +45,6 @@ def activityLoopExecution(inProcessPath,inProcessArgList,inLoopTimeEndDateTime,i ############################################################ ####Функция запуска таймера - потока ############################################################ -def activityLoopStart(inActivityLoopSeconds,inProcessPath,inProcessArgList,inLoopTimeEndDateTime,inPythonPackageName,inPythonFunctionName,inPythonFunctionArgList=[]): - lTimer = RepeatedTimer(inActivityLoopSeconds, activityLoopExecution, inProcessPath,inProcessArgList,inLoopTimeEndDateTime,inPythonPackageName,inPythonFunctionName,inPythonFunctionArgList) # it auto-starts, no need of rt.start() +def activityLoopStart(inActivityLoopSeconds, inLoopTimeEndDateTime, inActivity): + lTimer = RepeatedTimer(inActivityLoopSeconds, activityLoopExecution, inLoopTimeEndDateTime, inActivity) # it auto-starts, no need of rt.start() lTimer.start() diff --git a/RobotLogout.bat b/RobotLogout.bat new file mode 100644 index 00000000..8876580f --- /dev/null +++ b/RobotLogout.bat @@ -0,0 +1,5 @@ +for /f "skip=1 tokens=3" %%s in ('query user %USERNAME%') do ( + %windir%\System32\tscon.exe %%s /dest:console +) +timeout 10 +QRes.exe /x 1680 /y 1050 \ No newline at end of file