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 2016/09/13 17:54:27 UTC

[01/17] mesos git commit: Renamed `CGROUPS_ROOT_PERF_RollForward` to keep consistency.

Repository: mesos
Updated Branches:
  refs/heads/master f833169b4 -> 8e727e091


Renamed `CGROUPS_ROOT_PERF_RollForward` to keep consistency.

Review: https://reviews.apache.org/r/51791/


Project: http://git-wip-us.apache.org/repos/asf/mesos/repo
Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/8e727e09
Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/8e727e09
Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/8e727e09

Branch: refs/heads/master
Commit: 8e727e09141fa569487b557cd8a1f8e388366dcb
Parents: 08594c2
Author: haosdent huang <ha...@gmail.com>
Authored: Mon Sep 12 16:35:17 2016 -0700
Committer: Jie Yu <yu...@gmail.com>
Committed: Tue Sep 13 10:52:01 2016 -0700

----------------------------------------------------------------------
 src/tests/environment.cpp          | 3 +--
 src/tests/slave_recovery_tests.cpp | 2 +-
 2 files changed, 2 insertions(+), 3 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/8e727e09/src/tests/environment.cpp
----------------------------------------------------------------------
diff --git a/src/tests/environment.cpp b/src/tests/environment.cpp
index 57ec492..fba94f6 100644
--- a/src/tests/environment.cpp
+++ b/src/tests/environment.cpp
@@ -590,9 +590,8 @@ public:
   {
     // Disable all tests that try to sample 'cpu-cycles' events using 'perf'.
     return (matches(test, "ROOT_CGROUPS_PERF_PerfTest") ||
-            matches(test, "ROOT_CGROUPS_PERF_Sample") ||
             matches(test, "ROOT_CGROUPS_PERF_UserCgroup") ||
-            matches(test, "CGROUPS_ROOT_PERF_RollForward") ||
+            matches(test, "ROOT_CGROUPS_PERF_RollForward") ||
             matches(test, "ROOT_CGROUPS_PERF_Sample")) && perfError.isSome();
   }
 

http://git-wip-us.apache.org/repos/asf/mesos/blob/8e727e09/src/tests/slave_recovery_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/slave_recovery_tests.cpp b/src/tests/slave_recovery_tests.cpp
index 3c69e56..d58d9bc 100644
--- a/src/tests/slave_recovery_tests.cpp
+++ b/src/tests/slave_recovery_tests.cpp
@@ -3878,7 +3878,7 @@ TEST_F(MesosContainerizerSlaveRecoveryTest, ResourceStatistics)
 // Test that the perf event isolator can be enabled on a new slave.
 // Previously created containers will not report perf statistics but
 // newly created containers will.
