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

commit 60283dfed06a5fff4ecedaba4e67674dc01aa16e
Author: Devin Leamy <[email protected]>
AuthorDate: Fri Mar 22 11:45:03 2024 -0400

    [cgroups2] Add an interface to read and assign processes.
    
    `cgroup.procs` lists all of the processes inside of a cgroup, one per line.
    There may be duplicates. A single process can be moved into a cgroup by
    writing its process ID into `cgroup.procs`.
    
    Here we introduce:
    - Reading the processes inside of a cgroup, and
    - Assigning a process to a cgroup.
    
    This closes #532
---
 src/linux/cgroups2.cpp                     | 41 ++++++++++++++++++++++++++++++
 src/linux/cgroups2.hpp                     |  9 +++++++
 src/tests/containerizer/cgroups2_tests.cpp | 37 +++++++++++++++++++++++++++
 3 files changed, 87 insertions(+)

diff --git a/src/linux/cgroups2.cpp b/src/linux/cgroups2.cpp
index c2892f544..310119bc8 100644
--- a/src/linux/cgroups2.cpp
+++ b/src/linux/cgroups2.cpp
@@ -357,6 +357,47 @@ Try<string> cgroup(pid_t pid)
 }
 
 
+Try<set<pid_t>> processes(const string& cgroup)
+{
+  if (!cgroups2::exists(cgroup)) {
+    return Error("Cgroup '" + cgroup + "' does not exist");
+  }
+
+  Try<string> contents = cgroups2::read<string>(cgroup, control::PROCESSES);
+  if (contents.isError()) {
+    return Error(
+        "Failed to read cgroup.procs in '" + cgroup + "': " + 
contents.error());
+  }
+
+  string trimmed = strings::trim(*contents);
+  if (trimmed.empty()) {
+    return set<pid_t>();
+  }
+
+  set<pid_t> pids;
+  foreach (const string& _pid, strings::split(strings::trim(*contents), "\n")) 
{
+    Try<pid_t> pid = numify<pid_t>(strings::trim(_pid));
+    if (pid.isError()) {
+      return Error("Failed to parse pid: " + pid.error());
+    }
+
+    pids.insert(*pid);
+  }
+
+  return pids;
+}
+
+
+Try<Nothing> assign(const string& cgroup, pid_t pid)
+{
+  if (!cgroups2::exists(cgroup)) {
+    return Error("Cgroup '" + cgroup + "' does not exist");
+  }
+
+  return cgroups2::write(cgroup, control::PROCESSES, stringify(pid));
+}
+
+
 string path(const string& cgroup)
 {
   return path::join(cgroups2::MOUNT_POINT, cgroup);
diff --git a/src/linux/cgroups2.hpp b/src/linux/cgroups2.hpp
index ea3e577f9..9c9b9ceef 100644
--- a/src/linux/cgroups2.hpp
+++ b/src/linux/cgroups2.hpp
@@ -76,6 +76,15 @@ Try<Nothing> move_process(const std::string& cgroup, pid_t 
pid);
 Try<std::string> cgroup(pid_t pid);
 
 
+// Get the processes inside of a cgroup.
+Try<std::set<pid_t>> processes(const std::string& cgroup);
+
+
+// Assign a process to a cgroup, by PID. This removes the process from its
+// current cgroup.
+Try<Nothing> assign(const std::string& cgroup, pid_t pid);
+
+
 // Get the absolute of a cgroup. The cgroup provided should not start with '/'.
 std::string path(const std::string& cgroup);
 
diff --git a/src/tests/containerizer/cgroups2_tests.cpp 
b/src/tests/containerizer/cgroups2_tests.cpp
index ee3932e0e..756292096 100644
--- a/src/tests/containerizer/cgroups2_tests.cpp
+++ b/src/tests/containerizer/cgroups2_tests.cpp
@@ -123,6 +123,43 @@ TEST_F(Cgroups2Test, CGROUPS2_Path)
   EXPECT_EQ("/sys/fs/cgroup/foo/bar", cgroups2::path("foo/bar"));
 }
 
+
+TEST_F(Cgroups2Test, CGROUPS_Path)
+{
+  Try<set<pid_t>> pids = cgroups2::processes(cgroups2::ROOT_CGROUP);
+
+  EXPECT_SOME(pids);
+  EXPECT_TRUE(pids->size() > 0);
+
+  ASSERT_SOME(cgroups2::create(TEST_CGROUP));
+
+  pid_t pid = ::fork();
+  ASSERT_NE(-1, pid);
+
+  if (pid == 0) {
+    // In child process, wait for kill signal.
+    while (true) { sleep(1); }
+
+    SAFE_EXIT(
+        EXIT_FAILURE, "Error, child should be killed before reaching here");
+  }
+
+  pids = cgroups2::processes(TEST_CGROUP);
+  EXPECT_SOME(pids);
+  EXPECT_EQ(0u, pids->size());
+
+  EXPECT_SOME(cgroups2::assign(TEST_CGROUP, pid));
+  pids = cgroups2::processes(TEST_CGROUP);
+
+  EXPECT_SOME(pids);
+  EXPECT_EQ(1u, pids->size());
+  EXPECT_EQ(pid, *pids->begin());
+
+  // Kill the child process.
+  ASSERT_NE(-1, ::kill(pid, SIGKILL));
+  AWAIT_EXPECT_WTERMSIG_EQ(SIGKILL, process::reap(pid));
+}
+
 } // namespace tests {
 
 } // namespace internal {

Reply via email to