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(®istered)); + + 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 {
