예제 #1
0
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 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
예제 #3
0
    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()
예제 #4
0
    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")
예제 #6
0
 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 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)
예제 #9
0
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)
예제 #10
0
 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()
예제 #11
0
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
예제 #12
0
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