You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mesos.apache.org by qi...@apache.org on 2017/11/01 11:54:48 UTC

[1/5] mesos git commit: Added a test `ROOT_DOCKER_NoTransitionFromKillingToFinished`.

Repository: mesos
Updated Branches:
  refs/heads/master 816518867 -> 815263ead


Added a test `ROOT_DOCKER_NoTransitionFromKillingToFinished`.

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


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

Branch: refs/heads/master
Commit: f569aeee31ec7a9b9352fad729c6bdd7ef592f48
Parents: 8e3cb6a
Author: Qian Zhang <zh...@gmail.com>
Authored: Wed Oct 4 15:44:41 2017 +0800
Committer: Qian Zhang <zh...@gmail.com>
Committed: Wed Nov 1 15:34:10 2017 +0800

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


http://git-wip-us.apache.org/repos/asf/mesos/blob/f569aeee/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 419be5d..ad05da6 100644
--- a/src/tests/containerizer/docker_containerizer_tests.cpp
+++ b/src/tests/containerizer/docker_containerizer_tests.cpp
@@ -4137,6 +4137,129 @@ TEST_F(DockerContainerizerTest, ROOT_DOCKER_NoTransitionFromKillingToRunning)
 }
 
 
+// This test ensures that a task will transition from `TASK_KILLING`
+// to `TASK_KILLED` rather than `TASK_FINISHED` when it is killed,
+// even if it returns an "EXIT_STATUS" of 0 on receiving a SIGTERM.
+TEST_F(DockerContainerizerTest, ROOT_DOCKER_NoTransitionFromKillingToFinished)
+{
+  Shared<Docker> docker(new MockDocker(
+      tests::flags.docker, tests::flags.docker_socket));
+
+  Try<Owned<cluster::Master>> master = StartMaster();
+  ASSERT_SOME(master);
+
+  slave::Flags agentFlags = CreateSlaveFlags();
+
+  Fetcher fetcher(agentFlags);
+
+  Try<ContainerLogger*> logger =
+    ContainerLogger::create(agentFlags.container_logger);
+
+  ASSERT_SOME(logger);
+
+  MockDockerContainerizer containerizer(
+      agentFlags,
+      &fetcher,
+      Owned<ContainerLogger>(logger.get()),
+      docker);
+
+  Owned<MasterDetector> detector = master.get()->createDetector();
+
+  Try<Owned<cluster::Slave>> agent =
+    StartSlave(detector.get(), &containerizer, agentFlags);
+
+  ASSERT_SOME(agent);
+
+  // 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()->pid, 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());
+
+  const Offer& offer = offers.get()[0];
+
+  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_shell(false);
+
+  ContainerInfo containerInfo;
+  containerInfo.set_type(ContainerInfo::DOCKER);
+
+  // The "nginx:alpine" container returns an "EXIT_STATUS" of 0 on
+  // receiving a SIGTERM.
+  //
+  // TODO(tnachen): Use local image to test if possible.
+  ContainerInfo::DockerInfo dockerInfo;
+  dockerInfo.set_image("nginx:alpine");
+  containerInfo.mutable_docker()->CopyFrom(dockerInfo);
+
+  task.mutable_command()->CopyFrom(command);
+  task.mutable_container()->CopyFrom(containerInfo);
+
+  Future<ContainerID> containerId;
+  EXPECT_CALL(containerizer, launch(_, _, _, _))
+    .WillOnce(DoAll(FutureArg<0>(&containerId),
+                    Invoke(&containerizer,
+                           &MockDockerContainerizer::_launch)));
+
+  Future<TaskStatus> statusRunning;
+  Future<TaskStatus> statusKilling;
+  Future<TaskStatus> statusKilled;
+
+  EXPECT_CALL(sched, statusUpdate(&driver, _))
+    .WillOnce(FutureArg<1>(&statusRunning))
+    .WillOnce(FutureArg<1>(&statusKilling))
+    .WillOnce(FutureArg<1>(&statusKilled));
+
+  driver.launchTasks(offers->front().id(), {task});
+
+  AWAIT_READY_FOR(containerId, Seconds(60));
+  AWAIT_READY_FOR(statusRunning, Seconds(60));
+  EXPECT_EQ(TASK_RUNNING, statusRunning->state());
+
+  // Docker executor will call "docker stop ..." to send SIGTERM
+  // to kill the task.
+  driver.killTask(task.task_id());
+
+  AWAIT_READY(statusKilling);
+  EXPECT_EQ(TASK_KILLING, statusKilling->state());
+
+  AWAIT_READY(statusKilled);
+  EXPECT_EQ(TASK_KILLED, statusKilled->state());
+
+  Future<Option<ContainerTermination>> termination =
+    containerizer.wait(containerId.get());
+
+  driver.stop();
+  driver.join();
+
+  AWAIT_READY(termination);
+  EXPECT_SOME(termination.get());
+}
+
+
 // This test ensures that when `cgroups_enable_cfs` is set on agent,
 // the docker container launched through docker containerizer has
 // `cpuQuotas` limit.


