コード例 #1
0
ファイル: daemon_pants_runner.py プロジェクト: mabdi3/pants
    def create(cls, sock, args, env, services, scheduler_service):
        maybe_shutdown_socket = MaybeShutdownSocket(sock)

        try:
            # N.B. This will redirect stdio in the daemon's context to the nailgun session.
            with cls.nailgunned_stdio(maybe_shutdown_socket,
                                      env,
                                      handle_stdin=False) as finalizer:
                options, _, options_bootstrapper = LocalPantsRunner.parse_options(
                    args, env)
                subprocess_dir = options.for_global_scope().pants_subprocessdir
                graph_helper, target_roots, exit_code = scheduler_service.prefork(
                    options, options_bootstrapper)
                finalizer()
        except Exception:
            graph_helper = None
            target_roots = None
            options_bootstrapper = None
            # TODO: this should no longer be necessary, remove the creation of subprocess_dir
            subprocess_dir = os.path.join(get_buildroot(), '.pids')
            exit_code = 1
            # TODO This used to raise the _GracefulTerminationException, and maybe it should again, or notify in some way that the prefork has failed.

        return cls(maybe_shutdown_socket, args, env, graph_helper,
                   target_roots, services, subprocess_dir,
                   options_bootstrapper, exit_code)
コード例 #2
0
 def create(cls, sock, args, env, services, scheduler_service):
     return cls(maybe_shutdown_socket=MaybeShutdownSocket(sock),
                args=args,
                env=env,
                services=services,
                exit_code=0,
                scheduler_service=scheduler_service)
コード例 #3
0
 def test_handle_error(self):
     self.handler.handle_error()
     maybe_shutdown_socket = MaybeShutdownSocket(self.client_sock)
     last_chunk_type, last_payload = list(
         NailgunProtocol.iter_chunks(maybe_shutdown_socket))[-1]
     self.assertEqual(last_chunk_type, ChunkType.EXIT)
     self.assertEqual(last_payload, '1')
コード例 #4
0
ファイル: nailgun_client.py プロジェクト: zvikihouzz/pants
  def _process_session(self):
    """Process the outputs of the nailgun session.

    :raises: :class:`NailgunProtocol.ProcessStreamTimeout` if a timeout set from a signal handler
                                                           with .set_exit_timeout() completes.
    :raises: :class:`Exception` if the session completes before the timeout, the `reason` argument
                                to .set_exit_timeout() will be raised."""
    try:
      for chunk_type, payload in self.iter_chunks(
        MaybeShutdownSocket(self._sock),
        return_bytes=True,
        timeout_object=self,
      ):
        # TODO(#6579): assert that we have at this point received all the chunk types in
        # ChunkType.REQUEST_TYPES, then require PID and PGRP (exactly once?), and then allow any of
        # ChunkType.EXECUTION_TYPES.
        if chunk_type == ChunkType.STDOUT:
          self._write_flush(self._stdout, payload)
        elif chunk_type == ChunkType.STDERR:
          self._write_flush(self._stderr, payload)
        elif chunk_type == ChunkType.EXIT:
          self._write_flush(self._stdout)
          self._write_flush(self._stderr)
          return int(payload)
        elif chunk_type == ChunkType.PID:
          self.remote_pid = int(payload)
          self.remote_process_cmdline = psutil.Process(self.remote_pid).cmdline()
          if self._remote_pid_callback:
            self._remote_pid_callback(self.remote_pid)
        elif chunk_type == ChunkType.PGRP:
          self.remote_pgrp = int(payload)
          if self._remote_pgrp_callback:
            self._remote_pgrp_callback(self.remote_pgrp)
        elif chunk_type == ChunkType.START_READING_INPUT:
          self._maybe_start_input_writer()
        else:
          raise self.ProtocolError('received unexpected chunk {} -> {}'.format(chunk_type, payload))
    except NailgunProtocol.ProcessStreamTimeout as e:
      assert(self.remote_pid is not None)
      # NB: We overwrite the process title in the pantsd process, which causes it to have an
      # argv with lots of empty spaces for some reason. We filter those out and pretty-print the
      # rest here.
      filtered_remote_cmdline = safe_shlex_join(
        arg for arg in self.remote_process_cmdline if arg != '')
      logger.warning(
        "timed out when attempting to gracefully shut down the remote client executing \"{}\". "
        "sending SIGKILL to the remote client at pid: {}. message: {}"
        .format(filtered_remote_cmdline, self.remote_pid, e))
    finally:
      # Bad chunk types received from the server can throw NailgunProtocol.ProtocolError in
      # NailgunProtocol.iter_chunks(). This ensures the NailgunStreamWriter is always stopped.
      self._maybe_stop_input_writer()
      # If an asynchronous error was set at any point (such as in a signal handler), we want to make
      # sure we clean up the remote process before exiting with error.
      if self._exit_reason:
        if self.remote_pgrp:
          safe_kill(self.remote_pgrp, signal.SIGKILL)
        if self.remote_pid:
          safe_kill(self.remote_pid, signal.SIGKILL)
        raise self._exit_reason
