You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mesos.apache.org by bm...@apache.org on 2016/02/20 17:37:37 UTC

[01/11] mesos git commit: Introduced a TASK_KILLING state.

Repository: mesos
Updated Branches:
  refs/heads/master fdeb55a0a -> 1488f16d2


Introduced a TASK_KILLING state.

TASK_KILLING can be used to signify that the kill request has been
received by the executor, but the task is not yet killed. This is
similar to how TASK_STARTING indicates the launch request has been
received by the executor, but the task is not yet launched.

This new state will be guarded by a framework capability in order
to ensure that we do not break older frameworks.

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


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

Branch: refs/heads/master
Commit: 022be0a833dfb58de958a80eabc89fa9334782e0
Parents: fdeb55a
Author: Abhishek Dasgupta <a1...@linux.vnet.ibm.com>
Authored: Sat Feb 20 12:56:24 2016 +0100
Committer: Benjamin Mahler <bm...@apache.org>
Committed: Sat Feb 20 14:18:30 2016 +0100

----------------------------------------------------------------------
 include/mesos/mesos.proto    |  5 +++++
 include/mesos/v1/mesos.proto |  5 +++++
 src/master/http.cpp          |  5 +++++
 src/master/master.cpp        | 19 +++++++++++++++++++
 src/master/master.hpp        |  1 +
 src/master/metrics.cpp       |  5 +++++
 src/master/metrics.hpp       |  1 +
 src/slave/metrics.cpp        |  5 +++++
 src/slave/metrics.hpp        |  1 +
 src/slave/slave.cpp          | 16 ++++++++++++++++
 src/slave/slave.hpp          |  1 +
 src/tests/metrics_tests.cpp  |  2 ++
 12 files changed, 66 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/022be0a8/include/mesos/mesos.proto