[3/5] mesos git commit: Updated the comments of TASK_FINISHED to make it more clear.

Posted by qi...@apache.org.
Updated the comments of TASK_FINISHED to make it more clear.

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


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

Branch: refs/heads/master
Commit: ce83476449a0c2cfa6d192b4d017d302d92fea7b
Parents: 8165188
Author: Qian Zhang <zh...@gmail.com>
Authored: Fri Sep 29 15:28:58 2017 +0800
Committer: Qian Zhang <zh...@gmail.com>
Committed: Wed Nov 1 15:34:10 2017 +0800

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


http://git-wip-us.apache.org/repos/asf/mesos/blob/ce834764/include/mesos/mesos.proto
----------------------------------------------------------------------
diff --git a/include/mesos/mesos.proto b/include/mesos/mesos.proto
index 4966cd2..68a5538 100644
--- a/include/mesos/mesos.proto
+++ b/include/mesos/mesos.proto
@@ -2110,7 +2110,9 @@ 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.
+  // The task finished successfully on its own without external interference.
+  TASK_FINISHED = 2; // TERMINAL.
+
   TASK_FAILED = 3;   // TERMINAL: The task failed to finish successfully.
   TASK_KILLED = 4;   // TERMINAL: The task was killed by the executor.
   TASK_ERROR = 7;    // TERMINAL: The task description contains an error.

http://git-wip-us.apache.org/repos/asf/mesos/blob/ce834764/include/mesos/v1/mesos.proto
----------------------------------------------------------------------
diff --git a/include/mesos/v1/mesos.proto b/include/mesos/v1/mesos.proto
index e18ac00..c46cec7 100644
--- a/include/mesos/v1/mesos.proto
+++ b/include/mesos/v1/mesos.proto
@@ -2091,7 +2091,9 @@ 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.
+  // The task finished successfully on its own without external interference.
+  TASK_FINISHED = 2; // TERMINAL.
+
   TASK_FAILED = 3;   // TERMINAL: The task failed to finish successfully.
   TASK_KILLED = 4;   // TERMINAL: The task was killed by the executor.
   TASK_ERROR = 7;    // TERMINAL: The task description contains an error.


[2/5] mesos git commit: Checked TASK_KILLED in the test `ROOT_INTERNET_CURL_PortMapper`.

Posted by qi...@apache.org.
Checked TASK_KILLED in the test `ROOT_INTERNET_CURL_PortMapper`.

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


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

Branch: refs/heads/master
Commit: 8e3cb6ae6ca7d25fe768467ecc0a65f7509fce43
Parents: 0449a08
Author: Qian Zhang <zh...@gmail.com>
Authored: Thu Sep 14 17:33:05 2017 +0800
Committer: Qian Zhang <zh...@gmail.com>
Committed: Wed Nov 1 15:34:10 2017 +0800

