X-Git-Url: https://code.grnet.gr/git/ganeti-local/blobdiff_plain/b330ac0b2ed0425805c2849ba11b83924ab958c0..8161a64679c5b3c46a275bc3ae8e13b69c902993:/lib/utils.py diff --git a/lib/utils.py b/lib/utils.py index e900352..23fd1eb 100644 --- a/lib/utils.py +++ b/lib/utils.py @@ -74,13 +74,13 @@ class RunResult(object): "failed", "fail_reason", "cmd"] - def __init__(self, exit_code, signal, stdout, stderr, cmd): + def __init__(self, exit_code, signal_, stdout, stderr, cmd): self.cmd = cmd self.exit_code = exit_code - self.signal = signal + self.signal = signal_ self.stdout = stdout self.stderr = stderr - self.failed = (signal is not None or exit_code != 0) + self.failed = (signal_ is not None or exit_code != 0) if self.signal is not None: self.fail_reason = "terminated by signal %s" % self.signal @@ -168,12 +168,12 @@ def RunCmd(cmd): status = child.wait() if status >= 0: exitcode = status - signal = None + signal_ = None else: exitcode = None - signal = -status + signal_ = -status - return RunResult(exitcode, signal, out, err, strcmd) + return RunResult(exitcode, signal_, out, err, strcmd) def RemoveFile(filename): @@ -268,9 +268,13 @@ def IsProcessAlive(pid): Returns: true or false, depending on if the pid exists or not - Remarks: zombie processes treated as not alive + Remarks: zombie processes treated as not alive, and giving a pid <= + 0 makes the function to return False. """ + if pid <= 0: + return False + try: f = open("/proc/%d/status" % pid) except IOError, err: @@ -290,29 +294,30 @@ def IsProcessAlive(pid): return alive -def IsPidFileAlive(pidfile): - """Check whether the given pidfile points to a live process. +def ReadPidFile(pidfile): + """Read the pid from a file. - @param pidfile: Path to a file containing the pid to be checked - @type pidfile: string (filename) + @param pidfile: Path to a file containing the pid to be checked + @type pidfile: string (filename) + @return: The process id, if the file exista and contains a valid PID, + otherwise 0 + @rtype: int """ try: pf = open(pidfile, 'r') - except EnvironmentError, open_err: - if open_err.errno == errno.ENOENT: - return False - else: - raise errors.GenericError("Cannot open file %s. Error: %s" % - (pidfile, str(open_err))) + except EnvironmentError, err: + if err.errno != errno.ENOENT: + logging.exception("Can't read pid file?!") + return 0 try: pid = int(pf.read()) - except ValueError: - raise errors.GenericError("Invalid pid string in %s" % - (pidfile,)) + except ValueError, err: + logging.info("Can't parse pid file contents", exc_info=True) + return 0 - return IsProcessAlive(pid) + return pid def MatchNameComponent(key, name_list): @@ -1051,7 +1056,7 @@ def Daemonize(logfile, noclose_fds=None): return 0 -def _DaemonPidFileName(name): +def DaemonPidFileName(name): """Compute a ganeti pid file absolute path, given the daemon name. """ @@ -1065,9 +1070,9 @@ def WritePidFile(name): """ pid = os.getpid() - pidfilename = _DaemonPidFileName(name) - if IsPidFileAlive(pidfilename): - raise GenericError("%s contains a live process" % pidfilename) + pidfilename = DaemonPidFileName(name) + if IsProcessAlive(ReadPidFile(pidfilename)): + raise errors.GenericError("%s contains a live process" % pidfilename) WriteFile(pidfilename, data="%d\n" % pid) @@ -1079,7 +1084,7 @@ def RemovePidFile(name): """ pid = os.getpid() - pidfilename = _DaemonPidFileName(name) + pidfilename = DaemonPidFileName(name) # TODO: we could check here that the file contains our pid try: RemoveFile(pidfilename) @@ -1087,6 +1092,35 @@ def RemovePidFile(name): pass +def KillProcess(pid, signal_=signal.SIGTERM, timeout=30): + """Kill a process given by its pid. + + @type pid: int + @param pid: The PID to terminate. + @type signal_: int + @param signal_: The signal to send, by default SIGTERM + @type timeout: int + @param timeout: The timeout after which, if the process is still alive, + a SIGKILL will be sent. If not positive, no such checking + will be done + + """ + if pid <= 0: + # kill with pid=0 == suicide + raise errors.ProgrammerError("Invalid pid given '%s'" % pid) + + if not IsProcessAlive(pid): + return + os.kill(pid, signal_) + if timeout <= 0: + return + end = time.time() + timeout + while time.time() < end and IsProcessAlive(pid): + time.sleep(0.1) + if IsProcessAlive(pid): + os.kill(pid, signal.SIGKILL) + + def FindFile(name, search_path, test=os.path.exists): """Look for a filesystem object in a given path.