----------------------------------------------------------------------
diff --git a/include/mesos/mesos.proto b/include/mesos/mesos.proto
index a27c505..70e380a 100644
--- a/include/mesos/mesos.proto
+++ b/include/mesos/mesos.proto
@@ -1218,6 +1218,11 @@ enum TaskState {
   TASK_STAGING = 6; // Initial state. Framework status updates should not use.
   TASK_STARTING = 0;
   TASK_RUNNING = 1;
+
+  // NOTE: This should only be sent when the framework has
+  // the TASK_KILLING_STATE capability.
+  TASK_KILLING = 8;  // The task is being killed by the executor.
+
   TASK_FINISHED = 2; // TERMINAL. The task finished successfully.
   TASK_FAILED = 3; // TERMINAL. The task failed to finish successfully.
   TASK_KILLED = 4; // TERMINAL. The task was killed by the executor.

http://git-wip-us.apache.org/repos/asf/mesos/blob/022be0a8/include/mesos/v1/mesos.proto
----------------------------------------------------------------------
diff --git a/include/mesos/v1/mesos.proto b/include/mesos/v1/mesos.proto
index e4224af..6271d2a 100644
--- a/include/mesos/v1/mesos.proto
+++ b/include/mesos/v1/mesos.proto
@@ -1119,6 +1119,11 @@ enum TaskState {
   TASK_STAGING = 6; // Initial state. Framework status updates should not use.
   TASK_STARTING = 0;
   TASK_RUNNING = 1;
+
+  // NOTE: This should only be sent when the framework has
+  // the TASK_KILLING_STATE capability.
+  TASK_KILLING = 8;  // The task is being killed by the executor.
+
   TASK_FINISHED = 2; // TERMINAL. The task finished successfully.
   TASK_FAILED = 3; // TERMINAL. The task failed to finish successfully.
   TASK_KILLED = 4; // TERMINAL. The task was killed by the executor.

http://git-wip-us.apache.org/repos/asf/mesos/blob/022be0a8/src/master/http.cpp
----------------------------------------------------------------------
diff --git a/src/master/http.cpp b/src/master/http.cpp
index 248e3d4..ae6bc78 100644
--- a/src/master/http.cpp
+++ b/src/master/http.cpp
@@ -1548,6 +1548,7 @@ struct TaskStateSummary
     : staging(0),
       starting(0),
       running(0),
+      killing(0),
       finished(0),
       killed(0),
       failed(0),
@@ -1561,6 +1562,7 @@ struct TaskStateSummary
       case TASK_STAGING: { ++staging; break; }
       case TASK_STARTING: { ++starting; break; }
       case TASK_RUNNING: { ++running; break; }
+      case TASK_KILLING: { ++killing; break; }
       case TASK_FINISHED: { ++finished; break; }
       case TASK_KILLED: { ++killed; break; }
       case TASK_FAILED: { ++failed; break; }
@@ -1574,6 +1576,7 @@ struct TaskStateSummary
   size_t staging;
   size_t starting;
   size_t running;
+  size_t killing;
   size_t finished;
   size_t killed;
   size_t failed;
@@ -1683,6 +1686,7 @@ Future<Response> Master::Http::stateSummary(const Request& request) const
           writer->field("TASK_STAGING", summary.staging);
           writer->field("TASK_STARTING", summary.starting);
           writer->field("TASK_RUNNING", summary.running);
+          writer->field("TASK_KILLING", summary.killing);
           writer->field("TASK_FINISHED", summary.finished);
           writer->field("TASK_KILLED", summary.killed);
           writer->field("TASK_FAILED", summary.failed);
@@ -1724,6 +1728,7 @@ Future<Response> Master::Http::stateSummary(const Request& request) const
           writer->field("TASK_STAGING", summary.staging);
           writer->field("TASK_STARTING", summary.starting);
           writer->field("TASK_RUNNING", summary.running);
+          writer->field("TASK_KILLING", summary.killing);
           writer->field("TASK_FINISHED", summary.finished);
           writer->field("TASK_KILLED", summary.killed);
           writer->field("TASK_FAILED", summary.failed);

http://git-wip-us.apache.org/repos/asf/mesos/blob/022be0a8/src/master/master.cpp
----------------------------------------------------------------------
diff --git a/src/master/master.cpp b/src/master/master.cpp
index e5aaf67..b453bc7 100644
--- a/src/master/master.cpp
+++ b/src/master/master.cpp
@@ -6918,6 +6918,25 @@ double Master::_tasks_running()
 }
 
 
+double Master::_tasks_killing()
+{
+  double count = 0.0;
+
+  foreachvalue (Slave* slave, slaves.registered) {
+    typedef hashmap<TaskID, Task*> TaskMap;
+    foreachvalue (const TaskMap& tasks, slave->tasks) {
+      foreachvalue (const Task* task, tasks) {
+        if (task->state() == TASK_KILLING) {
+          count++;
+        }
+      }
+    }
+  }
+
+  return count;
+}
+
+
 double Master::_resources_total(const string& name)
 {
   double total = 0.0;

http://git-wip-us.apache.org/repos/asf/mesos/blob/022be0a8/src/master/master.hpp
----------------------------------------------------------------------
diff --git a/src/master/master.hpp b/src/master/master.hpp
index 2f2ad2a..13c6ff1 100644
--- a/src/master/master.hpp
+++ b/src/master/master.hpp
@@ -1462,6 +1462,7 @@ private:
   double _tasks_staging();
   double _tasks_starting();
   double _tasks_running();
+  double _tasks_killing();
 
   double _resources_total(const std::string& name);
   double _resources_used(const std::string& name);

http://git-wip-us.apache.org/repos/asf/mesos/blob/022be0a8/src/master/metrics.cpp
----------------------------------------------------------------------
diff --git a/src/master/metrics.cpp b/src/master/metrics.cpp
index 5e4f4d3..30c0911 100644
--- a/src/master/metrics.cpp
+++ b/src/master/metrics.cpp
@@ -80,6 +80,9 @@ Metrics::Metrics(const Master& master)
     tasks_running(
         "master/tasks_running",
         defer(master, &Master::_tasks_running)),
+    tasks_killing(
+        "master/tasks_killing",
+        defer(master, &Master::_tasks_killing)),
     tasks_finished(
         "master/tasks_finished"),
     tasks_failed(
@@ -199,6 +202,7 @@ Metrics::Metrics(const Master& master)
   process::metrics::add(tasks_staging);
   process::metrics::add(tasks_starting);
   process::metrics::add(tasks_running);
+  process::metrics::add(tasks_killing);
   process::metrics::add(tasks_finished);
   process::metrics::add(tasks_failed);
   process::metrics::add(tasks_killed);
@@ -335,6 +339,7 @@ Metrics::~Metrics()
   process::metrics::remove(tasks_staging);
   process::metrics::remove(tasks_starting);
   process::metrics::remove(tasks_running);
+  process::metrics::remove(tasks_killing);
   process::metrics::remove(tasks_finished);
   process::metrics::remove(tasks_failed);
   process::metrics::remove(tasks_killed);

http://git-wip-us.apache.org/repos/asf/mesos/blob/022be0a8/src/master/metrics.hpp
----------------------------------------------------------------------
diff --git a/src/master/metrics.hpp b/src/master/metrics.hpp
index 551e4eb..9d201fc 100644
--- a/src/master/metrics.hpp
+++ b/src/master/metrics.hpp
@@ -60,6 +60,7 @@ struct Metrics
   process::metrics::Gauge tasks_staging;
   process::metrics::Gauge tasks_starting;
   process::metrics::Gauge tasks_running;
+  process::metrics::Gauge tasks_killing;
   process::metrics::Counter tasks_finished;
   process::metrics::Counter tasks_failed;
   process::metrics::Counter tasks_killed;

http://git-wip-us.apache.org/repos/asf/mesos/blob/022be0a8/src/slave/metrics.cpp
----------------------------------------------------------------------
diff --git a/src/slave/metrics.cpp b/src/slave/metrics.cpp
index 0769495..42c66d7 100644
--- a/src/slave/metrics.cpp
+++ b/src/slave/metrics.cpp
@@ -53,6 +53,9 @@ Metrics::Metrics(const Slave& slave)
     tasks_running(
         "slave/tasks_running",
         defer(slave, &Slave::_tasks_running)),
+    tasks_killing(
+        "slave/tasks_killing",
+        defer(slave, &Slave::_tasks_killing)),
     tasks_finished(
         "slave/tasks_finished"),
     tasks_failed(
@@ -99,6 +102,7 @@ Metrics::Metrics(const Slave& slave)
   process::metrics::add(tasks_staging);
   process::metrics::add(tasks_starting);
   process::metrics::add(tasks_running);
+  process::metrics::add(tasks_killing);
   process::metrics::add(tasks_finished);
   process::metrics::add(tasks_failed);
   process::metrics::add(tasks_killed);
@@ -184,6 +188,7 @@ Metrics::~Metrics()
   process::metrics::remove(tasks_staging);
   process::metrics::remove(tasks_starting);
   process::metrics::remove(tasks_running);
+  process::metrics::remove(tasks_killing);
   process::metrics::remove(tasks_finished);
   process::metrics::remove(tasks_failed);
   process::metrics::remove(tasks_killed);

http://git-wip-us.apache.org/repos/asf/mesos/blob/022be0a8/src/slave/metrics.hpp
----------------------------------------------------------------------
diff --git a/src/slave/metrics.hpp b/src/slave/metrics.hpp
index 2c22de5..d443213 100644
--- a/src/slave/metrics.hpp
+++ b/src/slave/metrics.hpp
@@ -45,6 +45,7 @@ struct Metrics
   process::metrics::Gauge tasks_staging;
   process::metrics::Gauge tasks_starting;
   process::metrics::Gauge tasks_running;
+  process::metrics::Gauge tasks_killing;
   process::metrics::Counter tasks_finished;
   process::metrics::Counter tasks_failed;
   process::metrics::Counter tasks_killed;

http://git-wip-us.apache.org/repos/asf/mesos/blob/022be0a8/src/slave/slave.cpp
----------------------------------------------------------------------
diff --git a/src/slave/slave.cpp b/src/slave/slave.cpp
index f0be0d5..840534f 100644
--- a/src/slave/slave.cpp
+++ b/src/slave/slave.cpp
@@ -5046,6 +5046,22 @@ double Slave::_tasks_running()
 }
 
 
+double Slave::_tasks_killing()
+{
+  double count = 0.0;
+  foreachvalue (Framework* framework, frameworks) {
+    foreachvalue (Executor* executor, framework->executors) {
+      foreach (Task* task, executor->launchedTasks.values()) {
+        if (task->state() == TASK_KILLING) {
+          count++;
+        }
+      }
+    }
+  }
+  return count;
+}
+
+
 double Slave::_executors_registering()
 {
   double count = 0.0;

http://git-wip-us.apache.org/repos/asf/mesos/blob/022be0a8/src/slave/slave.hpp
----------------------------------------------------------------------
diff --git a/src/slave/slave.hpp b/src/slave/slave.hpp
index ced835d..7520cc3 100644
--- a/src/slave/slave.hpp
+++ b/src/slave/slave.hpp
@@ -478,6 +478,7 @@ private:
   double _tasks_staging();
   double _tasks_starting();
   double _tasks_running();
+  double _tasks_killing();
 
   double _executors_registering();
   double _executors_running();

http://git-wip-us.apache.org/repos/asf/mesos/blob/022be0a8/src/tests/metrics_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/metrics_tests.cpp b/src/tests/metrics_tests.cpp
index 106bea5..419d275 100644
--- a/src/tests/metrics_tests.cpp
+++ b/src/tests/metrics_tests.cpp
@@ -73,6 +73,7 @@ TEST_F(MetricsTest, Master)
   EXPECT_EQ(1u, stats.values.count("master/tasks_staging"));
   EXPECT_EQ(1u, stats.values.count("master/tasks_starting"));
   EXPECT_EQ(1u, stats.values.count("master/tasks_running"));
+  EXPECT_EQ(1u, stats.values.count("master/tasks_killing"));
   EXPECT_EQ(1u, stats.values.count("master/tasks_finished"));
   EXPECT_EQ(1u, stats.values.count("master/tasks_failed"));
   EXPECT_EQ(1u, stats.values.count("master/tasks_killed"));
@@ -180,6 +181,7 @@ TEST_F(MetricsTest, Slave)
   EXPECT_EQ(1u, stats.values.count("slave/tasks_staging"));
   EXPECT_EQ(1u, stats.values.count("slave/tasks_starting"));
   EXPECT_EQ(1u, stats.values.count("slave/tasks_running"));
+  EXPECT_EQ(1u, stats.values.count("slave/tasks_killing"));
   EXPECT_EQ(1u, stats.values.count("slave/tasks_finished"));
   EXPECT_EQ(1u, stats.values.count("slave/tasks_failed"));
   EXPECT_EQ(1u, stats.values.count("slave/tasks_killed"));


[10/11] mesos git commit: Fixed health check process leak when shutdown is called without killTask.

Posted by bm...@apache.org.
Fixed health check process leak when shutdown is called without killTask.


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

Branch: refs/heads/master
Commit: 25d303d8743b524c92627d48f7dfb7ac2a921ede
Parents: a30233b
Author: Benjamin Mahler <bm...@apache.org>
Authored: Sat Feb 20 15:31:28 2016 +0100
Committer: Benjamin Mahler <bm...@apache.org>
Committed: Sat Feb 20 17:32:26 2016 +0100

----------------------------------------------------------------------
 src/docker/executor.cpp   | 14 ++++++++++----
 src/launcher/executor.cpp | 14 ++++++++++----
 2 files changed, 20 insertions(+), 8 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/25d303d8/src/docker/executor.cpp
----------------------------------------------------------------------
diff --git a/src/docker/executor.cpp b/src/docker/executor.cpp
index cab9d80..1921d4a 100644
--- a/src/docker/executor.cpp
+++ b/src/docker/executor.cpp
@@ -195,10 +195,6 @@ public:
     // Since the docker executor manages a single task, we
     // shutdown completely when we receive a killTask.
     shutdown(driver);
-    if (healthPid != -1) {
-      // Cleanup health check process.
-      os::killtree(healthPid, SIGKILL);
-    }
   }
 
   void frameworkMessage(ExecutorDriver* driver, const string& data) {}
@@ -230,6 +226,16 @@ public:
       stop = docker->stop(containerName, stopTimeout);
       killed = true;
     }
+
+    // Cleanup health check process.
+    //
+    // TODO(bmahler): Consider doing this after the task has been
+    // reaped, since a framework may be interested in health
+    // information while the task is being killed (consider a
+    // task that takes 30 minutes to be cleanly killed).
+    if (healthPid != -1) {
+      os::killtree(healthPid, SIGKILL);
+    }
   }
 
   void error(ExecutorDriver* driver, const string& message) {}

http://git-wip-us.apache.org/repos/asf/mesos/blob/25d303d8/src/launcher/executor.cpp
----------------------------------------------------------------------
diff --git a/src/launcher/executor.cpp b/src/launcher/executor.cpp
index b65f0ab..4149f08 100644
--- a/src/launcher/executor.cpp
+++ b/src/launcher/executor.cpp
@@ -464,10 +464,6 @@ public:
     // Since the command executor manages a single task, we
     // shutdown completely when we receive a killTask.
     shutdown(driver);
-    if (healthPid != -1) {
-      // Cleanup health check process.
-      os::killtree(healthPid, SIGKILL);
-    }
   }
 
   void frameworkMessage(ExecutorDriver* driver, const string& data) {}