----------------------------------------------------------------------
 src/tests/containerizer/cni_isolator_tests.cpp | 8 +-------
 1 file changed, 1 insertion(+), 7 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/8e3cb6ae/src/tests/containerizer/cni_isolator_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/containerizer/cni_isolator_tests.cpp b/src/tests/containerizer/cni_isolator_tests.cpp
index 5a2af59..0d68dd6 100644
--- a/src/tests/containerizer/cni_isolator_tests.cpp
+++ b/src/tests/containerizer/cni_isolator_tests.cpp
@@ -1802,13 +1802,7 @@ TEST_F(CniIsolatorPortMapperTest, ROOT_INTERNET_CURL_PortMapper)
 
   AWAIT_READY(statusKilled);
 
-  // The executor would issue a SIGTERM to the container, followed by
-  // a SIGKILL (in case the container ignores the SIGTERM). The
-  // "nginx:alpine" container returns an "EXIT_STATUS" of 0 on
-  // receiving a SIGTERM making the executor send a `TASK_FINISHED`
-  // instead of a `TASK_KILLED`, hence checking for `TASK_FINISHED`
-  // instead of `TASK_KILLED`.
-  EXPECT_EQ(TASK_FINISHED, statusKilled.get().state());
+  EXPECT_EQ(TASK_KILLED, statusKilled.get().state());
 
   AWAIT_READY(gcSchedule);
 


[5/5] mesos git commit: Added a test `ROOT_NoTransitionFromKillingToFinished`.

Posted by qi...@apache.org.
Added a test `ROOT_NoTransitionFromKillingToFinished`.

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


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

Branch: refs/heads/master
Commit: 815263ead42f64fd0ff320614cfada30b2e8f899
Parents: f569aee
Author: Qian Zhang <zh...@gmail.com>
Authored: Wed Oct 4 23:38:11 2017 +0800
Committer: Qian Zhang <zh...@gmail.com>
Committed: Wed Nov 1 17:21:45 2017 +0800

----------------------------------------------------------------------
 src/tests/default_executor_tests.cpp  | 181 +++++++++++++++++++++++++++++
 src/tests/kill_policy_test_helper.cpp |   9 ++
 2 files changed, 190 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/815263ea/src/tests/default_executor_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/default_executor_tests.cpp b/src/tests/default_executor_tests.cpp
index f485b61..21950f5 100644
--- a/src/tests/default_executor_tests.cpp
+++ b/src/tests/default_executor_tests.cpp
@@ -48,6 +48,7 @@
 
 #include "tests/cluster.hpp"
 #include "tests/containerizer.hpp"
+#include "tests/kill_policy_test_helper.hpp"
 #include "tests/mesos.hpp"
 
 #include "slave/containerizer/mesos/containerizer.hpp"
@@ -1409,6 +1410,186 @@ TEST_P(DefaultExecutorTest, SigkillExecutor)
 }
 
 
