Future<Nothing> HealthCheckerProcess::__tcpHealthCheck( const tuple< Future<Option<int>>, Future<string>, Future<string>>& t) { Future<Option<int>> status = std::get<0>(t); if (!status.isReady()) { return Failure( "Failed to get the exit status of the " + string(TCP_CHECK_COMMAND) + " process: " + (status.isFailed() ? status.failure() : "discarded")); } if (status->isNone()) { return Failure( "Failed to reap the " + string(TCP_CHECK_COMMAND) + " process"); } int statusCode = status->get(); if (statusCode != 0) { Future<string> error = std::get<2>(t); if (!error.isReady()) { return Failure( string(TCP_CHECK_COMMAND) + " returned " + WSTRINGIFY(statusCode) + "; reading stderr failed: " + (error.isFailed() ? error.failure() : "discarded")); } return Failure( string(TCP_CHECK_COMMAND) + " returned " + WSTRINGIFY(statusCode) + ": " + error.get()); } return Nothing(); }
Future<Nothing> HealthCheckerProcess::__httpHealthCheck( const tuple< Future<Option<int>>, Future<string>, Future<string>>& t) { Future<Option<int>> status = std::get<0>(t); if (!status.isReady()) { return Failure( "Failed to get the exit status of the " + string(HTTP_CHECK_COMMAND) + " process: " + (status.isFailed() ? status.failure() : "discarded")); } if (status->isNone()) { return Failure( "Failed to reap the " + string(HTTP_CHECK_COMMAND) + " process"); } int statusCode = status->get(); if (statusCode != 0) { Future<string> error = std::get<2>(t); if (!error.isReady()) { return Failure( string(HTTP_CHECK_COMMAND) + " returned " + WSTRINGIFY(statusCode) + "; reading stderr failed: " + (error.isFailed() ? error.failure() : "discarded")); } return Failure( string(HTTP_CHECK_COMMAND) + " returned " + WSTRINGIFY(statusCode) + ": " + error.get()); } Future<string> output = std::get<1>(t); if (!output.isReady()) { return Failure( "Failed to read stdout from " + string(HTTP_CHECK_COMMAND) + ": " + (output.isFailed() ? output.failure() : "discarded")); } // Parse the output and get the HTTP response code. Try<int> code = numify<int>(output.get()); if (code.isError()) { return Failure( "Unexpected output from " + string(HTTP_CHECK_COMMAND) + ": " + output.get()); } if (code.get() < process::http::Status::OK || code.get() >= process::http::Status::BAD_REQUEST) { return Failure( "Unexpected HTTP response code: " + process::http::Status::string(code.get())); } return Nothing(); }
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(); }); }
Future<Nothing> NetworkCniIsolatorProcess::_detach( const ContainerID& containerId, const std::string& networkName, const string& plugin, const tuple<Future<Option<int>>, Future<string>>& t) { CHECK(infos.contains(containerId)); CHECK(infos[containerId]->containerNetworks.contains(networkName)); Future<Option<int>> status = std::get<0>(t); if (!status.isReady()) { return Failure( "Failed to get the exit status of the CNI plugin '" + plugin + "' subprocess: " + (status.isFailed() ? status.failure() : "discarded")); } if (status->isNone()) { return Failure( "Failed to reap the CNI plugin '" + plugin + "' subprocess"); } if (status.get() == 0) { const string ifDir = paths::getInterfaceDir( rootDir.get(), containerId.value(), networkName, infos[containerId]->containerNetworks[networkName].ifName); Try<Nothing> rmdir = os::rmdir(ifDir); if (rmdir.isError()) { return Failure( "Failed to remove interface directory '" + ifDir + "': " + rmdir.error()); } return Nothing(); } // CNI plugin will print result (in case of success) or error (in // case of failure) to stdout. Future<string> output = std::get<1>(t); if (!output.isReady()) { return Failure( "Failed to read stdout from the CNI plugin '" + plugin + "' subprocess: " + (output.isFailed() ? output.failure() : "discarded")); } return Failure( "The CNI plugin '" + plugin + "' failed to detach container " "from network '" + networkName + "': " + output.get()); }
static Future<Nothing> _fetch(const Future<std::tuple< Future<Option<int>>, Future<string>, Future<string>>>& future) { CHECK_READY(future); Future<Option<int>> status = std::get<0>(future.get()); if (!status.isReady()) { return Failure( "Failed to get the exit status of the curl subprocess: " + (status.isFailed() ? status.failure() : "discarded")); } if (status->isNone()) { return Failure("Failed to reap the curl subprocess"); } if (status->get() != 0) { Future<string> error = std::get<2>(future.get()); if (!error.isReady()) { return Failure( "Failed to perform 'curl'. Reading stderr failed: " + (error.isFailed() ? error.failure() : "discarded")); } return Failure("Failed to perform 'curl': " + error.get()); } Future<string> output = std::get<1>(future.get()); if (!output.isReady()) { return Failure( "Failed to read stdout from 'curl': " + (output.isFailed() ? output.failure() : "discarded")); } // Parse the output and get the HTTP response code. Try<int> code = numify<int>(output.get()); if (code.isError()) { return Failure("Unexpected output from 'curl': " + output.get()); } if (code.get() != http::Status::OK) { return Failure( "Unexpected HTTP response code: " + http::Status::string(code.get())); } return Nothing(); }
void _read(const Pipe::Reader& reader, const Future<Result<Event>>& event) { CHECK(!event.isDiscarded()); // Ignore enqueued events from the previous Subscribe call reader. if (subscribed.isNone() || subscribed->reader != reader) { VLOG(1) << "Ignoring event from old stale connection"; return; } CHECK_EQ(SUBSCRIBED, state); CHECK_SOME(connectionId); // This could happen if the agent process died while sending a response. if (event.isFailed()) { LOG(ERROR) << "Failed to decode the stream of events: " << event.failure(); disconnected(connectionId.get(), event.failure()); return; } // This could happen if the agent failed over after sending an event. if (event->isNone()) { const string error = "End-Of-File received from agent. The agent closed " "the event stream"; LOG(ERROR) << error; disconnected(connectionId.get(), error); return; } if (event->isError()) { error("Failed to de-serialize event: " + event->error()); return; } receive(event.get().get(), false); read(); }
Future<Nothing> CopyFetcherPlugin::fetch( const URI& uri, const string& directory) const { // TODO(jojy): Validate the given URI. if (!uri.has_path()) { return Failure("URI path is not specified"); } // TODO(jojy): Verify that the path is a file. Try<Nothing> mkdir = os::mkdir(directory); if (mkdir.isError()) { return Failure( "Failed to create directory '" + directory + "': " + mkdir.error()); } VLOG(1) << "Copying '" << uri.path() << "' to '" << directory << "'"; const vector<string> argv = {"cp", "-a", uri.path(), directory}; Try<Subprocess> s = subprocess( "cp", argv, Subprocess::PATH(os::DEV_NULL), Subprocess::PIPE(), Subprocess::PIPE()); if (s.isError()) { return Failure("Failed to exec the copy subprocess: " + s.error()); } return await( s.get().status(), io::read(s.get().out().get()), io::read(s.get().err().get())) .then([](const tuple< Future<Option<int>>, Future<string>, 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 copy subprocess: " + (status.isFailed() ? status.failure() : "discarded")); } if (status->isNone()) { return Failure("Failed to reap the copy subprocess"); } if (status->get() != 0) { Future<string> error = std::get<2>(t); if (!error.isReady()) { return Failure( "Failed to perform 'copy'. Reading stderr failed: " + (error.isFailed() ? error.failure() : "discarded")); } return Failure("Failed to perform 'copy': " + error.get()); } return Nothing(); }); }
Future<Nothing> CurlFetcherPlugin::fetch( const URI& uri, const string& directory) { // TODO(jieyu): Validate the given URI. if (!uri.has_path()) { return Failure("URI path is not specified"); } Try<Nothing> mkdir = os::mkdir(directory); if (mkdir.isError()) { return Failure( "Failed to create directory '" + directory + "': " + mkdir.error()); } // TODO(jieyu): Allow user to specify the name of the output file. const string output = path::join(directory, Path(uri.path()).basename()); const vector<string> argv = { "curl", "-s", // Don’t show progress meter or error messages. "-S", // Makes curl show an error message if it fails. "-L", // Follow HTTP 3xx redirects. "-w", "%{http_code}", // Display HTTP response code on stdout. "-o", output, // Write output to the file. strings::trim(stringify(uri)) }; Try<Subprocess> s = subprocess( "curl", argv, Subprocess::PATH("/dev/null"), Subprocess::PIPE(), Subprocess::PIPE()); if (s.isError()) { return Failure("Failed to exec the curl subprocess: " + s.error()); } return await( s.get().status(), io::read(s.get().out().get()), io::read(s.get().err().get())) .then([](const tuple< Future<Option<int>>, Future<string>, 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 curl subprocess: " + (status.isFailed() ? status.failure() : "discarded")); } if (status->isNone()) { return Failure("Failed to reap the curl subprocess"); } if (status->get() != 0) { Future<string> error = std::get<2>(t); if (!error.isReady()) { return Failure( "Failed to perform 'curl'. Reading stderr failed: " + (error.isFailed() ? error.failure() : "discarded")); } return Failure("Failed to perform 'curl': " + error.get()); } Future<string> output = std::get<1>(t); if (!output.isReady()) { return Failure( "Failed to read stdout from 'curl': " + (output.isFailed() ? output.failure() : "discarded")); } // Parse the output and get the HTTP response code. Try<int> code = numify<int>(output.get()); if (code.isError()) { return Failure("Unexpected output from 'curl': " + output.get()); } if (code.get() != http::Status::OK) { return Failure( "Unexpected HTTP response code: " + http::Status::string(code.get())); } return Nothing(); }); }
Future<Nothing> NetworkCniIsolatorProcess::_attach( const ContainerID& containerId, const string& networkName, const string& plugin, const tuple<Future<Option<int>>, Future<string>>& t) { CHECK(infos.contains(containerId)); CHECK(infos[containerId]->containerNetworks.contains(networkName)); Future<Option<int>> status = std::get<0>(t); if (!status.isReady()) { return Failure( "Failed to get the exit status of the CNI plugin '" + plugin + "' subprocess: " + (status.isFailed() ? status.failure() : "discarded")); } if (status->isNone()) { return Failure( "Failed to reap the CNI plugin '" + plugin + "' subprocess"); } // CNI plugin will print result (in case of success) or error (in // case of failure) to stdout. Future<string> output = std::get<1>(t); if (!output.isReady()) { return Failure( "Failed to read stdout from the CNI plugin '" + plugin + "' subprocess: " + (output.isFailed() ? output.failure() : "discarded")); } if (status.get() != 0) { return Failure( "The CNI plugin '" + plugin + "' failed to attach container " + containerId.value() + " to CNI network '" + networkName + "': " + output.get()); } // Parse the output of CNI plugin. Try<spec::NetworkInfo> parse = spec::parseNetworkInfo(output.get()); if (parse.isError()) { return Failure( "Failed to parse the output of the CNI plugin '" + plugin + "': " + parse.error()); } if (parse.get().has_ip4()) { LOG(INFO) << "Got assigned IPv4 address '" << parse.get().ip4().ip() << "' from CNI network '" << networkName << "' for container " << containerId; } if (parse.get().has_ip6()) { LOG(INFO) << "Got assigned IPv6 address '" << parse.get().ip6().ip() << "' from CNI network '" << networkName << "' for container " << containerId; } // Checkpoint the output of CNI plugin. // The destruction of the container cannot happen in the middle of // 'attach()' and '_attach()' because the containerizer will wait // for 'isolate()' to finish before destroying the container. ContainerNetwork& containerNetwork = infos[containerId]->containerNetworks[networkName]; const string networkInfoPath = paths::getNetworkInfoPath( rootDir.get(), containerId.value(), networkName, containerNetwork.ifName); Try<Nothing> write = os::write(networkInfoPath, output.get()); if (write.isError()) { return Failure( "Failed to checkpoint the output of CNI plugin'" + output.get() + "': " + write.error()); } containerNetwork.cniNetworkInfo = parse.get(); return Nothing(); }
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; }); }