You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
ORPA-pyOpenRPA/Robot/Orchestrator_ControlPanel.py

300 lines
17 KiB

import psutil, datetime, logging, os, json
## # # # # # # # # # # # # # # # # ##
# GLOBAL PARAMETERS
gBuildFolderPathStr = '\\'.join(__file__.split('\\')[:-1])
gRobotRepositoryPathStr = os.popen(f'cd {gBuildFolderPathStr} && git rev-parse --show-toplevel').read().replace("\n",'').replace('/','\\') # needed for cmd and git pull
gRobotStartFilePathStr = os.path.join(gBuildFolderPathStr,r"pyRobotName_x64_Run.cmd") # path\to\start\file
gRobotProcessNameWOEXEStr = "pyRobotName" # RobotProcessName
gRobotADLoginStr = "AD LOGIN" # Login of the robot rdp session
gRobotADPasswordStr = "AD PASSWORD" # Password for rdp session
gRobotKeyStr = "pyRobotName" # Key for store OrchestratorConnector key-value (Orchstrator gSettings["Storage"][gRobotKeyStr])
gRDPSessionKeyStr = "pyRobotName"
gRDPSessionHostStr = "localhost" # Rdp session host
gRDPSessionPortStr = "3389" # Default RDP port is 3389
gControlPanelKeyStr = "pyRobotName" # Str key for RDP session key
gControlPanelCheckRobotProcessFromOrchestratorUserBool = True # Check process activity from orchestrator GUI session (with help of task manager, when users on the same machine)
# !! ATTENTION !! SCHEDULE TIME START STOP FILL BELOW IN ACTIVITY SECTION
gRobotToOrchestratorKeyList = ["Storage",gRobotKeyStr,"RobotToOrchestrator"]
gOrchestratorToRobotResetKeyList = ["Storage",gRobotKeyStr,"OrchestratorToRobotReset"]
gOrchestratorToRobotResetSafeStopKeyList = gOrchestratorToRobotResetKeyList+["TurnOffSafeBool"]
# # # # # # BUSINESS USER AD LOGIN # # # # # # # # # # # # # # #
gADLoginList = [
"ADLOGIN_1",
"ADLOGIN_2",
"ADLOGIN_3",
"ADLOGIN_4"
]
gADDomainNameStr = "MY-PC" # DOMAIN or EMPTY str if no domain
gADDomainIsDefaultBool = True # If domain is exist and is default (default = you can type login without domain name)
## # # # # # # # # # # # # # # # # ##
# ACTIVITY TEMPLATE START RDP & SEND CMD
gActivityROBOTStartTimeHH_MMStr = "01:01" # Time "HH:MM" [Server time] to execute activity, example "05:10"
gActivityROBOTStartWeekdayList = [0,1,2,3,4] # WeekdayList when atcivity is starting, default [0,1,2,3,4,5,6]
gActivityROBOTStartList = [
{ # Start RDP Session
"DefNameStr":"RDPSessionConnect", # Function name in RobotRDPActive.Processor
"ArgList":[], # Args list
"ArgDict":{"inRDPSessionKeyStr": gRDPSessionKeyStr, "inHostStr": gRDPSessionHostStr, "inPortStr": gRDPSessionPortStr, "inLoginStr": gRobotADLoginStr, "inPasswordStr": gRobotADPasswordStr} # Args dictionary
},
{ # Run robot file in RDP session
"DefNameStr":"RDPSessionProcessStartIfNotRunning", # Function name in RobotRDPActive.Processor
"ArgList":[], # Args list
"ArgDict":{"inRDPSessionKeyStr": gRDPSessionKeyStr, "inProcessNameWEXEStr": f"{gRobotProcessNameWOEXEStr}.exe", "inFilePathStr": gRobotStartFilePathStr, "inFlagGetAbsPathBool": False} # Args dictionary
}
]
## # # # # # # # # # # # # # # # # ##
# ACTIVITY TEMPLATE SAFE STOP (SIGNAL TO ROBOT TO STOP VIA ORCHESTRATOR CONNECTOR)
gActivityROBOTSafeStopTimeHH_MMStr = "23:40" # Time "HH:MM" [Server time] to execute activity, example "05:10"
gActivityROBOTSafeStopWeekdayList = [0,1,2,3,4] # WeekdayList when atcivity is starting, default [0,1,2,3,4,5,6]
gActivityROBOTSafeStopList = [
{
"Type": "GlobalDictKeyListValueSet",
"KeyList": gOrchestratorToRobotResetSafeStopKeyList,
"Value": True
},
#{
# "Type": "ProcessStop", # Activity type
# "Name": f"{gRobotProcessNameWOEXEStr}.exe", # proces name with .exe
# "FlagForce": False, # Safe kill
# "User": gRobotADLoginStr #Empty, user or %username%
#},
{
"Type": "GlobalDictKeyListValueOperator+", # Activity type
"KeyList": ['RobotRDPActive', 'ActivityList'], # RobotRDP Active ActivityList
"Value": [ # ActivityList - see upper
{ # Kill process
"DefNameStr": "RDPSessionMonitorStop", # Function name in RobotRDPActive.Processor
"ArgList": [], # Args list
"ArgDict": {"inRDPSessionKeyStr": gRDPSessionKeyStr} # Args dictionary
}
]
}
]
## # # # # # # # # # # # # # # # # ##
# ACTIVITY TEMPLATE FORCE STOP (SEND CMD TO STOP PROCESS & LOGOFF THE SESSION)
gActivityROBOTStopList = [
{ # Kill process
"DefNameStr":"RDPSessionProcessStop", # Function name in RobotRDPActive.Processor
"ArgList":[], # Args list
"ArgDict":{"inRDPSessionKeyStr": gRDPSessionKeyStr, "inProcessNameWEXEStr":f"{gRobotProcessNameWOEXEStr}.exe","inFlagForceCloseBool": True} # Args dictionary
},
{ # Logoff RDP Session
"DefNameStr":"RDPSessionLogoff", # Function name in RobotRDPActive.Processor
"ArgList":[], # Args list
"ArgDict":{"inRDPSessionKeyStr": gRDPSessionKeyStr} # Args dictionary
}
]
## # # # # # # # # # # # # # # # # ##
# CONTROL PANEL RENDER FOR HTML
def ControlPanelRenderDict(inRequest, inGSettings):
# window.prompt("Укажите дату лога в формате дд.мм.гггг",null)
lUAC = inRequest.OpenRPA["DefUserRoleAccessAsk"] # Alias for request user role ask
"""result={
"HeaderLeftText":"<Robot name>",
"HeaderRightText":"<header>",
"DataStorageKey":"Robot_Name", #Use key for set current dict in mGlobal.DataStorage["DataStorageKey"] on client side
"SubheaderText": "State: <span style=\"color:green\">Turned on</span>",
"BodyKeyValueList":[
{"Key":"Session list","Value":""},
{"Key":"Session list","Value":""}
],
"FooterText":"Last update: 9:38:00 09.10.2019",
"FooterButtonX2List":[
{"Text":"Turn on", "Color":"green", "Link":"", "OnClick": lOnClickRunButton.replace("\\","\\\\")},
],
"FooterButtonX1List":[
{"Text":"Kill", "Color":"red", "Link":"", "OnClick": lOnClickForceCloseButton.replace("\\","\\\\")}
]
}"""
# START :: Create activities :: START #
## Robot START (create RDP session, send CMD to start process)
lActivityROBOTStartEscaped = f"mGlobal.Processor.ServerOperatorPlus({json.dumps(['RobotRDPActive','ActivityList'])},{json.dumps(gActivityROBOTStartList)});".replace("\"","\'")
## Robot SAFE STOP (SAFE STOP COMMAND (FROM ROBOT RULES), Logoff must do robot when safe turn off)
lActivityROBOTSafeStopEscaped = f"mGlobal.Processor.Send({json.dumps(gActivityROBOTSafeStopList)});"
## Robot FORCE STOP (send CMD to stop process, logoff)
lActivityROBOTStopEscaped = f"mGlobal.Processor.ServerOperatorPlus({json.dumps(['RobotRDPActive','ActivityList'])},{json.dumps(gActivityROBOTStopList)});".replace("\"","\'")
## REPOSITORY GIT PULL (send CMD to git pull)
gRobotRepositoryPathEscapedStr = gRobotRepositoryPathStr.replace("\\","\\\\")
lActivityRepositoryGITPULL = f'mGlobal.Controller.CMDRunText(\"cd \\\"{gRobotRepositoryPathEscapedStr}\\\" && git reset --hard && git pull\");'.replace("\"","&quot;")
lActivityRepositoryGITPULLHTML=f'<a onclick=\"{lActivityRepositoryGITPULL}\" style=\"color:orange\">Update GIT</a>'
# Activity download report ReportFileDocList
lActivityReportDownloadHTML=f'<a href=\"{gRobotKeyStr}/Reports/ReportFileDocList.xlsx\" target=\"_blank\" style=\"color:green\">Download</a>'
# Activity download report ReportPTSList
lActivityReportListDownloadHTML=f'<a href=\"{gRobotKeyStr}/Reports/ReportPTSList.xlsx\" target=\"_blank\" style=\"color:green\">Download</a>'
# END :: Create activities :: END #
# START :: Init result dict template :: START #
# lBodyKeyValue_r3_start=f'<a onclick="{lActivityROBOTStartEscaped}" style=\"color:green\">Start</a>'
lStatistics = TechDictKeyList_ItemGet(inDict = inGSettings, inKeyList = gRobotToOrchestratorKeyList+["Statistics"], inDefault={})
lResultDict={
"HeaderLeftText":"Robot description",
"HeaderRightText":"Robot",
"DataStorageKey":gControlPanelKeyStr, # CLIENT SIDE:: Use key for set current dict in mGlobal.DataStorage["DataStorageKey"] on client side
"SubheaderText":"<Subheader text, state filled below>",
"BodyKeyValueList":[
{"Key":"<b>Reports</b>","Value":""}
],
"FooterText":"Last update: 9:38:00 09.10.2019",
"FooterButtonX2List":[],
"FooterButtonX1List":[],
# "GlobalStorage": inGSettings.get("Storage",{}) # UNCOMMENT FOR DEBUG PURPOSE TO WATCH inGSettings on client side
}
# Start button
if lUAC([gRobotKeyStr,"Technical","Start"]): lResultDict["FooterButtonX2List"].append({"Text":"On", "Color":"green", "Link":"", "OnClick": lActivityROBOTStartEscaped})
# Stop safe button
if lUAC([gRobotKeyStr,"Technical","StopSafe"]): lResultDict["FooterButtonX2List"].append({"Text":"Off", "Color":"orange", "Link":"", "OnClick": lActivityROBOTSafeStopEscaped})
# Stop force button
if lUAC([gRobotKeyStr,"Technical","StopForce"]): lResultDict["FooterButtonX1List"].append({"Text":"Force ", "Color":"red", "Link":"", "OnClick": lActivityROBOTStopEscaped})
# END :: Init result dict template :: END #
# START :: Fill BodyKeyValueList :: START #
# Download report button ReportFileDocList.xlsx
if lUAC([gRobotKeyStr,"Business","ReportFileDocListDownload"]): lResultDict["BodyKeyValueList"].append({"Key":"Report 1","Value":lActivityReportDownloadHTML})
# Download report button ReportList.xlsx
if lUAC([gRobotKeyStr,"Business","ReportListDownload"]): lResultDict["BodyKeyValueList"].append({"Key":"Report 2","Value":lActivityReportListDownloadHTML})
# Add Addendum title
if lUAC([gRobotKeyStr,"Technical"]): lResultDict["BodyKeyValueList"].append({"Key":"<b>Additional</b>","Value":""})
# Download log file
lActivityLogDownloadOnclickStr = """var MyDate = new Date();var MyDateString;MyDateString = MyDate.getFullYear() + "_" + ('0' + (MyDate.getMonth()+1)).slice(-2) + "_" + ('0' + MyDate.getDate()).slice(-2);
var lLogFileNameWOExtStr = window.prompt("Please enter the date in format yyyy_mm_dd (example 2020_06_16)",MyDateString); window.open('pyRobotName/Logs/'+lLogFileNameWOExtStr+'.log','_blank');""".replace("\"","&quot;")
lActivityDayLogDownloadHTML = f'<a onclick=\"{lActivityLogDownloadOnclickStr}\" style=\"color:orange\">Download</a>'
if lUAC([gRobotKeyStr,"Technical","DayLogDownload"]): lResultDict["BodyKeyValueList"].append({"Key":"Log on date","Value":lActivityDayLogDownloadHTML})
# update git button button
if lUAC([gRobotKeyStr,"Technical","GITUpdate"]): lResultDict["BodyKeyValueList"].append({"Key": "GIT Repository", "Value": lActivityRepositoryGITPULLHTML})
# END :: Fill BodyKeyValueList :: END #
# START :: Fill SubheaderText :: START #
## FILL Robot state by the check the RDP session state
lSubheaderRunTrueText="State: <span style=\"color:green\">Turned on</span>"
lSubheaderRunFalseText="State: <span style=\"color:red\">Turned off</span>"
if gControlPanelCheckRobotProcessFromOrchestratorUserBool and gRDPSessionKeyStr in inGSettings["RobotRDPActive"]["RDPList"]:
lResultDict["SubheaderText"]=lSubheaderRunTrueText
else:
lResultDict["SubheaderText"]=lSubheaderRunFalseText
# END :: Fill SubheaderText :: END #
# Fill FooterText
lResultDict["FooterText"]=f'Last update: {datetime.datetime.now().strftime("%H:%M:%S %d.%m.%Y")}'
return lResultDict
# Technical def - Get item by the list of keys
def TechDictKeyList_ItemGet(inDict, inKeyList, inDefault={}):
lResult=inDict
for lItem in inKeyList:
if lResult:
lResult = lResult.get(lItem,None)
if lResult is None:
lResult=inDefault
return lResult
# Orchestrator - pyRobot business user-role access
# Role model - if len of keys in dict is 0 - all access. If at least len is 1 - only this access
# "pyRobot":{
# "Business": {
# "Report": {
# "ReportFileDocListDownload": {}, # Download a report
# "ReportListDownload": {}, # Download a report
# "DayLogDownload": {}, # Download a report
# },
# },
# "Technical": { # Technical functions - for developers
# "GITUpdate": {}, # Action to update git repository
# "Start": {}, # Action for start robot
# "StopForce": {}, # Action for the stop force
# "StopSafe": {} # Actions for the safe stop
# }
# }
# }
# USAGE in .py
# inRequest.OpenRPA["DefUserRoleAccessAsk"](["Orchestrator","RDPActive","Controls"]) - return True or False
# inRequest.OpenRPA["DefUserRoleHierarchyGet"]() - Return dict of the role hierarchy or {}
gRuleDomainUserDict = {
"MethodMatchURLBeforeList": [
{"Method": "GET", "MatchType": "Beginwith", "URL": "/", "FlagAccess": True},
{"Method": "POST", "MatchType": "Beginwith", "URL": "/", "FlagAccess": True}
],
"ControlPanelKeyAllowedList": [gControlPanelKeyStr], # If empty - all is allowed ["RobotScreenActive", ""]
"RoleHierarchyAllowedDict": {
gRobotKeyStr:{
"Business": {
"ReportFileDocListDownload": {}, # Download a report
"ReportListDownload": {}, # Download a report
},
"Technical": { # Technical functions - for developers
"DayLogDownload": {}, # Download a report
# "GITUpdate": {}, # Action to update git repository
# "Start": {}, # Action for start robot
# "StopForce": {}, # Action for the stop force
# "StopSafe": {} # Actions for the safe stop
}
}
}
}
#Orchestrator settings update
def SettingsUpdate(inGSettings):
# Add user roles
for lUserNameStr in gADLoginList:
# Case add domain + user
inGSettings["Server"]["AccessUsers"]["RuleDomainUserDict"].update({(gADDomainNameStr.upper(),lUserNameStr.upper()):gRuleDomainUserDict})
if gADDomainIsDefaultBool:
# Case add default domain + user
inGSettings["Server"]["AccessUsers"]["RuleDomainUserDict"].update({("",lUserNameStr.upper()):gRuleDomainUserDict})
#Add RobotRDPActive in control panel
inGSettings["ControlPanelDict"]["RobotList"].append({"RenderFunction": ControlPanelRenderDict, "KeyStr": gControlPanelKeyStr})
# Add folder to server to download files
lReportFolderItem = {
"Method": "GET",
"URL": f"/{gRobotKeyStr}/Reports/", # URL of the request
"MatchType": "BeginWith", # "BeginWith|Contains|Equal|EqualCase",
# "ResponseFilePath": "", #Absolute or relative path
"ResponseFolderPath": os.path.join(gBuildFolderPathStr, "Reports"),
# Absolute or relative path
"ResponseContentType": "application/octet-stream", #HTTP Content-type
# "ResponseDefRequestGlobal": None #Function with str result
}
inGSettings["Server"]["URLList"].append(lReportFolderItem)
# Add folder to server to download files
lReportFolderItem = {
"Method": "GET",
"URL": f"/{gRobotKeyStr}/Logs/", # URL of the request
"MatchType": "BeginWith", # "BeginWith|Contains|Equal|EqualCase",
# "ResponseFilePath": "", #Absolute or relative path
"ResponseFolderPath": os.path.join(gBuildFolderPathStr, "Logs"),
# Absolute or relative path
"ResponseContentType": "application/octet-stream", #HTTP Content-type
# "ResponseDefRequestGlobal": None #Function with str result
}
inGSettings["Server"]["URLList"].append(lReportFolderItem)
# AUTOSTART Robot
inGSettings["OrchestratorStart"]["ActivityList"].append(
{
"Type": "GlobalDictKeyListValueOperator+", #Activity type
"KeyList": ['RobotRDPActive','ActivityList'], # RobotRDP Active ActivityList
"Value": gActivityROBOTStartList # ActivityList - see upper
}
)
# Add scheduler activity in Scheduler.ActivityTimeList
# # # # # # # # # # # # # # # # # # # # # # # #
lActivityTimeItemRobotStart = {
"TimeHH:MM": gActivityROBOTStartTimeHH_MMStr, #Time [HH:MM] to trigger activity
"WeekdayList": gActivityROBOTStartWeekdayList, #List of the weekday index when activity is applicable, Default [1,2,3,4,5,6,7]
"Activity":{
"Type": "GlobalDictKeyListValueSet", #Activity type
"KeyList": ['RobotRDPActive','ActivityList'], # RobotRDP Active ActivityList
"Value": gActivityROBOTStartList # ActivityList - see upper
}
}
inGSettings["Scheduler"]["ActivityTimeList"].append(lActivityTimeItemRobotStart)
for lItem in gActivityROBOTSafeStopList: # Temporary method while Scheduler apply only 1 activity in 1 item
inGSettings["Scheduler"]["ActivityTimeList"].append({
"TimeHH:MM": gActivityROBOTSafeStopTimeHH_MMStr, # Time [HH:MM] to trigger activity
"WeekdayList": gActivityROBOTSafeStopWeekdayList,
"Activity": lItem # Run actiovity 0 from list # List of the weekday index when activity is applicable, Default [1,2,3,4,5,6,7]
})
return inGSettings