You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mesos.apache.org by vi...@apache.org on 2015/06/11 02:17:07 UTC

[2/3] mesos git commit: Added task validation for revocable resources.

Added task validation for revocable resources.

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


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

Branch: refs/heads/master
Commit: c6a9fff39e6ab625560894cf727bce54cd785113
Parents: 7840d32
Author: Vinod Kone <vi...@gmail.com>
Authored: Mon Jun 1 10:14:17 2015 -0700
Committer: Vinod Kone <vi...@gmail.com>
Committed: Wed Jun 10 16:55:54 2015 -0700

----------------------------------------------------------------------
 src/master/validation.cpp             | 85 ++++++++++++++++-----------
 src/master/validation.hpp             |  9 +++
 src/slave/slave.cpp                   |  8 ++-
 src/tests/master_validation_tests.cpp | 92 ++++++++++++++++++++++++++++++
 4 files changed, 157 insertions(+), 37 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/c6a9fff3/src/master/validation.cpp
----------------------------------------------------------------------
diff --git a/src/master/validation.cpp b/src/master/validation.cpp
index 6c9dc04..889387d 100644
--- a/src/master/validation.cpp
+++ b/src/master/validation.cpp
@@ -187,6 +187,8 @@ Option<Error> validate(const RepeatedPtrField<Resource>& resources)
 
 namespace task {
 
+namespace internal {
+
 // Validates that a task id is valid, i.e., contains only valid
 // characters.
 Option<Error> validateTaskID(const TaskInfo& task)
@@ -295,33 +297,6 @@ Option<Error> validateCheckpoint(Framework* framework, Slave* slave)
   return None();
 }
 
-// Validates that the resources specified by the framework are valid.
-Option<Error> validateResources(const TaskInfo& task)
-{
-  Option<Error> error = resource::validate(task.resources());
-  if (error.isSome()) {
-    return Error("Task uses invalid resources: " + error.get().message);
-  }
-
-  Resources total = task.resources();
-
-  if (task.has_executor()) {
-    error = resource::validate(task.executor().resources());
-    if (error.isSome()) {
-      return Error("Executor uses invalid resources: " + error.get().message);
-    }
-
-    total += task.executor().resources();
-  }
-
-  error = resource::validateUniquePersistenceID(total);
-  if (error.isSome()) {
-    return error;
-  }
-
-  return None();
-}
-
 
 // Validates that the task and the executor are using proper amount of
 // resources. For instance, the used resources by a task on each slave
@@ -390,6 +365,47 @@ Option<Error> validateResourceUsage(
 }
 
 
+// Validates that the resources specified by the task are valid.
+Option<Error> validateResources(const TaskInfo& task)
+{
+  Option<Error> error = resource::validate(task.resources());
+  if (error.isSome()) {
+    return Error("Task uses invalid resources: " + error.get().message);
+  }
+
+  Resources total = task.resources();
+
+  if (task.has_executor()) {
+    error = resource::validate(task.executor().resources());
+    if (error.isSome()) {
+      return Error("Executor uses invalid resources: " + error.get().message);
+    }
+
+    total += task.executor().resources();
+  }
+
+  // A task and its executor can either use non-revocable resources
+  // or revocable resources of a given name but not both.
+  foreach (const string& name, total.names()) {
+    Resources resources = total.get(name);
+    if (!resources.revocable().empty() &&
+        resources != resources.revocable()) {
+      return Error("Task (and its executor, if exists) uses both revocable and"
+                   " non-revocable " + name);
+    }
+  }
+
+  error = resource::validateUniquePersistenceID(total);
+  if (error.isSome()) {
+    return error;
+  }
+
+  return None();
+}
+
+} // namespace internal {
+
+
 Option<Error> validate(
     const TaskInfo& task,
     Framework* framework,
@@ -404,13 +420,14 @@ Option<Error> validate(
   // assumes that ExecutorInfo is valid which is verified by
   // 'validateExecutorInfo'.
   vector<lambda::function<Option<Error>(void)>> validators = {
-    lambda::bind(validateTaskID, task),
-    lambda::bind(validateUniqueTaskID, task, framework),
-    lambda::bind(validateSlaveID, task, slave),
-    lambda::bind(validateExecutorInfo, task, framework, slave),
-    lambda::bind(validateCheckpoint, framework, slave),
-    lambda::bind(validateResources, task),
-    lambda::bind(validateResourceUsage, task, framework, slave, offered)
+    lambda::bind(internal::validateTaskID, task),
+    lambda::bind(internal::validateUniqueTaskID, task, framework),
+    lambda::bind(internal::validateSlaveID, task, slave),
+    lambda::bind(internal::validateExecutorInfo, task, framework, slave),
+    lambda::bind(internal::validateCheckpoint, framework, slave),
+    lambda::bind(internal::validateResources, task),
+    lambda::bind(
+        internal::validateResourceUsage, task, framework, slave, offered)
   };
 
   // TODO(benh): Add a validateHealthCheck function.

http://git-wip-us.apache.org/repos/asf/mesos/blob/c6a9fff3/src/master/validation.hpp
----------------------------------------------------------------------
diff --git a/src/master/validation.hpp b/src/master/validation.hpp
index a74e844..469d6f5 100644
--- a/src/master/validation.hpp
+++ b/src/master/validation.hpp
@@ -59,6 +59,15 @@ Option<Error> validate(
     Slave* slave,
     const Resources& offered);
 
+
+// Functions in this namespace are only exposed for testing.
+namespace internal {
+
+// Validates resources of the task and executor (if present).
+Option<Error> validateResources(const TaskInfo& task);
+
+} // namespace internal {
+
 } // namespace task {
 
 

http://git-wip-us.apache.org/repos/asf/mesos/blob/c6a9fff3/src/slave/slave.cpp
----------------------------------------------------------------------
diff --git a/src/slave/slave.cpp b/src/slave/slave.cpp
index b9fb929..2eef391 100644
--- a/src/slave/slave.cpp
+++ b/src/slave/slave.cpp
@@ -3098,9 +3098,11 @@ ExecutorInfo Slave::getExecutorInfo(
 
     // Add an allowance for the command executor. This does lead to a
     // small overcommit of resources.
-    //
-    // TODO(bmahler): If revocable resources are used, this leads to
-    // mixing of resources.
+    // TODO(vinod): If a task is using revocable resources, mark the
+    // corresponding executor resource (e.g., cpus) to be also
+    // revocable. Currently, it is OK because the containerizer is
+    // given task + executor resources on task launch resulting in
+    // the container being correctly marked as revocable.
     executor.mutable_resources()->MergeFrom(
         Resources::parse(
           "cpus:" + stringify(DEFAULT_EXECUTOR_CPUS) + ";" +

http://git-wip-us.apache.org/repos/asf/mesos/blob/c6a9fff3/src/tests/master_validation_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/master_validation_tests.cpp b/src/tests/master_validation_tests.cpp
index dc9e91e..dbd5118 100644
--- a/src/tests/master_validation_tests.cpp
+++ b/src/tests/master_validation_tests.cpp
@@ -1100,6 +1100,98 @@ TEST_F(TaskValidationTest, ExecutorInfoDiffersOnDifferentSlaves)
   Shutdown();
 }
 
+
+// This test verifies that a task is not allowed to mix revocable and
+// non-revocable resources.
+TEST_F(TaskValidationTest, TaskUsesRevocableResources)
+{
+  TaskInfo task;
+  task.set_name("");
+  task.mutable_task_id()->set_value("task");
+  task.mutable_slave_id()->set_value("slave");
+
+  // Non-revocable cpus.
+  Resource cpus;
+  cpus.set_name("cpus");
+  cpus.set_type(Value::SCALAR);
+  cpus.mutable_scalar()->set_value(2);
+
+  // A task with only non-revocable cpus is valid.
+  task.add_resources()->CopyFrom(cpus);
+  EXPECT_NONE(task::internal::validateResources(task));
+
+  // Revocable cpus.
+  Resource revocableCpus = cpus;
+  revocableCpus.mutable_revocable();
+
+  // A task with only revocable cpus is valid.
+  task.clear_resources();
+  task.add_resources()->CopyFrom(revocableCpus);
+  EXPECT_NONE(task::internal::validateResources(task));
+
+  // A task with both revocable and non-revocable cpus is invalid.
+  task.clear_resources();
+  task.add_resources()->CopyFrom(cpus);
+  task.add_resources()->CopyFrom(revocableCpus);
+  EXPECT_SOME(task::internal::validateResources(task));
+}
+
+
+// This test verifies that a task and its executor are not allowed to
+// mix revocable and non-revocable resources.
+TEST_F(TaskValidationTest, TaskAndExecutorUseRevocableResources)
+{
+  TaskInfo task;
+  task.set_name("");
+  task.mutable_task_id()->set_value("task");
+  task.mutable_slave_id()->set_value("slave");
+
+  ExecutorInfo executor = DEFAULT_EXECUTOR_INFO;
+
+  // Non-revocable cpus.
+  Resource cpus;
+  cpus.set_name("cpus");
+  cpus.set_type(Value::SCALAR);
+  cpus.mutable_scalar()->set_value(2);
+
+  // A task and executor with only non-revocable cpus is valid.
+  task.add_resources()->CopyFrom(cpus);
+  executor.add_resources()->CopyFrom(cpus);
+  task.mutable_executor()->CopyFrom(executor);
+  EXPECT_NONE(task::internal::validateResources(task));
+
+  // Revocable cpus.
+  Resource revocableCpus = cpus;
+  revocableCpus.mutable_revocable();
+
+  // A task and executor with only revocable cpus is valid.
+  task.clear_resources();
+  task.add_resources()->CopyFrom(revocableCpus);
+  executor.clear_resources();
+  executor.add_resources()->CopyFrom(revocableCpus);
+  task.mutable_executor()->CopyFrom(executor);
+  EXPECT_NONE(task::internal::validateResources(task));
+
+  // A task with revocable cpus and its executor with non-revocable
+  // cpus is invalid.
+  task.clear_resources();
+  task.add_resources()->CopyFrom(revocableCpus);
+  executor.clear_resources();
+  executor.add_resources()->CopyFrom(cpus);
+  task.mutable_executor()->CopyFrom(executor);
+  EXPECT_SOME(task::internal::validateResources(task));
+
+  // A task with non-revocable cpus and its executor with
+  // non-revocable cpus is invalid.
+  task.clear_resources();
+  task.add_resources()->CopyFrom(cpus);
+  executor.clear_resources();
+  executor.add_resources()->CopyFrom(revocableCpus);
+  task.mutable_executor()->CopyFrom(executor);
+  EXPECT_SOME(task::internal::validateResources(task));
+}
+
+
 // TODO(jieyu): Add tests for checking duplicated persistence ID
 // against offered resources.