コード例 #5
0
    def test_iter_chunks(self):
        expected_chunks = [
            (ChunkType.COMMAND, self.TEST_COMMAND),
            (ChunkType.STDOUT, self.TEST_OUTPUT),
            (ChunkType.STDERR, self.TEST_OUTPUT),
            (ChunkType.EXIT, self.EMPTY_PAYLOAD)
            # N.B. without an EXIT chunk here (or socket failure), this test will deadlock in iter_chunks.
        ]

        for chunk_type, payload in expected_chunks:
            NailgunProtocol.write_chunk(self.server_sock, chunk_type, payload)

        for i, chunk in enumerate(
                NailgunProtocol.iter_chunks(
                    MaybeShutdownSocket(self.client_sock))):
            self.assertEqual(chunk, expected_chunks[i])
コード例 #6
0
ファイル: nailgun_client.py プロジェクト: matze999/pants
    def _process_session(self):
        """Process the outputs of the nailgun session.

        :raises: :class:`NailgunProtocol.ProcessStreamTimeout` if a timeout set from a signal handler
                                                               with .set_exit_timeout() completes.
        :raises: :class:`Exception` if the session completes before the timeout, the `reason` argument
                                    to .set_exit_timeout() will be raised.
        """
        try:
            for chunk_type, payload in self.iter_chunks(
                    MaybeShutdownSocket(self._sock),
                    return_bytes=True,
                    timeout_object=self,
            ):
                # TODO(#6579): assert that we have at this point received all the chunk types in
                # ChunkType.REQUEST_TYPES, and then allow any of ChunkType.EXECUTION_TYPES.
                if chunk_type == ChunkType.STDOUT:
                    self._write_flush(self._stdout, payload)
                elif chunk_type == ChunkType.STDERR:
                    self._write_flush(self._stderr, payload)
                elif chunk_type == ChunkType.EXIT:
                    self._write_flush(self._stdout)
                    self._write_flush(self._stderr)
                    return int(payload)
                elif chunk_type == ChunkType.START_READING_INPUT:
                    self._maybe_start_input_writer()
                else:
                    raise self.ProtocolError(
                        "received unexpected chunk {} -> {}".format(
                            chunk_type, payload))
        except NailgunProtocol.ProcessStreamTimeout as e:
            logger.warning(
                "timed out when attempting to gracefully shut down the remote run. Sending SIGKILL"
                "message: {}".format(e))
        finally:
            # Bad chunk types received from the server can throw NailgunProtocol.ProtocolError in
            # NailgunProtocol.iter_chunks(). This ensures the NailgunStreamWriter is always stopped.
            self._maybe_stop_input_writer()
            # If an asynchronous error was set at any point (such as in a signal handler), we want to make
            # sure we clean up the remote process before exiting with error.
            if self._exit_reason:
                raise self._exit_reason
コード例 #7
0
  def create(cls, sock, args, env, services, scheduler_service):
    maybe_shutdown_socket = MaybeShutdownSocket(sock)
    exception = None
    exit_code = PANTS_SUCCEEDED_EXIT_CODE

    # TODO(#8002) This can probably be moved to the try:except block in DaemonPantsRunner.run() function,
    #             Making exception handling a lot easier.
    try:
      # N.B. This will redirect stdio in the daemon's context to the nailgun session.
      with cls.nailgunned_stdio(maybe_shutdown_socket, env, handle_stdin=False) as finalizer:
        options, _, options_bootstrapper = LocalPantsRunner.parse_options(args, env)
        subprocess_dir = options.for_global_scope().pants_subprocessdir
        graph_helper, target_roots, exit_code = scheduler_service.prefork(options, options_bootstrapper)
        finalizer()
    except Exception as e:
      graph_helper = None
      target_roots = None
      options_bootstrapper = None
      # TODO: this should no longer be necessary, remove the creation of subprocess_dir
      subprocess_dir = os.path.join(get_buildroot(), '.pids')
      exception = _PantsProductPrecomputeFailed(e)

    # NB: If a scheduler_service.prefork finishes with a non-0 exit code but doesn't raise an exception
    # (e.g. ./pants list-and-die-for-testing ...). We still want to know about it.
    if exception is None and exit_code != PANTS_SUCCEEDED_EXIT_CODE:
      exception = _PantsProductPrecomputeFailed(
        _PantsRunFinishedWithFailureException(exit_code=exit_code)
      )

    return cls(
      maybe_shutdown_socket,
      args,
      env,
      graph_helper,
      target_roots,
      services,
      subprocess_dir,
      options_bootstrapper,
      exception
    )