You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mesos.apache.org by be...@apache.org on 2014/10/26 02:44:14 UTC

[1/3] git commit: Mark running tasks killed during framework shutdown.

Repository: mesos
Updated Branches:
  refs/heads/master 169e969c9 -> 12e067419


Mark running tasks killed during framework shutdown.

When a framework is shut down e.g. by calling driver.stop() from the
scheduler, running tasks are marked KILLED before migrating them to
completed.

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


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

Branch: refs/heads/master
Commit: 12e06741911300d70ae6498119563634730d33af
Parents: 06bec4f
Author: Alexander Rukletsov <al...@mesosphere.io>
Authored: Sun Oct 12 15:05:02 2014 -0700
Committer: Benjamin Hindman <be...@gmail.com>
Committed: Sat Oct 25 16:57:40 2014 -0700

----------------------------------------------------------------------
 src/master/master.cpp      | 20 ++++++++++++++
 src/tests/master_tests.cpp | 61 +++++++++++++++++++++++++++++++++++------
 2 files changed, 72 insertions(+), 9 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/12e06741/src/master/master.cpp
----------------------------------------------------------------------
diff --git a/src/master/master.cpp b/src/master/master.cpp
index 9ebdc35..9491b22 100644
--- a/src/master/master.cpp
+++ b/src/master/master.cpp
@@ -4226,6 +4226,26 @@ void Master::removeFramework(Framework* framework)
       << "Unknown slave " << task->slave_id()
       << " for task " << task->task_id();
 
+    // The task is implicitly killed, and TASK_KILLED is the closest
+    // state we have by now. We mark the task and remove it, without
+    // sending the update. However, a task may finish during the
+    // executor graceful shutdown period. By marking such task as
+    // killed and moving it to completed, we lose the opportunity to
+    // collect the possible finished status. We tolerate this,
+    // because we expect that if the framework has been asked to shut
+    // down, its user is not interested in results anymore.
+    // TODO(alex): consider a more descrptive state, e.g. TASK_ABANDONED.
+    const StatusUpdate& update = protobuf::createStatusUpdate(
+        task->framework_id(),
+        task->slave_id(),
+        task->task_id(),
+        TASK_KILLED,
+        "Framework " + framework->id.value() + " removed",
+        (task->has_executor_id()
+         ? Option<ExecutorID>(task->executor_id())
+         : None()));
+
+    updateTask(task, update);
     removeTask(task);
   }
 

http://git-wip-us.apache.org/repos/asf/mesos/blob/12e06741/src/tests/master_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/master_tests.cpp b/src/tests/master_tests.cpp
index f60e376..2e52574 100644
--- a/src/tests/master_tests.cpp
+++ b/src/tests/master_tests.cpp
@@ -164,9 +164,12 @@ TEST_F(MasterTest, TaskRunning)
 }
 
 
