# Agent Modify OSCMD - split SendLog2Orc and capture the output

# Create Git class (branchRev and Fetch) Work with Orc session and agent!

# Todo Schedule from
# Todo UpdateGit
# Todo Schedule git check
dev-linux
Ivan Maslov 3 years ago
parent 102fed3d71
commit 417e18b389

@ -87,7 +87,7 @@ def OSFileTextDataStrReceive(inFilePathStr, inEncodingStr="utf-8", inGSettings=N
return lFileDataStr return lFileDataStr
# Send CMD to OS. Result return to log + Orchestrator by the A2O connection # Send CMD to OS. Result return to log + Orchestrator by the A2O connection
def OSCMD(inCMDStr, inRunAsyncBool=True, inGSettings = None, inSendOutputToOrchestratorLogsBool = True, inCMDEncodingStr = "cp1251"): def OSCMD(inCMDStr, inRunAsyncBool=True, inGSettings = None, inSendOutputToOrchestratorLogsBool = True, inCMDEncodingStr = "cp1251", inCaptureBool = True):
""" """
Execute CMD on the Agent daemonic process Execute CMD on the Agent daemonic process
@ -95,18 +95,18 @@ def OSCMD(inCMDStr, inRunAsyncBool=True, inGSettings = None, inSendOutputToOrche
:param inRunAsyncBool: True - Agent processor don't wait execution; False - Agent processor wait cmd execution :param inRunAsyncBool: True - Agent processor don't wait execution; False - Agent processor wait cmd execution
:param inGSettings: Agent global settings dict :param inGSettings: Agent global settings dict
:param inSendOutputToOrchestratorLogsBool: True - catch cmd execution output and send it to the Orchestrator logs; Flase - else case; Default True :param inSendOutputToOrchestratorLogsBool: True - catch cmd execution output and send it to the Orchestrator logs; Flase - else case; Default True
!ATTENTION! If you need to start absolutely encapsulated app - set this flag as False. If you set True - the app output will come to Agent
:param inCMDEncodingStr: Set the encoding of the DOS window on the Agent server session. Windows is beautiful :) . Default is "cp1251" early was "cp866" - need test :param inCMDEncodingStr: Set the encoding of the DOS window on the Agent server session. Windows is beautiful :) . Default is "cp1251" early was "cp866" - need test
:param inCaptureBool: !ATTENTION! If you need to start absolutely encapsulated app - set this flag as False. If you set True - the app output will come to Agent
:return: :return:
""" """
lResultStr = "" lResultStr = ""
# Subdef to listen OS result # Subdef to listen OS result
def _CMDRunAndListenLogs(inCMDStr, inSendOutputToOrchestratorLogsBool, inCMDEncodingStr, inGSettings = None): def _CMDRunAndListenLogs(inCMDStr, inSendOutputToOrchestratorLogsBool, inCMDEncodingStr, inGSettings = None, inCaptureBool = True):
lL = inGSettings.get("Logger",None) if type(inGSettings) is dict else None lL = inGSettings.get("Logger",None) if type(inGSettings) is dict else None
lResultStr = "" lResultStr = ""
lOSCMDKeyStr = str(uuid.uuid4())[0:4].upper() lOSCMDKeyStr = str(uuid.uuid4())[0:4].upper()
lCMDProcess = None lCMDProcess = None
if inSendOutputToOrchestratorLogsBool == True: if inCaptureBool == True:
lCMDProcess = subprocess.Popen(f'cmd /c {inCMDStr}', stdout=subprocess.PIPE, stderr=subprocess.STDOUT) lCMDProcess = subprocess.Popen(f'cmd /c {inCMDStr}', stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
else: else:
lCMDProcess = subprocess.Popen(f'cmd /c {inCMDStr}', stdout=None, stderr=None, lCMDProcess = subprocess.Popen(f'cmd /c {inCMDStr}', stdout=None, stderr=None,
@ -114,12 +114,15 @@ def OSCMD(inCMDStr, inRunAsyncBool=True, inGSettings = None, inSendOutputToOrche
lListenBool = True lListenBool = True
lMessageStr = f"{lOSCMDKeyStr}: # # # # AGENT CMD Process has been STARTED # # # # " lMessageStr = f"{lOSCMDKeyStr}: # # # # AGENT CMD Process has been STARTED # # # # "
if lL: lL.info(lMessageStr) if lL: lL.info(lMessageStr)
if inSendOutputToOrchestratorLogsBool == True: # Capturing can be turned on!
A2O.LogListSend(inGSettings=inGSettings,inLogList=[lMessageStr]) A2O.LogListSend(inGSettings=inGSettings,inLogList=[lMessageStr])
lMessageStr = f"{lOSCMDKeyStr}: {inCMDStr}" lMessageStr = f"{lOSCMDKeyStr}: {inCMDStr}"
if lL: lL.info(lMessageStr) if lL: lL.info(lMessageStr)
if inSendOutputToOrchestratorLogsBool == True: # Capturing can be turned on!
A2O.LogListSend(inGSettings=inGSettings, inLogList=[lMessageStr]) A2O.LogListSend(inGSettings=inGSettings, inLogList=[lMessageStr])
while lListenBool: while lListenBool:
if inSendOutputToOrchestratorLogsBool == True: # Capturing can be turned on! #if inSendOutputToOrchestratorLogsBool == True: # Capturing can be turned on!
if inCaptureBool == True: # Capturing can be turned on!
lOutputLineBytes = lCMDProcess.stdout.readline() lOutputLineBytes = lCMDProcess.stdout.readline()
if lOutputLineBytes == b"": if lOutputLineBytes == b"":
lListenBool = False lListenBool = False
@ -127,6 +130,7 @@ def OSCMD(inCMDStr, inRunAsyncBool=True, inGSettings = None, inSendOutputToOrche
if lStr.endswith("\n"): lStr = lStr[:-1] if lStr.endswith("\n"): lStr = lStr[:-1]
lMessageStr = f"{lOSCMDKeyStr}: {lStr}" lMessageStr = f"{lOSCMDKeyStr}: {lStr}"
if lL: lL.info(lMessageStr) if lL: lL.info(lMessageStr)
if inSendOutputToOrchestratorLogsBool == True: # Capturing can be turned on!
A2O.LogListSend(inGSettings=inGSettings, inLogList=[lMessageStr]) A2O.LogListSend(inGSettings=inGSettings, inLogList=[lMessageStr])
lResultStr+=lStr lResultStr+=lStr
else: #Capturing is not turned on - wait until process will be closed else: #Capturing is not turned on - wait until process will be closed
@ -137,15 +141,16 @@ def OSCMD(inCMDStr, inRunAsyncBool=True, inGSettings = None, inSendOutputToOrche
lListenBool = False lListenBool = False
lMessageStr = f"{lOSCMDKeyStr}: # # # # AGENT CMD Process has been FINISHED # # # # " lMessageStr = f"{lOSCMDKeyStr}: # # # # AGENT CMD Process has been FINISHED # # # # "
if lL: lL.info(lMessageStr) if lL: lL.info(lMessageStr)
if inSendOutputToOrchestratorLogsBool == True: # Capturing can be turned on!
A2O.LogListSend(inGSettings=inGSettings, inLogList=[lMessageStr]) A2O.LogListSend(inGSettings=inGSettings, inLogList=[lMessageStr])
return lResultStr return lResultStr
# New call # New call
if inRunAsyncBool: if inRunAsyncBool:
lThread = threading.Thread(target=_CMDRunAndListenLogs, kwargs={"inCMDStr":inCMDStr, "inGSettings":inGSettings, "inSendOutputToOrchestratorLogsBool":inSendOutputToOrchestratorLogsBool, "inCMDEncodingStr":inCMDEncodingStr }) lThread = threading.Thread(target=_CMDRunAndListenLogs, kwargs={"inCMDStr":inCMDStr, "inGSettings":inGSettings, "inSendOutputToOrchestratorLogsBool":inSendOutputToOrchestratorLogsBool, "inCMDEncodingStr":inCMDEncodingStr, "inCaptureBool": inCaptureBool })
lThread.start() lThread.start()
lResultStr="ActivityList has been started in async mode - no output is available here." lResultStr="ActivityList has been started in async mode - no output is available here."
else: else:
lResultStr = _CMDRunAndListenLogs(inCMDStr=inCMDStr, inGSettings=inGSettings, inSendOutputToOrchestratorLogsBool = inSendOutputToOrchestratorLogsBool, inCMDEncodingStr = inCMDEncodingStr) lResultStr = _CMDRunAndListenLogs(inCMDStr=inCMDStr, inGSettings=inGSettings, inSendOutputToOrchestratorLogsBool = inSendOutputToOrchestratorLogsBool, inCMDEncodingStr = inCMDEncodingStr, inCaptureBool=inCaptureBool)
#lCMDCode = "cmd /c " + inCMDStr #lCMDCode = "cmd /c " + inCMDStr
#subprocess.Popen(lCMDCode) #subprocess.Popen(lCMDCode)
#lResultCMDRun = 1 # os.system(lCMDCode) #lResultCMDRun = 1 # os.system(lCMDCode)

@ -516,3 +516,8 @@ def Update(inGSettings):
if inGSettings.get("SchedulerDict",{}).get("Schedule",None) is None: if inGSettings.get("SchedulerDict",{}).get("Schedule",None) is None:
inGSettings["SchedulerDict"]["Schedule"] = schedule inGSettings["SchedulerDict"]["Schedule"] = schedule
if lL: lL.warning(f"Backward compatibility (v1.2.4 to v1.2.7): Create new module schedule (schedule.readthedocs.io)") # Log about compatibility if lL: lL.warning(f"Backward compatibility (v1.2.4 to v1.2.7): Create new module schedule (schedule.readthedocs.io)") # Log about compatibility
# ManagersGitDict
if "ManagersGitDict" not in inGSettings:
inGSettings["ManagersGitDict"]={}
if lL: lL.warning(
f"Backward compatibility (v1.2.4 to v1.2.7): Create new key: ManagersGitDict") # Log about compatibility

@ -0,0 +1,103 @@
import os
from .. import __Orchestrator__
class Git():
mAgentHostNameStr = None
mAgentUserNameStr = None
mAbsPathStr = None
def __init__(self, inAgentHostNameStr=None, inAgentUserNameStr=None, inGitPathStr=""):
"""
Init the Git repo instance. It helps to detect new changes in repo and auto restart services
:param inAgentHostNameStr: Agent hostname in any case. Required to identify Process. If None - works with Orc session
:param inAgentUserNameStr: Agent user name in any case. Required to identify Process. If None - works with Orc session
:param inGitPathStr: Relative (from the orchestrator working directory) or absolute. If "" - work with Orc repo
:return:
"""
lAbsPathUpperStr = os.path.abspath(inGitPathStr).upper()
lGS = __Orchestrator__.GSettingsGet()
# Check if Process is not exists in GSettings
if (inAgentHostNameStr.upper(), inAgentUserNameStr.upper(), lAbsPathUpperStr) not in lGS["ManagersGitDict"]:
self.mAbsPathUpperStr = lAbsPathUpperStr
self.mAgentHostNameStr = inAgentHostNameStr
self.mAgentUserNameStr = inAgentUserNameStr
lGS["ManagersGitDict"][(inAgentHostNameStr.upper(), inAgentUserNameStr.upper(), lAbsPathUpperStr)]=self
else: raise Exception(f"Managers.Git ({inAgentHostNameStr}, {inAgentUserNameStr}, {lAbsPathUpperStr}): Can't init the Git instance because it already inited in early")
def __OSCMDShell__(self, inCMDStr):
"""
Detect the way of use and send the cmd
:return: None is not exists
"""
if self.mAgentUserNameStr is not None and self.mAgentHostNameStr is not None: # Check if Agent specified
lActivityItemGUIDStr = __Orchestrator__.AgentOSCMD(inHostNameStr=self.mAgentHostNameStr,inUserStr=self.mAgentUserNameStr,inCMDStr=inCMDStr,inRunAsyncBool=False,inSendOutputToOrchestratorLogsBool=False)
lCMDResultStr = __Orchestrator__.AgentActivityItemReturnGet(inGUIDStr=lActivityItemGUIDStr)
else:
lCMDResultStr = __Orchestrator__.OSCMD(inCMDStr=inCMDStr, inRunAsyncBool=False)
return lCMDResultStr
def BranchRevGet(self, inBranchNameStr="HEAD"):
"""
Get the specified branch revision. Default return the current branch revision
.. code-block:: python
lGit.BranchRevGet(inBranchNameStr="dev") # Get revision of the local dev branch
lGit.BranchRevGet(inBranchNameStr="remotes/origin/dev") # Get revision of the remotes dev branch
lGit.BranchRevGet(inBranchNameStr="HEAD") # Get revision of the current HEAD branch
lGit.BranchRevGet() # Equal to the call inBranchNameStr="HEAD"
:param inBranchNameStr: The branch name where to get revision guid
:return: revision GUID
"""
lCMDStr = f"cd \"{self.mAbsPathUpperStr}\" && git rev-parse {inBranchNameStr}"
lCMDResultStr = self.__OSCMDShell__(inCMDStr=lCMDStr)
return lCMDResultStr
def Fetch(self):
"""
Get updates from the git server.
.. code-block:: python
lGit.Fetch() # get updates from the server
:return: None
"""
lCMDStr = f"cd \"{self.mAbsPathUpperStr}\" && git fetch"
lCMDResultStr = self.__OSCMDShell__(inCMDStr=lCMDStr)
def GitExists(inAgentHostNameStr: str, inAgentUserNameStr: str, inGitPathStr: str) -> bool:
"""
Check if the Git instance is exists in GSettings by the (inAgentHostNameStr: str, inAgentUserNameStr: str, inGitPathStr: str)
:param inAgentHostNameStr: Agent hostname in any case. Required to identify Process
:param inAgentUserNameStr: Agent user name in any case. Required to identify Process
:param inGitPathStr: Relative (from the orchestrator working directory) or absolute. If "" - work with Orc repo
:return: True - process exists in gsettings; False - else
"""
return (inAgentHostNameStr.upper(), inAgentUserNameStr.upper(), inGitPathStr.upper()) in __Orchestrator__.GSettingsGet()["ManagersGitDict"]
def GitGet(inAgentHostNameStr: str, inAgentUserNameStr: str, inGitPathStr: str) -> Git:
"""
Return the Git instance by the (inAgentHostNameStr: str, inAgentUserNameStr: str, inGitPathStr: str)
:param inAgentHostNameStr: Agent hostname in any case. Required to identify Process
:param inAgentUserNameStr: Agent user name in any case. Required to identify Process
:param inGitPathStr: Relative (from the orchestrator working directory) or absolute. If "" - work with Orc repo
:return: Git instance (if exists) Else None
"""
lAbsPathUpperStr = os.path.abspath(inGitPathStr).upper()
return __Orchestrator__.GSettingsGet()["ManagersGitDict"].get((inAgentHostNameStr.upper(), inAgentUserNameStr.upper(), lAbsPathUpperStr),None)
def GitBranchRevGet(inAgentHostNameStr: str, inAgentUserNameStr: str, inGitPathStr: str, inBranchNameStr: str="HEAD") -> str:
lGit = GitGet(inAgentHostNameStr = inAgentHostNameStr, inAgentUserNameStr = inAgentUserNameStr, inGitPathStr=inGitPathStr)
if lGit is not None: return lGit.BranchRevGet(inBranchNameStr=inBranchNameStr)
def GitFetch(inAgentHostNameStr: str, inAgentUserNameStr: str, inGitPathStr: str) -> None:
lGit = GitGet(inAgentHostNameStr=inAgentHostNameStr, inAgentUserNameStr=inAgentUserNameStr,
inGitPathStr=inGitPathStr)
if lGit is not None: lGit.Fetch()

@ -1,2 +1,3 @@
from .ControlPanel import * from .ControlPanel import *
from .Process import * from .Process import *
from .Git import *

@ -151,6 +151,7 @@ def __Create__():
], ],
}, },
"ManagersProcessDict":{}, # The key of the Process is (mAgentHostNameStr.upper(), mAgentUserNameStr.upper(), mProcessNameWOExeStr.upper()) "ManagersProcessDict":{}, # The key of the Process is (mAgentHostNameStr.upper(), mAgentUserNameStr.upper(), mProcessNameWOExeStr.upper())
"ManagersGitDict":{}, # The key of the Git instance is (mAgentHostNameStr.upper(), mAgentUserNameStr.upper(), mAbsPathUpperStr.upper())
"ProcessorDict": { # Has been changed. New general processor (one threaded) v.1.2.0 "ProcessorDict": { # Has been changed. New general processor (one threaded) v.1.2.0
"ActivityList": [ # List of the activities "ActivityList": [ # List of the activities
# { # {

@ -124,7 +124,7 @@ def AgentActivityItemReturnGet(inGUIDStr, inCheckIntervalSecFloat = 0.5, inGSett
else: else:
raise Exception(f"__Orchestrator__.AgentActivityItemReturnGet !ATTENTION! Use this function only after Orchestrator initialization! Before orchestrator init exception will be raised.") raise Exception(f"__Orchestrator__.AgentActivityItemReturnGet !ATTENTION! Use this function only after Orchestrator initialization! Before orchestrator init exception will be raised.")
def AgentOSCMD(inHostNameStr, inUserStr, inCMDStr, inRunAsyncBool=True, inSendOutputToOrchestratorLogsBool=True, inCMDEncodingStr="cp1251", inGSettings=None): def AgentOSCMD(inHostNameStr, inUserStr, inCMDStr, inRunAsyncBool=True, inSendOutputToOrchestratorLogsBool=True, inCMDEncodingStr="cp1251", inGSettings=None, inCaptureBool=True):
""" """
Send CMD to OS thought the pyOpenRPA.Agent daemon. Result return to log + Orchestrator by the A2O connection Send CMD to OS thought the pyOpenRPA.Agent daemon. Result return to log + Orchestrator by the A2O connection
@ -135,13 +135,14 @@ def AgentOSCMD(inHostNameStr, inUserStr, inCMDStr, inRunAsyncBool=True, inSendOu
:param inRunAsyncBool: True - Agent processor don't wait execution; False - Agent processor wait cmd execution :param inRunAsyncBool: True - Agent processor don't wait execution; False - Agent processor wait cmd execution
:param inSendOutputToOrchestratorLogsBool: True - catch cmd execution output and send it to the Orchestrator logs; Flase - else case; Default True :param inSendOutputToOrchestratorLogsBool: True - catch cmd execution output and send it to the Orchestrator logs; Flase - else case; Default True
:param inCMDEncodingStr: Set the encoding of the DOS window on the Agent server session. Windows is beautiful :) . Default is "cp1251" early was "cp866" - need test :param inCMDEncodingStr: Set the encoding of the DOS window on the Agent server session. Windows is beautiful :) . Default is "cp1251" early was "cp866" - need test
:param inCaptureBool: !ATTENTION! If you need to start absolutely encapsulated app - set this flag as False. If you set True - the app output will come to Agent
:return: GUID String of the ActivityItem - you can wait (sync or async) result by this guid! :return: GUID String of the ActivityItem - you can wait (sync or async) result by this guid!
""" """
inGSettings = GSettingsGet(inGSettings=inGSettings) # Set the global settings inGSettings = GSettingsGet(inGSettings=inGSettings) # Set the global settings
lActivityItemDict = { lActivityItemDict = {
"Def":"OSCMD", # def alias (look pyOpeRPA.Agent gSettings["ProcessorDict"]["AliasDefDict"]) "Def":"OSCMD", # def alias (look pyOpeRPA.Agent gSettings["ProcessorDict"]["AliasDefDict"])
"ArgList":[], # Args list "ArgList":[], # Args list
"ArgDict":{"inCMDStr":inCMDStr,"inRunAsyncBool":inRunAsyncBool, "inSendOutputToOrchestratorLogsBool": inSendOutputToOrchestratorLogsBool, "inCMDEncodingStr": inCMDEncodingStr}, # Args dictionary "ArgDict":{"inCMDStr":inCMDStr,"inRunAsyncBool":inRunAsyncBool, "inSendOutputToOrchestratorLogsBool": inSendOutputToOrchestratorLogsBool, "inCMDEncodingStr": inCMDEncodingStr, "inCaptureBool":inCaptureBool}, # Args dictionary
"ArgGSettings": "inGSettings", # Name of GSettings attribute: str (ArgDict) or index (for ArgList) "ArgGSettings": "inGSettings", # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
"ArgLogger": None # Name of GSettings attribute: str (ArgDict) or index (for ArgList) "ArgLogger": None # Name of GSettings attribute: str (ArgDict) or index (for ArgList)
} }

Loading…
Cancel
Save