+// This test verifies that a task will transition from `TASK_KILLING`
+// to `TASK_KILLED` rather than `TASK_FINISHED` when it is killed,
+// even if it returns an "EXIT_STATUS" of 0 on receiving a SIGTERM.
+TEST_P(DefaultExecutorTest, ROOT_NoTransitionFromKillingToFinished)
+{
+  Try<Owned<cluster::Master>> master = StartMaster();
+  ASSERT_SOME(master);
+
+  slave::Flags flags = CreateSlaveFlags();
+  flags.containerizers = GetParam();
+
+  Fetcher fetcher(flags);
+
+  Try<MesosContainerizer*> create =
+    MesosContainerizer::create(flags, true, &fetcher);
+
+  ASSERT_SOME(create);
+
+  Owned<Containerizer> containerizer(create.get());
+
+  Owned<MasterDetector> detector = master.get()->createDetector();
+
+  Try<Owned<cluster::Slave>> slave = StartSlave(
+        detector.get(),
+        containerizer.get(),
+        flags);
+
+  ASSERT_SOME(slave);
+
+  auto scheduler = std::make_shared<v1::MockHTTPScheduler>();
+
+  // Start the framework with the task killing capability.
+  v1::FrameworkInfo::Capability capability;
+  capability.set_type(v1::FrameworkInfo::Capability::TASK_KILLING_STATE);
+
+  v1::FrameworkInfo frameworkInfo = v1::DEFAULT_FRAMEWORK_INFO;
+  frameworkInfo.add_capabilities()->CopyFrom(capability);
+
+  EXPECT_CALL(*scheduler, connected(_))
+    .WillOnce(v1::scheduler::SendSubscribe(frameworkInfo));
+
+  Future<v1::scheduler::Event::Subscribed> subscribed;
+  EXPECT_CALL(*scheduler, subscribed(_, _))
+    .WillOnce(FutureArg<1>(&subscribed));
+
+  Future<v1::scheduler::Event::Offers> offers;
+  EXPECT_CALL(*scheduler, offers(_, _))
+    .WillOnce(FutureArg<1>(&offers))
+    .WillRepeatedly(Return()); // Ignore subsequent offers.
+
+  EXPECT_CALL(*scheduler, heartbeat(_))
+    .WillRepeatedly(Return()); // Ignore heartbeats.
+
+  v1::scheduler::TestMesos mesos(
+      master.get()->pid,
+      ContentType::PROTOBUF,
+      scheduler);
+
+  AWAIT_READY(subscribed);
+  v1::FrameworkID frameworkId(subscribed->framework_id());
+
+  v1::ExecutorInfo executorInfo = v1::createExecutorInfo(
+      v1::DEFAULT_EXECUTOR_ID,
+      None(),
+      "cpus:0.1;mem:32;disk:32",
+      v1::ExecutorInfo::DEFAULT,
+      frameworkId);
+
+  AWAIT_READY(offers);
+  ASSERT_FALSE(offers->offers().empty());
+
+  const v1::Offer& offer = offers->offers(0);
+  const v1::AgentID& agentId = offer.agent_id();
+
+  v1::CommandInfo commandInfo;
+  commandInfo.set_shell(false);
+  commandInfo.set_value(getTestHelperPath("test-helper"));
+  commandInfo.add_arguments("test-helper");
+  commandInfo.add_arguments(KillPolicyTestHelper::NAME);
+  commandInfo.add_arguments("--sleep_duration=0");
+
+  v1::TaskInfo taskInfo = v1::createTask(
+      agentId,
+      v1::Resources::parse("cpus:0.1;mem:32;disk:32").get(),
+      commandInfo);
+
+  Future<v1::scheduler::Event::Update> startingUpdate;
+  Future<v1::scheduler::Event::Update> runningUpdate;
+  EXPECT_CALL(*scheduler, update(_, _))
+    .WillOnce(
+        DoAll(
+            FutureArg<1>(&startingUpdate),
+            v1::scheduler::SendAcknowledge(frameworkId, agentId)))
+    .WillOnce(
+        DoAll(
+            FutureArg<1>(&runningUpdate),
+            v1::scheduler::SendAcknowledge(frameworkId, agentId)));
+
+  mesos.send(
+      v1::createCallAccept(
+          frameworkId,
+          offer,
+          {v1::LAUNCH_GROUP(
+              executorInfo, v1::createTaskGroupInfo({taskInfo}))}));
+
+  AWAIT_READY(startingUpdate);
+  ASSERT_EQ(TASK_STARTING, startingUpdate->status().state());
+
+  AWAIT_READY_FOR(runningUpdate, Seconds(60));
+  ASSERT_EQ(TASK_RUNNING, runningUpdate->status().state());
+  ASSERT_EQ(taskInfo.task_id(), runningUpdate->status().task_id());
+
+  v1::ContainerStatus status = runningUpdate->status().container_status();
+
+  ASSERT_TRUE(status.has_container_id());
+  EXPECT_TRUE(status.container_id().has_parent());
+
+  v1::ContainerID executorContainerId = status.container_id().parent();
+
+  Future<Option<ContainerTermination>> wait =
+    containerizer->wait(devolve(executorContainerId));
+
+  string executorSandbox = slave::paths::getExecutorLatestRunPath(
+      flags.work_dir,
+      devolve(agentId),
+      devolve(frameworkId),
+      devolve(executorInfo.executor_id()));
+
+  string filePath = path::join(
+      executorSandbox,
+      "tasks",
+      taskInfo.task_id().value(),
+      KillPolicyTestHelper::NAME);
+
+  // Wait up to 5 seconds for the `test-helper` program to create a file into
+  // its sandbox which is a signal that the task has been fully started.
+  Duration waited = Duration::zero();
+  do {
+    if (os::exists(filePath)) {
+      break;
+    }
+
+    os::sleep(Seconds(1));
+    waited += Seconds(1);
+  } while (waited < Seconds(5));
+
+  EXPECT_TRUE(os::exists(filePath));
+
+  Future<v1::scheduler::Event::Update> killingUpdate;
+  Future<v1::scheduler::Event::Update> killedUpdate;
+  EXPECT_CALL(*scheduler, update(_, _))
+    .WillOnce(
+        DoAll(
+            FutureArg<1>(&killingUpdate),
+            v1::scheduler::SendAcknowledge(frameworkId, agentId)))
+    .WillOnce(
+        DoAll(
+            FutureArg<1>(&killedUpdate),
+              v1::scheduler::SendAcknowledge(frameworkId, agentId)));
+
+  // Now kill the task in the task group, the default executor will
+  // call the agent to send SIGTERM to the container. The `test-helper`
+  // program will return an "EXIT_STATUS" of 0 on receiving a SIGTERM.
+  mesos.send(v1::createCallKill(frameworkId, taskInfo.task_id()));
+
+  AWAIT_READY(killingUpdate);
+  ASSERT_EQ(TASK_KILLING, killingUpdate->status().state());
+  ASSERT_EQ(taskInfo.task_id(), killingUpdate->status().task_id());
+
+  AWAIT_READY(killedUpdate);
+  ASSERT_EQ(TASK_KILLED, killedUpdate->status().state());
+  ASSERT_EQ(taskInfo.task_id(), killedUpdate->status().task_id());
+
+  AWAIT_READY(wait);
+  ASSERT_SOME(wait.get());
+  ASSERT_TRUE(wait.get()->has_status());
+  ASSERT_EQ(0, wait.get()->status());
+}
+
+
 #ifdef __linux__
 // This test verifies that tasks from two different
 // task groups can share the same pid namespace.

