This is an automated email from the ASF dual-hosted git repository.
bmahler pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mesos.git
The following commit(s) were added to refs/heads/master by this push:
new 15e001595 [cgroups2] Introduce cgroups2::disable to disable a
controller.
15e001595 is described below
commit 15e001595d5cae041895e62015c3fd0b1a818f7f
Author: Devin Leamy <[email protected]>
AuthorDate: Tue Mar 26 18:26:55 2024 -0400
[cgroups2] Introduce cgroups2::disable to disable a controller.
Allows a controller to be disabled on a cgroup. A test is introduced.
We additionally move the read and write utilities so that they are
accessible when we read the cgroup.subtree_control control file.
This closes #536
---
src/linux/cgroups2.cpp | 117 +++++++++++++++++++----------
src/linux/cgroups2.hpp | 6 ++
src/tests/containerizer/cgroups2_tests.cpp | 35 ++++++++-
3 files changed, 117 insertions(+), 41 deletions(-)
diff --git a/src/linux/cgroups2.cpp b/src/linux/cgroups2.cpp
index 399edfced..816251d84 100644
--- a/src/linux/cgroups2.cpp
+++ b/src/linux/cgroups2.cpp
@@ -58,6 +58,44 @@ Try<Nothing> write(
const T& value);
+template <>
+Try<string> read(const string& cgroup, const string& control)
+{
+ return os::read(path::join(cgroups2::path(cgroup), control));
+}
+
+
+template <>
+Try<uint64_t> read(const string& cgroup, const string& control)
+{
+ Try<string> content = read<string>(cgroup, control);
+ if (content.isError()) {
+ return Error(content.error());
+ }
+
+ return numify<uint64_t>(strings::trim(*content));
+}
+
+
+template <>
+Try<Nothing> write(
+ const string& cgroup,
+ const string& control,
+ const string& value)
+{
+ return os::write(path::join(cgroups2::path(cgroup), control), value);
+}
+
+
+template <>
+Try<Nothing> write(
+ const string& cgroup,
+ const string& control,
+ const uint64_t& value)
+{
+ return write(cgroup, control, stringify(value));
+}
+
namespace control {
// Interface files found in all cgroups.
@@ -106,6 +144,13 @@ struct State
_disabled.insert(controller);
}
+ void disable(const set<string>& controllers)
+ {
+ foreach (const string& controller, controllers) {
+ disable(controller);
+ }
+ }
+
set<string> enabled() const { return _enabled; }
set<string> disabled() const { return _disabled; }
@@ -148,48 +193,31 @@ std::ostream& operator<<(std::ostream& stream, const
State& state)
return stream;
}
-} // namespace subtree_control {
-
-} // namespace control {
-
-template <>
-Try<string> read(const string& cgroup, const string& control)
+Try<State> read(const string& cgroup)
{
- return os::read(path::join(cgroups2::path(cgroup), control));
-}
-
+ Try<string> contents =
+ cgroups2::read<string>(cgroup, cgroups2::control::SUBTREE_CONTROLLERS);
-template <>
-Try<uint64_t> read(const string& cgroup, const string& control)
-{
- Try<string> content = read<string>(cgroup, control);
- if (content.isError()) {
- return Error(content.error());
+ if (contents.isError()) {
+ return Error(
+ "Failed to read 'cgroup.subtree_control' for cgroup '" + cgroup + "': "
+ + contents.error());
}
- return numify<uint64_t>(strings::trim(*content));
+ return State::parse(*contents);
}
-template <>
-Try<Nothing> write(
- const string& cgroup,
- const string& control,
- const string& value)
+Try<Nothing> write(const string& cgroup, const State& state)
{
- return os::write(path::join(cgroups2::path(cgroup), control), value);
+ return cgroups2::write(
+ cgroup, control::SUBTREE_CONTROLLERS, stringify(state));
}
+} // namespace subtree_control {
-template <>
-Try<Nothing> write(
- const string& cgroup,
- const string& control,
- const uint64_t& value)
-{
- return write(cgroup, control, stringify(value));
-}
+} // namespace control {
bool enabled()
@@ -418,20 +446,29 @@ Try<set<string>> available(const string& cgroup)
Try<Nothing> enable(const string& cgroup, const vector<string>& controllers)
{
- Try<string> contents =
- cgroups2::read<string>(cgroup, cgroups2::control::SUBTREE_CONTROLLERS);
+ using State = control::subtree_control::State;
+ Try<State> control = cgroups2::control::subtree_control::read(cgroup);
- if (contents.isError()) {
- return Error(contents.error());
+ if (control.isError()) {
+ return Error(control.error());
}
+ control->enable(controllers);
+ return cgroups2::control::subtree_control::write(cgroup, *control);
+}
+
+
+Try<Nothing> disable(const string& cgroup, const set<string>& controllers)
+{
using State = control::subtree_control::State;
- State control = State::parse(*contents);
- control.enable(controllers);
- return cgroups2::write(
- cgroup,
- control::SUBTREE_CONTROLLERS,
- stringify(control));
+ Try<State> control = cgroups2::control::subtree_control::read(cgroup);
+
+ if (control.isError()) {
+ return Error(control.error());
+ }
+
+ control->disable(controllers);
+ return cgroups2::control::subtree_control::write(cgroup, *control);
}
diff --git a/src/linux/cgroups2.hpp b/src/linux/cgroups2.hpp
index abdfbf814..024b271a5 100644
--- a/src/linux/cgroups2.hpp
+++ b/src/linux/cgroups2.hpp
@@ -102,6 +102,12 @@ Try<Nothing> enable(
const std::vector<std::string>& controllers);
+// Disables controllers in the cgroup. No-op if the controller is not enabled.
+Try<Nothing> disable(
+ const std::string& cgroup,
+ const std::set<std::string>& controllers);
+
+
// Get all the controllers that are enabled for a cgroup.
Try<std::set<std::string>> enabled(const std::string& cgroup);
diff --git a/src/tests/containerizer/cgroups2_tests.cpp
b/src/tests/containerizer/cgroups2_tests.cpp
index 90f751d08..db541a5ca 100644
--- a/src/tests/containerizer/cgroups2_tests.cpp
+++ b/src/tests/containerizer/cgroups2_tests.cpp
@@ -22,6 +22,7 @@
#include <process/gtest.hpp>
#include <stout/exit.hpp>
+#include <stout/foreach.hpp>
#include <stout/set.hpp>
#include <stout/tests/utils.hpp>
#include <stout/try.hpp>
@@ -83,7 +84,8 @@ protected:
ASSERT_SOME(cgroups2::destroy(TEST_CGROUP));
}
- // TODO(bmahler): disable the enabled_controllers.
+ ASSERT_SOME(cgroups2::controllers::disable(
+ cgroups2::ROOT_CGROUP, enabled_controllers));
TemporaryDirectoryTest::TearDown();
}
@@ -177,6 +179,37 @@ TEST_F(Cgroups2Test, ROOT_CGROUPS2_CpuStats)
ASSERT_SOME(cgroups2::cpu::stats(TEST_CGROUP));
}
+
+TEST_F(Cgroups2Test, ROOT_CGROUPS2_EnableAndDisable)
+{
+ ASSERT_SOME(enable_controllers({"cpu"}));
+
+ ASSERT_SOME(cgroups2::create(TEST_CGROUP));
+
+ // Check that "cpu" not enabled.
+ Try<set<string>> enabled = cgroups2::controllers::enabled(TEST_CGROUP);
+ EXPECT_SOME(enabled);
+ EXPECT_EQ(0u, enabled->count("cpu"));
+
+ // Enable "cpu".
+ EXPECT_SOME(cgroups2::controllers::enable(TEST_CGROUP, {"cpu"}));
+ EXPECT_SOME(cgroups2::controllers::enable(TEST_CGROUP, {"cpu"})); // NOP
+
+ // Check that "cpu" is enabled.
+ enabled = cgroups2::controllers::enabled(TEST_CGROUP);
+ EXPECT_SOME(enabled);
+ EXPECT_EQ(1u, enabled->count("cpu"));
+
+ // Disable "cpu".
+ EXPECT_SOME(cgroups2::controllers::disable(TEST_CGROUP, {"cpu"}));
+ EXPECT_SOME(cgroups2::controllers::disable(TEST_CGROUP, {"cpu"})); // NOP
+
+ // Check that "cpu" not enabled.
+ enabled = cgroups2::controllers::enabled(TEST_CGROUP);
+ EXPECT_SOME(enabled);
+ EXPECT_EQ(0u, enabled->count("cpu"));
+}
+
} // namespace tests {
} // namespace internal {