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; }
// 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(SharedFilesystemIsolatorTest, ROOT_AbsoluteVolume) { slave::Flags flags = CreateSlaveFlags(); flags.isolation = "filesystem/shared"; Try<Isolator*> isolator = SharedFilesystemIsolatorProcess::create(flags); CHECK_SOME(isolator); Try<Launcher*> launcher = LinuxLauncher::create(flags); CHECK_SOME(launcher); // We'll mount the absolute test work directory as /var/tmp in the // container. const string hostPath = flags.work_dir; const string containerPath = "/var/tmp"; ContainerInfo containerInfo; containerInfo.set_type(ContainerInfo::MESOS); containerInfo.add_volumes()->CopyFrom( CREATE_VOLUME(containerPath, hostPath, Volume::RW)); ExecutorInfo executorInfo; executorInfo.mutable_container()->CopyFrom(containerInfo); ContainerID containerId; containerId.set_value(UUID::random().toString()); Future<Option<CommandInfo> > prepare = isolator.get()->prepare(containerId, executorInfo, flags.work_dir, None()); AWAIT_READY(prepare); ASSERT_SOME(prepare.get()); // Test the volume mounting by touching a file in the container's // /tmp, which should then be in flags.work_dir. const string filename = UUID::random().toString(); ASSERT_FALSE(os::exists(path::join(containerPath, filename))); vector<string> args; args.push_back("/bin/sh"); args.push_back("-x"); args.push_back("-c"); args.push_back(prepare.get().get().value() + " && touch " + path::join(containerPath, filename)); Try<pid_t> pid = launcher.get()->fork( containerId, "/bin/sh", args, Subprocess::FD(STDIN_FILENO), Subprocess::FD(STDOUT_FILENO), Subprocess::FD(STDERR_FILENO), None(), None(), None()); ASSERT_SOME(pid); // Set up the reaper to wait on the forked child. Future<Option<int> > status = process::reap(pid.get()); AWAIT_READY(status); EXPECT_SOME_EQ(0, status.get()); // Check the file was created in flags.work_dir. EXPECT_TRUE(os::exists(path::join(hostPath, filename))); // Check it didn't get created in the host's view of containerPath. EXPECT_FALSE(os::exists(path::join(containerPath, filename))); delete launcher.get(); delete isolator.get(); }
// Test that a container can create a private view of a system // directory (/var/tmp). Check that a file written by a process inside // the container doesn't appear on the host filesystem but does appear // under the container's work directory. TEST_F(SharedFilesystemIsolatorTest, ROOT_RelativeVolume) { slave::Flags flags = CreateSlaveFlags(); flags.isolation = "filesystem/shared"; Try<Isolator*> isolator = SharedFilesystemIsolatorProcess::create(flags); CHECK_SOME(isolator); Try<Launcher*> launcher = LinuxLauncher::create(flags); CHECK_SOME(launcher); // Use /var/tmp so we don't mask the work directory (under /tmp). const string containerPath = "/var/tmp"; ASSERT_TRUE(os::isdir(containerPath)); // Use a host path relative to the container work directory. const string hostPath = strings::remove(containerPath, "/", strings::PREFIX); ContainerInfo containerInfo; containerInfo.set_type(ContainerInfo::MESOS); containerInfo.add_volumes()->CopyFrom( CREATE_VOLUME(containerPath, hostPath, Volume::RW)); ExecutorInfo executorInfo; executorInfo.mutable_container()->CopyFrom(containerInfo); ContainerID containerId; containerId.set_value(UUID::random().toString()); Future<Option<CommandInfo> > prepare = isolator.get()->prepare(containerId, executorInfo, flags.work_dir, None()); AWAIT_READY(prepare); ASSERT_SOME(prepare.get()); // The test will touch a file in container path. const string file = path::join(containerPath, UUID::random().toString()); ASSERT_FALSE(os::exists(file)); // Manually run the isolator's preparation command first, then touch // the file. vector<string> args; args.push_back("/bin/sh"); args.push_back("-x"); args.push_back("-c"); args.push_back(prepare.get().get().value() + " && touch " + file); Try<pid_t> pid = launcher.get()->fork( containerId, "/bin/sh", args, Subprocess::FD(STDIN_FILENO), Subprocess::FD(STDOUT_FILENO), Subprocess::FD(STDERR_FILENO), None(), None(), None()); ASSERT_SOME(pid); // Set up the reaper to wait on the forked child. Future<Option<int> > status = process::reap(pid.get()); AWAIT_READY(status); EXPECT_SOME_EQ(0, status.get()); // Check the correct hierarchy was created under the container work // directory. string dir = "/"; foreach (const string& subdir, strings::tokenize(containerPath, "/")) { dir = path::join(dir, subdir); struct stat hostStat; EXPECT_EQ(0, ::stat(dir.c_str(), &hostStat)); struct stat containerStat; EXPECT_EQ(0, ::stat(path::join(flags.work_dir, dir).c_str(), &containerStat)); EXPECT_EQ(hostStat.st_mode, containerStat.st_mode); EXPECT_EQ(hostStat.st_uid, containerStat.st_uid); EXPECT_EQ(hostStat.st_gid, containerStat.st_gid); } // Check it did *not* create a file in the host namespace. EXPECT_FALSE(os::exists(file)); // Check it did create the file under the container's work directory // on the host. EXPECT_TRUE(os::exists(path::join(flags.work_dir, file))); delete launcher.get(); delete isolator.get(); }
// This test verifies that sandbox path volume allows two containers // nested under the same parent container to share data. // TODO(jieyu): Parameterize this test to test both linux and posix // launcher and filesystem isolator. TEST_F(VolumeSandboxPathIsolatorTest, SharedVolume) { slave::Flags flags = CreateSlaveFlags(); flags.isolation = "volume/sandbox_path"; Fetcher fetcher; Try<MesosContainerizer*> create = MesosContainerizer::create( flags, true, &fetcher); ASSERT_SOME(create); Owned<MesosContainerizer> containerizer(create.get()); SlaveState state; state.id = SlaveID(); AWAIT_READY(containerizer->recover(state)); ContainerID containerId; containerId.set_value(UUID::random().toString()); ExecutorInfo executor = createExecutorInfo("executor", "sleep 99", "cpus:1"); Try<string> directory = environment->mkdtemp(); ASSERT_SOME(directory); Future<bool> launch = containerizer->launch( containerId, None(), executor, directory.get(), None(), state.id, map<string, string>(), true); // TODO(benh): Ever want to check not-checkpointing? AWAIT_ASSERT_TRUE(launch); ContainerID nestedContainerId1; nestedContainerId1.mutable_parent()->CopyFrom(containerId); nestedContainerId1.set_value(UUID::random().toString()); ContainerInfo containerInfo; containerInfo.set_type(ContainerInfo::MESOS); Volume* volume = containerInfo.add_volumes(); volume->set_mode(Volume::RW); volume->set_container_path("parent"); Volume::Source* source = volume->mutable_source(); source->set_type(Volume::Source::SANDBOX_PATH); Volume::Source::SandboxPath* sandboxPath = source->mutable_sandbox_path(); sandboxPath->set_type(Volume::Source::SandboxPath::PARENT); sandboxPath->set_path("shared"); launch = containerizer->launch( nestedContainerId1, createCommandInfo("touch parent/file; sleep 1000"), containerInfo, None(), state.id); AWAIT_ASSERT_TRUE(launch); ContainerID nestedContainerId2; nestedContainerId2.mutable_parent()->CopyFrom(containerId); nestedContainerId2.set_value(UUID::random().toString()); launch = containerizer->launch( nestedContainerId2, createCommandInfo( "while true; do if [ -f parent/file ]; then exit 0; fi; done"), containerInfo, None(), state.id); AWAIT_ASSERT_TRUE(launch); Future<Option<ContainerTermination>> wait = containerizer->wait(nestedContainerId2); AWAIT_READY(wait); ASSERT_SOME(wait.get()); ASSERT_TRUE(wait.get()->has_status()); EXPECT_WEXITSTATUS_EQ(0, wait.get()->status()); wait = containerizer->wait(containerId); containerizer->destroy(containerId); AWAIT_READY(wait); ASSERT_SOME(wait.get()); ASSERT_TRUE(wait.get()->has_status()); EXPECT_WTERMSIG_EQ(SIGKILL, wait.get()->status()); }