Repository: mesos
Updated Branches:
  refs/heads/master a2f734498 -> 0b2853d1b


Updated Frameworkinfo.capabilities on framework re-registration to
support adding capabilities.

This updates both the master as well as the allocator. Added test for
master.

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


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

Branch: refs/heads/master
Commit: 0b2853d1bd59f9120c77c96f6fc208680fe1c19d
Parents: a2f7344
Author: Aditi Dixit <[email protected]>
Authored: Mon Jul 27 17:07:55 2015 -0700
Committer: Vinod Kone <[email protected]>
Committed: Mon Jul 27 17:10:33 2015 -0700

----------------------------------------------------------------------
 src/master/allocator/mesos/hierarchical.hpp |   7 ++
 src/master/master.hpp                       |   7 ++
 src/tests/fault_tolerance_tests.cpp         | 132 +++++++++++++++++++++++
 3 files changed, 146 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/0b2853d1/src/master/allocator/mesos/hierarchical.hpp
----------------------------------------------------------------------
diff --git a/src/master/allocator/mesos/hierarchical.hpp 
b/src/master/allocator/mesos/hierarchical.hpp
index d374e84..e278139 100644
--- a/src/master/allocator/mesos/hierarchical.hpp
+++ b/src/master/allocator/mesos/hierarchical.hpp
@@ -491,6 +491,13 @@ HierarchicalAllocatorProcess<RoleSorter, 
FrameworkSorter>::updateFramework(
   // these fields to be updated.
   CHECK_EQ(frameworks[frameworkId].role, frameworkInfo.role());
   CHECK_EQ(frameworks[frameworkId].checkpoint, frameworkInfo.checkpoint());
+
+  foreach (const FrameworkInfo::Capability& capability,
+           frameworkInfo.capabilities()) {
+    if (capability.type() == FrameworkInfo::Capability::REVOCABLE_RESOURCES) {
+      frameworks[frameworkId].revocable = true;
+    }
+  }
 }
 
 

http://git-wip-us.apache.org/repos/asf/mesos/blob/0b2853d1/src/master/master.hpp
----------------------------------------------------------------------
diff --git a/src/master/master.hpp b/src/master/master.hpp
index 9f27f8b..2c924ad 100644
--- a/src/master/master.hpp
+++ b/src/master/master.hpp
@@ -1411,6 +1411,13 @@ struct Framework
     } else {
       info.clear_webui_url();
     }
+
+    // TODO(aditidixit): Add the case where the capabilities are
+    // previously set but now being unset. (MESOS-2880)
+
+    if (source.capabilities_size() > 0) {
+      info.mutable_capabilities()->CopyFrom(source.capabilities());
+    }
   }
 
   FrameworkInfo info;

http://git-wip-us.apache.org/repos/asf/mesos/blob/0b2853d1/src/tests/fault_tolerance_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/fault_tolerance_tests.cpp 
b/src/tests/fault_tolerance_tests.cpp
index 9288718..7b977f5 100644
--- a/src/tests/fault_tolerance_tests.cpp
+++ b/src/tests/fault_tolerance_tests.cpp
@@ -1814,6 +1814,138 @@ TEST_F(FaultToleranceTest, SplitBrainMasters)
   Shutdown();
 }
 
+// This test verifies that when a framework re-registers with updated
+// FrameworkInfo, it gets updated in the master. The steps involved
+// are:
+//   1. Launch a master, slave and scheduler.
+//   2. Record FrameworkID of launched scheduler.
+//   3. Launch a second scheduler which has the same FrameworkID as
+//      the first scheduler and also has updated FrameworkInfo.
+//   4. Verify that the state of the master is updated with the new
+//      FrameworkInfo object.
+TEST_F(FaultToleranceTest, UpdateFrameworkInfoOnSchedulerFailover)
+{
+  Try<PID<Master> > master = StartMaster();
+  ASSERT_SOME(master);
+
+  Try<PID<Slave> > slave = StartSlave();
+  ASSERT_SOME(slave);
+
+  // Launch the first (i.e., failing) scheduler and wait until
+  // 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);
+
+  MockScheduler sched1;
+  MesosSchedulerDriver driver1(
+      &sched1, framework1, master.get(), DEFAULT_CREDENTIAL);
+
+  Future<FrameworkID> frameworkId;
+  EXPECT_CALL(sched1, registered(&driver1, _, _))
+    .WillOnce(FutureArg<1>(&frameworkId));
+
+  EXPECT_CALL(sched1, resourceOffers(&driver1, _))
+    .WillRepeatedly(Return());
+
+  driver1.start();
+
+  AWAIT_READY(frameworkId);
+
+  // Now launch the second (i.e., failover) scheduler using the
+  // framework id recorded from the first scheduler, along with the
+  // updated FrameworkInfo and wait until it gets a registered
+  // callback.
+
+  MockScheduler sched2;
+
+  FrameworkInfo framework2 = DEFAULT_FRAMEWORK_INFO;
+  framework2.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");
+
+  MesosSchedulerDriver driver2(
+      &sched2, framework2, master.get(), DEFAULT_CREDENTIAL);
+
+  Future<Nothing> sched2Registered;
+  EXPECT_CALL(sched2, registered(&driver2, frameworkId.get(), _))
+    .WillOnce(FutureSatisfy(&sched2Registered));
+
+  EXPECT_CALL(sched2, resourceOffers(&driver2, _))
+    .WillRepeatedly(Return());
+
+  EXPECT_CALL(sched2, offerRescinded(&driver2, _))
+    .Times(AtMost(1));
+
+  // Scheduler1's expectations.
+  EXPECT_CALL(sched1, offerRescinded(&driver1, _))
+    .Times(AtMost(1));
+
+  Future<Nothing> sched1Error;
+  EXPECT_CALL(sched1, error(&driver1, "Framework failed over"))
+    .WillOnce(FutureSatisfy(&sched1Error));
+
+  driver2.start();
+
+  AWAIT_READY(sched2Registered);
+
+  AWAIT_READY(sched1Error);
+
+  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);
+
+  JSON::Object state = parse.get();
+  EXPECT_EQ(1u, state.values.count("frameworks"));
+  JSON::Array frameworks =
+    state.values["frameworks"].as<JSON::Array>();
+  EXPECT_EQ(1u, frameworks.values.size());
+  JSON::Object framework = frameworks.values.front().as<JSON::Object>();
+
+  EXPECT_EQ(1u, framework.values.count("name"));
+  JSON::String name = framework.values["name"].as<JSON::String>();
+  EXPECT_EQ(framework2.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(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(1u, framework.values.count("hostname"));
+  JSON::String hostname = framework.values["hostname"].as<JSON::String>();
+  EXPECT_EQ(framework2.hostname(), hostname.value);
+
+  EXPECT_EQ(1u, framework.values.count("capabilities"));
+  JSON::Array capabilities =
+    framework.values["capabilities"].as<JSON::Array>();
+  EXPECT_EQ(1u, capabilities.values.size());
+  JSON::String capability = capabilities.values.front().as<JSON::String>();
+  EXPECT_EQ(FrameworkInfo::Capability::Type_Name(capabilityType),
+            capability.value);
+
+  EXPECT_EQ(DRIVER_STOPPED, driver2.stop());
+  EXPECT_EQ(DRIVER_STOPPED, driver2.join());
+
+  EXPECT_EQ(DRIVER_ABORTED, driver1.stop());
+  EXPECT_EQ(DRIVER_STOPPED, driver1.join());
+
+  Shutdown();
+}
+
 } // namespace tests {
 } // namespace internal {
 } // namespace mesos {

Reply via email to