Repository: mesos
Updated Branches:
  refs/heads/master d7e0c41df -> 482621ca4


Added "labels" to FrameworkInfo.

This is intended to support frameworks that want to offer capabilities to the
rest of the cluster (e.g., storage or some arbitrary third-party service). We
want processes running in the cluster to be able to discover these capabilities;
however, we don't want to commit to a fixed set of capabilities or how those
capabilities should be represented. Hence, this commit represents this
information using freeform key-value pairs, similar to the labels mechanism
already in use elsewhere.

Jira: MESOS-2841

Review: https://reviews.apache.org/r/37443


Project: http://git-wip-us.apache.org/repos/asf/mesos/repo
Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/482621ca
Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/482621ca
Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/482621ca

Branch: refs/heads/master
Commit: 482621ca43a0a24676bd7c4521f797b3216d4ad6
Parents: d7e0c41
Author: James DeFelice <[email protected]>
Authored: Fri Aug 14 14:45:03 2015 +0200
Committer: Bernd Mathiske <[email protected]>
Committed: Fri Aug 14 14:45:08 2015 +0200

----------------------------------------------------------------------
 include/mesos/mesos.proto           |  5 +++
 src/master/http.cpp                 | 12 +++++++
 src/master/master.hpp               | 10 ++++--
 src/tests/fault_tolerance_tests.cpp | 41 ++++++++++++++---------
 src/tests/master_tests.cpp          | 57 ++++++++++++++++++++++++++++++++
 5 files changed, 107 insertions(+), 18 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/482621ca/include/mesos/mesos.proto
----------------------------------------------------------------------
diff --git a/include/mesos/mesos.proto b/include/mesos/mesos.proto
index ea9c760..99b963b 100644
--- a/include/mesos/mesos.proto
+++ b/include/mesos/mesos.proto
@@ -186,6 +186,11 @@ message FrameworkInfo {
   // capabilities (e.g., ability to receive offers for revocable
   // resources).
   repeated Capability capabilities = 10;
+
+  // Labels are free-form key value pairs supplied by the framework
+  // scheduler (e.g., to describe additional functionality offered by
+  // the framework). These labels are not interpreted by Mesos itself.
+  optional Labels labels = 11;
 }
 
 

http://git-wip-us.apache.org/repos/asf/mesos/blob/482621ca/src/master/http.cpp
----------------------------------------------------------------------
diff --git a/src/master/http.cpp b/src/master/http.cpp
index 190248c..a73ee17 100644
--- a/src/master/http.cpp
+++ b/src/master/http.cpp
@@ -238,6 +238,18 @@ JSON::Object model(const Framework& framework)
     object.values["executors"] = std::move(executors);
   }
 
+  // Model all of the labels associated with a framework.
+  if (framework.info.has_labels()) {
+    JSON::Array array;
+    const mesos::Labels labels = framework.info.labels();
+    array.values.reserve(labels.labels_size());
+
+    foreach (const Label& label, labels.labels()) {
+      array.values.push_back(JSON::Protobuf(label));
+    }
+    object.values["labels"] = std::move(array);
+  }
+
   return object;
 }
 

http://git-wip-us.apache.org/repos/asf/mesos/blob/482621ca/src/master/master.hpp
----------------------------------------------------------------------
diff --git a/src/master/master.hpp b/src/master/master.hpp
index 1e12f65..0432842 100644
--- a/src/master/master.hpp
+++ b/src/master/master.hpp
@@ -1510,8 +1510,8 @@ struct Framework
   const FrameworkID id() const { return info.id(); }
 
   // Update fields in 'info' using those in 'source'. Currently this
-  // only updates 'name', 'failover_timeout', 'hostname', and
-  // 'webui_url'.
+  // only updates 'name', 'failover_timeout', 'hostname', 'webui_url',
+  // 'capabilities', and 'labels'.
   void updateFrameworkInfo(const FrameworkInfo& source)
   {
     // TODO(jmlvanre): We can't check 'FrameworkInfo.id' yet because
@@ -1569,6 +1569,12 @@ struct Framework
     if (source.capabilities_size() > 0) {
       info.mutable_capabilities()->CopyFrom(source.capabilities());
     }
+
+    if (source.has_labels()) {
+      info.mutable_labels()->CopyFrom(source.labels());
+    } else {
+      info.clear_labels();
+    }
   }
 
   void updateConnection(const process::UPID& newPid)