http://git-wip-us.apache.org/repos/asf/mesos/blob/815263ea/src/tests/kill_policy_test_helper.cpp
----------------------------------------------------------------------
diff --git a/src/tests/kill_policy_test_helper.cpp b/src/tests/kill_policy_test_helper.cpp
index a188059..28768a3 100644
--- a/src/tests/kill_policy_test_helper.cpp
+++ b/src/tests/kill_policy_test_helper.cpp
@@ -58,6 +58,15 @@ int KillPolicyTestHelper::execute()
   action.sa_handler = sigtermHandler;
   sigaction(SIGTERM, &action, nullptr);
 
+  // Create a file in the sandbox which can be considered as
+  // a signal that this test helper has been fully started.
+  Try<Nothing> touch = os::touch(KillPolicyTestHelper::NAME);
+  if (touch.isError()) {
+    std::cerr << "Failed to create file '" << KillPolicyTestHelper::NAME
+              << "': " << touch.error() << std::endl;
+    return EXIT_FAILURE;
+  }
+
   // Block the process until we get a signal.
   pause();
 


[4/5] mesos git commit: Always send TASK_KILLED when the task is killed by a framework.

Posted by qi...@apache.org.
Always send TASK_KILLED when the task is killed by a framework.

This change is done for command, docker and default executors.

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


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

