int main(int argc, char** argv) { if (argc != 2) { cerr << "Usage: " << argv[0] << " <master>" << endl; return -1; } // Find this executable's directory to locate executor. char buf[4096]; realpath(dirname(argv[0]), buf); string uri = string(buf) + "/long-lived-executor"; if (getenv("MESOS_BUILD_DIR")) { uri = string(getenv("MESOS_BUILD_DIR")) + "/src/long-lived-executor"; } ExecutorInfo executor; executor.mutable_executor_id()->set_value("default"); executor.mutable_command()->set_value(uri); LongLivedScheduler scheduler(executor); FrameworkInfo framework; framework.set_user(""); // Have Mesos fill in the current user. framework.set_name("Long Lived Framework (C++)"); MesosSchedulerDriver driver(&scheduler, framework, argv[1]); return driver.run() == DRIVER_STOPPED ? 0 : 1; }
virtual ExecutorInfo getExecutorInfo(SchedulerDriver*) { ExecutorInfo executor; executor.mutable_executor_id()->set_value("default"); executor.set_uri(uri); return executor; }
int main(int argc, char** argv) { // Find this executable's directory to locate executor. string path = os::realpath(dirname(argv[0])).get(); string uri = path + "/test-executor"; if (getenv("MESOS_BUILD_DIR")) { uri = string(getenv("MESOS_BUILD_DIR")) + "/src/test-executor"; } mesos::internal::logging::Flags flags; string role; flags.add(&role, "role", "Role to use when registering", "*"); Option<string> master; flags.add(&master, "master", "ip:port of master to connect"); Try<Nothing> load = flags.load(None(), argc, argv); if (load.isError()) { cerr << load.error() << endl; usage(argv[0], flags); exit(1); } else if (master.isNone()) { cerr << "Missing --master" << endl; usage(argv[0], flags); exit(1); } ExecutorInfo executor; executor.mutable_executor_id()->set_value("default"); executor.mutable_command()->set_value(uri); executor.set_name("Test Executor (C++)"); executor.set_source("cpp_test"); TestScheduler scheduler(executor, role); FrameworkInfo framework; framework.set_user(""); // Have Mesos fill in the current user. framework.set_name("Test Framework (C++)"); framework.set_role(role); MesosSchedulerDriver driver(&scheduler, framework, master.get()); return driver.run() == DRIVER_STOPPED ? 0 : 1; }
ExecutorInfo createExecutorInfo( const string& _frameworkId, const string& _executorId) { FrameworkID frameworkId; frameworkId.set_value(_frameworkId); ExecutorID executorId; executorId.set_value(_executorId); ExecutorInfo executorInfo; executorInfo.mutable_executor_id()->CopyFrom(executorId); executorInfo.mutable_framework_id()->CopyFrom(frameworkId); return executorInfo; }
int main(int argc, char** argv) { if (argc != 2) { cerr << "Usage: " << argv[0] << " <masterPid>" << endl; return -1; } // Find this executable's directory to locate executor char buf[4096]; realpath(dirname(argv[0]), buf); string uri = string(buf) + "/long-lived-executor"; // Run a Mesos scheduler MyScheduler sched; ExecutorInfo executor; executor.mutable_executor_id()->set_value("default"); executor.set_uri(uri); MesosSchedulerDriver driver(&sched, "C++ Test Framework", executor, argv[1]); driver.run(); return 0; }
// For use with a MockScheduler, for example: // EXPECT_CALL(sched, resourceOffers(_, _)) // .WillOnce(LaunchTasks(TASKS, CPUS, MEM)); // Launches up to TASKS no-op tasks, if possible, // each with CPUS cpus and MEM memory. ACTION_P4(LaunchTasks, tasks, cpus, mem, role) { SchedulerDriver* driver = arg0; std::vector<Offer> offers = arg1; int numTasks = tasks; int launched = 0; for (size_t i = 0; i < offers.size(); i++) { const Offer& offer = offers[i]; const Resources TASK_RESOURCES = Resources::parse( "cpus:" + stringify(cpus) + ";mem:" + stringify(mem)).get(); int nextTaskId = 0; std::vector<TaskInfo> tasks; Resources remaining = offer.resources(); while (TASK_RESOURCES <= remaining.flatten() && launched < numTasks) { TaskInfo task; task.set_name("TestTask"); task.mutable_task_id()->set_value(stringify(nextTaskId++)); task.mutable_slave_id()->MergeFrom(offer.slave_id()); ExecutorInfo executor; executor.mutable_executor_id()->set_value("default"); executor.mutable_command()->set_value(":"); task.mutable_executor()->MergeFrom(executor); Option<Resources> resources = remaining.find(TASK_RESOURCES, role); CHECK_SOME(resources); task.mutable_resources()->MergeFrom(resources.get()); remaining -= resources.get(); tasks.push_back(task); launched++; } driver->launchTasks(offer.id(), tasks); } }
inline TaskInfo createTask( const Offer& offer, const std::string& command, const Option<mesos::ExecutorID>& executorId = None(), const std::string& name = "test-task", const std::string& id = UUID::random().toString()) { TaskInfo task; task.set_name(name); task.mutable_task_id()->set_value(id); task.mutable_slave_id()->CopyFrom(offer.slave_id()); task.mutable_resources()->CopyFrom(offer.resources()); if (executorId.isSome()) { ExecutorInfo executor; executor.mutable_executor_id()->CopyFrom(executorId.get()); executor.mutable_command()->set_value(command); task.mutable_executor()->CopyFrom(executor); } else { task.mutable_command()->set_value(command); } return task; }
// This test verifies the correct handling of the statistics // endpoint when statistics is missing in ResourceUsage. TEST(MonitorTest, MissingStatistics) { ResourceMonitor monitor([]() -> Future<ResourceUsage> { FrameworkID frameworkId; frameworkId.set_value("framework"); ExecutorID executorId; executorId.set_value("executor"); ExecutorInfo executorInfo; executorInfo.mutable_executor_id()->CopyFrom(executorId); executorInfo.mutable_framework_id()->CopyFrom(frameworkId); executorInfo.set_name("name"); executorInfo.set_source("source"); Resources resources = Resources::parse("cpus:1;mem:2").get(); ResourceUsage usage; ResourceUsage::Executor* executor = usage.add_executors(); executor->mutable_executor_info()->CopyFrom(executorInfo); executor->mutable_allocated()->CopyFrom(resources); return usage; }); UPID upid("monitor", process::address()); Future<http::Response> response = http::get(upid, "statistics"); AWAIT_READY(response); AWAIT_EXPECT_RESPONSE_STATUS_EQ(http::OK().status, response); AWAIT_EXPECT_RESPONSE_HEADER_EQ( "application/json", "Content-Type", response); AWAIT_EXPECT_RESPONSE_BODY_EQ("[]", response); }
int main(int argc, char** argv) { string seedUrl, master; shift; while (true) { string s = argc>0 ? argv[0] : "--help"; if (argc > 1 && s == "--seedUrl") { seedUrl = argv[1]; shift; shift; } else if (argc > 1 && s == "--master") { master = argv[1]; shift; shift; } else { break; } } if (master.length() == 0 || seedUrl.length() == 0) { printf("Usage: rendler --seedUrl <URL> --master <ip>:<port>\n"); exit(1); } // Find this executable's directory to locate executor. string path = realpath(dirname(argv[0]), NULL); string crawlerURI = path + "/crawl_executor"; string rendererURI = path + "/render_executor"; cout << crawlerURI << endl; cout << rendererURI << endl; ExecutorInfo crawler; crawler.mutable_executor_id()->set_value("Crawler"); crawler.mutable_command()->set_value(crawlerURI); crawler.set_name("Crawl Executor (C++)"); crawler.set_source("cpp"); ExecutorInfo renderer; renderer.mutable_executor_id()->set_value("Renderer"); renderer.mutable_command()->set_value(rendererURI); renderer.set_name("Render Executor (C++)"); renderer.set_source("cpp"); Rendler scheduler(crawler, renderer, seedUrl); FrameworkInfo framework; framework.set_user(""); // Have Mesos fill in the current user. framework.set_name("Rendler Framework (C++)"); //framework.set_role(role); framework.set_principal("rendler-cpp"); // Set up the signal handler for SIGINT for clean shutdown. struct sigaction action; action.sa_handler = SIGINTHandler; sigemptyset(&action.sa_mask); action.sa_flags = 0; sigaction(SIGINT, &action, NULL); schedulerDriver = new MesosSchedulerDriver(&scheduler, framework, master); int status = schedulerDriver->run() == DRIVER_STOPPED ? 0 : 1; // Ensure that the driver process terminates. schedulerDriver->stop(); shutdown(); delete schedulerDriver; return status; }
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; }
TEST(MonitorTest, Statistics) { FrameworkID frameworkId; frameworkId.set_value("framework"); ExecutorID executorId; executorId.set_value("executor"); ExecutorInfo executorInfo; executorInfo.mutable_executor_id()->CopyFrom(executorId); executorInfo.mutable_framework_id()->CopyFrom(frameworkId); executorInfo.set_name("name"); executorInfo.set_source("source"); ResourceStatistics statistics; statistics.set_cpus_nr_periods(100); statistics.set_cpus_nr_throttled(2); statistics.set_cpus_user_time_secs(4); statistics.set_cpus_system_time_secs(1); statistics.set_cpus_throttled_time_secs(0.5); statistics.set_cpus_limit(1.0); statistics.set_mem_file_bytes(0); statistics.set_mem_anon_bytes(0); statistics.set_mem_mapped_file_bytes(0); statistics.set_mem_rss_bytes(1024); statistics.set_mem_limit_bytes(2048); statistics.set_timestamp(0); ResourceMonitor monitor([=]() -> Future<ResourceUsage> { Resources resources = Resources::parse("cpus:1;mem:2").get(); ResourceUsage usage; ResourceUsage::Executor* executor = usage.add_executors(); executor->mutable_executor_info()->CopyFrom(executorInfo); executor->mutable_allocated()->CopyFrom(resources); executor->mutable_statistics()->CopyFrom(statistics); return usage; }); UPID upid("monitor", process::address()); Future<http::Response> response = http::get(upid, "statistics"); AWAIT_READY(response); AWAIT_EXPECT_RESPONSE_STATUS_EQ(http::OK().status, response); AWAIT_EXPECT_RESPONSE_HEADER_EQ( "application/json", "Content-Type", response); JSON::Array expected; JSON::Object usage; usage.values["executor_id"] = "executor"; usage.values["executor_name"] = "name"; usage.values["framework_id"] = "framework"; usage.values["source"] = "source"; usage.values["statistics"] = JSON::Protobuf(statistics); expected.values.push_back(usage); Try<JSON::Array> result = JSON::parse<JSON::Array>(response.get().body); ASSERT_SOME(result); ASSERT_EQ(expected, result.get()); }
// This test verifies that when reregistering, the slave sends the // executor ID of a non-command executor task, but not the one of a // command executor task. We then check that the master's API has // task IDs absent only for the command executor case. // // This was motivated by MESOS-8135. TEST_F(MasterSlaveReconciliationTest, SlaveReregisterTaskExecutorIds) { Try<Owned<cluster::Master>> master = StartMaster(); ASSERT_SOME(master); slave::Flags flags = CreateSlaveFlags(); StandaloneMasterDetector detector(master.get()->pid); Try<Owned<cluster::Slave>> slave = StartSlave(&detector, 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); EXPECT_NE(0u, offers->size()); const Offer& offer = offers->front(); const SlaveID& slaveId = offer.slave_id(); Resources resources = Resources::parse(defaultTaskResourcesString).get(); TaskInfo commandExecutorTask = createTask(slaveId, resources, SLEEP_COMMAND(1000)); TaskInfo defaultExecutorTask = createTask(slaveId, resources, SLEEP_COMMAND(1000)); ExecutorInfo defaultExecutorInfo; defaultExecutorInfo.set_type(ExecutorInfo::DEFAULT); defaultExecutorInfo.mutable_executor_id()->CopyFrom(DEFAULT_EXECUTOR_ID); defaultExecutorInfo.mutable_framework_id()->CopyFrom(frameworkId.get()); defaultExecutorInfo.mutable_resources()->CopyFrom(resources); // We expect two TASK_STARTING and two TASK_RUNNING updates. vector<Future<TaskStatus>> taskStatuses(4); { // This variable doesn't have to be used explicitly. testing::InSequence inSequence; foreach (Future<TaskStatus>& taskStatus, taskStatuses) { EXPECT_CALL(sched, statusUpdate(&driver, _)) .WillOnce(FutureArg<1>(&taskStatus)); } EXPECT_CALL(sched, statusUpdate(&driver, _)) .WillRepeatedly(Return()); // Ignore subsequent updates. }
int main(int argc, char** argv) { if (argc != 2) { cerr << "Usage: " << argv[0] << " <master>" << endl; return -1; } // Find this executable's directory to locate executor. string path = os::realpath(dirname(argv[0])).get(); string uri = path + "/long-lived-executor"; if (getenv("MESOS_BUILD_DIR")) { uri = string(getenv("MESOS_BUILD_DIR")) + "/src/long-lived-executor"; } ExecutorInfo executor; executor.mutable_executor_id()->set_value("default"); executor.mutable_command()->set_value(uri); executor.set_name("Long Lived Executor (C++)"); executor.set_source("cpp_long_lived_framework"); LongLivedScheduler scheduler(executor); FrameworkInfo framework; framework.set_user(""); // Have Mesos fill in the current user. framework.set_name("Long Lived 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("long-lived-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; }
int main(int argc, char** argv) { if (argc != 2) { cerr << "Usage: " << argv[0] << " <master>" << endl; return -1; } // Find this executable's directory to locate executor. string uri; Option<string> value = os::getenv("MESOS_BUILD_DIR"); if (value.isSome()) { uri = path::join(value.get(), "src", "long-lived-executor"); } else { uri = path::join( os::realpath(Path(argv[0]).dirname()).get(), "long-lived-executor"); } ExecutorInfo executor; executor.mutable_executor_id()->set_value("default"); executor.mutable_command()->set_value(uri); executor.set_name("Long Lived Executor (C++)"); executor.set_source("cpp_long_lived_framework"); LongLivedScheduler scheduler(executor); FrameworkInfo framework; framework.set_user(""); // Have Mesos fill in the current user. framework.set_name("Long Lived Framework (C++)"); value = os::getenv("MESOS_CHECKPOINT"); if (value.isSome()) { framework.set_checkpoint( numify<bool>(value.get()).get()); } MesosSchedulerDriver* driver; if (os::getenv("MESOS_AUTHENTICATE").isSome()) { cout << "Enabling authentication for the framework" << endl; value = os::getenv("DEFAULT_PRINCIPAL"); if (value.isNone()) { EXIT(1) << "Expecting authentication principal in the environment"; } Credential credential; credential.set_principal(value.get()); framework.set_principal(value.get()); value = os::getenv("DEFAULT_SECRET"); if (value.isNone()) { EXIT(1) << "Expecting authentication secret in the environment"; } credential.set_secret(value.get()); driver = new MesosSchedulerDriver( &scheduler, framework, argv[1], credential); } else { framework.set_principal("long-lived-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; }
int main(int argc, char** argv) { // Find this executable's directory to locate executor. string path = os::realpath(dirname(argv[0])).get(); string uri = path + "/test-executor"; if (getenv("MESOS_BUILD_DIR")) { uri = string(getenv("MESOS_BUILD_DIR")) + "/src/test-executor"; } mesos::internal::logging::Flags flags; string role; flags.add(&role, "role", "Role to use when registering", "*"); Option<string> master; flags.add(&master, "master", "ip:port of master to connect"); Try<Nothing> load = flags.load(None(), argc, argv); if (load.isError()) { cerr << load.error() << endl; usage(argv[0], flags); exit(1); } else if (master.isNone()) { cerr << "Missing --master" << endl; usage(argv[0], flags); exit(1); } ExecutorInfo executor; executor.mutable_executor_id()->set_value("default"); executor.mutable_command()->set_value(uri); executor.set_name("Test Executor (C++)"); executor.set_source("cpp_test"); TestScheduler scheduler(executor, role); FrameworkInfo framework; framework.set_user(""); // Have Mesos fill in the current user. framework.set_name("Test Framework (C++)"); framework.set_role(role); // 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")); driver = new MesosSchedulerDriver( &scheduler, framework, master.get(), credential); } else { driver = new MesosSchedulerDriver( &scheduler, framework, master.get()); } int status = driver->run() == DRIVER_STOPPED ? 0 : 1; delete driver; return status; }
TEST_F(MultipleExecutorsTest, TasksExecutorInfoDiffers) { Try<PID<Master> > master = StartMaster(); ASSERT_SOME(master); MockExecutor exec(DEFAULT_EXECUTOR_ID); Try<PID<Slave> > slave = StartSlave(&exec); ASSERT_SOME(master); MockScheduler sched; MesosSchedulerDriver driver(&sched, DEFAULT_FRAMEWORK_INFO, master.get()); 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()); ExecutorInfo executor; executor.mutable_executor_id()->set_value("default"); executor.mutable_command()->set_value("exit 1"); TaskInfo task1; task1.set_name(""); task1.mutable_task_id()->set_value("1"); task1.mutable_slave_id()->MergeFrom(offers.get()[0].slave_id()); task1.mutable_resources()->MergeFrom(Resources::parse("cpus:1;mem:512").get()); task1.mutable_executor()->MergeFrom(executor); executor.mutable_command()->set_value("exit 2"); TaskInfo task2; task2.set_name(""); task2.mutable_task_id()->set_value("2"); task2.mutable_slave_id()->MergeFrom(offers.get()[0].slave_id()); task2.mutable_resources()->MergeFrom(Resources::parse("cpus:1;mem:512").get()); task2.mutable_executor()->MergeFrom(executor); vector<TaskInfo> tasks; tasks.push_back(task1); tasks.push_back(task2); EXPECT_CALL(exec, registered(_, _, _, _)) .Times(1); // Grab the "good" task but don't send a status update. Future<TaskInfo> task; EXPECT_CALL(exec, launchTask(_, _)) .WillOnce(FutureArg<1>(&task)); Future<TaskStatus> status; EXPECT_CALL(sched, statusUpdate(&driver, _)) .WillOnce(FutureArg<1>(&status)); driver.launchTasks(offers.get()[0].id(), tasks); AWAIT_READY(task); EXPECT_EQ(task1.task_id(), task.get().task_id()); AWAIT_READY(status); EXPECT_EQ(task2.task_id(), status.get().task_id()); EXPECT_EQ(TASK_LOST, status.get().state()); EXPECT_TRUE(status.get().has_message()); EXPECT_EQ("Task has invalid ExecutorInfo (existing ExecutorInfo" " with same ExecutorID is not compatible)", status.get().message()); EXPECT_CALL(exec, shutdown(_)) .Times(AtMost(1)); driver.stop(); driver.join(); Shutdown(); }
// TODO(bmahler): Add additional tests: // 1. Check that the data has been published to statistics. // 2. Check that metering is occurring on subsequent resource data. TEST(MonitorTest, WatchUnwatch) { FrameworkID frameworkId; frameworkId.set_value("framework"); ExecutorID executorId; executorId.set_value("executor"); ExecutorInfo executorInfo; executorInfo.mutable_executor_id()->CopyFrom(executorId); executorInfo.mutable_framework_id()->CopyFrom(frameworkId); executorInfo.set_name("name"); executorInfo.set_source("source"); ResourceStatistics initialStatistics; initialStatistics.set_cpus_user_time_secs(0); initialStatistics.set_cpus_system_time_secs(0); initialStatistics.set_cpus_limit(2.5); initialStatistics.set_mem_rss_bytes(0); initialStatistics.set_mem_limit_bytes(2048); initialStatistics.set_timestamp(Clock::now().secs()); ResourceStatistics statistics; statistics.set_cpus_nr_periods(100); statistics.set_cpus_nr_throttled(2); statistics.set_cpus_user_time_secs(4); statistics.set_cpus_system_time_secs(1); statistics.set_cpus_throttled_time_secs(0.5); statistics.set_cpus_limit(2.5); statistics.set_mem_rss_bytes(1024); statistics.set_mem_limit_bytes(2048); statistics.set_timestamp( initialStatistics.timestamp() + slave::RESOURCE_MONITORING_INTERVAL.secs()); TestingIsolator isolator; process::spawn(isolator); Future<Nothing> usage1, usage2; EXPECT_CALL(isolator, usage(frameworkId, executorId)) .WillOnce(DoAll(FutureSatisfy(&usage1), Return(initialStatistics))) .WillOnce(DoAll(FutureSatisfy(&usage2), Return(statistics))); slave::ResourceMonitor monitor(&isolator); // We pause the clock first in order to make sure that we can // advance time below to force the 'delay' in // ResourceMonitorProcess::watch to execute. process::Clock::pause(); monitor.watch( frameworkId, executorId, executorInfo, slave::RESOURCE_MONITORING_INTERVAL); // Now wait for ResouorceMonitorProcess::watch to finish so we can // advance time to cause collection to begin. process::Clock::settle(); process::Clock::advance(slave::RESOURCE_MONITORING_INTERVAL); process::Clock::settle(); AWAIT_READY(usage1); // Wait until the isolator has finished returning the statistics. process::Clock::settle(); // The second collection will populate the cpus_usage. process::Clock::advance(slave::RESOURCE_MONITORING_INTERVAL); process::Clock::settle(); AWAIT_READY(usage2); // Wait until the isolator has finished returning the statistics. process::Clock::settle(); process::UPID upid("monitor", process::ip(), process::port()); Future<Response> response = process::http::get(upid, "usage.json"); AWAIT_EXPECT_RESPONSE_STATUS_EQ(OK().status, response); AWAIT_EXPECT_RESPONSE_HEADER_EQ( "application/json", "Content-Type", response); // TODO(bmahler): Verify metering directly through statistics. AWAIT_EXPECT_RESPONSE_BODY_EQ( strings::format( "[{" "\"executor_id\":\"executor\"," "\"executor_name\":\"name\"," "\"framework_id\":\"framework\"," "\"resource_usage\":{" "\"cpu_time\":%g," "\"cpu_usage\":%g," "\"memory_rss\":%lu" "}," "\"source\":\"source\"" "}]", statistics.cpus_system_time_secs() + statistics.cpus_user_time_secs(), (statistics.cpus_system_time_secs() + statistics.cpus_user_time_secs()) / slave::RESOURCE_MONITORING_INTERVAL.secs(), statistics.mem_rss_bytes()).get(), response); response = process::http::get(upid, "statistics.json"); AWAIT_EXPECT_RESPONSE_STATUS_EQ(OK().status, response); AWAIT_EXPECT_RESPONSE_HEADER_EQ( "application/json", "Content-Type", response); // TODO(bmahler): Verify metering directly through statistics. AWAIT_EXPECT_RESPONSE_BODY_EQ( strings::format( "[{" "\"executor_id\":\"executor\"," "\"executor_name\":\"name\"," "\"framework_id\":\"framework\"," "\"source\":\"source\"," "\"statistics\":{" "\"cpus_limit\":%g," "\"cpus_nr_periods\":%d," "\"cpus_nr_throttled\":%d," "\"cpus_system_time_secs\":%g," "\"cpus_throttled_time_secs\":%g," "\"cpus_user_time_secs\":%g," "\"mem_limit_bytes\":%lu," "\"mem_rss_bytes\":%lu" "}" "}]", statistics.cpus_limit(), statistics.cpus_nr_periods(), statistics.cpus_nr_throttled(), statistics.cpus_system_time_secs(), statistics.cpus_throttled_time_secs(), statistics.cpus_user_time_secs(), statistics.mem_limit_bytes(), statistics.mem_rss_bytes()).get(), response); // Ensure the monitor stops polling the isolator. monitor.unwatch(frameworkId, executorId); // Wait until ResourceMonitorProcess::unwatch has completed. process::Clock::settle(); // This time, Isolator::usage should not get called. EXPECT_CALL(isolator, usage(frameworkId, executorId)) .Times(0); process::Clock::advance(slave::RESOURCE_MONITORING_INTERVAL); process::Clock::settle(); response = process::http::get(upid, "usage.json"); AWAIT_EXPECT_RESPONSE_STATUS_EQ(OK().status, response); AWAIT_EXPECT_RESPONSE_HEADER_EQ( "application/json", "Content-Type", response); AWAIT_EXPECT_RESPONSE_BODY_EQ("[]", response); }
// This test verifies that a task group is launched on the agent if the executor // provides a valid authentication token specifying its own ContainerID. TEST_F(ExecutorAuthorizationTest, RunTaskGroup) { Try<Owned<cluster::Master>> master = StartMaster(); ASSERT_SOME(master); // Start an agent with permissive ACLs so that a task can be launched. ACLs acls; acls.set_permissive(true); slave::Flags flags = CreateSlaveFlags(); flags.acls = acls; Owned<MasterDetector> detector = master.get()->createDetector(); Try<Owned<cluster::Slave>> slave = StartSlave(detector.get(), flags); ASSERT_SOME(slave); FrameworkInfo frameworkInfo = DEFAULT_FRAMEWORK_INFO; MockScheduler sched; MesosSchedulerDriver driver( &sched, frameworkInfo, 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_FALSE(offers->empty()); Offer offer = offers.get()[0]; TaskInfo task = createTask( offer.slave_id(), Resources::parse("cpus:0.5;mem:32").get(), "sleep 1000"); Future<TaskStatus> status; EXPECT_CALL(sched, statusUpdate(&driver, _)) .WillOnce(FutureArg<1>(&status)); Resources executorResources = allocatedResources(Resources::parse("cpus:0.1;mem:32;disk:32").get(), "*"); ExecutorInfo executor; executor.mutable_executor_id()->set_value("default"); executor.set_type(ExecutorInfo::DEFAULT); executor.mutable_framework_id()->CopyFrom(frameworkId.get()); executor.mutable_resources()->CopyFrom(executorResources); TaskGroupInfo taskGroup; taskGroup.add_tasks()->CopyFrom(task); driver.acceptOffers({offer.id()}, {LAUNCH_GROUP(executor, taskGroup)}); AWAIT_READY(status); ASSERT_EQ(task.task_id(), status->task_id()); EXPECT_EQ(TASK_STARTING, status->state()); driver.stop(); driver.join(); }