You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mesos.apache.org by an...@apache.org on 2018/02/26 07:24:20 UTC
[04/12] mesos git commit: Windows: Enabled Docker health checks.
Windows: Enabled Docker health checks.
The network health checks called `curl` and then executed `setns()` to
enter to container network namespace, which did not work on Windows.
To do the equivalent, Windows now calls `docker run` with PowerShell's
`curl` equivalent, `Invoke-WebRequest`, and uses the
`network=container:<ID>` flag to enter the container's namespace. The
command health check was trivially fixed by replacing the hard-coded
`sh -c`.
Review: https://reviews.apache.org/r/65127/
Project: http://git-wip-us.apache.org/repos/asf/mesos/repo
Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/97dadbe1
Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/97dadbe1
Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/97dadbe1
Branch: refs/heads/master
Commit: 97dadbe132efb21dc46d53b48b39c425fa8715f5
Parents: 3b6d58c
Author: Akash Gupta <ak...@hotmail.com>
Authored: Sat Feb 24 12:10:47 2018 -0800
Committer: Andrew Schwartzmeyer <an...@schwartzmeyer.com>
Committed: Sun Feb 25 22:13:32 2018 -0800
----------------------------------------------------------------------
src/checks/checker_process.cpp | 123 +++++++++++++++++++++++++++++-------
src/checks/checker_process.hpp | 12 ++++
2 files changed, 113 insertions(+), 22 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/mesos/blob/97dadbe1/src/checks/checker_process.cpp
----------------------------------------------------------------------
diff --git a/src/checks/checker_process.cpp b/src/checks/checker_process.cpp
index 1e696ad..cf9ec05 100644
--- a/src/checks/checker_process.cpp
+++ b/src/checks/checker_process.cpp
@@ -561,8 +561,8 @@ Future<int> CheckerProcess::dockerCommandCheck(
commandArguments.push_back(docker.containerName);
if (command.shell()) {
- commandArguments.push_back("sh");
- commandArguments.push_back("-c");
+ commandArguments.push_back(os::Shell::name);
+ commandArguments.push_back(os::Shell::arg1);
// We don't need to quote the arguments, because we're converting the
// shell command to the executable form.
@@ -992,9 +992,6 @@ Future<int> CheckerProcess::httpCheck(
const string url = http.scheme + "://" + http.domain + ":" +
stringify(http.port) + http.path;
- VLOG(1) << "Launching " << name << " '" << url << "'"
- << " for task '" << taskId << "'";
-
const vector<string> argv = {
HTTP_CHECK_COMMAND,
"-s", // Don't show progress meter or error messages.
@@ -1007,11 +1004,22 @@ Future<int> CheckerProcess::httpCheck(
url
};
+ return _httpCheck(argv, plain);
+}
+
+
+Future<int> CheckerProcess::_httpCheck(
+ const vector<string>& cmdArgv,
+ const Option<runtime::Plain>& plain)
+{
+ VLOG(1) << "Launching " << name << " with command '"
+ << strings::join(" ", cmdArgv) << "' for task '" << taskId << "'";
+
// TODO(alexr): Consider launching the helper binary once per task lifetime,
// see MESOS-6766.
Try<Subprocess> s = process::subprocess(
- HTTP_CHECK_COMMAND,
- argv,
+ cmdArgv[0],
+ cmdArgv,
Subprocess::PATH(os::DEV_NULL),
Subprocess::PIPE(),
Subprocess::PIPE(),
@@ -1056,11 +1064,11 @@ Future<int> CheckerProcess::httpCheck(
string(HTTP_CHECK_COMMAND) + " timed out after " +
stringify(timeout));
})
- .then(defer(self(), &Self::_httpCheck, lambda::_1));
+ .then(defer(self(), &Self::__httpCheck, lambda::_1));
}
-Future<int> CheckerProcess::_httpCheck(
+Future<int> CheckerProcess::__httpCheck(
const tuple<Future<Option<int>>, Future<string>, Future<string>>& t)
{
const Future<Option<int>>& status = std::get<0>(t);
@@ -1101,7 +1109,7 @@ Future<int> CheckerProcess::_httpCheck(
<< "': " << commandOutput.get();
// Parse the output and get the HTTP status code.
- Try<int> statusCode = numify<int>(commandOutput.get());
+ Try<int> statusCode = numify<int>(strings::trim(commandOutput.get()));
if (statusCode.isError()) {
return Failure(
"Unexpected output from " + string(HTTP_CHECK_COMMAND) + ": " +
@@ -1144,12 +1152,58 @@ void CheckerProcess::processHttpCheckResult(
#ifdef __WINDOWS__
+static vector<string> dockerNetworkRunCommand(
+ const runtime::Docker& docker,
+ const string& image)
+{
+ return {
+ docker.dockerPath,
+ "-H",
+ docker.socketName,
+ "run",
+ "--rm",
+ "--network=container:" + docker.containerName,
+ image,
+ "pwsh",
+ "-Command"
+ };
+}
+
+
+// On Windows, we can't directly change a process's namespace. So, for the
+// Docker HTTP checks, we need to use the network=container feature in
+// Docker to run the network check in the right namespace.
Future<int> CheckerProcess::dockerHttpCheck(
const check::Http& http,
const runtime::Docker& docker)
{
- // TODO(akagup): A later patch will implement this.
- return httpCheck(http, runtime::Plain{docker.namespaces, docker.taskPid});
+ vector<string> argv =
+ dockerNetworkRunCommand(docker, DOCKER_HEALTH_CHECK_IMAGE);
+
+ const string url = http.scheme + "://" + http.domain + ":" +
+ stringify(http.port) + http.path;
+
+ vector<string> httpCheckCommandParameters = {
+ "Invoke-WebRequest",
+ "-Uri", url,
+ "-UseBasicParsing", // Needed for nanoserver.
+ "-SkipCertificateCheck", // Similar to `curl -k`.
+ "|",
+ "Out-File", // Write status to file.
+ "-InputObject", "{$_.StatusCode}", // Just return status code.
+ "-Path", "$HOME\\status",
+ "-Encoding", "ASCII", // Avoid UTF-16 encoding.
+ "-NoNewline",
+ ";",
+ "Get-Content", "-Raw", "$HOME\\status" // Output status code.
+ };
+
+ argv.insert(
+ argv.end(),
+ httpCheckCommandParameters.cbegin(),
+ httpCheckCommandParameters.cend());
+
+ return _httpCheck(argv, runtime::Plain{docker.namespaces, docker.taskPid});
}
#endif // __WINDOWS__
@@ -1158,9 +1212,6 @@ Future<bool> CheckerProcess::tcpCheck(
const check::Tcp& tcp,
const Option<runtime::Plain>& plain)
{
- VLOG(1) << "Launching " << name << " for task '" << taskId << "'"
- << " at port " << tcp.port;
-
const string command = path::join(tcp.launcherDir, TCP_CHECK_COMMAND);
const vector<string> argv = {
@@ -1168,12 +1219,21 @@ Future<bool> CheckerProcess::tcpCheck(
"--ip=" + tcp.domain,
"--port=" + stringify(tcp.port)
};
+ return _tcpCheck(argv, plain);
+}
+
+Future<bool> CheckerProcess::_tcpCheck(
+ const vector<string>& cmdArgv,
+ const Option<runtime::Plain>& plain)
+{
+ VLOG(1) << "Launching " << name << " for task '" << taskId << "'"
+ << " with command '" << strings::join(" ", cmdArgv) << "'";
// TODO(alexr): Consider launching the helper binary once per task lifetime,
// see MESOS-6766.
Try<Subprocess> s = subprocess(
- command,
- argv,
+ cmdArgv[0],
+ cmdArgv,
Subprocess::PATH(os::DEV_NULL),
Subprocess::PIPE(),
Subprocess::PIPE(),
@@ -1183,7 +1243,7 @@ Future<bool> CheckerProcess::tcpCheck(
if (s.isError()) {
return Failure(
- "Failed to create the " + command + " subprocess: " + s.error());
+ "Failed to create the " + cmdArgv[0] + " subprocess: " + s.error());
}
// TODO(alexr): Use lambda named captures for
@@ -1216,11 +1276,11 @@ Future<bool> CheckerProcess::tcpCheck(
return Failure(
string(TCP_CHECK_COMMAND) + " timed out after " + stringify(timeout));
})
- .then(defer(self(), &Self::_tcpCheck, lambda::_1));
+ .then(defer(self(), &Self::__tcpCheck, lambda::_1));
}
-Future<bool> CheckerProcess::_tcpCheck(
+Future<bool> CheckerProcess::__tcpCheck(
const tuple<Future<Option<int>>, Future<string>, Future<string>>& t)
{
const Future<Option<int>>& status = std::get<0>(t);
@@ -1289,12 +1349,31 @@ void CheckerProcess::processTcpCheckResult(
#ifdef __WINDOWS__
+// On Windows, we can't directly change a process's namespace. So, for the
+// Docker TCP checks, we need to use the network=container feature in
+// Docker to run the network check in the right namespace.
Future<bool> CheckerProcess::dockerTcpCheck(
const check::Tcp& tcp,
const runtime::Docker& docker)
{
- // TODO(akagup): A later patch will implement this.
- return tcpCheck(tcp, runtime::Plain{docker.namespaces, docker.taskPid});
+ vector<string> argv =
+ dockerNetworkRunCommand(docker, DOCKER_HEALTH_CHECK_IMAGE);
+
+ // Test-NetConnection doesn't exist on PowerShell Core, so we
+ // call the C# TcpClient library instead. Command looks like:
+ // (New-Object System.Net.Sockets.TcpClient(IP, PORT)).Close()
+ vector<string> tcpCheckCommandParameters = {
+ "(New-Object",
+ "System.Net.Sockets.TcpClient(\"" + tcp.domain + "\",",
+ stringify(tcp.port) + ")).Close()"
+ };
+
+ argv.insert(
+ argv.end(),
+ tcpCheckCommandParameters.cbegin(),
+ tcpCheckCommandParameters.cend());
+
+ return _tcpCheck(argv, runtime::Plain{docker.namespaces, docker.taskPid});
}
#endif // __WINDOWS__
http://git-wip-us.apache.org/repos/asf/mesos/blob/97dadbe1/src/checks/checker_process.hpp
----------------------------------------------------------------------
diff --git a/src/checks/checker_process.hpp b/src/checks/checker_process.hpp
index ac0cd66..228ac78 100644
--- a/src/checks/checker_process.hpp
+++ b/src/checks/checker_process.hpp
@@ -41,6 +41,12 @@ namespace mesos {
namespace internal {
namespace checks {
+#ifdef __WINDOWS__
+// TODO(akagup): Change this to a newer nanoserver image once they come with
+// curl by default. See MESOS-8499.
+constexpr char DOCKER_HEALTH_CHECK_IMAGE[] = "microsoft/powershell:nanoserver";
+#endif // __WINDOWS__
+
class CheckerProcess : public ProtobufProcess<CheckerProcess>
{
public:
@@ -127,6 +133,9 @@ private:
const check::Http& http,
const Option<runtime::Plain>& plain);
process::Future<int> _httpCheck(
+ const std::vector<std::string>& cmdArgv,
+ const Option<runtime::Plain>& plain);
+ process::Future<int> __httpCheck(
const std::tuple<process::Future<Option<int>>,
process::Future<std::string>,
process::Future<std::string>>& t);
@@ -145,6 +154,9 @@ private:
const check::Tcp& tcp,
const Option<runtime::Plain>& plain);
process::Future<bool> _tcpCheck(
+ const std::vector<std::string>& cmdArgv,
+ const Option<runtime::Plain>& plain);
+ process::Future<bool> __tcpCheck(
const std::tuple<process::Future<Option<int>>,
process::Future<std::string>,
process::Future<std::string>>& t);