+// This test ensures that stopping a scheduler driver triggers
+// executor's shutdown callback and all still running tasks are
+// marked as killed.
 TEST_F(MasterTest, ShutdownFrameworkWhileTaskRunning)
 {
-  Try<PID<Master> > master = StartMaster();
+  Try<PID<Master>> master = StartMaster();
   ASSERT_SOME(master);
 
   MockExecutor exec(DEFAULT_EXECUTOR_ID);
@@ -176,7 +179,7 @@ TEST_F(MasterTest, ShutdownFrameworkWhileTaskRunning)
   slave::Flags flags = CreateSlaveFlags();
   flags.executor_shutdown_grace_period = Seconds(0);
 
-  Try<PID<Slave> > slave = StartSlave(&containerizer, flags);
+  Try<PID<Slave>> slave = StartSlave(&containerizer, flags);
   ASSERT_SOME(slave);
 
   MockScheduler sched;
@@ -186,7 +189,7 @@ TEST_F(MasterTest, ShutdownFrameworkWhileTaskRunning)
   EXPECT_CALL(sched, registered(&driver, _, _))
     .Times(1);
 
-  Future<vector<Offer> > offers;
+  Future<vector<Offer>> offers;
   EXPECT_CALL(sched, resourceOffers(&driver, _))
     .WillOnce(FutureArg<1>(&offers))
     .WillRepeatedly(Return()); // Ignore subsequent offers.
@@ -195,12 +198,13 @@ TEST_F(MasterTest, ShutdownFrameworkWhileTaskRunning)
 
   AWAIT_READY(offers);
   EXPECT_NE(0u, offers.get().size());
+  Offer offer = offers.get()[0];
 
   TaskInfo task;
   task.set_name("");
   task.mutable_task_id()->set_value("1");
-  task.mutable_slave_id()->MergeFrom(offers.get()[0].slave_id());
-  task.mutable_resources()->MergeFrom(offers.get()[0].resources());
+  task.mutable_slave_id()->MergeFrom(offer.slave_id());
+  task.mutable_resources()->MergeFrom(offer.resources());
   task.mutable_executor()->MergeFrom(DEFAULT_EXECUTOR_INFO);
 
   vector<TaskInfo> tasks;
@@ -214,7 +218,7 @@ TEST_F(MasterTest, ShutdownFrameworkWhileTaskRunning)
 
   Future<Nothing> update;
   EXPECT_CALL(containerizer,
-              update(_, Resources(offers.get()[0].resources())))
+              update(_, Resources(offer.resources())))
     .WillOnce(DoAll(FutureSatisfy(&update),
                     Return(Future<Nothing>())));
 
@@ -222,20 +226,59 @@ TEST_F(MasterTest, ShutdownFrameworkWhileTaskRunning)
   EXPECT_CALL(sched, statusUpdate(&driver, _))
     .WillOnce(FutureArg<1>(&status));
 
-  driver.launchTasks(offers.get()[0].id(), tasks);
+  driver.launchTasks(offer.id(), tasks);
 
   AWAIT_READY(status);
   EXPECT_EQ(TASK_RUNNING, status.get().state());
 
   AWAIT_READY(update);
 
+  // Set expectation that Master receives UnregisterFrameworkMessage,
+  // which triggers marking running tasks as killed.
+  UnregisterFrameworkMessage message;
+  message.mutable_framework_id()->MergeFrom(offer.framework_id());
+
+  Future<UnregisterFrameworkMessage> unregisterFrameworkMessage =
+    FUTURE_PROTOBUF(message, _, master.get());
+
+  // Set expectation that Executor's shutdown callback is invoked.
+  Future<Nothing> shutdown;
   EXPECT_CALL(exec, shutdown(_))
-    .Times(AtMost(1));
+    .WillOnce(FutureSatisfy(&shutdown));
 
+  // Stop the driver while the task is running.
   driver.stop();
   driver.join();
 
-  Shutdown(); // Must shutdown before 'containerizer' gets deallocated.
+  // Wait for UnregisterFrameworkMessage message to be dispatched and
+  // executor's shutdown callback to be called.
+  AWAIT_READY(unregisterFrameworkMessage);
+  AWAIT_READY(shutdown);
+
+  // We have to be sure the UnregisterFrameworkMessage is processed
+  // completely and running tasks enter a terminal state before we
+  // request the master state.
+  Clock::pause();
+  Clock::settle();
+  Clock::resume();
+
+  // Request master state.
+  Future<process::http::Response> response =
+    process::http::get(master.get(), "state.json");
+  AWAIT_READY(response);
+
+  // These checks are not essential for the test, but may help
+  // understand what went wrong.
+  Try<JSON::Object> parse = JSON::parse<JSON::Object>(response.get().body);
+  ASSERT_SOME(parse);
+
+  // Make sure the task landed in completed and marked as killed.
+  Result<JSON::String> state = parse.get().find<JSON::String>(
+      "completed_frameworks[0].completed_tasks[0].state");
+
+  ASSERT_SOME_EQ(JSON::String("TASK_KILLED"), state);
+
+  Shutdown();  // Must shutdown before 'containerizer' gets deallocated.
 }
 
 


