Example #1
0
Future<bool> LeaderContenderProcess::withdraw()
{
  if (contending.isNone()) {
    // Nothing to withdraw because the contender has not contended.
    return false;
  }

  if (withdrawing.isSome()) {
    // Repeated calls to withdraw get the same result.
    return withdrawing.get();
  }

  withdrawing = new Promise<bool>();

  CHECK(!candidacy.isDiscarded());

  if (candidacy.isPending()) {
    // If we have not obtained the candidacy yet, we withdraw after
    // it is obtained.
    LOG(INFO) << "Withdraw requested before the candidacy is obtained; will "
              << "withdraw after it happens";
    candidacy.onAny(defer(self(), &Self::cancel));
  } else if (candidacy.isReady()) {
    cancel();
  } else {
    // We have failed to obtain the candidacy so we do not need to
    // cancel it.
    return false;
  }

  return withdrawing.get()->future();
}
Example #2
0
void HealthCheckerProcess::_healthCheck()
{
  Future<Nothing> checkResult;

  switch (check.type()) {
    case HealthCheck::COMMAND: {
      checkResult = _commandHealthCheck();
      break;
    }

    case HealthCheck::HTTP: {
      checkResult = _httpHealthCheck();
      break;
    }

    case HealthCheck::TCP: {
      checkResult = _tcpHealthCheck();
      break;
    }

    default: {
      UNREACHABLE();
    }
  }

  checkResult.onAny(defer(self(), &Self::__healthCheck, lambda::_1));
}
Example #3
0
void CheckerProcess::performCheck()
{
  if (paused) {
    return;
  }

  Stopwatch stopwatch;
  stopwatch.start();

  // There are 3 checks (CMD/HTTP/TCP) for 3 runtimes (PLAIN/DOCKER/NESTED)
  // for 2 different OSes (Linux/Windows), so we have a 3x3x2 matrix of
  // possibilities. Luckily, a lot of the cases have the same implementation,
  // so we don't need to have 18 different code paths.
  //
  // Here is a matrix of all the different implementations with explanations.
  // Note that the format is "Linux/Windows", so the Linux implementation is
  // before Windows if they differ.
  //
  //         | CMD  | HTTP | TCP
  // --------+------+------+-------
  //  Plain  | A*/A |  B   |  C
  //  Docker |  D   | B*/E | C*/F
  //  Nested |  G/- |  B   |  C
  //
  // Explanations:
  // - A, B, C: Standard check launched directly by the library's user, i.e.,
  //   the executor. Specifically, it launches the given command for CMD checks,
  //   `curl` for HTTP checks, and `mesos-tcp-connect` for TCP checks.
  // - A*, B*, C*: On Linux, the proper namespaces will be entered, which are
  //   the optional "mnt" for CMD and the required "net" for Docker HTTP/TCP.
  //   These checks are executed by the library's user, i.e., the executor.
  // - D: Delegate the command to Docker by wrapping the command with
  //   `docker exec` to run in the container's namespaces.
  // - E, F: On Windows, delegate the network checks to Docker by wrapping the
  //   check with the `docker run --network=container:id ...` command to
  //   run the check in the container's namespaces.
  // - G: The library uses Agent API to delegate running the command in a
  //   nested container on Linux.
  // - '-': Not implemented (nested command checks on Windows).
  check.visit(
      [=](const check::Command& cmd) {
        Future<int> future = runtime.visit(
            [=](const runtime::Plain& plain) {
              // Case A* and A
              return commandCheck(cmd, plain);
            },
            [=](const runtime::Docker& docker) {
              // Case D
              return dockerCommandCheck(cmd, docker);
            },
            [=](const runtime::Nested& nested) {
              // Case G
              return nestedCommandCheck(cmd, nested);
            });

        future.onAny(defer(
            self(), &Self::processCommandCheckResult, stopwatch, lambda::_1));
      },
      [=](const check::Http& http) {
        Future<int> future = runtime.visit(
            [=](const runtime::Plain& plain) {
              // Case B
              return httpCheck(http, plain);
            },
            [=](const runtime::Docker& docker) {
#ifdef __WINDOWS__
              // Case E
              return dockerHttpCheck(http, docker);
#else
              // Case B*
              return httpCheck(
                  http, runtime::Plain{docker.namespaces, docker.taskPid});
#endif // __WINDOWS__
            },
            [=](const runtime::Nested&) {
              // Case B
              return httpCheck(http, None());
            });

        future.onAny(defer(
            self(), &Self::processHttpCheckResult, stopwatch, lambda::_1));
      },
      [=](const check::Tcp& tcp) {
        Future<bool> future = runtime.visit(
            [=](const runtime::Plain& plain) {
              // Case C
              return tcpCheck(tcp, plain);
            },
            [=](const runtime::Docker& docker) {
#ifdef __WINDOWS__
              // Case F
              return dockerTcpCheck(tcp, docker);
#else
              // Case C*
              return tcpCheck(
                  tcp, runtime::Plain{docker.namespaces, docker.taskPid});
#endif // __WINDOWS__
            },
            [=](const runtime::Nested&) {
              // Case C
              return tcpCheck(tcp, None());
            });

        future.onAny(
            defer(self(), &Self::processTcpCheckResult, stopwatch, lambda::_1));
      });
}