int main(int argc, char** argv) { if (argc != 3) { std::cerr << "Usage: " << argv[0] << " <master> <balloon limit in MB>" << std::endl; return -1; } // Verify the balloon limit. Try<size_t> limit = numify<size_t>(argv[2]); if (limit.isError()) { std::cerr << "Balloon limit is not a valid number" << std::endl; return -1; } if (limit.get() < EXECUTOR_MEMORY_MB) { std::cerr << "Please use a balloon limit bigger than " << EXECUTOR_MEMORY_MB << " MB" << std::endl; } // Find this executable's directory to locate executor. std::string path = os::realpath(::dirname(argv[0])).get(); std::string uri = path + "/balloon-executor"; if (getenv("MESOS_BUILD_DIR")) { uri = std::string(::getenv("MESOS_BUILD_DIR")) + "/src/balloon-executor"; } ExecutorInfo executor; executor.mutable_executor_id()->set_value("default"); executor.mutable_command()->set_value(uri); executor.set_name("Balloon Executor"); executor.set_source("balloon_test"); Resource* mem = executor.add_resources(); mem->set_name("mem"); mem->set_type(Value::SCALAR); mem->mutable_scalar()->set_value(EXECUTOR_MEMORY_MB); BalloonScheduler scheduler(executor, limit.get()); FrameworkInfo framework; framework.set_user(""); // Have Mesos fill in the current user. framework.set_name("Balloon Framework (C++)"); // TODO(vinod): Make checkpointing the default when it is default // on the slave. if (os::hasenv("MESOS_CHECKPOINT")) { cout << "Enabling checkpoint for the framework" << endl; framework.set_checkpoint(true); } MesosSchedulerDriver* driver; if (os::hasenv("MESOS_AUTHENTICATE")) { cout << "Enabling authentication for the framework" << endl; if (!os::hasenv("DEFAULT_PRINCIPAL")) { EXIT(1) << "Expecting authentication principal in the environment"; } if (!os::hasenv("DEFAULT_SECRET")) { EXIT(1) << "Expecting authentication secret in the environment"; } Credential credential; credential.set_principal(getenv("DEFAULT_PRINCIPAL")); credential.set_secret(getenv("DEFAULT_SECRET")); framework.set_principal(getenv("DEFAULT_PRINCIPAL")); driver = new MesosSchedulerDriver( &scheduler, framework, argv[1], credential); } else { framework.set_principal("balloon-framework-cpp"); driver = new MesosSchedulerDriver( &scheduler, framework, argv[1]); } int status = driver->run() == DRIVER_STOPPED ? 0 : 1; // Ensure that the driver process terminates. driver->stop(); delete driver; return status; }
// This test tries to catch the regression for MESOS-7366. It verifies // that the persistent volume mount points in the sandbox will be // cleaned up even if there is still reference to the volume. TEST_F(LinuxFilesystemIsolatorTest, ROOT_PersistentVolumeMountPointCleanup) { slave::Flags flags = CreateSlaveFlags(); flags.isolation = "filesystem/linux"; Fetcher fetcher(flags); Try<MesosContainerizer*> create = MesosContainerizer::create(flags, true, &fetcher); ASSERT_SOME(create); Owned<Containerizer> containerizer(create.get()); ContainerID containerId; containerId.set_value(id::UUID::random().toString()); ExecutorInfo executor = createExecutorInfo( "test_executor", "sleep 1000"); // Create a persistent volume. executor.add_resources()->CopyFrom(createPersistentVolume( Megabytes(32), "test_role", "persistent_volume_id", "volume")); string volume = slave::paths::getPersistentVolumePath( flags.work_dir, "test_role", "persistent_volume_id"); ASSERT_SOME(os::mkdir(volume)); string directory = path::join(flags.work_dir, "sandbox"); ASSERT_SOME(os::mkdir(directory)); Future<Containerizer::LaunchResult> launch = containerizer->launch( containerId, createContainerConfig(None(), executor, directory), map<string, string>(), None()); AWAIT_ASSERT_EQ(Containerizer::LaunchResult::SUCCESS, launch); ASSERT_SOME(os::touch(path::join(directory, "volume", "abc"))); // This keeps a reference to the persistent volume mount. Try<int_fd> fd = os::open( path::join(directory, "volume", "abc"), O_WRONLY | O_TRUNC | O_CLOEXEC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); ASSERT_SOME(fd); containerizer->destroy(containerId); Future<Option<ContainerTermination>> wait = containerizer->wait(containerId); AWAIT_READY(wait); ASSERT_SOME(wait.get()); ASSERT_TRUE(wait->get().has_status()); EXPECT_WTERMSIG_EQ(SIGKILL, wait.get()->status()); // Verifies that mount point has been removed. EXPECT_FALSE(os::exists(path::join(directory, "volume", "abc"))); os::close(fd.get()); }
TEST_F(RevocableCpuIsolatorTest, ROOT_CGROUPS_RevocableCpu) { slave::Flags flags; Try<Isolator*> isolator = CgroupsCpushareIsolatorProcess::create(flags); CHECK_SOME(isolator); Try<Launcher*> launcher = PosixLauncher::create(flags); // Include revocable CPU in the executor's resources. Resource cpu = Resources::parse("cpus", "1", "*").get(); cpu.mutable_revocable(); ExecutorInfo executorInfo; executorInfo.add_resources()->CopyFrom(cpu); ContainerID containerId; containerId.set_value(UUID::random().toString()); ContainerConfig containerConfig; containerConfig.mutable_executor_info()->CopyFrom(executorInfo); containerConfig.set_directory(os::getcwd()); AWAIT_READY(isolator.get()->prepare( containerId, containerConfig)); vector<string> argv{"sleep", "100"}; Try<pid_t> pid = launcher.get()->fork( containerId, "/bin/sleep", argv, Subprocess::PATH("/dev/null"), Subprocess::PATH("/dev/null"), Subprocess::PATH("/dev/null"), None(), None(), None(), None()); ASSERT_SOME(pid); AWAIT_READY(isolator.get()->isolate(containerId, pid.get())); // Executor should have proper cpu.shares for revocable containers. Result<string> cpuHierarchy = cgroups::hierarchy("cpu"); ASSERT_SOME(cpuHierarchy); Result<string> cpuCgroup = cgroups::cpu::cgroup(pid.get()); ASSERT_SOME(cpuCgroup); EXPECT_SOME_EQ( CPU_SHARES_PER_CPU_REVOCABLE, cgroups::cpu::shares(cpuHierarchy.get(), cpuCgroup.get())); // Kill the container and clean up. Future<Option<int>> status = process::reap(pid.get()); AWAIT_READY(launcher.get()->destroy(containerId)); AWAIT_READY(status); AWAIT_READY(isolator.get()->cleanup(containerId)); delete isolator.get(); delete launcher.get(); }
// This test verifies that persistent volumes are properly mounted if // the container does not specify a root filesystem. TEST_F(LinuxFilesystemIsolatorTest, ROOT_PersistentVolumeWithoutRootFilesystem) { string registry = path::join(sandbox.get(), "registry"); AWAIT_READY(DockerArchive::create(registry, "test_image")); slave::Flags flags = CreateSlaveFlags(); flags.isolation = "filesystem/linux,docker/runtime"; flags.docker_registry = registry; flags.docker_store_dir = path::join(sandbox.get(), "store"); flags.image_providers = "docker"; Fetcher fetcher(flags); Try<MesosContainerizer*> create = MesosContainerizer::create(flags, true, &fetcher); ASSERT_SOME(create); Owned<Containerizer> containerizer(create.get()); ContainerID containerId; containerId.set_value(id::UUID::random().toString()); ExecutorInfo executor = createExecutorInfo( "test_executor", "echo abc > volume/file"); executor.add_resources()->CopyFrom(createPersistentVolume( Megabytes(32), "test_role", "persistent_volume_id", "volume")); // Create a persistent volume. string volume = slave::paths::getPersistentVolumePath( flags.work_dir, "test_role", "persistent_volume_id"); ASSERT_SOME(os::mkdir(volume)); string directory = path::join(flags.work_dir, "sandbox"); ASSERT_SOME(os::mkdir(directory)); Future<Containerizer::LaunchResult> launch = containerizer->launch( containerId, createContainerConfig(None(), executor, directory), map<string, string>(), None()); AWAIT_ASSERT_EQ(Containerizer::LaunchResult::SUCCESS, launch); Future<Option<ContainerTermination>> wait = containerizer->wait(containerId); AWAIT_READY(wait); ASSERT_SOME(wait.get()); ASSERT_TRUE(wait->get().has_status()); EXPECT_WEXITSTATUS_EQ(0, wait->get().status()); EXPECT_SOME_EQ("abc\n", os::read(path::join(volume, "file"))); }