mesos-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From nniel...@apache.org
Subject git commit: Added user field to CommandInfo.
Date Thu, 08 May 2014 19:41:40 GMT
Repository: mesos
Updated Branches:
  refs/heads/master 0febc2e21 -> 23d717741


Added user field to CommandInfo.

Enables individual executors and tasks to run as a specific user. If
the user field is present both in FrameworkInfo and here, the
CommandInfo user value takes precedence.

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


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

Branch: refs/heads/master
Commit: 23d717741df7ca291270b762b7b93a37b4a144ef
Parents: 0febc2e
Author: Niklas Q. Nielsen <niklas@mesosphere.io>
Authored: Thu May 8 12:23:37 2014 -0700
Committer: Niklas Q. Nielsen <niklas@mesosphere.io>
Committed: Thu May 8 12:26:01 2014 -0700

----------------------------------------------------------------------
 include/mesos/mesos.proto |   5 ++
 src/slave/slave.cpp       |  12 +++-
 src/tests/slave_tests.cpp | 158 +++++++++++++++++++++++++++++++++++++++++
 3 files changed, 173 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/23d71774/include/mesos/mesos.proto
----------------------------------------------------------------------
diff --git a/include/mesos/mesos.proto b/include/mesos/mesos.proto
index e48e50a..bcf841a 100644
--- a/include/mesos/mesos.proto
+++ b/include/mesos/mesos.proto
@@ -163,6 +163,11 @@ message CommandInfo {
   // NOTE: MesosContainerizer does currently not support this attribute
   // and tasks supplying a 'container' will fail.
   optional ContainerInfo container = 4;
+
+  // Enables executor and tasks to run as a specific user. If the user
+  // field is present both in FrameworkInfo and here, the CommandInfo
+  // user value takes precedence.
+  optional string user = 5;
 }
 
 

