def check_pidfile(kill_other=False, scan_proc=True): """ Check to see if there's already a pidfile. If so, check to see if the indicated process is alive and is Hubble. kill_other Default false, if set to true, attempt to kill detected running Hubble processes; otherwise exit with an error. """ pidfile_path = __opts__['pidfile'] if os.path.isfile(pidfile_path): with open(pidfile_path, 'r') as pidfile: xpid = pidfile.readline().strip() try: xpid = int(xpid) except (TypeError, ValueError): xpid = 0 log.warn('unable to parse pid="%d" in pidfile=%s', xpid, pidfile_path) if xpid: log.warn('pidfile=%s exists and contains pid=%d', pidfile_path, xpid) kill_other_or_sys_exit(xpid, kill_other=kill_other) if scan_proc: scan_proc_for_hubbles(kill_other=kill_other)
def check_pidfile(kill_other=False, scan_proc=True): ''' Check to see if there's already a pidfile. If so, check to see if the indicated process is alive and is Hubble. kill_other Default false, if set to true, attempt to kill detected running Hubble processes; otherwise exit with an error. ''' pidfile = __opts__['pidfile'] if os.path.isfile(pidfile): with open(pidfile, 'r') as f: xpid = f.readline().strip() try: xpid = int(xpid) except: xpid = 0 log.warn( 'unable to parse pid="{pid}" in pidfile={file}'.format( pid=xpid, file=pidfile)) if xpid: log.warn('pidfile={file} exists and contains pid={pid}'.format( file=pidfile, pid=xpid)) kill_other_or_sys_exit(xpid, kill_other=kill_other) if scan_proc: scan_proc_for_hubbles(kill_other=kill_other)
def kill_other_or_sys_exit(xpid, hname=r'hubble', ksig=signal.SIGTERM, kill_other=True, no_pgrp=True): """ Attempt to locate other hubbles using a cmdline regular expression and kill them when found. If killing the other processes fails (or kill_other is False), sys.exit instead. params: hname :- the regular expression pattern to use to locate hubble (default: hubble) ksig :- the signal to use to kill the other processes (default: signal.SIGTERM=15) kill_other :- (default: True); when false, don't attempt to kill, just locate and exit (if found) no_pgrp :- Avoid killing processes in this pgrp (avoid suicide). When no_pgrp is True, invoke os.getprgp() to populate the actual value. caveats: There are some detailed notes on the process scanning in the function as comments. The most important caveat is that the hname regular expressions must match expecting that /proc/$$/cmdline text is null separated, not space separated. The other main caveat is that we can't actually examine the /proc/$$/exe file (that's always just a python). We have to scan the invocation text the kernel stored at launch. That text is not immutable and should not (normally) be relied upon for any purpose -- and this method does rely on it. """ if no_pgrp is True: no_pgrp = os.getpgrp() if isinstance(no_pgrp, int): no_pgrp = str(no_pgrp) if os.path.isdir("/proc/{pid}".format(pid=xpid)): # NOTE: we'd prefer to check readlink(/proc/[pid]/exe), but that won't do # any good the /opt/whatever/bin/hubble is normally a text file with a # shebang; which the kernel picks up and uses to execute the real binary # with the "bin" file as an argument; so we'll have to live with cmdline pfile = '/proc/{pid}/cmdline'.format(pid=xpid) log.debug('searching %s for hubble procs matching %s', pfile, hname) with open(pfile, 'r') as pidfile: # NOTE: cmdline is actually null separated, not space separated # that shouldn't matter much for most hname regular expressions, but one never knows. cmdline = pidfile.readline().replace('\x00', ' ').strip() if re.search(hname, cmdline): if no_pgrp: pstatfile = '/proc/{pid}/stat'.format(pid=xpid) with open(pstatfile, 'r') as fh2: # NOTE: man proc(5) § /proc/[pid]/stat # (pid, comm, state, ppid, pgrp, session, tty_nr, tpgid, flags, ...) pgrp = fh2.readline().split()[4] if pgrp == no_pgrp: log.debug( "process (%s) exists and seems to be a hubble, " "but matches our process group (%s), ignoring", xpid, pgrp) return False if kill_other: log.warn( "process seems to still be alive and seems to be hubble," " attempting to shutdown") os.kill(int(xpid), ksig) time.sleep(1) if os.path.isdir("/proc/{pid}".format(pid=xpid)): log.error( "fatal error: failed to shutdown process (pid=%s) successfully", xpid) sys.exit(1) else: return True else: log.error( "refusing to run while another hubble instance is running") sys.exit(1) else: # pidfile present, but nothing at that pid. Did we receive a sigterm? log.warning( 'Pidfile found on startup, but no process at that pid. Did hubble receive a SIGTERM?' ) return False