@@ -521,6 +517,16 @@ public:
 
       killed = true;
     }
+
+    // Cleanup health check process.
+    //
+    // TODO(bmahler): Consider doing this after the task has been
+    // reaped, since a framework may be interested in health
+    // information while the task is being killed (consider a
+    // task that takes 30 minutes to be cleanly killed).
+    if (healthPid != -1) {
+      os::killtree(healthPid, SIGKILL);
+    }
   }
 
   virtual void error(ExecutorDriver* driver, const string& message) {}


[09/11] mesos git commit: Updated the command / docker executors to send TASK_KILLING.

Posted by bm...@apache.org.
Updated the command / docker executors to send TASK_KILLING.

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


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

Branch: refs/heads/master
Commit: a30233b994dd1a77eb8ef37525b5aa7b6ecdf3bd
Parents: c893c9f
Author: Abhishek Dasgupta <a1...@linux.vnet.ibm.com>
Authored: Sat Feb 20 14:25:15 2016 +0100
Committer: Benjamin Mahler <bm...@apache.org>
Committed: Sat Feb 20 17:32:26 2016 +0100

----------------------------------------------------------------------
 src/docker/executor.cpp   | 51 ++++++++++++++++++++++++-------------
 src/launcher/executor.cpp | 58 +++++++++++++++++++++++++++++++-----------
 2 files changed, 77 insertions(+), 32 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/a30233b9/src/docker/executor.cpp
----------------------------------------------------------------------
diff --git a/src/docker/executor.cpp b/src/docker/executor.cpp
index 654a41d..cab9d80 100644
--- a/src/docker/executor.cpp
+++ b/src/docker/executor.cpp
@@ -91,11 +91,12 @@ public:
   void registered(
       ExecutorDriver* _driver,
       const ExecutorInfo& executorInfo,
-      const FrameworkInfo& frameworkInfo,
+      const FrameworkInfo& _frameworkInfo,
       const SlaveInfo& slaveInfo)
   {
     cout << "Registered docker executor on " << slaveInfo.hostname() << endl;
     driver = _driver;
+    frameworkInfo = _frameworkInfo;
   }
 
   void reregistered(
@@ -123,9 +124,10 @@ public:
       return;
     }
 
-    TaskID taskId = task.task_id();
+    // Capture the TaskID.
+    taskId = task.task_id();
 
-    cout << "Starting task " << taskId.value() << endl;
+    cout << "Starting task " << taskId.get() << endl;
 
     CHECK(task.has_container());
     CHECK(task.has_command());
@@ -147,13 +149,9 @@ public:
         task.resources() + task.executor().resources(),
         None(),
         Subprocess::FD(STDOUT_FILENO),
-        Subprocess::FD(STDERR_FILENO))
-      .onAny(defer(
-        self(),
-        &Self::reaped,
-        driver,
-        taskId,
-        lambda::_1));
+        Subprocess::FD(STDERR_FILENO));
+
+    run->onAny(defer(self(), &Self::reaped, driver, lambda::_1));
 
     // Delay sending TASK_RUNNING status update until we receive
     // inspect output.