http://git-wip-us.apache.org/repos/asf/mesos/blob/23d71774/src/slave/slave.cpp
----------------------------------------------------------------------
diff --git a/src/slave/slave.cpp b/src/slave/slave.cpp
index a7c0e4d..ba4bd73 100644
--- a/src/slave/slave.cpp
+++ b/src/slave/slave.cpp
@@ -3144,6 +3144,14 @@ Executor* Framework::launchExecutor(
   ExecutorInfo executorInfo_ = executor->info;
   executorInfo_.mutable_resources()->MergeFrom(taskInfo.resources());
 
+  // The command (either in form of task or executor command) can
+  // define a specific user to run as. If present, this precedes the
+  // framework user value.
+  string user = info.user();
+  if (executor->info.command().has_user()) {
+    user = executor->info.command().user();
+  }
+
   // Launch the container.
   Future<Nothing> launch;
   if (!executor->commandExecutor) {
@@ -3155,7 +3163,7 @@ Executor* Framework::launchExecutor(
         containerId,
         executorInfo_, // modified to include the task's resources
         executor->directory,
-        slave->flags.switch_user ? Option<string>(info.user()) : None(),
+        slave->flags.switch_user ? Option<string>(user) : None(),
         slave->info.id(),
         slave->self(),
         info.checkpoint());
@@ -3173,7 +3181,7 @@ Executor* Framework::launchExecutor(
         taskInfo,
         executorInfo_,
         executor->directory,
-        slave->flags.switch_user ? Option<string>(info.user()) : None(),
+        slave->flags.switch_user ? Option<string>(user) : None(),
         slave->info.id(),
         slave->self(),
         info.checkpoint());

http://git-wip-us.apache.org/repos/asf/mesos/blob/23d71774/src/tests/slave_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/slave_tests.cpp b/src/tests/slave_tests.cpp
index 0982455..6526952 100644
--- a/src/tests/slave_tests.cpp
+++ b/src/tests/slave_tests.cpp
@@ -247,3 +247,161 @@ TEST_F(SlaveTest, RemoveUnregisteredTerminatedExecutor)
   Shutdown(); // Must shutdown before 'containerizer' gets deallocated.
 }
 
+
+// This test runs a command without the command user field set. The
+// command will verify the assumption that the command is run as the
+// slave user (in this case, root).
+TEST_F(SlaveTest, ROOT_RunTaskWithCommandInfoWithoutUser)
+{
+  Try<PID<Master> > master = StartMaster();
+  ASSERT_SOME(master);
+
+  // Need flags for 'executor_registration_timeout'.
+  slave::Flags flags = CreateSlaveFlags();
+  flags.isolation = "posix/cpu,posix/mem";
+
+  Try<MesosContainerizer*> containerizer =
+    MesosContainerizer::create(flags, false);
+  CHECK_SOME(containerizer);
+
+  Try<PID<Slave> > slave = StartSlave(containerizer.get());
+  ASSERT_SOME(slave);
+
+  MockScheduler sched;
+  MesosSchedulerDriver driver(
+      &sched, DEFAULT_FRAMEWORK_INFO, master.get(), DEFAULT_CREDENTIAL);
+
+  EXPECT_CALL(sched, registered(&driver, _, _))
+    .Times(1);
+
+  Future<vector<Offer> > offers;
+  EXPECT_CALL(sched, resourceOffers(&driver, _))
+    .WillOnce(FutureArg<1>(&offers))
+    .WillRepeatedly(Return()); // Ignore subsequent offers.
+
+  driver.start();
+
+  AWAIT_READY(offers);
+  EXPECT_NE(0u, offers.get().size());
+
+  // Launch a task with the command executor.
+  TaskInfo task;
+  task.set_name("");
+  task.mutable_task_id()->set_value("1");
+  task.mutable_slave_id()->MergeFrom(offers.get()[0].slave_id());
+  task.mutable_resources()->MergeFrom(offers.get()[0].resources());
+
+  // Command executor will run as user running test.
+  string user = os::user();
+
+  CommandInfo command;
+  command.set_value("test `whoami` = " + user);
+
+  task.mutable_command()->MergeFrom(command);
+
+  vector<TaskInfo> tasks;
+  tasks.push_back(task);
+
+  Future<TaskStatus> statusRunning;
+  Future<TaskStatus> statusFinished;
+  EXPECT_CALL(sched, statusUpdate(&driver, _))
+    .WillOnce(FutureArg<1>(&statusRunning))
+    .WillOnce(FutureArg<1>(&statusFinished));
+
+  driver.launchTasks(offers.get()[0].id(), tasks);
+
+  AWAIT_READY(statusRunning);
+  EXPECT_EQ(TASK_RUNNING, statusRunning.get().state());
+
+  AWAIT_READY(statusFinished);
+  EXPECT_EQ(TASK_FINISHED, statusFinished.get().state());
+
+  driver.stop();
+  driver.join();
+
+  Shutdown(); // Must shutdown before 'containerizer' gets deallocated.
+}
+
+
+// This test runs a command _with_ the command user field set. The
+// command will very the assumption that the command is run as the
+// specified user. We use (and assume the precense) of the
+// unprivileged 'nobody' user which should be available on both Linux
+// and Mac OS X.
+TEST_F(SlaveTest, ROOT_RunTaskWithCommandInfoWithUser)
+{
+  // TODO(nnielsen): Introduce STOUT abstraction for user verification
+  // instead of flat getpwnam call.
+  const string testUser = "nobody";
+  if (::getpwnam(testUser.c_str()) == NULL) {
+    LOG(WARNING) << "Cannot run ROOT_RunTaskWithCommandInfoWithUser test:"
+                 << " user '" << testUser << "' is not present";
+    return;
+  }
+
+  Try<PID<Master> > master = StartMaster();
+  ASSERT_SOME(master);
+
+  // Need flags for 'executor_registration_timeout'.
+  slave::Flags flags = CreateSlaveFlags();
+  flags.isolation = "posix/cpu,posix/mem";
+
+  Try<MesosContainerizer*> containerizer =
+    MesosContainerizer::create(flags, false);
+  CHECK_SOME(containerizer);
+
+  Try<PID<Slave> > slave = StartSlave(containerizer.get());
+  ASSERT_SOME(slave);
+
+  MockScheduler sched;
+  MesosSchedulerDriver driver(
+      &sched, DEFAULT_FRAMEWORK_INFO, master.get(), DEFAULT_CREDENTIAL);
+
+  EXPECT_CALL(sched, registered(&driver, _, _))
+    .Times(1);
+
+  Future<vector<Offer> > offers;
+  EXPECT_CALL(sched, resourceOffers(&driver, _))
+    .WillOnce(FutureArg<1>(&offers))
+    .WillRepeatedly(Return()); // Ignore subsequent offers.
+
+  driver.start();
+
+  AWAIT_READY(offers);
+  EXPECT_NE(0u, offers.get().size());
+
+  // Launch a task with the command executor.
+  TaskInfo task;
+  task.set_name("");
+  task.mutable_task_id()->set_value("1");
+  task.mutable_slave_id()->MergeFrom(offers.get()[0].slave_id());
+  task.mutable_resources()->MergeFrom(offers.get()[0].resources());
+
+  CommandInfo command;
+  command.set_value("test `whoami` = " + testUser);
+  command.set_user(testUser);
+
+  task.mutable_command()->MergeFrom(command);
+
+  vector<TaskInfo> tasks;
+  tasks.push_back(task);
+
+  Future<TaskStatus> statusRunning;
+  Future<TaskStatus> statusFinished;
+  EXPECT_CALL(sched, statusUpdate(&driver, _))
+    .WillOnce(FutureArg<1>(&statusRunning))
+    .WillOnce(FutureArg<1>(&statusFinished));
+
+  driver.launchTasks(offers.get()[0].id(), tasks);
+
+  AWAIT_READY(statusRunning);
+  EXPECT_EQ(TASK_RUNNING, statusRunning.get().state());
+
+  AWAIT_READY(statusFinished);
+  EXPECT_EQ(TASK_FINISHED, statusFinished.get().state());
+
+  driver.stop();
+  driver.join();
+
+  Shutdown(); // Must shutdown before 'containerizer' gets deallocated.
+}


Mime
View raw message