Example #1
0
string createSlaveDirectory(
    const string& rootDir,
    const SlaveID& slaveId)
{
  // `slaveId` should be valid because it's assigned by the master but
  // we do a sanity check here before using it to create a directory.
  CHECK_NONE(common::validation::validateSlaveID(slaveId));

  const string directory = getSlavePath(rootDir, slaveId);

  Try<Nothing> mkdir = os::mkdir(directory);

  CHECK_SOME(mkdir)
    << "Failed to create agent directory '" << directory << "'";

  // Remove the previous "latest" symlink.
  const string latest = getLatestSlavePath(rootDir);

  if (os::exists(latest)) {
    CHECK_SOME(os::rm(latest))
      << "Failed to remove latest symlink '" << latest << "'";
  }

  // Symlink the new slave directory to "latest".
  Try<Nothing> symlink = ::fs::symlink(directory, latest);

  CHECK_SOME(symlink)
    << "Failed to symlink directory '" << directory
    << "' to '" << latest << "'";

  return directory;
}
Example #2
0
Try<Option<Entry> > LevelDBStorageProcess::read(const string& name)
{
  CHECK_NONE(error);

  leveldb::ReadOptions options;

  string value;

  leveldb::Status status = db->Get(options, name, &value);

  if (status.IsNotFound()) {
    return None();
  } else if (!status.ok()) {
    return Error(status.ToString());
  }

  google::protobuf::io::ArrayInputStream stream(value.data(), value.size());

  Entry entry;

  if (!entry.ParseFromZeroCopyStream(&stream)) {
    return Error("Failed to deserialize Entry");
  }

  return Some(entry);
}
Example #3
0
string getPersistentVolumePath(
    const string& rootDir,
    const Resource& volume)
{
  CHECK(volume.has_role());
  CHECK(volume.has_disk());
  CHECK(volume.disk().has_persistence());

  // Additionally check that the role and the persistent ID are valid
  // before using them to construct a directory path.
  CHECK_NONE(roles::validate(volume.role()));
  CHECK_NONE(common::validation::validateID(volume.disk().persistence().id()));

  // If no `source` is provided in `DiskInfo` volumes are mapped into
  // the `rootDir`.
  if (!volume.disk().has_source()) {
    return getPersistentVolumePath(
        rootDir,
        volume.role(),
        volume.disk().persistence().id());
  }

  // If a `source` was provided for the volume, we map it according
  // to the `type` of disk. Currently only the `PATH` and 'MOUNT'
  // types are supported.
  if (volume.disk().source().type() == Resource::DiskInfo::Source::PATH) {
    // For `PATH` we mount a directory inside the `root`.
    CHECK(volume.disk().source().has_path());
    return getPersistentVolumePath(
        volume.disk().source().path().root(),
        volume.role(),
        volume.disk().persistence().id());
  } else if (
      volume.disk().source().type() == Resource::DiskInfo::Source::MOUNT) {
    // For `MOUNT` we map straight onto the root of the mount.
    CHECK(volume.disk().source().has_mount());
    return volume.disk().source().mount().root();
  }

  UNREACHABLE();
}
Example #4
0
    static int on_message_begin(http_parser* p)
    {
        StreamingResponseDecoder* decoder = (StreamingResponseDecoder*) p->data;

        CHECK(!decoder->failure);

        decoder->header = HEADER_FIELD;
        decoder->field.clear();
        decoder->value.clear();

        CHECK(decoder->response == NULL);
        CHECK_NONE(decoder->writer);

        decoder->response = new http::Response();
        decoder->response->type = http::Response::PIPE;
        decoder->writer = None();

        return 0;
    }