-TEST_F(MesosContainerizerSlaveRecoveryTest, CGROUPS_ROOT_PERF_RollForward)
+TEST_F(MesosContainerizerSlaveRecoveryTest, ROOT_CGROUPS_PERF_RollForward)
 {
   Try<Owned<cluster::Master>> master = this->StartMaster();
   ASSERT_SOME(master);


[08/17] mesos git commit: Removed CgroupsNetClsIsolatorProcess.

Posted by ji...@apache.org.
Removed CgroupsNetClsIsolatorProcess.

Review: https://reviews.apache.org/r/50750/


Project: http://git-wip-us.apache.org/repos/asf/mesos/repo
Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/34bcae44
Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/34bcae44
Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/34bcae44

Branch: refs/heads/master
Commit: 34bcae442945bd7f3d7cd21b69c5ca133f3daef9
Parents: f75d949
Author: haosdent huang <ha...@gmail.com>
Authored: Mon Sep 12 16:34:47 2016 -0700
Committer: Jie Yu <yu...@gmail.com>
Committed: Tue Sep 13 10:52:01 2016 -0700

----------------------------------------------------------------------
 src/CMakeLists.txt                              |   1 -
 src/Makefile.am                                 |   2 -
 src/slave/containerizer/mesos/containerizer.cpp |   1 -
 .../mesos/isolators/cgroups/net_cls.cpp         | 500 -------------------
 .../mesos/isolators/cgroups/net_cls.hpp         | 117 -----
 src/tests/containerizer/isolator_tests.cpp      | 314 ------------
 src/tests/environment.cpp                       |  16 +-
 7 files changed, 9 insertions(+), 942 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/34bcae44/src/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 4e66c74..7caa466 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -159,7 +159,6 @@ set(LINUX_SRC
   slave/containerizer/mesos/linux_launcher.cpp
   slave/containerizer/mesos/isolators/appc/runtime.cpp
   slave/containerizer/mesos/isolators/cgroups/cgroups.cpp
-  slave/containerizer/mesos/isolators/cgroups/net_cls.cpp
   slave/containerizer/mesos/isolators/cgroups/perf_event.cpp
   slave/containerizer/mesos/isolators/cgroups/subsystem.cpp
   slave/containerizer/mesos/isolators/cgroups/subsystems/cpu.cpp

http://git-wip-us.apache.org/repos/asf/mesos/blob/34bcae44/src/Makefile.am
----------------------------------------------------------------------
diff --git a/src/Makefile.am b/src/Makefile.am
index cf06c8d..d4b90f1 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1025,7 +1025,6 @@ MESOS_LINUX_FILES =									\
   slave/containerizer/mesos/linux_launcher.cpp						\
   slave/containerizer/mesos/isolators/appc/runtime.cpp					\
   slave/containerizer/mesos/isolators/cgroups/cgroups.cpp				\
-  slave/containerizer/mesos/isolators/cgroups/net_cls.cpp				\
   slave/containerizer/mesos/isolators/cgroups/perf_event.cpp				\
   slave/containerizer/mesos/isolators/cgroups/subsystem.cpp				\
   slave/containerizer/mesos/isolators/cgroups/subsystems/cpu.cpp			\
@@ -1063,7 +1062,6 @@ MESOS_LINUX_FILES +=									\
   slave/containerizer/mesos/isolators/appc/runtime.hpp					\
   slave/containerizer/mesos/isolators/cgroups/cgroups.hpp				\
   slave/containerizer/mesos/isolators/cgroups/constants.hpp				\
-  slave/containerizer/mesos/isolators/cgroups/net_cls.hpp				\
   slave/containerizer/mesos/isolators/cgroups/perf_event.hpp				\
   slave/containerizer/mesos/isolators/cgroups/subsystem.hpp				\
   slave/containerizer/mesos/isolators/cgroups/subsystems/cpu.hpp			\

http://git-wip-us.apache.org/repos/asf/mesos/blob/34bcae44/src/slave/containerizer/mesos/containerizer.cpp
----------------------------------------------------------------------
diff --git a/src/slave/containerizer/mesos/containerizer.cpp b/src/slave/containerizer/mesos/containerizer.cpp
index 69150e7..bbf5d53 100644
--- a/src/slave/containerizer/mesos/containerizer.cpp
+++ b/src/slave/containerizer/mesos/containerizer.cpp
@@ -73,7 +73,6 @@
 
 #ifdef __linux__
 #include "slave/containerizer/mesos/isolators/cgroups/cgroups.hpp"
-#include "slave/containerizer/mesos/isolators/cgroups/net_cls.hpp"
 #include "slave/containerizer/mesos/isolators/cgroups/perf_event.hpp"
 #endif // __linux__
 

http://git-wip-us.apache.org/repos/asf/mesos/blob/34bcae44/src/slave/containerizer/mesos/isolators/cgroups/net_cls.cpp
----------------------------------------------------------------------
diff --git a/src/slave/containerizer/mesos/isolators/cgroups/net_cls.cpp b/src/slave/containerizer/mesos/isolators/cgroups/net_cls.cpp
deleted file mode 100644
index dcbc499..0000000
--- a/src/slave/containerizer/mesos/isolators/cgroups/net_cls.cpp
+++ /dev/null
@@ -1,500 +0,0 @@
-// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements.  See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership.  The ASF licenses this file
-// to you under the Apache License, Version 2.0 (the
-// "License"); you may not use this file except in compliance
-// with the License.  You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include <list>
-#include <sstream>
-#include <vector>
-
-#include <process/defer.hpp>
-#include <process/future.hpp>
-#include <process/pid.hpp>
-
-#include <stout/numify.hpp>
-#include <stout/os.hpp>
-#include <stout/path.hpp>
-#include <stout/try.hpp>
-
-#include "linux/cgroups.hpp"
-
-#include "slave/flags.hpp"
-
-#include "slave/containerizer/mesos/isolators/cgroups/net_cls.hpp"
-
-using std::bitset;
-using std::list;
-using std::ostream;
-using std::set;
-using std::string;
-using std::stringstream;
-using std::vector;
-
-using process::Failure;
-using process::Future;
-using process::Owned;
-using process::PID;
-
-using mesos::slave::ContainerConfig;
-using mesos::slave::ContainerLaunchInfo;
-using mesos::slave::ContainerLimitation;
-using mesos::slave::ContainerState;
-using mesos::slave::Isolator;
-
-namespace mesos {
-namespace internal {
-namespace slave {
-
-Try<Isolator*> CgroupsNetClsIsolatorProcess::create(const Flags& flags)
-{
-  Try<string> hierarchy = cgroups::prepare(
-      flags.cgroups_hierarchy,
-      "net_cls",
-      flags.cgroups_root);
-
-  if (hierarchy.isError()) {
-    return Error("Failed to create net_cls cgroup: " + hierarchy.error());
-  }
-
-  // Ensure that no unexpected subsystem is attached to the hierarchy.
-  Try<set<string>> subsystems = cgroups::subsystems(hierarchy.get());
-  if (subsystems.isError()) {
-    return Error(
-        "Failed to get the list of attached subsystems for hierarchy "
-        "'" + hierarchy.get() + "'");
-  } else if (subsystems.get().size() != 1) {
-    // Some Linux distributions mount net_cls and net_prio subsystems
-    // to the same hierarchy.
-    // TODO(jieyu): If we ever introduce a cgroups net_prio isolator,
-    // we need to make sure it will not conflict with this isolator if
-    // two subsystems are co-mounted into the same hierarchy. For
-    // instance, we should not remove a cgroup twice.
-    foreach (const string& subsystem, subsystems.get()) {
-      if (subsystem != "net_cls" && subsystem != "net_prio") {
-        return Error(
-            "Unexpected subsystems found attached to hierarchy "
-            "'" + hierarchy.get() + "'");
-      }
-    }
-  }
-
-  IntervalSet<uint32_t> primaries;
-  IntervalSet<uint32_t> secondaries;
-
-  // Primary handle.
-  if (flags.cgroups_net_cls_primary_handle.isSome()) {
-    Try<uint16_t> primary = numify<uint16_t>(
-        flags.cgroups_net_cls_primary_handle.get());
-
-    if (primary.isError()) {
-      return Error(
-          "Failed to parse the primary handle '" +
-          flags.cgroups_net_cls_primary_handle.get() +
-          "' set in flag --cgroups_net_cls_primary_handle");
-    }
-
-    primaries +=
-      (Bound<uint32_t>::closed(primary.get()),
-       Bound<uint32_t>::closed(primary.get()));
-
-    // Range of valid secondary handles.
-    if (flags.cgroups_net_cls_secondary_handles.isSome()) {
-      vector<string> range =
-        strings::tokenize(flags.cgroups_net_cls_secondary_handles.get(), ",");
-
-      if (range.size() != 2) {
-        return Error(
-            "Failed to parse the range of secondary handles " +
-            flags.cgroups_net_cls_secondary_handles.get() +
-            " set in flag --cgroups_net_cls_secondary_handles");
-      }
-
-      Try<uint16_t> lower = numify<uint16_t>(range[0]);
-      if (lower.isError()) {
-        return Error(
-            "Failed to parse the lower bound of range of secondary handles" +
-            flags.cgroups_net_cls_secondary_handles.get() +
-            " set in flag --cgroups_net_cls_secondary_handles");
-      }
-
-      if (lower.get() == 0) {
-        return Error("The secondary handle has to be a non-zero value.");
-      }
-
-      Try<uint16_t> upper =  numify<uint16_t>(range[1]);
-      if (upper.isError()) {
-        return Error(
-            "Failed to parse the upper bound of range of secondary handles" +
-            flags.cgroups_net_cls_secondary_handles.get() +
-            " set in flag --cgroups_net_cls_secondary_handles");
-      }
-
-      secondaries +=
-        (Bound<uint32_t>::closed(lower.get()),
-         Bound<uint32_t>::closed(upper.get()));
-
-      if (secondaries.empty()) {
-        return Error(
-            "Secondary handle range specified " +
-            flags.cgroups_net_cls_secondary_handles.get() +
-            ", in flag --cgroups_net_cls_secondary_handles, is an empty set");
-      }
-    }
-  }
-
-  process::Owned<MesosIsolatorProcess> process(
-      new CgroupsNetClsIsolatorProcess(
-          flags,
-          hierarchy.get(),
-          primaries,
-          secondaries));
-
-  return new MesosIsolator(process);
-}
-
-
-CgroupsNetClsIsolatorProcess::CgroupsNetClsIsolatorProcess(
-    const Flags& _flags,
-    const string& _hierarchy,
-    const IntervalSet<uint32_t>& primaries,
-    const IntervalSet<uint32_t>& secondaries)
-  : ProcessBase(process::ID::generate("cgroups-net-cls-isolator")),
-    flags(_flags),
-    hierarchy(_hierarchy)
-{
-  if (!primaries.empty()) {
-    handleManager = NetClsHandleManager(primaries, secondaries);
-  }
-}
-
-
-CgroupsNetClsIsolatorProcess::~CgroupsNetClsIsolatorProcess() {}
-
-
-Future<Nothing> CgroupsNetClsIsolatorProcess::recover(
-    const list<ContainerState>& states,
-    const hashset<ContainerID>& orphans)
-{
-  foreach (const ContainerState& state, states) {
-    const ContainerID& containerId = state.container_id();
-    const string cgroup = path::join(flags.cgroups_root, containerId.value());
-
-    Try<bool> exists = cgroups::exists(hierarchy, cgroup);
-    if (exists.isError()) {
-      infos.clear();
-      return Failure(
-          "Failed to check cgroup for container " + stringify(containerId));
-    }
-
-    if (!exists.get()) {
-      VLOG(1) << "Couldn't find cgroup for container " << containerId;
-      // This may occur if the executor has exited and the isolator
-      // has destroyed the cgroup but the slave dies before noticing
-      // this. This will be detected when the containerizer tries to
-      // monitor the executor's pid.
-      continue;
-    }
-
-    // Read the net_cls handle.
-    Result<NetClsHandle> handle = recoverHandle(hierarchy, cgroup);
-    if (handle.isError()) {
-      infos.clear();
-      return Failure(
-          "Failed to recover the net_cls handle for " +
-          stringify(containerId) + ": " + handle.error());
-    }
-
-    if (handle.isSome()) {
-      infos.emplace(containerId, Info(cgroup, handle.get()));
-    } else {
-      infos.emplace(containerId, Info(cgroup));
-    }
-  }
-
-  // Remove orphan cgroups.
-  Try<vector<string>> cgroups = cgroups::get(hierarchy, flags.cgroups_root);
-  if (cgroups.isError()) {
-    infos.clear();
-    return Failure(cgroups.error());
-  }
-
-  foreach (const string& cgroup, cgroups.get()) {
-    // Ignore the slave cgroup (see the --agent_subsystems flag).
-    // TODO(idownes): Remove this when the cgroups layout is updated,
-    // see MESOS-1185.
-    if (cgroup == path::join(flags.cgroups_root, "slave")) {
-      continue;
-    }
-
-    ContainerID containerId;
-    containerId.set_value(Path(cgroup).basename());
-
-    if (infos.contains(containerId)) {
-      continue;
-    }
-
-    Result<NetClsHandle> handle = recoverHandle(hierarchy, cgroup);
-    if (handle.isError()) {
-      infos.clear();
-      return Failure(
-          "Failed to recover the net_cls handle for orphan container " +
-          stringify(containerId) + ": " + handle.error());
-    }
-
-    // Known orphan cgroups will be destroyed by the containerizer
-    // using the normal cleanup path. See MESOS-2367 for details.
-    if (orphans.contains(containerId)) {
-      if (handle.isSome()) {
-        infos.emplace(containerId, Info(cgroup, handle.get()));
-      } else {
-        infos.emplace(containerId, Info(cgroup));
-      }
-
-      continue;
-    }
-
-    LOG(INFO) << "Removing unknown orphaned cgroup '" << cgroup << "'";
-
-    // We don't wait on the destroy as we don't want to block recovery.
-    // TODO(jieyu): Release the handle after destroy has been done.
-    cgroups::destroy(hierarchy, cgroup, cgroups::DESTROY_TIMEOUT);
-  }
-
-  return Nothing();
-}
-
-
-// TODO(asridharan): Currently we haven't decided on the entity who
-// will allocate the net_cls handles, or the interfaces through which
-// the net_cls handles will be exposed to network isolators and
-// frameworks. Once the management entity is decided we might need to
-// revisit this implementation.
-Future<Nothing> CgroupsNetClsIsolatorProcess::update(
-    const ContainerID& containerId,
-    const Resources& resources)
-{
-  return Nothing();
-}
-
-
-Future<ContainerStatus> CgroupsNetClsIsolatorProcess::status(
-    const ContainerID& containerId)
-{
-  if (!infos.contains(containerId)) {
-    return Failure("Unknown container");
-  }
-
-  const Info& info = infos.at(containerId);
-
-  ContainerStatus status;
-
-  if (info.handle.isSome()) {
-    VLOG(1) << "Updating container status with net_cls classid: "
-            << info.handle.get();
-
-    CgroupInfo* cgroupInfo = status.mutable_cgroup_info();
-    CgroupInfo::NetCls* netCls = cgroupInfo->mutable_net_cls();
-
-    netCls->set_classid(info.handle->get());
-  }
-
-  return status;
-}
-
-
-Future<Option<ContainerLaunchInfo>> CgroupsNetClsIsolatorProcess::prepare(
-    const ContainerID& containerId,
-    const ContainerConfig& containerConfig)
-{
-  if (infos.contains(containerId)) {
-    return Failure("Container has already been prepared");
-  }
-
-  // Use this info to create the cgroup, but do not insert it into
-  // infos till the cgroup has been created successfully.
-  const string cgroup = path::join(flags.cgroups_root, containerId.value());
-
-  // Create a cgroup for this container.
-  Try<bool> exists = cgroups::exists(hierarchy, cgroup);
-  if (exists.isError()) {
-    return Failure(
-        "Failed to check if the cgroup already exists: " + exists.error());
-  } else if (exists.get()) {
-    return Failure("The cgroup already exists");
-  }
-
-  Try<Nothing> create = cgroups::create(hierarchy, cgroup);
-  if (create.isError()) {
-    return Failure("Failed to create the cgroup: " + create.error());
-  }
-
-  // 'chown' the cgroup so the executor can create nested cgroups. Do
-  // not recurse so the control files are still owned by the slave
-  // user and thus cannot be changed by the executor.
-  if (containerConfig.has_user()) {
-    Try<Nothing> chown = os::chown(
-        containerConfig.user(),
-        path::join(hierarchy, cgroup),
-        false);
-
-    if (chown.isError()) {
-      return Failure(
-          "Failed to change ownership of cgroup hierarchy: " + chown.error());
-    }
-  }
-
-  if (handleManager.isSome()) {
-    Try<NetClsHandle> handle = handleManager->alloc();
-    if (handle.isError()) {
-      return Failure (
-          "Failed to allocate a net_cls handle: " +
-          handle.error());
-    }
-
-    LOG(INFO) << "Allocated handle: " << handle.get()
-              << " to container " << containerId;
-
-    infos.emplace(containerId, Info(cgroup, handle.get()));
-  } else {
-    infos.emplace(containerId, Info(cgroup));
-  }
-
-  return update(containerId, containerConfig.executor_info().resources())
-    .then([]() -> Future<Option<ContainerLaunchInfo>> {
-      return None();
-    });
-}
-
-
-Future<Nothing> CgroupsNetClsIsolatorProcess::isolate(
-    const ContainerID& containerId,
-    pid_t pid)
-{
-  if (!infos.contains(containerId)) {
-    return Failure("Unknown container");
-  }
-
-  const Info& info = infos.at(containerId);
-
-  Try<Nothing> assign = cgroups::assign(hierarchy, info.cgroup, pid);
-  if (assign.isError()) {
-    return Failure(
-        "Failed to assign container " + stringify(containerId) +
-        " to its own cgroup '" + path::join(hierarchy, info.cgroup) +
-        "': " + assign.error());
-  }
-
-  // If info.handle is not specified, the assumption is that the
-  // operator is responsible for assigning the net_cls handles.
-  if (info.handle.isSome()) {
-    Try<Nothing> write = cgroups::net_cls::classid(
-        hierarchy,
-        info.cgroup,
-        info.handle->get());
-
-    if (write.isError()) {
-      return Failure(
-          "Failed to assign a net_cls handle to the cgroup: " +
-          write.error());
-    }
-  }
-
-  return Nothing();
-}
-
-
-// The net_cls handles are labels and hence there are no limitations
-// associated with them. This function would therefore always return
-// a pending future since the limitation is never reached.
-Future<ContainerLimitation> CgroupsNetClsIsolatorProcess::watch(
-    const ContainerID& containerId)
-{
-  if (!infos.contains(containerId)) {
-    return Failure("Unknown container");
-  }
-
-  return Future<ContainerLimitation>();
-}
-
-
-Future<Nothing> CgroupsNetClsIsolatorProcess::cleanup(
-    const ContainerID& containerId)
-{
-  // Multiple calls may occur during test clean up.
-  if (!infos.contains(containerId)) {
-    VLOG(1) << "Ignoring cleanup request for unknown container: "
-            << containerId;
-    return Nothing();
-  }
-
-  const Info& info = infos.at(containerId);
-
-  return cgroups::destroy(hierarchy, info.cgroup, cgroups::DESTROY_TIMEOUT)
-    .then(defer(PID<CgroupsNetClsIsolatorProcess>(this),
-                &CgroupsNetClsIsolatorProcess::_cleanup,
-                containerId));
-}
-
-
-Future<Nothing> CgroupsNetClsIsolatorProcess::_cleanup(
-    const ContainerID& containerId)
-{
-  if (!infos.contains(containerId)) {
-    return Nothing();
-  }
-
-  const Info& info = infos.at(containerId);
-
-  if (info.handle.isSome() && handleManager.isSome()) {
-    Try<Nothing> free = handleManager->free(info.handle.get());
-    if (free.isError()) {
-      return Failure("Could not free the net_cls handle: " + free.error());
-    }
-  }
-
-  infos.erase(containerId);
-
-  return Nothing();
-}
-
-
-Result<NetClsHandle> CgroupsNetClsIsolatorProcess::recoverHandle(
-    const std::string& hierarchy,
-    const std::string& cgroup)
-{
-  Try<uint32_t> classid = cgroups::net_cls::classid(hierarchy, cgroup);
-  if (classid.isError()) {
-    return Error("Failed to read 'net_cls.classid': " + classid.error());
-  }
-
-  if (classid.get() == 0) {
-    return None();
-  }
-
-  NetClsHandle handle(classid.get());
-
-  // Mark the handle as used in handle manager.
-  if (handleManager.isSome()) {
-    Try<Nothing> reserve = handleManager->reserve(handle);
-    if (reserve.isError()) {
-      return Error("Failed to reserve the handle: " + reserve.error());
-    }
-  }
-
-  return handle;
-}
-
-} // namespace slave {
-} // namespace internal {
-} // namespace mesos {

http://git-wip-us.apache.org/repos/asf/mesos/blob/34bcae44/src/slave/containerizer/mesos/isolators/cgroups/net_cls.hpp
----------------------------------------------------------------------
diff --git a/src/slave/containerizer/mesos/isolators/cgroups/net_cls.hpp b/src/slave/containerizer/mesos/isolators/cgroups/net_cls.hpp
deleted file mode 100644
index 452eedd..0000000
--- a/src/slave/containerizer/mesos/isolators/cgroups/net_cls.hpp
+++ /dev/null
@@ -1,117 +0,0 @@
-// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements.  See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership.  The ASF licenses this file
-// to you under the Apache License, Version 2.0 (the
-// "License"); you may not use this file except in compliance
-// with the License.  You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#ifndef __CGROUPS_NET_CLS_ISOLATOR_HPP__
-#define __CGROUPS_NET_CLS_ISOLATOR_HPP__
-
-#include <stdint.h>
-
-#include <bitset>
-#include <iostream>
-#include <string>
-
-#include <stout/hashmap.hpp>
-#include <stout/interval.hpp>
-#include <stout/none.hpp>
-#include <stout/nothing.hpp>
-#include <stout/result.hpp>
-#include <stout/try.hpp>
-
-#include "slave/containerizer/mesos/isolator.hpp"
-
-#include "slave/containerizer/mesos/isolators/cgroups/subsystems/net_cls.hpp"
-
-namespace mesos {
-namespace internal {
-namespace slave {
-
-// Uses the Linux net_cls subsystem for allocating network handles to
-// containers. The network handles of a net_cls cgroup will be used
-// for tagging packets originating from containers belonging to that
-// cgroup. The tags on the packets can then be used by applications,
-// such as traffic-controllers (tc) and firewalls (iptables), to
-// provide network performance isolation. A more detailed explanation
-// can be found at:
-// https://www.kernel.org/doc/Documentation/cgroups/net_cls.txt
-class CgroupsNetClsIsolatorProcess : public MesosIsolatorProcess
-{
-public:
-  static Try<mesos::slave::Isolator*> create(const Flags& flags);
-
-  virtual ~CgroupsNetClsIsolatorProcess();
-
-  virtual process::Future<Nothing> recover(
-      const std::list<mesos::slave::ContainerState>& states,
-      const hashset<ContainerID>& orphans);
-
-  virtual process::Future<Option<mesos::slave::ContainerLaunchInfo>> prepare(
-      const ContainerID& containerId,
-      const mesos::slave::ContainerConfig& containerConfig);
-
-  virtual process::Future<Nothing> isolate(
-      const ContainerID& containerId,
-      pid_t pid);
-
-  virtual process::Future<mesos::slave::ContainerLimitation> watch(
-      const ContainerID& containerId);
-
-  virtual process::Future<Nothing> update(
-      const ContainerID& containerId,
-      const Resources& resources);
-
-  virtual process::Future<ContainerStatus> status(
-      const ContainerID& containerId);
-
-  virtual process::Future<Nothing> cleanup(
-      const ContainerID& containerId);
-
-private:
-  struct Info
-  {
-    Info(const std::string& _cgroup)
-      : cgroup(_cgroup) {}
-
-    Info(const std::string& _cgroup, const NetClsHandle &_handle)
-      : cgroup(_cgroup), handle(_handle) {}
-
-    const std::string cgroup;
-    const Option<NetClsHandle> handle;
-  };
-
-  CgroupsNetClsIsolatorProcess(
-      const Flags& _flags,
-      const std::string& _hierarchy,
-      const IntervalSet<uint32_t>& primaries,
-      const IntervalSet<uint32_t>& secondaries);
-
-  process::Future<Nothing> _cleanup(
-      const ContainerID& containerId);
-
-  Result<NetClsHandle> recoverHandle(
-      const std::string& hierarchy,
-      const std::string& cgroup);
-
-  const Flags flags;
-  const std::string hierarchy;
-
-  hashmap<ContainerID, Info> infos;
-  Option<NetClsHandleManager> handleManager;
-};
-
-} // namespace slave {
-} // namespace internal {
-} // namespace mesos {
-#endif // __CGROUPS_NET_CLS_ISOLATOR_HPP__

http://git-wip-us.apache.org/repos/asf/mesos/blob/34bcae44/src/tests/containerizer/isolator_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/containerizer/isolator_tests.cpp b/src/tests/containerizer/isolator_tests.cpp
index a7b9ff5..85a13d7 100644
--- a/src/tests/containerizer/isolator_tests.cpp
+++ b/src/tests/containerizer/isolator_tests.cpp
@@ -52,7 +52,6 @@
 #include "slave/slave.hpp"
 
 #ifdef __linux__
-#include "slave/containerizer/mesos/isolators/cgroups/net_cls.hpp"
 #include "slave/containerizer/mesos/isolators/cgroups/perf_event.hpp"
 #include "slave/containerizer/mesos/isolators/filesystem/shared.hpp"
 #endif // __linux__
@@ -75,12 +74,9 @@ using namespace process;
 
 using mesos::internal::master::Master;
 #ifdef __linux__
-using mesos::internal::slave::CgroupsNetClsIsolatorProcess;
 using mesos::internal::slave::CgroupsPerfEventIsolatorProcess;
 using mesos::internal::slave::Fetcher;
 using mesos::internal::slave::LinuxLauncher;
-using mesos::internal::slave::NetClsHandle;
-using mesos::internal::slave::NetClsHandleManager;
 using mesos::internal::slave::SharedFilesystemIsolatorProcess;
 #endif // __linux__
 using mesos::internal::slave::Launcher;
@@ -95,9 +91,6 @@ using mesos::slave::ContainerLaunchInfo;
 using mesos::slave::ContainerTermination;
 using mesos::slave::Isolator;
 
-using process::http::OK;
-using process::http::Response;
-
 using std::ostringstream;
 using std::set;
 using std::string;
@@ -108,313 +101,6 @@ namespace internal {
 namespace tests {
 
 #ifdef __linux__
-class NetClsHandleManagerTest : public testing::Test {};
-
-
-// Tests the ability of the `NetClsHandleManager` class to allocate
-// and free secondary handles from a range of primary handles.
-TEST_F(NetClsHandleManagerTest, AllocateFreeHandles)
-{
-  NetClsHandleManager manager(IntervalSet<uint32_t>(
-      (Bound<uint32_t>::closed(0x0002),
-       Bound<uint32_t>::closed(0x0003))));
-
-  Try<NetClsHandle> handle = manager.alloc(0x0003);
-  ASSERT_SOME(handle);
-
-  EXPECT_SOME_TRUE(manager.isUsed(handle.get()));
-
-  ASSERT_SOME(manager.free(handle.get()));
-
-  EXPECT_SOME_FALSE(manager.isUsed(handle.get()));
-}
-
-
-// Make sure allocation of secondary handles for invalid primary
-// handles results in an error.
-TEST_F(NetClsHandleManagerTest, AllocateInvalidPrimary)
-{
-  NetClsHandleManager manager(IntervalSet<uint32_t>(
-      (Bound<uint32_t>::closed(0x0002),
-       Bound<uint32_t>::closed(0x0003))));
-
-  ASSERT_ERROR(manager.alloc(0x0001));
-}
-
-
-// Tests that we can reserve secondary handles for a given primary
-// handle so that they won't be allocated out later.
-TEST_F(NetClsHandleManagerTest, ReserveHandles)
-{
-  NetClsHandleManager manager(IntervalSet<uint32_t>(
-      (Bound<uint32_t>::closed(0x0002),
-       Bound<uint32_t>::closed(0x0003))));
-
-  NetClsHandle handle(0x0003, 0xffff);
-
-  ASSERT_SOME(manager.reserve(handle));
-
-  EXPECT_SOME_TRUE(manager.isUsed(handle));
-}
-
-
-// Tests that secondary handles are allocated only from a given range,
-// when the range is specified.
-TEST_F(NetClsHandleManagerTest, SecondaryHandleRange)
-{
-  NetClsHandleManager manager(
-      IntervalSet<uint32_t>(
-        (Bound<uint32_t>::closed(0x0002),
-         Bound<uint32_t>::closed(0x0003))),
-      IntervalSet<uint32_t>(
-        (Bound<uint32_t>::closed(0xffff),
-         Bound<uint32_t>::closed(0xffff))));
-
-  Try<NetClsHandle> handle = manager.alloc(0x0003);
-  ASSERT_SOME(handle);
-
-  EXPECT_SOME_TRUE(manager.isUsed(handle.get()));
-
-  // Try allocating another handle. This should fail, since we don't
-  // have any more secondary handles left.
-  EXPECT_ERROR(manager.alloc(0x0003));
-
-  ASSERT_SOME(manager.free(handle.get()));
-
-  ASSERT_SOME(manager.reserve(handle.get()));
-
-  EXPECT_SOME_TRUE(manager.isUsed(handle.get()));
-
-  // Make sure you cannot reserve a secondary handle that is out of
-  // range.
-  EXPECT_ERROR(manager.reserve(NetClsHandle(0x0003, 0x0001)));
-}
-#endif // __linux__
-
-
-#ifdef __linux__
-class NetClsIsolatorTest : public MesosTest {};
-
-
-// This tests the create, prepare, isolate and cleanup methods of the
-// 'CgroupNetClsIsolatorProcess'. The test first creates a 'MesosContainerizer'
-// with net_cls cgroup isolator enabled. The net_cls cgroup isolator is
-// implemented in the 'CgroupNetClsIsolatorProcess' class. The test then
-// launches a task in a mesos container and checks to see if the container has
-// been added to the right net_cls cgroup. Finally, the test kills the task and
-// makes sure that the 'CgroupNetClsIsolatorProcess' cleans up the net_cls
-// cgroup created for the container.
-TEST_F(NetClsIsolatorTest, ROOT_CGROUPS_NetClsIsolate)
-{
-  Try<Owned<cluster::Master>> master = StartMaster();
-  ASSERT_SOME(master);
-
-  uint16_t primary = 0x0012;
-
-  slave::Flags flags = CreateSlaveFlags();
-  flags.isolation = "cgroups/net_cls";
-  flags.cgroups_net_cls_primary_handle = stringify(primary);
-  flags.cgroups_net_cls_secondary_handles = "0xffff,0xffff";
-
-  Fetcher fetcher;
-
-  Try<MesosContainerizer*> _containerizer =
-    MesosContainerizer::create(flags, true, &fetcher);
-
-  ASSERT_SOME(_containerizer);
-  Owned<MesosContainerizer> containerizer(_containerizer.get());
-
-  Owned<MasterDetector> detector = master.get()->createDetector();
-
-  Try<Owned<cluster::Slave>> slave =
-    StartSlave(detector.get(), containerizer.get(), flags);
-  ASSERT_SOME(slave);
-
-  MockScheduler sched;
-
-  MesosSchedulerDriver driver(
-      &sched, DEFAULT_FRAMEWORK_INFO, master.get()->pid, DEFAULT_CREDENTIAL);
-
-  Future<Nothing> schedRegistered;
-  EXPECT_CALL(sched, registered(_, _, _))
-    .WillOnce(FutureSatisfy(&schedRegistered));
-
-  Future<vector<Offer>> offers;
-  EXPECT_CALL(sched, resourceOffers(_, _))
-    .WillOnce(FutureArg<1>(&offers))
-    .WillRepeatedly(Return());      // Ignore subsequent offers.
-
-  driver.start();
-
-  AWAIT_READY(schedRegistered);
-
-  AWAIT_READY(offers);
-  EXPECT_EQ(1u, offers.get().size());
-
-  // Create a task to be launched in the mesos-container. We will be
-  // explicitly killing this task to perform the cleanup test.
-  TaskInfo task = createTask(offers.get()[0], "sleep 1000");
-
-  Future<TaskStatus> status;
-  EXPECT_CALL(sched, statusUpdate(_, _))
-    .WillOnce(FutureArg<1>(&status));
-
-  driver.launchTasks(offers.get()[0].id(), {task});
-
-  // Capture the update to verify that the task has been launched.
-  AWAIT_READY(status);
-  ASSERT_EQ(TASK_RUNNING, status.get().state());
-
-  // Task is ready.  Make sure there is exactly 1 container in the hashset.
-  Future<hashset<ContainerID>> containers = containerizer->containers();
-  AWAIT_READY(containers);
-  EXPECT_EQ(1u, containers.get().size());
-
-  const ContainerID& containerID = *(containers.get().begin());
-
-  Result<string> hierarchy = cgroups::hierarchy("net_cls");
-  ASSERT_SOME(hierarchy);
-
-  // Check if the net_cls cgroup for this container exists, by
-  // checking for the processes associated with this cgroup.
-  string cgroup = path::join(
-      flags.cgroups_root,
-      containerID.value());
-
-  Try<set<pid_t>> pids = cgroups::processes(hierarchy.get(), cgroup);
-  ASSERT_SOME(pids);
-
-  // There should be at least one TGID associated with this cgroup.
-  EXPECT_LE(1u, pids.get().size());
-
-  // Read the `net_cls.classid` to verify that the handle has been set.
-  Try<uint32_t> classid = cgroups::net_cls::classid(hierarchy.get(), cgroup);
-  EXPECT_SOME(classid);
-
-  if (classid.isSome()) {
-    // Make sure the primary handle is the same as the one set in
-    // `--cgroup_net_cls_primary_handle`.
-    EXPECT_EQ(primary, (classid.get() & 0xffff0000) >> 16);
-
-    // Make sure the secondary handle is 0xffff.
-    EXPECT_EQ(0xffffu, classid.get() & 0xffff);
-  }
-
-  // Isolator cleanup test: Killing the task should cleanup the cgroup
-  // associated with the container.
-  Future<TaskStatus> killStatus;
-  EXPECT_CALL(sched, statusUpdate(_, _))
-    .WillOnce(FutureArg<1>(&killStatus));
-
-  // Wait for the executor to exit. We are using 'gc.schedule' as a proxy event
-  // to monitor the exit of the executor.
-  Future<Nothing> gcSchedule = FUTURE_DISPATCH(
-      _, &slave::GarbageCollectorProcess::schedule);
-
-  driver.killTask(status.get().task_id());
-
-  AWAIT_READY(gcSchedule);
-
-  // If the cleanup is successful the net_cls cgroup for this container should
-  // not exist.
-  ASSERT_FALSE(os::exists(cgroup));
-
-  driver.stop();
-  driver.join();
-}
-
-
-// This test verifies that we are able to retrieve the `net_cls` handle
-// from `/state`.
-TEST_F(NetClsIsolatorTest, ROOT_CGROUPS_ContainerStatus)
-{
-  Try<Owned<cluster::Master>> master = StartMaster();
-  ASSERT_SOME(master);
-
-  slave::Flags flags = CreateSlaveFlags();
-  flags.isolation = "cgroups/net_cls";
-  flags.cgroups_net_cls_primary_handle = stringify(0x0012);
-  flags.cgroups_net_cls_secondary_handles = "0x0011,0x0012";
-
-  Fetcher fetcher;
-
-  Try<MesosContainerizer*> _containerizer =
-    MesosContainerizer::create(flags, true, &fetcher);
-
-  ASSERT_SOME(_containerizer);
-  Owned<MesosContainerizer> containerizer(_containerizer.get());
-
-  Owned<MasterDetector> detector = master.get()->createDetector();
-
-  Try<Owned<cluster::Slave>> slave =
-    StartSlave(detector.get(), containerizer.get(), flags);
-  ASSERT_SOME(slave);
-
-  MockScheduler sched;
-
-  MesosSchedulerDriver driver(
-      &sched, DEFAULT_FRAMEWORK_INFO, master.get()->pid, DEFAULT_CREDENTIAL);
-
-  Future<Nothing> schedRegistered;
-  EXPECT_CALL(sched, registered(_, _, _))
-    .WillOnce(FutureSatisfy(&schedRegistered));
-
-  Future<vector<Offer>> offers;
-  EXPECT_CALL(sched, resourceOffers(_, _))
-    .WillOnce(FutureArg<1>(&offers))
-    .WillRepeatedly(Return());      // Ignore subsequent offers.
-
-  driver.start();
-
-  AWAIT_READY(schedRegistered);
-
-  AWAIT_READY(offers);
-  EXPECT_EQ(1u, offers.get().size());
-
-  // Create a task to be launched in the mesos-container.
-  TaskInfo task = createTask(offers.get()[0], "sleep 1000");
-
-  Future<TaskStatus> status;
-  EXPECT_CALL(sched, statusUpdate(_, _))
-    .WillOnce(FutureArg<1>(&status));
-
-  driver.launchTasks(offers.get()[0].id(), {task});
-
-  AWAIT_READY(status);
-  ASSERT_EQ(TASK_RUNNING, status.get().state());
-
-  // Task is ready. Verify `ContainerStatus` is present in slave state.
-  Future<Response> response = http::get(
-      slave.get()->pid,
-      "state",
-      None(),
-      createBasicAuthHeaders(DEFAULT_CREDENTIAL));
-
-  AWAIT_EXPECT_RESPONSE_STATUS_EQ(OK().status, response);
-  AWAIT_EXPECT_RESPONSE_HEADER_EQ(APPLICATION_JSON, "Content-Type", response);
-
-  Try<JSON::Object> parse = JSON::parse<JSON::Object>(response.get().body);
-  ASSERT_SOME(parse);
-
-  Result<JSON::Object> netCls = parse->find<JSON::Object>(
-      "frameworks[0].executors[0].tasks[0].statuses[0]."
-      "container_status.cgroup_info.net_cls");
-  ASSERT_SOME(netCls);
-
-  uint32_t classid =
-    netCls->values["classid"].as<JSON::Number>().as<uint32_t>();
-
-  // Check the primary and the secondary handle.
-  EXPECT_EQ(0x0012u, classid >> 16);
-  EXPECT_EQ(0x0011u, classid & 0xffff);
-
-  driver.stop();
-  driver.join();
-}
-#endif
-
-
-#ifdef __linux__
 class PerfEventIsolatorTest : public MesosTest {};
 
 

http://git-wip-us.apache.org/repos/asf/mesos/blob/34bcae44/src/tests/environment.cpp
----------------------------------------------------------------------
diff --git a/src/tests/environment.cpp b/src/tests/environment.cpp
index 7f144f1..d5abfc9 100644
--- a/src/tests/environment.cpp
+++ b/src/tests/environment.cpp
@@ -408,8 +408,9 @@ public:
     if (netCls.isError()) {
       std::cerr
         << "-------------------------------------------------------------\n"
-        << "Cannot enable NetClsIsolatorTest since we cannot determine \n"
-        << "the existence of the net_cls cgroup subsystem.\n"
+        << "Cannot enable net_cls cgroup subsystem associated test cases \n"
+        << "since we cannot determine the existence of the net_cls cgroup\n"
+        << "subsystem.\n"
         << "-------------------------------------------------------------\n";
       return;
     }
@@ -417,9 +418,10 @@ public:
     if (netCls.isSome() && !netCls.get()) {
       std::cerr
         << "-------------------------------------------------------------\n"
-        << "Cannot enable NetClsIsolatorTest since net_cls cgroup \n"
-        << "subsystem is not enabled. Check instructions for your linux\n"
-        << "distrubtion to enable the net_cls cgroups on your system.\n"
+        << "Cannot enable net_cls cgroup subsystem associated test cases \n"
+        << "since net_cls cgroup subsystem is not enabled. Check instructions\n"
+        << "for your linux distrubtion to enable the net_cls cgroup subsystem\n"
+        << "on your system.\n"
         << "-----------------------------------------------------------\n";
       return;
     }
@@ -427,8 +429,8 @@ public:
 #else
     std::cerr
         << "-----------------------------------------------------------\n"
-        << "Cannot enable NetClsIsolatorTest since this platform does\n"
-        << "not support cgroups.\n"
+        << "Cannot enable net_cls cgroup subsystem associated test cases\n"
+        << "since this platform does not support cgroups.\n"
         << "-----------------------------------------------------------\n";
 #endif
   }


[05/17] mesos git commit: Enabled cgroups unified isolator in isolation.

Posted by ji...@apache.org.
Enabled cgroups unified isolator in isolation.

Review: https://reviews.apache.org/r/49855/


Project: http://git-wip-us.apache.org/repos/asf/mesos/repo
Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/e2fea326
Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/e2fea326
Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/e2fea326

Branch: refs/heads/master
Commit: e2fea326de58bd60d6ca8513ffd4fb89cf2dce8d
Parents: f833169
Author: haosdent huang <ha...@gmail.com>
Authored: Mon Sep 12 16:34:33 2016 -0700
Committer: Jie Yu <yu...@gmail.com>
Committed: Tue Sep 13 10:52:01 2016 -0700

----------------------------------------------------------------------
 src/slave/containerizer/mesos/containerizer.cpp | 25 ++++++++++++++++----
 1 file changed, 20 insertions(+), 5 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/e2fea326/src/slave/containerizer/mesos/containerizer.cpp
----------------------------------------------------------------------
diff --git a/src/slave/containerizer/mesos/containerizer.cpp b/src/slave/containerizer/mesos/containerizer.cpp
index 1a120f1..24b0585 100644
--- a/src/slave/containerizer/mesos/containerizer.cpp
+++ b/src/slave/containerizer/mesos/containerizer.cpp
@@ -72,6 +72,7 @@
 #endif // __linux__
 
 #ifdef __linux__
+#include "slave/containerizer/mesos/isolators/cgroups/cgroups.hpp"
 #include "slave/containerizer/mesos/isolators/cgroups/cpushare.hpp"
 #include "slave/containerizer/mesos/isolators/cgroups/devices.hpp"
 #include "slave/containerizer/mesos/isolators/cgroups/mem.hpp"
@@ -326,11 +327,11 @@ Try<MesosContainerizer*> MesosContainerizer::create(
     {"windows/cpu", &WindowsCpuIsolatorProcess::create},
 #endif // __WINDOWS__
 #ifdef __linux__
-    {"cgroups/cpu", &CgroupsCpushareIsolatorProcess::create},
-    {"cgroups/devices", &CgroupsDevicesIsolatorProcess::create},
-    {"cgroups/mem", &CgroupsMemIsolatorProcess::create},
-    {"cgroups/net_cls", &CgroupsNetClsIsolatorProcess::create},
-    {"cgroups/perf_event", &CgroupsPerfEventIsolatorProcess::create},
+    {"cgroups/cpu", &CgroupsIsolatorProcess::create},
+    {"cgroups/devices", &CgroupsIsolatorProcess::create},
+    {"cgroups/mem", &CgroupsIsolatorProcess::create},
+    {"cgroups/net_cls", &CgroupsIsolatorProcess::create},
+    {"cgroups/perf_event", &CgroupsIsolatorProcess::create},
     {"appc/runtime", &AppcRuntimeIsolatorProcess::create},
     {"docker/runtime", &DockerRuntimeIsolatorProcess::create},
     {"docker/volume", &DockerVolumeIsolatorProcess::create},
@@ -372,7 +373,21 @@ Try<MesosContainerizer*> MesosContainerizer::create(
 
   vector<Owned<Isolator>> isolators;
 
+  // Note: For cgroups, we only create `CgroupsIsolatorProcess` once.
+  // We use this flag to identify whether `CgroupsIsolatorProcess` has
+  // been created or not.
+  bool cgroupsIsolatorCreated = false;
+
   foreach (const string& isolation, isolations) {
+    if (strings::startsWith(isolation, "cgroups/")) {
+      if (cgroupsIsolatorCreated) {
+        // Skip when `CgroupsIsolatorProcess` have been created.
+        continue;
+      } else {
+        cgroupsIsolatorCreated = true;
+      }
+    }
+
     Try<Isolator*> isolator = [&]() -> Try<Isolator*> {
       if (creators.contains(isolation)) {
         return creators.at(isolation)(flags_);


[15/17] mesos git commit: Added a test case `ROOT_CGROUPS_CFS_BigQuotaDecimal`.

Posted by ji...@apache.org.
Added a test case `ROOT_CGROUPS_CFS_BigQuotaDecimal`.

Add a new test case `ROOT_CGROUPS_CFS_BigQuotaDecimal` to test updating
CFS quota with decimal.

Review: https://reviews.apache.org/r/51794/


Project: http://git-wip-us.apache.org/repos/asf/mesos/repo
Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/6cfa4a6f
Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/6cfa4a6f
Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/6cfa4a6f

Branch: refs/heads/master
Commit: 6cfa4a6f07f61c9b5edc5cce4b778fdf58baa81a
Parents: 451f65f
Author: haosdent huang <ha...@gmail.com>
Authored: Tue Sep 13 10:27:54 2016 -0700
Committer: Jie Yu <yu...@gmail.com>
Committed: Tue Sep 13 10:52:01 2016 -0700

----------------------------------------------------------------------
 src/tests/containerizer/cgroups_tests.cpp | 17 ++++++++++++++++-
 1 file changed, 16 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/6cfa4a6f/src/tests/containerizer/cgroups_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/containerizer/cgroups_tests.cpp b/src/tests/containerizer/cgroups_tests.cpp
index 821c786..6ebcebb 100644
--- a/src/tests/containerizer/cgroups_tests.cpp
+++ b/src/tests/containerizer/cgroups_tests.cpp
@@ -509,7 +509,7 @@ TEST_F(CgroupsAnyHierarchyTest, ROOT_CGROUPS_Write)
 }
 
 
-TEST_F(CgroupsAnyHierarchyTest, ROOT_CGROUPS_CFS_Big_Quota)
+TEST_F(CgroupsAnyHierarchyTest, ROOT_CGROUPS_CFS_BigQuota)
 {
   string hierarchy = path::join(baseHierarchy, "cpu");
   ASSERT_SOME(cgroups::create(hierarchy, TEST_CGROUPS_ROOT));
@@ -524,6 +524,21 @@ TEST_F(CgroupsAnyHierarchyTest, ROOT_CGROUPS_CFS_Big_Quota)
 }
 
 
+TEST_F(CgroupsAnyHierarchyTest, ROOT_CGROUPS_CFS_BigQuotaDecimal)
+{
+  string hierarchy = path::join(baseHierarchy, "cpu");
+  ASSERT_SOME(cgroups::create(hierarchy, TEST_CGROUPS_ROOT));
+
+  Duration quota = Seconds(100.5); // Big quota with decimal.
+  ASSERT_SOME(cgroups::cpu::cfs_quota_us(hierarchy, TEST_CGROUPS_ROOT, quota));
+
+  // Ensure we can read back the correct quota.
+  ASSERT_SOME_EQ(
+      quota,
+      cgroups::cpu::cfs_quota_us(hierarchy, TEST_CGROUPS_ROOT));
+}
+
+
 class CgroupsAnyHierarchyWithCpuAcctMemoryTest
   : public CgroupsAnyHierarchyTest
 {


[02/17] mesos git commit: Refactored the test cases for net_cls cgroups isolation.

Posted by ji...@apache.org.
Refactored the test cases for net_cls cgroups isolation.

Review: https://reviews.apache.org/r/51789/


Project: http://git-wip-us.apache.org/repos/asf/mesos/repo
Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/665d4cc1
Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/665d4cc1
Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/665d4cc1

Branch: refs/heads/master
Commit: 665d4cc103640de43c742268a84fd0816de6ca42
Parents: 612efe2
Author: haosdent huang <ha...@gmail.com>
Authored: Mon Sep 12 16:35:11 2016 -0700
Committer: Jie Yu <yu...@gmail.com>
Committed: Tue Sep 13 10:52:01 2016 -0700

----------------------------------------------------------------------
 .../containerizer/cgroups_isolator_tests.cpp    | 324 +++++++++++++++++++
 1 file changed, 324 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/665d4cc1/src/tests/containerizer/cgroups_isolator_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/containerizer/cgroups_isolator_tests.cpp b/src/tests/containerizer/cgroups_isolator_tests.cpp
index 75fe3b7..4882af0 100644
--- a/src/tests/containerizer/cgroups_isolator_tests.cpp
+++ b/src/tests/containerizer/cgroups_isolator_tests.cpp
@@ -24,6 +24,8 @@
 
 #include "slave/containerizer/mesos/isolators/cgroups/constants.hpp"
 
+#include "slave/containerizer/mesos/isolators/cgroups/subsystems/net_cls.hpp"
+
 #include "tests/mesos.hpp"
 #include "tests/script.hpp"
 
@@ -41,6 +43,8 @@ using mesos::internal::slave::CPU_SHARES_PER_CPU_REVOCABLE;
 using mesos::internal::slave::DEFAULT_EXECUTOR_CPUS;
 using mesos::internal::slave::Fetcher;
 using mesos::internal::slave::MesosContainerizer;
+using mesos::internal::slave::NetClsHandle;
+using mesos::internal::slave::NetClsHandleManager;
 
 using mesos::master::detector::MasterDetector;
 
@@ -48,6 +52,10 @@ using process::Future;
 using process::Owned;
 using process::Queue;
 
+using process::http::OK;
+using process::http::Response;
+
+using std::set;
 using std::string;
 using std::vector;
 
@@ -513,6 +521,322 @@ TEST_F(CgroupsIsolatorTest, ROOT_CGROUPS_PidsAndTids)
   driver.join();
 }
 
+
+class NetClsHandleManagerTest : public testing::Test {};
+
+
+// Tests the ability of the `NetClsHandleManager` class to allocate
+// and free secondary handles from a range of primary handles.
+TEST_F(NetClsHandleManagerTest, AllocateFreeHandles)
+{
+  NetClsHandleManager manager(IntervalSet<uint32_t>(
+      (Bound<uint32_t>::closed(0x0002),
+       Bound<uint32_t>::closed(0x0003))));
+
+  Try<NetClsHandle> handle = manager.alloc(0x0003);
+  ASSERT_SOME(handle);
+
+  EXPECT_SOME_TRUE(manager.isUsed(handle.get()));
+
+  ASSERT_SOME(manager.free(handle.get()));
+
+  EXPECT_SOME_FALSE(manager.isUsed(handle.get()));
+}
+
+
+// Make sure allocation of secondary handles for invalid primary
+// handles results in an error.
+TEST_F(NetClsHandleManagerTest, AllocateInvalidPrimary)
+{
+  NetClsHandleManager manager(IntervalSet<uint32_t>(
+      (Bound<uint32_t>::closed(0x0002),
+       Bound<uint32_t>::closed(0x0003))));
+
+  ASSERT_ERROR(manager.alloc(0x0001));
+}
+
+
+// Tests that we can reserve secondary handles for a given primary
+// handle so that they won't be allocated out later.
+TEST_F(NetClsHandleManagerTest, ReserveHandles)
+{
+  NetClsHandleManager manager(IntervalSet<uint32_t>(
+      (Bound<uint32_t>::closed(0x0002),
+       Bound<uint32_t>::closed(0x0003))));
+
+  NetClsHandle handle(0x0003, 0xffff);
+
+  ASSERT_SOME(manager.reserve(handle));
+
+  EXPECT_SOME_TRUE(manager.isUsed(handle));
+}
+
+
+// Tests that secondary handles are allocated only from a given range,
+// when the range is specified.
+TEST_F(NetClsHandleManagerTest, SecondaryHandleRange)
+{
+  NetClsHandleManager manager(
+      IntervalSet<uint32_t>(
+        (Bound<uint32_t>::closed(0x0002),
+         Bound<uint32_t>::closed(0x0003))),
+      IntervalSet<uint32_t>(
+        (Bound<uint32_t>::closed(0xffff),
+         Bound<uint32_t>::closed(0xffff))));
+
+  Try<NetClsHandle> handle = manager.alloc(0x0003);
+  ASSERT_SOME(handle);
+
+  EXPECT_SOME_TRUE(manager.isUsed(handle.get()));
+
+  // Try allocating another handle. This should fail, since we don't
+  // have any more secondary handles left.
+  EXPECT_ERROR(manager.alloc(0x0003));
+
+  ASSERT_SOME(manager.free(handle.get()));
+
+  ASSERT_SOME(manager.reserve(handle.get()));
+
+  EXPECT_SOME_TRUE(manager.isUsed(handle.get()));
+
+  // Make sure you cannot reserve a secondary handle that is out of
+  // range.
+  EXPECT_ERROR(manager.reserve(NetClsHandle(0x0003, 0x0001)));
+}
+
+
+// This tests the create, prepare, isolate and cleanup methods of the
+// 'CgroupNetClsIsolatorProcess'. The test first creates a
+// 'MesosContainerizer' with net_cls cgroup isolator enabled. The
+// net_cls cgroup isolator is implemented in the
+// 'CgroupNetClsIsolatorProcess' class. The test then launches a task
+// in a mesos container and checks to see if the container has been
+// added to the right net_cls cgroup. Finally, the test kills the task
+// and makes sure that the 'CgroupNetClsIsolatorProcess' cleans up the
+// net_cls cgroup created for the container.
+TEST_F(CgroupsIsolatorTest, ROOT_CGROUPS_NET_CLS_Isolate)
+{
+  Try<Owned<cluster::Master>> master = StartMaster();
+  ASSERT_SOME(master);
+
+  uint16_t primary = 0x0012;
+
+  slave::Flags flags = CreateSlaveFlags();
+  flags.isolation = "cgroups/net_cls";
+  flags.cgroups_net_cls_primary_handle = stringify(primary);
+  flags.cgroups_net_cls_secondary_handles = "0xffff,0xffff";
+
+  Fetcher fetcher;
+
+  Try<MesosContainerizer*> _containerizer =
+    MesosContainerizer::create(flags, true, &fetcher);
+
+  ASSERT_SOME(_containerizer);
+
+  Owned<MesosContainerizer> containerizer(_containerizer.get());
+
+  Owned<MasterDetector> detector = master.get()->createDetector();
+
+  Try<Owned<cluster::Slave>> slave = StartSlave(
+      detector.get(),
+      containerizer.get(),
+      flags);
+
+  ASSERT_SOME(slave);
+
+  MockScheduler sched;
+
+  MesosSchedulerDriver driver(
+      &sched,
+      DEFAULT_FRAMEWORK_INFO,
+      master.get()->pid,
+      DEFAULT_CREDENTIAL);
+
+  Future<Nothing> schedRegistered;
+  EXPECT_CALL(sched, registered(_, _, _))
+    .WillOnce(FutureSatisfy(&schedRegistered));
+
+  Future<vector<Offer>> offers;
+  EXPECT_CALL(sched, resourceOffers(_, _))
+    .WillOnce(FutureArg<1>(&offers))
+    .WillRepeatedly(Return());      // Ignore subsequent offers.
+
+  driver.start();
+
+  AWAIT_READY(schedRegistered);
+
+  AWAIT_READY(offers);
+  EXPECT_EQ(1u, offers.get().size());
+
+  // Create a task to be launched in the mesos-container. We will be
+  // explicitly killing this task to perform the cleanup test.
+  TaskInfo task = createTask(offers.get()[0], "sleep 1000");
+
+  Future<TaskStatus> status;
+  EXPECT_CALL(sched, statusUpdate(_, _))
+    .WillOnce(FutureArg<1>(&status));
+
+  driver.launchTasks(offers.get()[0].id(), {task});
+
+  // Capture the update to verify that the task has been launched.
+  AWAIT_READY(status);
+  ASSERT_EQ(TASK_RUNNING, status.get().state());
+
+  // Task is ready.  Make sure there is exactly 1 container in the hashset.
+  Future<hashset<ContainerID>> containers = containerizer->containers();
+  AWAIT_READY(containers);
+  EXPECT_EQ(1u, containers.get().size());
+
+  const ContainerID& containerID = *(containers.get().begin());
+
+  Result<string> hierarchy = cgroups::hierarchy("net_cls");
+  ASSERT_SOME(hierarchy);
+
+  // Check if the net_cls cgroup for this container exists, by
+  // checking for the processes associated with this cgroup.
+  string cgroup = path::join(
+      flags.cgroups_root,
+      containerID.value());
+
+  Try<set<pid_t>> pids = cgroups::processes(hierarchy.get(), cgroup);
+  ASSERT_SOME(pids);
+
+  // There should be at least one TGID associated with this cgroup.
+  EXPECT_LE(1u, pids.get().size());
+
+  // Read the `net_cls.classid` to verify that the handle has been set.
+  Try<uint32_t> classid = cgroups::net_cls::classid(hierarchy.get(), cgroup);
+  EXPECT_SOME(classid);
+
+  if (classid.isSome()) {
+    // Make sure the primary handle is the same as the one set in
+    // `--cgroup_net_cls_primary_handle`.
+    EXPECT_EQ(primary, (classid.get() & 0xffff0000) >> 16);
+
+    // Make sure the secondary handle is 0xffff.
+    EXPECT_EQ(0xffffu, classid.get() & 0xffff);
+  }
+
+  // Isolator cleanup test: Killing the task should cleanup the cgroup
+  // associated with the container.
+  Future<TaskStatus> killStatus;
+  EXPECT_CALL(sched, statusUpdate(_, _))
+    .WillOnce(FutureArg<1>(&killStatus));
+
+  // Wait for the executor to exit. We are using 'gc.schedule' as a proxy event
+  // to monitor the exit of the executor.
+  Future<Nothing> gcSchedule = FUTURE_DISPATCH(
+      _, &slave::GarbageCollectorProcess::schedule);
+
+  driver.killTask(status.get().task_id());
+
+  AWAIT_READY(gcSchedule);
+
+  // If the cleanup is successful the net_cls cgroup for this container should
+  // not exist.
+  ASSERT_FALSE(os::exists(cgroup));
+
+  driver.stop();
+  driver.join();
+}
+
+
+// This test verifies that we are able to retrieve the `net_cls` handle
+// from `/state`.
+TEST_F(CgroupsIsolatorTest, ROOT_CGROUPS_NET_CLS_ContainerStatus)
+{
+  Try<Owned<cluster::Master>> master = StartMaster();
+  ASSERT_SOME(master);
+
+  slave::Flags flags = CreateSlaveFlags();
+  flags.isolation = "cgroups/net_cls";
+  flags.cgroups_net_cls_primary_handle = stringify(0x0012);
+  flags.cgroups_net_cls_secondary_handles = "0x0011,0x0012";
+
+  Fetcher fetcher;
+
+  Try<MesosContainerizer*> _containerizer =
+    MesosContainerizer::create(flags, true, &fetcher);
+
+  ASSERT_SOME(_containerizer);
+
+  Owned<MesosContainerizer> containerizer(_containerizer.get());
+
+  Owned<MasterDetector> detector = master.get()->createDetector();
+
+  Try<Owned<cluster::Slave>> slave = StartSlave(
+      detector.get(),
+      containerizer.get(),
+      flags);
+
+  ASSERT_SOME(slave);
+
+  MockScheduler sched;
+
+  MesosSchedulerDriver driver(
+      &sched,
+      DEFAULT_FRAMEWORK_INFO,
+      master.get()->pid,
+      DEFAULT_CREDENTIAL);
+
+  Future<Nothing> schedRegistered;
+  EXPECT_CALL(sched, registered(_, _, _))
+    .WillOnce(FutureSatisfy(&schedRegistered));
+
+  Future<vector<Offer>> offers;
+  EXPECT_CALL(sched, resourceOffers(_, _))
+    .WillOnce(FutureArg<1>(&offers))
+    .WillRepeatedly(Return());      // Ignore subsequent offers.
+
+  driver.start();
+
+  AWAIT_READY(schedRegistered);
+
+  AWAIT_READY(offers);
+  EXPECT_EQ(1u, offers.get().size());
+
+  // Create a task to be launched in the mesos-container.
+  TaskInfo task = createTask(offers.get()[0], "sleep 1000");
+
+  Future<TaskStatus> status;
+  EXPECT_CALL(sched, statusUpdate(_, _))
+    .WillOnce(FutureArg<1>(&status));
+
+  driver.launchTasks(offers.get()[0].id(), {task});
+
+  AWAIT_READY(status);
+  ASSERT_EQ(TASK_RUNNING, status.get().state());
+
+  // Task is ready. Verify `ContainerStatus` is present in slave state.
+  Future<Response> response = process::http::get(
+      slave.get()->pid,
+      "state",
+      None(),
+      createBasicAuthHeaders(DEFAULT_CREDENTIAL));
+
+  AWAIT_EXPECT_RESPONSE_STATUS_EQ(OK().status, response);
+  AWAIT_EXPECT_RESPONSE_HEADER_EQ(APPLICATION_JSON, "Content-Type", response);
+
+  Try<JSON::Object> parse = JSON::parse<JSON::Object>(response.get().body);
+  ASSERT_SOME(parse);
+
+  Result<JSON::Object> netCls = parse->find<JSON::Object>(
+      "frameworks[0].executors[0].tasks[0].statuses[0]."
+      "container_status.cgroup_info.net_cls");
+
+  ASSERT_SOME(netCls);
+
+  uint32_t classid =
+    netCls->values["classid"].as<JSON::Number>().as<uint32_t>();
+
+  // Check the primary and the secondary handle.
+  EXPECT_EQ(0x0012u, classid >> 16);
+  EXPECT_EQ(0x0011u, classid & 0xffff);
+
+  driver.stop();
+  driver.join();
+}
+
 } // namespace tests {
 } // namespace internal {
 } // namespace mesos {


[03/17] mesos git commit: Disabled perf test when perf version is not supported.

Posted by ji...@apache.org.
Disabled perf test when perf version is not supported.

Review: https://reviews.apache.org/r/38528/


Project: http://git-wip-us.apache.org/repos/asf/mesos/repo
Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/e766d4d1
Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/e766d4d1
Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/e766d4d1

Branch: refs/heads/master
Commit: e766d4d191e762916194fd0bfb94b68a22dfa49f
Parents: 0c3a227
Author: haosdent huang <ha...@gmail.com>
Authored: Tue Sep 13 10:01:54 2016 -0700
Committer: Jie Yu <yu...@gmail.com>
Committed: Tue Sep 13 10:52:01 2016 -0700

----------------------------------------------------------------------
 src/tests/environment.cpp | 12 +++++++-----
 1 file changed, 7 insertions(+), 5 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/e766d4d1/src/tests/environment.cpp
----------------------------------------------------------------------
diff --git a/src/tests/environment.cpp b/src/tests/environment.cpp
index a0dbfc2..57ec492 100644
--- a/src/tests/environment.cpp
+++ b/src/tests/environment.cpp
@@ -48,6 +48,7 @@
 #ifdef __linux__
 #include "linux/cgroups.hpp"
 #include "linux/fs.hpp"
+#include "linux/perf.hpp"
 #endif
 
 #ifdef WITH_NETWORK_ISOLATOR
@@ -555,11 +556,12 @@ public:
   PerfCPUCyclesFilter()
   {
 #ifdef __linux__
-    bool perfUnavailable = os::system("perf help >&-") != 0;
+    bool perfUnavailable = !perf::supported();
     if (perfUnavailable) {
       perfError = Error(
-          "The 'perf' command wasn't found so tests using it\n"
-          "to sample the 'cpu-cycles' hardware event will not be run.");
+          "Could not find the 'perf' command or its version lower that "
+          "2.6.39 so tests using it to sample the 'cpu-cycles' hardware "
+          "event will not be run.");
     } else {
       bool cyclesUnavailable =
         os::system("perf list hw | grep cpu-cycles >/dev/null") != 0;
@@ -605,11 +607,11 @@ public:
   PerfFilter()
   {
 #ifdef __linux__
-    perfError = os::system("perf help >&-") != 0;
+    perfError = !perf::supported();
     if (perfError) {
       std::cerr
         << "-------------------------------------------------------------\n"
-        << "No 'perf' command found so no 'perf' tests will be run\n"
+        << "require 'perf' version >= 2.6.39 so no 'perf' tests will be run\n"
         << "-------------------------------------------------------------"
         << std::endl;
     }


[10/17] mesos git commit: Updated `NetClsCgroupsFilter` to use `NET_CLS_` to filter test cases.

Posted by ji...@apache.org.
Updated `NetClsCgroupsFilter` to use `NET_CLS_` to filter test cases.

Review: https://reviews.apache.org/r/51781/


Project: http://git-wip-us.apache.org/repos/asf/mesos/repo
Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/dcf48fe0
Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/dcf48fe0
Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/dcf48fe0

Branch: refs/heads/master
Commit: dcf48fe041ba02d81238d069263e2323ab0c3df0
Parents: edf824b
Author: haosdent huang <ha...@gmail.com>
Authored: Mon Sep 12 16:34:54 2016 -0700
Committer: Jie Yu <yu...@gmail.com>
Committed: Tue Sep 13 10:52:01 2016 -0700

----------------------------------------------------------------------
 src/tests/environment.cpp | 5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/dcf48fe0/src/tests/environment.cpp
----------------------------------------------------------------------
diff --git a/src/tests/environment.cpp b/src/tests/environment.cpp
index d5abfc9..a0dbfc2 100644
--- a/src/tests/environment.cpp
+++ b/src/tests/environment.cpp
@@ -437,10 +437,7 @@ public:
 
   bool disable(const ::testing::TestInfo* test) const
   {
-    if (matches(test, "NetClsIsolatorTest")) {
-      return netClsError;
-    }
-    return false;
+    return matches(test, "NET_CLS_") && netClsError;
   }
 
 private:


[16/17] mesos git commit: Refactored the test cases for perf_event cgroups isolation.

Posted by ji...@apache.org.
Refactored the test cases for perf_event cgroups isolation.

Review: https://reviews.apache.org/r/51790/


Project: http://git-wip-us.apache.org/repos/asf/mesos/repo
Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/08594c26
Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/08594c26
Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/08594c26

Branch: refs/heads/master
Commit: 08594c26a41fc9593ab69b62bd2f2cc8b177bbdc
Parents: 665d4cc
Author: haosdent huang <ha...@gmail.com>
Authored: Mon Sep 12 16:35:14 2016 -0700
Committer: Jie Yu <yu...@gmail.com>
Committed: Tue Sep 13 10:52:01 2016 -0700

----------------------------------------------------------------------
 .../containerizer/cgroups_isolator_tests.cpp    | 111 +++++++++++++++++++
 1 file changed, 111 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/08594c26/src/tests/containerizer/cgroups_isolator_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/containerizer/cgroups_isolator_tests.cpp b/src/tests/containerizer/cgroups_isolator_tests.cpp
index 4882af0..31c95c8 100644
--- a/src/tests/containerizer/cgroups_isolator_tests.cpp
+++ b/src/tests/containerizer/cgroups_isolator_tests.cpp
@@ -837,6 +837,117 @@ TEST_F(CgroupsIsolatorTest, ROOT_CGROUPS_NET_CLS_ContainerStatus)
   driver.join();
 }
 
+
+TEST_F(CgroupsIsolatorTest, ROOT_CGROUPS_PERF_Sample)
+{
+  Try<Owned<cluster::Master>> master = StartMaster();
+  ASSERT_SOME(master);
+
+  slave::Flags flags = CreateSlaveFlags();
+  flags.perf_events = "cycles,task-clock";
+  flags.perf_duration = Milliseconds(250);
+  flags.perf_interval = Milliseconds(500);
+  flags.isolation = "cgroups/perf_event";
+
+  Fetcher fetcher;
+
+  Try<MesosContainerizer*> _containerizer =
+    MesosContainerizer::create(flags, true, &fetcher);
+
+  ASSERT_SOME(_containerizer);
+
+  Owned<MesosContainerizer> containerizer(_containerizer.get());
+
+  Owned<MasterDetector> detector = master.get()->createDetector();
+
+  Try<Owned<cluster::Slave>> slave = StartSlave(
+      detector.get(),
+      containerizer.get());
+
+  ASSERT_SOME(slave);
+
+  MockScheduler sched;
+
+  MesosSchedulerDriver driver(
+      &sched,
+      DEFAULT_FRAMEWORK_INFO,
+      master.get()->pid,
+      DEFAULT_CREDENTIAL);
+
+  EXPECT_CALL(sched, registered(&driver, _, _))
+    .Times(1);
+
+  Future<vector<Offer>> offers;
+  EXPECT_CALL(sched, resourceOffers(&driver, _))
+    .WillOnce(FutureArg<1>(&offers))
+    .WillRepeatedly(Return()); // Ignore subsequent offers.
+
+  driver.start();
+
+  AWAIT_READY(offers);
+  EXPECT_NE(0u, offers.get().size());
+
+  TaskInfo task = createTask(offers.get()[0], "sleep 120");
+
+  Future<TaskStatus> statusRunning;
+  EXPECT_CALL(sched, statusUpdate(&driver, _))
+    .WillOnce(FutureArg<1>(&statusRunning));
+
+  driver.launchTasks(offers.get()[0].id(), {task});
+
+  AWAIT_READY(statusRunning);
+  EXPECT_EQ(TASK_RUNNING, statusRunning.get().state());
+
+  Future<hashset<ContainerID>> containers = containerizer->containers();
+  AWAIT_READY(containers);
+  EXPECT_EQ(1u, containers.get().size());
+
+  ContainerID containerId = *(containers.get().begin());
+
+  // This first sample is likely to be empty because perf hasn't
+  // completed yet but we should still have the required fields.
+  Future<ResourceStatistics> statistics1 = containerizer->usage(containerId);
+  AWAIT_READY(statistics1);
+  ASSERT_TRUE(statistics1.get().has_perf());
+  EXPECT_TRUE(statistics1.get().perf().has_timestamp());
+  EXPECT_TRUE(statistics1.get().perf().has_duration());
+
+  // Wait until we get the next sample. We use a generous timeout of
+  // two seconds because we currently have a one second reap interval;
+  // when running perf with perf_duration of 250ms we won't notice the
+  // exit for up to one second.
+  ResourceStatistics statistics2;
+  Duration waited = Duration::zero();
+  do {
+    Future<ResourceStatistics> statistics = containerizer->usage(containerId);
+    AWAIT_READY(statistics);
+
+    statistics2 = statistics.get();
+
+    ASSERT_TRUE(statistics2.has_perf());
+
+    if (statistics1.get().perf().timestamp() !=
+        statistics2.perf().timestamp()) {
+      break;
+    }
+
+    os::sleep(Milliseconds(250));
+    waited += Milliseconds(250);
+  } while (waited < Seconds(2));
+
+  EXPECT_NE(statistics1.get().perf().timestamp(),
+            statistics2.perf().timestamp());
+
+  EXPECT_TRUE(statistics2.perf().has_cycles());
+  EXPECT_LE(0u, statistics2.perf().cycles());
+
+  EXPECT_TRUE(statistics2.perf().has_task_clock());
+  EXPECT_LE(0.0, statistics2.perf().task_clock());
+
+  driver.stop();
+  driver.join();
+}
+
 } // namespace tests {
 } // namespace internal {
 } // namespace mesos {


[04/17] mesos git commit: Removed CgroupsDevicesIsolatorProcess.

Posted by ji...@apache.org.
Removed CgroupsDevicesIsolatorProcess.

Review: https://reviews.apache.org/r/50749/


Project: http://git-wip-us.apache.org/repos/asf/mesos/repo
Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/dfd3690b
Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/dfd3690b
Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/dfd3690b

Branch: refs/heads/master
Commit: dfd3690b9bbede8cce0c25a4274acaa0bfdf5b83
Parents: c3d1f77
Author: haosdent huang <ha...@gmail.com>
Authored: Mon Sep 12 16:34:40 2016 -0700
Committer: Jie Yu <yu...@gmail.com>
Committed: Tue Sep 13 10:52:01 2016 -0700

----------------------------------------------------------------------
 src/CMakeLists.txt                              |   1 -
 src/Makefile.am                                 |   2 -
 src/slave/containerizer/mesos/containerizer.cpp |   1 -
 .../mesos/isolators/cgroups/devices.cpp         | 368 -------------------
 .../mesos/isolators/cgroups/devices.hpp         |  98 -----
 5 files changed, 470 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/dfd3690b/src/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 414e723..aae8af8 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -159,7 +159,6 @@ set(LINUX_SRC
   slave/containerizer/mesos/linux_launcher.cpp
   slave/containerizer/mesos/isolators/appc/runtime.cpp
   slave/containerizer/mesos/isolators/cgroups/cgroups.cpp
-  slave/containerizer/mesos/isolators/cgroups/devices.cpp
   slave/containerizer/mesos/isolators/cgroups/mem.cpp
   slave/containerizer/mesos/isolators/cgroups/net_cls.cpp
   slave/containerizer/mesos/isolators/cgroups/perf_event.cpp

http://git-wip-us.apache.org/repos/asf/mesos/blob/dfd3690b/src/Makefile.am
----------------------------------------------------------------------
diff --git a/src/Makefile.am b/src/Makefile.am
index 2ef8a21..3c3f9bd 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1025,7 +1025,6 @@ MESOS_LINUX_FILES =									\
   slave/containerizer/mesos/linux_launcher.cpp						\
   slave/containerizer/mesos/isolators/appc/runtime.cpp					\
   slave/containerizer/mesos/isolators/cgroups/cgroups.cpp				\
-  slave/containerizer/mesos/isolators/cgroups/devices.cpp				\
   slave/containerizer/mesos/isolators/cgroups/mem.cpp					\
   slave/containerizer/mesos/isolators/cgroups/net_cls.cpp				\
   slave/containerizer/mesos/isolators/cgroups/perf_event.cpp				\
@@ -1065,7 +1064,6 @@ MESOS_LINUX_FILES +=									\
   slave/containerizer/mesos/isolators/appc/runtime.hpp					\
   slave/containerizer/mesos/isolators/cgroups/cgroups.hpp				\
   slave/containerizer/mesos/isolators/cgroups/constants.hpp				\
-  slave/containerizer/mesos/isolators/cgroups/devices.hpp				\
   slave/containerizer/mesos/isolators/cgroups/mem.hpp					\
   slave/containerizer/mesos/isolators/cgroups/net_cls.hpp				\
   slave/containerizer/mesos/isolators/cgroups/perf_event.hpp				\

http://git-wip-us.apache.org/repos/asf/mesos/blob/dfd3690b/src/slave/containerizer/mesos/containerizer.cpp
----------------------------------------------------------------------
diff --git a/src/slave/containerizer/mesos/containerizer.cpp b/src/slave/containerizer/mesos/containerizer.cpp
index 0b240d4..c94a683 100644
--- a/src/slave/containerizer/mesos/containerizer.cpp
+++ b/src/slave/containerizer/mesos/containerizer.cpp
@@ -73,7 +73,6 @@
 
 #ifdef __linux__
 #include "slave/containerizer/mesos/isolators/cgroups/cgroups.hpp"
-#include "slave/containerizer/mesos/isolators/cgroups/devices.hpp"
 #include "slave/containerizer/mesos/isolators/cgroups/mem.hpp"
 #include "slave/containerizer/mesos/isolators/cgroups/net_cls.hpp"
 #include "slave/containerizer/mesos/isolators/cgroups/perf_event.hpp"

http://git-wip-us.apache.org/repos/asf/mesos/blob/dfd3690b/src/slave/containerizer/mesos/isolators/cgroups/devices.cpp
----------------------------------------------------------------------
diff --git a/src/slave/containerizer/mesos/isolators/cgroups/devices.cpp b/src/slave/containerizer/mesos/isolators/cgroups/devices.cpp
deleted file mode 100644
index f1b5e75..0000000
--- a/src/slave/containerizer/mesos/isolators/cgroups/devices.cpp
+++ /dev/null
@@ -1,368 +0,0 @@
-// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements.  See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership.  The ASF licenses this file
-// to you under the Apache License, Version 2.0 (the
-// "License"); you may not use this file except in compliance
-// with the License.  You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include <stdint.h>
-
-#include <list>
-#include <set>
-#include <string>
-#include <vector>
-
-#include <process/defer.hpp>
-#include <process/future.hpp>
-#include <process/owned.hpp>
-#include <process/shared.hpp>
-
-#include <stout/error.hpp>
-#include <stout/foreach.hpp>
-#include <stout/hashset.hpp>
-#include <stout/nothing.hpp>
-#include <stout/option.hpp>
-#include <stout/os.hpp>
-#include <stout/try.hpp>
-
-#include "linux/cgroups.hpp"
-
-#include "slave/flags.hpp"
-
-#include "slave/containerizer/containerizer.hpp"
-
-#include "slave/containerizer/mesos/isolator.hpp"
-
-#include "slave/containerizer/mesos/isolators/cgroups/devices.hpp"
-
-using cgroups::devices::Entry;
-
-using mesos::slave::ContainerConfig;
-using mesos::slave::ContainerLaunchInfo;
-using mesos::slave::ContainerLimitation;
-using mesos::slave::ContainerState;
-using mesos::slave::Isolator;
-
-using mesos::internal::slave::Containerizer;
-
-using process::Failure;
-using process::Future;
-using process::PID;
-using process::Shared;
-
-using std::list;
-using std::set;
-using std::string;
-using std::vector;
-
-namespace mesos {
-namespace internal {
-namespace slave {
-
-// The default list of devices to whitelist when device isolation is
-// turned on. The full list of devices can be found here:
-// https://www.kernel.org/doc/Documentation/devices.txt
-//
-// Device whitelisting is described here:
-// https://www.kernel.org/doc/Documentation/cgroup-v1/devices.txt
-static const char* DEFAULT_WHITELIST_ENTRIES[] = {
-  "c *:* m",      // Make new character devices.
-  "b *:* m",      // Make new block devices.
-  "c 5:1 rwm",    // /dev/console
-  "c 4:0 rwm",    // /dev/tty0
-  "c 4:1 rwm",    // /dev/tty1
-  "c 136:* rwm",  // /dev/pts/*
-  "c 5:2 rwm",    // /dev/ptmx
-  "c 10:200 rwm", // /dev/net/tun
-  "c 1:3 rwm",    // /dev/null
-  "c 1:5 rwm",    // /dev/zero
-  "c 1:7 rwm",    // /dev/full
-  "c 5:0 rwm",    // /dev/tty
-  "c 1:9 rwm",    // /dev/urandom
-  "c 1:8 rwm",    // /dev/random
-};
-
-
-CgroupsDevicesIsolatorProcess::CgroupsDevicesIsolatorProcess(
-    const Flags& _flags,
-    const string& _hierarchy)
-  : ProcessBase(process::ID::generate("cgroups-devices-isolator")),
-    flags(_flags),
-    hierarchy(_hierarchy) {}
-
-
-Try<Isolator*> CgroupsDevicesIsolatorProcess::create(const Flags& flags)
-{
-  // Prepare the cgroups device hierarchy.
-  Try<string> hierarchy = cgroups::prepare(
-        flags.cgroups_hierarchy,
-        "devices",
-        flags.cgroups_root);
-
-  if (hierarchy.isError()) {
-    return Error("Failed to prepare hierarchy for 'devices' subsystem: " +
-                 hierarchy.error());
-  }
-
-  // Ensure that no other subsystem is attached to the hierarchy.
-  Try<set<string>> subsystems = cgroups::subsystems(hierarchy.get());
-  if (subsystems.isError()) {
-    return Error("Failed to get subsystems attached to hierarchy"
-                 " '" + stringify(hierarchy.get()) + "': " +
-                 subsystems.error());
-  } else if (subsystems->size() != 1) {
-    return Error("Unexpected subsystems attached to hierarchy"
-                 " '" + stringify(hierarchy.get()) + "': " +
-                 stringify(subsystems.get()));
-  }
-
-  process::Owned<MesosIsolatorProcess> process(
-      new CgroupsDevicesIsolatorProcess(
-          flags,
-          hierarchy.get()));
-
-  return new MesosIsolator(process);
-}
-
-
-Future<Nothing> CgroupsDevicesIsolatorProcess::recover(
-    const list<ContainerState>& states,
-    const hashset<ContainerID>& orphans)
-{
-  foreach (const ContainerState& state, states) {
-    const ContainerID& containerId = state.container_id();
-    const string cgroup = path::join(flags.cgroups_root, containerId.value());
-
-    Try<bool> exists = cgroups::exists(hierarchy, cgroup);
-    if (exists.isError()) {
-      foreachvalue (Info* info, infos) {
-        delete info;
-      }
-      infos.clear();
-      return Failure("Failed to check cgroup for container '" +
-                     stringify(containerId) + "'");
-    }
-
-    if (!exists.get()) {
-      // This may occur if the executor has exited and the isolator
-      // has destroyed the cgroup but the slave dies before noticing
-      // this. This will be detected when the containerizer tries to
-      // monitor the executor's pid.
-      VLOG(1) << "Couldn't find cgroup for container " << containerId;
-      continue;
-    }
-
-    infos[containerId] = new Info(containerId, cgroup);
-  }
-
-  // Remove orphan cgroups.
-  Try<vector<string>> cgroups = cgroups::get(hierarchy, flags.cgroups_root);
-  if (cgroups.isError()) {
-    foreachvalue (Info* info, infos) {
-      delete info;
-    }
-    infos.clear();
-    return Failure(cgroups.error());
-  }
-
-  foreach (const string& cgroup, cgroups.get()) {
-    // Ignore the slave cgroup (see the --agent_subsystems flag).
-    // TODO(idownes): Remove this when the cgroups layout is updated,
-    // see MESOS-1185.
-    if (cgroup == path::join(flags.cgroups_root, "slave")) {
-      continue;
-    }
-
-    ContainerID containerId;
-    containerId.set_value(Path(cgroup).basename());
-
-    if (infos.contains(containerId)) {
-      continue;
-    }
-
-    // Known orphan cgroups will be destroyed by the containerizer
-    // using the normal cleanup path. See MESOS-2367 for details.
-    if (orphans.contains(containerId)) {
-      infos[containerId] = new Info(containerId, cgroup);
-      continue;
-    }
-
-    LOG(INFO) << "Removing unknown orphaned cgroup '" << cgroup << "'";
-
-    // We don't wait on the destroy as we don't want to block recovery.
-    cgroups::destroy(hierarchy, cgroup, cgroups::DESTROY_TIMEOUT);
-  }
-
-  return Nothing();
-}
-
-
-Future<Option<ContainerLaunchInfo>> CgroupsDevicesIsolatorProcess::prepare(
-    const ContainerID& containerId,
-    const mesos::slave::ContainerConfig& containerConfig)
-{
-  if (infos.contains(containerId)) {
-    return Failure("Container has already been prepared");
-  }
-
-  // TODO(bmahler): Don't insert into 'infos' unless we create the
-  // cgroup successfully. It's safe for now because 'cleanup' gets
-  // called if we return a Failure, but cleanup will fail because the
-  // cgroup does not exist when cgroups::destroy is called.
-  Info* info = new Info(
-      containerId, path::join(flags.cgroups_root, containerId.value()));
-
-  infos[containerId] = info;
-
-  Try<bool> exists = cgroups::exists(hierarchy, info->cgroup);
-  if (exists.isError()) {
-    return Failure("Failed to prepare isolator: " + exists.error());
-  } else if (exists.get()) {
-    return Failure("Failed to prepare isolator: cgroup already exists");
-  }
-
-  Try<Nothing> create = cgroups::create(hierarchy, info->cgroup);
-  if (create.isError()) {
-    return Failure("Failed to prepare isolator: " + create.error());
-  }
-
-  // Chown the cgroup so the executor can create nested cgroups. Do
-  // not recurse so the control files are still owned by the slave
-  // user and thus cannot be changed by the executor.
-  if (containerConfig.has_user()) {
-    Try<Nothing> chown = os::chown(
-        containerConfig.user(),
-        path::join(hierarchy, info->cgroup),
-        false);
-    if (chown.isError()) {
-      return Failure("Failed to prepare isolator: " + chown.error());
-    }
-  }
-
-  // When a devices cgroup is first created, its whitelist inherits
-  // all devices from its parent's whitelist (i.e., "a *:* rwm" by
-  // default). In theory, we should be able to add and remove devices
-  // from the whitelist by writing to the respective `devices.allow`
-  // and `devices.deny` files associated with the cgroup. However, the
-  // semantics of the whitelist are such that writing to the deny file
-  // will only remove entries in the whitelist that are explicitly
-  // listed in there (i.e., denying "b 1:3 rwm" when the whitelist
-  // only contains "a *:* rwm" will not modify the whitelist because
-  // "b 1:3 rwm" is not explicitly listed). Although the whitelist
-  // doesn't change, access to the device is still denied as expected
-  // (there is just no way of querying the system to detect it).
-  // Because of this, we first deny access to all devices and
-  // selectively add some back in so we can control the entries in the
-  // whitelist explicitly.
-  cgroups::devices::Entry all;
-  all.selector.type = Entry::Selector::Type::ALL;
-  all.selector.major = None();
-  all.selector.minor = None();
-  all.access.read = true;
-  all.access.write = true;
-  all.access.mknod = true;
-
-  Try<Nothing> deny = cgroups::devices::deny(hierarchy, info->cgroup, all);
-
-  if (deny.isError()) {
-    return Failure("Failed to deny all devices: " + deny.error());
-  }
-
-  foreach (const char* _entry, DEFAULT_WHITELIST_ENTRIES) {
-    Try<cgroups::devices::Entry> entry =
-      cgroups::devices::Entry::parse(_entry);
-
-    CHECK_SOME(entry);
-
-    Try<Nothing> allow =
-      cgroups::devices::allow(hierarchy, info->cgroup, entry.get());
-
-    if (allow.isError()) {
-      return Failure("Failed to whitelist default device"
-                     " '" + stringify(entry.get()) + "': " + allow.error());
-    }
-  }
-
-  return None();
-}
-
-
-Future<Nothing> CgroupsDevicesIsolatorProcess::isolate(
-    const ContainerID& containerId,
-    pid_t pid)
-{
-  if (!infos.contains(containerId)) {
-    return Failure("Unknown container");
-  }
-
-  Info* info = CHECK_NOTNULL(infos[containerId]);
-
-  Try<Nothing> assign = cgroups::assign(
-      hierarchy, info->cgroup, pid);
-
-  if (assign.isError()) {
-    LOG(ERROR) << "Failed to assign container '" << info->containerId << "'"
-               << " to cgroup '" << path::join(hierarchy, info->cgroup) << "': "
-               << assign.error();
-
-    return Failure("Failed to isolate container: " + assign.error());
-  }
-
-  return Nothing();
-}
-
-
-Future<Nothing> CgroupsDevicesIsolatorProcess::cleanup(
-    const ContainerID& containerId)
-{
-  // Multiple calls may occur during test clean up.
-  if (!infos.contains(containerId)) {
-    VLOG(1) << "Ignoring cleanup request for unknown container " << containerId;
-
-    return Nothing();
-  }
-
-  Info* info = CHECK_NOTNULL(infos[containerId]);
-
-  return cgroups::destroy(hierarchy, info->cgroup, cgroups::DESTROY_TIMEOUT)
-    .onAny(defer(PID<CgroupsDevicesIsolatorProcess>(this),
-                 &CgroupsDevicesIsolatorProcess::_cleanup,
-                 containerId,
-                 lambda::_1));
-}
-
-
-Future<Nothing> CgroupsDevicesIsolatorProcess::_cleanup(
-    const ContainerID& containerId,
-    const Future<Nothing>& future)
-{
-  if (!infos.contains(containerId)) {
-    return Failure("Unknown container");
-  }
-
-  Info* info = CHECK_NOTNULL(infos[containerId]);
-
-  if (!future.isReady()) {
-    return Failure(
-        "Failed to clean up container " + stringify(containerId) + ": " +
-        (future.isFailed() ? future.failure() : "discarded"));
-  }
-
-  delete info;
-  infos.erase(containerId);
-
-  return Nothing();
-}
-
-} // namespace slave {
-} // namespace internal {
-} // namespace mesos {

http://git-wip-us.apache.org/repos/asf/mesos/blob/dfd3690b/src/slave/containerizer/mesos/isolators/cgroups/devices.hpp
----------------------------------------------------------------------
diff --git a/src/slave/containerizer/mesos/isolators/cgroups/devices.hpp b/src/slave/containerizer/mesos/isolators/cgroups/devices.hpp
deleted file mode 100644
index 7ad9644..0000000
--- a/src/slave/containerizer/mesos/isolators/cgroups/devices.hpp
+++ /dev/null
@@ -1,98 +0,0 @@
-// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements.  See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership.  The ASF licenses this file
-// to you under the Apache License, Version 2.0 (the
-// "License"); you may not use this file except in compliance
-// with the License.  You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#ifndef __CGROUPS_DEVICES_ISOLATOR_HPP__
-#define __CGROUPS_DEVICES_ISOLATOR_HPP__
-
-#include <list>
-#include <string>
-
-#include <process/future.hpp>
-
-#include <stout/hashmap.hpp>
-#include <stout/hashset.hpp>
-#include <stout/nothing.hpp>
-#include <stout/option.hpp>
-#include <stout/try.hpp>
-
-#include "linux/cgroups.hpp"
-
-#include "slave/flags.hpp"
-
-#include "slave/containerizer/mesos/isolator.hpp"
-
-namespace mesos {
-namespace internal {
-namespace slave {
-
-// This isolator uses the cgroups devices subsystem to
-// restrict access to devices in `/dev`. A small set of
-// default devices are whitelisted upon container creation,
-// and access to all other devices is restricted. It is
-// assumed that other isolators will be used to allow / deny
-// access to devices outside the default whitelist.
-class CgroupsDevicesIsolatorProcess : public MesosIsolatorProcess
-{
-public:
-  static Try<mesos::slave::Isolator*> create(const Flags& flags);
-
-  virtual process::Future<Nothing> recover(
-      const std::list<mesos::slave::ContainerState>& states,
-      const hashset<ContainerID>& orphans);
-
-  virtual process::Future<Option<mesos::slave::ContainerLaunchInfo>> prepare(
-      const ContainerID& containerId,
-      const mesos::slave::ContainerConfig& containerConfig);
-
-  virtual process::Future<Nothing> isolate(
-      const ContainerID& containerId,
-      pid_t pid);
-
-  virtual process::Future<Nothing> cleanup(
-      const ContainerID& containerId);
-
-private:
-  struct Info
-  {
-    Info(const ContainerID& _containerId, const std::string& _cgroup)
-      : containerId(_containerId), cgroup(_cgroup) {}
-
-    const ContainerID containerId;
-    const std::string cgroup;
-  };
-
-  CgroupsDevicesIsolatorProcess(
-      const Flags& _flags,
-      const std::string& hierarchy);
-
-  process::Future<Nothing> _cleanup(
-      const ContainerID& containerId,
-      const process::Future<Nothing>& future);
-
-  const Flags flags;
-
-  // The path to the cgroups subsystem hierarchy root.
-  const std::string hierarchy;
-
-  // TODO(bmahler): Use Owned<Info>.
-  hashmap<ContainerID, Info*> infos;
-};
-
-} // namespace slave {
-} // namespace internal {
-} // namespace mesos {
-
-#endif // __CGROUPS_DEVICES_ISOLATOR_HPP__


[09/17] mesos git commit: Removed CgroupsPerfEventIsolatorProcess.

Posted by ji...@apache.org.
Removed CgroupsPerfEventIsolatorProcess.

Review: https://reviews.apache.org/r/50751/


Project: http://git-wip-us.apache.org/repos/asf/mesos/repo
Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/edf824b4
Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/edf824b4
Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/edf824b4

Branch: refs/heads/master
Commit: edf824b4d95d44c33c7c381718594b01d0357712
Parents: 34bcae4
Author: haosdent huang <ha...@gmail.com>
Authored: Mon Sep 12 16:34:51 2016 -0700
Committer: Jie Yu <yu...@gmail.com>
Committed: Tue Sep 13 10:52:01 2016 -0700

----------------------------------------------------------------------
 src/CMakeLists.txt                              |   1 -
 src/Makefile.am                                 |   2 -
 src/slave/containerizer/mesos/containerizer.cpp |   1 -
 .../mesos/isolators/cgroups/perf_event.cpp      | 415 -------------------
 .../mesos/isolators/cgroups/perf_event.hpp      | 118 ------
 src/tests/containerizer/isolator_tests.cpp      | 232 -----------
 6 files changed, 769 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/edf824b4/src/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 7caa466..42c52b6 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -159,7 +159,6 @@ set(LINUX_SRC
   slave/containerizer/mesos/linux_launcher.cpp
   slave/containerizer/mesos/isolators/appc/runtime.cpp
   slave/containerizer/mesos/isolators/cgroups/cgroups.cpp
-  slave/containerizer/mesos/isolators/cgroups/perf_event.cpp
   slave/containerizer/mesos/isolators/cgroups/subsystem.cpp
   slave/containerizer/mesos/isolators/cgroups/subsystems/cpu.cpp
   slave/containerizer/mesos/isolators/cgroups/subsystems/cpuacct.cpp

http://git-wip-us.apache.org/repos/asf/mesos/blob/edf824b4/src/Makefile.am
----------------------------------------------------------------------
diff --git a/src/Makefile.am b/src/Makefile.am
index d4b90f1..e789994 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1025,7 +1025,6 @@ MESOS_LINUX_FILES =									\
   slave/containerizer/mesos/linux_launcher.cpp						\
   slave/containerizer/mesos/isolators/appc/runtime.cpp					\
   slave/containerizer/mesos/isolators/cgroups/cgroups.cpp				\
-  slave/containerizer/mesos/isolators/cgroups/perf_event.cpp				\
   slave/containerizer/mesos/isolators/cgroups/subsystem.cpp				\
   slave/containerizer/mesos/isolators/cgroups/subsystems/cpu.cpp			\
   slave/containerizer/mesos/isolators/cgroups/subsystems/cpuacct.cpp			\
@@ -1062,7 +1061,6 @@ MESOS_LINUX_FILES +=									\
   slave/containerizer/mesos/isolators/appc/runtime.hpp					\
   slave/containerizer/mesos/isolators/cgroups/cgroups.hpp				\
   slave/containerizer/mesos/isolators/cgroups/constants.hpp				\
-  slave/containerizer/mesos/isolators/cgroups/perf_event.hpp				\
   slave/containerizer/mesos/isolators/cgroups/subsystem.hpp				\
   slave/containerizer/mesos/isolators/cgroups/subsystems/cpu.hpp			\
   slave/containerizer/mesos/isolators/cgroups/subsystems/cpuacct.hpp			\

http://git-wip-us.apache.org/repos/asf/mesos/blob/edf824b4/src/slave/containerizer/mesos/containerizer.cpp
----------------------------------------------------------------------
diff --git a/src/slave/containerizer/mesos/containerizer.cpp b/src/slave/containerizer/mesos/containerizer.cpp
index bbf5d53..dc18e4e 100644
--- a/src/slave/containerizer/mesos/containerizer.cpp
+++ b/src/slave/containerizer/mesos/containerizer.cpp
@@ -73,7 +73,6 @@
 
 #ifdef __linux__
 #include "slave/containerizer/mesos/isolators/cgroups/cgroups.hpp"
-#include "slave/containerizer/mesos/isolators/cgroups/perf_event.hpp"
 #endif // __linux__
 
 #ifdef __linux__

http://git-wip-us.apache.org/repos/asf/mesos/blob/edf824b4/src/slave/containerizer/mesos/isolators/cgroups/perf_event.cpp
----------------------------------------------------------------------
diff --git a/src/slave/containerizer/mesos/isolators/cgroups/perf_event.cpp b/src/slave/containerizer/mesos/isolators/cgroups/perf_event.cpp
deleted file mode 100644
index 31f3538..0000000
--- a/src/slave/containerizer/mesos/isolators/cgroups/perf_event.cpp
+++ /dev/null
@@ -1,415 +0,0 @@
-// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements.  See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership.  The ASF licenses this file
-// to you under the Apache License, Version 2.0 (the
-// "License"); you may not use this file except in compliance
-// with the License.  You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include <stdint.h>
-
-#include <vector>
-
-#include <google/protobuf/descriptor.h>
-#include <google/protobuf/message.h>
-
-#include <process/collect.hpp>
-#include <process/defer.hpp>
-#include <process/delay.hpp>
-#include <process/io.hpp>
-#include <process/pid.hpp>
-#include <process/reap.hpp>
-#include <process/subprocess.hpp>
-
-#include <stout/bytes.hpp>
-#include <stout/check.hpp>
-#include <stout/error.hpp>
-#include <stout/foreach.hpp>
-#include <stout/hashset.hpp>
-#include <stout/lambda.hpp>
-#include <stout/os.hpp>
-#include <stout/path.hpp>
-#include <stout/stringify.hpp>
-#include <stout/try.hpp>
-
-#include "linux/cgroups.hpp"
-#include "linux/perf.hpp"
-
-#include "slave/containerizer/mesos/isolators/cgroups/perf_event.hpp"
-
-using mesos::slave::ContainerConfig;
-using mesos::slave::ContainerLaunchInfo;
-using mesos::slave::ContainerLimitation;
-using mesos::slave::ContainerState;
-using mesos::slave::Isolator;
-
-using std::list;
-using std::set;
-using std::string;
-using std::vector;
-
-using process::Clock;
-using process::Failure;
-using process::Future;
-using process::PID;
-using process::Time;
-
-namespace mesos {
-namespace internal {
-namespace slave {
-
-Try<Isolator*> CgroupsPerfEventIsolatorProcess::create(const Flags& flags)
-{
-  LOG(INFO) << "Creating PerfEvent isolator";
-
-  if (!perf::supported()) {
-    return Error("Perf is not supported");
-  }
-
-  if (flags.perf_duration > flags.perf_interval) {
-    return Error("Sampling perf for duration (" +
-                 stringify(flags.perf_duration) +
-                 ") > interval (" +
-                 stringify(flags.perf_interval) +
-                 ") is not supported.");
-  }
-
-  if (!flags.perf_events.isSome()) {
-    return Error("No perf events specified");
-  }
-
-  set<string> events;
-  foreach (const string& event,
-           strings::tokenize(flags.perf_events.get(), ",")) {
-    events.insert(event);
-  }
-
-  if (!perf::valid(events)) {
-    return Error("Failed to create PerfEvent isolator, invalid events: " +
-                 stringify(events));
-  }
-
-  Try<string> hierarchy = cgroups::prepare(
-      flags.cgroups_hierarchy,
-      "perf_event",
-      flags.cgroups_root);
-
-  if (hierarchy.isError()) {
-    return Error("Failed to create perf_event cgroup: " + hierarchy.error());
-  }
-
-  LOG(INFO) << "PerfEvent isolator will profile for " << flags.perf_duration
-            << " every " << flags.perf_interval
-            << " for events: " << stringify(events);
-
-  process::Owned<MesosIsolatorProcess> process(
-      new CgroupsPerfEventIsolatorProcess(flags, hierarchy.get(), events));
-
-  return new MesosIsolator(process);
-}
-
-
-CgroupsPerfEventIsolatorProcess::~CgroupsPerfEventIsolatorProcess() {}
-
-
-void CgroupsPerfEventIsolatorProcess::initialize()
-{
-  // Start sampling.
-  sample();
-}
-
-
-Future<Nothing> CgroupsPerfEventIsolatorProcess::recover(
-    const list<ContainerState>& states,
-    const hashset<ContainerID>& orphans)
-{
-  foreach (const ContainerState& state, states) {
-    const ContainerID& containerId = state.container_id();
-    const string cgroup = path::join(flags.cgroups_root, containerId.value());
-
-    Try<bool> exists = cgroups::exists(hierarchy, cgroup);
-    if (exists.isError()) {
-      foreachvalue (Info* info, infos) {
-        delete info;
-      }
-
-      infos.clear();
-      return Failure("Failed to check cgroup " + cgroup +
-                     " for container '" + stringify(containerId) + "'");
-    }
-
-    if (!exists.get()) {
-      // This may occur if the executor is exiting and the isolator has
-      // destroyed the cgroup but the slave dies before noticing this. This
-      // will be detected when the containerizer tries to monitor the
-      // executor's pid.
-      // NOTE: This could also occur if this isolator is now enabled for a
-      // container that was started without this isolator. For this
-      // particular isolator it is acceptable to continue running this
-      // container without a perf_event cgroup because we don't ever
-      // query it and the destroy will succeed immediately.
-      VLOG(1) << "Couldn't find perf event cgroup for container " << containerId
-              << ", perf statistics will not be available";
-      continue;
-    }
-
-    infos[containerId] = new Info(containerId, cgroup);
-  }
-
-  // Remove orphan cgroups.
-  Try<vector<string>> cgroups = cgroups::get(hierarchy, flags.cgroups_root);
-  if (cgroups.isError()) {
-    foreachvalue (Info* info, infos) {
-      delete info;
-    }
-    infos.clear();
-    return Failure(cgroups.error());
-  }
-
-  foreach (const string& cgroup, cgroups.get()) {
-    // Ignore the slave cgroup (see the --agent_subsystems flag).
-    // TODO(idownes): Remove this when the cgroups layout is updated,
-    // see MESOS-1185.
-    if (cgroup == path::join(flags.cgroups_root, "slave")) {
-      continue;
-    }
-
-    ContainerID containerId;
-    containerId.set_value(Path(cgroup).basename());
-
-    if (infos.contains(containerId)) {
-      continue;
-    }
-
-    // Known orphan cgroups will be destroyed by the containerizer
-    // using the normal cleanup path. See details in MESOS-2367.
-    if (orphans.contains(containerId)) {
-      infos[containerId] = new Info(containerId, cgroup);
-      continue;
-    }
-
-    LOG(INFO) << "Removing unknown orphaned cgroup '" << cgroup << "'";
-
-    // We don't wait on the destroy as we don't want to block recovery.
-    cgroups::destroy(hierarchy, cgroup, cgroups::DESTROY_TIMEOUT);
-  }
-
-  return Nothing();
-}
-
-
-Future<Option<ContainerLaunchInfo>> CgroupsPerfEventIsolatorProcess::prepare(
-    const ContainerID& containerId,
-    const ContainerConfig& containerConfig)
-{
-  if (infos.contains(containerId)) {
-    return Failure("Container has already been prepared");
-  }
-
-  LOG(INFO) << "Preparing perf event cgroup for " << containerId;
-
-  Info* info = new Info(
-      containerId,
-      path::join(flags.cgroups_root, containerId.value()));
-
-  infos[containerId] = CHECK_NOTNULL(info);
-
-  // Create a cgroup for this container.
-  Try<bool> exists = cgroups::exists(hierarchy, info->cgroup);
-
-  if (exists.isError()) {
-    return Failure("Failed to prepare isolator: " + exists.error());
-  }
-
-  if (exists.get()) {
-    return Failure("Failed to prepare isolator: cgroup already exists");
-  }
-
-  if (!exists.get()) {
-    Try<Nothing> create = cgroups::create(hierarchy, info->cgroup);
-    if (create.isError()) {
-      return Failure("Failed to prepare isolator: " + create.error());
-    }
-  }
-
-  // Chown the cgroup so the executor can create nested cgroups. Do
-  // not recurse so the control files are still owned by the slave
-  // user and thus cannot be changed by the executor.
-  if (containerConfig.has_user()) {
-    Try<Nothing> chown = os::chown(
-        containerConfig.user(),
-        path::join(hierarchy, info->cgroup),
-        false);
-    if (chown.isError()) {
-      return Failure("Failed to prepare isolator: " + chown.error());
-    }
-  }
-
-  return None();
-}
-
-
-Future<Nothing> CgroupsPerfEventIsolatorProcess::isolate(
-    const ContainerID& containerId,
-    pid_t pid)
-{
-  if (!infos.contains(containerId)) {
-    return Failure("Unknown container");
-  }
-
-  Info* info = CHECK_NOTNULL(infos[containerId]);
-
-  Try<Nothing> assign = cgroups::assign(hierarchy, info->cgroup, pid);
-  if (assign.isError()) {
-    return Failure("Failed to assign container '" +
-                   stringify(info->containerId) + "' to its own cgroup '" +
-                   path::join(hierarchy, info->cgroup) +
-                   "' : " + assign.error());
-  }
-
-  return Nothing();
-}
-
-
-Future<ResourceStatistics> CgroupsPerfEventIsolatorProcess::usage(
-    const ContainerID& containerId)
-{
-  if (!infos.contains(containerId)) {
-    // Return an empty ResourceStatistics, i.e., without
-    // PerfStatistics, if we don't know about this container.
-    return ResourceStatistics();
-  }
-
-  CHECK_NOTNULL(infos[containerId]);
-
-  ResourceStatistics statistics;
-  statistics.mutable_perf()->CopyFrom(infos[containerId]->statistics);
-
-  return statistics;
-}
-
-
-Future<Nothing> CgroupsPerfEventIsolatorProcess::cleanup(
-    const ContainerID& containerId)
-{
-  // Tolerate clean up attempts for unknown containers which may arise from
-  // repeated clean up attempts (during test cleanup).
-  if (!infos.contains(containerId)) {
-    VLOG(1) << "Ignoring cleanup request for unknown container: "
-            << containerId;
-    return Nothing();
-  }
-
-  Info* info = CHECK_NOTNULL(infos[containerId]);
-
-  info->destroying = true;
-
-  return cgroups::destroy(hierarchy, info->cgroup)
-    .then(defer(PID<CgroupsPerfEventIsolatorProcess>(this),
-                &CgroupsPerfEventIsolatorProcess::_cleanup,
-                containerId));
-}
-
-
-Future<Nothing> CgroupsPerfEventIsolatorProcess::_cleanup(
-    const ContainerID& containerId)
-{
-  if (!infos.contains(containerId)) {
-    return Nothing();
-  }
-
-  delete infos[containerId];
-  infos.erase(containerId);
-
-  return Nothing();
-}
-
-
-Future<hashmap<string, PerfStatistics>> discardSample(
-    Future<hashmap<string, PerfStatistics>> future,
-    const Duration& duration,
-    const Duration& timeout)
-{
-  LOG(ERROR) << "Perf sample of " << stringify(duration)
-             << " failed to complete within " << stringify(timeout)
-             << "; sampling will be halted";
-
-  future.discard();
-
-  return future;
-}
-
-
-void CgroupsPerfEventIsolatorProcess::sample()
-{
-  // Collect a perf sample for all cgroups that are not being
-  // destroyed. Since destroyal is asynchronous, 'perf stat' may
-  // fail if the cgroup is destroyed before running perf.
-  set<string> cgroups;
-
-  foreachvalue (Info* info, infos) {
-    CHECK_NOTNULL(info);
-
-    if (!info->destroying) {
-      cgroups.insert(info->cgroup);
-    }
-  }
-
-  // The discard timeout includes an allowance of twice the
-  // reaper interval to ensure we see the perf process exit.
-  Duration timeout = flags.perf_duration + process::MAX_REAP_INTERVAL() * 2;
-
-  perf::sample(events, cgroups, flags.perf_duration)
-    .after(timeout,
-           lambda::bind(&discardSample,
-                        lambda::_1,
-                        flags.perf_duration,
-                        timeout))
-    .onAny(defer(PID<CgroupsPerfEventIsolatorProcess>(this),
-                 &CgroupsPerfEventIsolatorProcess::_sample,
-                 Clock::now() + flags.perf_interval,
-                 lambda::_1));
-}
-
-
-void CgroupsPerfEventIsolatorProcess::_sample(
-    const Time& next,
-    const Future<hashmap<string, PerfStatistics>>& statistics)
-{
-  if (!statistics.isReady()) {
-    // In case the failure is transient or this is due to a timeout,
-    // we continue sampling. Note that since sampling is done on an
-    // interval, it should be ok if this is a non-transient failure.
-    LOG(ERROR) << "Failed to get perf sample: "
-               << (statistics.isFailed()
-                   ? statistics.failure()
-                   : "discarded due to timeout");
-  } else {
-    // Store the latest statistics, note that cgroups added in the
-    // interim will be picked up by the next sample.
-    foreachvalue (Info* info, infos) {
-      CHECK_NOTNULL(info);
-
-      if (statistics->contains(info->cgroup)) {
-        info->statistics = statistics->get(info->cgroup).get();
-      }
-    }
-  }
-
-  // Schedule sample for the next time.
-  delay(next - Clock::now(),
-        PID<CgroupsPerfEventIsolatorProcess>(this),
-        &CgroupsPerfEventIsolatorProcess::sample);
-}
-
-} // namespace slave {
-} // namespace internal {
-} // namespace mesos {

http://git-wip-us.apache.org/repos/asf/mesos/blob/edf824b4/src/slave/containerizer/mesos/isolators/cgroups/perf_event.hpp
----------------------------------------------------------------------
diff --git a/src/slave/containerizer/mesos/isolators/cgroups/perf_event.hpp b/src/slave/containerizer/mesos/isolators/cgroups/perf_event.hpp
deleted file mode 100644
index 4abde12..0000000
--- a/src/slave/containerizer/mesos/isolators/cgroups/perf_event.hpp
+++ /dev/null
@@ -1,118 +0,0 @@
-// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements.  See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership.  The ASF licenses this file
-// to you under the Apache License, Version 2.0 (the
-// "License"); you may not use this file except in compliance
-// with the License.  You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#ifndef __PERF_EVENT_ISOLATOR_HPP__
-#define __PERF_EVENT_ISOLATOR_HPP__
-
-#include <set>
-
-#include <process/id.hpp>
-#include <process/time.hpp>
-
-#include <stout/hashmap.hpp>
-#include <stout/nothing.hpp>
-
-#include "slave/flags.hpp"
-
-#include "slave/containerizer/mesos/isolator.hpp"
-
-namespace mesos {
-namespace internal {
-namespace slave {
-
-class CgroupsPerfEventIsolatorProcess : public MesosIsolatorProcess
-{
-public:
-  static Try<mesos::slave::Isolator*> create(const Flags& flags);
-
-  virtual ~CgroupsPerfEventIsolatorProcess();
-
-  virtual process::Future<Nothing> recover(
-      const std::list<mesos::slave::ContainerState>& states,
-      const hashset<ContainerID>& orphans);
-
-  virtual process::Future<Option<mesos::slave::ContainerLaunchInfo>> prepare(
-      const ContainerID& containerId,
-      const mesos::slave::ContainerConfig& containerConfig);
-
-  virtual process::Future<Nothing> isolate(
-      const ContainerID& containerId,
-      pid_t pid);
-
-  virtual process::Future<ResourceStatistics> usage(
-      const ContainerID& containerId);
-
-  virtual process::Future<Nothing> cleanup(
-      const ContainerID& containerId);
-
-protected:
-  virtual void initialize();
-
-private:
-  CgroupsPerfEventIsolatorProcess(
-      const Flags& _flags,
-      const std::string& _hierarchy,
-      const std::set<std::string>& _events)
-    : ProcessBase(process::ID::generate("cgroups-perf-event-isolator")),
-      flags(_flags),
-      hierarchy(_hierarchy),
-      events(_events) {}
-
-  void sample();
-
-  void _sample(
-      const process::Time& next,
-      const process::Future<hashmap<std::string, PerfStatistics>>& statistics);
-
-  virtual process::Future<Nothing> _cleanup(const ContainerID& containerId);
-
-  struct Info
-  {
-    Info(const ContainerID& _containerId, const std::string& _cgroup)
-      : containerId(_containerId), cgroup(_cgroup), destroying(false)
-    {
-      // Ensure the initial statistics include the required fields.
-      // Note the duration is set to zero to indicate no sampling has
-      // taken place. This empty sample will be returned from usage()
-      // until the first true sample is obtained.
-      statistics.set_timestamp(process::Clock::now().secs());
-      statistics.set_duration(Seconds(0).secs());
-    }
-
-    const ContainerID containerId;
-    const std::string cgroup;
-    PerfStatistics statistics;
-    // Mark a container when we start destruction so we stop sampling it.
-    bool destroying;
-  };
-
-  const Flags flags;
-
-  // The path to the cgroups subsystem hierarchy root.
-  const std::string hierarchy;
-
-  // Set of events to sample.
-  std::set<std::string> events;
-
-  // TODO(jieyu): Use Owned<Info>.
-  hashmap<ContainerID, Info*> infos;
-};
-
-} // namespace slave {
-} // namespace internal {
-} // namespace mesos {
-
-#endif // __PERF_EVENT_ISOLATOR_HPP__

http://git-wip-us.apache.org/repos/asf/mesos/blob/edf824b4/src/tests/containerizer/isolator_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/containerizer/isolator_tests.cpp b/src/tests/containerizer/isolator_tests.cpp
index 85a13d7..9bb1e69 100644
--- a/src/tests/containerizer/isolator_tests.cpp
+++ b/src/tests/containerizer/isolator_tests.cpp
@@ -52,7 +52,6 @@
 #include "slave/slave.hpp"
 
 #ifdef __linux__
-#include "slave/containerizer/mesos/isolators/cgroups/perf_event.hpp"
 #include "slave/containerizer/mesos/isolators/filesystem/shared.hpp"
 #endif // __linux__
 #include "slave/containerizer/mesos/isolators/posix.hpp"
@@ -74,7 +73,6 @@ using namespace process;
 
 using mesos::internal::master::Master;
 #ifdef __linux__
-using mesos::internal::slave::CgroupsPerfEventIsolatorProcess;
 using mesos::internal::slave::Fetcher;
 using mesos::internal::slave::LinuxLauncher;
 using mesos::internal::slave::SharedFilesystemIsolatorProcess;
@@ -101,85 +99,6 @@ namespace internal {
 namespace tests {
 
 #ifdef __linux__
-class PerfEventIsolatorTest : public MesosTest {};
-
-
-TEST_F(PerfEventIsolatorTest, ROOT_CGROUPS_PERF_Sample)
-{
-  slave::Flags flags;
-
-  flags.perf_events = "cycles,task-clock";
-  flags.perf_duration = Milliseconds(250);
-  flags.perf_interval = Milliseconds(500);
-
-  Try<Isolator*> _isolator = CgroupsPerfEventIsolatorProcess::create(flags);
-  ASSERT_SOME(_isolator);
-  Owned<Isolator> isolator(_isolator.get());
-
-  ExecutorInfo executorInfo;
-
-  ContainerID containerId;
-  containerId.set_value(UUID::random().toString());
-
-  // Use a relative temporary directory so it gets cleaned up
-  // automatically with the test.
-  Try<string> dir = os::mkdtemp(path::join(os::getcwd(), "XXXXXX"));
-  ASSERT_SOME(dir);
-
-  ContainerConfig containerConfig;
-  containerConfig.mutable_executor_info()->CopyFrom(executorInfo);
-  containerConfig.set_directory(dir.get());
-
-  AWAIT_READY(isolator->prepare(
-      containerId,
-      containerConfig));
-
-  // This first sample is likely to be empty because perf hasn't
-  // completed yet but we should still have the required fields.
-  Future<ResourceStatistics> statistics1 = isolator->usage(containerId);
-  AWAIT_READY(statistics1);
-  ASSERT_TRUE(statistics1.get().has_perf());
-  EXPECT_TRUE(statistics1.get().perf().has_timestamp());
-  EXPECT_TRUE(statistics1.get().perf().has_duration());
-
-  // Wait until we get the next sample. We use a generous timeout of
-  // two seconds because we currently have a one second reap interval;
-  // when running perf with perf_duration of 250ms we won't notice the
-  // exit for up to one second.
-  ResourceStatistics statistics2;
-  Duration waited = Duration::zero();
-  do {
-    Future<ResourceStatistics> statistics = isolator->usage(containerId);
-    AWAIT_READY(statistics);
-
-    statistics2 = statistics.get();
-
-    ASSERT_TRUE(statistics2.has_perf());
-
-    if (statistics1.get().perf().timestamp() !=
-        statistics2.perf().timestamp()) {
-      break;
-    }
-
-    os::sleep(Milliseconds(250));
-    waited += Milliseconds(250);
-  } while (waited < Seconds(2));
-
-  sleep(2);
-
-  EXPECT_NE(statistics1.get().perf().timestamp(),
-            statistics2.perf().timestamp());
-
-  EXPECT_TRUE(statistics2.perf().has_cycles());
-  EXPECT_LE(0u, statistics2.perf().cycles());
-
-  EXPECT_TRUE(statistics2.perf().has_task_clock());
-  EXPECT_LE(0.0, statistics2.perf().task_clock());
-
-  AWAIT_READY(isolator->cleanup(containerId));
-}
-
-
 class SharedFilesystemIsolatorTest : public MesosTest {};
 
 
@@ -444,157 +363,6 @@ TEST_F(NamespacesPidIsolatorTest, ROOT_PidNamespace)
 
   EXPECT_EQ("sh", strings::trim(init.get()));
 }
-
-
-// Username for the unprivileged user that will be created to test
-// unprivileged cgroup creation. It will be removed after the tests.
-// It is presumed this user does not normally exist.
-const string UNPRIVILEGED_USERNAME = "mesos.test.unprivileged.user";
-
-
-template <typename T>
-class UserCgroupIsolatorTest
-  : public ContainerizerTest<slave::MesosContainerizer>
-{
-public:
-  static void SetUpTestCase()
-  {
-    ContainerizerTest<slave::MesosContainerizer>::SetUpTestCase();
-
-    // Remove the user in case it wasn't cleaned up from a previous
-    // test.
-    os::system("userdel -r " + UNPRIVILEGED_USERNAME + " > /dev/null");
-
-    ASSERT_EQ(0, os::system("useradd " + UNPRIVILEGED_USERNAME));
-  }
-
-
-  static void TearDownTestCase()
-  {
-    ContainerizerTest<slave::MesosContainerizer>::TearDownTestCase();
-
-    ASSERT_EQ(0, os::system("userdel -r " + UNPRIVILEGED_USERNAME));
-  }
-};
-
-
-// Test all isolators that use cgroups.
-typedef ::testing::Types<CgroupsPerfEventIsolatorProcess> CgroupsIsolatorTypes;
-
-
-TYPED_TEST_CASE(UserCgroupIsolatorTest, CgroupsIsolatorTypes);
-
-
-TYPED_TEST(UserCgroupIsolatorTest, ROOT_CGROUPS_PERF_UserCgroup)
-{
-  slave::Flags flags = UserCgroupIsolatorTest<TypeParam>::CreateSlaveFlags();
-  flags.perf_events = "cpu-cycles"; // Needed for CgroupsPerfEventIsolator.
-
-  Try<Isolator*> _isolator = TypeParam::create(flags);
-  ASSERT_SOME(_isolator);
-  Owned<Isolator> isolator(_isolator.get());
-
-  ExecutorInfo executorInfo;
-  executorInfo.mutable_resources()->CopyFrom(
-      Resources::parse("mem:1024;cpus:1").get()); // For cpu/mem isolators.
-
-  ContainerID containerId;
-  containerId.set_value(UUID::random().toString());
-
-  ContainerConfig containerConfig;
-  containerConfig.mutable_executor_info()->CopyFrom(executorInfo);
-  containerConfig.set_directory(os::getcwd());
-  containerConfig.set_user(UNPRIVILEGED_USERNAME);
-
-  AWAIT_READY(isolator->prepare(
-      containerId,
-      containerConfig));
-
-  // Isolators don't provide a way to determine the cgroups they use
-  // so we'll inspect the cgroups for an isolated dummy process.
-  pid_t pid = fork();
-  if (pid == 0) {
-    // Child just sleeps.
-    ::sleep(100);
-
-    ABORT("Child process should not reach here");
-  }
-  ASSERT_GT(pid, 0);
-
-  AWAIT_READY(isolator->isolate(containerId, pid));
-
-  // Get the container's cgroups from /proc/$PID/cgroup. We're only
-  // interested in the cgroups that this isolator has created which we
-  // can do explicitly by selecting those that have the path that
-  // corresponds to the 'cgroups_root' slave flag. For example:
-  //
-  //   $ cat /proc/pid/cgroup
-  //   6:blkio:/
-  //   5:perf_event:/
-  //   4:memory:/mesos/b7410ed8-c85b-445e-b50e-3a1698d0e18c
-  //   3:freezer:/
-  //   2:cpuacct:/
-  //   1:cpu:/
-  //
-  // Our 'grep' will only select the 'memory' line and then 'awk' will
-  // output 'memory/mesos/b7410ed8-c85b-445e-b50e-3a1698d0e18c'.
-  Try<string> grepOut = os::shell(
-      "grep '" + path::join("/", flags.cgroups_root) + "' /proc/" +
-       stringify(pid) + "/cgroup | awk -F ':' '{print $2$3}'");
-
-  ASSERT_SOME(grepOut);
-
-  // Kill the dummy child process.
-  ::kill(pid, SIGKILL);
-  int exitStatus;
-  EXPECT_NE(-1, ::waitpid(pid, &exitStatus, 0));
-
-  vector<string> cgroups = strings::tokenize(grepOut.get(), "\n");
-  ASSERT_FALSE(cgroups.empty());
-
-  foreach (string cgroup, cgroups) {
-    if (!os::exists(path::join(flags.cgroups_hierarchy, cgroup)) &&
-        strings::startsWith(cgroup, "cpuacct,cpu")) {
-      // An existing bug in CentOS 7.x causes 'cpuacct,cpu' cgroup to
-      // be under 'cpu,cpuacct'. Actively detect this here to
-      // work around this problem.
-      vector<string> parts = strings::split(cgroup, "/");
-      parts[0] = "cpu,cpuacct";
-      cgroup = strings::join("/", parts);
-    }
-
-    // Check the user cannot manipulate the container's cgroup control
-    // files.
-    EXPECT_NE(0, os::system(
-          "su - " + UNPRIVILEGED_USERNAME +
-          " -c 'echo $$ >" +
-          path::join(flags.cgroups_hierarchy, cgroup, "cgroup.procs") +
-          "'"));
-
-    // Check the user can create a cgroup under the container's
-    // cgroup.
-    string userCgroup = path::join(cgroup, "user");
-
-    EXPECT_EQ(0, os::system(
-          "su - " +
-          UNPRIVILEGED_USERNAME +
-          " -c 'mkdir " +
-          path::join(flags.cgroups_hierarchy, userCgroup) +
-          "'"));
-
-    // Check the user can manipulate control files in the created
-    // cgroup.
-    EXPECT_EQ(0, os::system(
-          "su - " +
-          UNPRIVILEGED_USERNAME +
-          " -c 'echo $$ >" +
-          path::join(flags.cgroups_hierarchy, userCgroup, "cgroup.procs") +
-          "'"));
-  }
-
-  // Clean up the container. This will also remove the nested cgroups.
-  AWAIT_READY(isolator->cleanup(containerId));
-}
 #endif // __linux__
 
 } // namespace tests {


[14/17] mesos git commit: Support changing the cgroup owner for command tasks that has rootfs.

Posted by ji...@apache.org.
Support changing the cgroup owner for command tasks that has rootfs.

For command tasks that have rootfs defined, the command executor will
be running as root. However, the task might want to manipulate
cgroups. This patch allows that.

Review: https://reviews.apache.org/r/51835


Project: http://git-wip-us.apache.org/repos/asf/mesos/repo
Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/0c3a227a
Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/0c3a227a
Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/0c3a227a

Branch: refs/heads/master
Commit: 0c3a227a5b71e9b8d4578fecedd819b76fbaca21
Parents: feb5114
Author: Jie Yu <yu...@gmail.com>
Authored: Mon Sep 12 21:33:34 2016 -0700
Committer: Jie Yu <yu...@gmail.com>
Committed: Tue Sep 13 10:52:01 2016 -0700

----------------------------------------------------------------------
 .../mesos/isolators/cgroups/cgroups.cpp         | 45 ++++++++++++++++----
 1 file changed, 36 insertions(+), 9 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/0c3a227a/src/slave/containerizer/mesos/isolators/cgroups/cgroups.cpp
----------------------------------------------------------------------
diff --git a/src/slave/containerizer/mesos/isolators/cgroups/cgroups.cpp b/src/slave/containerizer/mesos/isolators/cgroups/cgroups.cpp
index 8b6dfde..e87d055 100644
--- a/src/slave/containerizer/mesos/isolators/cgroups/cgroups.cpp
+++ b/src/slave/containerizer/mesos/isolators/cgroups/cgroups.cpp
@@ -404,16 +404,43 @@ Future<Option<ContainerLaunchInfo>> CgroupsIsolatorProcess::prepare(
     // TODO(haosdent): Multiple tasks under the same user can change
     // cgroups settings for each other. A better solution is using
     // cgroups namespaces and user namespaces to achieve the goal.
+    //
+    // NOTE: We only need to handle the case where 'flags.switch_user'
+    // is true (i.e., 'containerConfig.has_user() == true'). If
+    // 'flags.switch_user' is false, the cgroup will be owned by root
+    // anyway since cgroups isolator requires root permission.
     if (containerConfig.has_user()) {
-      Try<Nothing> chown = os::chown(
-          containerConfig.user(),
-          path,
-          false);
-
-      if (chown.isError()) {
-        return Failure(
-            "Failed to chown the cgroup at "
-            "'" + path + "': " + chown.error());
+      Option<string> user;
+      if (containerConfig.has_task_info() && containerConfig.has_rootfs()) {
+        // Command task that has a rootfs. In this case, the executor
+        // will be running under root, and the command task itself
+        // might be running under a different user.
+        //
+        // TODO(jieyu): The caveat here is that if the 'user' in
+        // task's command is not set, we don't know exactly what user
+        // the task will be running as because we don't know the
+        // framework user. We do not support this case right now.
+        if (containerConfig.task_info().command().has_user()) {
+          user = containerConfig.task_info().command().user();
+        }
+      } else {
+        user = containerConfig.user();
+      }
+
+      if (user.isSome()) {
+        VLOG(1) << "Chown the cgroup at '" << path << "' to user "
+                << "'" << user.get() << "' for container " << containerId;
+
+        Try<Nothing> chown = os::chown(
+            user.get(),
+            path,
+            false);
+
+        if (chown.isError()) {
+          return Failure(
+              "Failed to chown the cgroup at '" + path + "' "
+              "to user '" + user.get() + "': " + chown.error());
+        }
       }
     }
   }


[06/17] mesos git commit: Removed CgroupsMemIsolatorProcess.

Posted by ji...@apache.org.
Removed CgroupsMemIsolatorProcess.

Review: https://reviews.apache.org/r/50748/


Project: http://git-wip-us.apache.org/repos/asf/mesos/repo
Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/f75d9494
Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/f75d9494
Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/f75d9494

Branch: refs/heads/master
Commit: f75d94947aaf10643293a09ebdf627ff8566de74
Parents: dfd3690
Author: haosdent huang <ha...@gmail.com>
Authored: Mon Sep 12 16:34:44 2016 -0700
Committer: Jie Yu <yu...@gmail.com>
Committed: Tue Sep 13 10:52:01 2016 -0700

----------------------------------------------------------------------
 src/CMakeLists.txt                              |   1 -
 src/Makefile.am                                 |   2 -
 src/docker/docker.cpp                           |   1 -
 src/slave/containerizer/mesos/containerizer.cpp |   1 -
 .../mesos/isolators/cgroups/mem.cpp             | 732 -------------------
 .../mesos/isolators/cgroups/mem.hpp             | 137 ----
 src/tests/containerizer/isolator_tests.cpp      |  81 +-
 7 files changed, 1 insertion(+), 954 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/f75d9494/src/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index aae8af8..4e66c74 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -159,7 +159,6 @@ set(LINUX_SRC
   slave/containerizer/mesos/linux_launcher.cpp
   slave/containerizer/mesos/isolators/appc/runtime.cpp
   slave/containerizer/mesos/isolators/cgroups/cgroups.cpp
-  slave/containerizer/mesos/isolators/cgroups/mem.cpp
   slave/containerizer/mesos/isolators/cgroups/net_cls.cpp
   slave/containerizer/mesos/isolators/cgroups/perf_event.cpp
   slave/containerizer/mesos/isolators/cgroups/subsystem.cpp

http://git-wip-us.apache.org/repos/asf/mesos/blob/f75d9494/src/Makefile.am
----------------------------------------------------------------------
diff --git a/src/Makefile.am b/src/Makefile.am
index 3c3f9bd..cf06c8d 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1025,7 +1025,6 @@ MESOS_LINUX_FILES =									\
   slave/containerizer/mesos/linux_launcher.cpp						\
   slave/containerizer/mesos/isolators/appc/runtime.cpp					\
   slave/containerizer/mesos/isolators/cgroups/cgroups.cpp				\
-  slave/containerizer/mesos/isolators/cgroups/mem.cpp					\
   slave/containerizer/mesos/isolators/cgroups/net_cls.cpp				\
   slave/containerizer/mesos/isolators/cgroups/perf_event.cpp				\
   slave/containerizer/mesos/isolators/cgroups/subsystem.cpp				\
@@ -1064,7 +1063,6 @@ MESOS_LINUX_FILES +=									\
   slave/containerizer/mesos/isolators/appc/runtime.hpp					\
   slave/containerizer/mesos/isolators/cgroups/cgroups.hpp				\
   slave/containerizer/mesos/isolators/cgroups/constants.hpp				\
-  slave/containerizer/mesos/isolators/cgroups/mem.hpp					\
   slave/containerizer/mesos/isolators/cgroups/net_cls.hpp				\
   slave/containerizer/mesos/isolators/cgroups/perf_event.hpp				\
   slave/containerizer/mesos/isolators/cgroups/subsystem.hpp				\

http://git-wip-us.apache.org/repos/asf/mesos/blob/f75d9494/src/docker/docker.cpp
----------------------------------------------------------------------
diff --git a/src/docker/docker.cpp b/src/docker/docker.cpp
index 44036c1..3d55424 100755
--- a/src/docker/docker.cpp
+++ b/src/docker/docker.cpp
@@ -43,7 +43,6 @@
 #endif // __linux__
 
 #include "slave/containerizer/mesos/isolators/cgroups/constants.hpp"
-#include "slave/containerizer/mesos/isolators/cgroups/mem.hpp"
 
 #include "slave/constants.hpp"
 

http://git-wip-us.apache.org/repos/asf/mesos/blob/f75d9494/src/slave/containerizer/mesos/containerizer.cpp
----------------------------------------------------------------------
diff --git a/src/slave/containerizer/mesos/containerizer.cpp b/src/slave/containerizer/mesos/containerizer.cpp
index c94a683..69150e7 100644
--- a/src/slave/containerizer/mesos/containerizer.cpp
+++ b/src/slave/containerizer/mesos/containerizer.cpp
@@ -73,7 +73,6 @@
 
 #ifdef __linux__
 #include "slave/containerizer/mesos/isolators/cgroups/cgroups.hpp"
-#include "slave/containerizer/mesos/isolators/cgroups/mem.hpp"
 #include "slave/containerizer/mesos/isolators/cgroups/net_cls.hpp"
 #include "slave/containerizer/mesos/isolators/cgroups/perf_event.hpp"
 #endif // __linux__

http://git-wip-us.apache.org/repos/asf/mesos/blob/f75d9494/src/slave/containerizer/mesos/isolators/cgroups/mem.cpp
----------------------------------------------------------------------
diff --git a/src/slave/containerizer/mesos/isolators/cgroups/mem.cpp b/src/slave/containerizer/mesos/isolators/cgroups/mem.cpp
deleted file mode 100644
index 0a4f38d..0000000
--- a/src/slave/containerizer/mesos/isolators/cgroups/mem.cpp
+++ /dev/null
@@ -1,732 +0,0 @@
-// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements.  See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership.  The ASF licenses this file
-// to you under the Apache License, Version 2.0 (the
-// "License"); you may not use this file except in compliance
-// with the License.  You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include <stdint.h>
-
-#include <list>
-#include <vector>
-
-#include <mesos/type_utils.hpp>
-#include <mesos/values.hpp>
-
-#include <process/collect.hpp>
-#include <process/defer.hpp>
-#include <process/id.hpp>
-#include <process/pid.hpp>
-
-#include <stout/bytes.hpp>
-#include <stout/check.hpp>
-#include <stout/error.hpp>
-#include <stout/foreach.hpp>
-#include <stout/hashset.hpp>
-#include <stout/lambda.hpp>
-#include <stout/os.hpp>
-#include <stout/path.hpp>
-#include <stout/stringify.hpp>
-#include <stout/try.hpp>
-
-#include "common/protobuf_utils.hpp"
-
-#include "slave/containerizer/mesos/isolators/cgroups/constants.hpp"
-#include "slave/containerizer/mesos/isolators/cgroups/mem.hpp"
-
-using namespace process;
-
-using cgroups::memory::pressure::Level;
-using cgroups::memory::pressure::Counter;
-
-using std::list;
-using std::ostringstream;
-using std::set;
-using std::string;
-using std::vector;
-
-using mesos::slave::ContainerConfig;
-using mesos::slave::ContainerLaunchInfo;
-using mesos::slave::ContainerLimitation;
-using mesos::slave::ContainerState;
-using mesos::slave::Isolator;
-
-namespace mesos {
-namespace internal {
-namespace slave {
-
-static const vector<Level> levels()
-{
-  return {Level::LOW, Level::MEDIUM, Level::CRITICAL};
-}
-
-
-CgroupsMemIsolatorProcess::CgroupsMemIsolatorProcess(
-    const Flags& _flags,
-    const string& _hierarchy,
-    const bool _limitSwap)
-  : ProcessBase(process::ID::generate("cgroups-mem-isolator")),
-    flags(_flags),
-    hierarchy(_hierarchy),
-    limitSwap(_limitSwap) {}
-
-
-CgroupsMemIsolatorProcess::~CgroupsMemIsolatorProcess() {}
-
-
-Try<Isolator*> CgroupsMemIsolatorProcess::create(const Flags& flags)
-{
-  Try<string> hierarchy = cgroups::prepare(
-      flags.cgroups_hierarchy,
-      "memory",
-      flags.cgroups_root);
-
-  if (hierarchy.isError()) {
-    return Error("Failed to create memory cgroup: " + hierarchy.error());
-  }
-
-  // Ensure that no other subsystem is attached to the hierarchy.
-  Try<set<string>> subsystems = cgroups::subsystems(hierarchy.get());
-  if (subsystems.isError()) {
-    return Error(
-        "Failed to get the list of attached subsystems for hierarchy " +
-        hierarchy.get());
-  } else if (subsystems.get().size() != 1) {
-    return Error(
-        "Unexpected subsystems found attached to the hierarchy " +
-        hierarchy.get());
-  }
-
-  // Make sure the kernel OOM-killer is enabled.
-  // The Mesos OOM handler, as implemented, is not capable of handling
-  // the oom condition by itself safely given the limitations Linux
-  // imposes on this code path.
-  Try<Nothing> enable = cgroups::memory::oom::killer::enable(
-      hierarchy.get(), flags.cgroups_root);
-
-  if (enable.isError()) {
-    return Error(enable.error());
-  }
-
-  // Test if memory pressure listening is enabled. We test that on the
-  // root cgroup. We rely on 'Counter::create' to test if memory
-  // pressure listening is enabled or not. The created counters will
-  // be destroyed immediately.
-  foreach (Level level, levels()) {
-    Try<Owned<Counter>> counter = Counter::create(
-        hierarchy.get(),
-        flags.cgroups_root,
-        level);
-
-    if (counter.isError()) {
-      return Error("Failed to listen on " + stringify(level) +
-                   " memory events: " + counter.error());
-    }
-  }
-
-  // Determine whether to limit swap or not.
-  bool limitSwap = false;
-
-  if (flags.cgroups_limit_swap) {
-    Result<Bytes> check = cgroups::memory::memsw_limit_in_bytes(
-        hierarchy.get(), flags.cgroups_root);
-
-    if (check.isError()) {
-      return Error(
-          "Failed to read 'memory.memsw.limit_in_bytes': " +
-          check.error());
-    } else if (check.isNone()) {
-      return Error("'memory.memsw.limit_in_bytes' is not available");
-    }
-
-    limitSwap = true;
-  }
-
-  process::Owned<MesosIsolatorProcess> process(
-      new CgroupsMemIsolatorProcess(flags, hierarchy.get(), limitSwap));
-
-  return new MesosIsolator(process);
-}
-
-
-Future<Nothing> CgroupsMemIsolatorProcess::recover(
-    const list<ContainerState>& states,
-    const hashset<ContainerID>& orphans)
-{
-  foreach (const ContainerState& state, states) {
-    const ContainerID& containerId = state.container_id();
-    const string cgroup = path::join(flags.cgroups_root, containerId.value());
-
-    Try<bool> exists = cgroups::exists(hierarchy, cgroup);
-    if (exists.isError()) {
-      foreachvalue (Info* info, infos) {
-        delete info;
-      }
-      infos.clear();
-      return Failure("Failed to check cgroup for container '" +
-                     stringify(containerId) + "'");
-    }
-
-    if (!exists.get()) {
-      VLOG(1) << "Couldn't find cgroup for container " << containerId;
-      // This may occur if the executor has exited and the isolator
-      // has destroyed the cgroup but the slave dies before noticing
-      // this. This will be detected when the containerizer tries to
-      // monitor the executor's pid.
-      continue;
-    }
-
-    infos[containerId] = new Info(containerId, cgroup);
-
-    oomListen(containerId);
-    pressureListen(containerId);
-  }
-
-  // Remove orphan cgroups.
-  Try<vector<string>> cgroups = cgroups::get(hierarchy, flags.cgroups_root);
-  if (cgroups.isError()) {
-    foreachvalue (Info* info, infos) {
-      delete info;
-    }
-    infos.clear();
-    return Failure(cgroups.error());
-  }
-
-  foreach (const string& cgroup, cgroups.get()) {
-    // Ignore the slave cgroup (see the --agent_subsystems flag).
-    // TODO(idownes): Remove this when the cgroups layout is updated,
-    // see MESOS-1185.
-    if (cgroup == path::join(flags.cgroups_root, "slave")) {
-      continue;
-    }
-
-    ContainerID containerId;
-    containerId.set_value(Path(cgroup).basename());
-
-    if (infos.contains(containerId)) {
-      continue;
-    }
-
-    // Known orphan cgroups will be destroyed by the containerizer
-    // using the normal cleanup path. See MESOS-2367 for details.
-    if (orphans.contains(containerId)) {
-      infos[containerId] = new Info(containerId, cgroup);
-      continue;
-    }
-
-    LOG(INFO) << "Removing unknown orphaned cgroup '" << cgroup << "'";
-
-    // We don't wait on the destroy as we don't want to block recovery.
-    cgroups::destroy(hierarchy, cgroup, cgroups::DESTROY_TIMEOUT);
-  }
-
-  return Nothing();
-}
-
-
-Future<Option<ContainerLaunchInfo>> CgroupsMemIsolatorProcess::prepare(
-    const ContainerID& containerId,
-    const ContainerConfig& containerConfig)
-{
-  if (infos.contains(containerId)) {
-    return Failure("Container has already been prepared");
-  }
-
-  // TODO(bmahler): Don't insert into 'infos' unless we create the
-  // cgroup successfully. It's safe for now because 'cleanup' gets
-  // called if we return a Failure, but cleanup will fail because the
-  // cgroup does not exist when cgroups::destroy is called.
-  Info* info = new Info(
-      containerId, path::join(flags.cgroups_root, containerId.value()));
-
-  infos[containerId] = info;
-
-  // Create a cgroup for this container.
-  Try<bool> exists = cgroups::exists(hierarchy, info->cgroup);
-
-  if (exists.isError()) {
-    return Failure("Failed to prepare isolator: " + exists.error());
-  } else if (exists.get()) {
-    return Failure("Failed to prepare isolator: cgroup already exists");
-  }
-
-  Try<Nothing> create = cgroups::create(hierarchy, info->cgroup);
-  if (create.isError()) {
-    return Failure("Failed to prepare isolator: " + create.error());
-  }
-
-  // Chown the cgroup so the executor can create nested cgroups. Do
-  // not recurse so the control files are still owned by the slave
-  // user and thus cannot be changed by the executor.
-  if (containerConfig.has_user()) {
-    Try<Nothing> chown = os::chown(
-        containerConfig.user(),
-        path::join(hierarchy, info->cgroup),
-        false);
-    if (chown.isError()) {
-      return Failure("Failed to prepare isolator: " + chown.error());
-    }
-  }
-
-  oomListen(containerId);
-  pressureListen(containerId);
-
-  return update(containerId, containerConfig.executor_info().resources())
-    .then([]() -> Future<Option<ContainerLaunchInfo>> {
-      return None();
-    });
-}
-
-
-Future<Nothing> CgroupsMemIsolatorProcess::isolate(
-    const ContainerID& containerId,
-    pid_t pid)
-{
-  if (!infos.contains(containerId)) {
-    return Failure("Unknown container");
-  }
-
-  Info* info = CHECK_NOTNULL(infos[containerId]);
-
-  CHECK_NONE(info->pid);
-  info->pid = pid;
-
-  Try<Nothing> assign = cgroups::assign(hierarchy, info->cgroup, pid);
-  if (assign.isError()) {
-    return Failure("Failed to assign container '" +
-                   stringify(info->containerId) + "' to its own cgroup '" +
-                   path::join(hierarchy, info->cgroup) +
-                   "' : " + assign.error());
-  }
-
-  return Nothing();
-}
-
-
-Future<ContainerLimitation> CgroupsMemIsolatorProcess::watch(
-    const ContainerID& containerId)
-{
-  if (!infos.contains(containerId)) {
-    return Failure("Unknown container");
-  }
-
-  CHECK_NOTNULL(infos[containerId]);
-
-  return infos[containerId]->limitation.future();
-}
-
-
-Future<Nothing> CgroupsMemIsolatorProcess::update(
-    const ContainerID& containerId,
-    const Resources& resources)
-{
-  if (resources.mem().isNone()) {
-    return Failure("No memory resource given");
-  }
-
-  if (!infos.contains(containerId)) {
-    return Failure("Unknown container");
-  }
-
-  Info* info = CHECK_NOTNULL(infos[containerId]);
-
-  // New limit.
-  Bytes mem = resources.mem().get();
-  Bytes limit = std::max(mem, MIN_MEMORY);
-
-  // Always set the soft limit.
-  Try<Nothing> write =
-    cgroups::memory::soft_limit_in_bytes(hierarchy, info->cgroup, limit);
-
-  if (write.isError()) {
-    return Failure(
-        "Failed to set 'memory.soft_limit_in_bytes': " + write.error());
-  }
-
-  LOG(INFO) << "Updated 'memory.soft_limit_in_bytes' to " << limit
-            << " for container " << containerId;
-
-  // Read the existing limit.
-  Try<Bytes> currentLimit =
-    cgroups::memory::limit_in_bytes(hierarchy, info->cgroup);
-
-  // NOTE: If limitSwap is (has been) used then both limit_in_bytes
-  // and memsw.limit_in_bytes will always be set to the same value.
-  if (currentLimit.isError()) {
-    return Failure(
-        "Failed to read 'memory.limit_in_bytes': " + currentLimit.error());
-  }
-
-  // Determine whether to set the hard limit. If this is the first
-  // time (info->pid.isNone()), or we're raising the existing limit,
-  // then we can update the hard limit safely. Otherwise, if we need
-  // to decrease 'memory.limit_in_bytes' we may induce an OOM if too
-  // much memory is in use. As a result, we only update the soft limit
-  // when the memory reservation is being reduced. This is probably
-  // okay if the machine has available resources.
-  // TODO(benh): Introduce a MemoryWatcherProcess which monitors the
-  // discrepancy between usage and soft limit and introduces a "manual
-  // oom" if necessary.
-  if (info->pid.isNone() || limit > currentLimit.get()) {
-    // We always set limit_in_bytes first and optionally set
-    // memsw.limit_in_bytes if limitSwap is true.
-    Try<Nothing> write = cgroups::memory::limit_in_bytes(
-        hierarchy, info->cgroup, limit);
-
-    if (write.isError()) {
-      return Failure(
-          "Failed to set 'memory.limit_in_bytes': " + write.error());
-    }
-
-    LOG(INFO) << "Updated 'memory.limit_in_bytes' to " << limit
-              << " for container " << containerId;
-
-    if (limitSwap) {
-      Try<bool> write = cgroups::memory::memsw_limit_in_bytes(
-          hierarchy, info->cgroup, limit);
-
-      if (write.isError()) {
-        return Failure(
-            "Failed to set 'memory.memsw.limit_in_bytes': " + write.error());
-      }
-
-      LOG(INFO) << "Updated 'memory.memsw.limit_in_bytes' to " << limit
-                << " for container " << containerId;
-    }
-  }
-
-  return Nothing();
-}
-
-
-Future<ResourceStatistics> CgroupsMemIsolatorProcess::usage(
-    const ContainerID& containerId)
-{
-  if (!infos.contains(containerId)) {
-    return Failure("Unknown container");
-  }
-
-  Info* info = CHECK_NOTNULL(infos[containerId]);
-
-  ResourceStatistics result;
-
-  // The rss from memory.stat is wrong in two dimensions:
-  //   1. It does not include child cgroups.
-  //   2. It does not include any file backed pages.
-  Try<Bytes> usage = cgroups::memory::usage_in_bytes(hierarchy, info->cgroup);
-  if (usage.isError()) {
-    return Failure("Failed to parse memory.usage_in_bytes: " + usage.error());
-  }
-
-  result.set_mem_total_bytes(usage.get().bytes());
-
-  if (limitSwap) {
-    Try<Bytes> usage =
-      cgroups::memory::memsw_usage_in_bytes(hierarchy, info->cgroup);
-    if (usage.isError()) {
-      return Failure(
-        "Failed to parse memory.memsw.usage_in_bytes: " + usage.error());
-    }
-
-    result.set_mem_total_memsw_bytes(usage.get().bytes());
-  }
-
-  // TODO(bmahler): Add namespacing to cgroups to enforce the expected
-  // structure, e.g, cgroups::memory::stat.
-  Try<hashmap<string, uint64_t>> stat =
-    cgroups::stat(hierarchy, info->cgroup, "memory.stat");
-  if (stat.isError()) {
-    return Failure("Failed to read memory.stat: " + stat.error());
-  }
-
-  Option<uint64_t> total_cache = stat.get().get("total_cache");
-  if (total_cache.isSome()) {
-    // TODO(chzhcn): mem_file_bytes is deprecated in 0.23.0 and will
-    // be removed in 0.24.0.
-    result.set_mem_file_bytes(total_cache.get());
-
-    result.set_mem_cache_bytes(total_cache.get());
-  }
-
-  Option<uint64_t> total_rss = stat.get().get("total_rss");
-  if (total_rss.isSome()) {
-    // TODO(chzhcn): mem_anon_bytes is deprecated in 0.23.0 and will
-    // be removed in 0.24.0.
-    result.set_mem_anon_bytes(total_rss.get());
-
-    result.set_mem_rss_bytes(total_rss.get());
-  }
-
-  Option<uint64_t> total_mapped_file = stat.get().get("total_mapped_file");
-  if (total_mapped_file.isSome()) {
-    result.set_mem_mapped_file_bytes(total_mapped_file.get());
-  }
-
-  Option<uint64_t> total_swap = stat.get().get("total_swap");
-  if (total_swap.isSome()) {
-    result.set_mem_swap_bytes(total_swap.get());
-  }
-
-  Option<uint64_t> total_unevictable = stat.get().get("total_unevictable");
-  if (total_unevictable.isSome()) {
-    result.set_mem_unevictable_bytes(total_unevictable.get());
-  }
-
-  // Get pressure counter readings.
-  list<Level> levels;
-  list<Future<uint64_t>> values;
-  foreachpair (Level level,
-               const Owned<Counter>& counter,
-               info->pressureCounters) {
-    levels.push_back(level);
-    values.push_back(counter->value());
-  }
-
-  return await(values)
-    .then(defer(PID<CgroupsMemIsolatorProcess>(this),
-                &CgroupsMemIsolatorProcess::_usage,
-                containerId,
-                result,
-                levels,
-                lambda::_1));
-}
-
-
-Future<ResourceStatistics> CgroupsMemIsolatorProcess::_usage(
-    const ContainerID& containerId,
-    ResourceStatistics result,
-    const list<Level>& levels,
-    const list<Future<uint64_t>>& values)
-{
-  if (!infos.contains(containerId)) {
-    return Failure("Unknown container");
-  }
-
-  list<Level>::const_iterator iterator = levels.begin();
-  foreach (const Future<uint64_t>& value, values) {
-    if (value.isReady()) {
-      switch (*iterator) {
-        case Level::LOW:
-          result.set_mem_low_pressure_counter(value.get());
-          break;
-        case Level::MEDIUM:
-          result.set_mem_medium_pressure_counter(value.get());
-          break;
-        case Level::CRITICAL:
-          result.set_mem_critical_pressure_counter(value.get());
-          break;
-      }
-    } else {
-      LOG(ERROR) << "Failed to listen on " << stringify(*iterator)
-                 << " pressure events for container " << containerId << ": "
-                 << (value.isFailed() ? value.failure() : "discarded");
-    }
-
-    ++iterator;
-  }
-
-  return result;
-}
-
-
-Future<Nothing> CgroupsMemIsolatorProcess::cleanup(
-    const ContainerID& containerId)
-{
-  // Multiple calls may occur during test clean up.
-  if (!infos.contains(containerId)) {
-    VLOG(1) << "Ignoring cleanup request for unknown container: "
-            << containerId;
-    return Nothing();
-  }
-
-  Info* info = CHECK_NOTNULL(infos[containerId]);
-
-  if (info->oomNotifier.isPending()) {
-    info->oomNotifier.discard();
-  }
-
-  return cgroups::destroy(hierarchy, info->cgroup, cgroups::DESTROY_TIMEOUT)
-    .onAny(defer(PID<CgroupsMemIsolatorProcess>(this),
-                 &CgroupsMemIsolatorProcess::_cleanup,
-                 containerId,
-                 lambda::_1));
-}
-
-
-Future<Nothing> CgroupsMemIsolatorProcess::_cleanup(
-    const ContainerID& containerId,
-    const Future<Nothing>& future)
-{
-  if (!infos.contains(containerId)) {
-    return Failure("Unknown container");
-  }
-
-  CHECK_NOTNULL(infos[containerId]);
-
-  if (!future.isReady()) {
-    return Failure("Failed to clean up container " + stringify(containerId) +
-                   " : " + (future.isFailed() ? future.failure()
-                                              : "discarded"));
-  }
-
-  delete infos[containerId];
-  infos.erase(containerId);
-
-  return Nothing();
-}
-
-
-void CgroupsMemIsolatorProcess::oomListen(
-    const ContainerID& containerId)
-{
-  CHECK(infos.contains(containerId));
-  Info* info = CHECK_NOTNULL(infos[containerId]);
-
-  info->oomNotifier = cgroups::memory::oom::listen(hierarchy, info->cgroup);
-
-  // If the listening fails immediately, something very wrong
-  // happened.  Therefore, we report a fatal error here.
-  if (info->oomNotifier.isFailed()) {
-    LOG(FATAL) << "Failed to listen for OOM events for container "
-               << containerId << ": "
-               << info->oomNotifier.failure();
-  }
-
-  LOG(INFO) << "Started listening for OOM events for container "
-            << containerId;
-
-  info->oomNotifier.onReady(defer(
-      PID<CgroupsMemIsolatorProcess>(this),
-      &CgroupsMemIsolatorProcess::oomWaited,
-      containerId,
-      lambda::_1));
-}
-
-
-void CgroupsMemIsolatorProcess::oomWaited(
-    const ContainerID& containerId,
-    const Future<Nothing>& future)
-{
-  if (future.isDiscarded()) {
-    LOG(INFO) << "Discarded OOM notifier for container "
-              << containerId;
-  } else if (future.isFailed()) {
-    LOG(ERROR) << "Listening on OOM events failed for container "
-               << containerId << ": " << future.failure();
-  } else {
-    // Out-of-memory event happened, call the handler.
-    LOG(INFO) << "OOM notifier is triggered for container " << containerId;
-    oom(containerId);
-  }
-}
-
-
-void CgroupsMemIsolatorProcess::oom(const ContainerID& containerId)
-{
-  if (!infos.contains(containerId)) {
-    // It is likely that process exited is executed before this
-    // function (e.g.  The kill and OOM events happen at the same
-    // time, and the process exit event arrives first.) Therefore, we
-    // should not report a fatal error here.
-    LOG(INFO) << "OOM detected for an already terminated executor";
-    return;
-  }
-
-  Info* info = CHECK_NOTNULL(infos[containerId]);
-
-  LOG(INFO) << "OOM detected for container " << containerId;
-
-  // Construct a "message" string to describe why the isolator
-  // destroyed the executor's cgroup (in order to assist in
-  // debugging).
-  ostringstream message;
-  message << "Memory limit exceeded: ";
-
-  // Output the requested memory limit.
-  // NOTE: If limitSwap is (has been) used then both limit_in_bytes
-  // and memsw.limit_in_bytes will always be set to the same value.
-  Try<Bytes> limit = cgroups::memory::limit_in_bytes(hierarchy, info->cgroup);
-
-  if (limit.isError()) {
-    LOG(ERROR) << "Failed to read 'memory.limit_in_bytes': "
-               << limit.error();
-  } else {
-    message << "Requested: " << limit.get() << " ";
-  }
-
-  // Output the maximum memory usage.
-  Try<Bytes> usage = cgroups::memory::max_usage_in_bytes(
-      hierarchy, info->cgroup);
-
-  if (usage.isError()) {
-    LOG(ERROR) << "Failed to read 'memory.max_usage_in_bytes': "
-               << usage.error();
-  } else {
-    message << "Maximum Used: " << usage.get() << "\n";
-  }
-
-  // Output 'memory.stat' of the cgroup to help with debugging.
-  // NOTE: With Kernel OOM-killer enabled these stats may not reflect
-  // memory state at time of OOM.
-  Try<string> read = cgroups::read(hierarchy, info->cgroup, "memory.stat");
-  if (read.isError()) {
-    LOG(ERROR) << "Failed to read 'memory.stat': " << read.error();
-  } else {
-    message << "\nMEMORY STATISTICS: \n" << read.get() << "\n";
-  }
-
-  LOG(INFO) << strings::trim(message.str()); // Trim the extra '\n' at the end.
-
-  // TODO(jieyu): This is not accurate if the memory resource is from
-  // a non-star role or spans roles (e.g., "*" and "role"). Ideally,
-  // we should save the resources passed in and report it here.
-  Resources mem = Resources::parse(
-      "mem",
-      stringify(usage.isSome() ? usage.get().megabytes() : 0),
-      "*").get();
-
-  info->limitation.set(
-      protobuf::slave::createContainerLimitation(
-          mem,
-          message.str(),
-          TaskStatus::REASON_CONTAINER_LIMITATION_MEMORY));
-}
-
-
-void CgroupsMemIsolatorProcess::pressureListen(
-    const ContainerID& containerId)
-{
-  CHECK(infos.contains(containerId));
-  Info* info = CHECK_NOTNULL(infos[containerId]);
-
-  foreach (Level level, levels()) {
-    Try<Owned<Counter>> counter = Counter::create(
-        hierarchy,
-        info->cgroup,
-        level);
-
-    if (counter.isError()) {
-      LOG(ERROR) << "Failed to listen on " << level << " memory pressure "
-                 << "events for container " << containerId << ": "
-                 << counter.error();
-    } else {
-      info->pressureCounters[level] = counter.get();
-
-      LOG(INFO) << "Started listening on " << level << " memory pressure "
-                << "events for container " << containerId;
-    }
-  }
-}
-
-} // namespace slave {
-} // namespace internal {
-} // namespace mesos {

http://git-wip-us.apache.org/repos/asf/mesos/blob/f75d9494/src/slave/containerizer/mesos/isolators/cgroups/mem.hpp
----------------------------------------------------------------------
diff --git a/src/slave/containerizer/mesos/isolators/cgroups/mem.hpp b/src/slave/containerizer/mesos/isolators/cgroups/mem.hpp
deleted file mode 100644
index b3ce6ed..0000000
--- a/src/slave/containerizer/mesos/isolators/cgroups/mem.hpp
+++ /dev/null
@@ -1,137 +0,0 @@
-// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements.  See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership.  The ASF licenses this file
-// to you under the Apache License, Version 2.0 (the
-// "License"); you may not use this file except in compliance
-// with the License.  You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#ifndef __MEM_ISOLATOR_HPP__
-#define __MEM_ISOLATOR_HPP__
-
-#include <sys/types.h>
-
-#include <process/future.hpp>
-#include <process/owned.hpp>
-
-#include <stout/hashmap.hpp>
-#include <stout/nothing.hpp>
-#include <stout/option.hpp>
-
-#include "linux/cgroups.hpp"
-
-#include "slave/flags.hpp"
-
-#include "slave/containerizer/mesos/isolator.hpp"
-
-namespace mesos {
-namespace internal {
-namespace slave {
-
-class CgroupsMemIsolatorProcess : public MesosIsolatorProcess
-{
-public:
-  static Try<mesos::slave::Isolator*> create(const Flags& flags);
-
-  virtual ~CgroupsMemIsolatorProcess();
-
-  virtual process::Future<Nothing> recover(
-      const std::list<mesos::slave::ContainerState>& states,
-      const hashset<ContainerID>& orphans);
-
-  virtual process::Future<Option<mesos::slave::ContainerLaunchInfo>> prepare(
-      const ContainerID& containerId,
-      const mesos::slave::ContainerConfig& containerConfig);
-
-  virtual process::Future<Nothing> isolate(
-      const ContainerID& containerId,
-      pid_t pid);
-
-  virtual process::Future<mesos::slave::ContainerLimitation> watch(
-      const ContainerID& containerId);
-
-  virtual process::Future<Nothing> update(
-      const ContainerID& containerId,
-      const Resources& resources);
-
-  virtual process::Future<ResourceStatistics> usage(
-      const ContainerID& containerId);
-
-  virtual process::Future<Nothing> cleanup(
-      const ContainerID& containerId);
-
-private:
-  CgroupsMemIsolatorProcess(
-      const Flags& flags,
-      const std::string& hierarchy,
-      bool limitSwap);
-
-  process::Future<ResourceStatistics> _usage(
-      const ContainerID& containerId,
-      ResourceStatistics result,
-      const std::list<cgroups::memory::pressure::Level>& levels,
-      const std::list<process::Future<uint64_t>>& values);
-
-  process::Future<Nothing> _cleanup(
-      const ContainerID& containerId,
-      const process::Future<Nothing>& future);
-
-  struct Info
-  {
-    Info(const ContainerID& _containerId, const std::string& _cgroup)
-      : containerId(_containerId), cgroup(_cgroup) {}
-
-    const ContainerID containerId;
-    const std::string cgroup;
-    Option<pid_t> pid;
-
-    process::Promise<mesos::slave::ContainerLimitation> limitation;
-
-    // Used to cancel the OOM listening.
-    process::Future<Nothing> oomNotifier;
-
-    hashmap<cgroups::memory::pressure::Level,
-            process::Owned<cgroups::memory::pressure::Counter>>
-      pressureCounters;
-  };
-
-  // Start listening on OOM events. This function will create an
-  // eventfd and start polling on it.
-  void oomListen(const ContainerID& containerId);
-
-  // This function is invoked when the polling on eventfd has a
-  // result.
-  void oomWaited(
-      const ContainerID& containerId,
-      const process::Future<Nothing>& future);
-
-  // This function is invoked when the OOM event happens.
-  void oom(const ContainerID& containerId);
-
-  // Start listening on memory pressure events.
-  void pressureListen(const ContainerID& containerId);
-
-  const Flags flags;
-
-  // The path to the cgroups subsystem hierarchy root.
-  const std::string hierarchy;
-
-  const bool limitSwap;
-
-  // TODO(bmahler): Use Owned<Info>.
-  hashmap<ContainerID, Info*> infos;
-};
-
-} // namespace slave {
-} // namespace internal {
-} // namespace mesos {
-
-#endif // __MEM_ISOLATOR_HPP__

http://git-wip-us.apache.org/repos/asf/mesos/blob/f75d9494/src/tests/containerizer/isolator_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/containerizer/isolator_tests.cpp b/src/tests/containerizer/isolator_tests.cpp
index 15978ae..a7b9ff5 100644
--- a/src/tests/containerizer/isolator_tests.cpp
+++ b/src/tests/containerizer/isolator_tests.cpp
@@ -52,7 +52,6 @@
 #include "slave/slave.hpp"
 
 #ifdef __linux__
-#include "slave/containerizer/mesos/isolators/cgroups/mem.hpp"
 #include "slave/containerizer/mesos/isolators/cgroups/net_cls.hpp"
 #include "slave/containerizer/mesos/isolators/cgroups/perf_event.hpp"
 #include "slave/containerizer/mesos/isolators/filesystem/shared.hpp"
@@ -72,13 +71,10 @@
 #include "tests/module.hpp"
 #include "tests/utils.hpp"
 
-#include "tests/containerizer/memory_test_helper.hpp"
-
 using namespace process;
 
 using mesos::internal::master::Master;
 #ifdef __linux__
-using mesos::internal::slave::CgroupsMemIsolatorProcess;
 using mesos::internal::slave::CgroupsNetClsIsolatorProcess;
 using mesos::internal::slave::CgroupsPerfEventIsolatorProcess;
 using mesos::internal::slave::Fetcher;
@@ -90,7 +86,6 @@ using mesos::internal::slave::SharedFilesystemIsolatorProcess;
 using mesos::internal::slave::Launcher;
 using mesos::internal::slave::MesosContainerizer;
 using mesos::internal::slave::PosixLauncher;
-using mesos::internal::slave::PosixMemIsolatorProcess;
 using mesos::internal::slave::Slave;
 
 using mesos::master::detector::MasterDetector;
@@ -197,78 +192,6 @@ TEST_F(NetClsHandleManagerTest, SecondaryHandleRange)
 #endif // __linux__
 
 
-template <typename T>
-class MemIsolatorTest : public MesosTest {};
-
-
-typedef ::testing::Types<
-    PosixMemIsolatorProcess,
-#ifdef __linux__
-    CgroupsMemIsolatorProcess,
-#endif // __linux__
-    tests::Module<Isolator, TestMemIsolator>> MemIsolatorTypes;
-
-
-TYPED_TEST_CASE(MemIsolatorTest, MemIsolatorTypes);
-
-
-TYPED_TEST(MemIsolatorTest, MemUsage)
-{
-  slave::Flags flags;
-
-  Try<Isolator*> _isolator = TypeParam::create(flags);
-  ASSERT_SOME(_isolator);
-  Owned<Isolator> isolator(_isolator.get());
-
-  ExecutorInfo executorInfo;
-  executorInfo.mutable_resources()->CopyFrom(
-      Resources::parse("mem:1024").get());
-
-  ContainerID containerId;
-  containerId.set_value(UUID::random().toString());
-
-  // Use a relative temporary directory so it gets cleaned up
-  // automatically with the test.
-  Try<string> dir = os::mkdtemp(path::join(os::getcwd(), "XXXXXX"));
-  ASSERT_SOME(dir);
-
-  ContainerConfig containerConfig;
-  containerConfig.mutable_executor_info()->CopyFrom(executorInfo);
-  containerConfig.set_directory(dir.get());
-
-  AWAIT_READY(isolator->prepare(
-      containerId,
-      containerConfig));
-
-  MemoryTestHelper helper;
-  ASSERT_SOME(helper.spawn());
-  ASSERT_SOME(helper.pid());
-
-  // Set up the reaper to wait on the subprocess.
-  Future<Option<int>> status = process::reap(helper.pid().get());
-
-  // Isolate the subprocess.
-  AWAIT_READY(isolator->isolate(containerId, helper.pid().get()));
-
-  const Bytes allocation = Megabytes(128);
-  EXPECT_SOME(helper.increaseRSS(allocation));
-
-  Future<ResourceStatistics> usage = isolator->usage(containerId);
-  AWAIT_READY(usage);
-
-  EXPECT_GE(usage.get().mem_rss_bytes(), allocation.bytes());
-
-  // Ensure the process is killed.
-  helper.cleanup();
-
-  // Make sure the subprocess was reaped.
-  AWAIT_READY(status);
-
-  // Let the isolator clean up.
-  AWAIT_READY(isolator->cleanup(containerId));
-}
-
-
 #ifdef __linux__
 class NetClsIsolatorTest : public MesosTest {};
 
@@ -870,9 +793,7 @@ public:
 
 
 // Test all isolators that use cgroups.
-typedef ::testing::Types<
-  CgroupsMemIsolatorProcess,
-  CgroupsPerfEventIsolatorProcess> CgroupsIsolatorTypes;
+typedef ::testing::Types<CgroupsPerfEventIsolatorProcess> CgroupsIsolatorTypes;
 
 
 TYPED_TEST_CASE(UserCgroupIsolatorTest, CgroupsIsolatorTypes);


Re: [13/17] mesos git commit: Refactored cpu isolator associated test cases.

Posted by Alex R <ru...@gmail.com>.
This one broke the Mac build:http://pastebin.com/ryJEBkrX

alex@alexr.local: ~/Projects/mesos/build/default $ c++ --version

Apple LLVM version 7.3.0 (clang-703.0.31)

Target: x86_64-apple-darwin15.6.0

In file included from
../../../src/tests/containerizer/cpu_isolator_tests.cpp:20:

In file included from
../../../3rdparty/libprocess/include/process/gtest.hpp:16:

In file included from
../3rdparty/gmock-1.7.0/gtest/include/gtest/gtest.h:62:

In file included from
../3rdparty/gmock-1.7.0/gtest/include/gtest/gtest-param-test.h:193:

../3rdparty/gmock-1.7.0/gtest/include/gtest/internal/gtest-param-util-generated.h:82:47:
error: no viable conversion from returned value of type
'ParamGenerator<typename
::testing::internal::IteratorTraits<const char *const *>::value_type>' to
function return type 'ParamGenerator<std::__1::basic_string<char>>'

  operator ParamGenerator<T>() const { return ValuesIn(&v1_, &v1_ + 1); }

                                              ^~~~~~~~~~~~~~~~~~~~~~~~

../../../src/tests/containerizer/cpu_isolator_tests.cpp:53:126: note: in
instantiation of function template specialization
'testing::internal::ValueArray1<const char *>::operator
ParamGenerator<std::__1::basic_string<char> >' requested here

::testing::internal::ParamGenerator<CpuIsolatorTest::ParamType>
gtest_IsolationFlagCpuIsolatorTest_EvalGenerator_() { return
::testing::Values("posix/cpu"); } int
gtest_IsolationFlagCpuIsolatorTest_dummy_ =
::testing::UnitTest::GetInstance()->parameterized_test_registry().
GetTestCasePatternHolder<CpuIsolatorTest>( "CpuIsolatorTest",
"../../../src/tests/containerizer/cpu_isolator_tests.cpp",
59)->AddTestCaseInstantiation( "IsolationFlag",
&gtest_IsolationFlagCpuIsolatorTest_EvalGenerator_,
"../../../src/tests/containerizer/cpu_isolator_tests.cpp", 59);


                                                  ^

../3rdparty/gmock-1.7.0/gtest/include/gtest/internal/gtest-param-util.h:164:3:
note: candidate constructor not viable: no known conversion from
'internal::ParamGenerator<typename
::testing::internal::IteratorTraits<const char *const *>::value_type>' (aka
'ParamGenerator<const char *>') to 'const
testing::internal::ParamGenerator<std::__1::basic_string<char> > &' for 1st
argument

  ParamGenerator(const ParamGenerator& other) : impl_(other.impl_) {}

  ^

1 error generated.

On 13 September 2016 at 19:54, <ji...@apache.org> wrote:

> Refactored cpu isolator associated test cases.
>
> Review: https://reviews.apache.org/r/51787/
>
>
> Project: http://git-wip-us.apache.org/repos/asf/mesos/repo
> Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/451f65fd
> Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/451f65fd
> Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/451f65fd
>
> Branch: refs/heads/master
> Commit: 451f65fdaf7953dcfcf865e093869540df890e0f
> Parents: e766d4d
> Author: haosdent huang <ha...@gmail.com>
> Authored: Mon Sep 12 16:35:02 2016 -0700
> Committer: Jie Yu <yu...@gmail.com>
> Committed: Tue Sep 13 10:52:01 2016 -0700
>
> ----------------------------------------------------------------------
>  src/Makefile.am                                 |   1 +
>  .../containerizer/cgroups_isolator_tests.cpp    | 307 +++++++++++++++++++
>  src/tests/containerizer/cpu_isolator_tests.cpp  | 249 +++++++++++++++
>  3 files changed, 557 insertions(+)
> ----------------------------------------------------------------------
>
>
> http://git-wip-us.apache.org/repos/asf/mesos/blob/451f65fd/src/Makefile.am
> ----------------------------------------------------------------------
> diff --git a/src/Makefile.am b/src/Makefile.am
> index e789994..5d38747 100644
> --- a/src/Makefile.am
> +++ b/src/Makefile.am
> @@ -2134,6 +2134,7 @@ mesos_tests_SOURCES =
>              \
>    tests/common/type_utils_tests.cpp                            \
>    tests/containerizer/appc_spec_tests.cpp                      \
>    tests/containerizer/composing_containerizer_tests.cpp                \
> +  tests/containerizer/cpu_isolator_tests.cpp                   \
>    tests/containerizer/docker_containerizer_tests.cpp           \
>    tests/containerizer/docker_spec_tests.cpp                    \
>    tests/containerizer/docker_tests.cpp                         \
>
> http://git-wip-us.apache.org/repos/asf/mesos/blob/451f65fd/
> src/tests/containerizer/cgroups_isolator_tests.cpp
> ----------------------------------------------------------------------
> diff --git a/src/tests/containerizer/cgroups_isolator_tests.cpp
> b/src/tests/containerizer/cgroups_isolator_tests.cpp
> index 396c96c..75fe3b7 100644
> --- a/src/tests/containerizer/cgroups_isolator_tests.cpp
> +++ b/src/tests/containerizer/cgroups_isolator_tests.cpp
> @@ -15,6 +15,7 @@
>  // limitations under the License.
>
>  #include <process/gtest.hpp>
> +#include <process/queue.hpp>
>
>  #include <stout/format.hpp>
>  #include <stout/gtest.hpp>
> @@ -36,6 +37,8 @@ using mesos::internal::slave::
> CGROUP_SUBSYSTEM_DEVICES_NAME;
>  using mesos::internal::slave::CGROUP_SUBSYSTEM_MEMORY_NAME;
>  using mesos::internal::slave::CGROUP_SUBSYSTEM_NET_CLS_NAME;
>  using mesos::internal::slave::CGROUP_SUBSYSTEM_PERF_EVENT_NAME;
> +using mesos::internal::slave::CPU_SHARES_PER_CPU_REVOCABLE;
> +using mesos::internal::slave::DEFAULT_EXECUTOR_CPUS;
>  using mesos::internal::slave::Fetcher;
>  using mesos::internal::slave::MesosContainerizer;
>
> @@ -43,10 +46,13 @@ using mesos::master::detector::MasterDetector;
>
>  using process::Future;
>  using process::Owned;
> +using process::Queue;
>
>  using std::string;
>  using std::vector;
>
> +using testing::InvokeWithoutArgs;
> +
>  namespace mesos {
>  namespace internal {
>  namespace tests {
> @@ -206,6 +212,307 @@ TEST_F(CgroupsIsolatorTest,
> ROOT_CGROUPS_PERF_NET_CLS_UserCgroup)
>    driver.join();
>  }
>
> +
> +TEST_F(CgroupsIsolatorTest, ROOT_CGROUPS_RevocableCpu)
> +{
> +  Try<Owned<cluster::Master>> master = StartMaster();
> +  ASSERT_SOME(master);
> +
> +  slave::Flags flags = CreateSlaveFlags();
> +  flags.isolation = "cgroups/cpu";
> +
> +  Fetcher fetcher;
> +
> +  Try<MesosContainerizer*> _containerizer =
> +    MesosContainerizer::create(flags, true, &fetcher);
> +
> +  ASSERT_SOME(_containerizer);
> +
> +  Owned<MesosContainerizer> containerizer(_containerizer.get());
> +
> +  MockResourceEstimator resourceEstimator;
> +  EXPECT_CALL(resourceEstimator, initialize(_));
> +
> +  Queue<Resources> estimations;
> +  EXPECT_CALL(resourceEstimator, oversubscribable())
> +    .WillRepeatedly(InvokeWithoutArgs(&estimations,
> &Queue<Resources>::get));
> +
> +  Owned<MasterDetector> detector = master.get()->createDetector();
> +
> +  Try<Owned<cluster::Slave>> slave = StartSlave(
> +      detector.get(),
> +      containerizer.get(),
> +      &resourceEstimator,
> +      flags);
> +
> +  ASSERT_SOME(slave);
> +
> +  // Start the framework which accepts revocable resources.
> +  FrameworkInfo frameworkInfo = DEFAULT_FRAMEWORK_INFO;
> +  frameworkInfo.add_capabilities()->set_type(
> +      FrameworkInfo::Capability::REVOCABLE_RESOURCES);
> +
> +  MockScheduler sched;
> +  MesosSchedulerDriver driver(
> +      &sched,
> +      frameworkInfo,
> +      master.get()->pid,
> +      DEFAULT_CREDENTIAL);
> +
> +  EXPECT_CALL(sched, registered(&driver, _, _))
> +    .Times(1);
> +
> +  Future<vector<Offer>> offers1;
> +  EXPECT_CALL(sched, resourceOffers(&driver, _))
> +    .WillOnce(FutureArg<1>(&offers1));
> +
> +  driver.start();
> +
> +  // Initially the framework will get all regular resources.
> +  AWAIT_READY(offers1);
> +  EXPECT_NE(0u, offers1.get().size());
> +  EXPECT_TRUE(Resources(offers1.get()[0].resources()).
> revocable().empty());
> +
> +  Future<vector<Offer>> offers2;
> +  EXPECT_CALL(sched, resourceOffers(&driver, _))
> +    .WillOnce(FutureArg<1>(&offers2))
> +    .WillRepeatedly(Return()); // Ignore subsequent offers.
> +
> +  // Inject an estimation of revocable cpu resources.
> +  Resource cpu = Resources::parse("cpus", "1", "*").get();
> +  cpu.mutable_revocable();
> +  Resources cpus(cpu);
> +  estimations.put(cpus);
> +
> +  // Now the framework will get revocable resources.
> +  AWAIT_READY(offers2);
> +  EXPECT_NE(0u, offers2.get().size());
> +  EXPECT_EQ(cpus, Resources(offers2.get()[0].resources()));
> +
> +  TaskInfo task = createTask(
> +      offers2.get()[0].slave_id(),
> +      cpus,
> +      "sleep 120");
> +
> +  Future<TaskStatus> statusRunning;
> +  EXPECT_CALL(sched, statusUpdate(&driver, _))
> +    .WillOnce(FutureArg<1>(&statusRunning));
> +
> +  driver.launchTasks(offers2.get()[0].id(), {task});
> +
> +  AWAIT_READY(statusRunning);
> +  EXPECT_EQ(TASK_RUNNING, statusRunning.get().state());
> +
> +  Future<hashset<ContainerID>> containers = containerizer->containers();
> +  AWAIT_READY(containers);
> +  EXPECT_EQ(1u, containers.get().size());
> +
> +  ContainerID containerId = *(containers.get().begin());
> +
> +  string cpuHierarchy = path::join(flags.cgroups_hierarchy, "cpu");
> +  string cpuCgroup= path::join(flags.cgroups_root, containerId.value());
> +
> +  double totalCpus = cpus.cpus().get() + DEFAULT_EXECUTOR_CPUS;
> +  EXPECT_SOME_EQ(
> +      CPU_SHARES_PER_CPU_REVOCABLE * totalCpus,
> +      cgroups::cpu::shares(cpuHierarchy, cpuCgroup));
> +
> +  driver.stop();
> +  driver.join();
> +}
> +
> +
> +TEST_F(CgroupsIsolatorTest, ROOT_CGROUPS_CFS_EnableCfs)
> +{
> +  Try<Owned<cluster::Master>> master = StartMaster();
> +  ASSERT_SOME(master);
> +
> +  slave::Flags flags = CreateSlaveFlags();
> +  flags.isolation = "cgroups/cpu";
> +
> +  // Enable CFS to cap CPU utilization.
> +  flags.cgroups_enable_cfs = true;
> +
> +  Fetcher fetcher;
> +
> +  Try<MesosContainerizer*> _containerizer =
> +    MesosContainerizer::create(flags, true, &fetcher);
> +
> +  ASSERT_SOME(_containerizer);
> +
> +  Owned<MesosContainerizer> containerizer(_containerizer.get());
> +
> +  Owned<MasterDetector> detector = master.get()->createDetector();
> +
> +  Try<Owned<cluster::Slave>> slave = StartSlave(
> +      detector.get(),
> +      containerizer.get());
> +
> +  ASSERT_SOME(slave);
> +
> +  MockScheduler sched;
> +  MesosSchedulerDriver driver(
> +      &sched,
> +      DEFAULT_FRAMEWORK_INFO,
> +      master.get()->pid,
> +      DEFAULT_CREDENTIAL);
> +
> +  EXPECT_CALL(sched, registered(&driver, _, _))
> +    .Times(1);
> +
> +  Future<vector<Offer>> offers;
> +  EXPECT_CALL(sched, resourceOffers(&driver, _))
> +    .WillOnce(FutureArg<1>(&offers))
> +    .WillRepeatedly(Return()); // Ignore subsequent offers.
> +
> +  driver.start();
> +
> +  AWAIT_READY(offers);
> +  EXPECT_NE(0u, offers.get().size());
> +
> +  // Generate random numbers to max out a single core. We'll run this
> +  // for 0.5 seconds of wall time so it should consume approximately
> +  // 250 ms of total cpu time when limited to 0.5 cpu. We use
> +  // /dev/urandom to prevent blocking on Linux when there's
> +  // insufficient entropy.
> +  string command =
> +    "cat /dev/urandom > /dev/null & "
> +    "export MESOS_TEST_PID=$! && "
> +    "sleep 0.5 && "
> +    "kill $MESOS_TEST_PID";
> +
> +  ASSERT_GE(Resources(offers.get()[0].resources()).cpus().get(), 0.5);
> +
> +  TaskInfo task = createTask(
> +      offers.get()[0].slave_id(),
> +      Resources::parse("cpus:0.5").get(),
> +      command);
> +
> +  Future<TaskStatus> statusRunning;
> +  EXPECT_CALL(sched, statusUpdate(&driver, _))
> +    .WillOnce(FutureArg<1>(&statusRunning));
> +
> +  driver.launchTasks(offers.get()[0].id(), {task});
> +
> +  AWAIT_READY(statusRunning);
> +  EXPECT_EQ(TASK_RUNNING, statusRunning.get().state());
> +
> +  Future<hashset<ContainerID>> containers = containerizer->containers();
> +  AWAIT_READY(containers);
> +  EXPECT_EQ(1u, containers.get().size());
> +
> +  ContainerID containerId = *(containers.get().begin());
> +
> +  Future<ResourceStatistics> usage = containerizer->usage(containerId);
> +  AWAIT_READY(usage);
> +
> +  // Expect that no more than 300 ms of cpu time has been consumed. We
> +  // also check that at least 50 ms of cpu time has been consumed so
> +  // this test will fail if the host system is very heavily loaded.
> +  // This behavior is correct because under such conditions we aren't
> +  // actually testing the CFS cpu limiter.
> +  double cpuTime = usage.get().cpus_system_time_secs() +
> +                   usage.get().cpus_user_time_secs();
> +
> +  EXPECT_GE(0.30, cpuTime);
> +  EXPECT_LE(0.05, cpuTime);
> +
> +  driver.stop();
> +  driver.join();
> +}
> +
> +
> +// The test verifies that the number of processes and threads in a
> +// container is correctly reported.
> +TEST_F(CgroupsIsolatorTest, ROOT_CGROUPS_PidsAndTids)
> +{
> +  Try<Owned<cluster::Master>> master = StartMaster();
> +  ASSERT_SOME(master);
> +
> +  slave::Flags flags = CreateSlaveFlags();
> +  flags.isolation = "cgroups/cpu";
> +  flags.cgroups_cpu_enable_pids_and_tids_count = true;
> +
> +  Fetcher fetcher;
> +
> +  Try<MesosContainerizer*> _containerizer =
> +    MesosContainerizer::create(flags, true, &fetcher);
> +
> +  ASSERT_SOME(_containerizer);
> +
> +  Owned<MesosContainerizer> containerizer(_containerizer.get());
> +
> +  Owned<MasterDetector> detector = master.get()->createDetector();
> +
> +  Try<Owned<cluster::Slave>> slave = StartSlave(
> +      detector.get(),
> +      containerizer.get());
> +
> +  ASSERT_SOME(slave);
> +
> +  MockScheduler sched;
> +  MesosSchedulerDriver driver(
> +      &sched,
> +      DEFAULT_FRAMEWORK_INFO,
> +      master.get()->pid,
> +      DEFAULT_CREDENTIAL);
> +
> +  EXPECT_CALL(sched, registered(&driver, _, _))
> +    .Times(1);
> +
> +  Future<vector<Offer>> offers;
> +  EXPECT_CALL(sched, resourceOffers(&driver, _))
> +    .WillOnce(FutureArg<1>(&offers))
> +    .WillRepeatedly(Return()); // Ignore subsequent offers.
> +
> +  driver.start();
> +
> +  AWAIT_READY(offers);
> +  EXPECT_NE(0u, offers.get().size());
> +
> +  CommandInfo command;
> +  command.set_shell(false);
> +  command.set_value("/bin/cat");
> +  command.add_arguments("/bin/cat");
> +
> +  TaskInfo task = createTask(
> +      offers.get()[0].slave_id(),
> +      offers.get()[0].resources(),
> +      command);
> +
> +  Future<TaskStatus> statusRunning;
> +  EXPECT_CALL(sched, statusUpdate(&driver, _))
> +    .WillOnce(FutureArg<1>(&statusRunning));
> +
> +  driver.launchTasks(offers.get()[0].id(), {task});
> +
> +  AWAIT_READY(statusRunning);
> +  EXPECT_EQ(TASK_RUNNING, statusRunning.get().state());
> +
> +  Future<hashset<ContainerID>> containers = containerizer->containers();
> +  AWAIT_READY(containers);
> +  EXPECT_EQ(1u, containers.get().size());
> +
> +  ContainerID containerId = *(containers.get().begin());
> +
> +  Future<ResourceStatistics> usage = containerizer->usage(containerId);
> +  AWAIT_READY(usage);
> +
> +  // The possible running processes during capture process number.
> +  //   - src/.libs/mesos-executor
> +  //   - src/mesos-executor
> +  //   - src/.libs/mesos-containerizer
> +  //   - src/mesos-containerizer
> +  //   - cat
> +  // For `cat` and `mesos-executor`, they keep idling during running
> +  // the test case. For other processes, they may occur temporarily.
> +  EXPECT_GE(usage.get().processes(), 2U);
> +  EXPECT_GE(usage.get().threads(), 2U);
> +
> +  driver.stop();
> +  driver.join();
> +}
> +
>  } // namespace tests {
>  } // namespace internal {
>  } // namespace mesos {
>
> http://git-wip-us.apache.org/repos/asf/mesos/blob/451f65fd/
> src/tests/containerizer/cpu_isolator_tests.cpp
> ----------------------------------------------------------------------
> diff --git a/src/tests/containerizer/cpu_isolator_tests.cpp
> b/src/tests/containerizer/cpu_isolator_tests.cpp
> new file mode 100644
> index 0000000..c8755f1
> --- /dev/null
> +++ b/src/tests/containerizer/cpu_isolator_tests.cpp
> @@ -0,0 +1,249 @@
> +// Licensed to the Apache Software Foundation (ASF) under one
> +// or more contributor license agreements.  See the NOTICE file
> +// distributed with this work for additional information
> +// regarding copyright ownership.  The ASF licenses this file
> +// to you under the Apache License, Version 2.0 (the
> +// "License"); you may not use this file except in compliance
> +// with the License.  You may obtain a copy of the License at
> +//
> +//     http://www.apache.org/licenses/LICENSE-2.0
> +//
> +// Unless required by applicable law or agreed to in writing, software
> +// distributed under the License is distributed on an "AS IS" BASIS,
> +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
> implied.
> +// See the License for the specific language governing permissions and
> +// limitations under the License.
> +
> +#include <string>
> +#include <vector>
> +
> +#include <process/gtest.hpp>
> +
> +#include <stout/gtest.hpp>
> +
> +#include "slave/containerizer/mesos/containerizer.hpp"
> +
> +#include "tests/mesos.hpp"
> +
> +using mesos::internal::master::Master;
> +
> +using mesos::internal::slave::Fetcher;
> +using mesos::internal::slave::MesosContainerizer;
> +
> +using mesos::master::detector::MasterDetector;
> +
> +using process::Future;
> +using process::Owned;
> +
> +using std::string;
> +using std::vector;
> +
> +using testing::WithParamInterface;
> +
> +namespace mesos {
> +namespace internal {
> +namespace tests {
> +
> +class CpuIsolatorTest
> +  : public MesosTest,
> +    public WithParamInterface<string> {};
> +
> +
> +// These tests are parameterized by the isolation flag.
> +INSTANTIATE_TEST_CASE_P(
> +    IsolationFlag,
> +    CpuIsolatorTest,
> +#ifdef __linux__
> +    ::testing::Values("posix/cpu", "cgroups/cpu"));
> +#else
> +    ::testing::Values("posix/cpu"));
> +#endif // __linux__
> +
> +
> +TEST_P(CpuIsolatorTest, ROOT_UserCpuUsage)
> +{
> +  Try<Owned<cluster::Master>> master = StartMaster();
> +  ASSERT_SOME(master);
> +
> +  slave::Flags flags = CreateSlaveFlags();
> +  flags.isolation = GetParam();
> +
> +  Fetcher fetcher;
> +
> +  Try<MesosContainerizer*> _containerizer =
> +    MesosContainerizer::create(flags, true, &fetcher);
> +
> +  ASSERT_SOME(_containerizer);
> +
> +  Owned<MesosContainerizer> containerizer(_containerizer.get());
> +
> +  Owned<MasterDetector> detector = master.get()->createDetector();
> +
> +  Try<Owned<cluster::Slave>> slave = StartSlave(
> +      detector.get(),
> +      containerizer.get());
> +
> +  ASSERT_SOME(slave);
> +
> +  MockScheduler sched;
> +  MesosSchedulerDriver driver(
> +      &sched,
> +      DEFAULT_FRAMEWORK_INFO,
> +      master.get()->pid,
> +      DEFAULT_CREDENTIAL);
> +
> +  EXPECT_CALL(sched, registered(&driver, _, _))
> +    .Times(1);
> +
> +  Future<vector<Offer>> offers;
> +  EXPECT_CALL(sched, resourceOffers(&driver, _))
> +    .WillOnce(FutureArg<1>(&offers))
> +    .WillRepeatedly(Return()); // Ignore subsequent offers.
> +
> +  driver.start();
> +
> +  AWAIT_READY(offers);
> +  EXPECT_NE(0u, offers.get().size());
> +
> +  // Max out a single core in userspace. This will run for at most one
> +  // second.
> +  TaskInfo task = createTask(
> +      offers.get()[0],
> +      "while true ; do true ; done & sleep 60");
> +
> +  Future<TaskStatus> statusRunning;
> +  EXPECT_CALL(sched, statusUpdate(&driver, _))
> +    .WillOnce(FutureArg<1>(&statusRunning));
> +
> +  driver.launchTasks(offers.get()[0].id(), {task});
> +
> +  AWAIT_READY(statusRunning);
> +  EXPECT_EQ(TASK_RUNNING, statusRunning.get().state());
> +
> +  Future<hashset<ContainerID>> containers = containerizer->containers();
> +  AWAIT_READY(containers);
> +  EXPECT_EQ(1u, containers.get().size());
> +
> +  ContainerID containerId = *(containers.get().begin());
> +
> +  // Wait up to 1 second for the child process to induce 1/8 of a
> +  // second of user cpu time.
> +  ResourceStatistics statistics;
> +  Duration waited = Duration::zero();
> +  do {
> +    Future<ResourceStatistics> usage = containerizer->usage(containerId);
> +    AWAIT_READY(usage);
> +
> +    statistics = usage.get();
> +
> +    // If we meet our usage expectations, we're done!
> +    if (statistics.cpus_user_time_secs() >= 0.125) {
> +      break;
> +    }
> +
> +    os::sleep(Milliseconds(200));
> +    waited += Milliseconds(200);
> +  } while (waited < Seconds(1));
> +
> +  EXPECT_LE(0.125, statistics.cpus_user_time_secs());
> +
> +  driver.stop();
> +  driver.join();
> +}
> +
> +
> +TEST_P(CpuIsolatorTest, ROOT_SystemCpuUsage)
> +{
> +  Try<Owned<cluster::Master>> master = StartMaster();
> +  ASSERT_SOME(master);
> +
> +  slave::Flags flags = CreateSlaveFlags();
> +  flags.isolation = GetParam();
> +
> +  Fetcher fetcher;
> +
> +  Try<MesosContainerizer*> _containerizer =
> +    MesosContainerizer::create(flags, true, &fetcher);
> +
> +  ASSERT_SOME(_containerizer);
> +
> +  Owned<MesosContainerizer> containerizer(_containerizer.get());
> +
> +  Owned<MasterDetector> detector = master.get()->createDetector();
> +
> +  Try<Owned<cluster::Slave>> slave = StartSlave(
> +      detector.get(),
> +      containerizer.get());
> +
> +  ASSERT_SOME(slave);
> +
> +  MockScheduler sched;
> +  MesosSchedulerDriver driver(
> +      &sched,
> +      DEFAULT_FRAMEWORK_INFO,
> +      master.get()->pid,
> +      DEFAULT_CREDENTIAL);
> +
> +  EXPECT_CALL(sched, registered(&driver, _, _))
> +    .Times(1);
> +
> +  Future<vector<Offer>> offers;
> +  EXPECT_CALL(sched, resourceOffers(&driver, _))
> +    .WillOnce(FutureArg<1>(&offers))
> +    .WillRepeatedly(Return()); // Ignore subsequent offers.
> +
> +  driver.start();
> +
> +  AWAIT_READY(offers);
> +  EXPECT_NE(0u, offers.get().size());
> +
> +  // Generating random numbers is done by the kernel and will max out
> +  // a single core and run almost exclusively in the kernel, i.e.,
> +  // system time.
> +  TaskInfo task = createTask(
> +      offers.get()[0],
> +      "cat /dev/urandom > /dev/null & sleep 60");
> +
> +  Future<TaskStatus> statusRunning;
> +  EXPECT_CALL(sched, statusUpdate(&driver, _))
> +    .WillOnce(FutureArg<1>(&statusRunning));
> +
> +  driver.launchTasks(offers.get()[0].id(), {task});
> +
> +  AWAIT_READY(statusRunning);
> +  EXPECT_EQ(TASK_RUNNING, statusRunning.get().state());
> +
> +  Future<hashset<ContainerID>> containers = containerizer->containers();
> +  AWAIT_READY(containers);
> +  EXPECT_EQ(1u, containers.get().size());
> +
> +  ContainerID containerId = *(containers.get().begin());
> +
> +  // Wait up to 1 second for the child process to induce 1/8 of a
> +  // second of user cpu time.
> +  ResourceStatistics statistics;
> +  Duration waited = Duration::zero();
> +  do {
> +    Future<ResourceStatistics> usage = containerizer->usage(containerId);
> +    AWAIT_READY(usage);
> +
> +    statistics = usage.get();
> +
> +    // If we meet our usage expectations, we're done!
> +    if (statistics.cpus_system_time_secs() >= 0.125) {
> +      break;
> +    }
> +
> +    os::sleep(Milliseconds(200));
> +    waited += Milliseconds(200);
> +  } while (waited < Seconds(1));
> +
> +  EXPECT_LE(0.125, statistics.cpus_user_time_secs());
> +
> +  driver.stop();
> +  driver.join();
> +}
> +
> +} // namespace tests {
> +} // namespace internal {
> +} // namespace mesos {
>
>

[13/17] mesos git commit: Refactored cpu isolator associated test cases.

Posted by ji...@apache.org.
Refactored cpu isolator associated test cases.

Review: https://reviews.apache.org/r/51787/


Project: http://git-wip-us.apache.org/repos/asf/mesos/repo
Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/451f65fd
Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/451f65fd
Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/451f65fd

Branch: refs/heads/master
Commit: 451f65fdaf7953dcfcf865e093869540df890e0f
Parents: e766d4d
Author: haosdent huang <ha...@gmail.com>
Authored: Mon Sep 12 16:35:02 2016 -0700
Committer: Jie Yu <yu...@gmail.com>
Committed: Tue Sep 13 10:52:01 2016 -0700

----------------------------------------------------------------------
 src/Makefile.am                                 |   1 +
 .../containerizer/cgroups_isolator_tests.cpp    | 307 +++++++++++++++++++
 src/tests/containerizer/cpu_isolator_tests.cpp  | 249 +++++++++++++++
 3 files changed, 557 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/451f65fd/src/Makefile.am
----------------------------------------------------------------------
diff --git a/src/Makefile.am b/src/Makefile.am
index e789994..5d38747 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -2134,6 +2134,7 @@ mesos_tests_SOURCES =						\
   tests/common/type_utils_tests.cpp				\
   tests/containerizer/appc_spec_tests.cpp			\
   tests/containerizer/composing_containerizer_tests.cpp		\
+  tests/containerizer/cpu_isolator_tests.cpp			\
   tests/containerizer/docker_containerizer_tests.cpp		\
   tests/containerizer/docker_spec_tests.cpp			\
   tests/containerizer/docker_tests.cpp				\

http://git-wip-us.apache.org/repos/asf/mesos/blob/451f65fd/src/tests/containerizer/cgroups_isolator_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/containerizer/cgroups_isolator_tests.cpp b/src/tests/containerizer/cgroups_isolator_tests.cpp
index 396c96c..75fe3b7 100644
--- a/src/tests/containerizer/cgroups_isolator_tests.cpp
+++ b/src/tests/containerizer/cgroups_isolator_tests.cpp
@@ -15,6 +15,7 @@
 // limitations under the License.
 
 #include <process/gtest.hpp>
+#include <process/queue.hpp>
 
 #include <stout/format.hpp>
 #include <stout/gtest.hpp>
@@ -36,6 +37,8 @@ using mesos::internal::slave::CGROUP_SUBSYSTEM_DEVICES_NAME;
 using mesos::internal::slave::CGROUP_SUBSYSTEM_MEMORY_NAME;
 using mesos::internal::slave::CGROUP_SUBSYSTEM_NET_CLS_NAME;
 using mesos::internal::slave::CGROUP_SUBSYSTEM_PERF_EVENT_NAME;
+using mesos::internal::slave::CPU_SHARES_PER_CPU_REVOCABLE;
+using mesos::internal::slave::DEFAULT_EXECUTOR_CPUS;
 using mesos::internal::slave::Fetcher;
 using mesos::internal::slave::MesosContainerizer;
 
@@ -43,10 +46,13 @@ using mesos::master::detector::MasterDetector;
 
 using process::Future;
 using process::Owned;
+using process::Queue;
 
 using std::string;
 using std::vector;
 
+using testing::InvokeWithoutArgs;
+
 namespace mesos {
 namespace internal {
 namespace tests {
@@ -206,6 +212,307 @@ TEST_F(CgroupsIsolatorTest, ROOT_CGROUPS_PERF_NET_CLS_UserCgroup)
   driver.join();
 }
 
+
+TEST_F(CgroupsIsolatorTest, ROOT_CGROUPS_RevocableCpu)
+{
+  Try<Owned<cluster::Master>> master = StartMaster();
+  ASSERT_SOME(master);
+
+  slave::Flags flags = CreateSlaveFlags();
+  flags.isolation = "cgroups/cpu";
+
+  Fetcher fetcher;
+
+  Try<MesosContainerizer*> _containerizer =
+    MesosContainerizer::create(flags, true, &fetcher);
+
+  ASSERT_SOME(_containerizer);
+
+  Owned<MesosContainerizer> containerizer(_containerizer.get());
+
+  MockResourceEstimator resourceEstimator;
+  EXPECT_CALL(resourceEstimator, initialize(_));
+
+  Queue<Resources> estimations;
+  EXPECT_CALL(resourceEstimator, oversubscribable())
+    .WillRepeatedly(InvokeWithoutArgs(&estimations, &Queue<Resources>::get));
+
+  Owned<MasterDetector> detector = master.get()->createDetector();
+
+  Try<Owned<cluster::Slave>> slave = StartSlave(
+      detector.get(),
+      containerizer.get(),
+      &resourceEstimator,
+      flags);
+
+  ASSERT_SOME(slave);
+
+  // Start the framework which accepts revocable resources.
+  FrameworkInfo frameworkInfo = DEFAULT_FRAMEWORK_INFO;
+  frameworkInfo.add_capabilities()->set_type(
+      FrameworkInfo::Capability::REVOCABLE_RESOURCES);
+
+  MockScheduler sched;
+  MesosSchedulerDriver driver(
+      &sched,
+      frameworkInfo,
+      master.get()->pid,
+      DEFAULT_CREDENTIAL);
+
+  EXPECT_CALL(sched, registered(&driver, _, _))
+    .Times(1);
+
+  Future<vector<Offer>> offers1;
+  EXPECT_CALL(sched, resourceOffers(&driver, _))
+    .WillOnce(FutureArg<1>(&offers1));
+
+  driver.start();
+
+  // Initially the framework will get all regular resources.
+  AWAIT_READY(offers1);
+  EXPECT_NE(0u, offers1.get().size());
+  EXPECT_TRUE(Resources(offers1.get()[0].resources()).revocable().empty());
+
+  Future<vector<Offer>> offers2;
+  EXPECT_CALL(sched, resourceOffers(&driver, _))
+    .WillOnce(FutureArg<1>(&offers2))
+    .WillRepeatedly(Return()); // Ignore subsequent offers.
+
+  // Inject an estimation of revocable cpu resources.
+  Resource cpu = Resources::parse("cpus", "1", "*").get();
+  cpu.mutable_revocable();
+  Resources cpus(cpu);
+  estimations.put(cpus);
+
+  // Now the framework will get revocable resources.
+  AWAIT_READY(offers2);
+  EXPECT_NE(0u, offers2.get().size());
+  EXPECT_EQ(cpus, Resources(offers2.get()[0].resources()));
+
+  TaskInfo task = createTask(
+      offers2.get()[0].slave_id(),
+      cpus,
+      "sleep 120");
+
+  Future<TaskStatus> statusRunning;
+  EXPECT_CALL(sched, statusUpdate(&driver, _))
+    .WillOnce(FutureArg<1>(&statusRunning));
+
+  driver.launchTasks(offers2.get()[0].id(), {task});
+
+  AWAIT_READY(statusRunning);
+  EXPECT_EQ(TASK_RUNNING, statusRunning.get().state());
+
+  Future<hashset<ContainerID>> containers = containerizer->containers();
+  AWAIT_READY(containers);
+  EXPECT_EQ(1u, containers.get().size());
+
+  ContainerID containerId = *(containers.get().begin());
+
+  string cpuHierarchy = path::join(flags.cgroups_hierarchy, "cpu");
+  string cpuCgroup= path::join(flags.cgroups_root, containerId.value());
+
+  double totalCpus = cpus.cpus().get() + DEFAULT_EXECUTOR_CPUS;
+  EXPECT_SOME_EQ(
+      CPU_SHARES_PER_CPU_REVOCABLE * totalCpus,
+      cgroups::cpu::shares(cpuHierarchy, cpuCgroup));
+
+  driver.stop();
+  driver.join();
+}
+
+
+TEST_F(CgroupsIsolatorTest, ROOT_CGROUPS_CFS_EnableCfs)
+{
+  Try<Owned<cluster::Master>> master = StartMaster();
+  ASSERT_SOME(master);
+
+  slave::Flags flags = CreateSlaveFlags();
+  flags.isolation = "cgroups/cpu";
+
+  // Enable CFS to cap CPU utilization.
+  flags.cgroups_enable_cfs = true;
+
+  Fetcher fetcher;
+
+  Try<MesosContainerizer*> _containerizer =
+    MesosContainerizer::create(flags, true, &fetcher);
+
+  ASSERT_SOME(_containerizer);
+
+  Owned<MesosContainerizer> containerizer(_containerizer.get());
+
+  Owned<MasterDetector> detector = master.get()->createDetector();
+
+  Try<Owned<cluster::Slave>> slave = StartSlave(
+      detector.get(),
+      containerizer.get());
+
+  ASSERT_SOME(slave);
+
+  MockScheduler sched;
+  MesosSchedulerDriver driver(
+      &sched,
+      DEFAULT_FRAMEWORK_INFO,
+      master.get()->pid,
+      DEFAULT_CREDENTIAL);
+
+  EXPECT_CALL(sched, registered(&driver, _, _))
+    .Times(1);
+
+  Future<vector<Offer>> offers;
+  EXPECT_CALL(sched, resourceOffers(&driver, _))
+    .WillOnce(FutureArg<1>(&offers))
+    .WillRepeatedly(Return()); // Ignore subsequent offers.
+
+  driver.start();
+
+  AWAIT_READY(offers);
+  EXPECT_NE(0u, offers.get().size());
+
+  // Generate random numbers to max out a single core. We'll run this
+  // for 0.5 seconds of wall time so it should consume approximately
+  // 250 ms of total cpu time when limited to 0.5 cpu. We use
+  // /dev/urandom to prevent blocking on Linux when there's
+  // insufficient entropy.
+  string command =
+    "cat /dev/urandom > /dev/null & "
+    "export MESOS_TEST_PID=$! && "
+    "sleep 0.5 && "
+    "kill $MESOS_TEST_PID";
+
+  ASSERT_GE(Resources(offers.get()[0].resources()).cpus().get(), 0.5);
+
+  TaskInfo task = createTask(
+      offers.get()[0].slave_id(),
+      Resources::parse("cpus:0.5").get(),
+      command);
+
+  Future<TaskStatus> statusRunning;
+  EXPECT_CALL(sched, statusUpdate(&driver, _))
+    .WillOnce(FutureArg<1>(&statusRunning));
+
+  driver.launchTasks(offers.get()[0].id(), {task});
+
+  AWAIT_READY(statusRunning);
+  EXPECT_EQ(TASK_RUNNING, statusRunning.get().state());
+
+  Future<hashset<ContainerID>> containers = containerizer->containers();
+  AWAIT_READY(containers);
+  EXPECT_EQ(1u, containers.get().size());
+
+  ContainerID containerId = *(containers.get().begin());
+
+  Future<ResourceStatistics> usage = containerizer->usage(containerId);
+  AWAIT_READY(usage);
+
+  // Expect that no more than 300 ms of cpu time has been consumed. We
+  // also check that at least 50 ms of cpu time has been consumed so
+  // this test will fail if the host system is very heavily loaded.
+  // This behavior is correct because under such conditions we aren't
+  // actually testing the CFS cpu limiter.
+  double cpuTime = usage.get().cpus_system_time_secs() +
+                   usage.get().cpus_user_time_secs();
+
+  EXPECT_GE(0.30, cpuTime);
+  EXPECT_LE(0.05, cpuTime);
+
+  driver.stop();
+  driver.join();
+}
+
+
+// The test verifies that the number of processes and threads in a
+// container is correctly reported.
+TEST_F(CgroupsIsolatorTest, ROOT_CGROUPS_PidsAndTids)
+{
+  Try<Owned<cluster::Master>> master = StartMaster();
+  ASSERT_SOME(master);
+
+  slave::Flags flags = CreateSlaveFlags();
+  flags.isolation = "cgroups/cpu";
+  flags.cgroups_cpu_enable_pids_and_tids_count = true;
+
+  Fetcher fetcher;
+
+  Try<MesosContainerizer*> _containerizer =
+    MesosContainerizer::create(flags, true, &fetcher);
+
+  ASSERT_SOME(_containerizer);
+
+  Owned<MesosContainerizer> containerizer(_containerizer.get());
+
+  Owned<MasterDetector> detector = master.get()->createDetector();
+
+  Try<Owned<cluster::Slave>> slave = StartSlave(
+      detector.get(),
+      containerizer.get());
+
+  ASSERT_SOME(slave);
+
+  MockScheduler sched;
+  MesosSchedulerDriver driver(
+      &sched,
+      DEFAULT_FRAMEWORK_INFO,
+      master.get()->pid,
+      DEFAULT_CREDENTIAL);
+
+  EXPECT_CALL(sched, registered(&driver, _, _))
+    .Times(1);
+
+  Future<vector<Offer>> offers;
+  EXPECT_CALL(sched, resourceOffers(&driver, _))
+    .WillOnce(FutureArg<1>(&offers))
+    .WillRepeatedly(Return()); // Ignore subsequent offers.
+
+  driver.start();
+
+  AWAIT_READY(offers);
+  EXPECT_NE(0u, offers.get().size());
+
+  CommandInfo command;
+  command.set_shell(false);
+  command.set_value("/bin/cat");
+  command.add_arguments("/bin/cat");
+
+  TaskInfo task = createTask(
+      offers.get()[0].slave_id(),
+      offers.get()[0].resources(),
+      command);
+
+  Future<TaskStatus> statusRunning;
+  EXPECT_CALL(sched, statusUpdate(&driver, _))
+    .WillOnce(FutureArg<1>(&statusRunning));
+
+  driver.launchTasks(offers.get()[0].id(), {task});
+
+  AWAIT_READY(statusRunning);
+  EXPECT_EQ(TASK_RUNNING, statusRunning.get().state());
+
+  Future<hashset<ContainerID>> containers = containerizer->containers();
+  AWAIT_READY(containers);
+  EXPECT_EQ(1u, containers.get().size());
+
+  ContainerID containerId = *(containers.get().begin());
+
+  Future<ResourceStatistics> usage = containerizer->usage(containerId);
+  AWAIT_READY(usage);
+
+  // The possible running processes during capture process number.
+  //   - src/.libs/mesos-executor
+  //   - src/mesos-executor
+  //   - src/.libs/mesos-containerizer
+  //   - src/mesos-containerizer
+  //   - cat
+  // For `cat` and `mesos-executor`, they keep idling during running
+  // the test case. For other processes, they may occur temporarily.
+  EXPECT_GE(usage.get().processes(), 2U);
+  EXPECT_GE(usage.get().threads(), 2U);
+
+  driver.stop();
+  driver.join();
+}
+
 } // namespace tests {
 } // namespace internal {
 } // namespace mesos {

http://git-wip-us.apache.org/repos/asf/mesos/blob/451f65fd/src/tests/containerizer/cpu_isolator_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/containerizer/cpu_isolator_tests.cpp b/src/tests/containerizer/cpu_isolator_tests.cpp
new file mode 100644
index 0000000..c8755f1
--- /dev/null
+++ b/src/tests/containerizer/cpu_isolator_tests.cpp
@@ -0,0 +1,249 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <string>
+#include <vector>
+
+#include <process/gtest.hpp>
+
+#include <stout/gtest.hpp>
+
+#include "slave/containerizer/mesos/containerizer.hpp"
+
+#include "tests/mesos.hpp"
+
+using mesos::internal::master::Master;
+
+using mesos::internal::slave::Fetcher;
+using mesos::internal::slave::MesosContainerizer;
+
+using mesos::master::detector::MasterDetector;
+
+using process::Future;
+using process::Owned;
+
+using std::string;
+using std::vector;
+
+using testing::WithParamInterface;
+
+namespace mesos {
+namespace internal {
+namespace tests {
+
+class CpuIsolatorTest
+  : public MesosTest,
+    public WithParamInterface<string> {};
+
+
+// These tests are parameterized by the isolation flag.
+INSTANTIATE_TEST_CASE_P(
+    IsolationFlag,
+    CpuIsolatorTest,
+#ifdef __linux__
+    ::testing::Values("posix/cpu", "cgroups/cpu"));
+#else
+    ::testing::Values("posix/cpu"));
+#endif // __linux__
+
+
+TEST_P(CpuIsolatorTest, ROOT_UserCpuUsage)
+{
+  Try<Owned<cluster::Master>> master = StartMaster();
+  ASSERT_SOME(master);
+
+  slave::Flags flags = CreateSlaveFlags();
+  flags.isolation = GetParam();
+
+  Fetcher fetcher;
+
+  Try<MesosContainerizer*> _containerizer =
+    MesosContainerizer::create(flags, true, &fetcher);
+
+  ASSERT_SOME(_containerizer);
+
+  Owned<MesosContainerizer> containerizer(_containerizer.get());
+
+  Owned<MasterDetector> detector = master.get()->createDetector();
+
+  Try<Owned<cluster::Slave>> slave = StartSlave(
+      detector.get(),
+      containerizer.get());
+
+  ASSERT_SOME(slave);
+
+  MockScheduler sched;
+  MesosSchedulerDriver driver(
+      &sched,
+      DEFAULT_FRAMEWORK_INFO,
+      master.get()->pid,
+      DEFAULT_CREDENTIAL);
+
+  EXPECT_CALL(sched, registered(&driver, _, _))
+    .Times(1);
+
+  Future<vector<Offer>> offers;
+  EXPECT_CALL(sched, resourceOffers(&driver, _))
+    .WillOnce(FutureArg<1>(&offers))
+    .WillRepeatedly(Return()); // Ignore subsequent offers.
+
+  driver.start();
+
+  AWAIT_READY(offers);
+  EXPECT_NE(0u, offers.get().size());
+
+  // Max out a single core in userspace. This will run for at most one
+  // second.
+  TaskInfo task = createTask(
+      offers.get()[0],
+      "while true ; do true ; done & sleep 60");
+
+  Future<TaskStatus> statusRunning;
+  EXPECT_CALL(sched, statusUpdate(&driver, _))
+    .WillOnce(FutureArg<1>(&statusRunning));
+
+  driver.launchTasks(offers.get()[0].id(), {task});
+
+  AWAIT_READY(statusRunning);
+  EXPECT_EQ(TASK_RUNNING, statusRunning.get().state());
+
+  Future<hashset<ContainerID>> containers = containerizer->containers();
+  AWAIT_READY(containers);
+  EXPECT_EQ(1u, containers.get().size());
+
+  ContainerID containerId = *(containers.get().begin());
+
+  // Wait up to 1 second for the child process to induce 1/8 of a
+  // second of user cpu time.
+  ResourceStatistics statistics;
+  Duration waited = Duration::zero();
+  do {
+    Future<ResourceStatistics> usage = containerizer->usage(containerId);
+    AWAIT_READY(usage);
+
+    statistics = usage.get();
+
+    // If we meet our usage expectations, we're done!
+    if (statistics.cpus_user_time_secs() >= 0.125) {
+      break;
+    }
+
+    os::sleep(Milliseconds(200));
+    waited += Milliseconds(200);
+  } while (waited < Seconds(1));
+
+  EXPECT_LE(0.125, statistics.cpus_user_time_secs());
+
+  driver.stop();
+  driver.join();
+}
+
+
+TEST_P(CpuIsolatorTest, ROOT_SystemCpuUsage)
+{
+  Try<Owned<cluster::Master>> master = StartMaster();
+  ASSERT_SOME(master);
+
+  slave::Flags flags = CreateSlaveFlags();
+  flags.isolation = GetParam();
+
+  Fetcher fetcher;
+
+  Try<MesosContainerizer*> _containerizer =
+    MesosContainerizer::create(flags, true, &fetcher);
+
+  ASSERT_SOME(_containerizer);
+
+  Owned<MesosContainerizer> containerizer(_containerizer.get());
+
+  Owned<MasterDetector> detector = master.get()->createDetector();
+
+  Try<Owned<cluster::Slave>> slave = StartSlave(
+      detector.get(),
+      containerizer.get());
+
+  ASSERT_SOME(slave);
+
+  MockScheduler sched;
+  MesosSchedulerDriver driver(
+      &sched,
+      DEFAULT_FRAMEWORK_INFO,
+      master.get()->pid,
+      DEFAULT_CREDENTIAL);
+
+  EXPECT_CALL(sched, registered(&driver, _, _))
+    .Times(1);
+
+  Future<vector<Offer>> offers;
+  EXPECT_CALL(sched, resourceOffers(&driver, _))
+    .WillOnce(FutureArg<1>(&offers))
+    .WillRepeatedly(Return()); // Ignore subsequent offers.
+
+  driver.start();
+
+  AWAIT_READY(offers);
+  EXPECT_NE(0u, offers.get().size());
+
+  // Generating random numbers is done by the kernel and will max out
+  // a single core and run almost exclusively in the kernel, i.e.,
+  // system time.
+  TaskInfo task = createTask(
+      offers.get()[0],
+      "cat /dev/urandom > /dev/null & sleep 60");
+
+  Future<TaskStatus> statusRunning;
+  EXPECT_CALL(sched, statusUpdate(&driver, _))
+    .WillOnce(FutureArg<1>(&statusRunning));
+
+  driver.launchTasks(offers.get()[0].id(), {task});
+
+  AWAIT_READY(statusRunning);
+  EXPECT_EQ(TASK_RUNNING, statusRunning.get().state());
+
+  Future<hashset<ContainerID>> containers = containerizer->containers();
+  AWAIT_READY(containers);
+  EXPECT_EQ(1u, containers.get().size());
+
+  ContainerID containerId = *(containers.get().begin());
+
+  // Wait up to 1 second for the child process to induce 1/8 of a
+  // second of user cpu time.
+  ResourceStatistics statistics;
+  Duration waited = Duration::zero();
+  do {
+    Future<ResourceStatistics> usage = containerizer->usage(containerId);
+    AWAIT_READY(usage);
+
+    statistics = usage.get();
+
+    // If we meet our usage expectations, we're done!
+    if (statistics.cpus_system_time_secs() >= 0.125) {
+      break;
+    }
+
+    os::sleep(Milliseconds(200));
+    waited += Milliseconds(200);
+  } while (waited < Seconds(1));
+
+  EXPECT_LE(0.125, statistics.cpus_user_time_secs());
+
+  driver.stop();
+  driver.join();
+}
+
+} // namespace tests {
+} // namespace internal {
+} // namespace mesos {


[17/17] mesos git commit: Refactored mem isolator associated test cases.

Posted by ji...@apache.org.
Refactored mem isolator associated test cases.

Review: https://reviews.apache.org/r/51788/


Project: http://git-wip-us.apache.org/repos/asf/mesos/repo
Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/612efe29
Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/612efe29
Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/612efe29

Branch: refs/heads/master
Commit: 612efe291804fc5544125ae201935a4ffc91c4b0
Parents: 6cfa4a6
Author: haosdent huang <ha...@gmail.com>
Authored: Mon Sep 12 16:35:08 2016 -0700
Committer: Jie Yu <yu...@gmail.com>
Committed: Tue Sep 13 10:52:01 2016 -0700

----------------------------------------------------------------------
 src/Makefile.am                                 |   1 +
 .../containerizer/memory_isolator_tests.cpp     | 138 +++++++++++++++++++
 2 files changed, 139 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/612efe29/src/Makefile.am
----------------------------------------------------------------------
diff --git a/src/Makefile.am b/src/Makefile.am
index 5d38747..b6b64bc 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -2140,6 +2140,7 @@ mesos_tests_SOURCES =						\
   tests/containerizer/docker_tests.cpp				\
   tests/containerizer/isolator_tests.cpp			\
   tests/containerizer/launcher.cpp				\
+  tests/containerizer/memory_isolator_tests.cpp			\
   tests/containerizer/memory_test_helper.cpp			\
   tests/containerizer/mesos_containerizer_tests.cpp		\
   tests/containerizer/provisioner_appc_tests.cpp		\

http://git-wip-us.apache.org/repos/asf/mesos/blob/612efe29/src/tests/containerizer/memory_isolator_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/containerizer/memory_isolator_tests.cpp b/src/tests/containerizer/memory_isolator_tests.cpp
new file mode 100644
index 0000000..39f29f4
--- /dev/null
+++ b/src/tests/containerizer/memory_isolator_tests.cpp
@@ -0,0 +1,138 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <string>
+#include <vector>
+
+#include <process/gtest.hpp>
+
+#include <stout/gtest.hpp>
+
+#include "slave/containerizer/mesos/containerizer.hpp"
+
+#include "tests/mesos.hpp"
+
+using mesos::internal::master::Master;
+
+using mesos::internal::slave::Fetcher;
+using mesos::internal::slave::MesosContainerizer;
+
+using mesos::master::detector::MasterDetector;
+
+using process::Future;
+using process::Owned;
+
+using std::string;
+using std::vector;
+
+using testing::WithParamInterface;
+
+namespace mesos {
+namespace internal {
+namespace tests {
+
+class MemoryIsolatorTest
+  : public MesosTest,
+    public WithParamInterface<string> {};
+
+
+// These tests are parameterized by the isolation flag.
+INSTANTIATE_TEST_CASE_P(
+    IsolationFlag,
+    MemoryIsolatorTest,
+#ifdef __linux__
+    ::testing::Values("posix/mem", "cgroups/mem"));
+#else
+    ::testing::Values("posix/mem"));
+#endif // __linux__
+
+
+TEST_P(MemoryIsolatorTest, ROOT_MemUsage)
+{
+  Try<Owned<cluster::Master>> master = StartMaster();
+  ASSERT_SOME(master);
+
+  slave::Flags flags = CreateSlaveFlags();
+  flags.isolation = GetParam();
+
+  Fetcher fetcher;
+
+  Try<MesosContainerizer*> _containerizer =
+    MesosContainerizer::create(flags, true, &fetcher);
+
+  ASSERT_SOME(_containerizer);
+
+  Owned<MesosContainerizer> containerizer(_containerizer.get());
+
+  Owned<MasterDetector> detector = master.get()->createDetector();
+
+  Try<Owned<cluster::Slave>> slave = StartSlave(
+      detector.get(),
+      containerizer.get());
+
+  ASSERT_SOME(slave);
+
+  MockScheduler sched;
+  MesosSchedulerDriver driver(
+      &sched,
+      DEFAULT_FRAMEWORK_INFO,
+      master.get()->pid,
+      DEFAULT_CREDENTIAL);
+
+  EXPECT_CALL(sched, registered(&driver, _, _))
+    .Times(1);
+
+  Future<vector<Offer>> offers;
+  EXPECT_CALL(sched, resourceOffers(&driver, _))
+    .WillOnce(FutureArg<1>(&offers))
+    .WillRepeatedly(Return()); // Ignore subsequent offers.
+
+  driver.start();
+
+  AWAIT_READY(offers);
+  EXPECT_NE(0u, offers.get().size());
+
+  TaskInfo task = createTask(offers.get()[0], "sleep 120");
+
+  Future<TaskStatus> statusRunning;
+  EXPECT_CALL(sched, statusUpdate(&driver, _))
+    .WillOnce(FutureArg<1>(&statusRunning));
+
+  driver.launchTasks(offers.get()[0].id(), {task});
+
+  AWAIT_READY(statusRunning);
+  EXPECT_EQ(TASK_RUNNING, statusRunning.get().state());
+
+  Future<hashset<ContainerID>> containers = containerizer->containers();
+  AWAIT_READY(containers);
+  EXPECT_EQ(1u, containers.get().size());
+
+  ContainerID containerId = *(containers.get().begin());
+
+  Future<ResourceStatistics> usage = containerizer->usage(containerId);
+  AWAIT_READY(usage);
+
+  // TODO(jieyu): Consider using a program that predictably increases
+  // RSS so that we can set more meaningful expectation here.
+  EXPECT_GT(usage.get().mem_rss_bytes(), 0);
+
+  driver.stop();
+  driver.join();
+}
+
+} // namespace tests {
+} // namespace internal {
+} // namespace mesos {


