def createExpandFile(self): ''' determine if this is an expand node, and if so, generate a temp file (descriptor) to hold the results, otherwise return None ''' # # Tractor supports the extension that "Cmd -expand x" # can specify a filename explictly that the launched # command is known to write to, or it can be a number # (0 or 1) as in classic alfred scripts. # f = None if type(self.expands) in (str, unicode): # filename (string) given as -expand arg s = self.expands.strip() if len(s): try: f = open(s, "wb") except: pass if f: trSetNoInherit( f ) self.expandfile = s elif self.expands > 0: # "classic" usage: -expand 1 s = "trxJ%sT%sC%s.%s." % (self.jid, self.tid, self.cid, self.rev) try: fd = tempfile.mkstemp(prefix=s, suffix=".xalf") f = os.fdopen(fd[0], 'w') trSetNoInherit( f ) self.expandfile = fd[1] except: pass return f
def __init__(self, cmd): # # Some subprocess module parameters are not supported on all # platforms, so we we create our own member variables and apply # the settings selectively in _execute_child. For example, # on unix we'd -like- to add the parameter 'close_fds=True' # to Popen. But the mere presence of the parameter raises an # error on windows. So rather than having multiple os-dependent # constructor lines here, we just set the parameter explicitly # in _execute_child below. Similarly, since the subprocess # module doesn't have an os-independent abstraction for login # impersonation, we must apply those settings in _execute_child # as well. # self.login = cmd.login self.pidIsProcessGroupLeader = False self._child_created = False # prevent __del__ errors if we fail self.launchTime = time.time() # stand-in, updated closer to launch fxpnd = cmd.createExpandFile() nrm = hasattr(cmd, 'sockDict') if nrm and 'stdio' in cmd.sockDict: sIn = cmd.sockDict['stdio'] if fxpnd: sOut = fxpnd elif 'err' in cmd.sockDict: sOut = cmd.sockDict['err'] else: sOut = cmd.sockDict['stdio'] sErr = subprocess.STDOUT self.closeFDs = False try: trSetInherit( cmd.sockDict['dspy'] ) trSetInherit( cmd.sockDict['file'] ) except: pass else: sIn = subprocess.PIPE sErr = subprocess.PIPE if fxpnd: sOut = fxpnd else: sOut = subprocess.PIPE self.closeFDs = True cmd.launchnote = "" cmd.guise = "" cmd.uid = 0 self.cmd = cmd if subprocess.mswindows: fullapp = cmd.argv[0] else: fullapp = None pid = subprocess.Popen.__init__(self, cmd.argv, bufsize=1, executable=fullapp, stdin=sIn, stdout=sOut, stderr=sErr, env=cmd.env, cwd=None) # ensure stray descriptors, especially netrender sockets, # can't be inherited by future execs if fxpnd: try: trSetNoInherit( fxpnd ) except: pass if nrm: for s in cmd.sockDict: try: trSetNoInherit( cmd.sockDict[s] ) except: pass return pid
def SaveOutput (self, txt, now=None, xbanner=""): if self.jid <= 0 and not self.altMode: self.logger.info("missing jid for logging") return try: isInternal = False if None == now: # this is a "system" message, generated by tractor, # not emitted by the cmd itself now = time.time() isInternal = True tm = time.strftime('%Y/%m/%d %H:%M:%S', time.localtime(now)) if isInternal: txt = "\n"+xbanner+"[" + tm + " " + txt + "]"+xbanner+"\n" if self.cmdtee and xbanner=="": self.logger.info("cmd output:\n\n" + txt) if self.altMode: return if self.logdir: # note that all cmds within the same task are # logged to the same (task) file # # fnm = "%s/J%s/T%s.log" % (self.logdir, self.jid, self.tid) # prior = False if not self.logfile: (type,_,loginfo) = self.cmdOutputLogging.partition("=") fnm = loginfo.replace("%u", self.login).replace("%j", str(self.jid)).replace("%t", str(self.tid)) prior = os.path.exists(fnm) self.logfile = open(fnm, "ab") trSetNoInherit( self.logfile ) if not self.hasEverLogged(): if prior: self.logfile.write("\n\n") # sep txt of nxt cmds self.logfile.write("====[%s %s on %s ]====\n\n" % (tm, self.logref, self.bladehost)) # mark this command as having generated output self.indicateLogging(now) self.logfile.write(txt) # don't self.logfile.close() for now, # leave open while cmd is running # ... but if you do close it, remember: self.logfile=None self.logfile.flush() # might consider this only once/sec elif self.tasklogger: # log modules are being served by the remote logger d={"user": self.login, "jid": self.jid, "tid": self.tid, "cid": self.cid, "rev": self.rev} if not self.hasEverLogged(): self.tasklogger.info("====[%s %s on %s ]====\n\n" % (tm, self.logref, self.bladehost), extra=d) # mark this command as having generated output self.indicateLogging(now) self.tasklogger.info(txt, extra=d) else: self.logger.error("no cmd output logging scheme defined!") except Exception: self.logger.error("cmd output logging failed: %s" % \ (self.logger.Xcpt()))