http://git-wip-us.apache.org/repos/asf/mesos/blob/482621ca/src/tests/fault_tolerance_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/fault_tolerance_tests.cpp 
b/src/tests/fault_tolerance_tests.cpp
index c63599a..89cb18b 100644
--- a/src/tests/fault_tolerance_tests.cpp
+++ b/src/tests/fault_tolerance_tests.cpp
@@ -1828,13 +1828,14 @@ TEST_F(FaultToleranceTest, 
UpdateFrameworkInfoOnSchedulerFailover)
   // registered gets called to launch the second (i.e., failover)
   // scheduler with updated information.
 
-  FrameworkInfo framework1 = DEFAULT_FRAMEWORK_INFO;
-  framework1.set_name("Framework 1");
-  framework1.set_failover_timeout(1000);
+  FrameworkInfo finfo1 = DEFAULT_FRAMEWORK_INFO;
+  finfo1.set_name("Framework 1");
+  finfo1.set_failover_timeout(1000);
+  finfo1.mutable_labels()->add_labels()->CopyFrom(createLabel("foo", "bar"));
 
   MockScheduler sched1;
   MesosSchedulerDriver driver1(
-      &sched1, framework1, master.get(), DEFAULT_CREDENTIAL);
+      &sched1, finfo1, master.get(), DEFAULT_CREDENTIAL);
 
   Future<FrameworkID> frameworkId;
   EXPECT_CALL(sched1, registered(&driver1, _, _))
@@ -1854,17 +1855,18 @@ TEST_F(FaultToleranceTest, 
UpdateFrameworkInfoOnSchedulerFailover)
 
   MockScheduler sched2;
 
-  FrameworkInfo framework2 = DEFAULT_FRAMEWORK_INFO;
-  framework2.mutable_id()->MergeFrom(frameworkId.get());
+  FrameworkInfo finfo2 = DEFAULT_FRAMEWORK_INFO;
+  finfo2.mutable_id()->MergeFrom(frameworkId.get());
   auto capabilityType = FrameworkInfo::Capability::REVOCABLE_RESOURCES;
-  framework2.add_capabilities()->set_type(capabilityType);
-  framework2.set_name("Framework 2");
-  framework2.set_webui_url("http://localhost:8080/";);
-  framework2.set_failover_timeout(100);
-  framework2.set_hostname("myHostname");
+  finfo2.add_capabilities()->set_type(capabilityType);
+  finfo2.set_name("Framework 2");
+  finfo2.set_webui_url("http://localhost:8080/";);
+  finfo2.set_failover_timeout(100);
+  finfo2.set_hostname("myHostname");
+  finfo2.mutable_labels()->add_labels()->CopyFrom(createLabel("baz", "qux"));
 
   MesosSchedulerDriver driver2(
-      &sched2, framework2, master.get(), DEFAULT_CREDENTIAL);
+      &sched2, finfo2, master.get(), DEFAULT_CREDENTIAL);
 
   Future<Nothing> sched2Registered;
   EXPECT_CALL(sched2, registered(&driver2, frameworkId.get(), _))
@@ -1907,20 +1909,20 @@ TEST_F(FaultToleranceTest, 
UpdateFrameworkInfoOnSchedulerFailover)
 
   EXPECT_EQ(1u, framework.values.count("name"));
   JSON::String name = framework.values["name"].as<JSON::String>();
-  EXPECT_EQ(framework2.name(), name.value);
+  EXPECT_EQ(finfo2.name(), name.value);
 
   EXPECT_EQ(1u, framework.values.count("webui_url"));
   JSON::String webuiUrl = framework.values["webui_url"].as<JSON::String>();
-  EXPECT_EQ(framework2.webui_url(), webuiUrl.value);
+  EXPECT_EQ(finfo2.webui_url(), webuiUrl.value);
 
   EXPECT_EQ(1u, framework.values.count("failover_timeout"));
   JSON::Number failoverTimeout =
     framework.values["failover_timeout"].as<JSON::Number>();