Example #5
0
Try<bool> LevelDBStorageProcess::write(const Entry& entry)
{
  CHECK_NONE(error);

  leveldb::WriteOptions options;
  options.sync = true;

  string value;

  if (!entry.SerializeToString(&value)) {
    return Error("Failed to serialize Entry");
  }

  leveldb::Status status = db->Put(options, entry.name(), value);

  if (!status.ok()) {
    return Error(status.ToString());
  }

  return true;
}
Example #6
0
    static int on_headers_complete(http_parser* p)
    {
        StreamingResponseDecoder* decoder = (StreamingResponseDecoder*) p->data;

        CHECK_NOTNULL(decoder->response);

        // Add final header.
        decoder->response->headers[decoder->field] = decoder->value;
        decoder->field.clear();
        decoder->value.clear();

        // Get the response status string.
        if (http::statuses.contains(decoder->parser.status_code)) {
            decoder->response->status = http::statuses[decoder->parser.status_code];
        } else {
            decoder->failure = true;
            return 1;
        }

        // We cannot provide streaming gzip decompression!
        Option<std::string> encoding =
            decoder->response->headers.get("Content-Encoding");
        if (encoding.isSome() && encoding.get() == "gzip") {
            decoder->failure = true;
            return 1;
        }

        CHECK_NONE(decoder->writer);

        http::Pipe pipe;
        decoder->writer = pipe.writer();
        decoder->response->reader = pipe.reader();

        // Send the response to the caller, but keep a Pipe::Writer for
        // streaming the body content into the response.
        decoder->responses.push_back(decoder->response);
        decoder->response = NULL;

        return 0;
    }
