TEST_F(MesosContainerizerProcessTest, MultipleURIs) { CommandInfo commandInfo; CommandInfo::URI uri; uri.set_value("hdfs:///uri1"); uri.set_executable(false); commandInfo.add_uris()->MergeFrom(uri); uri.set_value("hdfs:///uri2"); uri.set_executable(true); commandInfo.add_uris()->MergeFrom(uri); string directory = "/tmp/directory"; Option<string> user("user"); Flags flags; flags.frameworks_home = "/tmp/frameworks"; flags.hadoop_home = "/tmp/hadoop"; map<string, string> environment = fetcherEnvironment(commandInfo, directory, user, flags); EXPECT_EQ(5u, environment.size()); EXPECT_EQ( "hdfs:///uri1+0X hdfs:///uri2+1X", environment["MESOS_EXECUTOR_URIS"]); EXPECT_EQ(directory, environment["MESOS_WORK_DIRECTORY"]); EXPECT_EQ(user.get(), environment["MESOS_USER"]); EXPECT_EQ(flags.frameworks_home, environment["MESOS_FRAMEWORKS_HOME"]); EXPECT_EQ(flags.hadoop_home, environment["HADOOP_HOME"]); }
TEST_F(FetcherEnvironmentTest, MultipleURIs) { CommandInfo commandInfo; CommandInfo::URI uri; uri.set_value("hdfs:///uri1"); uri.set_executable(false); commandInfo.add_uris()->MergeFrom(uri); uri.set_value("hdfs:///uri2"); uri.set_executable(true); commandInfo.add_uris()->MergeFrom(uri); string directory = "/tmp/directory"; Option<string> user("user"); slave::Flags flags; flags.frameworks_home = "/tmp/frameworks"; flags.hadoop_home = "/tmp/hadoop"; map<string, string> environment = fetcher::environment(commandInfo, directory, user, flags); EXPECT_EQ(5u, environment.size()); EXPECT_EQ(stringify(JSON::Protobuf(commandInfo)), environment["MESOS_COMMAND_INFO"]); EXPECT_EQ(directory, environment["MESOS_WORK_DIRECTORY"]); EXPECT_EQ(user.get(), environment["MESOS_USER"]); EXPECT_EQ(flags.frameworks_home, environment["MESOS_FRAMEWORKS_HOME"]); EXPECT_EQ(flags.hadoop_home, environment["HADOOP_HOME"]); }
Try<Subprocess> run( const string& _command, const Option<string>& rootfs = None()) { slave::MesosContainerizerLaunch::Flags launchFlags; CommandInfo command; command.set_value(_command); launchFlags.command = JSON::Protobuf(command); launchFlags.directory = "/tmp"; launchFlags.pipe_read = open("/dev/zero", O_RDONLY); launchFlags.pipe_write = open("/dev/null", O_WRONLY); launchFlags.rootfs = rootfs; vector<string> argv(2); argv[0] = "mesos-containerizer"; argv[1] = slave::MesosContainerizerLaunch::NAME; Try<Subprocess> s = subprocess( path::join(tests::flags.build_dir, "src", "mesos-containerizer"), argv, Subprocess::PATH("/dev/null"), Subprocess::FD(STDOUT_FILENO), Subprocess::FD(STDERR_FILENO), launchFlags, None(), None(), lambda::bind(&clone, lambda::_1)); close(launchFlags.pipe_read.get()); close(launchFlags.pipe_write.get()); return s; }
TEST_F(FetcherTest, FileLocalhostURI) { string fromDir = path::join(os::getcwd(), "from"); ASSERT_SOME(os::mkdir(fromDir)); string testFile = path::join(fromDir, "test"); EXPECT_FALSE(os::write(testFile, "data").isError()); string localFile = path::join(os::getcwd(), "test"); EXPECT_FALSE(os::exists(localFile)); slave::Flags flags; flags.frameworks_home = "/tmp/frameworks"; CommandInfo commandInfo; CommandInfo::URI* uri = commandInfo.add_uris(); uri->set_value(path::join("file://localhost", testFile)); map<string, string> env = fetcher::environment(commandInfo, os::getcwd(), None(), flags); Try<Subprocess> fetcherProcess = process::subprocess( path::join(mesos::internal::tests::flags.build_dir, "src/mesos-fetcher"), env); ASSERT_SOME(fetcherProcess); Future<Option<int>> status = fetcherProcess.get().status(); AWAIT_READY(status); ASSERT_SOME(status.get()); EXPECT_EQ(0, status.get().get()); EXPECT_TRUE(os::exists(localFile)); }
TEST_F(DockerTest, ROOT_DOCKER_CheckPortResource) { const string containerName = NAME_PREFIX + "-port-resource-test"; Owned<Docker> docker(Docker::create(tests::flags.docker, tests::flags.docker_socket, false).get()); // Make sure the container is removed. Future<Nothing> remove = docker->rm(containerName, true); ASSERT_TRUE(process::internal::await(remove, Seconds(10))); ContainerInfo containerInfo; containerInfo.set_type(ContainerInfo::DOCKER); ContainerInfo::DockerInfo dockerInfo; dockerInfo.set_image("busybox"); dockerInfo.set_network(ContainerInfo::DockerInfo::BRIDGE); ContainerInfo::DockerInfo::PortMapping portMapping; portMapping.set_host_port(10000); portMapping.set_container_port(80); dockerInfo.add_port_mappings()->CopyFrom(portMapping); containerInfo.mutable_docker()->CopyFrom(dockerInfo); CommandInfo commandInfo; commandInfo.set_shell(false); commandInfo.set_value("true"); Resources resources = Resources::parse("ports:[9998-9999];ports:[10001-11000]").get(); Future<Nothing> run = docker->run( containerInfo, commandInfo, containerName, "dir", "/mnt/mesos/sandbox", resources); // Port should be out side of the provided ranges. AWAIT_EXPECT_FAILED(run); resources = Resources::parse("ports:[9998-9999];ports:[10000-11000]").get(); Try<string> directory = environment->mkdtemp(); CHECK_SOME(directory) << "Failed to create temporary directory"; run = docker->run( containerInfo, commandInfo, containerName, directory.get(), "/mnt/mesos/sandbox", resources); AWAIT_READY(run); }
CarsorSelectReAction* MakimonoItem::getSelectReaction(){ // TODO: 巻物のセレクトの実装 CommandInfo* com = new CommandInfo(m_scene); com->addCarsor(new YomuCommand(m_scene)); com->addCarsor(new NageruCommand(m_scene)); com->addCarsor(new OkuCommand(m_scene)); com->addCarsor(new SetumeiCommand(m_scene)); return com; }
CarsorSelectReAction* EatingItem::getSelectReaction(){ CommandInfo* command = new CommandInfo(m_scene); command->addCarsor(new TaberuCommand(m_scene)); command->addCarsor(new NageruCommand(m_scene)); command->addCarsor(new OkuCommand(m_scene)); command->addCarsor(new SetumeiCommand(m_scene)); return command; }
TaskInfo buildTask (string hostname, string id, const SlaveID& slave) { hostProfile profile = hostList[hostname]; // Define the Docker container. /* Since there is no "executor" to manage the tasks, the container will be built and attached directly into the task below */ ContainerInfo container; container.set_type(container.DOCKER); ContainerInfo::DockerInfo docker; docker.set_image(DOCKER_IMAGE); container.mutable_docker()->MergeFrom(docker); // Mount local volume inside Container Volume * volume = container.add_volumes(); volume->set_container_path("/mnt"); volume->set_host_path("/local/mesos"); volume->set_mode(Volume_Mode_RW); // Define the task TaskInfo task; task.set_name("K3-" + k3binary); task.mutable_task_id()->set_value(id); task.mutable_slave_id()->MergeFrom(slave); task.mutable_container()->MergeFrom(container); //task.set_data(stringify(localTasks)); // Define include files for the command CommandInfo command; CommandInfo_URI * k3_bin = command.add_uris(); k3_bin->set_value(fileServer + "/" + k3binary); k3_bin->set_executable(true); k3_bin->set_extract(false); // CommandInfo_URI * k3_args = command.add_uris(); // k3_args->set_value(runpath + "/k3input.yaml"); // command.set_value("$MESOS_SANDBOX/" + k3binary + " -l INFO -p " + // "$MESOS_SANDBOX/k3input.yaml"); task.mutable_command()->MergeFrom(command); // Option A for doing resources management (see scheduler for option B) Resource* resource; resource = task.add_resources(); resource->set_name("cpus"); resource->set_type(Value::SCALAR); resource->mutable_scalar()->set_value(profile.cpu); resource = task.add_resources(); resource->set_name("mem"); resource->set_type(Value::SCALAR); resource->mutable_scalar()->set_value(profile.mem); return task; }
TEST_F(FetcherTest, ExtractNotExecutable) { // First construct a temporary file that can be fetched and archive // with tar gzip. Try<string> path = os::mktemp(); ASSERT_SOME(path); ASSERT_SOME(os::write(path.get(), "hello world")); // TODO(benh): Update os::tar so that we can capture or ignore // stdout/stderr output. ASSERT_SOME(os::tar(path.get(), path.get() + ".tar.gz")); CommandInfo commandInfo; CommandInfo::URI* uri = commandInfo.add_uris(); uri->set_value(path.get() + ".tar.gz"); uri->set_executable(false); uri->set_extract(true); Option<int> stdout = None(); Option<int> stderr = None(); // Redirect mesos-fetcher output if running the tests verbosely. if (tests::flags.verbose) { stdout = STDOUT_FILENO; stderr = STDERR_FILENO; } slave::Flags flags; flags.launcher_dir = path::join(tests::flags.build_dir, "src"); Future<Option<int>> run = fetcher::run(commandInfo, os::getcwd(), None(), flags, stdout, stderr); AWAIT_READY(run); EXPECT_SOME_EQ(0, run.get()); ASSERT_TRUE(os::exists(path::join(".", path.get()))); ASSERT_SOME_EQ("hello world", os::read(path::join(".", path.get()))); Try<os::Permissions> permissions = os::permissions(path::join(".", path.get())); ASSERT_SOME(permissions); EXPECT_FALSE(permissions.get().owner.x); EXPECT_FALSE(permissions.get().group.x); EXPECT_FALSE(permissions.get().others.x); ASSERT_SOME(os::rm(path.get())); }
void offers(const vector<Offer>& offers) { CHECK_EQ(SUBSCRIBED, state); static const Try<Resources> TASK_RESOURCES = Resources::parse(resources); if (TASK_RESOURCES.isError()) { EXIT(EXIT_FAILURE) << "Failed to parse resources '" << resources << "': " << TASK_RESOURCES.error(); } foreach (const Offer& offer, offers) { Resources offered = offer.resources(); if (!launched && offered.flatten().contains(TASK_RESOURCES.get())) { TaskInfo task; task.set_name(name); task.mutable_task_id()->set_value(name); task.mutable_agent_id()->MergeFrom(offer.agent_id()); // Takes resources first from the specified role, then from '*'. Option<Resources> resources = offered.find(TASK_RESOURCES.get().flatten(frameworkInfo.role())); CHECK_SOME(resources); task.mutable_resources()->CopyFrom(resources.get()); CommandInfo* commandInfo = task.mutable_command(); if (shell) { CHECK_SOME(command); commandInfo->set_shell(true); commandInfo->set_value(command.get()); } else { // TODO(gilbert): Treat 'command' as executable value and arguments. commandInfo->set_shell(false); } if (environment.isSome()) { Environment* environment_ = commandInfo->mutable_environment(); foreachpair ( const string& name, const string& value, environment.get()) { Environment::Variable* environmentVariable = environment_->add_variables(); environmentVariable->set_name(name); environmentVariable->set_value(value); } }
common::Error TestArgsInRange(const CommandInfo& cmd, commands_args_t argv) { const size_t argc = argv.size(); const uint16_t max = cmd.GetMaxArgumentsCount(); const uint8_t min = cmd.GetMinArgumentsCount(); if (argc > max || argc < min) { std::string buff = common::MemSPrintf("Invalid input argument for command: '%s', passed %d arguments, must be in range %u - %u.", cmd.name, argc, min, max); return common::make_error(buff); } return common::Error(); }
//-------------------------------------------------------------------------------------------------- static void OnChildSignal ( int sigNum ///< Id of the signal that fired. ) //-------------------------------------------------------------------------------------------------- { pid_t pid; int status; LE_INFO("Child signal received."); // Get the result code from the child process. do { pid = waitpid(-1, &status, WNOHANG | WUNTRACED | WCONTINUED); } while ( (pid < 0) && (errno == EINTR)); LE_DEBUG("Server: Child PID %d, exit status: %d.", pid, status); // Now, if this is the child process we launched earlier, attempt to call the registered // callback. if (pid == Current.pid) { if (Current.handlerPtr != NULL) { Current.handlerPtr(status, Current.contextPtr); } Current.pid = -1; Current.handlerPtr = NULL; Current.contextPtr = NULL; } }
TEST_F(FetcherTest, NoExtractExecutable) { // First construct a temporary file that can be fetched. Try<string> path = os::mktemp(); ASSERT_SOME(path); CommandInfo commandInfo; CommandInfo::URI* uri = commandInfo.add_uris(); uri->set_value(path.get()); uri->set_executable(true); uri->set_extract(false); Option<int> stdout = None(); Option<int> stderr = None(); // Redirect mesos-fetcher output if running the tests verbosely. if (tests::flags.verbose) { stdout = STDOUT_FILENO; stderr = STDERR_FILENO; } slave::Flags flags; flags.launcher_dir = path::join(tests::flags.build_dir, "src"); Future<Option<int>> run = fetcher::run(commandInfo, os::getcwd(), None(), flags, stdout, stderr); AWAIT_READY(run); EXPECT_SOME_EQ(0, run.get()); Try<string> basename = os::basename(path.get()); ASSERT_SOME(basename); Try<os::Permissions> permissions = os::permissions(basename.get()); ASSERT_SOME(permissions); EXPECT_TRUE(permissions.get().owner.x); EXPECT_TRUE(permissions.get().group.x); EXPECT_TRUE(permissions.get().others.x); ASSERT_SOME(os::rm(path.get())); }
vector<TaskInfo> populateTasks( const string& cmd, const string& healthCmd, const Offer& offer, int gracePeriodSeconds = 0, const Option<int>& consecutiveFailures = None(), const Option<map<string, string> >& env = None()) { CommandInfo healthCommand; healthCommand.set_value(healthCmd); return populateTasks( cmd, healthCommand, offer, gracePeriodSeconds, consecutiveFailures, env); }
Future<Option<ContainerLaunchInfo>> LinuxFilesystemIsolatorProcess::prepare( const ContainerID& containerId, const ContainerConfig& containerConfig) { const string& directory = containerConfig.directory(); Option<string> user; if (containerConfig.has_user()) { user = containerConfig.user(); } if (infos.contains(containerId)) { return Failure("Container has already been prepared"); } Owned<Info> info(new Info( directory, containerConfig.executor_info())); infos.put(containerId, info); ContainerLaunchInfo launchInfo; launchInfo.set_namespaces(CLONE_NEWNS); // Prepare the commands that will be run in the container's mount // namespace right after forking the executor process. We use these // commands to mount those volumes specified in the container info // so that they don't pollute the host mount namespace. Try<string> _script = script(containerId, containerConfig); if (_script.isError()) { return Failure("Failed to generate isolation script: " + _script.error()); } CommandInfo* command = launchInfo.add_commands(); command->set_value(_script.get()); return update(containerId, containerConfig.executor_info().resources()) .then([launchInfo]() -> Future<Option<ContainerLaunchInfo>> { return launchInfo; }); }
// This test verifies mounting in an absolute path when running a // docker container works. TEST_F(DockerTest, ROOT_DOCKER_MountAbsolute) { Owned<Docker> docker = Docker::create( tests::flags.docker, tests::flags.docker_socket, false).get(); ContainerInfo containerInfo; containerInfo.set_type(ContainerInfo::DOCKER); Try<string> directory = environment->mkdtemp(); CHECK_SOME(directory) << "Failed to create temporary directory"; const string testFile = path::join(directory.get(), "test_file"); EXPECT_SOME(os::write(testFile, "data")); Volume* volume = containerInfo.add_volumes(); volume->set_host_path(testFile); volume->set_container_path("/tmp/test_file"); volume->set_mode(Volume::RO); ContainerInfo::DockerInfo dockerInfo; dockerInfo.set_image("busybox"); containerInfo.mutable_docker()->CopyFrom(dockerInfo); CommandInfo commandInfo; commandInfo.set_shell(true); commandInfo.set_value("ls /tmp/test_file"); Future<Nothing> run = docker->run( containerInfo, commandInfo, NAME_PREFIX + "-mount-absolute-test", directory.get(), directory.get()); AWAIT_READY(run); }
TEST_F(MesosContainerizerProcessTest, NoUser) { CommandInfo commandInfo; CommandInfo::URI uri; uri.set_value("hdfs:///uri"); uri.set_executable(false); commandInfo.add_uris()->MergeFrom(uri); string directory = "/tmp/directory"; Flags flags; flags.frameworks_home = "/tmp/frameworks"; flags.hadoop_home = "/tmp/hadoop"; map<string, string> environment = fetcherEnvironment(commandInfo, directory, None(), flags); EXPECT_EQ(4u, environment.size()); EXPECT_EQ("hdfs:///uri+0X", environment["MESOS_EXECUTOR_URIS"]); EXPECT_EQ(directory, environment["MESOS_WORK_DIRECTORY"]); EXPECT_EQ(flags.frameworks_home, environment["MESOS_FRAMEWORKS_HOME"]); EXPECT_EQ(flags.hadoop_home, environment["HADOOP_HOME"]); }
TEST_F(FetcherEnvironmentTest, NoHadoop) { CommandInfo commandInfo; CommandInfo::URI* uri = commandInfo.add_uris(); uri->set_value("hdfs:///uri"); uri->set_executable(false); string directory = "/tmp/directory"; Option<string> user = "******"; slave::Flags flags; flags.frameworks_home = "/tmp/frameworks"; map<string, string> environment = fetcher::environment(commandInfo, directory, user, flags); EXPECT_EQ(4u, environment.size()); EXPECT_EQ(stringify(JSON::Protobuf(commandInfo)), environment["MESOS_COMMAND_INFO"]); EXPECT_EQ(directory, environment["MESOS_WORK_DIRECTORY"]); EXPECT_EQ(user.get(), environment["MESOS_USER"]); EXPECT_EQ(flags.frameworks_home, environment["MESOS_FRAMEWORKS_HOME"]); }
vector<TaskInfo> populateTasks( const string& cmd, CommandInfo healthCommand, const Offer& offer, int gracePeriodSeconds = 0, const Option<int>& consecutiveFailures = None(), const Option<map<string, string> >& env = None()) { 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(cmd); Environment::Variable* variable = command.mutable_environment()->add_variables(); // We need to set the correct directory to launch health check process // instead of the default for tests. variable->set_name("MESOS_LAUNCHER_DIR"); variable->set_value(path::join(tests::flags.build_dir, "src")); task.mutable_command()->CopyFrom(command); HealthCheck healthCheck; if (env.isSome()) { foreachpair (const string& name, const string value, env.get()) { Environment::Variable* variable = healthCommand.mutable_environment()->mutable_variables()->Add(); variable->set_name(name); variable->set_value(value); } }
TEST_F(FetcherTest, OSNetUriTest) { HttpProcess process; spawn(process); string url = "http://" + net::getHostname(process.self().node.ip).get() + ":" + stringify(process.self().node.port) + "/help"; string localFile = path::join(os::getcwd(), "help"); EXPECT_FALSE(os::exists(localFile)); slave::Flags flags; flags.frameworks_home = "/tmp/frameworks"; CommandInfo commandInfo; CommandInfo::URI* uri = commandInfo.add_uris(); uri->set_value(url); map<string, string> env = fetcher::environment(commandInfo, os::getcwd(), None(), flags); Try<Subprocess> fetcherProcess = process::subprocess( path::join(mesos::internal::tests::flags.build_dir, "src/mesos-fetcher"), env); ASSERT_SOME(fetcherProcess); Future<Option<int>> status = fetcherProcess.get().status(); AWAIT_READY(status); ASSERT_SOME(status.get()); EXPECT_EQ(0, status.get().get()); EXPECT_TRUE(os::exists(localFile)); }
static Try<Nothing> validateUris(const CommandInfo& commandInfo) { foreach (const CommandInfo::URI& uri, commandInfo.uris()) { Try<Nothing> uriValidation = Fetcher::validateUri(uri.value()); if (uriValidation.isError()) { return Error(uriValidation.error()); } if (uri.has_output_file()) { Try<Nothing> outputFileValidation = Fetcher::validateOutputFile(uri.output_file()); if (outputFileValidation.isError()) { return Error(outputFileValidation.error()); } } } return Nothing(); }
Future<Nothing> Fetcher::fetch( const ContainerID& containerId, const CommandInfo& commandInfo, const string& sandboxDirectory, const Option<string>& user, const SlaveID& slaveId, const Flags& flags) { if (commandInfo.uris().size() == 0) { return Nothing(); } return dispatch(process.get(), &FetcherProcess::fetch, containerId, commandInfo, sandboxDirectory, user, slaveId, flags); }
TEST_F(SlaveTest, ShutdownUnregisteredExecutor) { Try<PID<Master> > master = StartMaster(); ASSERT_SOME(master); // Need flags for 'executor_registration_timeout'. slave::Flags flags = CreateSlaveFlags(); // Set the isolation flag so we know a MesoContainerizer will be created. 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("sleep 10"); task.mutable_command()->MergeFrom(command); vector<TaskInfo> tasks; tasks.push_back(task); // Drop the registration message from the executor to the slave. Future<process::Message> registerExecutor = DROP_MESSAGE(Eq(RegisterExecutorMessage().GetTypeName()), _, _); driver.launchTasks(offers.get()[0].id(), tasks); AWAIT_READY(registerExecutor); Clock::pause(); Future<TaskStatus> status; EXPECT_CALL(sched, statusUpdate(&driver, _)) .WillOnce(FutureArg<1>(&status)); // Ensure that the slave times out and kills the executor. Future<Nothing> destroyExecutor = FUTURE_DISPATCH(_, &MesosContainerizerProcess::destroy); Clock::advance(flags.executor_registration_timeout); AWAIT_READY(destroyExecutor); Clock::settle(); // Wait for Containerizer::destroy to complete. // Now advance time until the reaper reaps the executor. while (status.isPending()) { Clock::advance(Seconds(1)); Clock::settle(); } AWAIT_READY(status); ASSERT_EQ(TASK_FAILED, status.get().state()); Clock::resume(); 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 verify 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, DISABLED_ROOT_RunTaskWithCommandInfoWithUser) { // TODO(nnielsen): Introduce STOUT abstraction for user verification // instead of flat getpwnam call. const string testUser = "******"; 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. }
// 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()); Result<string> user = os::user(); CHECK_SOME(user) << "Failed to get current user name" << (user.isError() ? ": " + user.error() : ""); // Command executor will run as user running test. CommandInfo command; command.set_value("test `whoami` = " + user.get()); 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. }
// Test that we can run the mesos-executor and specify an "override" // command to use via the --override argument. TEST_F(SlaveTest, MesosExecutorWithOverride) { Try<PID<Master> > master = StartMaster(); ASSERT_SOME(master); TestContainerizer containerizer; Try<PID<Slave> > slave = StartSlave(&containerizer); 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("sleep 10"); task.mutable_command()->MergeFrom(command); vector<TaskInfo> tasks; tasks.push_back(task); // Expect the launch and just assume it was sucessful since we'll be // launching the executor ourselves manually below. Future<Nothing> launch; EXPECT_CALL(containerizer, launch(_, _, _, _, _, _, _)) .WillOnce(DoAll(FutureSatisfy(&launch), Return(true))); // Expect wait after launch is called but don't return anything // until after we've finished everything below. Future<Nothing> wait; process::Promise<containerizer::Termination> promise; EXPECT_CALL(containerizer, wait(_)) .WillOnce(DoAll(FutureSatisfy(&wait), Return(promise.future()))); driver.launchTasks(offers.get()[0].id(), tasks); // Once we get the launch the mesos-executor with --override. AWAIT_READY(launch); // Set up fake environment for executor. map<string, string> environment; environment["MESOS_SLAVE_PID"] = stringify(slave.get()); environment["MESOS_SLAVE_ID"] = stringify(offers.get()[0].slave_id()); environment["MESOS_FRAMEWORK_ID"] = stringify(offers.get()[0].framework_id()); environment["MESOS_EXECUTOR_ID"] = stringify(task.task_id()); environment["MESOS_DIRECTORY"] = ""; // Create temporary file to store validation string. If command is // succesfully replaced, this file will end up containing the string // 'Hello World\n'. Otherwise, the original task command i.e. // 'sleep' will be called and the test will fail. Try<std::string> file = os::mktemp(); ASSERT_SOME(file); string executorCommand = path::join(tests::flags.build_dir, "src", "mesos-executor") + " --override -- /bin/sh -c 'echo hello world >" + file.get() + "'"; // Expect two status updates, one for once the mesos-executor says // the task is running and one for after our overridden command // above finishes. Future<TaskStatus> status1, status2; EXPECT_CALL(sched, statusUpdate(_, _)) .WillOnce(FutureArg<1>(&status1)) .WillOnce(FutureArg<1>(&status2)); Try<process::Subprocess> executor = process::subprocess( executorCommand, process::Subprocess::PIPE(), process::Subprocess::PIPE(), process::Subprocess::PIPE(), environment); ASSERT_SOME(executor); // Scheduler should receive the TASK_RUNNING update. AWAIT_READY(status1); ASSERT_EQ(TASK_RUNNING, status1.get().state()); AWAIT_READY(status2); ASSERT_EQ(TASK_FINISHED, status2.get().state()); AWAIT_READY(wait); containerizer::Termination termination; termination.set_killed(false); termination.set_message("Killed executor"); termination.set_status(0); promise.set(termination); driver.stop(); driver.join(); AWAIT_READY(executor.get().status()); // Verify file contents. Try<std::string> validate = os::read(file.get()); ASSERT_SOME(validate); EXPECT_EQ(validate.get(), "hello world\n"); os::rm(file.get()); Shutdown(); }
bool operator == (const CommandInfo& left, const CommandInfo& right) { if (left.uris().size() != right.uris().size()) { return false; } // TODO(vinod): Factor out the comparison for repeated fields. for (int i = 0; i < left.uris().size(); i++) { bool found = false; for (int j = 0; j < right.uris().size(); j++) { if (left.uris().Get(i) == right.uris().Get(j)) { found = true; break; } } if (!found) { return false; } } if (left.arguments().size() != right.arguments().size()) { return false; } // The order of argv is important. for (int i = 0; i < left.arguments().size(); i++) { if (left.arguments().Get(i) != right.arguments().Get(i)) { return false; } } // NOTE: We are not validating CommandInfo::ContainerInfo here // because it is being deprecated in favor of ContainerInfo. // TODO(vinod): Kill the above comment when // CommandInfo::ContainerInfo is removed. return left.environment() == right.environment() && left.value() == right.value() && left.user() == right.user() && left.shell() == right.shell(); }
// Test that the prepare launch docker hook execute before launch // a docker container. Test hook create a file "foo" in the sandbox // directory. When the docker container launched, the sandbox directory // is mounted to the docker container. We validate the hook by verifying // the "foo" file exists in the docker container or not. TEST_F(HookTest, ROOT_DOCKER_VerifySlavePreLaunchDockerHook) { Try<Owned<cluster::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 containerizer( flags, &fetcher, Owned<ContainerLogger>(logger.get()), docker); Owned<MasterDetector> detector = master.get()->createDetector(); Try<Owned<cluster::Slave>> slave = StartSlave(detector.get(), &containerizer, flags); ASSERT_SOME(slave); MockScheduler sched; MesosSchedulerDriver driver( &sched, DEFAULT_FRAMEWORK_INFO, master.get()->pid, 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("test -f " + path::join(flags.sandbox_directory, "foo")); 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); vector<TaskInfo> tasks; tasks.push_back(task); Future<ContainerID> containerId; EXPECT_CALL(containerizer, launch(_, _, _, _, _, _, _, _)) .WillOnce(DoAll(FutureArg<0>(&containerId), Invoke(&containerizer, &MockDockerContainerizer::_launch))); Future<TaskStatus> statusRunning; Future<TaskStatus> statusFinished; EXPECT_CALL(sched, statusUpdate(&driver, _)) .WillOnce(FutureArg<1>(&statusRunning)) .WillOnce(FutureArg<1>(&statusFinished)) .WillRepeatedly(DoDefault()); driver.launchTasks(offers.get()[0].id(), tasks); AWAIT_READY_FOR(containerId, Seconds(60)); AWAIT_READY_FOR(statusRunning, Seconds(60)); EXPECT_EQ(TASK_RUNNING, statusRunning.get().state()); AWAIT_READY_FOR(statusFinished, Seconds(60)); EXPECT_EQ(TASK_FINISHED, statusFinished.get().state()); Future<containerizer::Termination> termination = containerizer.wait(containerId.get()); driver.stop(); driver.join(); AWAIT_READY(termination); Future<list<Docker::Container>> containers = docker.get()->ps(true, slave::DOCKER_NAME_PREFIX); AWAIT_READY(containers); // Cleanup all mesos launched containers. foreach (const Docker::Container& container, containers.get()) { AWAIT_READY_FOR(docker.get()->rm(container.id, true), Seconds(30)); } }
inline bool operator == (const CommandInfo& left, const CommandInfo& right) { if (left.uris().size() != right.uris().size()) { return false; } for (int i=0; i<left.uris().size(); i++) { bool found = false; for (int j=0; j<right.uris().size(); j++) { if (left.uris().Get(i) == right.uris().Get(j)) { found = true; break; } } if (!found) { return false; } } return left.has_environment() == right.has_environment() && (!left.has_environment() || (left.environment() == right.environment())) && left.value() == right.value(); }
virtual void resourceOffers( SchedulerDriver* driver, const vector<Offer>& offers) { static const Try<Resources> TASK_RESOURCES = Resources::parse(resources); if (TASK_RESOURCES.isError()) { cerr << "Failed to parse resources '" << resources << "': " << TASK_RESOURCES.error() << endl; driver->abort(); return; } foreach (const Offer& offer, offers) { if (!launched && Resources(offer.resources()).contains(TASK_RESOURCES.get())) { TaskInfo task; task.set_name(name); task.mutable_task_id()->set_value(name); task.mutable_slave_id()->MergeFrom(offer.slave_id()); task.mutable_resources()->CopyFrom(TASK_RESOURCES.get()); CommandInfo* commandInfo = task.mutable_command(); commandInfo->set_value(command); if (environment.isSome()) { Environment* environment_ = commandInfo->mutable_environment(); foreachpair (const std::string& name, const std::string& value, environment.get()) { Environment_Variable* environmentVariable = environment_->add_variables(); environmentVariable->set_name(name); environmentVariable->set_value(value); } } if (uri.isSome()) { task.mutable_command()->add_uris()->set_value(uri.get()); } if (dockerImage.isSome()) { ContainerInfo containerInfo; if (containerizer == "mesos") { containerInfo.set_type(ContainerInfo::MESOS); ContainerInfo::MesosInfo mesosInfo; Image mesosImage; mesosImage.set_type(Image::DOCKER); mesosImage.mutable_docker()->set_name(dockerImage.get()); mesosInfo.mutable_image()->CopyFrom(mesosImage); containerInfo.mutable_mesos()->CopyFrom(mesosInfo); } else if (containerizer == "docker") { containerInfo.set_type(ContainerInfo::DOCKER); ContainerInfo::DockerInfo dockerInfo; dockerInfo.set_image(dockerImage.get()); containerInfo.mutable_docker()->CopyFrom(dockerInfo); } else { cerr << "Unsupported containerizer: " << containerizer << endl;; driver->abort(); return; } task.mutable_container()->CopyFrom(containerInfo); } vector<TaskInfo> tasks; tasks.push_back(task); driver->launchTasks(offer.id(), tasks); cout << "task " << name << " submitted to slave " << offer.slave_id() << endl; launched = true; } else {