Future<Nothing> untar(const string& file, const string& directory) { const vector<string> argv = { "tar", "-C", directory, "-x", "-f", file }; Try<Subprocess> s = subprocess( "tar", argv, Subprocess::PATH("/dev/null"), Subprocess::PATH("/dev/null"), Subprocess::PIPE()); if (s.isError()) { return Failure("Failed to execute the subprocess: " + s.error()); } return await( s.get().status(), process::io::read(s.get().err().get())) .then([](const tuple< Future<Option<int>>, Future<string>>& t) -> Future<Nothing> { Future<Option<int>> status = std::get<0>(t); if (!status.isReady()) { return Failure( "Failed to get the exit status of the subprocess: " + (status.isFailed() ? status.failure() : "discarded")); } Future<string> error = std::get<1>(t); if (!error.isReady()) { return Failure( "Failed to read stderr from the subprocess: " + (error.isFailed() ? error.failure() : "discarded")); } if (status->isNone()) { return Failure("Failed to reap the subprocess"); } if (status->get() != 0) { return Failure( "Unexpected result from the subprocess: " + WSTRINGIFY(status->get()) + ", stderr='" + error.get() + "'"); } return Nothing(); }); }
void execute(const string& script) { // Create a temporary directory for the test. Try<string> directory = environment->mkdtemp(); CHECK_SOME(directory) << "Failed to create temporary directory"; if (flags.verbose) { std::cerr << "Using temporary directory '" << directory.get() << "'" << std::endl; } // Determine the path for the script. Result<string> path = os::realpath(path::join(flags.source_dir, "src", "tests", script)); if (!path.isSome()) { FAIL() << "Failed to locate script: " << (path.isError() ? path.error() : "No such file or directory"); } // Fork a process to change directory and run the test. pid_t pid; if ((pid = fork()) == -1) { FAIL() << "Failed to fork to launch script"; } if (pid > 0) { // In parent process. int status; while (wait(&status) != pid || WIFSTOPPED(status)); CHECK(WIFEXITED(status) || WIFSIGNALED(status)); if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) { FAIL() << script << " " << WSTRINGIFY(status); } } else { // In child process. DO NOT USE GLOG! // Start by cd'ing into the temporary directory. Try<Nothing> chdir = os::chdir(directory.get()); if (chdir.isError()) { std::cerr << "Failed to chdir to '" << directory.get() << "': " << chdir.error() << std::endl; abort(); } // Redirect output to /dev/null unless the test is verbose. if (!flags.verbose) { if (freopen("/dev/null", "w", stdout) == NULL || freopen("/dev/null", "w", stderr) == NULL) { std::cerr << "Failed to redirect stdout/stderr to /dev/null:" << os::strerror(errno) << std::endl; abort(); } } // Set up the environment for executing the script. os::setenv("MESOS_SOURCE_DIR", flags.source_dir); os::setenv("MESOS_BUILD_DIR", flags.build_dir); os::setenv("MESOS_WEBUI_DIR", path::join(flags.source_dir, "src", "webui")); os::setenv("MESOS_LAUNCHER_DIR", path::join(flags.build_dir, "src")); // Enable replicated log based registry. os::setenv("MESOS_REGISTRY", "replicated_log"); // Enable authentication. os::setenv("MESOS_AUTHENTICATE", "true"); // Create test credentials. const string& credentials = DEFAULT_CREDENTIAL.principal() + " " + DEFAULT_CREDENTIAL.secret(); const string& credentialsPath = path::join(directory.get(), "credentials"); CHECK_SOME(os::write(credentialsPath, credentials)) << "Failed to write credentials to '" << credentialsPath << "'"; os::setenv("MESOS_CREDENTIALS", "file://" + credentialsPath); // We set test credentials here for example frameworks to use. os::setenv("DEFAULT_PRINCIPAL", DEFAULT_CREDENTIAL.principal()); os::setenv("DEFAULT_SECRET", DEFAULT_CREDENTIAL.secret()); // TODO(bmahler): Update the example frameworks to use flags and // remove the special DEFAULT_* environment variables above. os::setenv("MESOS_PRINCIPAL", DEFAULT_CREDENTIAL.principal()); os::setenv("MESOS_SECRET", DEFAULT_CREDENTIAL.secret()); // Create test ACLs. ACLs acls; acls.set_permissive(false); mesos::ACL::RunTask* run = acls.add_run_tasks(); run->mutable_principals()->add_values(DEFAULT_CREDENTIAL.principal()); Result<string> user = os::user(); CHECK_SOME(user) << "Failed to get current user name"; run->mutable_users()->add_values(user.get()); mesos::ACL::RegisterFramework* register_ = acls.add_register_frameworks(); register_->mutable_principals()->add_values(DEFAULT_CREDENTIAL.principal()); register_->mutable_roles()->add_values("*"); const string& aclsPath = path::join(directory.get(), "acls"); CHECK_SOME(os::write(aclsPath, stringify(JSON::protobuf(acls)))) << "Failed to write ACLs to '" << aclsPath << "'"; os::setenv("MESOS_ACLS", "file://" + aclsPath); // Now execute the script. execl(path.get().c_str(), path.get().c_str(), (char*) NULL); std::cerr << "Failed to execute '" << script << "': " << os::strerror(errno) << std::endl; abort(); } }
Future<Nothing> untar(const string& file, const string& directory) { const vector<string> argv = { "tar", "-C", directory, "-x", "-f", file }; Try<Subprocess> s = subprocess( "tar", argv, Subprocess::PATH("/dev/null"), Subprocess::PATH("/dev/null"), Subprocess::PIPE()); if (s.isError()) { return Failure( "Failed to create untar subprocess for file '" + file + "': " + s.error()); } Owned<Promise<Nothing>> promise(new Promise<Nothing>()); s.get().status() .onAny([s, file, promise](const Future<Option<int>>& future) { if (!future.isReady()) { promise->fail( "Failed to launch untar subprocess for file '" + file + "': " + (future.isFailed() ? future.failure() : "future discarded")); return; } if (future.get().isNone()) { promise->fail( "Failed to get status for untar subprocess for file '" + file + "'"); return; } int status = future.get().get(); if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) { const string errorMessage = "Failed to run ntar process for file '" + file + "' (exit code: " + WSTRINGIFY(status) + ")"; // Read stderr from the process(if any) to add to the failure report. process::io::read(s.get().err().get()) .onAny([file, promise, errorMessage](const Future<string>& future) { if (!future.isReady()) { LOG(WARNING) << "Failed to read stderr from untar process for" << "file: '" << file << "': " << (future.isFailed() ? future.failure() : "future discarded"); promise->fail(errorMessage); } else { promise->fail(errorMessage + ": " + future.get()); } }); return; } promise->set(Nothing()); }); return promise->future(); }
static Future<string> launch( const string& path, const vector<string>& argv) { Try<Subprocess> s = subprocess( path, argv, Subprocess::PATH("/dev/null"), Subprocess::PIPE(), Subprocess::PIPE()); string command = strings::join( ", ", path, strings::join(", ", argv)); if (s.isError()) { return Failure( "Failed to execute the subprocess '" + command + "': " + s.error()); } return await( s.get().status(), process::io::read(s.get().out().get()), process::io::read(s.get().err().get())) .then([command](const tuple< Future<Option<int>>, Future<string>, Future<string>>& t) -> Future<string> { Future<Option<int>> status = std::get<0>(t); if (!status.isReady()) { return Failure( "Failed to get the exit status of the subprocess: " + (status.isFailed() ? status.failure() : "discarded")); } if (status->isNone()) { return Failure("Failed to reap the subprocess"); } if (status->get() != 0) { Future<string> error = std::get<2>(t); if (!error.isReady()) { return Failure( "Unexpected result from the subprocess: " + WSTRINGIFY(status->get()) + ", stderr='" + error.get() + "'"); } return Failure("Subprocess '" + command + "' failed: " + error.get()); } Future<string> output = std::get<1>(t); if (!output.isReady()) { return Failure( "Failed to read stdout from '" + command + "': " + (output.isFailed() ? output.failure() : "discarded")); } return output; }); }