You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mesos.apache.org by be...@apache.org on 2011/06/05 07:43:01 UTC
svn commit: r1131871 - in /incubator/mesos/trunk: ./ src/ src/tests/
src/tests/external/LxcIsolation/
Author: benh
Date: Sun Jun 5 05:43:01 2011
New Revision: 1131871
URL: http://svn.apache.org/viewvc?rev=1131871&view=rev
Log:
Finished work on the scheduled_memhog and added some unit tests that use
it to test the LXC isolation module. Also fixed some build errors that
were introduced in a commit in master.
Added:
incubator/mesos/trunk/src/tests/external/LxcIsolation/
incubator/mesos/trunk/src/tests/external/LxcIsolation/HoldMoreMemThanRequested.sh (with props)
incubator/mesos/trunk/src/tests/external/LxcIsolation/ScaleUpAndDown.sh (with props)
incubator/mesos/trunk/src/tests/external/LxcIsolation/TwoSeparateTasks.sh (with props)
incubator/mesos/trunk/src/tests/external/LxcIsolation/run_scheduled_memhog_test.sh
incubator/mesos/trunk/src/tests/test_lxc_isolation.cpp
Modified:
incubator/mesos/trunk/.gitignore
incubator/mesos/trunk/src/Makefile.in
incubator/mesos/trunk/src/lxc_isolation_module.hpp
incubator/mesos/trunk/src/memhog_executor.cpp
incubator/mesos/trunk/src/scheduled_memhog.cpp
incubator/mesos/trunk/src/tests/external_test.cpp
Modified: incubator/mesos/trunk/.gitignore
URL: http://svn.apache.org/viewvc/incubator/mesos/trunk/.gitignore?rev=1131871&r1=1131870&r2=1131871&view=diff
==============================================================================
--- incubator/mesos/trunk/.gitignore (original)
+++ incubator/mesos/trunk/.gitignore Sun Jun 5 05:43:01 2011
@@ -78,6 +78,7 @@ src/memhog
src/memhog-executor
src/test-framework
src/test-executor
+src/scheduled-memhog
src/swig/java/nexus
src/swig/python/nexus.py
src/test_output
Modified: incubator/mesos/trunk/src/Makefile.in
URL: http://svn.apache.org/viewvc/incubator/mesos/trunk/src/Makefile.in?rev=1131871&r1=1131870&r2=1131871&view=diff
==============================================================================
--- incubator/mesos/trunk/src/Makefile.in (original)
+++ incubator/mesos/trunk/src/Makefile.in Sun Jun 5 05:43:01 2011
@@ -93,7 +93,7 @@ LIBS += -lglog -lgtest -lprocess -lev -l
NEXUS_EXES = nexus-master nexus-slave nexus-local nexus-launcher \
test-framework test-executor cpp-test-framework cpp-test-executor \
- memhog memhog-executor
+ memhog memhog-executor scheduled-memhog
ifeq ($(OS_NAME),solaris)
NEXUS_EXES += nexus-projd
@@ -108,15 +108,14 @@ NEXUS_LIB = libnexus++.a
NEXUS_LIBS = $(SCHED_LIB) $(EXEC_LIB) $(NEXUS_LIB)
MASTER_OBJ = master.o allocator_factory.o simple_allocator.o
-SLAVE_OBJ = slave.o launcher.o isolation_module_factory.o \
+SLAVE_OBJ = slave.o launcher.o isolation_module.o \
process_based_isolation_module.o
-COMMON_OBJ = fatal.o hash_pid.o messages.o lock.o master_detector.o \
- url_processor.o zookeeper.o configuration.o
+COMMON_OBJ = fatal.o hash_pid.o messages.o lock.o master_detector.o url_processor.o zookeeper.o
EXEC_LIB_OBJ = nexus_exec.o
SCHED_LIB_OBJ = nexus_sched.o nexus_local.o params.o
TEST_OBJ = tests/main.o tests/test_master.o tests/test_resources.o \
tests/external_test.o tests/test_sample_frameworks.o \
- tests/testing_utils.o tests/test_configuration.o
+ tests/test_lxc_isolation.o
ifeq ($(OS_NAME),solaris)
SLAVE_OBJ += solaris_project_isolation_module.o
@@ -226,6 +225,9 @@ memhog: memhog.cpp $(NEXUS_LIB) third_pa
memhog-executor: memhog_executor.cpp $(NEXUS_LIB) third_party/libprocess/libprocess.a
$(CXX) $(CXXFLAGS) -o $@ $< -L. $(LDFLAGS) -lnexus++ $(LIBS)
+scheduled-memhog: scheduled_memhog.cpp $(NEXUS_LIB) third_party/libprocess/libprocess.a
+ $(CXX) $(CXXFLAGS) -o $@ $< -L. $(LDFLAGS) -lnexus++ $(LIBS)
+
java: $(JAVA_LIB) swig/java/nexus.jar swig/java/TestFramework.class swig/java/TestExecutor.class swig/java/TestExceptionFramework.class swig/java/TestExceptionExecutor.class
python: $(PYTHON_LIB)
Modified: incubator/mesos/trunk/src/lxc_isolation_module.hpp
URL: http://svn.apache.org/viewvc/incubator/mesos/trunk/src/lxc_isolation_module.hpp?rev=1131871&r1=1131870&r2=1131871&view=diff
==============================================================================
--- incubator/mesos/trunk/src/lxc_isolation_module.hpp (original)
+++ incubator/mesos/trunk/src/lxc_isolation_module.hpp Sun Jun 5 05:43:01 2011
@@ -6,6 +6,8 @@
#include <boost/unordered_map.hpp>
#include "isolation_module.hpp"
+#include "messages.hpp"
+#include "slave.hpp"
namespace nexus { namespace internal { namespace slave {
Modified: incubator/mesos/trunk/src/memhog_executor.cpp
URL: http://svn.apache.org/viewvc/incubator/mesos/trunk/src/memhog_executor.cpp?rev=1131871&r1=1131870&r2=1131871&view=diff
==============================================================================
--- incubator/mesos/trunk/src/memhog_executor.cpp (original)
+++ incubator/mesos/trunk/src/memhog_executor.cpp Sun Jun 5 05:43:01 2011
@@ -83,7 +83,7 @@ void* runTask(void* threadArg)
pos = nextRand(pos);
data[pos % arg->memToHog] = pos;
count++;
- if (count == 5000) {
+ if (count == 2000) {
// Check whether enough time has elapsed to end the task
count = 0;
time_t now = time(0);
Modified: incubator/mesos/trunk/src/scheduled_memhog.cpp
URL: http://svn.apache.org/viewvc/incubator/mesos/trunk/src/scheduled_memhog.cpp?rev=1131871&r1=1131870&r2=1131871&view=diff
==============================================================================
--- incubator/mesos/trunk/src/scheduled_memhog.cpp (original)
+++ incubator/mesos/trunk/src/scheduled_memhog.cpp Sun Jun 5 05:43:01 2011
@@ -1,5 +1,9 @@
#include <nexus_sched.hpp>
+#include <libgen.h>
+#include <stdlib.h>
+#include <unistd.h>
+
#include <algorithm>
#include <cstdlib>
#include <iostream>
@@ -9,6 +13,8 @@
#include <boost/lexical_cast.hpp>
#include <boost/unordered_map.hpp>
+#include <glog/logging.h>
+
#include "foreach.hpp"
using namespace std;
@@ -22,9 +28,13 @@ struct Task {
double duration;
bool launched;
bool finished;
+ int64_t memToRequest;
+ int64_t memToHog;
- Task(double launchTime_, double duration_)
+ Task(double launchTime_, double duration_,
+ int64_t memToRequest_, int64_t memToHog_)
: launchTime(launchTime_), duration(duration_),
+ memToRequest(memToRequest_), memToHog(memToHog_),
launched(0), finished(0) {}
};
@@ -39,32 +49,40 @@ struct TaskComparator
class MyScheduler : public Scheduler
{
+public:
string executor;
double taskLen;
int threadsPerTask;
- int64_t memToRequest;
- int64_t memToHog;
string scheduleFile;
vector<Task> tasks;
time_t startTime;
int tasksLaunched;
int tasksFinished;
+ int successfulTasks;
-public:
MyScheduler(const string& executor_, const string& scheduleFile_,
- int threadsPerTask_, int64_t memToRequest_, int64_t memToHog_)
+ int threadsPerTask_)
: executor(executor_), scheduleFile(scheduleFile_),
threadsPerTask(threadsPerTask_),
- memToRequest(memToRequest_), memToHog(memToHog_),
- tasksLaunched(0), tasksFinished(0)
+ tasksLaunched(0), tasksFinished(0), successfulTasks(0)
{
ifstream in(scheduleFile.c_str());
double launchTime;
double duration;
- while (in >> launchTime >> duration) {
- tasks.push_back(Task(launchTime, duration));
+ int64_t memToRequest;
+ int64_t memToHog;
+ while (in >> launchTime >> duration >> memToRequest >> memToHog) {
+ memToRequest *= (1024 * 1024);
+ memToHog *= (1024 * 1024);
+ tasks.push_back(Task(launchTime, duration, memToRequest, memToHog));
}
in.close();
+ LOG(INFO) << "Loaded " << tasks.size() << " tasks";
+ if (tasks.size() == 0) {
+ cerr << "Schedule file contained no tasks!" << endl;
+ exit(1);
+ }
+ // Sort tasks by start time
TaskComparator comp;
sort(tasks.begin(), tasks.end(), comp);
}
@@ -80,7 +98,7 @@ public:
}
virtual void registered(SchedulerDriver*, FrameworkID fid) {
- cout << "Registered!" << endl;
+ LOG(INFO) << "Registered!";
startTime = time(0);
}
@@ -94,15 +112,19 @@ public:
// This is kind of ugly because operator[] isn't a const function
int32_t cpus = lexical_cast<int32_t>(offer.params.find("cpus")->second);
int64_t mem = lexical_cast<int64_t>(offer.params.find("mem")->second);
- if ((tasksLaunched < tasks.size()) && (cpus >= 1 && mem >= memToRequest) &&
- curTime >= tasks[tasksLaunched].launchTime) {
+ if (tasksLaunched < tasks.size() &&
+ cpus >= 1 &&
+ curTime >= tasks[tasksLaunched].launchTime &&
+ mem >= tasks[tasksLaunched].memToRequest)
+ {
TaskID tid = tasksLaunched++;
- cout << "Launcing task " << tid << " on " << offer.host << endl;
+ LOG(INFO) << "Launcing task " << tid << " on " << offer.host;
map<string, string> params;
params["cpus"] = "1";
- params["mem"] = lexical_cast<string>(memToRequest);
+ params["mem"] = lexical_cast<string>(tasks[tid].memToRequest);
ostringstream arg;
- arg << memToHog << " " << tasks[tid].duration << " " << threadsPerTask;
+ arg << tasks[tid].memToHog << " " << tasks[tid].duration
+ << " " << threadsPerTask;
TaskDescription desc(tid, offer.slaveId, "task", params, arg.str());
toLaunch.push_back(desc);
}
@@ -112,11 +134,14 @@ public:
}
virtual void statusUpdate(SchedulerDriver* d, const TaskStatus& status) {
- cout << "Task " << status.taskId << " is in state " << status.state << endl;
+ LOG(INFO) << "Task " << status.taskId << " is in state " << status.state;
if (status.state == TASK_FINISHED || status.state == TASK_FAILED ||
status.state == TASK_KILLED || status.state == TASK_LOST) {
tasks[status.taskId].finished = true;
tasksFinished++;
+ if (status.state == TASK_FINISHED) {
+ successfulTasks++;
+ }
if (tasksFinished == tasks.size()) {
d->stop();
}
@@ -126,21 +151,15 @@ public:
int main(int argc, char ** argv) {
- if (argc != 6) {
- cerr << "Usage: " << argv[0]
- << " <master> <schedule_file> <threads_per_task>"
- << " <MB_to_request> <MB_per_task>" << endl;
+ if (argc != 3) {
+ cerr << "Usage: " << argv[0] << " <master> <schedule_file>";
return -1;
}
- char cwd[512];
- getcwd(cwd, sizeof(cwd));
- string executor = string(cwd) + "/memhog-executor";
- MyScheduler sched(executor,
- argv[2],
- lexical_cast<int>(argv[3]),
- lexical_cast<int64_t>(argv[4]) * 1024 * 1024,
- lexical_cast<int64_t>(argv[5]) * 1024 * 1024);
+ char buf[4096];
+ realpath(dirname(argv[0]), buf);
+ string executor = string(buf) + "/memhog-executor";
+ MyScheduler sched(executor, argv[2], 1);
NexusSchedulerDriver driver(&sched, argv[1]);
driver.run();
- return 0;
+ return (sched.successfulTasks == sched.tasks.size()) ? 0 : 1;
}
Added: incubator/mesos/trunk/src/tests/external/LxcIsolation/HoldMoreMemThanRequested.sh
URL: http://svn.apache.org/viewvc/incubator/mesos/trunk/src/tests/external/LxcIsolation/HoldMoreMemThanRequested.sh?rev=1131871&view=auto
==============================================================================
--- incubator/mesos/trunk/src/tests/external/LxcIsolation/HoldMoreMemThanRequested.sh (added)
+++ incubator/mesos/trunk/src/tests/external/LxcIsolation/HoldMoreMemThanRequested.sh Sun Jun 5 05:43:01 2011
@@ -0,0 +1,18 @@
+#!/bin/bash
+
+# Create scheduled-memhog's schedule file. In this schedule, we launch two
+# tasks that each claim to require 200 MB, but the first task only uses 50 MB
+# while the second uses 350. While both tasks are running, this is fine, but
+# once the first task finishes, the framework's memory can't be scaled down
+# below 350 and so the LXC isolation module should kill it.
+echo "
+0 10 200 50
+0 30 200 350
+" > schedule
+
+# Expect exit code 1 (returned by scheduled-memhog if some of its tasks fail)
+export DESIRED_MEMHOG_EXIT_CODE=1
+
+# Exec run_scheduled_memhog_test.sh, which actually runs the test and reports
+# whether memhog gave the desired exit status through its exit status
+exec $MESOS_HOME/tests/external/LxcIsolation/run_scheduled_memhog_test.sh
Propchange: incubator/mesos/trunk/src/tests/external/LxcIsolation/HoldMoreMemThanRequested.sh
------------------------------------------------------------------------------
svn:executable = *
Added: incubator/mesos/trunk/src/tests/external/LxcIsolation/ScaleUpAndDown.sh
URL: http://svn.apache.org/viewvc/incubator/mesos/trunk/src/tests/external/LxcIsolation/ScaleUpAndDown.sh?rev=1131871&view=auto
==============================================================================
--- incubator/mesos/trunk/src/tests/external/LxcIsolation/ScaleUpAndDown.sh (added)
+++ incubator/mesos/trunk/src/tests/external/LxcIsolation/ScaleUpAndDown.sh Sun Jun 5 05:43:01 2011
@@ -0,0 +1,13 @@
+#!/bin/bash
+
+# Create scheduled-memhog's schedule file
+echo "
+0 30 200 200
+10 10 200 200
+" > schedule
+
+export DESIRED_MEMHOG_EXIT_CODE=0
+
+# Exec run_scheduled_memhog_test.sh, which actually runs the test and reports
+# whether memhog gave the desired exit status through its exit status
+exec $MESOS_HOME/tests/external/LxcIsolation/run_scheduled_memhog_test.sh
Propchange: incubator/mesos/trunk/src/tests/external/LxcIsolation/ScaleUpAndDown.sh
------------------------------------------------------------------------------
svn:executable = *
Added: incubator/mesos/trunk/src/tests/external/LxcIsolation/TwoSeparateTasks.sh
URL: http://svn.apache.org/viewvc/incubator/mesos/trunk/src/tests/external/LxcIsolation/TwoSeparateTasks.sh?rev=1131871&view=auto
==============================================================================
--- incubator/mesos/trunk/src/tests/external/LxcIsolation/TwoSeparateTasks.sh (added)
+++ incubator/mesos/trunk/src/tests/external/LxcIsolation/TwoSeparateTasks.sh Sun Jun 5 05:43:01 2011
@@ -0,0 +1,13 @@
+#!/bin/bash
+
+# Create scheduled-memhog's schedule file
+echo "
+0 5 200 200
+10 5 200 200
+" > schedule
+
+export DESIRED_MEMHOG_EXIT_CODE=0
+
+# Exec run_scheduled_memhog_test.sh, which actually runs the test and reports
+# whether memhog gave the desired exit status through its exit status
+exec $MESOS_HOME/tests/external/LxcIsolation/run_scheduled_memhog_test.sh
Propchange: incubator/mesos/trunk/src/tests/external/LxcIsolation/TwoSeparateTasks.sh
------------------------------------------------------------------------------
svn:executable = *
Added: incubator/mesos/trunk/src/tests/external/LxcIsolation/run_scheduled_memhog_test.sh
URL: http://svn.apache.org/viewvc/incubator/mesos/trunk/src/tests/external/LxcIsolation/run_scheduled_memhog_test.sh?rev=1131871&view=auto
==============================================================================
--- incubator/mesos/trunk/src/tests/external/LxcIsolation/run_scheduled_memhog_test.sh (added)
+++ incubator/mesos/trunk/src/tests/external/LxcIsolation/run_scheduled_memhog_test.sh Sun Jun 5 05:43:01 2011
@@ -0,0 +1,66 @@
+#!/bin/bash
+
+# This script runs scheduled-memhog with the schedule file in ./schedule on a
+# cluster using Linux Containers isolation, and checks if it returns
+# $DESIRED_MEMHOG_EXIT_CODE (set through the # environment).
+# It is invoked by the actual tests (TwoSeparateTasks.sh, etc) after creating
+# the schedule file and setting DESIRED_MEMHOG_EXIT_CODE.
+
+# Check that we're running as root
+if [[ $EUID -ne 0 ]]; then
+ echo "This test must be run as root because it uses Linux Containers." >&2
+ exit 2
+fi
+
+# Launch master
+$MESOS_HOME/nexus-master -p 5432 > master.log 2>&1 &
+MASTER_PID=$!
+echo "Launched master, PID = $MASTER_PID"
+sleep 2
+
+# Check if it's still running after 2 seconds
+kill -0 $MASTER_PID
+KILL_EXIT_CODE=$?
+if [[ $KILL_EXIT_CODE -ne 0 ]]; then
+ echo "Master crashed; failing test"
+ exit 2
+fi
+
+# Launch slave
+$MESOS_HOME/nexus-slave -u 1@$HOSTNAME:5432 -i lxc \
+ -c 2 -m $[512*1024*1024] > slave.log 2>&1 &
+SLAVE_PID=$!
+echo "Launched slave, PID = $SLAVE_PID"
+sleep 2
+
+# Check if it's still running after 2 seconds
+kill -0 $SLAVE_PID
+KILL_EXIT_CODE=$?
+if [[ $KILL_EXIT_CODE -ne 0 ]]; then
+ echo "Slave crashed; failing test"
+ kill $MASTER_PID
+ exit 2
+fi
+
+# Launch memhog
+echo "Running scheduled-memhog"
+$MESOS_HOME/scheduled-memhog 1@$HOSTNAME:5432 schedule > memhog.log 2>&1
+EXIT_CODE=$?
+echo "Memhog exit code: $?"
+sleep 2
+
+# Kill everything once memhog exited
+echo "Killing slave: $SLAVE_PID"
+kill $SLAVE_PID
+sleep 2
+echo "Killing master: $MASTER_PID"
+kill $MASTER_PID
+sleep 2
+
+echo "Exiting"
+# Check whether memhog returned the right code
+if [[ $EXIT_CODE -eq $DESIRED_MEMHOG_EXIT_CODE ]]; then
+ exit 0
+else
+ exit 1
+fi
Modified: incubator/mesos/trunk/src/tests/external_test.cpp
URL: http://svn.apache.org/viewvc/incubator/mesos/trunk/src/tests/external_test.cpp?rev=1131871&r1=1131870&r2=1131871&view=diff
==============================================================================
--- incubator/mesos/trunk/src/tests/external_test.cpp (original)
+++ incubator/mesos/trunk/src/tests/external_test.cpp Sun Jun 5 05:43:01 2011
@@ -1,5 +1,6 @@
#include <gtest/gtest.h>
+#include <ctype.h>
#include <stdlib.h>
#include <string>
@@ -11,7 +12,21 @@
#include "testing_utils.hpp"
using std::string;
-using namespace nexus::internal::test;
+
+namespace {
+
+// Check that a test name contains only letters, numbers and underscores, to
+// prevent messing with directories outside test_output in runExternalTest.
+bool isValidTestName(const char* name) {
+ for (const char* p = name; *p != 0; p++) {
+ if (!isalnum(*p) && *p != '_') {
+ return false;
+ }
+ }
+ return true;
+}
+
+}
/**
@@ -21,14 +36,25 @@ using namespace nexus::internal::test;
* piping its output to files called stdout and stderr, and the test
* passes if the script returns 0.
*/
-void nexus::internal::test::runExternalTest(const char* testCase,
- const char* testName)
+void nexus::test::runExternalTest(const char* testCase, const char* testName)
{
- // Create and go into the test's work directory
- enterTestDirectory(testCase, testName);
+ // Remove DISABLED_ prefix from test name if this is a disabled test
+ if (strncmp(testName, "DISABLED_", strlen("DISABLED_")) == 0)
+ testName += strlen("DISABLED_");
+ // Check that the test name is valid
+ if (!isValidTestName(testCase) || !isValidTestName(testName)) {
+ FAIL() << "Invalid test name for external test (name should "
+ << "only contain alphanumeric and underscore characters)";
+ }
// Figure out the absolute path to the test script
- string script = mesosHome + "/tests/external/" + testCase
+ string script = MESOS_HOME + "/tests/external/" + testCase
+ "/" + testName + ".sh";
+ // Make the work directory for this test
+ string workDir = MESOS_HOME + "/test_output/" + testCase + "/" + testName;
+ string command = "rm -fr '" + workDir + "'";
+ ASSERT_EQ(0, system(command.c_str())) << "Command failed: " << command;
+ command = "mkdir -p '" + workDir + "'";
+ ASSERT_EQ(0, system(command.c_str())) << "Command failed: " << command;
// Fork a process to change directory and run the test
pid_t pid;
if ((pid = fork()) == -1) {
@@ -40,13 +66,14 @@ void nexus::internal::test::runExternalT
wait(&exitCode);
ASSERT_EQ(0, exitCode) << "External test " << testName << " failed";
} else {
- // In child process. Redirect standard output and error to files,
+ // In child process. Go into to the work directory, redirect IO to files,
// set MESOS_HOME environment variable, and exec the test script.
+ chdir(workDir.c_str());
if (freopen("stdout", "w", stdout) == NULL)
fatalerror("freopen failed");
if (freopen("stderr", "w", stderr) == NULL)
fatalerror("freopen failed");
- setenv("MESOS_HOME", mesosHome.c_str(), 1);
+ setenv("MESOS_HOME", MESOS_HOME.c_str(), 1);
execl(script.c_str(), script.c_str(), (char*) NULL);
// If we get here, execl failed; report the error
fatalerror("Could not execute %s", script.c_str());
Added: incubator/mesos/trunk/src/tests/test_lxc_isolation.cpp
URL: http://svn.apache.org/viewvc/incubator/mesos/trunk/src/tests/test_lxc_isolation.cpp?rev=1131871&view=auto
==============================================================================
--- incubator/mesos/trunk/src/tests/test_lxc_isolation.cpp (added)
+++ incubator/mesos/trunk/src/tests/test_lxc_isolation.cpp Sun Jun 5 05:43:01 2011
@@ -0,0 +1,12 @@
+#include <gtest/gtest.h>
+
+#include "external_test.hpp"
+
+// Run a number of tests for the LXC isolation module.
+// These tests are disabled by default since they require alltests to be run
+// with sudo for Linux Container commands to be usable (and of course, they
+// also require a Linux version with LXC support).
+// You can enable them using ./alltests --gtest_also_run_disabled_tests.
+TEST_EXTERNAL(LxcIsolation, DISABLED_TwoSeparateTasks)
+TEST_EXTERNAL(LxcIsolation, DISABLED_ScaleUpAndDown)
+TEST_EXTERNAL(LxcIsolation, DISABLED_HoldMoreMemThanRequested)