Updated the container launcher mount sequence. The `linux/devices` isolator needs to make bind mounts into the `/dev` directory of the container. However, the container mounts are made before the container `/dev` is mounted as part of the chroot preparation. We need to prepare the chroot, then make any necessary container mounts, and finally enter the chroot. This sequence of operations also requires us to touch the target mount point, since we can't do it from the isolator because the '/dev' directory doesn't exist yet.
Review: https://reviews.apache.org/r/67098/ Project: http://git-wip-us.apache.org/repos/asf/mesos/repo Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/68db3f98 Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/68db3f98 Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/68db3f98 Branch: refs/heads/master Commit: 68db3f988d557e326f88bf32ef32368f0b919bcf Parents: ae413c9 Author: James Peach <[email protected]> Authored: Fri May 25 13:38:10 2018 -0700 Committer: James Peach <[email protected]> Committed: Fri May 25 13:38:10 2018 -0700 ---------------------------------------------------------------------- src/slave/containerizer/mesos/launch.cpp | 112 ++++++++++++++++++++------ 1 file changed, 87 insertions(+), 25 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/mesos/blob/68db3f98/src/slave/containerizer/mesos/launch.cpp ---------------------------------------------------------------------- diff --git a/src/slave/containerizer/mesos/launch.cpp b/src/slave/containerizer/mesos/launch.cpp index b8ca608..70b7805 100644 --- a/src/slave/containerizer/mesos/launch.cpp +++ b/src/slave/containerizer/mesos/launch.cpp @@ -396,6 +396,32 @@ static Try<Nothing> prepareMounts(const ContainerLaunchInfo& launchInfo) } } + // If the mount target doesn't exist yet, create it. The isolator + // is responsible for ensuring the target path is safe. + if (mount.has_source() && !os::exists(mount.target())) { + const string dirname = Path(mount.target()).dirname(); + + if (!os::exists(dirname)) { + Try<Nothing> mkdir = os::mkdir(Path(mount.target()).dirname()); + + if (mkdir.isError()) { + return Error( + "Failed to create mount target directory '" + dirname + "': " + + mkdir.error()); + } + } + + Try<Nothing> target = os::stat::isdir(mount.source()) + ? os::mkdir(mount.target()) + : os::touch(mount.target()); + + if (target.isError()) { + return Error( + "Failed to create mount target '" + mount.target() + "': " + + target.error()); + } + } + Try<Nothing> mnt = fs::mount( (mount.has_source() ? Option<string>(mount.source()) : None()), mount.target(), @@ -437,7 +463,7 @@ static Try<Nothing> installResourceLimits(const RLimitInfo& limits) } -static Try<Nothing> enterChroot(const string& rootfs) +static Try<Nothing> prepareChroot(const string& rootfs) { #ifdef __WINDOWS__ return Error("Changing rootfs is not supported on Windows"); @@ -461,9 +487,19 @@ static Try<Nothing> enterChroot(const string& rootfs) "Failed to prepare chroot '" + rootfs + "': " + prepare.error()); } +#endif // __linux__ + + return Nothing(); +#endif // __WINDOWS__ +} - // TODO(jpeach): apply container mounts here. +static Try<Nothing> enterChroot(const string& rootfs) +{ +#ifdef __WINDOWS__ + return Error("Changing rootfs is not supported on Windows"); +#else +#ifdef __linux__ Try<Nothing> chroot = fs::chroot::enter(rootfs); #else // For any other platform we'll just use POSIX chroot. @@ -634,6 +670,52 @@ int MesosContainerizerLaunch::execute() } #endif // __WINDOWS__ +#ifdef __linux__ + // If we need a new mount namespace, we have to do it before + // we make the mounts needed to prepare the rootfs template. + if (flags.unshare_namespace_mnt) { + if (!launchInfo.mounts().empty()) { + cerr << "Mounts are not supported if " + << "'unshare_namespace_mnt' is set" << endl; + exitWithStatus(EXIT_FAILURE); + } + + if (unshare(CLONE_NEWNS) != 0) { + cerr << "Failed to unshare mount namespace: " + << os::strerror(errno) << endl; + exitWithStatus(EXIT_FAILURE); + } + } + + if (flags.namespace_mnt_target.isSome()) { + if (!launchInfo.mounts().empty()) { + cerr << "Mounts are not supported if " + << "'namespace_mnt_target' is set" << endl; + exitWithStatus(EXIT_FAILURE); + } + + if (launchInfo.has_rootfs()) { + cerr << "Container rootfs is not supported if " + << "'namespace_mnt_target' is set" << endl; + exitWithStatus(EXIT_FAILURE); + } + } +#endif // __linux__ + + // Prepare root to a new root, if provided. Make sure that we do this before + // processing the container mounts so that container mounts can be made on + // top of the rootfs template. + if (launchInfo.has_rootfs()) { + cout << "Preparing rootfs at " << launchInfo.rootfs() << endl; + + Try<Nothing> prepare = prepareChroot(launchInfo.rootfs()); + + if (prepare.isError()) { + cerr << prepare.error() << endl; + exitWithStatus(EXIT_FAILURE); + } + } + Try<Nothing> mount = prepareMounts(launchInfo); if (mount.isError()) { cerr << "Failed to prepare mounts: " << mount.error() << endl; @@ -767,12 +849,6 @@ int MesosContainerizerLaunch::execute() #ifdef __linux__ if (flags.namespace_mnt_target.isSome()) { - if (!launchInfo.mounts().empty()) { - cerr << "Mounts are not supported if " - << "'namespace_mnt_target' is set" << endl; - exitWithStatus(EXIT_FAILURE); - } - string path = path::join( "/proc", stringify(flags.namespace_mnt_target.get()), @@ -786,30 +862,16 @@ int MesosContainerizerLaunch::execute() exitWithStatus(EXIT_FAILURE); } } - - if (flags.unshare_namespace_mnt) { - if (!launchInfo.mounts().empty()) { - cerr << "Mounts are not supported if " - << "'unshare_namespace_mnt' is set" << endl; - exitWithStatus(EXIT_FAILURE); - } - - if (unshare(CLONE_NEWNS) != 0) { - cerr << "Failed to unshare mount namespace: " - << os::strerror(errno) << endl; - exitWithStatus(EXIT_FAILURE); - } - } #endif // __linux__ // Change root to a new root, if provided. if (launchInfo.has_rootfs()) { cout << "Changing root to " << launchInfo.rootfs() << endl; - Try<Nothing> chroot = enterChroot(launchInfo.rootfs()); + Try<Nothing> enter = enterChroot(launchInfo.rootfs()); - if (chroot.isError()) { - cerr << chroot.error() << endl; + if (enter.isError()) { + cerr << enter.error() << endl; exitWithStatus(EXIT_FAILURE); } }
