def kill_running_process(): """Find and kill any running web service processes.""" global service_name try: pid = get_pid(service_name) except IOError: # We could not find an existing pidfile. return except ValueError: # The file contained a mangled and invalid PID number, so we should # clean the file up. safe_unlink(pidfile_path(service_name)) else: if pid is not None: try: os.kill(pid, signal.SIGTERM) # We need to use a busy-wait to find out when the socket # becomes available. Failing to do so causes a race condition # between freeing the socket in the killed process, and # opening it in the current one. wait_for_service_shutdown() except os.error as err: if err.errno == errno.ESRCH: # Whoops, we got a 'No such process' error. The PID file # is probably stale, so we'll remove it to prevent trash # from lying around in the test environment. # See bug #237086. safe_unlink(pidfile_path(service_name)) else: raise
def launch(self): self.pre_launch() pidfile = pidfile_path(self.name) logfile = config[self.section_name].logfile tacfile = make_abspath(self.tac_filename) args = [ tachandler.twistd_script, "--no_save", "--nodaemon", "--python", tacfile, "--pidfile", pidfile, "--prefix", self.name.capitalize(), "--logfile", logfile, ] if config[self.section_name].spew: args.append("--spew") # Note that startup tracebacks and evil programmers using 'print' will # cause output to our stdout. However, we don't want to have twisted # log to stdout and redirect it ourselves because we then lose the # ability to cycle the log files by sending a signal to the twisted # process. process = subprocess.Popen(args, stdin=subprocess.PIPE) self.addCleanup(stop_process, process) process.stdin.close()
def init(self, parser, opts, args): top = os.path.abspath( os.path.join(os.path.dirname(__file__), os.pardir, os.pardir)) listen_host = config.codebrowse.listen_host log_folder = config.codebrowse.log_folder or os.path.join(top, "logs") if not os.path.exists(log_folder): os.makedirs(log_folder) cfg = { "accesslog": os.path.join(log_folder, "access.log"), "bind": [ "%s:%s" % (listen_host, config.codebrowse.port), "%s:%s" % (listen_host, config.codebrowse.private_port), ], "capture_output": True, "errorlog": os.path.join(log_folder, "debug.log"), # Trust that firewalls only permit sending requests to # loggerhead via a frontend. "forwarded_allow_ips": "*", "logger_class": "launchpad_loggerhead.wsgi.LoggerheadLogger", "loglevel": "debug", "on_starting": _on_starting_hook, "pidfile": pidfile_path("codebrowse"), "preload_app": True, # XXX cjwatson 2018-05-15: These are gunicorn defaults plus # X-Forwarded-Scheme: https, which we use in staging/production. # We should switch the staging/production configuration to # something that gunicorn understands natively and then drop # this. "secure_scheme_headers": { "X-FORWARDED-PROTOCOL": "ssl", "X-FORWARDED-PROTO": "https", "X-FORWARDED-SCHEME": "https", "X-FORWARDED-SSL": "on", }, # Kill threads after 300 seconds of inactivity. This is # insanely high, but loggerhead is often pretty slow. "timeout": 300, "threads": 10, "worker_class": "gthread", } cfg.update(self.options) return cfg
def test_stopAppServer(self): # Test that stopping the app server kills the process and remove the # PID file. LayerProcessController.setConfig() LayerProcessController.startAppServer() pid = LayerProcessController.appserver.pid pid_file = pidfile_path('launchpad', LayerProcessController.appserver_config) LayerProcessController.stopAppServer() self.assertRaises(OSError, os.kill, pid, 0) self.failIf(os.path.exists(pid_file), "PID file wasn't removed") self.failUnless(LayerProcessController.appserver is None, "appserver class attribute wasn't reset")
def test_stale_pid_file_cleanup(self): """The service should be able to clean up invalid PID files.""" bogus_pid = 9999999 self.failIf(process_exists(bogus_pid), "There is already a process with PID '%d'." % bogus_pid) # Create a stale/bogus PID file. filepath = pidfile_path(googletestservice.service_name) pidfile = file(filepath, 'w') pidfile.write(str(bogus_pid)) pidfile.close() # The PID clean-up code should silently remove the file and return. googletestservice.kill_running_process() self.failIf(os.path.exists(filepath), "The PID file '%s' should have been deleted." % filepath)
def start_librarian(): """Start the Librarian in the background.""" # Create the ZCML override file based on the instance. config.generate_overrides() # Create the Librarian storage directory if it doesn't already exist. prepare_for_librarian() pidfile = pidfile_path('librarian') cmd = [ tachandler.twistd_script, "--python", 'daemons/librarian.tac', "--pidfile", pidfile, "--prefix", 'Librarian', "--logfile", config.librarian_server.logfile, ] return subprocess.call(cmd)
def _setUp(self): pidfile = pidfile_path( "codebrowse", use_config=LayerProcessController.appserver_config) pid = get_pid_from_file(pidfile) if pid is not None: warnings.warn( "Attempt to start LoggerheadFixture with an existing " "instance (%d) running in %s." % (pid, pidfile)) kill_by_pidfile(pidfile) self.logfile = os.path.join(config.codebrowse.log_folder, "debug.log") remove_if_exists(self.logfile) self.addCleanup(kill_by_pidfile, pidfile) run_script( os.path.join("scripts", "start-loggerhead.py"), ["--daemon"], # The testrunner-appserver config provides the correct # openid_provider_root URL. extra_env={"LPCONFIG": BaseLayer.appserver_config_name}) self._waitForStartup()
def main(): parser = OptionParser('Usage: %prog [options] [SERVICE ...]') parser.add_option("-w", "--wait", metavar="SECS", default=20, type="int", help="Wait up to SECS seconds for processes " "to die before retrying with SIGKILL") logger_options(parser, logging.INFO) (options, args) = parser.parse_args() log = logger(options) if len(args) < 1: parser.error('No service name provided') pids = [] # List of pids we tried to kill. services = args[:] # Mailman is special, but only stop it if it was launched. if 'mailman' in services: if config.mailman.launch: stop_mailman() services.remove('mailman') for service in services: log.debug("PID file is %s", pidfile_path(service)) try: pid = get_pid(service) except ValueError as error: log.error(error) continue if pid is not None: log.info("Killing %s (%d)", service, pid) try: os.kill(pid, SIGTERM) pids.append((service, pid)) except OSError as x: log.error("Unable to SIGTERM %s (%d) - %s", service, pid, x.strerror) else: log.debug("No PID file for %s", service) wait_for_pids(pids, options.wait, log) # Anything that didn't die, kill harder with SIGKILL. for service, pid in pids: if not process_exists(pid): continue log.warn("SIGTERM failed to kill %s (%d). Trying SIGKILL", service, pid) try: os.kill(pid, SIGKILL) except OSError as x: log.error("Unable to SIGKILL %s (%d) - %s", service, pid, x.strerror) wait_for_pids(pids, options.wait, log) # Report anything still left running after a SIGKILL. for service, pid in pids: if process_exists(pid): log.error("SIGKILL didn't terminate %s (%d)", service, pid) # Remove any pidfiles that didn't get cleaned up if there is no # corresponding process (from an unkillable process, or maybe some # other job has relaunched it while we were not looking). for service in services: pid = get_pid(service) if pid is not None and not process_exists(pid): try: remove_pidfile(service) except OSError: pass
def main(): parser = OptionParser('Usage: %prog [options] [SERVICE ...]') parser.add_option("-w", "--wait", metavar="SECS", default=20, type="int", help="Wait up to SECS seconds for processes " "to die before retrying with SIGKILL") logger_options(parser, logging.INFO) (options, args) = parser.parse_args() log = logger(options) if len(args) < 1: parser.error('No service name provided') pids = [] # List of pids we tried to kill. services = args[:] # Mailman is special, but only stop it if it was launched. if 'mailman' in services: if config.mailman.launch: stop_mailman() services.remove('mailman') for service in services: log.debug("PID file is %s", pidfile_path(service)) try: pid = get_pid(service) except ValueError as error: log.error(error) continue if pid is not None: log.info("Killing %s (%d)", service, pid) try: os.kill(pid, SIGTERM) pids.append((service, pid)) except OSError as x: log.error( "Unable to SIGTERM %s (%d) - %s", service, pid, x.strerror) else: log.debug("No PID file for %s", service) wait_for_pids(pids, options.wait, log) # Anything that didn't die, kill harder with SIGKILL. for service, pid in pids: if not process_exists(pid): continue log.warn( "SIGTERM failed to kill %s (%d). Trying SIGKILL", service, pid) try: os.kill(pid, SIGKILL) except OSError as x: log.error( "Unable to SIGKILL %s (%d) - %s", service, pid, x.strerror) wait_for_pids(pids, options.wait, log) # Report anything still left running after a SIGKILL. for service, pid in pids: if process_exists(pid): log.error("SIGKILL didn't terminate %s (%d)", service, pid) # Remove any pidfiles that didn't get cleaned up if there is no # corresponding process (from an unkillable process, or maybe some # other job has relaunched it while we were not looking). for service in services: pid = get_pid(service) if pid is not None and not process_exists(pid): try: remove_pidfile(service) except OSError: pass