[3/3] git commit: Implemented array subscript lookup in JSON::Object::find.

Posted by be...@apache.org.
Implemented array subscript lookup in JSON::Object::find.

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


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

Branch: refs/heads/master
Commit: dfe338078659a73846f2972a4bebccafcc369a07
Parents: 169e969
Author: Benjamin Hindman <be...@gmail.com>
Authored: Sun Oct 12 21:33:58 2014 -0700
Committer: Benjamin Hindman <be...@gmail.com>
Committed: Sat Oct 25 16:57:40 2014 -0700

----------------------------------------------------------------------
 .../3rdparty/stout/include/stout/json.hpp       | 54 +++++++++++++++++---
 .../3rdparty/stout/tests/json_tests.cpp         | 20 +++++---
 2 files changed, 59 insertions(+), 15 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/dfe33807/3rdparty/libprocess/3rdparty/stout/include/stout/json.hpp
----------------------------------------------------------------------
diff --git a/3rdparty/libprocess/3rdparty/stout/include/stout/json.hpp b/3rdparty/libprocess/3rdparty/stout/include/stout/json.hpp
index 2e1f78e..11bb7ed 100644
--- a/3rdparty/libprocess/3rdparty/stout/include/stout/json.hpp
+++ b/3rdparty/libprocess/3rdparty/stout/include/stout/json.hpp
@@ -19,7 +19,6 @@
 #include <iomanip>
 #include <iostream>
 #include <limits>
-#include <list>
 #include <map>
 #include <string>
 #include <vector>
@@ -30,6 +29,7 @@
 
 #include <stout/check.hpp>
 #include <stout/foreach.hpp>
+#include <stout/numify.hpp>
 #include <stout/result.hpp>
 #include <stout/strings.hpp>
 #include <stout/try.hpp>
@@ -85,7 +85,7 @@ struct Object
   // Returns the JSON value (specified by the type) given a "path"
   // into the structure, for example:
   //
-  //   Result<JSON::Array> array = object.find<JSON::Array>("nested.array");
+  //   Result<JSON::Array> array = object.find<JSON::Array>("nested.array[0]");
   //
   // Will return 'None' if no field could be found called 'array'
   // within a field called 'nested' of 'object' (where 'nested' must
@@ -94,8 +94,6 @@ struct Object
   // Returns an error if a JSON value of the wrong type is found, or
   // an intermediate JSON value is not an object that we can do a
   // recursive find on.
-  //
-  // TODO(benh): Support paths that index, e.g., 'nested.array[4].field'.
   template <typename T>
   Result<T> find(const std::string& path) const;
 
@@ -105,7 +103,7 @@ struct Object
 
 struct Array
 {
-  std::list<Value> values;
+  std::vector<Value> values;
 };
 
 
@@ -225,13 +223,53 @@ Result<T> Object::find(const std::string& path) const
     return None();
   }
 
-  std::map<std::string, Value>::const_iterator entry = values.find(names[0]);
+  std::string name = names[0];
+
+  // Determine if we have an array subscript. If so, save it but
+  // remove it from the name for doing the lookup.
+  Option<size_t> subscript = None();
+  size_t index = name.find('[');
+  if (index != std::string::npos) {
+    // Check for the closing bracket.
+    if (name.at(name.length() - 1) != ']') {
+      return Error("Malformed array subscript, expecting ']'");
+    }
+
+    // Now remove the closing bracket (last character) and everything
+    // before and including the opening bracket.
+    std::string s = name.substr(0, name.length() - 1);
+    s = s.substr(index + 1);
+
+    // Now numify the subscript.
+    Try<int> i = numify<int>(s);
+
+    if (i.isError()) {
+      return Error("Failed to numify array subscript '" + s + "'");
+    } else if (i.get() < 0) {
+      return Error("Array subscript '" + s + "' must be >= 0");
+    }
+
+    subscript = i.get();
+
+    // And finally remove the array subscript from the name.
+    name = name.substr(0, index);
+  }
+
+  std::map<std::string, Value>::const_iterator entry = values.find(name);
 
   if (entry == values.end()) {
     return None();
   }
 