[07/17] mesos git commit: Removed CgroupsCpushareIsolatorProcess.

Posted by ji...@apache.org.
Removed CgroupsCpushareIsolatorProcess.

Review: https://reviews.apache.org/r/50733/


Project: http://git-wip-us.apache.org/repos/asf/mesos/repo
Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/c3d1f776
Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/c3d1f776
Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/c3d1f776

Branch: refs/heads/master
Commit: c3d1f7761297aea52d5e5ef5fe460807a3d59b3a
Parents: e2fea32
Author: haosdent huang <ha...@gmail.com>
Authored: Mon Sep 12 16:34:37 2016 -0700
Committer: Jie Yu <yu...@gmail.com>
Committed: Tue Sep 13 10:52:01 2016 -0700

----------------------------------------------------------------------
 src/CMakeLists.txt                              |   1 -
 src/Makefile.am                                 |   2 -
 src/docker/docker.cpp                           |   2 +-
 src/slave/containerizer/mesos/containerizer.cpp |   1 -
 .../mesos/isolators/cgroups/cpushare.cpp        | 571 ---------------
 .../mesos/isolators/cgroups/cpushare.hpp        | 118 ---
 src/tests/containerizer/isolator_tests.cpp      | 725 -------------------
 7 files changed, 1 insertion(+), 1419 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/c3d1f776/src/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 01ef494..414e723 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -159,7 +159,6 @@ set(LINUX_SRC
   slave/containerizer/mesos/linux_launcher.cpp
   slave/containerizer/mesos/isolators/appc/runtime.cpp
   slave/containerizer/mesos/isolators/cgroups/cgroups.cpp
-  slave/containerizer/mesos/isolators/cgroups/cpushare.cpp
   slave/containerizer/mesos/isolators/cgroups/devices.cpp
   slave/containerizer/mesos/isolators/cgroups/mem.cpp
   slave/containerizer/mesos/isolators/cgroups/net_cls.cpp

http://git-wip-us.apache.org/repos/asf/mesos/blob/c3d1f776/src/Makefile.am
----------------------------------------------------------------------
diff --git a/src/Makefile.am b/src/Makefile.am
index 2dd7913..2ef8a21 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1025,7 +1025,6 @@ MESOS_LINUX_FILES =									\
   slave/containerizer/mesos/linux_launcher.cpp						\
   slave/containerizer/mesos/isolators/appc/runtime.cpp					\
   slave/containerizer/mesos/isolators/cgroups/cgroups.cpp				\
-  slave/containerizer/mesos/isolators/cgroups/cpushare.cpp				\
   slave/containerizer/mesos/isolators/cgroups/devices.cpp				\
   slave/containerizer/mesos/isolators/cgroups/mem.cpp					\
   slave/containerizer/mesos/isolators/cgroups/net_cls.cpp				\
@@ -1066,7 +1065,6 @@ MESOS_LINUX_FILES +=									\
   slave/containerizer/mesos/isolators/appc/runtime.hpp					\
   slave/containerizer/mesos/isolators/cgroups/cgroups.hpp				\
   slave/containerizer/mesos/isolators/cgroups/constants.hpp				\
-  slave/containerizer/mesos/isolators/cgroups/cpushare.hpp				\
   slave/containerizer/mesos/isolators/cgroups/devices.hpp				\
   slave/containerizer/mesos/isolators/cgroups/mem.hpp					\
   slave/containerizer/mesos/isolators/cgroups/net_cls.hpp				\

http://git-wip-us.apache.org/repos/asf/mesos/blob/c3d1f776/src/docker/docker.cpp
----------------------------------------------------------------------
diff --git a/src/docker/docker.cpp b/src/docker/docker.cpp
index 16abf64..44036c1 100755
--- a/src/docker/docker.cpp
+++ b/src/docker/docker.cpp
@@ -42,7 +42,7 @@
 #include "linux/cgroups.hpp"
 #endif // __linux__
 
-#include "slave/containerizer/mesos/isolators/cgroups/cpushare.hpp"
+#include "slave/containerizer/mesos/isolators/cgroups/constants.hpp"
 #include "slave/containerizer/mesos/isolators/cgroups/mem.hpp"
 
 #include "slave/constants.hpp"

http://git-wip-us.apache.org/repos/asf/mesos/blob/c3d1f776/src/slave/containerizer/mesos/containerizer.cpp
----------------------------------------------------------------------
diff --git a/src/slave/containerizer/mesos/containerizer.cpp b/src/slave/containerizer/mesos/containerizer.cpp
index 24b0585..0b240d4 100644
--- a/src/slave/containerizer/mesos/containerizer.cpp
+++ b/src/slave/containerizer/mesos/containerizer.cpp
@@ -73,7 +73,6 @@
 
 #ifdef __linux__
 #include "slave/containerizer/mesos/isolators/cgroups/cgroups.hpp"
-#include "slave/containerizer/mesos/isolators/cgroups/cpushare.hpp"
 #include "slave/containerizer/mesos/isolators/cgroups/devices.hpp"
 #include "slave/containerizer/mesos/isolators/cgroups/mem.hpp"
 #include "slave/containerizer/mesos/isolators/cgroups/net_cls.hpp"

http://git-wip-us.apache.org/repos/asf/mesos/blob/c3d1f776/src/slave/containerizer/mesos/isolators/cgroups/cpushare.cpp
----------------------------------------------------------------------
diff --git a/src/slave/containerizer/mesos/isolators/cgroups/cpushare.cpp b/src/slave/containerizer/mesos/isolators/cgroups/cpushare.cpp
deleted file mode 100644
index 221e814..0000000
--- a/src/slave/containerizer/mesos/isolators/cgroups/cpushare.cpp
+++ /dev/null
@@ -1,571 +0,0 @@
-// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements.  See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership.  The ASF licenses this file
-// to you under the Apache License, Version 2.0 (the
-// "License"); you may not use this file except in compliance
-// with the License.  You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include <stdint.h>
-
-#include <mesos/type_utils.hpp>
-#include <mesos/values.hpp>
-
-#include <process/collect.hpp>
-#include <process/defer.hpp>
-#include <process/id.hpp>
-#include <process/pid.hpp>
-
-#include <stout/bytes.hpp>
-#include <stout/check.hpp>
-#include <stout/error.hpp>
-#include <stout/foreach.hpp>
-#include <stout/hashset.hpp>
-#include <stout/nothing.hpp>
-#include <stout/os.hpp>
-#include <stout/path.hpp>
-#include <stout/stringify.hpp>
-#include <stout/try.hpp>
-
-#include "linux/cgroups.hpp"
-
-#include "slave/containerizer/mesos/isolators/cgroups/cpushare.hpp"
-
-using namespace process;
-
-using std::list;
-using std::set;
-using std::string;
-using std::vector;
-
-using mesos::slave::ContainerConfig;
-using mesos::slave::ContainerLaunchInfo;
-using mesos::slave::ContainerLimitation;
-using mesos::slave::ContainerState;
-using mesos::slave::Isolator;
-
-namespace mesos {
-namespace internal {
-namespace slave {
-
-CgroupsCpushareIsolatorProcess::CgroupsCpushareIsolatorProcess(
-    const Flags& _flags,
-    const hashmap<string, string>& _hierarchies,
-    const vector<string>& _subsystems)
-  : ProcessBase(process::ID::generate("cgroups-cpushare-isolator")),
-    flags(_flags),
-    hierarchies(_hierarchies),
-    subsystems(_subsystems) {}
-
-
-CgroupsCpushareIsolatorProcess::~CgroupsCpushareIsolatorProcess() {}
-
-
-Try<Isolator*> CgroupsCpushareIsolatorProcess::create(const Flags& flags)
-{
-  Try<string> hierarchyCpu = cgroups::prepare(
-        flags.cgroups_hierarchy,
-        "cpu",
-        flags.cgroups_root);
-
-  if (hierarchyCpu.isError()) {
-    return Error(
-        "Failed to prepare hierarchy for cpu subsystem: " +
-        hierarchyCpu.error());
-  }
-
-  Try<string> hierarchyCpuacct = cgroups::prepare(
-        flags.cgroups_hierarchy,
-        "cpuacct",
-        flags.cgroups_root);
-
-  if (hierarchyCpuacct.isError()) {
-    return Error(
-        "Failed to prepare hierarchy for cpuacct subsystem: " +
-        hierarchyCpuacct.error());
-  }
-
-  hashmap<string, string> hierarchies;
-  vector<string> subsystems;
-
-  hierarchies["cpu"] = hierarchyCpu.get();
-  hierarchies["cpuacct"] = hierarchyCpuacct.get();
-
-  if (hierarchyCpu.get() == hierarchyCpuacct.get()) {
-    // Subsystem cpu and cpuacct are co-mounted (e.g., systemd).
-    hierarchies["cpu,cpuacct"] = hierarchyCpu.get();
-    subsystems.push_back("cpu,cpuacct");
-
-    // Ensure that no other subsystem is attached to the hierarchy.
-    Try<set<string>> _subsystems = cgroups::subsystems(hierarchyCpu.get());
-    if (_subsystems.isError()) {
-      return Error(
-          "Failed to get the list of attached subsystems for hierarchy " +
-          hierarchyCpu.get());
-    } else if (_subsystems.get().size() != 2) {
-      return Error(
-          "Unexpected subsystems found attached to the hierarchy " +
-          hierarchyCpu.get());
-    }
-  } else {
-    // Subsystem cpu and cpuacct are mounted separately.
-    subsystems.push_back("cpu");
-    subsystems.push_back("cpuacct");
-
-    // Ensure that no other subsystem is attached to each of the
-    // hierarchy.
-    Try<set<string>> _subsystems = cgroups::subsystems(hierarchyCpu.get());
-    if (_subsystems.isError()) {
-      return Error(
-          "Failed to get the list of attached subsystems for hierarchy " +
-          hierarchyCpu.get());
-    } else if (_subsystems.get().size() != 1) {
-      return Error(
-          "Unexpected subsystems found attached to the hierarchy " +
-          hierarchyCpu.get());
-    }
-
-    _subsystems = cgroups::subsystems(hierarchyCpuacct.get());
-    if (_subsystems.isError()) {
-      return Error(
-          "Failed to get the list of attached subsystems for hierarchy " +
-          hierarchyCpuacct.get());
-    } else if (_subsystems.get().size() != 1) {
-      return Error(
-          "Unexpected subsystems found attached to the hierarchy " +
-          hierarchyCpuacct.get());
-    }
-  }
-
-  if (flags.cgroups_enable_cfs) {
-    Try<bool> exists = cgroups::exists(
-        hierarchies["cpu"],
-        flags.cgroups_root,
-        "cpu.cfs_quota_us");
-
-    if (exists.isError() || !exists.get()) {
-      return Error(
-          "Failed to find 'cpu.cfs_quota_us'. Your kernel "
-          "might be too old to use the CFS cgroups feature.");
-    }
-  }
-
-  process::Owned<MesosIsolatorProcess> process(
-      new CgroupsCpushareIsolatorProcess(flags, hierarchies, subsystems));
-
-  return new MesosIsolator(process);
-}
-
-
-Future<Nothing> CgroupsCpushareIsolatorProcess::recover(
-    const list<ContainerState>& states,
-    const hashset<ContainerID>& orphans)
-{
-  foreach (const ContainerState& state, states) {
-    const ContainerID& containerId = state.container_id();
-    const string cgroup = path::join(flags.cgroups_root, containerId.value());
-
-    Try<bool> exists = cgroups::exists(hierarchies["cpu"], cgroup);
-    if (exists.isError()) {
-      foreachvalue (Info* info, infos) {
-        delete info;
-      }
-      infos.clear();
-      return Failure(
-          "Failed to check cgroup for container " + stringify(containerId));
-    }
-
-    if (!exists.get()) {
-      // This may occur if the executor has exited and the isolator
-      // has destroyed the cgroup but the slave dies before noticing
-      // this. This will be detected when the containerizer tries to
-      // monitor the executor's pid.
-      LOG(WARNING) << "Couldn't find cgroup for container " << containerId;
-      continue;
-    }
-
-    infos[containerId] = new Info(containerId, cgroup);
-  }
-
-  // Remove orphan cgroups.
-  foreach (const string& subsystem, subsystems) {
-    Try<vector<string>> cgroups = cgroups::get(
-        hierarchies[subsystem],
-        flags.cgroups_root);
-
-    if (cgroups.isError()) {
-      foreachvalue (Info* info, infos) {
-        delete info;
-      }
-      infos.clear();
-      return Failure(cgroups.error());
-    }
-
-    foreach (const string& cgroup, cgroups.get()) {
-      // Ignore the slave cgroup (see the --agent_subsystems flag).
-      // TODO(idownes): Remove this when the cgroups layout is
-      // updated, see MESOS-1185.
-      if (cgroup == path::join(flags.cgroups_root, "slave")) {
-        continue;
-      }
-
-      ContainerID containerId;
-      containerId.set_value(Path(cgroup).basename());
-
-      if (infos.contains(containerId)) {
-        continue;
-      }
-
-      // Known orphan cgroups will be destroyed by the containerizer
-      // using the normal cleanup path. See MESOS-2367 for details.
-      if (orphans.contains(containerId)) {
-        infos[containerId] = new Info(containerId, cgroup);
-        continue;
-      }
-
-      LOG(INFO) << "Removing unknown orphaned cgroup '"
-                << path::join(subsystem, cgroup) << "'";
-
-      // We don't wait on the destroy as we don't want to block recovery.
-      cgroups::destroy(
-          hierarchies[subsystem],
-          cgroup,
-          cgroups::DESTROY_TIMEOUT);
-    }
-  }
-
-  return Nothing();
-}
-
-
-Future<Option<ContainerLaunchInfo>> CgroupsCpushareIsolatorProcess::prepare(
-    const ContainerID& containerId,
-    const ContainerConfig& containerConfig)
-{
-  if (infos.contains(containerId)) {
-    return Failure("Container has already been prepared");
-  }
-
-  // TODO(bmahler): Don't insert into 'infos' unless we create the
-  // cgroup successfully. It's safe for now because 'cleanup' gets
-  // called if we return a Failure, but cleanup will fail because the
-  // cgroup does not exist when cgroups::destroy is called.
-  Info* info = new Info(
-      containerId, path::join(flags.cgroups_root, containerId.value()));
-
-  infos[containerId] = info;
-
-  foreach (const string& subsystem, subsystems) {
-    Try<bool> exists = cgroups::exists(hierarchies[subsystem], info->cgroup);
-    if (exists.isError()) {
-      return Failure("Failed to prepare isolator: " + exists.error());
-    } else if (exists.get()) {
-      return Failure("Failed to prepare isolator: cgroup already exists");
-    }
-
-    Try<Nothing> create = cgroups::create(hierarchies[subsystem], info->cgroup);
-    if (create.isError()) {
-      return Failure("Failed to prepare isolator: " + create.error());
-    }
-
-    // Chown the cgroup so the executor can create nested cgroups. Do
-    // not recurse so the control files are still owned by the slave
-    // user and thus cannot be changed by the executor.
-    if (containerConfig.has_user()) {
-      Try<Nothing> chown = os::chown(
-          containerConfig.user(),
-          path::join(hierarchies[subsystem], info->cgroup),
-          false);
-      if (chown.isError()) {
-        return Failure("Failed to prepare isolator: " + chown.error());
-      }
-    }
-  }
-
-  return update(containerId, containerConfig.executor_info().resources())
-    .then([]() -> Future<Option<ContainerLaunchInfo>> {
-      return None();
-    });
-}
-
-
-Future<Nothing> CgroupsCpushareIsolatorProcess::isolate(
-    const ContainerID& containerId,
-    pid_t pid)
-{
-  if (!infos.contains(containerId)) {
-    return Failure("Unknown container");
-  }
-
-  Info* info = CHECK_NOTNULL(infos[containerId]);
-
-  CHECK_NONE(info->pid);
-  info->pid = pid;
-
-  foreach (const string& subsystem, subsystems) {
-    Try<Nothing> assign = cgroups::assign(
-        hierarchies[subsystem],
-        info->cgroup,
-        pid);
-
-    if (assign.isError()) {
-      LOG(ERROR) << "Failed to assign container '" << info->containerId
-                 << " to its own cgroup '"
-                 << path::join(hierarchies[subsystem], info->cgroup)
-                 << "' : " << assign.error();
-
-      return Failure("Failed to isolate container: " + assign.error());
-    }
-  }
-
-  return Nothing();
-}
-
-
-Future<ContainerLimitation> CgroupsCpushareIsolatorProcess::watch(
-    const ContainerID& containerId)
-{
-  if (!infos.contains(containerId)) {
-    return Failure("Unknown container");
-  }
-
-  CHECK_NOTNULL(infos[containerId]);
-
-  return infos[containerId]->limitation.future();
-}
-
-
-Future<Nothing> CgroupsCpushareIsolatorProcess::update(
-    const ContainerID& containerId,
-    const Resources& resources)
-{
-  if (resources.cpus().isNone()) {
-    return Failure("No cpus resource given");
-  }
-
-  if (!infos.contains(containerId)) {
-    return Failure("Unknown container");
-  }
-
-  const Option<string>& hierarchy = hierarchies.get("cpu");
-  if (hierarchy.isNone()) {
-    return Failure("No 'cpu' hierarchy");
-  }
-
-  Info* info = CHECK_NOTNULL(infos[containerId]);
-  info->resources = resources;
-
-  double cpus = resources.cpus().get();
-
-  // Always set cpu.shares.
-  uint64_t shares;
-
-  if (flags.revocable_cpu_low_priority &&
-      resources.revocable().cpus().isSome()) {
-    shares = std::max(
-        (uint64_t) (CPU_SHARES_PER_CPU_REVOCABLE * cpus),
-        MIN_CPU_SHARES);
-  } else {
-    shares = std::max(
-        (uint64_t) (CPU_SHARES_PER_CPU * cpus),
-        MIN_CPU_SHARES);
-  }
-
-  Try<Nothing> write = cgroups::cpu::shares(
-      hierarchy.get(),
-      info->cgroup,
-      shares);
-
-  if (write.isError()) {
-    return Failure("Failed to update 'cpu.shares': " + write.error());
-  }
-
-  LOG(INFO) << "Updated 'cpu.shares' to " << shares
-            << " (cpus " << cpus << ")"
-            << " for container " << containerId;
-
-  // Set cfs quota if enabled.
-  if (flags.cgroups_enable_cfs) {
-    write = cgroups::cpu::cfs_period_us(
-        hierarchy.get(),
-        info->cgroup,
-        CPU_CFS_PERIOD);
-
-    if (write.isError()) {
-      return Failure("Failed to update 'cpu.cfs_period_us': " + write.error());
-    }
-
-    Duration quota = std::max(CPU_CFS_PERIOD * cpus, MIN_CPU_CFS_QUOTA);
-
-    write = cgroups::cpu::cfs_quota_us(hierarchy.get(), info->cgroup, quota);
-    if (write.isError()) {
-      return Failure("Failed to update 'cpu.cfs_quota_us': " + write.error());
-    }
-
-    LOG(INFO) << "Updated 'cpu.cfs_period_us' to " << CPU_CFS_PERIOD
-              << " and 'cpu.cfs_quota_us' to " << quota
-              << " (cpus " << cpus << ")"
-              << " for container " << containerId;
-  }
-
-  return Nothing();
-}
-
-
-Future<ResourceStatistics> CgroupsCpushareIsolatorProcess::usage(
-    const ContainerID& containerId)
-{
-  if (!infos.contains(containerId)) {
-    return Failure("Unknown container");
-  }
-
-  Info* info = CHECK_NOTNULL(infos[containerId]);
-
-  ResourceStatistics result;
-
-  // TODO(chzhcn): Getting the number of processes and threads is
-  // available as long as any cgroup subsystem is used so this best
-  // not be tied to a specific cgroup isolator. A better place is
-  // probably Linux Launcher, which uses the cgroup freezer subsystem.
-  // That requires some change for it to adopt the new semantics of
-  // reporting subsystem-independent cgroup usage.
-  // Note: The complexity of this operation is linear to the number of
-  // processes and threads in a container: the kernel has to allocate
-  // memory to contain the list of pids or tids; the userspace has to
-  // parse the cgroup files to get the size. If this proves to be a
-  // performance bottleneck, some kind of rate limiting mechanism
-  // needs to be employed.
-  if (flags.cgroups_cpu_enable_pids_and_tids_count) {
-    Try<std::set<pid_t>> pids =
-      cgroups::processes(hierarchies["cpuacct"], info->cgroup);
-    if (pids.isError()) {
-      return Failure("Failed to get number of processes: " + pids.error());
-    }
-
-    result.set_processes(pids.get().size());
-
-    Try<std::set<pid_t>> tids =
-      cgroups::threads(hierarchies["cpuacct"], info->cgroup);
-    if (tids.isError()) {
-      return Failure("Failed to get number of threads: " + tids.error());
-    }
-
-    result.set_threads(tids.get().size());
-  }
-
-  // Get the number of clock ticks, used for cpu accounting.
-  static long ticks = sysconf(_SC_CLK_TCK);
-
-  PCHECK(ticks > 0) << "Failed to get sysconf(_SC_CLK_TCK)";
-
-  // Add the cpuacct.stat information.
-  Try<hashmap<string, uint64_t>> stat = cgroups::stat(
-      hierarchies["cpuacct"],
-      info->cgroup,
-      "cpuacct.stat");
-
-  if (stat.isError()) {
-    return Failure("Failed to read cpuacct.stat: " + stat.error());
-  }
-
-  // TODO(bmahler): Add namespacing to cgroups to enforce the expected
-  // structure, e.g., cgroups::cpuacct::stat.
-  Option<uint64_t> user = stat.get().get("user");
-  Option<uint64_t> system = stat.get().get("system");
-
-  if (user.isSome() && system.isSome()) {
-    result.set_cpus_user_time_secs((double) user.get() / (double) ticks);
-    result.set_cpus_system_time_secs((double) system.get() / (double) ticks);
-  }
-
-  // Add the cpu.stat information only if CFS is enabled.
-  if (flags.cgroups_enable_cfs) {
-    stat = cgroups::stat(hierarchies["cpu"], info->cgroup, "cpu.stat");
-    if (stat.isError()) {
-      return Failure("Failed to read cpu.stat: " + stat.error());
-    }
-
-    Option<uint64_t> nr_periods = stat.get().get("nr_periods");
-    if (nr_periods.isSome()) {
-      result.set_cpus_nr_periods(nr_periods.get());
-    }
-
-    Option<uint64_t> nr_throttled = stat.get().get("nr_throttled");
-    if (nr_throttled.isSome()) {
-      result.set_cpus_nr_throttled(nr_throttled.get());
-    }
-
-    Option<uint64_t> throttled_time = stat.get().get("throttled_time");
-    if (throttled_time.isSome()) {
-      result.set_cpus_throttled_time_secs(
-          Nanoseconds(throttled_time.get()).secs());
-    }
-  }
-
-  return result;
-}
-
-
-Future<Nothing> CgroupsCpushareIsolatorProcess::cleanup(
-    const ContainerID& containerId)
-{
-  // Multiple calls may occur during test clean up.
-  if (!infos.contains(containerId)) {
-    VLOG(1) << "Ignoring cleanup request for unknown container: "
-            << containerId;
-
-    return Nothing();
-  }
-
-  Info* info = CHECK_NOTNULL(infos[containerId]);
-
-  list<Future<Nothing>> futures;
-  foreach (const string& subsystem, subsystems) {
-    futures.push_back(cgroups::destroy(
-        hierarchies[subsystem],
-        info->cgroup,
-        cgroups::DESTROY_TIMEOUT));
-  }
-
-  return collect(futures)
-    .onAny(defer(PID<CgroupsCpushareIsolatorProcess>(this),
-                &CgroupsCpushareIsolatorProcess::_cleanup,
-                containerId,
-                lambda::_1))
-    .then([]() { return Nothing(); });
-}
-
-
-Future<list<Nothing>> CgroupsCpushareIsolatorProcess::_cleanup(
-    const ContainerID& containerId,
-    const Future<list<Nothing>>& future)
-{
-  if (!infos.contains(containerId)) {
-    return Failure("Unknown container");
-  }
-
-  CHECK_NOTNULL(infos[containerId]);
-
-  if (!future.isReady()) {
-    return Failure(
-        "Failed to clean up container " + stringify(containerId) +
-        " : " + (future.isFailed() ? future.failure() : "discarded"));
-  }
-
-  delete infos[containerId];
-  infos.erase(containerId);
-
-  return future;
-}
-
-} // namespace slave {
-} // namespace internal {
-} // namespace mesos {

http://git-wip-us.apache.org/repos/asf/mesos/blob/c3d1f776/src/slave/containerizer/mesos/isolators/cgroups/cpushare.hpp
----------------------------------------------------------------------
diff --git a/src/slave/containerizer/mesos/isolators/cgroups/cpushare.hpp b/src/slave/containerizer/mesos/isolators/cgroups/cpushare.hpp
deleted file mode 100644
index 74982a6..0000000
--- a/src/slave/containerizer/mesos/isolators/cgroups/cpushare.hpp
+++ /dev/null
@@ -1,118 +0,0 @@
-// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements.  See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership.  The ASF licenses this file
-// to you under the Apache License, Version 2.0 (the
-// "License"); you may not use this file except in compliance
-// with the License.  You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#ifndef __CPUSHARE_ISOLATOR_HPP__
-#define __CPUSHARE_ISOLATOR_HPP__
-
-#include <sys/types.h>
-
-#include <string>
-#include <vector>
-
-#include <process/future.hpp>
-
-#include <stout/hashmap.hpp>
-#include <stout/option.hpp>
-
-#include "slave/flags.hpp"
-
-#include "slave/containerizer/mesos/isolator.hpp"
-
-#include "slave/containerizer/mesos/isolators/cgroups/constants.hpp"
-
-namespace mesos {
-namespace internal {
-namespace slave {
-
-// Use the Linux cpu cgroup controller for cpu isolation which uses the
-// Completely Fair Scheduler (CFS).
-// - cpushare implements proportionally weighted scheduling.
-// - cfs implements hard quota based scheduling.
-class CgroupsCpushareIsolatorProcess : public MesosIsolatorProcess
-{
-public:
-  static Try<mesos::slave::Isolator*> create(const Flags& flags);
-
-  virtual ~CgroupsCpushareIsolatorProcess();
-
-  virtual process::Future<Nothing> recover(
-      const std::list<mesos::slave::ContainerState>& states,
-      const hashset<ContainerID>& orphans);
-
-  virtual process::Future<Option<mesos::slave::ContainerLaunchInfo>> prepare(
-      const ContainerID& containerId,
-      const mesos::slave::ContainerConfig& containerConfig);
-
-  virtual process::Future<Nothing> isolate(
-      const ContainerID& containerId,
-      pid_t pid);
-
-  virtual process::Future<mesos::slave::ContainerLimitation> watch(
-      const ContainerID& containerId);
-
-  virtual process::Future<Nothing> update(
-      const ContainerID& containerId,
-      const Resources& resources);
-
-  virtual process::Future<ResourceStatistics> usage(
-      const ContainerID& containerId);
-
-  virtual process::Future<Nothing> cleanup(
-      const ContainerID& containerId);
-
-private:
-  CgroupsCpushareIsolatorProcess(
-      const Flags& flags,
-      const hashmap<std::string, std::string>& hierarchies,
-      const std::vector<std::string>& subsystems);
-
-  virtual process::Future<std::list<Nothing>> _cleanup(
-      const ContainerID& containerId,
-      const process::Future<std::list<Nothing>>& future);
-
-  struct Info
-  {
-    Info(const ContainerID& _containerId, const std::string& _cgroup)
-      : containerId(_containerId), cgroup(_cgroup) {}
-
-    const ContainerID containerId;
-    const std::string cgroup;
-    Option<pid_t> pid;
-    Option<Resources> resources;
-
-    process::Promise<mesos::slave::ContainerLimitation> limitation;
-  };
-
-  const Flags flags;
-
-  // Map from subsystem to hierarchy.
-  hashmap<std::string, std::string> hierarchies;
-
-  // Subsystems used for this isolator. Typically, there are two
-  // elements in the vector: 'cpu' and 'cpuacct'. If cpu and cpuacct
-  // systems are co-mounted (e.g., systems using systemd), then there
-  // will be only one element in the vector which is 'cpu,cpuacct'.
-  std::vector<std::string> subsystems;
-
-  // TODO(bmahler): Use Owned<Info>.
-  hashmap<ContainerID, Info*> infos;
-};
-
-} // namespace slave {
-} // namespace internal {
-} // namespace mesos {
-
-#endif // __CPUSHARE_ISOLATOR_HPP__

http://git-wip-us.apache.org/repos/asf/mesos/blob/c3d1f776/src/tests/containerizer/isolator_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/containerizer/isolator_tests.cpp b/src/tests/containerizer/isolator_tests.cpp
index f8056ca..15978ae 100644
--- a/src/tests/containerizer/isolator_tests.cpp
+++ b/src/tests/containerizer/isolator_tests.cpp
@@ -52,8 +52,6 @@
 #include "slave/slave.hpp"
 
 #ifdef __linux__
-#include "slave/containerizer/mesos/isolators/cgroups/constants.hpp"
-#include "slave/containerizer/mesos/isolators/cgroups/cpushare.hpp"
 #include "slave/containerizer/mesos/isolators/cgroups/mem.hpp"
 #include "slave/containerizer/mesos/isolators/cgroups/net_cls.hpp"
 #include "slave/containerizer/mesos/isolators/cgroups/perf_event.hpp"
@@ -80,11 +78,9 @@ using namespace process;
 
 using mesos::internal::master::Master;
 #ifdef __linux__
-using mesos::internal::slave::CgroupsCpushareIsolatorProcess;
 using mesos::internal::slave::CgroupsMemIsolatorProcess;
 using mesos::internal::slave::CgroupsNetClsIsolatorProcess;
 using mesos::internal::slave::CgroupsPerfEventIsolatorProcess;
-using mesos::internal::slave::CPU_SHARES_PER_CPU_REVOCABLE;
 using mesos::internal::slave::Fetcher;
 using mesos::internal::slave::LinuxLauncher;
 using mesos::internal::slave::NetClsHandle;
@@ -94,7 +90,6 @@ using mesos::internal::slave::SharedFilesystemIsolatorProcess;
 using mesos::internal::slave::Launcher;
 using mesos::internal::slave::MesosContainerizer;
 using mesos::internal::slave::PosixLauncher;
-using mesos::internal::slave::PosixCpuIsolatorProcess;
 using mesos::internal::slave::PosixMemIsolatorProcess;
 using mesos::internal::slave::Slave;
 
@@ -117,321 +112,6 @@ namespace mesos {
 namespace internal {
 namespace tests {
 
-// Flag describing whether a the isolatePid parentHook should check the cgroups
-// before and after isolation.
-enum CheckCgroups
-{
-  CHECK_CGROUPS,
-  NO_CHECK_CGROUPS,
-};
-
-// A hook that is executed in the parent process. It attempts to isolate
-// a process and can optionally check the cgroups before and after isolation.
-//
-// NOTE: The child process is blocked by the hook infrastructure while
-// these hooks are executed.
-// NOTE: Returning an Error implies the child process will be killed.
-Try<Nothing> isolatePid(
-    pid_t child,
-    const Owned<Isolator>& isolator,
-    const ContainerID& containerId,
-    const CheckCgroups checkCgroups = NO_CHECK_CGROUPS)
-{
-  if (checkCgroups == CHECK_CGROUPS) {
-    // Before isolation, the cgroup is empty.
-    Future<ResourceStatistics> usage = isolator->usage(containerId);
-
-    // Note this is following the implementation of AWAIT_READY.
-    if (!process::internal::await(usage, Seconds(15))) {
-      return Error("Could check cgroup usage");
-    }
-    if (usage.isDiscarded() || usage.isFailed()) {
-      return Error("Could check cgroup usage");
-    }
-
-    if (0U != usage.get().processes()) {
-      return Error("Cgroups processes not empty before isolation");
-    }
-    if (0U != usage.get().threads()) {
-      return Error("Cgroups threads not empty before isolation");
-    }
-  }
-
-  // Isolate process.
-  Future<Nothing> isolate = isolator->isolate(containerId, child);
-
-  // Note this is following the implementation of AWAIT_READY.
-  if (!process::internal::await(isolate, Seconds(15))) {
-    return Error("Could not isolate pid");
-  }
-  if (isolate.isDiscarded() || isolate.isFailed()) {
-    return Error("Could not isolate pid");
-  }
-
-  if (checkCgroups == CHECK_CGROUPS) {
-    // After isolation, there should be one process in the cgroup.
-    Future<ResourceStatistics> usage = isolator->usage(containerId);
-
-    // Note this is following the implementation of AWAIT_READY.
-    if (!process::internal::await(usage, Seconds(15))) {
-      return Error("Could check cgroup usage");
-    }
-    if (usage.isDiscarded() || usage.isFailed()) {
-      return Error("Could check cgroup usage");
-    }
-
-    if (1U != usage.get().processes()) {
-      return Error("Cgroups processes empty after isolation");
-    }
-    if (1U != usage.get().threads()) {
-      return Error("Cgroups threads empty after isolation");
-    }
-  }
-
-  return Nothing();
-}
-
-
-template <typename T>
-class CpuIsolatorTest : public MesosTest {};
-
-
-typedef ::testing::Types<
-    PosixCpuIsolatorProcess,
-#ifdef __linux__
-    CgroupsCpushareIsolatorProcess,
-#endif // __linux__
-    tests::Module<Isolator, TestCpuIsolator>> CpuIsolatorTypes;
-
-
-TYPED_TEST_CASE(CpuIsolatorTest, CpuIsolatorTypes);
-
-
-TYPED_TEST(CpuIsolatorTest, UserCpuUsage)
-{
-  slave::Flags flags;
-
-  Try<Isolator*> _isolator = TypeParam::create(flags);
-  ASSERT_SOME(_isolator);
-  Owned<Isolator> isolator(_isolator.get());
-
-  // A PosixLauncher is sufficient even when testing a cgroups isolator.
-  Try<Launcher*> _launcher = PosixLauncher::create(flags);
-  ASSERT_SOME(_launcher);
-  Owned<Launcher> launcher(_launcher.get());
-
-  ExecutorInfo executorInfo;
-  executorInfo.mutable_resources()->CopyFrom(
-      Resources::parse("cpus:1.0").get());
-
-  ContainerID containerId;
-  containerId.set_value(UUID::random().toString());
-
-  // Use a relative temporary directory so it gets cleaned up
-  // automatically with the test.
-  Try<string> dir = os::mkdtemp(path::join(os::getcwd(), "XXXXXX"));
-  ASSERT_SOME(dir);
-
-  ContainerConfig containerConfig;
-  containerConfig.mutable_executor_info()->CopyFrom(executorInfo);
-  containerConfig.set_directory(dir.get());
-
-  AWAIT_READY(isolator->prepare(
-      containerId,
-      containerConfig));
-
-  const string& file = path::join(dir.get(), "mesos_isolator_test_ready");
-
-  // Max out a single core in userspace. This will run for at most onesecond.
-  string command = "while true ; do true ; done &"
-    "touch " + file + "; " // Signals the command is running.
-    "sleep 60";
-
-  vector<string> argv(3);
-  argv[0] = "sh";
-  argv[1] = "-c";
-  argv[2] = command;
-
-  vector<Subprocess::Hook> parentHooks;
-
-  // Create parent Hook to isolate child.
-  //
-  // NOTE: We can safely use references here as the hook will be executed
-  // during the call to `fork`.
-  const lambda::function<Try<Nothing>(pid_t)> isolatePidHook = lambda::bind(
-      isolatePid,
-      lambda::_1,
-      std::cref(isolator),
-      std::cref(containerId),
-      NO_CHECK_CGROUPS);
-
-  parentHooks.emplace_back(Subprocess::Hook(isolatePidHook));
-
-  Try<pid_t> pid = launcher->fork(
-      containerId,
-      "sh",
-      argv,
-      Subprocess::FD(STDIN_FILENO),
-      Subprocess::FD(STDOUT_FILENO),
-      Subprocess::FD(STDERR_FILENO),
-      nullptr,
-      None(),
-      None(),
-      parentHooks);
-
-  ASSERT_SOME(pid);
-
-  // Reap the forked child.
-  Future<Option<int>> status = process::reap(pid.get());
-
-  // Wait for the command to start.
-  while (!os::exists(file));
-
-  // Wait up to 1 second for the child process to induce 1/8 of a second of
-  // user cpu time.
-  ResourceStatistics statistics;
-  Duration waited = Duration::zero();
-  do {
-    Future<ResourceStatistics> usage = isolator->usage(containerId);
-    AWAIT_READY(usage);
-
-    statistics = usage.get();
-
-    // If we meet our usage expectations, we're done!
-    if (statistics.cpus_user_time_secs() >= 0.125) {
-      break;
-    }
-
-    os::sleep(Milliseconds(200));
-    waited += Milliseconds(200);
-  } while (waited < Seconds(1));
-
-  EXPECT_LE(0.125, statistics.cpus_user_time_secs());
-
-  // Ensure all processes are killed.
-  AWAIT_READY(launcher.get()->destroy(containerId));
-
-  // Make sure the child was reaped.
-  AWAIT_READY(status);
-
-  // Let the isolator clean up.
-  AWAIT_READY(isolator->cleanup(containerId));
-}
-
-
-TYPED_TEST(CpuIsolatorTest, SystemCpuUsage)
-{
-  slave::Flags flags;
-
-  Try<Isolator*> _isolator = TypeParam::create(flags);
-  ASSERT_SOME(_isolator);
-  Owned<Isolator> isolator(_isolator.get());
-
-  // A PosixLauncher is sufficient even when testing a cgroups isolator.
-  Try<Launcher*> _launcher = PosixLauncher::create(flags);
-  ASSERT_SOME(_launcher);
-  Owned<Launcher> launcher(_launcher.get());
-
-  ExecutorInfo executorInfo;
-  executorInfo.mutable_resources()->CopyFrom(
-      Resources::parse("cpus:1.0").get());
-
-  ContainerID containerId;
-  containerId.set_value(UUID::random().toString());
-
-  // Use a relative temporary directory so it gets cleaned up
-  // automatically with the test.
-  Try<string> dir = os::mkdtemp(path::join(os::getcwd(), "XXXXXX"));
-  ASSERT_SOME(dir);
-
-  ContainerConfig containerConfig;
-  containerConfig.mutable_executor_info()->CopyFrom(executorInfo);
-  containerConfig.set_directory(dir.get());
-
-  AWAIT_READY(isolator->prepare(
-      containerId,
-      containerConfig));
-
-  const string& file = path::join(dir.get(), "mesos_isolator_test_ready");
-
-  // Generating random numbers is done by the kernel and will max out a single
-  // core and run almost exclusively in the kernel, i.e., system time.
-  string command = "cat /dev/urandom > /dev/null & "
-    "touch " + file + "; " // Signals the command is running.
-    "sleep 60";
-
-  vector<string> argv(3);
-  argv[0] = "sh";
-  argv[1] = "-c";
-  argv[2] = command;
-
-  vector<Subprocess::Hook> parentHooks;
-
-  // Create parent Hook to isolate child.
-  //
-  // NOTE: We can safely use references here as the hook will be executed
-  // during the call to `fork`.
-  const lambda::function<Try<Nothing>(pid_t)> isolatePidHook = lambda::bind(
-      isolatePid,
-      lambda::_1,
-      std::cref(isolator),
-      std::cref(containerId),
-      NO_CHECK_CGROUPS);
-
-  parentHooks.emplace_back(Subprocess::Hook(isolatePidHook));
-
-  Try<pid_t> pid = launcher->fork(
-      containerId,
-      "sh",
-      argv,
-      Subprocess::FD(STDIN_FILENO),
-      Subprocess::FD(STDOUT_FILENO),
-      Subprocess::FD(STDERR_FILENO),
-      nullptr,
-      None(),
-      None(),
-      parentHooks);
-
-  ASSERT_SOME(pid);
-
-  // Reap the forked child.
-  Future<Option<int>> status = process::reap(pid.get());
-
-  // Wait for the command to start.
-  while (!os::exists(file));
-
-  // Wait up to 1 second for the child process to induce 1/8 of a second of
-  // system cpu time.
-  ResourceStatistics statistics;
-  Duration waited = Duration::zero();
-  do {
-    Future<ResourceStatistics> usage = isolator->usage(containerId);
-    AWAIT_READY(usage);
-
-    statistics = usage.get();
-
-    // If we meet our usage expectations, we're done!
-    if (statistics.cpus_system_time_secs() >= 0.125) {
-      break;
-    }
-
-    os::sleep(Milliseconds(200));
-    waited += Milliseconds(200);
-  } while (waited < Seconds(1));
-
-  EXPECT_LE(0.125, statistics.cpus_system_time_secs());
-
-  // Ensure all processes are killed.
-  AWAIT_READY(launcher.get()->destroy(containerId));
-
-  // Make sure the child was reaped.
-  AWAIT_READY(status);
-
-  // Let the isolator clean up.
-  AWAIT_READY(isolator->cleanup(containerId));
-}
-
-
 #ifdef __linux__
 class NetClsHandleManagerTest : public testing::Test {};
 
@@ -517,410 +197,6 @@ TEST_F(NetClsHandleManagerTest, SecondaryHandleRange)
 #endif // __linux__
 
 
-#ifdef __linux__
-class RevocableCpuIsolatorTest : public MesosTest {};
-
-
-TEST_F(RevocableCpuIsolatorTest, ROOT_CGROUPS_RevocableCpu)
-{
-  slave::Flags flags;
-
-  Try<Isolator*> _isolator = CgroupsCpushareIsolatorProcess::create(flags);
-  ASSERT_SOME(_isolator);
-  Owned<Isolator> isolator(_isolator.get());
-
-  Try<Launcher*> _launcher = PosixLauncher::create(flags);
-  ASSERT_SOME(_launcher);
-  Owned<Launcher> launcher(_launcher.get());
-
-  // Include revocable CPU in the executor's resources.
-  Resource cpu = Resources::parse("cpus", "1", "*").get();
-  cpu.mutable_revocable();
-
-  ExecutorInfo executorInfo;
-  executorInfo.add_resources()->CopyFrom(cpu);
-
-  ContainerID containerId;
-  containerId.set_value(UUID::random().toString());
-
-  ContainerConfig containerConfig;
-  containerConfig.mutable_executor_info()->CopyFrom(executorInfo);
-  containerConfig.set_directory(os::getcwd());
-
-  AWAIT_READY(isolator->prepare(
-        containerId,
-        containerConfig));
-
-  vector<string> argv{"sleep", "100"};
-
-  Try<pid_t> pid = launcher->fork(
-      containerId,
-      "/bin/sleep",
-      argv,
-      Subprocess::PATH("/dev/null"),
-      Subprocess::PATH("/dev/null"),
-      Subprocess::PATH("/dev/null"),
-      nullptr,
-      None(),
-      None());
-
-  ASSERT_SOME(pid);
-
-  AWAIT_READY(isolator->isolate(containerId, pid.get()));
-
-  // Executor should have proper cpu.shares for revocable containers.
-  Result<string> cpuHierarchy = cgroups::hierarchy("cpu");
-  ASSERT_SOME(cpuHierarchy);
-
-  Result<string> cpuCgroup = cgroups::cpu::cgroup(pid.get());
-  ASSERT_SOME(cpuCgroup);
-
-  EXPECT_SOME_EQ(
-      CPU_SHARES_PER_CPU_REVOCABLE,
-      cgroups::cpu::shares(cpuHierarchy.get(), cpuCgroup.get()));
-
-  // Kill the container and clean up.
-  Future<Option<int>> status = process::reap(pid.get());
-
-  AWAIT_READY(launcher.get()->destroy(containerId));
-
-  AWAIT_READY(status);
-
-  AWAIT_READY(isolator->cleanup(containerId));
-}
-#endif // __linux__
-
-
-#ifdef __linux__
-class LimitedCpuIsolatorTest : public MesosTest {};
-
-
-TEST_F(LimitedCpuIsolatorTest, ROOT_CGROUPS_CFS_Enable_Cfs)
-{
-  slave::Flags flags;
-
-  // Enable CFS to cap CPU utilization.
-  flags.cgroups_enable_cfs = true;
-
-  Try<Isolator*> _isolator = CgroupsCpushareIsolatorProcess::create(flags);
-  ASSERT_SOME(_isolator);
-  Owned<Isolator> isolator(_isolator.get());
-
-  Try<Launcher*> _launcher = LinuxLauncher::create(flags);
-  ASSERT_SOME(_launcher);
-  Owned<Launcher> launcher(_launcher.get());
-
-  // Set the executor's resources to 0.5 cpu.
-  ExecutorInfo executorInfo;
-  executorInfo.mutable_resources()->CopyFrom(
-      Resources::parse("cpus:0.5").get());
-
-  ContainerID containerId;
-  containerId.set_value(UUID::random().toString());
-
-  // Use a relative temporary directory so it gets cleaned up
-  // automatically with the test.
-  Try<string> dir = os::mkdtemp(path::join(os::getcwd(), "XXXXXX"));
-  ASSERT_SOME(dir);
-
-  ContainerConfig containerConfig;
-  containerConfig.mutable_executor_info()->CopyFrom(executorInfo);
-  containerConfig.set_directory(dir.get());
-
-  Future<Option<ContainerLaunchInfo>> prepare =
-    isolator->prepare(
-        containerId,
-        containerConfig);
-
-  AWAIT_READY(prepare);
-
-  // Generate random numbers to max out a single core. We'll run this for 0.5
-  // seconds of wall time so it should consume approximately 250 ms of total
-  // cpu time when limited to 0.5 cpu. We use /dev/urandom to prevent blocking
-  // on Linux when there's insufficient entropy.
-  string command = "cat /dev/urandom > /dev/null & "
-    "export MESOS_TEST_PID=$! && "
-    "sleep 0.5 && "
-    "kill $MESOS_TEST_PID";
-
-  vector<string> argv(3);
-  argv[0] = "sh";
-  argv[1] = "-c";
-  argv[2] = command;
-
-  vector<Subprocess::Hook> parentHooks;
-
-  // Create parent Hook to isolate child.
-  //
-  // NOTE: We can safely use references here as the hook will be executed
-  // during the call to `fork`.
-  const lambda::function<Try<Nothing>(pid_t)> isolatePidHook = lambda::bind(
-      isolatePid,
-      lambda::_1,
-      std::cref(isolator),
-      std::cref(containerId),
-      NO_CHECK_CGROUPS);
-
-  parentHooks.emplace_back(Subprocess::Hook(isolatePidHook));
-
-  Try<pid_t> pid = launcher->fork(
-      containerId,
-      "sh",
-      argv,
-      Subprocess::FD(STDIN_FILENO),
-      Subprocess::FD(STDOUT_FILENO),
-      Subprocess::FD(STDERR_FILENO),
-      nullptr,
-      None(),
-      prepare.get().isSome() ? prepare.get().get().namespaces() : 0,
-      parentHooks);
-
-  ASSERT_SOME(pid);
-
-  // Reap the forked child.
-  Future<Option<int>> status = process::reap(pid.get());
-
-  // Wait for the command to complete.
-  AWAIT_READY(status);
-
-  Future<ResourceStatistics> usage = isolator->usage(containerId);
-  AWAIT_READY(usage);
-
-  // Expect that no more than 300 ms of cpu time has been consumed. We also
-  // check that at least 50 ms of cpu time has been consumed so this test will
-  // fail if the host system is very heavily loaded. This behavior is correct
-  // because under such conditions we aren't actually testing the CFS cpu
-  // limiter.
-  double cpuTime = usage.get().cpus_system_time_secs() +
-                   usage.get().cpus_user_time_secs();
-
-  EXPECT_GE(0.30, cpuTime);
-  EXPECT_LE(0.05, cpuTime);
-
-  // Ensure all processes are killed.
-  AWAIT_READY(launcher.get()->destroy(containerId));
-
-  // Let the isolator clean up.
-  AWAIT_READY(isolator->cleanup(containerId));
-}
-
-
-// This test verifies that we can successfully launch a container with
-// a big (>= 10 cpus) cpu quota. This is to catch the regression
-// observed in MESOS-1049.
-// TODO(vinod): Revisit this if/when the isolator restricts the number
-// of cpus that an executor can use based on the slave cpus.
-TEST_F(LimitedCpuIsolatorTest, ROOT_CGROUPS_CFS_Big_Quota)
-{
-  slave::Flags flags;
-
-  // Enable CFS to cap CPU utilization.
-  flags.cgroups_enable_cfs = true;
-
-  Try<Isolator*> _isolator = CgroupsCpushareIsolatorProcess::create(flags);
-  ASSERT_SOME(_isolator);
-  Owned<Isolator> isolator(_isolator.get());
-
-  Try<Launcher*> _launcher = LinuxLauncher::create(flags);
-  ASSERT_SOME(_launcher);
-  Owned<Launcher> launcher(_launcher.get());
-
-  // Set the executor's resources to 100.5 cpu.
-  ExecutorInfo executorInfo;
-  executorInfo.mutable_resources()->CopyFrom(
-      Resources::parse("cpus:100.5").get());
-
-  ContainerID containerId;
-  containerId.set_value(UUID::random().toString());
-
-  // Use a relative temporary directory so it gets cleaned up
-  // automatically with the test.
-  Try<string> dir = os::mkdtemp(path::join(os::getcwd(), "XXXXXX"));
-  ASSERT_SOME(dir);
-
-  ContainerConfig containerConfig;
-  containerConfig.mutable_executor_info()->CopyFrom(executorInfo);
-  containerConfig.set_directory(dir.get());
-
-  Future<Option<ContainerLaunchInfo>> prepare =
-    isolator->prepare(
-        containerId,
-        containerConfig);
-
-  AWAIT_READY(prepare);
-
-  vector<string> argv(3);
-  argv[0] = "sh";
-  argv[1] = "-c";
-  argv[2] = "exit 0";
-
-  vector<Subprocess::Hook> parentHooks;
-
-  // Create parent Hook to isolate child.
-  // Note: We can safely use references here as we are sure that the life time
-  // of the parent will exceed the child.
-  const lambda::function<Try<Nothing>(pid_t)> isolatePidHook = lambda::bind(
-      isolatePid,
-      lambda::_1,
-      std::cref(isolator),
-      std::cref(containerId),
-      NO_CHECK_CGROUPS);
-
-  parentHooks.emplace_back(Subprocess::Hook(isolatePidHook));
-
-  Try<pid_t> pid = launcher->fork(
-      containerId,
-      "sh",
-      argv,
-      Subprocess::FD(STDIN_FILENO),
-      Subprocess::FD(STDOUT_FILENO),
-      Subprocess::FD(STDERR_FILENO),
-      nullptr,
-      None(),
-      prepare.get().isSome() ? prepare.get().get().namespaces() : 0,
-      parentHooks);
-
-  ASSERT_SOME(pid);
-
-  // Reap the forked child.
-  Future<Option<int>> status = process::reap(pid.get());
-
-  // Wait for the command to complete successfully.
-  AWAIT_READY(status);
-  ASSERT_SOME_EQ(0, status.get());
-
-  // Ensure all processes are killed.
-  AWAIT_READY(launcher.get()->destroy(containerId));
-
-  // Let the isolator clean up.
-  AWAIT_READY(isolator->cleanup(containerId));
-}
-
-
-// A test to verify the number of processes and threads in a
-// container.
-TEST_F(LimitedCpuIsolatorTest, ROOT_CGROUPS_Pids_and_Tids)
-{
-  slave::Flags flags;
-  flags.cgroups_cpu_enable_pids_and_tids_count = true;
-
-  Try<Isolator*> _isolator = CgroupsCpushareIsolatorProcess::create(flags);
-  ASSERT_SOME(_isolator);
-  Owned<Isolator> isolator(_isolator.get());
-
-  Try<Launcher*> _launcher = LinuxLauncher::create(flags);
-  ASSERT_SOME(_launcher);
-  Owned<Launcher> launcher(_launcher.get());
-
-  ExecutorInfo executorInfo;
-  executorInfo.mutable_resources()->CopyFrom(
-      Resources::parse("cpus:0.5;mem:512").get());
-
-  ContainerID containerId;
-  containerId.set_value(UUID::random().toString());
-
-  // Use a relative temporary directory so it gets cleaned up
-  // automatically with the test.
-  Try<string> dir = os::mkdtemp(path::join(os::getcwd(), "XXXXXX"));
-  ASSERT_SOME(dir);
-
-  ContainerConfig containerConfig;
-  containerConfig.mutable_executor_info()->CopyFrom(executorInfo);
-  containerConfig.set_directory(dir.get());
-
-  Future<Option<ContainerLaunchInfo>> prepare =
-    isolator->prepare(
-        containerId,
-        containerConfig);
-
-  AWAIT_READY(prepare);
-
-  // Right after the creation of the cgroup, which happens in
-  // 'prepare', we check that it is empty.
-  Future<ResourceStatistics> usage = isolator->usage(containerId);
-  AWAIT_READY(usage);
-  EXPECT_EQ(0U, usage.get().processes());
-  EXPECT_EQ(0U, usage.get().threads());
-
-  // Use these to communicate with the test process after it has
-  // exec'd to make sure it is running.
-  int inputPipes[2];
-  ASSERT_NE(-1, ::pipe(inputPipes));
-
-  int outputPipes[2];
-  ASSERT_NE(-1, ::pipe(outputPipes));
-
-  vector<string> argv(1);
-  argv[0] = "cat";
-
-  vector<Subprocess::Hook> parentHooks;
-
-  // Create parent Hook to isolate child.
-  // Note: We can safely use references here as we are sure that the life time
-  // of the parent will exceed the child.
-  const lambda::function<Try<Nothing>(pid_t)> isolatePidHook = lambda::bind(
-      isolatePid,
-      lambda::_1,
-      std::cref(isolator),
-      std::cref(containerId),
-      CHECK_CGROUPS);
-
-  parentHooks.emplace_back(Subprocess::Hook(isolatePidHook));
-
-  Try<pid_t> pid = launcher->fork(
-      containerId,
-      "cat",
-      argv,
-      Subprocess::FD(inputPipes[0], Subprocess::IO::OWNED),
-      Subprocess::FD(outputPipes[1], Subprocess::IO::OWNED),
-      Subprocess::FD(STDERR_FILENO),
-      nullptr,
-      None(),
-      prepare.get().isSome() ? prepare.get().get().namespaces() : 0,
-      parentHooks);
-
-  ASSERT_SOME(pid);
-
-  // Reap the forked child.
-  Future<Option<int>> status = process::reap(pid.get());
-
-  // Write to the test process and wait for an echoed result.
-  // This observation ensures that the "cat" process has
-  // completed its part of the exec() procedure and is now
-  // executing normally.
-  AWAIT_READY(io::write(inputPipes[1], "foo")
-    .then([outputPipes]() -> Future<short> {
-      return io::poll(outputPipes[0], io::READ);
-    }));
-
-  // Process count should be 1 since 'cat' is still idling.
-  usage = isolator->usage(containerId);
-  AWAIT_READY(usage);
-  EXPECT_EQ(1U, usage.get().processes());
-  EXPECT_EQ(1U, usage.get().threads());
-
-  // Ensure all processes are killed.
-  AWAIT_READY(launcher.get()->destroy(containerId));
-
-  // Clean up the extra pipes created for synchronization.
-  EXPECT_SOME(os::close(inputPipes[1]));
-  EXPECT_SOME(os::close(outputPipes[0]));
-
-  // Wait for the command to complete.
-  AWAIT_READY(status);
-
-  // After the process is killed, the cgroup should be empty again.
-  usage = isolator->usage(containerId);
-  AWAIT_READY(usage);
-  EXPECT_EQ(0U, usage.get().processes());
-  EXPECT_EQ(0U, usage.get().threads());
-
-  // Let the isolator clean up.
-  AWAIT_READY(isolator->cleanup(containerId));
-}
-#endif // __linux__
-
-
 template <typename T>
 class MemIsolatorTest : public MesosTest {};
 
@@ -1596,7 +872,6 @@ public:
 // Test all isolators that use cgroups.
 typedef ::testing::Types<
   CgroupsMemIsolatorProcess,
-  CgroupsCpushareIsolatorProcess,
   CgroupsPerfEventIsolatorProcess> CgroupsIsolatorTypes;
 
 


[11/17] mesos git commit: Entered working directory before switch user.

Posted by ji...@apache.org.
Entered working directory before switch user.

If `chdir` into the working directory after switch user, the user may
fail because of permissions problem.

Review: https://reviews.apache.org/r/51782/


Project: http://git-wip-us.apache.org/repos/asf/mesos/repo
Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/d25cafa3
Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/d25cafa3
Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/d25cafa3

Branch: refs/heads/master
Commit: d25cafa30af94323fbd17dd220d7fdf7563e2f2a
Parents: dcf48fe
Author: haosdent huang <ha...@gmail.com>
Authored: Mon Sep 12 16:34:57 2016 -0700
Committer: Jie Yu <yu...@gmail.com>
Committed: Tue Sep 13 10:52:01 2016 -0700

----------------------------------------------------------------------
 src/slave/containerizer/mesos/launch.cpp | 20 ++++++++++----------
 1 file changed, 10 insertions(+), 10 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/d25cafa3/src/slave/containerizer/mesos/launch.cpp
----------------------------------------------------------------------
diff --git a/src/slave/containerizer/mesos/launch.cpp b/src/slave/containerizer/mesos/launch.cpp
index b8ad27e..0feaed1 100644
--- a/src/slave/containerizer/mesos/launch.cpp
+++ b/src/slave/containerizer/mesos/launch.cpp
@@ -377,6 +377,16 @@ int MesosContainerizerLaunch::execute()
     }
   }
 
+  if (flags.working_directory.isSome()) {
+    Try<Nothing> chdir = os::chdir(flags.working_directory.get());
+    if (chdir.isError()) {
+      cerr << "Failed to chdir into current working directory "
+           << "'" << flags.working_directory.get() << "': "
+           << chdir.error() << endl;
+      return EXIT_FAILURE;
+    }
+  }
+
   // Change user if provided. Note that we do that after executing the
   // preparation commands so that those commands will be run with the
   // same privilege as the mesos-agent.
@@ -451,16 +461,6 @@ int MesosContainerizerLaunch::execute()
   }
 #endif // __linux__
 
-  if (flags.working_directory.isSome()) {
-    Try<Nothing> chdir = os::chdir(flags.working_directory.get());
-    if (chdir.isError()) {
-      cerr << "Failed to chdir into current working directory "
-           << "'" << flags.working_directory.get() << "': "
-           << chdir.error() << endl;
-      return EXIT_FAILURE;
-    }
-  }
-
   // Relay the environment variables.
   // TODO(jieyu): Consider using a clean environment.
 


[12/17] mesos git commit: Refactored `UserCgroupsIsolatorTest`.

Posted by ji...@apache.org.
Refactored `UserCgroupsIsolatorTest`.

Refactor `UserCgroupsIsolatorTest.ROOT_CGROUPS_PERF_UserCgroup` and
rename to `CgroupsIsolatorTest.ROOT_CGROUPS_PERF_NET_CLS_UserCgroup`.

Review: https://reviews.apache.org/r/51783/


Project: http://git-wip-us.apache.org/repos/asf/mesos/repo
Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/feb51147
Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/feb51147
Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/feb51147

Branch: refs/heads/master
Commit: feb51147b5a5728447373304e4a2186b24a5b1ff
Parents: d25cafa
Author: haosdent huang <ha...@gmail.com>
Authored: Mon Sep 12 16:34:59 2016 -0700
Committer: Jie Yu <yu...@gmail.com>
Committed: Tue Sep 13 10:52:01 2016 -0700

----------------------------------------------------------------------
 .../containerizer/cgroups_isolator_tests.cpp    | 179 ++++++++++++++++++-
 1 file changed, 176 insertions(+), 3 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/feb51147/src/tests/containerizer/cgroups_isolator_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/containerizer/cgroups_isolator_tests.cpp b/src/tests/containerizer/cgroups_isolator_tests.cpp
index c4e467c..396c96c 100644
--- a/src/tests/containerizer/cgroups_isolator_tests.cpp
+++ b/src/tests/containerizer/cgroups_isolator_tests.cpp
@@ -14,15 +14,39 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include <map>
-#include <utility>
+#include <process/gtest.hpp>
 
-#include <gtest/gtest.h>
+#include <stout/format.hpp>
+#include <stout/gtest.hpp>
 
 #include "slave/containerizer/mesos/containerizer.hpp"
 
+#include "slave/containerizer/mesos/isolators/cgroups/constants.hpp"
+
+#include "tests/mesos.hpp"
 #include "tests/script.hpp"
 
+#include "tests/containerizer/docker_archive.hpp"
+
+using mesos::internal::master::Master;
+
+using mesos::internal::slave::CGROUP_SUBSYSTEM_CPU_NAME;
+using mesos::internal::slave::CGROUP_SUBSYSTEM_CPUACCT_NAME;
+using mesos::internal::slave::CGROUP_SUBSYSTEM_DEVICES_NAME;
+using mesos::internal::slave::CGROUP_SUBSYSTEM_MEMORY_NAME;
+using mesos::internal::slave::CGROUP_SUBSYSTEM_NET_CLS_NAME;
+using mesos::internal::slave::CGROUP_SUBSYSTEM_PERF_EVENT_NAME;
+using mesos::internal::slave::Fetcher;
+using mesos::internal::slave::MesosContainerizer;
+
+using mesos::master::detector::MasterDetector;
+
+using process::Future;
+using process::Owned;
+
+using std::string;
+using std::vector;
+
 namespace mesos {
 namespace internal {
 namespace tests {
@@ -33,6 +57,155 @@ TEST_SCRIPT(ContainerizerTest,
             ROOT_CGROUPS_BalloonFramework,
             "balloon_framework_test.sh")
 
+
+class CgroupsIsolatorTest : public MesosTest {};
+
+
+// This test starts the agent with cgroups isolation and launches a
+// task with an unprivileged user. Then verifies that the unprivileged
+// user has write permission under the corresponding cgroups which are
+// prepared for the container to run the task.
+TEST_F(CgroupsIsolatorTest, ROOT_CGROUPS_PERF_NET_CLS_UserCgroup)
+{
+  Try<Owned<cluster::Master>> master = StartMaster();
+  ASSERT_SOME(master);
+
+  const string registry = path::join(os::getcwd(), "registry");
+
+  Future<Nothing> testImage = DockerArchive::create(registry, "alpine");
+  AWAIT_READY(testImage);
+
+  ASSERT_TRUE(os::exists(path::join(registry, "alpine.tar")));
+
+  slave::Flags flags = CreateSlaveFlags();
+  flags.docker_registry = registry;
+  flags.docker_store_dir = path::join(os::getcwd(), "store");
+  flags.image_providers = "docker";
+  flags.perf_events = "cpu-cycles"; // Needed for `PerfEventSubsystem`.
+  flags.isolation =
+    "cgroups/cpu,"
+    "cgroups/devices,"
+    "cgroups/mem,"
+    "cgroups/net_cls,"
+    "cgroups/perf_event,"
+    "docker/runtime,"
+    "filesystem/linux";
+
+  Fetcher fetcher;
+
+  Try<MesosContainerizer*> _containerizer =
+    MesosContainerizer::create(flags, true, &fetcher);
+
+  ASSERT_SOME(_containerizer);
+
+  Owned<MesosContainerizer> containerizer(_containerizer.get());
+
+  Owned<MasterDetector> detector = master.get()->createDetector();
+
+  Try<Owned<cluster::Slave>> slave = StartSlave(
+      detector.get(),
+      containerizer.get());
+
+  ASSERT_SOME(slave);
+
+  MockScheduler sched;
+
+  MesosSchedulerDriver driver(
+      &sched,
+      DEFAULT_FRAMEWORK_INFO,
+      master.get()->pid,
+      DEFAULT_CREDENTIAL);
+
+  EXPECT_CALL(sched, registered(&driver, _, _))
+    .Times(1);
+
+  Future<vector<Offer>> offers;
+  EXPECT_CALL(sched, resourceOffers(&driver, _))
+    .WillOnce(FutureArg<1>(&offers))
+    .WillRepeatedly(Return()); // Ignore subsequent offers.
+
+  driver.start();
+
+  AWAIT_READY(offers);
+  EXPECT_NE(0u, offers.get().size());
+
+  // Launch a task with the command executor.
+  CommandInfo command;
+  command.set_shell(false);
+  command.set_value("/bin/sleep");
+  command.add_arguments("sleep");
+  command.add_arguments("120");
+  command.set_user("nobody");
+
+  TaskInfo task = createTask(
+      offers.get()[0].slave_id(),
+      offers.get()[0].resources(),
+      command);
+
+  Image image;
+  image.set_type(Image::DOCKER);
+  image.mutable_docker()->set_name("alpine");
+
+  ContainerInfo* container = task.mutable_container();
+  container->set_type(ContainerInfo::MESOS);
+  container->mutable_mesos()->mutable_image()->CopyFrom(image);
+
+  Future<TaskStatus> statusRunning;
+  EXPECT_CALL(sched, statusUpdate(&driver, _))
+    .WillOnce(FutureArg<1>(&statusRunning));
+
+  driver.launchTasks(offers.get()[0].id(), {task});
+
+  AWAIT_READY_FOR(statusRunning, Seconds(60));
+  EXPECT_EQ(TASK_RUNNING, statusRunning.get().state());
+
+  vector<string> subsystems = {
+    CGROUP_SUBSYSTEM_CPU_NAME,
+    CGROUP_SUBSYSTEM_CPUACCT_NAME,
+    CGROUP_SUBSYSTEM_DEVICES_NAME,
+    CGROUP_SUBSYSTEM_MEMORY_NAME,
+    CGROUP_SUBSYSTEM_NET_CLS_NAME,
+    CGROUP_SUBSYSTEM_PERF_EVENT_NAME,
+  };
+
+  Future<hashset<ContainerID>> containers = containerizer->containers();
+  AWAIT_READY(containers);
+  EXPECT_EQ(1u, containers.get().size());
+
+  ContainerID containerId = *(containers.get().begin());
+
+  foreach (const string& subsystem, subsystems) {
+    string hierarchy = path::join(flags.cgroups_hierarchy, subsystem);
+    string cgroup = path::join(flags.cgroups_root, containerId.value());
+
+    // Verify that the user cannot manipulate the container's cgroup
+    // control files as their owner is root.
+    EXPECT_NE(0, os::system(strings::format(
+        "su - nobody -s /bin/sh -c 'echo $$ > %s'",
+        path::join(hierarchy, cgroup, "cgroup.procs")).get()));
+
+    // Verify that the user can create a cgroup under the container's
+    // cgroup as the isolator changes the owner of the cgroup.
+    string userCgroup = path::join(cgroup, "user");
+
+    EXPECT_EQ(0, os::system(strings::format(
+        "su - nobody -s /bin/sh -c 'mkdir %s'",
+        path::join(hierarchy, userCgroup)).get()));
+
+    // Verify that the user can manipulate control files in the
+    // created cgroup as it's owned by the user.
+    EXPECT_EQ(0, os::system(strings::format(
+        "su - nobody -s /bin/sh -c 'echo $$ > %s'",
+        path::join(hierarchy, userCgroup, "cgroup.procs")).get()));
+
+    // Clear up the folder.
+    AWAIT_READY(cgroups::destroy(hierarchy, userCgroup));
+  }
+
+  driver.stop();
+  driver.join();
+}
+
 } // namespace tests {
 } // namespace internal {
 } // namespace mesos {