Example #7
0
void LeaderContenderProcess::joined()
{
  CHECK(!candidacy.isDiscarded());

  // Cannot be watching because the candidacy is not obtained yet.
  CHECK_NONE(watching);

  CHECK_SOME(contending);

  if (candidacy.isFailed()) {
    // The promise 'withdrawing' will be set to false in cancel().
    contending.get()->fail(candidacy.failure());
    return;
  }

  if (withdrawing.isSome()) {
    LOG(INFO) << "Joined group after the contender started withdrawing";

    // The promise 'withdrawing' will be set to 'false' in subsequent
    // 'cancel()' call.
    return;
  }

  LOG(INFO) << "New candidate (id='" << candidacy->id()
            << "') has entered the contest for leadership";

  // Transition to 'watching' state.
  watching = new Promise<Nothing>();

  // Notify the client.
  if (contending.get()->set(watching.get()->future())) {
    // Continue to watch that our membership is not removed (if the
    // client still cares about it).
    candidacy->cancelled()
      .onAny(defer(self(), &Self::cancelled, lambda::_1));
  }
}
Example #8
0
string createExecutorDirectory(
    const string& rootDir,
    const SlaveID& slaveId,
    const FrameworkID& frameworkId,
    const ExecutorID& executorId,
    const ContainerID& containerId,
    const Option<string>& user)
{
  // These IDs should be valid as they are either assigned by the
  // master/agent or validated by the master but we do a sanity check
  // here before using them to create a directory.
  CHECK_NONE(common::validation::validateSlaveID(slaveId));
  CHECK_NONE(common::validation::validateFrameworkID(frameworkId));
  CHECK_NONE(common::validation::validateExecutorID(executorId));
  CHECK_NONE(slave::validation::container::validateContainerId(containerId));

  const string directory =
    getExecutorRunPath(rootDir, slaveId, frameworkId, executorId, containerId);

  Try<Nothing> mkdir = os::mkdir(directory);

  CHECK_SOME(mkdir)
    << "Failed to create executor directory '" << directory << "'";

  // Remove the previous "latest" symlink.
  const string latest =
    getExecutorLatestRunPath(rootDir, slaveId, frameworkId, executorId);

  if (os::exists(latest)) {
    CHECK_SOME(os::rm(latest))
      << "Failed to remove latest symlink '" << latest << "'";
  }

  // Symlink the new executor directory to "latest".
  Try<Nothing> symlink = ::fs::symlink(directory, latest);

  CHECK_SOME(symlink)
    << "Failed to symlink directory '" << directory
    << "' to '" << latest << "'";

// `os::chown()` is not available on Windows.
#ifndef __WINDOWS__
  if (user.isSome()) {
    // Per MESOS-2592, we need to set the ownership of the executor
    // directory during its creation. We should not rely on subsequent
    // phases of the executor creation to ensure the ownership as
    // those may be conditional and in some cases leave the executor
    // directory owned by the slave user instead of the specified
    // framework or per-executor user.
    LOG(INFO) << "Trying to chown '" << directory << "' to user '"
              << user.get() << "'";
    Try<Nothing> chown = os::chown(user.get(), directory);
    if (chown.isError()) {
      // TODO(nnielsen): We currently have tests which depend on using
      // user names which may not be available on the test machines.
      // Therefore, we cannot make the chown validation a hard
      // CHECK().
      LOG(WARNING) << "Failed to chown executor directory '" << directory
                   << "'. This may be due to attempting to run the executor "
                   << "as a nonexistent user on the agent; see the description"
                   << " for the `--switch_user` flag for more information: "
                   << chown.error();
    }
  }
#endif // __WINDOWS__

  return directory;
}
  // Forwards the status update on the specified update stream.
  //
  // If `checkpoint` is `false`, the update will be retried as long as it is in
  // memory, but it will not be checkpointed.
  process::Future<Nothing> update(
      const UpdateType& update,
      const IDType& streamId,
      bool checkpoint)
  {
    LOG(INFO) << "Received " << statusUpdateType << " " << update;

    if (!streams.contains(streamId)) {
      Try<Nothing> create =
        createStatusUpdateStream(
            streamId,
            update.has_framework_id()
              ? Option<FrameworkID>(update.framework_id())
              : None(),
            checkpoint);

      if (create.isError()) {
        return process::Failure(create.error());
      }
    }
    CHECK(streams.contains(streamId));
    StatusUpdateStream* stream = streams[streamId].get();

    if (update.has_latest_status()) {
      return process::Failure(
          "Expected " + statusUpdateType + " to not contain 'latest_status'");
    }

    // Verify that we didn't get a non-checkpointable update for a
    // stream that is checkpointable, and vice-versa.
    if (stream->checkpointed() != checkpoint) {
      return process::Failure(
          "Mismatched checkpoint value for " + statusUpdateType + " " +
          stringify(update) + " (expected checkpoint=" +
          stringify(stream->checkpointed()) + " actual checkpoint=" +
          stringify(checkpoint) + ")");
    }

    // Verify that the framework ID of the update matches the framework ID
    // of the stream.
    if (update.has_framework_id() != stream->frameworkId.isSome()) {
      return process::Failure(
          "Mismatched framework ID for " + statusUpdateType +
          " " + stringify(update) + " (expected " +
          (stream->frameworkId.isSome()
             ? stringify(stream->frameworkId.get())
             : "no framework ID") +
          " got " +
          (update.has_framework_id()
             ? stringify(update.framework_id())
             : "no framework ID") +
          ")");
    }

    if (update.has_framework_id() &&
        update.framework_id() != stream->frameworkId.get()) {
      return process::Failure(
          "Mismatched framework ID for " + statusUpdateType +
          " " + stringify(update) +
          " (expected " + stringify(stream->frameworkId.get()) +
          " actual " + stringify(update.framework_id()) + ")");
    }

    // Handle the status update.
    Try<bool> result = stream->update(update);
    if (result.isError()) {
      return process::Failure(result.error());
    }

    // This only happens if the status update is a duplicate.
    if (!result.get()) {
      return Nothing();
    }

    // Forward the status update if this is at the front of the queue.
    // Subsequent status updates will be sent in `acknowledgement()`.
    if (!paused && stream->pending.size() == 1) {
      CHECK_NONE(stream->timeout);

      const Result<UpdateType>& next = stream->next();
      if (next.isError()) {
        return process::Failure(next.error());
      }

      CHECK_SOME(next);
      stream->timeout =
        forward(stream, next.get(), slave::STATUS_UPDATE_RETRY_INTERVAL_MIN);
    }

    return Nothing();
  }