-  const Value& value = entry->second;
+  Value value = entry->second;
+
+  if (value.is<Array>() && subscript.isSome()) {
+    Array array = value.as<Array>();
+    if (subscript.get() >= array.values.size()) {
+      return None();
+    }
+    value = array.values[subscript.get()];
+  }
 
   if (names.size() == 1) {
     if (!value.is<T>()) {
@@ -375,7 +413,7 @@ inline std::ostream& operator << (std::ostream& out, const Object& object)
 inline std::ostream& operator << (std::ostream& out, const Array& array)
 {
   out << "[";
-  std::list<Value>::const_iterator iterator;
+  std::vector<Value>::const_iterator iterator;
   iterator = array.values.begin();
   while (iterator != array.values.end()) {
     out << *iterator;

http://git-wip-us.apache.org/repos/asf/mesos/blob/dfe33807/3rdparty/libprocess/3rdparty/stout/tests/json_tests.cpp
----------------------------------------------------------------------
diff --git a/3rdparty/libprocess/3rdparty/stout/tests/json_tests.cpp b/3rdparty/libprocess/3rdparty/stout/tests/json_tests.cpp
index 3bfc8e6..2be4c65 100644
--- a/3rdparty/libprocess/3rdparty/stout/tests/json_tests.cpp
+++ b/3rdparty/libprocess/3rdparty/stout/tests/json_tests.cpp
@@ -220,13 +220,19 @@ TEST(JsonTest, Find)
       JSON::Null(),
       object.find<JSON::Null>("nested1.nested2.null"));
 
-  Result<JSON::Array> result =
-    object.find<JSON::Array>("nested1.nested2.array");
-
-  ASSERT_SOME(result);
-  ASSERT_FALSE(result.get().values.empty());
-  ASSERT_TRUE(result.get().values.front().is<JSON::String>());
-  ASSERT_EQ("hello", result.get().values.front().as<JSON::String>());
+  ASSERT_SOME_EQ(
+      JSON::String("hello"),
+      object.find<JSON::String>("nested1.nested2.array[0]"));
+
+  ASSERT_ERROR(object.find<JSON::String>("nested1.nested2.array[1"));
+  ASSERT_ERROR(object.find<JSON::String>("nested1.nested2.array[[1]"));
+  ASSERT_ERROR(object.find<JSON::String>("nested1.nested2.array[1]]"));
+  ASSERT_ERROR(object.find<JSON::String>("nested1.nested2.array.[1]"));
+  ASSERT_ERROR(object.find<JSON::String>("nested1.nested2.array[.1]"));
+  ASSERT_ERROR(object.find<JSON::String>("nested1.nested2.array[1.]"));
+
+  // Out of bounds is none.
+  ASSERT_NONE(object.find<JSON::String>("nested1.nested2.array[1]"));
 
   // Also test getting JSON::Value when you don't know the type.
   ASSERT_SOME(object.find<JSON::Value>("nested1.nested2.null"));


[2/3] git commit: Fixes necessary due to JSON::Array::values change to std::vector.

Posted by be...@apache.org.
Fixes necessary due to JSON::Array::values change to std::vector.

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


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

Branch: refs/heads/master
Commit: 06bec4fa91f5f1c30eb1eac30f2a123100872d8e
Parents: dfe3380
Author: Benjamin Hindman <be...@gmail.com>
Authored: Sun Oct 12 21:34:43 2014 -0700
Committer: Benjamin Hindman <be...@gmail.com>
Committed: Sat Oct 25 16:57:40 2014 -0700

----------------------------------------------------------------------
 3rdparty/libprocess/3rdparty/stout/include/stout/json.hpp | 3 +--
 3rdparty/libprocess/3rdparty/stout/tests/json_tests.cpp   | 7 +++++++
 src/docker/docker.cpp                                     | 2 +-
 3 files changed, 9 insertions(+), 3 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/06bec4fa/3rdparty/libprocess/3rdparty/stout/include/stout/json.hpp
----------------------------------------------------------------------
diff --git a/3rdparty/libprocess/3rdparty/stout/include/stout/json.hpp b/3rdparty/libprocess/3rdparty/stout/include/stout/json.hpp
index 11bb7ed..334c898 100644
--- a/3rdparty/libprocess/3rdparty/stout/include/stout/json.hpp
+++ b/3rdparty/libprocess/3rdparty/stout/include/stout/json.hpp
@@ -237,8 +237,7 @@ Result<T> Object::find(const std::string& path) const
 
     // Now remove the closing bracket (last character) and everything
     // before and including the opening bracket.
-    std::string s = name.substr(0, name.length() - 1);
-    s = s.substr(index + 1);
+    std::string s = name.substr(index + 1, name.length() - index - 2);
 
     // Now numify the subscript.
     Try<int> i = numify<int>(s);

http://git-wip-us.apache.org/repos/asf/mesos/blob/06bec4fa/3rdparty/libprocess/3rdparty/stout/tests/json_tests.cpp
----------------------------------------------------------------------
diff --git a/3rdparty/libprocess/3rdparty/stout/tests/json_tests.cpp b/3rdparty/libprocess/3rdparty/stout/tests/json_tests.cpp
index 2be4c65..f60d1bb 100644
--- a/3rdparty/libprocess/3rdparty/stout/tests/json_tests.cpp
+++ b/3rdparty/libprocess/3rdparty/stout/tests/json_tests.cpp
@@ -230,6 +230,13 @@ TEST(JsonTest, Find)
   ASSERT_ERROR(object.find<JSON::String>("nested1.nested2.array.[1]"));
   ASSERT_ERROR(object.find<JSON::String>("nested1.nested2.array[.1]"));
   ASSERT_ERROR(object.find<JSON::String>("nested1.nested2.array[1.]"));
+  ASSERT_ERROR(object.find<JSON::String>("nested1.nested2.array[]"));
+  ASSERT_ERROR(object.find<JSON::String>("nested1.nested2.array[[]"));
+  ASSERT_ERROR(object.find<JSON::String>("nested1.nested2.array[]]"));
+  ASSERT_ERROR(object.find<JSON::String>("nested1.nested2.array[[]]"));
+  ASSERT_ERROR(object.find<JSON::String>("nested1.nested2.array[[1]]"));
+  ASSERT_ERROR(object.find<JSON::String>("nested1.nested2.array[[1]"));
+  ASSERT_ERROR(object.find<JSON::String>("nested1.nested2.array[1]]"));
 
   // Out of bounds is none.
   ASSERT_NONE(object.find<JSON::String>("nested1.nested2.array[1]"));

http://git-wip-us.apache.org/repos/asf/mesos/blob/06bec4fa/src/docker/docker.cpp
----------------------------------------------------------------------
diff --git a/src/docker/docker.cpp b/src/docker/docker.cpp
index e09b51c..9973782 100644
--- a/src/docker/docker.cpp
+++ b/src/docker/docker.cpp
@@ -253,7 +253,7 @@ Try<Docker::Image> Docker::Image::create(const JSON::Object& json)
     return Error("Unexpected type found for 'ContainerConfig.Entrypoint'");
   }
 
-  const list<JSON::Value>& values = entrypoint.get().as<JSON::Array>().values;
+  const vector<JSON::Value>& values = entrypoint.get().as<JSON::Array>().values;
   if (values.size() == 0) {
     return Docker::Image(None());
   }