@@ -161,7 +159,7 @@ public:
       .then(defer(self(), [=](const Docker::Container& container) {
         if (!killed) {
           TaskStatus status;
-          status.mutable_task_id()->CopyFrom(taskId);
+          status.mutable_task_id()->CopyFrom(taskId.get());
           status.set_state(TASK_RUNNING);
           status.set_data(container.output);
           if (container.ipAddress.isSome()) {
@@ -192,7 +190,10 @@ public:
 
   void killTask(ExecutorDriver* driver, const TaskID& taskId)
   {
-    cout << "Killing docker task" << endl;
+    cout << "Received killTask" << endl;
+
+    // Since the docker executor manages a single task, we
+    // shutdown completely when we receive a killTask.
     shutdown(driver);
     if (healthPid != -1) {
       // Cleanup health check process.
@@ -207,12 +208,25 @@ public:
     cout << "Shutting down" << endl;
 
     if (run.isSome() && !killed) {
+      // Send TASK_KILLING if the framework can handle it.
+      CHECK_SOME(frameworkInfo);
+      CHECK_SOME(taskId);
+
+      foreach (const FrameworkInfo::Capability& c,
+               frameworkInfo->capabilities()) {
+        if (c.type() == FrameworkInfo::Capability::TASK_KILLING_STATE) {
+          TaskStatus status;
+          status.mutable_task_id()->CopyFrom(taskId.get());
+          status.set_state(TASK_KILLING);
+          driver->sendStatusUpdate(status);
+          break;
+        }
+      }
+
       // The docker daemon might still be in progress starting the
       // container, therefore we kill both the docker run process
       // and also ask the daemon to stop the container.
-
-      // Making a mutable copy of the future so we can call discard.
-      Future<Nothing>(run.get()).discard();
+      run->discard();
       stop = docker->stop(containerName, stopTimeout);
       killed = true;
     }
@@ -257,7 +271,6 @@ protected:
 private:
   void reaped(
       ExecutorDriver* _driver,
-      const TaskID& taskId,
       const Future<Nothing>& run)
   {
     // Wait for docker->stop to finish, and best effort wait for the
@@ -287,8 +300,10 @@ private:
             state = TASK_FINISHED;
           }
 
+          CHECK_SOME(taskId);
+
           TaskStatus taskStatus;
-          taskStatus.mutable_task_id()->CopyFrom(taskId);
+          taskStatus.mutable_task_id()->CopyFrom(taskId.get());
           taskStatus.set_state(state);
           taskStatus.set_message(message);
           if (killed && killedByHealthCheck) {
@@ -415,6 +430,8 @@ private:
   Future<Nothing> stop;
   Future<Nothing> inspect;
   Option<ExecutorDriver*> driver;
+  Option<FrameworkInfo> frameworkInfo;
+  Option<TaskID> taskId;
 };
 
 

http://git-wip-us.apache.org/repos/asf/mesos/blob/a30233b9/src/launcher/executor.cpp
----------------------------------------------------------------------
diff --git a/src/launcher/executor.cpp b/src/launcher/executor.cpp
index c27e079..b65f0ab 100644
--- a/src/launcher/executor.cpp
+++ b/src/launcher/executor.cpp
@@ -93,6 +93,8 @@ public:
       healthPid(-1),
       escalationTimeout(slave::EXECUTOR_SIGNAL_ESCALATION_TIMEOUT),
       driver(None()),
+      frameworkInfo(None()),
+      taskId(None()),
       healthCheckDir(_healthCheckDir),
       override(override),
       sandboxDirectory(_sandboxDirectory),
@@ -105,13 +107,16 @@ public:
   void registered(
       ExecutorDriver* _driver,
       const ExecutorInfo& _executorInfo,
-      const FrameworkInfo& frameworkInfo,
+      const FrameworkInfo& _frameworkInfo,
       const SlaveInfo& slaveInfo)
   {
     CHECK_EQ(REGISTERING, state);
 
     cout << "Registered executor on " << slaveInfo.hostname() << endl;
+
     driver = _driver;
+    frameworkInfo = _frameworkInfo;
+
     state = REGISTERED;
   }
 
@@ -122,6 +127,7 @@ public:
     CHECK(state == REGISTERED || state == REGISTERING) << state;
 
     cout << "Re-registered executor on " << slaveInfo.hostname() << endl;
+
     state = REGISTERED;
   }
 
@@ -142,6 +148,9 @@ public:
       return;
     }
 
+    // Capture the TaskID.
+    taskId = task.task_id();
+
     // Determine the command to launch the task.
     CommandInfo command;
 
@@ -438,12 +447,7 @@ public:
 
     // Monitor this process.
     process::reap(pid)
-      .onAny(defer(self(),
-                   &Self::reaped,
-                   driver,
-                   task.task_id(),
-                   pid,
-                   lambda::_1));
+      .onAny(defer(self(), &Self::reaped, driver, pid, lambda::_1));
 
     TaskStatus status;
     status.mutable_task_id()->MergeFrom(task.task_id());
@@ -455,6 +459,10 @@ public:
 
   void killTask(ExecutorDriver* driver, const TaskID& taskId)
   {
+    cout << "Received killTask" << endl;
+
+    // Since the command executor manages a single task, we
+    // shutdown completely when we receive a killTask.
     shutdown(driver);
     if (healthPid != -1) {
       // Cleanup health check process.
@@ -468,22 +476,39 @@ public:
   {
     cout << "Shutting down" << endl;
 
-    if (pid > 0 && !killed) {
-      cout << "Sending SIGTERM to process tree at pid "
-           << pid << endl;
+    if (launched && !killed) {
+      // Send TASK_KILLING if the framework can handle it.
+      CHECK_SOME(frameworkInfo);
+      CHECK_SOME(taskId);
+
+      foreach (const FrameworkInfo::Capability& c,
+               frameworkInfo->capabilities()) {
+        if (c.type() == FrameworkInfo::Capability::TASK_KILLING_STATE) {
+          TaskStatus status;
+          status.mutable_task_id()->CopyFrom(taskId.get());
+          status.set_state(TASK_KILLING);
+          driver->sendStatusUpdate(status);
+          break;
+        }
+      }
+
+      // Now perform signal escalation to begin killing the task.
+      CHECK_GT(pid, 0);
+
+      cout << "Sending SIGTERM to process tree at pid " << pid << endl;
 
       Try<std::list<os::ProcessTree> > trees =
         os::killtree(pid, SIGTERM, true, true);
 
       if (trees.isError()) {
-        cerr << "Failed to kill the process tree rooted at pid "
-             << pid << ": " << trees.error() << endl;
+        cerr << "Failed to kill the process tree rooted at pid " << pid
+             << ": " << trees.error() << endl;
 
         // Send SIGTERM directly to process 'pid' as it may not have
         // received signal before os::killtree() failed.
         ::kill(pid, SIGTERM);
       } else {
-        cout << "Killing the following process trees:\n"
+        cout << "Sent SIGTERM to the following process trees:\n"
              << stringify(trees.get()) << endl;
       }
 
@@ -538,7 +563,6 @@ protected:
 private:
   void reaped(
       ExecutorDriver* driver,
-      const TaskID& taskId,
       pid_t pid,
       const Future<Option<int> >& status_)
   {
@@ -574,8 +598,10 @@ private:
 
     cout << message << " (pid: " << pid << ")" << endl;
 
+    CHECK_SOME(taskId);
+
     TaskStatus taskStatus;
-    taskStatus.mutable_task_id()->MergeFrom(taskId);
+    taskStatus.mutable_task_id()->MergeFrom(taskId.get());
     taskStatus.set_state(taskState);
     taskStatus.set_message(message);
     if (killed && killedByHealthCheck) {
@@ -671,6 +697,8 @@ private:
   Duration escalationTimeout;
   Timer escalationTimer;
   Option<ExecutorDriver*> driver;
+  Option<FrameworkInfo> frameworkInfo;
+  Option<TaskID> taskId;
   string healthCheckDir;
   Option<char**> override;
   Option<string> sandboxDirectory;


[11/11] mesos git commit: Added TASK_KILLING to the API changes in the CHANGELOG.

Posted by bm...@apache.org.
Added TASK_KILLING to the API changes in the CHANGELOG.


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

Branch: refs/heads/master
Commit: 1488f16d283f69b7dc96feaee91b04a09012ca4a
Parents: 978ccb5
Author: Benjamin Mahler <bm...@apache.org>
Authored: Sat Feb 20 17:35:30 2016 +0100
Committer: Benjamin Mahler <bm...@apache.org>
Committed: Sat Feb 20 17:35:30 2016 +0100

----------------------------------------------------------------------
 CHANGELOG | 1 +
 1 file changed, 1 insertion(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/1488f16d/CHANGELOG
----------------------------------------------------------------------
diff --git a/CHANGELOG b/CHANGELOG
index 004978f..e6cc39b 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -4,6 +4,7 @@ Release Notes - Mesos - Version 0.28.0 (WIP)
 ** API Changes:
   * [MESOS-4066] - Agent should not return partial state when a request is made to /state endpoint during recovery.
   * [MESOS-4479] - Implement reservation labels.
+  * [MESOS-4547] - Introduce TASK_KILLING state.
 
 
 Release Notes - Mesos - Version 0.27.1


[03/11] mesos git commit: Minor cleanup for TaskState comments.

Posted by bm...@apache.org.
Minor cleanup for TaskState comments.


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

Branch: refs/heads/master
Commit: de4094daa141d24691b81a2c41eef67ceee8d661
Parents: 1bd0663
Author: Benjamin Mahler <bm...@apache.org>
Authored: Sat Feb 20 13:06:03 2016 +0100
Committer: Benjamin Mahler <bm...@apache.org>
Committed: Sat Feb 20 14:22:19 2016 +0100

----------------------------------------------------------------------
 include/mesos/mesos.proto    | 12 ++++++------
 include/mesos/v1/mesos.proto | 12 ++++++------
 2 files changed, 12 insertions(+), 12 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/de4094da/include/mesos/mesos.proto
----------------------------------------------------------------------
diff --git a/include/mesos/mesos.proto b/include/mesos/mesos.proto
index 5078da4..debc59d 100644
--- a/include/mesos/mesos.proto
+++ b/include/mesos/mesos.proto
@@ -1215,7 +1215,7 @@ message TaskInfo {
  * another task).
  */
 enum TaskState {
-  TASK_STAGING = 6; // Initial state. Framework status updates should not use.
+  TASK_STAGING = 6;  // Initial state. Framework status updates should not use.
   TASK_STARTING = 0; // The task is being launched by the executor.
   TASK_RUNNING = 1;
 
@@ -1223,11 +1223,11 @@ enum TaskState {
   // the TASK_KILLING_STATE capability.
   TASK_KILLING = 8;  // The task is being killed by the executor.
 
-  TASK_FINISHED = 2; // TERMINAL. The task finished successfully.
-  TASK_FAILED = 3; // TERMINAL. The task failed to finish successfully.
-  TASK_KILLED = 4; // TERMINAL. The task was killed by the executor.
-  TASK_LOST = 5; // TERMINAL. The task failed but can be rescheduled.
-  TASK_ERROR = 7; // TERMINAL. The task description contains an error.
+  TASK_FINISHED = 2; // TERMINAL: The task finished successfully.
+  TASK_FAILED = 3;   // TERMINAL: The task failed to finish successfully.
+  TASK_KILLED = 4;   // TERMINAL: The task was killed by the executor.
+  TASK_LOST = 5;     // TERMINAL: The task failed but can be rescheduled.
+  TASK_ERROR = 7;    // TERMINAL: The task description contains an error.
 }
 
 

http://git-wip-us.apache.org/repos/asf/mesos/blob/de4094da/include/mesos/v1/mesos.proto
----------------------------------------------------------------------
diff --git a/include/mesos/v1/mesos.proto b/include/mesos/v1/mesos.proto
index a1da4a0..61c3d94 100644
--- a/include/mesos/v1/mesos.proto
+++ b/include/mesos/v1/mesos.proto
@@ -1116,7 +1116,7 @@ message TaskInfo {
  * another task).
  */
 enum TaskState {
-  TASK_STAGING = 6; // Initial state. Framework status updates should not use.
+  TASK_STAGING = 6;  // Initial state. Framework status updates should not use.
   TASK_STARTING = 0; // The task is being launched by the executor.
   TASK_RUNNING = 1;
 
@@ -1124,11 +1124,11 @@ enum TaskState {
   // the TASK_KILLING_STATE capability.
   TASK_KILLING = 8;  // The task is being killed by the executor.
 
-  TASK_FINISHED = 2; // TERMINAL. The task finished successfully.
-  TASK_FAILED = 3; // TERMINAL. The task failed to finish successfully.
-  TASK_KILLED = 4; // TERMINAL. The task was killed by the executor.
-  TASK_LOST = 5; // TERMINAL. The task failed but can be rescheduled.
-  TASK_ERROR = 7; // TERMINAL. The task description contains an error.
+  TASK_FINISHED = 2; // TERMINAL: The task finished successfully.
+  TASK_FAILED = 3;   // TERMINAL: The task failed to finish successfully.
+  TASK_KILLED = 4;   // TERMINAL: The task was killed by the executor.
+  TASK_LOST = 5;     // TERMINAL: The task failed but can be rescheduled.
+  TASK_ERROR = 7;    // TERMINAL: The task description contains an error.
 }
 
 


[02/11] mesos git commit: Added a comment to explain TASK_STARTING.

Posted by bm...@apache.org.
Added a comment to explain TASK_STARTING.


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

Branch: refs/heads/master
Commit: 1bd06637cf75068006df72b4e8bc5433b8e6090c
Parents: 022be0a
Author: Benjamin Mahler <bm...@apache.org>
Authored: Sat Feb 20 13:04:52 2016 +0100
Committer: Benjamin Mahler <bm...@apache.org>
Committed: Sat Feb 20 14:18:35 2016 +0100

----------------------------------------------------------------------
 include/mesos/mesos.proto    | 2 +-
 include/mesos/v1/mesos.proto | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/1bd06637/include/mesos/mesos.proto
----------------------------------------------------------------------
diff --git a/include/mesos/mesos.proto b/include/mesos/mesos.proto
index 70e380a..5078da4 100644
--- a/include/mesos/mesos.proto
+++ b/include/mesos/mesos.proto
@@ -1216,7 +1216,7 @@ message TaskInfo {
  */
 enum TaskState {
   TASK_STAGING = 6; // Initial state. Framework status updates should not use.
-  TASK_STARTING = 0;
+  TASK_STARTING = 0; // The task is being launched by the executor.
   TASK_RUNNING = 1;
 
   // NOTE: This should only be sent when the framework has

http://git-wip-us.apache.org/repos/asf/mesos/blob/1bd06637/include/mesos/v1/mesos.proto
----------------------------------------------------------------------
diff --git a/include/mesos/v1/mesos.proto b/include/mesos/v1/mesos.proto
index 6271d2a..a1da4a0 100644
--- a/include/mesos/v1/mesos.proto
+++ b/include/mesos/v1/mesos.proto
@@ -1117,7 +1117,7 @@ message TaskInfo {
  */
 enum TaskState {
   TASK_STAGING = 6; // Initial state. Framework status updates should not use.
-  TASK_STARTING = 0;
+  TASK_STARTING = 0; // The task is being launched by the executor.
   TASK_RUNNING = 1;
 
   // NOTE: This should only be sent when the framework has


[06/11] mesos git commit: Added missing assertions to MasterTest.StateEndpointFrameworkInfo.

Posted by bm...@apache.org.
Added missing assertions to MasterTest.StateEndpointFrameworkInfo.

The MasterTest.StateEndpointFrameworkInfo test can crash when the
assumed JSON types do not hold. Rather, we should assert the type
before using JSON::Value::as, so that the test fails rather than
crashing the program.


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

Branch: refs/heads/master
Commit: c893c9f8e7fd9fb3f1668e0f065318b8196c0f7e
Parents: a99a205
Author: Benjamin Mahler <bm...@apache.org>
Authored: Sat Feb 20 14:00:23 2016 +0100
Committer: Benjamin Mahler <bm...@apache.org>
Committed: Sat Feb 20 17:32:23 2016 +0100

----------------------------------------------------------------------
 src/tests/master_tests.cpp | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/c893c9f8/src/tests/master_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/master_tests.cpp b/src/tests/master_tests.cpp
index 7cf04a2..0bd8c0e 100644
--- a/src/tests/master_tests.cpp
+++ b/src/tests/master_tests.cpp
@@ -2948,13 +2948,14 @@ TEST_F(MasterTest, StateEndpointFrameworkInfo)
   JSON::Array frameworks = object->values["frameworks"].as<JSON::Array>();
 
   EXPECT_EQ(1u, frameworks.values.size());
+  ASSERT_TRUE(frameworks.values.front().is<JSON::Object>());
+
   JSON::Object framework = frameworks.values.front().as<JSON::Object>();
 
   EXPECT_EQ(1u, framework.values.count("webui_url"));
-  JSON::String webui_url =
-    framework.values["webui_url"].as<JSON::String>();
-
-  EXPECT_EQ("http://localhost:8080/", webui_url.value);
+  ASSERT_TRUE(framework.values["webui_url"].is<JSON::String>());
+  EXPECT_EQ("http://localhost:8080/",
+            framework.values["webui_url"].as<JSON::String>().value);
 
   EXPECT_EQ(1u, framework.values.count("capabilities"));
   ASSERT_TRUE(framework.values["capabilities"].is<JSON::Array>());


[05/11] mesos git commit: Added a framework capability to guard TASK_KILLING.

Posted by bm...@apache.org.
Added a framework capability to guard TASK_KILLING.

Frameworks must opt-in to receive TASK_KILLING. For now, it will be
entirely the responsibility of the executor to check the capability
before sending a TASK_KILLING update.

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


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

Branch: refs/heads/master
Commit: cae9162a198a4a298fee920c57dbd128731529e2
Parents: de4094d
Author: Abhishek Dasgupta <a1...@linux.vnet.ibm.com>
Authored: Sat Feb 20 13:09:16 2016 +0100
Committer: Benjamin Mahler <bm...@apache.org>
Committed: Sat Feb 20 14:22:20 2016 +0100

----------------------------------------------------------------------
 include/mesos/mesos.proto    |  5 +++++
 include/mesos/v1/mesos.proto |  5 +++++
 src/tests/master_tests.cpp   | 33 ++++++++++++++++++++++++++-------
 3 files changed, 36 insertions(+), 7 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/cae9162a/include/mesos/mesos.proto
----------------------------------------------------------------------
diff --git a/include/mesos/mesos.proto b/include/mesos/mesos.proto
index debc59d..11a71cb 100644
--- a/include/mesos/mesos.proto
+++ b/include/mesos/mesos.proto
@@ -262,6 +262,11 @@ message FrameworkInfo {
       // message for details.
       // TODO(vinod): This is currently a no-op.
       REVOCABLE_RESOURCES = 1;
+
+      // Receive the TASK_KILLING TaskState when a task is being
+      // killed by an executor. The executor will examine this
+      // capability to determine whether it can send TASK_KILLING.
+      TASK_KILLING_STATE = 2;
     }
 
     required Type type = 1;

http://git-wip-us.apache.org/repos/asf/mesos/blob/cae9162a/include/mesos/v1/mesos.proto
----------------------------------------------------------------------
diff --git a/include/mesos/v1/mesos.proto b/include/mesos/v1/mesos.proto
index 61c3d94..84e933e 100644
--- a/include/mesos/v1/mesos.proto
+++ b/include/mesos/v1/mesos.proto
@@ -262,6 +262,11 @@ message FrameworkInfo {
       // message for details.
       // TODO(vinod): This is currently a no-op.
       REVOCABLE_RESOURCES = 1;
+
+      // Receive the TASK_KILLING TaskState when a task is being
+      // killed by an executor. The executor will examine this
+      // capability to determine whether it can send TASK_KILLING.
+      TASK_KILLING_STATE = 2;
     }
 
     required Type type = 1;

http://git-wip-us.apache.org/repos/asf/mesos/blob/cae9162a/src/tests/master_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/master_tests.cpp b/src/tests/master_tests.cpp
index 393a6f5f..01b82df 100644
--- a/src/tests/master_tests.cpp
+++ b/src/tests/master_tests.cpp
@@ -3016,8 +3016,15 @@ TEST_F(MasterTest, FrameworkWebUIUrlandCapabilities)
 
   FrameworkInfo framework = DEFAULT_FRAMEWORK_INFO;
   framework.set_webui_url("http://localhost:8080/");
-  auto capabilityType = FrameworkInfo::Capability::REVOCABLE_RESOURCES;
-  framework.add_capabilities()->set_type(capabilityType);
+
+  vector<FrameworkInfo::Capability::Type> capabilities = {
+    FrameworkInfo::Capability::REVOCABLE_RESOURCES,
+    FrameworkInfo::Capability::TASK_KILLING_STATE
+  };
+
+  foreach (FrameworkInfo::Capability::Type capability, capabilities) {
+    framework.add_capabilities()->set_type(capability);
+  }
 
   MockScheduler sched;
   MesosSchedulerDriver driver(
@@ -3054,12 +3061,24 @@ TEST_F(MasterTest, FrameworkWebUIUrlandCapabilities)
   EXPECT_EQ("http://localhost:8080/", webui_url.value);
 
   EXPECT_EQ(1u, framework_.values.count("capabilities"));
-  JSON::Array capabilities =
-    framework_.values["capabilities"].as<JSON::Array>();
-  JSON::String capability = capabilities.values.front().as<JSON::String>();
+  ASSERT_TRUE(framework_.values["capabilities"].is<JSON::Array>());
+
+  vector<FrameworkInfo::Capability::Type> actual;
+
+  foreach (const JSON::Value& capability,
+           framework_.values["capabilities"].as<JSON::Array>().values) {
+    FrameworkInfo::Capability::Type type;
+
+    ASSERT_TRUE(capability.is<JSON::String>());
+    ASSERT_TRUE(
+        FrameworkInfo::Capability::Type_Parse(
+            capability.as<JSON::String>().value,
+            &type));
+
+    actual.push_back(type);
+  }
 
-  EXPECT_EQ(FrameworkInfo::Capability::Type_Name(capabilityType),
-            capability.value);
+  EXPECT_EQ(capabilities, actual);
 
   driver.stop();
   driver.join();


[04/11] mesos git commit: Generalization and cleanup of MasterTest.FrameworkWebUIUrlandCapabilities.

Posted by bm...@apache.org.
Generalization and cleanup of MasterTest.FrameworkWebUIUrlandCapabilities.


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

Branch: refs/heads/master
Commit: a99a2059689537f0af3bc4746f1ffda1572910e1
Parents: cae9162
Author: Benjamin Mahler <bm...@apache.org>
Authored: Sat Feb 20 13:56:31 2016 +0100
Committer: Benjamin Mahler <bm...@apache.org>
Committed: Sat Feb 20 14:22:20 2016 +0100

----------------------------------------------------------------------
 src/tests/master_tests.cpp | 160 ++++++++++++++++++++--------------------
 1 file changed, 79 insertions(+), 81 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/a99a2059/src/tests/master_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/master_tests.cpp b/src/tests/master_tests.cpp
index 01b82df..7cf04a2 100644
--- a/src/tests/master_tests.cpp
+++ b/src/tests/master_tests.cpp
@@ -2904,6 +2904,85 @@ TEST_F(MasterTest, StateEndpoint)
 }
 
 
+// This test ensures that the framework's information is included in
+// the master's state endpoint.
+//
+// TODO(bmahler): This only looks at capabilities and the webui URL
+// currently; add more to this test.
+TEST_F(MasterTest, StateEndpointFrameworkInfo)
+{
+  Try<PID<Master>> master = StartMaster();
+  ASSERT_SOME(master);
+
+  FrameworkInfo frameworkInfo = DEFAULT_FRAMEWORK_INFO;
+  frameworkInfo.set_webui_url("http://localhost:8080/");
+
+  vector<FrameworkInfo::Capability::Type> capabilities = {
+    FrameworkInfo::Capability::REVOCABLE_RESOURCES,
+    FrameworkInfo::Capability::TASK_KILLING_STATE
+  };
+
+  foreach (FrameworkInfo::Capability::Type capability, capabilities) {
+    frameworkInfo.add_capabilities()->set_type(capability);
+  }
+
+  MockScheduler sched;
+  MesosSchedulerDriver driver(
+      &sched, frameworkInfo, master.get(), DEFAULT_CREDENTIAL);
+
+  Future<Nothing> registered;
+  EXPECT_CALL(sched, registered(&driver, _, _))
+    .WillOnce(FutureSatisfy(&registered));
+
+  driver.start();
+
+  AWAIT_READY(registered);
+
+  Future<Response> response = process::http::get(master.get(), "state");
+  AWAIT_EXPECT_RESPONSE_STATUS_EQ(OK().status, response);
+
+  Try<JSON::Object> object = JSON::parse<JSON::Object>(response->body);
+  ASSERT_SOME(object);
+
+  EXPECT_EQ(1u, object->values.count("frameworks"));
+  JSON::Array frameworks = object->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("webui_url"));
+  JSON::String webui_url =
+    framework.values["webui_url"].as<JSON::String>();
+
+  EXPECT_EQ("http://localhost:8080/", webui_url.value);
+
+  EXPECT_EQ(1u, framework.values.count("capabilities"));
+  ASSERT_TRUE(framework.values["capabilities"].is<JSON::Array>());
+
+  vector<FrameworkInfo::Capability::Type> actual;
+
+  foreach (const JSON::Value& capability,
+           framework.values["capabilities"].as<JSON::Array>().values) {
+    FrameworkInfo::Capability::Type type;
+
+    ASSERT_TRUE(capability.is<JSON::String>());
+    ASSERT_TRUE(
+        FrameworkInfo::Capability::Type_Parse(
+            capability.as<JSON::String>().value,
+            &type));
+
+    actual.push_back(type);
+  }
+
+  EXPECT_EQ(capabilities, actual);
+
+  driver.stop();
+  driver.join();
+
+  Shutdown();
+}
+
+
 TEST_F(MasterTest, StateSummaryEndpoint)
 {
   master::Flags flags = CreateMasterFlags();
@@ -3006,87 +3085,6 @@ TEST_F(MasterTest, StateSummaryEndpoint)
 }
 
 
-// This test ensures that the web UI and capabilities of a framework
-// are included in the master's state endpoint, if provided by the
-// framework.
-TEST_F(MasterTest, FrameworkWebUIUrlandCapabilities)
-{
-  Try<PID<Master>> master = StartMaster();
-  ASSERT_SOME(master);
-
-  FrameworkInfo framework = DEFAULT_FRAMEWORK_INFO;
-  framework.set_webui_url("http://localhost:8080/");
-
-  vector<FrameworkInfo::Capability::Type> capabilities = {
-    FrameworkInfo::Capability::REVOCABLE_RESOURCES,
-    FrameworkInfo::Capability::TASK_KILLING_STATE
-  };
-
-  foreach (FrameworkInfo::Capability::Type capability, capabilities) {
-    framework.add_capabilities()->set_type(capability);
-  }
-
-  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<Response> masterState = process::http::get(master.get(), "state");
-  AWAIT_EXPECT_RESPONSE_STATUS_EQ(OK().status, masterState);
-
-  Try<JSON::Object> parse = JSON::parse<JSON::Object>(masterState.get().body);
-  ASSERT_SOME(parse);
-
-  // We need a mutable copy of parse to use [].
-  JSON::Object masterStateObject = parse.get();
-
-  EXPECT_EQ(1u, masterStateObject.values.count("frameworks"));
-  JSON::Array frameworks =
-    masterStateObject.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("webui_url"));
-  JSON::String webui_url =
-    framework_.values["webui_url"].as<JSON::String>();
-
-  EXPECT_EQ("http://localhost:8080/", webui_url.value);
-
-  EXPECT_EQ(1u, framework_.values.count("capabilities"));
-  ASSERT_TRUE(framework_.values["capabilities"].is<JSON::Array>());
-
-  vector<FrameworkInfo::Capability::Type> actual;
-
-  foreach (const JSON::Value& capability,
-           framework_.values["capabilities"].as<JSON::Array>().values) {
-    FrameworkInfo::Capability::Type type;
-
-    ASSERT_TRUE(capability.is<JSON::String>());
-    ASSERT_TRUE(
-        FrameworkInfo::Capability::Type_Parse(
-            capability.as<JSON::String>().value,
-            &type));
-
-    actual.push_back(type);
-  }
-
-  EXPECT_EQ(capabilities, actual);
-
-  driver.stop();
-  driver.join();
-
-  Shutdown();
-}
-
-
 // This test verifies that label values are exposed over the master's
 // state endpoint.
 TEST_F(MasterTest, TaskLabels)


[08/11] mesos git commit: Added docker executor tests for TASK_KILLING.

Posted by bm...@apache.org.
Added docker executor tests for TASK_KILLING.


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

Branch: refs/heads/master
Commit: 978ccb5dd637f0e1577ecae1e21973f50429b04c
Parents: ee86b13
Author: Benjamin Mahler <bm...@apache.org>
Authored: Sat Feb 20 17:28:58 2016 +0100
Committer: Benjamin Mahler <bm...@apache.org>
Committed: Sat Feb 20 17:32:26 2016 +0100

----------------------------------------------------------------------
 .../docker_containerizer_tests.cpp              | 128 +++++++++++++++++++
 1 file changed, 128 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/978ccb5d/src/tests/containerizer/docker_containerizer_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/containerizer/docker_containerizer_tests.cpp b/src/tests/containerizer/docker_containerizer_tests.cpp
index 2b96e41..a299c9e 100644
--- a/src/tests/containerizer/docker_containerizer_tests.cpp
+++ b/src/tests/containerizer/docker_containerizer_tests.cpp
@@ -670,6 +670,134 @@ TEST_F(DockerContainerizerTest, ROOT_DOCKER_Kill)
 }
 
 
+// Ensures that the framework will receive a TASK_KILLING update
+// before TASK_KILLED, if the capability is supported.
+TEST_F(DockerContainerizerTest, ROOT_DOCKER_TaskKillingCapability)
+{
+  Try<PID<Master> > master = StartMaster();
+  ASSERT_SOME(master);
+
+  MockDocker* mockDocker =
+    new MockDocker(tests::flags.docker, tests::flags.docker_socket);
+
+  Shared<Docker> docker(mockDocker);
+
+  slave::Flags flags = CreateSlaveFlags();
+
+  Fetcher fetcher;
+
+  Try<ContainerLogger*> logger =
+    ContainerLogger::create(flags.container_logger);
+
+  ASSERT_SOME(logger);
+
+  MockDockerContainerizer dockerContainerizer(
+      flags,
+      &fetcher,
+      Owned<ContainerLogger>(logger.get()),
+      docker);
+
+  Try<PID<Slave> > slave = StartSlave(&dockerContainerizer, flags);
+  ASSERT_SOME(slave);
+
+  // Start the framework with the task killing capability.
+  FrameworkInfo::Capability capability;
+  capability.set_type(FrameworkInfo::Capability::TASK_KILLING_STATE);
+
+  FrameworkInfo frameworkInfo = DEFAULT_FRAMEWORK_INFO;
+  frameworkInfo.add_capabilities()->CopyFrom(capability);
+
+  MockScheduler sched;
+  MesosSchedulerDriver driver(
+      &sched, frameworkInfo, master.get(), DEFAULT_CREDENTIAL);
+
+  Future<FrameworkID> frameworkId;
+  EXPECT_CALL(sched, registered(&driver, _, _))
+    .WillOnce(FutureArg<1>(&frameworkId));
+
+  Future<vector<Offer> > offers;
+  EXPECT_CALL(sched, resourceOffers(&driver, _))
+    .WillOnce(FutureArg<1>(&offers))
+    .WillRepeatedly(Return()); // Ignore subsequent offers.
+
+  driver.start();
+
+  AWAIT_READY(frameworkId);
+
+  AWAIT_READY(offers);
+  ASSERT_NE(0u, offers.get().size());
+
+  const Offer& offer = offers.get()[0];
+
+  SlaveID slaveId = offer.slave_id();
+
+  TaskInfo task;
+  task.set_name("");
+  task.mutable_task_id()->set_value("1");
+  task.mutable_slave_id()->CopyFrom(offer.slave_id());
+  task.mutable_resources()->CopyFrom(offer.resources());
+
+  CommandInfo command;
+  command.set_value("sleep 1000");
+
+  ContainerInfo containerInfo;
+  containerInfo.set_type(ContainerInfo::DOCKER);
+
+  // TODO(tnachen): Use local image to test if possible.
+  ContainerInfo::DockerInfo dockerInfo;
+  dockerInfo.set_image("alpine");
+  containerInfo.mutable_docker()->CopyFrom(dockerInfo);
+
+  task.mutable_command()->CopyFrom(command);
+  task.mutable_container()->CopyFrom(containerInfo);
+
+  Future<ContainerID> containerId;
+  EXPECT_CALL(dockerContainerizer, launch(_, _, _, _, _, _, _, _))
+    .WillOnce(DoAll(FutureArg<0>(&containerId),
+                    Invoke(&dockerContainerizer,
+                           &MockDockerContainerizer::_launch)));
+
+  Future<TaskStatus> statusRunning;
+  EXPECT_CALL(sched, statusUpdate(&driver, _))
+    .WillOnce(FutureArg<1>(&statusRunning));
+
+  driver.launchTasks(offers.get()[0].id(), {task});
+
+  AWAIT_READY_FOR(containerId, Seconds(60));
+  AWAIT_READY_FOR(statusRunning, Seconds(60));
+  EXPECT_EQ(TASK_RUNNING, statusRunning->state());
+
+  ASSERT_TRUE(
+    exists(docker, slaveId, containerId.get(), ContainerState::RUNNING));
+
+  Future<TaskStatus> statusKilling, statusKilled;
+  EXPECT_CALL(sched, statusUpdate(&driver, _))
+    .WillOnce(FutureArg<1>(&statusKilling))
+    .WillOnce(FutureArg<1>(&statusKilled));
+
+  Future<containerizer::Termination> termination =
+    dockerContainerizer.wait(containerId.get());
+
+  driver.killTask(task.task_id());
+
+  AWAIT_READY(statusKilling);
+  EXPECT_EQ(TASK_KILLING, statusKilling->state());
+
+  AWAIT_READY(statusKilled);
+  EXPECT_EQ(TASK_KILLED, statusKilled->state());
+
+  AWAIT_READY(termination);
+
+  ASSERT_FALSE(
+    exists(docker, slaveId, containerId.get(), ContainerState::RUNNING));
+
+  driver.stop();
+  driver.join();
+
+  Shutdown();
+}
+
+
 // This test tests DockerContainerizer::usage().
 TEST_F(DockerContainerizerTest, ROOT_DOCKER_Usage)
 {


[07/11] mesos git commit: Added command executor tests for TASK_KILLING.

Posted by bm...@apache.org.
Added command executor tests for TASK_KILLING.


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

Branch: refs/heads/master
Commit: ee86b13633a9469629dbd79681d0776b6020f76a
Parents: 25d303d
Author: Benjamin Mahler <bm...@apache.org>
Authored: Sat Feb 20 16:18:22 2016 +0100
Committer: Benjamin Mahler <bm...@apache.org>
Committed: Sat Feb 20 17:32:26 2016 +0100

----------------------------------------------------------------------
 src/Makefile.am                      |   1 +
 src/tests/command_executor_tests.cpp | 180 ++++++++++++++++++++++++++++++
 2 files changed, 181 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/ee86b136/src/Makefile.am
----------------------------------------------------------------------
diff --git a/src/Makefile.am b/src/Makefile.am
index 27aec37..73e7ff0 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1803,6 +1803,7 @@ mesos_tests_SOURCES =						\
   tests/authentication_tests.cpp				\
   tests/authorization_tests.cpp					\
   tests/cluster.cpp						\
+  tests/command_executor_tests.cpp				\
   tests/container_logger_tests.cpp				\
   tests/containerizer.cpp					\
   tests/cram_md5_authentication_tests.cpp			\

http://git-wip-us.apache.org/repos/asf/mesos/blob/ee86b136/src/tests/command_executor_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/command_executor_tests.cpp b/src/tests/command_executor_tests.cpp
new file mode 100644
index 0000000..0d2fcf6
--- /dev/null
+++ b/src/tests/command_executor_tests.cpp
@@ -0,0 +1,180 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <vector>
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include <mesos/mesos.hpp>
+
+#include <process/future.hpp>
+#include <process/gmock.hpp>
+#include <process/gtest.hpp>
+#include <process/pid.hpp>
+
+#include <stout/gtest.hpp>
+
+#include "master/master.hpp"
+
+#include "slave/slave.hpp"
+
+#include "tests/mesos.hpp"
+
+using mesos::internal::master::Master;
+
+using mesos::internal::slave::Slave;
+
+using process::Future;
+using process::PID;
+
+using std::vector;
+
+namespace mesos {
+namespace internal {
+namespace tests {
+
+// Tests that exercise the command executor implementation
+// should be located in this file.
+
+class CommandExecutorTest : public MesosTest {};
+
+
+// This test ensures that the command executor does not send
+// TASK_KILLING to frameworks that do not support the capability.
+TEST_F(CommandExecutorTest, NoTaskKillingCapability)
+{
+  Try<PID<Master>> master = StartMaster();
+  ASSERT_SOME(master);
+
+  Try<PID<Slave>> slave = StartSlave();
+  ASSERT_SOME(slave);
+
+  // Start the framework without the task killing capability.
+  MockScheduler sched;
+  MesosSchedulerDriver driver(
+      &sched, DEFAULT_FRAMEWORK_INFO, master.get(), DEFAULT_CREDENTIAL);
+
+  EXPECT_CALL(sched, registered(&driver, _, _));
+
+  Future<vector<Offer>> offers;
+  EXPECT_CALL(sched, resourceOffers(&driver, _))
+    .WillOnce(FutureArg<1>(&offers))
+    .WillRepeatedly(Return()); // Ignore subsequent offers.
+
+  driver.start();
+
+  AWAIT_READY(offers);
+  EXPECT_EQ(1u, offers->size());
+
+  // Launch a task with the command executor.
+  TaskInfo task = createTask(
+      offers->front().slave_id(),
+      offers->front().resources(),
+      "sleep 1000");
+
+  Future<TaskStatus> statusRunning;
+  EXPECT_CALL(sched, statusUpdate(_, _))
+    .WillOnce(FutureArg<1>(&statusRunning));
+
+  driver.launchTasks(offers->front().id(), {task});
+
+  AWAIT_READY(statusRunning);
+  EXPECT_EQ(TASK_RUNNING, statusRunning->state());
+
+  // There should only be a TASK_KILLED update.
+  Future<TaskStatus> statusKilled;
+  EXPECT_CALL(sched, statusUpdate(_, _))
+    .WillOnce(FutureArg<1>(&statusKilled));
+
+  driver.killTask(task.task_id());
+
+  AWAIT_READY(statusKilled);
+  EXPECT_EQ(TASK_KILLED, statusKilled->state());
+
+  driver.stop();
+  driver.join();
+}
+
+
+// This test ensures that the command executor sends TASK_KILLING
+// to frameworks that support the capability.
+TEST_F(CommandExecutorTest, TaskKillingCapability)
+{
+  Try<PID<Master>> master = StartMaster();
+  ASSERT_SOME(master);
+
+  Try<PID<Slave>> slave = StartSlave();
+  ASSERT_SOME(slave);
+
+  // Start the framework with the task killing capability.
+  FrameworkInfo::Capability capability;
+  capability.set_type(FrameworkInfo::Capability::TASK_KILLING_STATE);
+
+  FrameworkInfo frameworkInfo = DEFAULT_FRAMEWORK_INFO;
+  frameworkInfo.add_capabilities()->CopyFrom(capability);
+
+  MockScheduler sched;
+  MesosSchedulerDriver driver(
+      &sched, frameworkInfo, master.get(), DEFAULT_CREDENTIAL);
+
+  EXPECT_CALL(sched, registered(&driver, _, _));
+
+  Future<vector<Offer>> offers;
+  EXPECT_CALL(sched, resourceOffers(&driver, _))
+    .WillOnce(FutureArg<1>(&offers))
+    .WillRepeatedly(Return()); // Ignore subsequent offers.
+
+  driver.start();
+
+  AWAIT_READY(offers);
+  EXPECT_EQ(1u, offers->size());
+
+  // Launch a task with the command executor.
+  TaskInfo task = createTask(
+      offers->front().slave_id(),
+      offers->front().resources(),
+      "sleep 1000");
+
+  Future<TaskStatus> statusRunning;
+  EXPECT_CALL(sched, statusUpdate(_, _))
+    .WillOnce(FutureArg<1>(&statusRunning));
+
+  driver.launchTasks(offers->front().id(), {task});
+
+  AWAIT_READY(statusRunning);
+  EXPECT_EQ(TASK_RUNNING, statusRunning->state());
+
+  Future<TaskStatus> statusKilling, statusKilled;
+  EXPECT_CALL(sched, statusUpdate(_, _))
+    .WillOnce(FutureArg<1>(&statusKilling))
+    .WillOnce(FutureArg<1>(&statusKilled));
+
+  driver.killTask(task.task_id());
+
+  AWAIT_READY(statusKilling);
+  EXPECT_EQ(TASK_KILLING, statusKilling->state());
+
+  AWAIT_READY(statusKilled);
+  EXPECT_EQ(TASK_KILLED, statusKilled->state());
+
+  driver.stop();
+  driver.join();
+}
+
+} // namespace tests {
+} // namespace internal {
+} // namespace mesos {