You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mesos.apache.org by mp...@apache.org on 2016/01/15 18:59:54 UTC
[4/4] mesos git commit: Updated `Master::Http::state` to use
`jsonify` in mesos.
Updated `Master::Http::state` to use `jsonify` in mesos.
Review: https://reviews.apache.org/r/41595/
Project: http://git-wip-us.apache.org/repos/asf/mesos/repo
Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/e8af5cca
Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/e8af5cca
Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/e8af5cca
Branch: refs/heads/master
Commit: e8af5cca9bbc7e0ab96749e42b584c09554b2347
Parents: 69188c5
Author: Michael Park <mp...@apache.org>
Authored: Tue Dec 8 09:25:43 2015 -0500
Committer: Michael Park <mp...@apache.org>
Committed: Fri Jan 15 09:37:47 2016 -0800
----------------------------------------------------------------------
src/common/http.cpp | 184 +++++++++++++++++++++++
src/common/http.hpp | 10 ++
src/master/http.cpp | 381 +++++++++++++++++++++++++++++++++--------------
3 files changed, 467 insertions(+), 108 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/mesos/blob/e8af5cca/src/common/http.cpp
----------------------------------------------------------------------
diff --git a/src/common/http.cpp b/src/common/http.cpp
index 7165551..6d88091 100644
--- a/src/common/http.cpp
+++ b/src/common/http.cpp
@@ -396,5 +396,189 @@ JSON::Object model(
return object;
}
+
+void json(JSON::ObjectWriter* writer, const Task& task)
+{
+ writer->field("id", task.task_id().value());
+ writer->field("name", task.name());
+ writer->field("framework_id", task.framework_id().value());
+ writer->field("executor_id", task.executor_id().value());
+ writer->field("slave_id", task.slave_id().value());
+ writer->field("state", TaskState_Name(task.state()));
+ writer->field("resources", Resources(task.resources()));
+ writer->field("statuses", task.statuses());
+
+ if (task.has_labels()) {
+ writer->field("labels", task.labels());
+ }
+
+ if (task.has_discovery()) {
+ writer->field("discovery", task.discovery());
+ }
+
+ if (task.has_container()) {
+ writer->field("container", task.container());
+ }
+}
+
} // namespace internal {
+
+void json(JSON::ObjectWriter* writer, const Attributes& attributes)
+{
+ foreach (const Attribute& attribute, attributes) {
+ switch (attribute.type()) {
+ case Value::SCALAR:
+ writer->field(attribute.name(), attribute.scalar());
+ break;
+ case Value::RANGES:
+ writer->field(attribute.name(), attribute.ranges());
+ break;
+ case Value::SET:
+ writer->field(attribute.name(), attribute.set());
+ break;
+ case Value::TEXT:
+ writer->field(attribute.name(), attribute.text());
+ break;
+ default:
+ LOG(FATAL) << "Unexpected Value type: " << attribute.type();
+ }
+ }
+}
+
+
+void json(JSON::ObjectWriter* writer, const CommandInfo& command)
+{
+ if (command.has_shell()) {
+ writer->field("shell", command.shell());
+ }
+
+ if (command.has_value()) {
+ writer->field("value", command.value());
+ }
+
+ writer->field("argv", command.arguments());
+
+ if (command.has_environment()) {
+ writer->field("environment", command.environment());
+ }
+
+ writer->field("uris", [&command](JSON::ArrayWriter* writer) {
+ foreach (const CommandInfo::URI& uri, command.uris()) {
+ writer->element([&uri](JSON::ObjectWriter* writer) {
+ writer->field("value", uri.value());
+ writer->field("executable", uri.executable());
+ });
+ }
+ });
+}
+
+
+void json(JSON::ObjectWriter* writer, const ExecutorInfo& executorInfo)
+{
+ writer->field("executor_id", executorInfo.executor_id().value());
+ writer->field("name", executorInfo.name());
+ writer->field("framework_id", executorInfo.framework_id().value());
+ writer->field("command", executorInfo.command());
+ writer->field("resources", Resources(executorInfo.resources()));
+}
+
+
+void json(JSON::ArrayWriter* writer, const Labels& labels)
+{
+ json(writer, labels.labels());
+}
+
+
+void json(JSON::ObjectWriter* writer, const NetworkInfo& info)
+{
+ if (info.has_ip_address()) {
+ writer->field("ip_address", info.ip_address());
+ }
+
+ if (info.groups().size() > 0) {
+ writer->field("groups", info.groups());
+ }
+
+ if (info.has_labels()) {
+ writer->field("labels", info.labels());
+ }
+
+ if (info.ip_addresses().size() > 0) {
+ writer->field("ip_addresses", info.ip_addresses());
+ }
+}
+
+
+void json(JSON::ObjectWriter* writer, const Resources& resources)
+{
+ hashmap<std::string, double> scalars = {{"cpus", 0}, {"mem", 0}, {"disk", 0}};
+ hashmap<std::string, Value::Ranges> ranges;
+ hashmap<std::string, Value::Set> sets;
+
+ foreach (const Resource& resource, resources) {
+ std::string name =
+ resource.name() + (Resources::isRevocable(resource) ? "_revocable" : "");
+ switch (resource.type()) {
+ case Value::SCALAR:
+ scalars[name] += resource.scalar().value();
+ break;
+ case Value::RANGES:
+ ranges[name] += resource.ranges();
+ break;
+ case Value::SET:
+ sets[name] += resource.set();
+ break;
+ default:
+ LOG(FATAL) << "Unexpected Value type: " << resource.type();
+ }
+ }
+
+ json(writer, scalars);
+ json(writer, ranges);
+ json(writer, sets);
+}
+
+
+void json(JSON::ObjectWriter* writer, const TaskStatus& status)
+{
+ writer->field("state", TaskState_Name(status.state()));
+ writer->field("timestamp", status.timestamp());
+
+ if (status.has_labels()) {
+ writer->field("labels", status.labels());
+ }
+
+ if (status.has_container_status()) {
+ writer->field("container_status", status.container_status());
+ }
+
+ if (status.has_healthy()) {
+ writer->field("healthy", status.healthy());
+ }
+}
+
+
+void json(JSON::NumberWriter* writer, const Value::Scalar& scalar)
+{
+ writer->set(scalar.value());
+}
+
+
+void json(JSON::StringWriter* writer, const Value::Ranges& ranges)
+{
+ writer->append(stringify(ranges));
+}
+
+
+void json(JSON::StringWriter* writer, const Value::Set& set)
+{
+ writer->append(stringify(set));
+}
+
+
+void json(JSON::StringWriter* writer, const Value::Text& text)
+{
+ writer->append(text.value());
+}
+
} // namespace mesos {
http://git-wip-us.apache.org/repos/asf/mesos/blob/e8af5cca/src/common/http.hpp
----------------------------------------------------------------------
diff --git a/src/common/http.hpp b/src/common/http.hpp
index 4f4cbf6..f88590f 100644
--- a/src/common/http.hpp
+++ b/src/common/http.hpp
@@ -24,6 +24,7 @@
#include <stout/hashmap.hpp>
#include <stout/json.hpp>
+#include <stout/jsonify.hpp>
#include <stout/protobuf.hpp>
namespace mesos {
@@ -88,7 +89,16 @@ JSON::Object model(
const TaskState& state,
const std::vector<TaskStatus>& statuses);
+
+void json(JSON::ObjectWriter* writer, const Task& task);
+
} // namespace internal {
+
+void json(JSON::ObjectWriter* writer, const Attributes& attributes);
+void json(JSON::ArrayWriter* writer, const Labels& labels);
+void json(JSON::ObjectWriter* writer, const Resources& resources);
+void json(JSON::ObjectWriter* writer, const TaskStatus& status);
+
} // namespace mesos {
#endif // __COMMON_HTTP_HPP__
http://git-wip-us.apache.org/repos/asf/mesos/blob/e8af5cca/src/master/http.cpp
----------------------------------------------------------------------
diff --git a/src/master/http.cpp b/src/master/http.cpp
index bcafc7a..e6ba311 100644
--- a/src/master/http.cpp
+++ b/src/master/http.cpp
@@ -42,12 +42,14 @@
#include <stout/hashmap.hpp>
#include <stout/hashset.hpp>
#include <stout/json.hpp>
+#include <stout/jsonify.hpp>
#include <stout/lambda.hpp>
#include <stout/net.hpp>
#include <stout/nothing.hpp>
#include <stout/numify.hpp>
#include <stout/os.hpp>
#include <stout/protobuf.hpp>
+#include <stout/representation.hpp>
#include <stout/result.hpp>
#include <stout/strings.hpp>
#include <stout/try.hpp>
@@ -103,6 +105,22 @@ using std::vector;
namespace mesos {
+
+void json(
+ JSON::StringWriter* writer, const FrameworkInfo::Capability& capability)
+{
+ writer->append(FrameworkInfo::Capability::Type_Name(capability.type()));
+}
+
+
+void json(JSON::ObjectWriter* writer, const Offer& offer)
+{
+ writer->field("id", offer.id().value());
+ writer->field("framework_id", offer.framework_id().value());
+ writer->field("slave_id", offer.slave_id().value());
+ writer->field("resources", Resources(offer.resources()));
+}
+
namespace internal {
namespace master {
@@ -115,6 +133,177 @@ using process::http::Request;
using process::Owned;
+// The summary representation of `T` to support the `/state-summary` endpoint.
+// e.g., `Summary<Slave>`.
+template <typename T>
+struct Summary : Representation<T>
+{
+ using Representation<T>::Representation;
+};
+
+
+// The full representation of `T` to support the `/state` endpoint.
+// e.g., `Full<Slave>`.
+template <typename T>
+struct Full : Representation<T>
+{
+ using Representation<T>::Representation;
+};
+
+
+void json(JSON::ObjectWriter* writer, const Summary<Slave>& summary)
+{
+ const Slave& slave = summary;
+
+ writer->field("id", slave.id.value());
+ writer->field("pid", string(slave.pid));
+ writer->field("hostname", slave.info.hostname());
+ writer->field("registered_time", slave.registeredTime.secs());
+
+ if (slave.reregisteredTime.isSome()) {
+ writer->field("reregistered_time", slave.reregisteredTime.get().secs());
+ }
+
+ const Resources& totalResources = slave.totalResources;
+ writer->field("resources", totalResources);
+ writer->field("used_resources", Resources::sum(slave.usedResources));
+ writer->field("offered_resources", slave.offeredResources);
+ writer->field("reserved_resources", totalResources.reserved());
+ writer->field("unreserved_resources", totalResources.unreserved());
+
+ writer->field("attributes", Attributes(slave.info.attributes()));
+ writer->field("active", slave.active);
+ writer->field("version", slave.version);
+}
+
+
+void json(JSON::ObjectWriter* writer, const Full<Slave>& full)
+{
+ const Slave& slave = full;
+
+ json(writer, Summary<Slave>(slave));
+}
+
+
+void json(JSON::ObjectWriter* writer, const Summary<Framework>& summary)
+{
+ const Framework& framework = summary;
+
+ writer->field("id", framework.id().value());
+ writer->field("name", framework.info.name());
+
+ // Omit pid for http frameworks.
+ if (framework.pid.isSome()) {
+ writer->field("pid", string(framework.pid.get()));
+ }
+
+ // TODO(bmahler): Use these in the webui.
+ writer->field("used_resources", framework.totalUsedResources);
+ writer->field("offered_resources", framework.totalOfferedResources);
+ writer->field("capabilities", framework.info.capabilities());
+ writer->field("hostname", framework.info.hostname());
+ writer->field("webui_url", framework.info.webui_url());
+ writer->field("active", framework.active);
+}
+
+
+void json(JSON::ObjectWriter* writer, const Full<Framework>& full)
+{
+ const Framework& framework = full;
+
+ json(writer, Summary<Framework>(framework));
+
+ // Add additional fields to those generated by 'summarize'.
+ writer->field("user", framework.info.user());
+ writer->field("failover_timeout", framework.info.failover_timeout());
+ writer->field("checkpoint", framework.info.checkpoint());
+ writer->field("role", framework.info.role());
+ writer->field("registered_time", framework.registeredTime.secs());
+ writer->field("unregistered_time", framework.unregisteredTime.secs());
+ writer->field("active", framework.active);
+
+ if (framework.info.has_principal()) {
+ writer->field("principal", framework.info.principal());
+ }
+
+ // TODO(bmahler): Consider deprecating this in favor of the split
+ // used and offered resources added in 'summarize'.
+ writer->field(
+ "resources",
+ framework.totalUsedResources + framework.totalOfferedResources);
+
+ // TODO(benh): Consider making reregisteredTime an Option.
+ if (framework.registeredTime != framework.reregisteredTime) {
+ writer->field("reregistered_time", framework.reregisteredTime.secs());
+ }
+
+ // Model all of the tasks associated with a framework.
+ writer->field("tasks", [&framework](JSON::ArrayWriter* writer) {
+ foreachvalue (const TaskInfo& taskInfo, framework.pendingTasks) {
+ writer->element([&framework, &taskInfo](JSON::ObjectWriter* writer) {
+ writer->field("id", taskInfo.task_id().value());
+ writer->field("name", taskInfo.name());
+ writer->field("framework_id", framework.id().value());
+
+ writer->field("executor_id", taskInfo.executor().executor_id().value());
+
+ writer->field("slave_id", taskInfo.slave_id().value());
+ writer->field("state", TaskState_Name(TASK_STAGING));
+ writer->field("resources", Resources(taskInfo.resources()));
+ writer->field("statuses", std::initializer_list<TaskStatus>{});
+
+ if (taskInfo.has_labels()) {
+ writer->field("labels", taskInfo.labels());
+ }
+
+ if (taskInfo.has_discovery()) {
+ writer->field("discovery", taskInfo.discovery());
+ }
+
+ if (taskInfo.has_container()) {
+ writer->field("container", taskInfo.container());
+ }
+ });
+ }
+
+ foreachvalue (Task* task, framework.tasks) {
+ writer->element(*task);
+ }
+ });
+
+ writer->field("completed_tasks", [&framework](JSON::ArrayWriter* writer) {
+ foreach (const std::shared_ptr<Task>& task, framework.completedTasks) {
+ writer->element(*task);
+ }
+ });
+
+ // Model all of the offers associated with a framework.
+ writer->field("offers", [&framework](JSON::ArrayWriter* writer) {
+ foreach (Offer* offer, framework.offers) {
+ writer->element(*offer);
+ }
+ });
+
+ // Model all of the executors of a framework.
+ writer->field("executors", [&framework](JSON::ArrayWriter* writer) {
+ foreachpair (
+ const SlaveID& slaveId, const auto& executorsMap, framework.executors) {
+ foreachvalue (const ExecutorInfo& executor, executorsMap) {
+ writer->element([&executor, &slaveId](JSON::ObjectWriter* writer) {
+ json(writer, executor);
+ writer->field("slave_id", slaveId.value());
+ });
+ }
+ }
+ });
+
+ // Model all of the labels associated with a framework.
+ if (framework.info.has_labels()) {
+ writer->field("labels", framework.info.labels());
+ }
+}
+
+
// TODO(bmahler): Kill these in favor of automatic Proto->JSON Conversion (when
// it becomes available).
@@ -1107,139 +1296,115 @@ string Master::Http::STATE_HELP()
Future<Response> Master::Http::state(const Request& request) const
{
- JSON::Object object;
- object.values["version"] = MESOS_VERSION;
+ auto state = [this](JSON::ObjectWriter* writer) {
+ writer->field("version", MESOS_VERSION);
- if (build::GIT_SHA.isSome()) {
- object.values["git_sha"] = build::GIT_SHA.get();
- }
-
- if (build::GIT_BRANCH.isSome()) {
- object.values["git_branch"] = build::GIT_BRANCH.get();
- }
-
- if (build::GIT_TAG.isSome()) {
- object.values["git_tag"] = build::GIT_TAG.get();
- }
-
- object.values["build_date"] = build::DATE;
- object.values["build_time"] = build::TIME;
- object.values["build_user"] = build::USER;
- object.values["start_time"] = master->startTime.secs();
-
- if (master->electedTime.isSome()) {
- object.values["elected_time"] = master->electedTime.get().secs();
- }
-
- object.values["id"] = master->info().id();
- object.values["pid"] = string(master->self());
- object.values["hostname"] = master->info().hostname();
- object.values["activated_slaves"] = master->_slaves_active();
- object.values["deactivated_slaves"] = master->_slaves_inactive();
-
- if (master->flags.cluster.isSome()) {
- object.values["cluster"] = master->flags.cluster.get();
- }
+ if (build::GIT_SHA.isSome()) {
+ writer->field("git_sha", build::GIT_SHA.get());
+ }
- if (master->leader.isSome()) {
- object.values["leader"] = master->leader.get().pid();
- }
+ if (build::GIT_BRANCH.isSome()) {
+ writer->field("git_branch", build::GIT_BRANCH.get());
+ }
- if (master->flags.log_dir.isSome()) {
- object.values["log_dir"] = master->flags.log_dir.get();
- }
+ if (build::GIT_TAG.isSome()) {
+ writer->field("git_tag", build::GIT_TAG.get());
+ }
- if (master->flags.external_log_file.isSome()) {
- object.values["external_log_file"] = master->flags.external_log_file.get();
- }
+ writer->field("build_date", build::DATE);
+ writer->field("build_time", build::TIME);
+ writer->field("build_user", build::USER);
+ writer->field("start_time", master->startTime.secs());
- {
- JSON::Object flags;
- foreachpair (const string& name, const flags::Flag& flag, master->flags) {
- Option<string> value = flag.stringify(master->flags);
- if (value.isSome()) {
- flags.values[name] = value.get();
- }
+ if (master->electedTime.isSome()) {
+ writer->field("elected_time", master->electedTime.get().secs());
}
- object.values["flags"] = std::move(flags);
- }
- // Model all of the slaves.
- {
- JSON::Array array;
- array.values.reserve(master->slaves.registered.size()); // MESOS-2353.
+ writer->field("id", master->info().id());
+ writer->field("pid", string(master->self()));
+ writer->field("hostname", master->info().hostname());
+ writer->field("activated_slaves", master->_slaves_active());
+ writer->field("deactivated_slaves", master->_slaves_inactive());
- foreachvalue (Slave* slave, master->slaves.registered) {
- array.values.push_back(model(*slave));
+ if (master->flags.cluster.isSome()) {
+ writer->field("cluster", master->flags.cluster.get());
}
- object.values["slaves"] = std::move(array);
- }
-
- // Model all of the frameworks.
- {
- JSON::Array array;
- array.values.reserve(master->frameworks.registered.size()); // MESOS-2353.
+ if (master->leader.isSome()) {
+ writer->field("leader", master->leader.get().pid());
+ }
- foreachvalue (Framework* framework, master->frameworks.registered) {
- array.values.push_back(model(*framework));
+ if (master->flags.log_dir.isSome()) {
+ writer->field("log_dir", master->flags.log_dir.get());
}
- object.values["frameworks"] = std::move(array);
- }
+ if (master->flags.external_log_file.isSome()) {
+ writer->field("external_log_file", master->flags.external_log_file.get());
+ }
- // Model all of the completed frameworks.
- {
- JSON::Array array;
- array.values.reserve(master->frameworks.completed.size()); // MESOS-2353.
+ writer->field("flags", [this](JSON::ObjectWriter* writer) {
+ foreachpair (const string& name, const flags::Flag& flag, master->flags) {
+ Option<string> value = flag.stringify(master->flags);
+ if (value.isSome()) {
+ writer->field(name, value.get());
+ }
+ }
+ });
- foreach (const std::shared_ptr<Framework>& framework,
- master->frameworks.completed) {
- array.values.push_back(model(*framework));
- }
+ // Model all of the slaves.
+ writer->field("slaves", [this](JSON::ArrayWriter* writer) {
+ foreachvalue (Slave* slave, master->slaves.registered) {
+ writer->element(Full<Slave>(*slave));
+ }
+ });
- object.values["completed_frameworks"] = std::move(array);
- }
+ // Model all of the frameworks.
+ writer->field("frameworks", [this](JSON::ArrayWriter* writer) {
+ foreachvalue (Framework* framework, master->frameworks.registered) {
+ writer->element(Full<Framework>(*framework));
+ }
+ });
- // Model all of the orphan tasks.
- {
- JSON::Array array;
+ // Model all of the completed frameworks.
+ writer->field("completed_frameworks", [this](JSON::ArrayWriter* writer) {
+ foreach (const std::shared_ptr<Framework>& framework,
+ master->frameworks.completed) {
+ writer->element(Full<Framework>(*framework));
+ }
+ });
- // Find those orphan tasks.
- foreachvalue (const Slave* slave, master->slaves.registered) {
- typedef hashmap<TaskID, Task*> TaskMap;
- foreachvalue (const TaskMap& tasks, slave->tasks) {
- foreachvalue (const Task* task, tasks) {
- CHECK_NOTNULL(task);
- if (!master->frameworks.registered.contains(task->framework_id())) {
- array.values.push_back(model(*task));
+ // Model all of the orphan tasks.
+ writer->field("orphan_tasks", [this](JSON::ArrayWriter* writer) {
+ // Find those orphan tasks.
+ foreachvalue (const Slave* slave, master->slaves.registered) {
+ typedef hashmap<TaskID, Task*> TaskMap;
+ foreachvalue (const TaskMap& tasks, slave->tasks) {
+ foreachvalue (const Task* task, tasks) {
+ CHECK_NOTNULL(task);
+ if (!master->frameworks.registered.contains(task->framework_id())) {
+ writer->element(*task);
+ }
}
}
}
- }
-
- object.values["orphan_tasks"] = std::move(array);
- }
-
- // Model all currently unregistered frameworks.
- // This could happen when the framework has yet to re-register
- // after master failover.
- {
- JSON::Array array;
+ });
- // Find unregistered frameworks.
- foreachvalue (const Slave* slave, master->slaves.registered) {
- foreachkey (const FrameworkID& frameworkId, slave->tasks) {
- if (!master->frameworks.registered.contains(frameworkId)) {
- array.values.push_back(frameworkId.value());
+ // Model all currently unregistered frameworks.
+ // This could happen when the framework has yet to re-register
+ // after master failover.
+ writer->field("unregistered_frameworks", [this](JSON::ArrayWriter* writer) {
+ // Find unregistered frameworks.
+ foreachvalue (const Slave* slave, master->slaves.registered) {
+ foreachkey (const FrameworkID& frameworkId, slave->tasks) {
+ if (!master->frameworks.registered.contains(frameworkId)) {
+ writer->element(frameworkId.value());
+ }
}
}
- }
-
- object.values["unregistered_frameworks"] = std::move(array);
- }
+ });
+ };
- return OK(object, request.url.query.get("jsonp"));
+ return OK(jsonify(state), request.url.query.get("jsonp"));
}