def __stopProcesses(self): """ stop all processes that run as app_user_account refers to http://stackoverflow.com/questions/4669754/python-kill-all-processes-owned-by-user """ self._updateStatus(progress=10) uname = pylons.config['app_user_account'] import pwd uid = pwd.getpwnam(uname).pw_uid pids = filter(lambda pid: pid.isdigit(), os.listdir('/proc')) execThreads = [] # test if PID is owned by user for pid in pids: # check if PID still exist if not os.path.exists(os.path.join('/proc', pid)): LOG.debug("pid doesn't exist any more: %s" % pid) continue puid = os.stat(os.path.join('/proc', pid)).st_uid if puid == uid: cmd = utils.sudoCmd(['kill', '-9', pid], uname) execThread = ExecThread(self._threadMgr, cmd) execThread.setTimeout(self.__killTimeout) execThread.start() execThreads.append(execThread) while (True): self._checkStop() running = False for execThread in execThreads: status = execThread.getStatus() if (status['error'] != None): raise AgentException(status['error'], status['errorMsg']) if (execThread.isAlive()): LOG.debug("process is still alive: %s" % execThread.getCmd()) running = True if (not running): LOG.debug( "stop processes finished: %s" % [execThread.getCmd()[-1] for execThread in execThreads]) break time.sleep(0.1) self._updateStatus(progress=50)
def __stopProcesses(self): """ stop all processes that run as app_user_account refers to http://stackoverflow.com/questions/4669754/python-kill-all-processes-owned-by-user """ self._updateStatus(progress = 10) uname = configutil.getAppUser() uid, _ = utils.getUidGid(uname) pids = filter(lambda pid: pid.isdigit(), os.listdir('/proc')) execThreads = [] # test if PID is owned by user for pid in pids: # check if PID still exist if not os.path.exists(os.path.join('/proc', pid)): LOG.debug("pid doesn't exist any more: %s" % pid) continue puid = os.stat(os.path.join('/proc', pid)).st_uid if puid == uid: cmd = utils.sudoCmd(['kill', '-9', pid], uname) execThread = ExecThread(self._threadMgr, cmd) execThread.setTimeout(self.__killTimeout) execThread.start() execThreads.append(execThread) self._addChildExeThreadId(execThread.getUuid()) while(True): self._checkStop() running = False for execThread in execThreads: status = execThread.getStatus() if (status['error'] != None): raise AgentException(status['error'], status['errorMsg']) if (execThread.isAlive()): LOG.debug("process is still alive: %s" % execThread.getCmd()) running = True if (not running): LOG.debug("stop processes finished: %s" % [execThread.getCmd()[-1] for execThread in execThreads]) break time.sleep(0.1) self._updateStatus(progress = 50)
def executeScript(self, service, scriptname): """ execute a script from remote location""" scriptpath = None try: # parse the body if (not request.body or request.body == ""): LOG.error('invalid body found in post command') return errorResult(request, response, Errors.INVALID_REQUEST, 'No body found in post command', controller = self) body = json.loads(request.body) paramobj = body['params'] if 'params' in body else [] params = paramobj if type(paramobj) == list else paramobj.split() LOG.info('%s' % (params)) scriptpath = None for package in manifestutil.packagesInManifest(service): scriptpathtmp = os.path.join(manifestutil.packagePath(service, 'active', package), 'cronus', 'scripts', scriptname) if os.path.exists(scriptpathtmp): scriptpath = scriptpathtmp break if not scriptpath: return errorResult(request, response, Errors.INVALID_REQUEST, 'script %s not found' % scriptname, controller = self) cmd = ['sudo', '-u', 'cronusapp', scriptpath] for param in params: param = param.encode('ascii', 'ignore') cmd.append(param) LOG.info('cmd = %s' % cmd) appGlobal = config['pylons.app_globals'] execThread = ExecThread(appGlobal.threadMgr, cmd) execThread.setLogLevel('info') execThread.start() execThread.threadMgrEvent.wait() return statusResult(request, response, execThread, controller = self) except Exception as excp: return errorResult(request, response, error = Errors.UNKNOWN_ERROR, errorMsg = 'Unknown error when executing cmd %s, %s - %s' % (scriptpath, str(excp), traceback.format_exc(2)), controller = self)
def executeScript(self, service, scriptname): """ execute a script from remote location""" scriptpath = None try: # parse the body if (not request.body or request.body == ""): LOG.error('invalid body found in post command') return errorResult(request, response, Errors.INVALID_REQUEST, 'No body found in post command', controller=self) body = json.loads(request.body) paramobj = body['params'] if 'params' in body else [] params = paramobj if type(paramobj) == list else paramobj.split() LOG.info('%s' % (params)) scriptpath = None for package in manifestutil.packagesInManifest(service): scriptpathtmp = os.path.join( manifestutil.packagePath(service, 'active', package), 'cronus', 'scripts', scriptname) if os.path.exists(scriptpathtmp): scriptpath = scriptpathtmp break if not scriptpath: return errorResult(request, response, Errors.INVALID_REQUEST, 'script %s not found' % scriptname, controller=self) cmd = ['sudo', '-u', 'cronusapp', scriptpath] for param in params: param = param.encode('ascii', 'ignore') cmd.append(param) LOG.info('cmd = %s' % cmd) appGlobal = config['pylons.app_globals'] execThread = ExecThread(appGlobal.threadMgr, cmd) execThread.setLogLevel('info') execThread.start() execThread.threadMgrEvent.wait() return statusResult(request, response, execThread, controller=self) except Exception as excp: return errorResult( request, response, error=Errors.UNKNOWN_ERROR, errorMsg='Unknown error when executing cmd %s, %s - %s' % (scriptpath, str(excp), traceback.format_exc(2)), controller=self)
def _getBuiltThread(self, service, manifest, package, exeName): """ here """ # figure out the path to the cronus scripts uname = configutil.getAppUser() execPath = os.path.join(manifestutil.manifestPath(service, manifest), package, 'cronus', 'scripts', exeName) if (isHigherPrivilegeService(service)) or not uname: cmd = execPath else: cmd = utils.sudoCmd([execPath], uname) dummy = not os.path.exists(execPath) if not dummy: execThread = ExecThread(self._threadMgr, cmd, parentId = self.getUuid()) contextutils.copyJobContexts(self, execThread) # issue 17, not inject ctx for startup and shutdown script if exeName == 'startup' or exeName == 'shutdown': execThread.setInjectctx(False) return execThread else: return None
def executeCmd(self): """ execute a command synchronously """ try: # parse the body if not request.body: LOG.error('invalid body found in post command') return errorResult(request, response, Errors.INVALID_REQUEST, 'No body found', controller = self) body = json.loads(request.body.encode('ascii', 'ignore')) if 'cmd' not in body: return errorResult(request, response, Errors.INVALID_REQUEST, 'No cmd found', controller = self) cmd0 = body['cmd'] hasSudo = ('sudoUser' in body and body['sudoUser']) sudoUser = body['sudoUser'] if ('sudoUser' in body and body['sudoUser'] != 'root') else None LOG.info('%s %s %s' % (cmd0, hasSudo, sudoUser)) cmd = cmd0.split() if hasSudo: cmd.insert(0, 'sudo') if sudoUser is not None: cmd.insert(1, sudoUser) cmd.insert(1, '-u') appGlobal = config['pylons.app_globals'] execThread = ExecThread(appGlobal.threadMgr, cmd) execThread.setLogLevel('info') contextutils.copyJobContexts(self, execThread) execThread.start() return statusResult(request, response, execThread, controller = self) except Exception as excp: return errorResult(request, response, error = Errors.UNKNOWN_ERROR, errorMsg = 'Unknown error when executing cmd %s, %s - %s' % (cmd, str(excp), traceback.format_exc(2)), controller = self)
def untar(self, packagePath, untarPath, nicelevel): ''' do real untar ''' cmd = ['tar', '-C', untarPath, '-x', '-f', packagePath] # timeout 60 minute execThread = ExecThread(None, cmd, None) execThread.setTimeout(3600) execThread.run() status = execThread.getStatus() if (status['error'] != None): msg = 'untar cmd (%s) failed (%s - %s)' % (' '.join(cmd), status['error'], status['errorMsg']) LOG.error(msg) raise AgentException(Errors.PACKAGE_UNTAR_FAILURE, msg)
def _executeCommand(self, cmd, timeout = 2, service = None): ''' execute command ''' execThread = ExecThread(None, cmd) execThread.setLogLevel('debug') execThread.run() # now wait for the threads to complete and update progress status = execThread.getStatus() if (status['error'] != None): return None # raise AgentException(status['error'], status['errorMsg']) return status['result']
def executeCmd(self): """ execute a command synchronously """ try: # parse the body if (not request.body or request.body == ""): LOG.error('invalid body found in post command') return errorResult(request, response, 10001, 'No body found', controller=self) body = json.loads(request.body) cmd0 = body['cmd'] if 'cmd' in body else None needsudo = asbool( body['need-sudo']) if 'need-sudo' in body else False sudotgt = body['sudo-target'] if 'sudo-target' in body else None paramobj = body['params'] if 'params' in body else [] params = paramobj if type(paramobj) == list else paramobj.split() LOG.info('%s %s %s %s' % (cmd0, needsudo, sudotgt, params)) if cmd0 is None or cmd0 == '': return errorResult(request, response, 10002, 'No command found', controller=self) cmd = [cmd0.encode('ascii', 'ignore')] if needsudo: cmd.insert(0, 'sudo') if sudotgt is not None: sudotgt = sudotgt.encode('ascii', 'ignore') cmd.insert(1, sudotgt) cmd.insert(1, '-u') for param in params: param = param.encode('ascii', 'ignore') cmd.append(param) appGlobal = config['pylons.app_globals'] execThread = ExecThread(appGlobal.threadMgr, cmd) execThread.setLogLevel('info') execThread.start() return statusResult(request, response, execThread, controller=self) except Exception as excp: return errorResult( request, response, error=Errors.UNKNOWN_ERROR, errorMsg='Unknown error when executing cmd %s, %s - %s' % (cmd, str(excp), traceback.format_exc(2)), controller=self)
def _getBuiltThread(self, service, manifest, package, exeName): """ here """ # figure out the path to the cronus scripts uname = pylons.config['app_user_account'] execPath = os.path.join( ManifestController.manifestPath(service, manifest), package, 'cronus', 'scripts', exeName) if (isHigherPrivilegeService(service)): cmd = execPath else: cmd = utils.sudoCmd([execPath], uname) dummy = not os.path.exists(execPath) execThread = ExecThread(self._threadMgr, cmd) copycontexts(self, execThread, contextutils.CTX_NAMES) return execThread, dummy
def _getBuiltThread(self, scriptName): """ build lcm script exec thread """ # figure out the path to the cronus scripts uname = pylons.config['app_user_account'] execPath = os.path.join( manifestutil.modulePath(self.__service, self.__module), self.__package, 'cronus', 'scripts', scriptName) if (isHigherPrivilegeService(self.__service)): cmd = execPath else: cmd = utils.sudoCmd([execPath], uname) dummy = not os.path.exists(execPath) execThread = ExecThread(self._threadMgr, cmd) copycontexts(self, execThread, ['service', 'guid']) return execThread, dummy
def untar(self, packagePath, untarPath, nicelevel): ''' do real untar ''' cmd = ['tar', '-C', untarPath, '-x', '-f', packagePath] # timeout 60 minute execThread = ExecThread(None, cmd, None, self.getUuid()) execThread.setTimeout(3600) execThread.run() status = execThread.getStatus() if (status['error'] != None): msg = 'untar cmd (%s) failed (%s - %s)' % (' '.join(cmd), status['error'], status['errorMsg']) LOG.error(msg) raise AgentException(Errors.PACKAGE_UNTAR_FAILURE, msg)
def runScript(self, script, timeout, progressTimeout): ''' @param script: script name @param timeout: total script timeout @param progressTimeout: progress timeout @return: ExecThread instance @throws PackageScriptNotFound: if script does not exist ''' if not self.hasScript(script): raise PackageScriptNotFound('missing package script: ' + self.__scriptPath(script)) cmd = utils.sudoCmd([], self.__userName) if self.__userName else [] cmd.append(self.__scriptPath(script)) execThread = ExecThread(self.__threadMgr, cmd) execThread.setTimeout(timeout) execThread.setProgressTimeout(progressTimeout) copycontexts(self, execThread, ['guid', 'service']) execThread.start() return execThread
def executeScript(self): """ execute a script from remote location""" scriptpath = None try: # parse the body if (not request.body or request.body == ""): LOG.error('invalid body found in post command') return errorResult(request, response, 10001, 'No body found in post command', controller=self) body = json.loads(request.body) scriptloc = body['script-location'].encode( 'ascii', 'ignore') if 'script-location' in body else None scriptname = body['script-name'].encode( 'ascii', 'ignore') if 'script-name' in body else None needsudo = asbool( body['need-sudo']) if 'need-sudo' in body else False sudotgt = body['sudo-target'].encode( 'ascii', 'ignore') if 'sudo-target' in body else None paramobj = body['params'] if 'params' in body else [] params = paramobj if type(paramobj) == list else paramobj.split() LOG.info('%s %s %s %s %s' % (scriptloc, scriptname, needsudo, sudotgt, params)) if scriptloc is None or scriptloc == '': return errorResult(request, response, 10003, 'Script location not found', controller=self) if scriptname is None or scriptname == '': return errorResult(request, response, 10003, 'Script name not found', controller=self) scriptpath = os.path.join(self.dataPath(), scriptname) LOG.info('scriptpath = %s' % scriptpath) os.system('wget %s -O %s' % (scriptloc, scriptpath)) if scriptpath is None or not os.path.exists(scriptpath): return errorResult(request, response, 10003, 'Failed to get script %s' % scriptpath, controller=self) rchmod(scriptpath, '+rx') cmd = [scriptpath] if needsudo: cmd.insert(0, 'sudo') if sudotgt is not None: cmd.insert(1, sudotgt) cmd.insert(1, '-u') for param in params: param = param.encode('ascii', 'ignore') cmd.append(param) LOG.info('cmd = %s' % cmd) appGlobal = config['pylons.app_globals'] execThread = ExecThread(appGlobal.threadMgr, cmd) execThread.setLogLevel('info') execThread.start() execThread.threadMgrEvent.wait() return statusResult(request, response, execThread, controller=self) except Exception as excp: return errorResult( request, response, error=Errors.UNKNOWN_ERROR, errorMsg='Unknown error when executing cmd %s, %s - %s' % (scriptpath, str(excp), traceback.format_exc(2)), controller=self)
def test_process_exec_response(self): exeThread = ExecThread(None, 'dummy') exeThread.setTimeout(0) msg_header = '[AGENT_MESSAGE]{"errorMsg": "' msg_line1 = 'line 1' msg_line2 = 'line 2' msg_line3 = 'line 3' msg_footer = '"}' exeThread.processExecResponse(msg_header) exeThread.processExecResponse(msg_line1) exeThread.processExecResponse(msg_line2) exeThread.processExecResponse(msg_line3) exeThread.processExecResponse(msg_footer)
def _test_progress(self): cmd = os.path.join(self.scriptDir, 'test.sh') LOG.debug('cmd = %s' % cmd) testExec = ExecThread(self.threadMgr, cmd) testExec.setTimeout(30) testExec.setProgressTimeout(10) testExec.start() # make sure the script is running tm = time.time() while (testExec.getCmdPid() == None and tm + 10 > time.time()): time.sleep(0.1) assert testExec.getCmdPid() != None print '****** cmd pid = %d' % testExec.getCmdPid() progress = 10 # check that we increment the progress to 100 tm = time.time() while (progress < 101 and tm + 5 > time.time()): LOG.debug('progress == %s: %s' % (str(testExec.getStatus()['progress']), str(progress))) if (int(testExec.getStatus()['progress']) == int(progress)): LOG.debug('sending sigint') try: #The script itself traps the signal in increments its progress. os.kill(testExec.getCmdPid(), signal.SIGINT) except OSError: pass progress += 10 time.sleep(0.05) self.printStatus(testExec.getStatus()) if (not os.name == 'nt'): assert int(testExec.getStatus()['progress']) == 100
def test_good_code_invalid_msg_script(self): cmd = [ os.path.join(self.scriptDir, 'test2.sh'), 'good_code_invalid_msg' ] LOG.debug('cmd = %s' % cmd) testExec = ExecThread(self.threadMgr, cmd) testExec.setTimeout(10) testExec.setProgressTimeout(10) testExec.start() tm = time.time() while (int(testExec.getStatus()['progress']) != 100 and tm + 20 > time.time()): pass self.printStatus(testExec.getStatus()) assert int(testExec.getStatus()['httpStatus']) == 200 assert testExec.getStatus()['result'] == None assert testExec.getStatus()['error'] == None assert testExec.getStatus()['errorMsg'] == None
def test_random_script(self): if (os.name == 'nt'): #ls.exe as a part of cygwin cmd = ['ls.exe', '/tmp'] else: cmd = ['ls', '/tmp'] LOG.debug('cmd = %s' % cmd) testExec = ExecThread(self.threadMgr, cmd) testExec.setTimeout(10) testExec.setProgressTimeout(10) testExec.start() tm = time.time() while (int(testExec.getStatus()['progress']) != 100 and tm + 20 > time.time()): pass self.printStatus(testExec.getStatus()) assert int(testExec.getStatus()['httpStatus']) == 200 assert testExec.getStatus()['result'] == None assert testExec.getStatus()['error'] == None assert testExec.getStatus()['errorMsg'] == None
def test_nonending_script(self): cmd = os.path.join(self.scriptDir, 'test.sh') LOG.debug('cmd = %s' % cmd) testExec = ExecThread(self.threadMgr, cmd) testExec.setTimeout(1) testExec.setProgressTimeout(10) testExec.start() # make sure the script is running tm = time.time() while (testExec.getCmdPid() == None and tm + 15 > time.time()): pass assert testExec.getCmdPid() != None tm = time.time() while (int(testExec.getStatus()['httpStatus']) != 500 and tm + 20 > time.time()): pass self.printStatus(testExec.getStatus()) assert int(testExec.getStatus()['httpStatus']) == 500 assert testExec.getStatus()['error'] == Errors.AGENT_THREAD_TIMEDOUT
pkgName = 'test' forcePackages = None exist = ((forcePackages is not None) and (pkgName in forcePackages)) print exist import re pkgSuffix = re.sub(r"\W", "", "mymanifest-1.0.0") print pkgSuffix for _ in range(3): print 3 ** (1+_) print int(time.time()) % 2 response = json.loads(ERROR) isValid = ExecThread.validateResponse(response) errorMsgRe = re.compile('.*errorMsg\".*:.*\"(.*)\"}') match = errorMsgRe.match(ERROR) if (match != None): errorMsg = match.group(1) errorlines = ERROR.split('\n') errorjoin = None ethread = ExecThread(NullThreadMgr, 'agent') for line in errorlines: ethread.processExecResponse(line) line = line.rstrip('\n') errorjoin = line if not errorjoin else (errorjoin + '\\n' + line) threadjson = ethread.getResponse()
def test_good_code_invalid_msg_script(self): cmd = [os.path.join(self.scriptDir, 'test2.sh'), 'good_code_invalid_msg'] LOG.debug('cmd = %s' % cmd) testExec = ExecThread(self.threadMgr, cmd) testExec.setTimeout(10) testExec.setProgressTimeout(10) testExec.start() tm = time.time() while (int(testExec.getStatus()['progress']) != 100 and tm + 20 > time.time()): pass self.printStatus(testExec.getStatus()) assert int(testExec.getStatus()['httpStatus']) == 200 assert testExec.getStatus()['result'] == None assert testExec.getStatus()['error'] == None assert testExec.getStatus()['errorMsg'] == None
def executeScript(self): """ execute a script from remote location""" scriptpath = None try: # parse the body if (not request.body or request.body == ""): LOG.error('invalid body found in post command') return errorResult(request, response, 10001, 'No body found in post command', controller = self) body = json.loads(request.body.encode('ascii', 'ignore')) scriptloc = body['scriptLocation'] if 'scriptLocation' in body else None scriptname = body['scriptName'] if 'scriptName' in body else None hasSudo = ('sudoUser' in body and body['sudoUser']) sudoUser = body['sudoUser'] if ('sudoUser' in body and body['sudoUser'] != 'root') else None paramobj = body['params'] if 'params' in body else [] params = paramobj if type(paramobj) == list else paramobj.split() LOG.info('%s %s %s %s %s' % (scriptloc, scriptname, hasSudo, sudoUser, params)) if not scriptloc: return errorResult(request, response, Errors.INVALID_REQUEST, 'Script location not found', controller = self) if not scriptname: return errorResult(request, response, Errors.INVALID_REQUEST, 'Script name not found', controller = self) scriptpath = os.path.join(self.dataPath(), scriptname) LOG.info('scriptpath = %s' % scriptpath) utils.runsyscmd('wget %s -O %s' % (scriptloc, scriptpath)) if not os.path.exists(scriptpath): return errorResult(request, response, Errors.FILE_NOT_FOUND_ERROR, 'Failed to get script %s' % scriptpath, controller = self) utils.rchmod(scriptpath, '+rx') cmd = [scriptpath] if hasSudo: cmd.insert(0, 'sudo') if sudoUser: cmd.insert(1, sudoUser) cmd.insert(1, '-u') for param in params: cmd.append(param) LOG.info('cmd = %s' % cmd) appGlobal = config['pylons.app_globals'] execThread = ExecThread(appGlobal.threadMgr, cmd) execThread.setLogLevel('info') contextutils.copyJobContexts(self, execThread) execThread.start() execThread.threadMgrEvent.wait() return statusResult(request, response, execThread, controller = self) except Exception as excp: return errorResult(request, response, error = Errors.UNKNOWN_ERROR, errorMsg = 'Unknown error when executing cmd %s, %s - %s' % (scriptpath, str(excp), traceback.format_exc(2)), controller = self)
pkgName = 'test' forcePackages = None exist = ((forcePackages is not None) and (pkgName in forcePackages)) print exist import re pkgSuffix = re.sub(r"\W", "", "mymanifest-1.0.0") print pkgSuffix for _ in range(3): print 3**(1 + _) print int(time.time()) % 2 response = json.loads(ERROR) isValid = ExecThread.validateResponse(response) errorMsgRe = re.compile('.*errorMsg\".*:.*\"(.*)\"}') match = errorMsgRe.match(ERROR) if (match != None): errorMsg = match.group(1) errorlines = ERROR.split('\n') errorjoin = None ethread = ExecThread(NullThreadMgr, 'agent') for line in errorlines: ethread.processExecResponse(line) line = line.rstrip('\n') errorjoin = line if not errorjoin else (errorjoin + '\\n' + line) threadjson = ethread.getResponse()