-  EXPECT_EQ(framework2.failover_timeout(), failoverTimeout.value);
+  EXPECT_EQ(finfo2.failover_timeout(), failoverTimeout.value);
 
   EXPECT_EQ(1u, framework.values.count("hostname"));
   JSON::String hostname = framework.values["hostname"].as<JSON::String>();
-  EXPECT_EQ(framework2.hostname(), hostname.value);
+  EXPECT_EQ(finfo2.hostname(), hostname.value);
 
   EXPECT_EQ(1u, framework.values.count("capabilities"));
   JSON::Array capabilities =
@@ -1930,6 +1932,13 @@ TEST_F(FaultToleranceTest, 
UpdateFrameworkInfoOnSchedulerFailover)
   EXPECT_EQ(FrameworkInfo::Capability::Type_Name(capabilityType),
             capability.value);
 
+  EXPECT_EQ(1u, framework.values.count("labels"));
+  JSON::Array labels = framework.values["labels"].as<JSON::Array>();
+
+  EXPECT_EQ(
+      JSON::Value(JSON::Protobuf(createLabel("baz", "qux"))),
+      labels.values[0]);
+
   EXPECT_EQ(DRIVER_STOPPED, driver2.stop());
   EXPECT_EQ(DRIVER_STOPPED, driver2.join());
 

http://git-wip-us.apache.org/repos/asf/mesos/blob/482621ca/src/tests/master_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/master_tests.cpp b/src/tests/master_tests.cpp
index a4703af..8a6b98b 100644
--- a/src/tests/master_tests.cpp
+++ b/src/tests/master_tests.cpp
@@ -3594,6 +3594,63 @@ TEST_F(MasterTest, MasterFailoverLongLivedExecutor)
   Shutdown(); // Must shutdown before 'containerizer' gets deallocated.
 }
 
+// This test ensures that if a framework scheduler provides any labels in its
+// FrameworkInfo message, those labels are included in the state.json endpoint.
+TEST_F(MasterTest, FrameworkInfoLabels)
+{
+  Try<PID<Master>> master = StartMaster();
+  ASSERT_SOME(master);
+
+  FrameworkInfo framework = DEFAULT_FRAMEWORK_INFO;
+
+  // Add three labels to the FrameworkInfo. Two labels share the same key.
+  framework.mutable_labels()->add_labels()->CopyFrom(createLabel("foo", 
"bar"));
+  framework.mutable_labels()->add_labels()->CopyFrom(createLabel("bar", 
"baz"));
+  framework.mutable_labels()->add_labels()->CopyFrom(createLabel("bar", 
"qux"));
+
+  MockScheduler sched;
+  MesosSchedulerDriver driver(
+      &sched, framework, master.get(), DEFAULT_CREDENTIAL);
+
+  Future<Nothing> registered;
+  EXPECT_CALL(sched, registered(&driver, _, _))
+    .WillOnce(FutureSatisfy(&registered));
+
+  driver.start();
+
+  AWAIT_READY(registered);
+
+  Future<process::http::Response> response =
+    process::http::get(master.get(), "state.json");
+  AWAIT_EXPECT_RESPONSE_STATUS_EQ(process::http::OK().status, response);
+
+  Try<JSON::Object> parse = JSON::parse<JSON::Object>(response.get().body);
+  ASSERT_SOME(parse);
+
+  Result<JSON::Array> labelsObject = parse.get().find<JSON::Array>(
+      "frameworks[0].labels");
+  EXPECT_SOME(labelsObject);
+
+  JSON::Array labelsObject_ = labelsObject.get();
+
+  EXPECT_EQ(
+      JSON::Value(JSON::Protobuf(createLabel("foo", "bar"))),
+      labelsObject_.values[0]);
+
+  EXPECT_EQ(
+      JSON::Value(JSON::Protobuf(createLabel("bar", "baz"))),
+      labelsObject_.values[1]);
+
+  EXPECT_EQ(
+      JSON::Value(JSON::Protobuf(createLabel("bar", "qux"))),
+      labelsObject_.values[2]);
+
+  driver.stop();
+  driver.join();
+
+  Shutdown();
+}
+
 } // namespace tests {
 } // namespace internal {
 } // namespace mesos {

Reply via email to