Branch: refs/heads/master
Commit: 0449a0840d154fc169fb0b1d866d8c6b87ca5eae
Parents: ce83476
Author: Qian Zhang <zh...@gmail.com>
Authored: Thu Sep 14 17:29:39 2017 +0800
Committer: Qian Zhang <zh...@gmail.com>
Committed: Wed Nov 1 15:34:10 2017 +0800

----------------------------------------------------------------------
 src/docker/executor.cpp           | 6 +++---
 src/launcher/default_executor.cpp | 6 +++---
 src/launcher/executor.cpp         | 6 +++---
 3 files changed, 9 insertions(+), 9 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/0449a084/src/docker/executor.cpp
----------------------------------------------------------------------
diff --git a/src/docker/executor.cpp b/src/docker/executor.cpp
index 5f6a0d0..3974f20 100644
--- a/src/docker/executor.cpp
+++ b/src/docker/executor.cpp
@@ -524,9 +524,7 @@ private:
       CHECK(WIFEXITED(status) || WIFSIGNALED(status))
         << "Unexpected wait status " << status;
 
-      if (WSUCCEEDED(status)) {
-        state = TASK_FINISHED;
-      } else if (killed) {
+      if (killed) {
         // Send TASK_KILLED if the task was killed as a result of
         // kill() or shutdown(). Note that in general there is a
         // race between signaling the container and it terminating
@@ -536,6 +534,8 @@ private:
         // determine whether the container was terminated via
         // our signal or terminated on its own.
         state = TASK_KILLED;
+      } else if (WSUCCEEDED(status)) {
+        state = TASK_FINISHED;
       } else {
         state = TASK_FAILED;
       }

http://git-wip-us.apache.org/repos/asf/mesos/blob/0449a084/src/launcher/default_executor.cpp
----------------------------------------------------------------------
diff --git a/src/launcher/default_executor.cpp b/src/launcher/default_executor.cpp
index 3064052..248c46d 100644
--- a/src/launcher/default_executor.cpp
+++ b/src/launcher/default_executor.cpp
@@ -827,12 +827,12 @@ protected:
       CHECK(WIFEXITED(status) || WIFSIGNALED(status))
         << "Unexpected wait status " << status;
 
-      if (WSUCCEEDED(status)) {
-        taskState = TASK_FINISHED;
-      } else if (container->killing) {
+      if (container->killing) {
         // Send TASK_KILLED if the task was killed as a result of
         // `killTask()` or `shutdown()`.
         taskState = TASK_KILLED;
+      } else if (WSUCCEEDED(status)) {
+        taskState = TASK_FINISHED;
       } else {
         taskState = TASK_FAILED;
       }

http://git-wip-us.apache.org/repos/asf/mesos/blob/0449a084/src/launcher/executor.cpp
----------------------------------------------------------------------
diff --git a/src/launcher/executor.cpp b/src/launcher/executor.cpp
index 34f6f7a..c688c04 100644
--- a/src/launcher/executor.cpp
+++ b/src/launcher/executor.cpp
@@ -913,12 +913,12 @@ private:
       CHECK(WIFEXITED(status) || WIFSIGNALED(status))
         << "Unexpected wait status " << status;
 
-      if (WSUCCEEDED(status)) {
-        taskState = TASK_FINISHED;
-      } else if (killed) {
+      if (killed) {
         // Send TASK_KILLED if the task was killed as a result of
         // kill() or shutdown().
         taskState = TASK_KILLED;
+      } else if (WSUCCEEDED(status)) {
+        taskState = TASK_FINISHED;
       } else {
         taskState = TASK_FAILED;
       }