You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mesos.apache.org by ji...@apache.org on 2019/01/12 00:35:25 UTC
[mesos] 01/09: Kept `CNI_NETNS` unset in detach if network
namespace is gone.
This is an automated email from the ASF dual-hosted git repository.
jieyu pushed a commit to branch 1.7.x
in repository https://gitbox.apache.org/repos/asf/mesos.git
commit 0fb3f9f14714d48a6f61b1fb97d1f1a963cb9781
Author: Jie Yu <yu...@gmail.com>
AuthorDate: Thu Jan 10 12:38:04 2019 -0800
Kept `CNI_NETNS` unset in detach if network namespace is gone.
We introduced a new agent flag in MESOS-9492 so that CNI configs can be
persisted across reboot. This is for some CNI plugins to be able to
cleanup IP allocated to the containers after a sudden reboot of the host
(not all CNI plugins need this).
It's important to unset `CNI_NETNS` environment variable after reboot
when invoking CNI plugin "DEL" command so that it conforms to the spec.
Review: https://reviews.apache.org/r/69706
(cherry picked from commit 9863daca0baaa52984dc42c27c6e4e33c3b169b5)
---
.../mesos/isolators/network/cni/cni.cpp | 103 +++++++++++++++------
1 file changed, 75 insertions(+), 28 deletions(-)
diff --git a/src/slave/containerizer/mesos/isolators/network/cni/cni.cpp b/src/slave/containerizer/mesos/isolators/network/cni/cni.cpp
index 4cd4700..1f8bddf 100644
--- a/src/slave/containerizer/mesos/isolators/network/cni/cni.cpp
+++ b/src/slave/containerizer/mesos/isolators/network/cni/cni.cpp
@@ -1593,6 +1593,30 @@ Try<ResourceStatistics> NetworkCniIsolatorProcess::_usage(
}
+static Try<bool> isNetworkNamespaceHandle(const string& netNsHandle)
+{
+ // Determine if a path is a network namespace handle or not by
+ // checking its device number against that of '/proc'. If they are
+ // not the same, the given path shouldn't be a network namespac
+ // handle.
+ Try<dev_t> netNsHandleDev = os::stat::dev(netNsHandle);
+ if (netNsHandleDev.isError()) {
+ return Error(
+ "Failed to get the device number of '" + netNsHandle +
+ "': " + netNsHandleDev.error());
+ }
+
+ Try<dev_t> procDev = os::stat::dev("/proc");
+ if (procDev.isError()) {
+ return Error(
+ "Failed to get the device number of '/proc'"
+ ": " + procDev.error());
+ }
+
+ return netNsHandleDev.get() == procDev.get();
+}
+
+
Future<Nothing> NetworkCniIsolatorProcess::cleanup(
const ContainerID& containerId)
{
@@ -1664,15 +1688,22 @@ Future<Nothing> NetworkCniIsolatorProcess::_cleanup(
paths::getNamespacePath(rootDir.get(), containerId);
if (os::exists(target)) {
- Try<Nothing> unmount = fs::unmount(target);
- if (unmount.isError()) {
- return Failure(
- "Failed to unmount the network namespace handle '" +
- target + "': " + unmount.error());
+ Try<bool> isNetNsHandle = isNetworkNamespaceHandle(target);
+ if (isNetNsHandle.isError()) {
+ return Failure(isNetNsHandle.error());
}
- LOG(INFO) << "Unmounted the network namespace handle '"
- << target << "' for container " << containerId;
+ if (isNetNsHandle.get()) {
+ Try<Nothing> unmount = fs::unmount(target);
+ if (unmount.isError()) {
+ return Failure(
+ "Failed to unmount the network namespace handle '" +
+ target + "': " + unmount.error());
+ }
+
+ LOG(INFO) << "Unmounted the network namespace handle '"
+ << target << "' for container " << containerId;
+ }
}
if (os::exists(containerDir)) {
@@ -1702,27 +1733,6 @@ Future<Nothing> NetworkCniIsolatorProcess::detach(
const ContainerNetwork& containerNetwork =
infos[containerId]->containerNetworks[networkName];
- // Prepare environment variables for CNI plugin.
- CHECK_SOME(flags.network_cni_plugins_dir);
-
- map<string, string> environment;
- environment["CNI_COMMAND"] = "DEL";
- environment["CNI_CONTAINERID"] = stringify(containerId);
- environment["CNI_PATH"] = flags.network_cni_plugins_dir.get();
- environment["CNI_IFNAME"] = containerNetwork.ifName;
- environment["CNI_NETNS"] =
- paths::getNamespacePath(rootDir.get(), containerId);
-
- // Some CNI plugins need to run "iptables" to set up IP Masquerade, so we
- // need to set the "PATH" environment variable so that the plugin can locate
- // the "iptables" executable file.
- Option<string> value = os::getenv("PATH");
- if (value.isSome()) {
- environment["PATH"] = value.get();
- } else {
- environment["PATH"] = os::host_default_path();
- }
-
// Use the checkpointed CNI network configuration to call the
// CNI plugin to detach the container from the CNI network.
const string networkConfigPath = paths::getNetworkConfigPath(
@@ -1746,6 +1756,43 @@ Future<Nothing> NetworkCniIsolatorProcess::detach(
return Nothing();
}
+ // Prepare environment variables for CNI plugin.
+ CHECK_SOME(flags.network_cni_plugins_dir);
+
+ map<string, string> environment;
+ environment["CNI_COMMAND"] = "DEL";
+ environment["CNI_CONTAINERID"] = stringify(containerId);
+ environment["CNI_PATH"] = flags.network_cni_plugins_dir.get();
+ environment["CNI_IFNAME"] = containerNetwork.ifName;
+
+ // If the file is not a network namespace handle, do not set
+ // `CNI_NETNS`. This is possible after a reboot where all bind
+ // mounts of the network namespace handles are gone. According to
+ // the CNI spec, we should not set `CNI_NETNS` in such a case, but
+ // still call `DEL` command so that CNI plugins can do best effort
+ // cleanup (e.g., deallocating IP allocated for the container).
+ const string netNsHandle =
+ paths::getNamespacePath(rootDir.get(), containerId);
+
+ Try<bool> isNetNsHandle = isNetworkNamespaceHandle(netNsHandle);
+ if (isNetNsHandle.isError()) {
+ return Failure(isNetNsHandle.error());
+ }
+
+ if (isNetNsHandle.get()) {
+ environment["CNI_NETNS"] = netNsHandle;
+ }
+
+ // Some CNI plugins need to run "iptables" to set up IP Masquerade, so we
+ // need to set the "PATH" environment variable so that the plugin can locate
+ // the "iptables" executable file.
+ Option<string> value = os::getenv("PATH");
+ if (value.isSome()) {
+ environment["PATH"] = value.get();
+ } else {
+ environment["PATH"] = os::host_default_path();
+ }
+
Try<JSON::Object> networkConfigJSON = getNetworkConfigJSON(
networkName,
networkConfigPath);