lxcpp: cgroups configration (part 3) 97/50297/6
authorKrzysztof Dynowski <k.dynowski@samsung.com>
Fri, 23 Oct 2015 23:33:43 +0000 (01:33 +0200)
committerDariusz Michaluk <d.michaluk@samsung.com>
Fri, 30 Oct 2015 15:56:59 +0000 (08:56 -0700)
[Feature]       Control-groups configuration for containers
[Cause]         N/A
[Solution]      N/A
[Verification]  build, install, run unit tests

Change-Id: I5a0e1403d3524973e6d2eed02118a213f3a764a4

13 files changed:
common/utils/fs.cpp
common/utils/fs.hpp
libs/lxcpp/cgroups/cgroup-config.hpp [new file with mode: 0644]
libs/lxcpp/cgroups/cgroup.cpp
libs/lxcpp/cgroups/cgroup.hpp
libs/lxcpp/commands/cgroups.cpp [new file with mode: 0644]
libs/lxcpp/commands/cgroups.hpp [new file with mode: 0644]
libs/lxcpp/container-config.hpp
libs/lxcpp/container-impl.cpp
libs/lxcpp/container-impl.hpp
libs/lxcpp/container.hpp
tests/unit_tests/lxcpp/ut-cgroups.cpp
tests/unit_tests/lxcpp/ut-network.cpp

index cd70e3b..a9a3537 100644 (file)
@@ -49,13 +49,34 @@ namespace utils {
 
 std::string readFileStream(const std::string& path)
 {
-    std::ifstream is(path);
-    return std::string(std::istreambuf_iterator<char>(is), std::istreambuf_iterator<char>());
+    std::ifstream file(path);
+
+    if (!file) {
+        throw UtilsException("Read failed");
+    }
+    // 2 x faster then std::istreambuf_iterator
+    std::stringstream content;
+    content << file.rdbuf();
+    return content.str();
+}
+
+bool readFileStream(const std::string& path, std::string& result)
+{
+    std::ifstream file(path);
+
+    if (!file) {
+        return false;
+    }
+    std::stringstream content;
+    content << file.rdbuf();
+    result = content.str();
+    return true;
 }
 
 std::string readFileContent(const std::string& path)
 {
     std::string result;
+
     if (!readFileContent(path, result)) {
         throw UtilsException("Read failed");
     }
index e533670..2979c41 100644 (file)
@@ -39,6 +39,11 @@ namespace utils {
 std::string readFileStream(const std::string& path);
 
 /**
+ * Reads the content of file stream (no seek)
+ */
+bool readFileStream(const std::string& path, std::string& result);
+
+/**
  * Reads the content of a file (performs seek); Throws exception on error
  */
 std::string readFileContent(const std::string& path);
diff --git a/libs/lxcpp/cgroups/cgroup-config.hpp b/libs/lxcpp/cgroups/cgroup-config.hpp
new file mode 100644 (file)
index 0000000..82aa803
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ *  Copyright (C) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License version 2.1 as published by the Free Software Foundation.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+/**
+ * @file
+ * @author  Krzysztof Dynowski (k.dynowski@samsumg.com)
+ * @brief   Control-groups configuration
+ */
+
+#ifndef LXCPP_CGROUPS_CGROUP_CONFIG_HPP
+#define LXCPP_CGROUPS_CGROUP_CONFIG_HPP
+
+#include "config/config.hpp"
+#include "config/fields.hpp"
+
+#include <string>
+#include <vector>
+
+namespace lxcpp {
+
+struct SubsystemConfig {
+    std::string name;
+    std::string path;
+
+    CONFIG_REGISTER
+    (
+        name,
+        path
+    )
+};
+
+struct CGroupParam {
+    std::string name;
+    std::string value;
+
+    CONFIG_REGISTER
+    (
+        name,
+        value
+    )
+};
+
+struct CGroupConfig {
+    std::string subsystem;
+    std::string name;
+    std::vector<CGroupParam> common; // cgroup.*
+    std::vector<CGroupParam> params; // {name}.*
+
+    CONFIG_REGISTER
+    (
+        subsystem,
+        name,
+        common,
+        params
+    )
+};
+
+struct CGroupsConfig {
+    std::vector<SubsystemConfig> subsystems;
+    std::vector<CGroupConfig> cgroups;
+
+    CONFIG_REGISTER
+    (
+        subsystems,
+        cgroups
+    )
+};
+
+} // namespace lxcpp
+
+#endif //LXCPP_CGROUPS_CGROUP_CONFIG_HPP
index 5e72d21..a22b0dc 100644 (file)
@@ -23,6 +23,7 @@
 
 #include "lxcpp/cgroups/cgroup.hpp"
 #include "lxcpp/exception.hpp"
+#include "utils/exception.hpp"
 #include "utils/fs.hpp"
 #include "utils/text.hpp"
 #include "logger/logger.hpp"
@@ -35,6 +36,7 @@ namespace {
 std::string getSubsysName(const std::string& s)
 {
     auto p = s.find(':');
+
     if (p == std::string::npos) {
         const std::string msg = "wrong subsys format " + s;
         LOGE(msg);
@@ -46,6 +48,7 @@ std::string getSubsysName(const std::string& s)
 std::string getCGroupName(const std::string& s)
 {
     auto p = s.find(':');
+
     if (p == std::string::npos) {
         const std::string msg = "wrong cgroup format " + s;
         LOGE(msg);
@@ -65,6 +68,7 @@ CGroup::CGroup(const std::string& subsysAndCgroup) :
 bool CGroup::exists() const
 {
     const fs::path path = fs::path(mSubsys.getMountPoint()) / mName;
+
     return fs::is_directory(path);
 }
 
@@ -84,6 +88,7 @@ void CGroup::destroy()
 void CGroup::setCommonValue(const std::string& param, const std::string& value)
 {
     const fs::path path = fs::path(mSubsys.getMountPoint()) / mName / ("cgroup." + param);
+
     if (!utils::saveFileContent(path.string(), value)) {
         const std::string msg = "Invalid param " + param;
         LOGE(msg);
@@ -94,12 +99,20 @@ void CGroup::setCommonValue(const std::string& param, const std::string& value)
 std::string CGroup::getCommonValue(const std::string& param) const
 {
     const fs::path path = fs::path(mSubsys.getMountPoint()) / mName / ("cgroup." + param);
-    return utils::readFileStream(path.string());
+
+    try {
+        return utils::readFileStream(path.string());
+    } catch (const utils::UtilsException& e) {
+        const std::string msg = "Invalid param " + param;
+        LOGE(msg);
+        throw CGroupException(msg);
+    }
 }
 
 void CGroup::setValue(const std::string& param, const std::string& value)
 {
     const fs::path path = fs::path(mSubsys.getMountPoint()) / mName / (mSubsys.getName() + "." + param);
+
     if (!utils::saveFileContent(path.string(), value)) {
         const std::string msg = "Invalid param " + param;
         LOGE(msg);
@@ -110,7 +123,14 @@ void CGroup::setValue(const std::string& param, const std::string& value)
 std::string CGroup::getValue(const std::string& param) const
 {
     const fs::path path = fs::path(mSubsys.getMountPoint()) / mName / (mSubsys.getName() + "." + param);
-    return utils::readFileStream(path.string());
+
+    try {
+        return utils::readFileStream(path.string());
+    } catch (const utils::UtilsException& e) {
+        const std::string msg = "Invalid param " + param;
+        LOGE(msg);
+        throw CGroupException(msg);
+    }
 }
 
 void CGroup::assignGroup(pid_t pid)
@@ -128,6 +148,7 @@ std::vector<pid_t> CGroup::getPids() const
 {
     const fs::path path = fs::path(mSubsys.getMountPoint()) / mName / "tasks";
     std::ifstream fileStream(path.string());
+
     if (!fileStream.good()) {
         const std::string msg = "Failed to open " + path.string();
         LOGE(msg);
@@ -147,6 +168,7 @@ std::vector<pid_t> CGroup::getPids() const
 CGroup CGroup::getCGroup(const std::string& subsys, pid_t pid)
 {
     std::vector<std::string> cgroups = Subsystem::getCGroups(pid);
+
     for (const auto& i : cgroups) {
         if (utils::beginsWith(i, subsys + ":")) {
             return CGroup(i);
index c65c12d..ffde06c 100644 (file)
@@ -32,7 +32,8 @@ class CGroup {
 
 public:
     /**
-     * Define control-group object
+     * Define control-group object.
+     * Name can be also considered as path relative to root of subsystem.
      */
     CGroup(const std::string& subsys, const std::string& name) :
         mSubsys(subsys),
@@ -41,18 +42,18 @@ public:
     }
 
     /**
-     * Define control-group object (format "subsys:cgroup_path")
+     * Define control-group object (format "subsys:cgroup_path").
      */
     CGroup(const std::string& subsysAndCgroup);
 
     /**
-     * Check if cgroup exists
+     * Check if cgroup exists.
      * @return true if cgroup path (subsys.path / mName) exists
      */
     bool exists() const;
 
     /**
-     * Create cgroup directory
+     * Create cgroup directory.
      * Equivalent of: mkdir subsys.path / mName
      */
     void create();
@@ -60,54 +61,54 @@ public:
     /**
      * Destroy cgroup directory
      * Equivalent of: rmdir subsys.path / mName
-     * Note: set memory.force_empty before removing a cgroup to avoid moving out-of-use page caches to parent
+     * Note: set memory.force_empty before removing a cgroup to avoid moving out-of-use page caches to parent.
      */
     void destroy();
 
     /**
-     * Set common 'cgroup' paramter
+     * Set common 'cgroup' parameter.
      * Equivalent of: echo value > mSubsys_path/mName/cgroup.param
      */
     void setCommonValue(const std::string& param, const std::string& value);
 
     /**
-     * Get common 'cgroup' paramter
+     * Get common 'cgroup' paramter.
      * Equivalent of: cat mSubsys_path/mName/cgroup.param
      */
     std::string getCommonValue(const std::string& param) const;
 
     /**
-     * Set cgroup parameter to value (name validity depends on subsystem)
+     * Set cgroup parameter to value (name validity depends on subsystem).
      * Equivalent of: echo value > mSubsys_path/mName/mSubsys_name.param
      */
     void setValue(const std::string& param, const std::string& value);
 
     /**
-     * Get cgroup parameter
+     * Get cgroup parameter.
      * Equivalent of: cat mSubsys_path/mName/mSubsys_name.param
      */
     std::string getValue(const std::string& param) const;
 
     /**
-     * Assign all processes in threadgroup of pid to this cgroup
+     * Assign all processes in threadgroup of pid to this cgroup.
      * Equivalent of: echo pid > mSubsys_path/mName/cgroup.procs
      */
     void assignGroup(pid_t pid);
 
     /**
-     * Assign single process to this cgroup (will be removed from previous cgroup automatically)
+     * Assign single process to this cgroup (will be removed from previous cgroup automatically).
      * Equivalent of: echo pid > mSubsys_path/mName/tasks
      */
     void assignPid(pid_t pid);
 
     /**
-     * Get list of pid assigned to this group
+     * Get list of pid assigned to this group.
      * Equivalent of: cat mSubsys_path/mName/tasks
      */
     std::vector<pid_t> getPids() const;
 
     /**
-     * Get cgroup of process pid in given subsystem
+     * Get cgroup of process pid in given subsystem.
      */
     static CGroup getCGroup(const std::string& subsys, pid_t pid);
 
diff --git a/libs/lxcpp/commands/cgroups.cpp b/libs/lxcpp/commands/cgroups.cpp
new file mode 100644 (file)
index 0000000..76b2587
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ *  Copyright (C) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License version 2.1 as published by the Free Software Foundation.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+/**
+ * @file
+ * @author  Krzysztof Dynowski (k.dynowski@samsumg.com)
+ * @brief   CGroups configuration command
+ */
+
+#include "lxcpp/commands/cgroups.hpp"
+#include "lxcpp/cgroups/cgroup.hpp"
+#include "lxcpp/exception.hpp"
+#include "logger/logger.hpp"
+
+namespace lxcpp {
+
+void CGroupMakeAll::execute()
+{
+    for (const auto i : mCgroups.subsystems) {
+        SubsystemMake(i).execute();
+    }
+
+    for (const auto i : mCgroups.cgroups) {
+        CGroupMake(i).execute();
+    }
+}
+
+void SubsystemMake::execute()
+{
+    Subsystem sub(mSubsys.name);
+
+    if (!sub.isAttached()) {
+        sub.attach(mSubsys.path, {mSubsys.name});
+    } else if (sub.getMountPoint() != mSubsys.path) {
+        std::string msg = "Subsys " + mSubsys.name + " already mounted elsewhere";
+        LOGW(msg);
+        // no exception, usually subsystems are mounted
+    }
+}
+
+void CGroupMake::execute()
+{
+    CGroup cgroup(mCgroup.subsystem, mCgroup.name);
+
+    if (!cgroup.exists()) {
+        cgroup.create();
+    }
+
+    for (const auto p : mCgroup.common) {
+        cgroup.setCommonValue(p.name, p.value);
+    }
+
+    for (const auto p : mCgroup.params) {
+        cgroup.setValue(p.name, p.value);
+    }
+}
+
+void CGroupAssignPid::execute()
+{
+    CGroup cgroup(mSubsysName, mCgroupName);
+
+    cgroup.assignPid(mPid);
+}
+
+} // namespace lxcpp
diff --git a/libs/lxcpp/commands/cgroups.hpp b/libs/lxcpp/commands/cgroups.hpp
new file mode 100644 (file)
index 0000000..32f189b
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ *  Copyright (C) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License version 2.1 as published by the Free Software Foundation.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+/**
+ * @file
+ * @author  Krzysztof Dynowski (k.dynowski@samsumg.com)
+ * @brief   CGroups configuration command
+ */
+
+#ifndef LXCPP_COMMANDS_CGROUPS_HPP
+#define LXCPP_COMMANDS_CGROUPS_HPP
+
+#include "lxcpp/commands/command.hpp"
+#include "lxcpp/cgroups/cgroup-config.hpp"
+
+
+namespace lxcpp {
+
+class CGroupMakeAll final: Command {
+public:
+   /**
+    * Creates and configures cgroups.
+    */
+    CGroupMakeAll(const CGroupsConfig& cfg) :
+        mCgroups(cfg)
+    {
+    }
+
+    void execute();
+
+private:
+    const CGroupsConfig& mCgroups;
+};
+
+class SubsystemMake final: Command {
+public:
+   /**
+    * Creates and configures cgroup subsystem.
+    */
+    SubsystemMake(const SubsystemConfig& cfg) :
+        mSubsys(cfg)
+    {
+    }
+
+    void execute();
+
+private:
+    const SubsystemConfig& mSubsys;
+};
+
+class CGroupMake final: Command {
+public:
+   /**
+    * Creates and configures cgroup.
+    */
+    CGroupMake(const CGroupConfig& cfg) :
+        mCgroup(cfg)
+    {
+    }
+
+    void execute();
+
+private:
+    const CGroupConfig& mCgroup;
+};
+
+class CGroupAssignPid final: Command {
+public:
+   /**
+    * Add pid to existng group.
+    */
+    CGroupAssignPid(const std::string& subsys, const std::string& cgroup, pid_t pid) :
+        mSubsysName(subsys),
+        mCgroupName(cgroup),
+        mPid(pid)
+    {
+    }
+
+    void execute();
+
+private:
+    std::string mSubsysName;
+    std::string mCgroupName;
+    pid_t mPid;
+};
+
+} // namespace lxcpp
+
+#endif //LXCPP_COMMANDS_CGROUPS_HPP
index 05f11ed..896a817 100644 (file)
@@ -29,6 +29,7 @@
 #include "lxcpp/terminal-config.hpp"
 #include "lxcpp/provision-config.hpp"
 #include "lxcpp/userns-config.hpp"
+#include "lxcpp/cgroups/cgroup-config.hpp"
 
 #include <config/config.hpp>
 #include <config/fields.hpp>
@@ -135,6 +136,11 @@ struct ContainerConfig {
      */
     UserNSConfig mUserNSConfig;
 
+    /*
+     * CGropus configuration
+     */
+    CGroupsConfig mCgroups;
+
     ContainerConfig() : mGuardPid(-1), mInitPid(-1), mNamespaces(0) {}
 
     CONFIG_REGISTER
index 33331a2..df22f37 100644 (file)
@@ -418,4 +418,17 @@ void ContainerImpl::removeLink(const provision::Link& item)
     }
 }
 
+void ContainerImpl::addSubsystem(const std::string& name, const std::string& path)
+{
+    mConfig.mCgroups.subsystems.push_back(SubsystemConfig{name, path});
+}
+
+void ContainerImpl::addCGroup(const std::string& subsys,
+                              const std::string& grpname,
+                              const std::vector<CGroupParam>& comm,
+                              const std::vector<CGroupParam>& params)
+{
+    mConfig.mCgroups.cgroups.push_back(CGroupConfig{subsys, grpname, comm, params});
+}
+
 } // namespace lxcpp
index a759929..eba479a 100644 (file)
@@ -118,6 +118,13 @@ public:
     const LinkVector& getLinks() const;
     void removeLink(const provision::Link& item);
 
+    // CGroups
+    void addSubsystem(const std::string& name, const std::string& path);
+    void addCGroup(const std::string& subsys,
+                   const std::string& grpname,
+                   const std::vector<CGroupParam>& comm,
+                   const std::vector<CGroupParam>& params);
+
 private:
     ContainerConfig mConfig;
 };
index bc43066..f1f2785 100644 (file)
@@ -26,6 +26,7 @@
 
 #include "lxcpp/network-config.hpp"
 #include "lxcpp/provision-config.hpp"
+#include "lxcpp/cgroups/cgroup-config.hpp"
 #include "lxcpp/logger-config.hpp"
 
 #include <sys/types.h>
@@ -123,6 +124,13 @@ public:
                              const std::string& target) = 0;
     virtual const LinkVector& getLinks() const = 0;
     virtual void removeLink(const provision::Link& item) = 0;
+
+    // CGroups
+    virtual void addSubsystem(const std::string& name, const std::string& path) = 0;
+    virtual void addCGroup(const std::string& subsys,
+                           const std::string& grpname,
+                           const std::vector<CGroupParam>& comm,
+                           const std::vector<CGroupParam>& params) = 0;
 };
 
 } // namespace lxcpp
index 5bde171..e9eddab 100644 (file)
  */
 
 #include "config.hpp"
+#include "config/manager.hpp"
 #include "ut.hpp"
 #include "logger/logger.hpp"
 
 #include "lxcpp/cgroups/devices.hpp"
+#include "lxcpp/cgroups/cgroup-config.hpp"
+
+#include "lxcpp/commands/cgroups.hpp"
+
 #include "lxcpp/exception.hpp"
 #include "utils/text.hpp"
 
@@ -46,6 +51,7 @@ using namespace lxcpp;
 BOOST_AUTO_TEST_CASE(GetAvailable)
 {
     std::vector<std::string> subs;
+
     BOOST_CHECK_NO_THROW(subs = Subsystem::availableSubsystems());
     BOOST_CHECK_MESSAGE(subs.size() > 0, "Control groups not supported");
     for (auto n : subs){
@@ -57,6 +63,7 @@ BOOST_AUTO_TEST_CASE(GetAvailable)
 BOOST_AUTO_TEST_CASE(GetCGroupsByPid)
 {
     std::vector<std::string> cg;
+
     BOOST_CHECK_NO_THROW(cg=Subsystem::getCGroups(::getpid()));
     BOOST_CHECK(cg.size() > 0);
 }
@@ -65,6 +72,7 @@ BOOST_AUTO_TEST_CASE(GetPidsByCGroup)
 {
     CGroup cg = CGroup::getCGroup("memory", ::getpid());
     std::vector<pid_t> pids;
+
     BOOST_CHECK_NO_THROW(pids = cg.getPids());
     BOOST_CHECK(pids.size() > 0);
 }
@@ -72,6 +80,7 @@ BOOST_AUTO_TEST_CASE(GetPidsByCGroup)
 BOOST_AUTO_TEST_CASE(SubsysAttach)
 {
     Subsystem sub("freezer");
+
     BOOST_CHECK_MESSAGE(sub.isAvailable(), "freezer not found");
 
     if (!sub.isAvailable()) return ;
@@ -95,33 +104,84 @@ BOOST_AUTO_TEST_CASE(SubsysAttach)
 BOOST_AUTO_TEST_CASE(ControlGroupParams)
 {
     CGroup memg("memory:/ut-params");
-    BOOST_CHECK(memg.exists() == false);
+
+    // this test can fail if prev. test round left unexpected
+    BOOST_CHECK_MESSAGE(memg.exists() == false, "Cgroup alredy exists");
     BOOST_CHECK_NO_THROW(memg.create());
     BOOST_CHECK(memg.exists() == true);
 
-    if (!memg.exists()) return ;
+    if (!memg.exists()) {
+        return ;
+    }
+
+    BOOST_CHECK_NO_THROW(memg.assignPid(::getpid()));
+    BOOST_CHECK_NO_THROW(memg.assignGroup(::getpid()));
 
-    memg.assignPid(::getpid());
-    memg.setValue("limit_in_bytes", "10k");
-    memg.setValue("soft_limit_in_bytes", "10k");
+    BOOST_CHECK_NO_THROW(memg.setValue("limit_in_bytes", "10k"));
+    BOOST_CHECK_NO_THROW(memg.setValue("soft_limit_in_bytes", "10k"));
+    BOOST_CHECK_THROW(memg.getValue("non-existing-name"), CGroupException);
     BOOST_CHECK_THROW(memg.setValue("non-existing-name", "xxx"), CGroupException);
 
     LOGD("limit_in_bytes: " << memg.getValue("limit_in_bytes"));
     LOGD("soft_limit_in_bytes: " << memg.getValue("soft_limit_in_bytes"));
     LOGD("max_usage_in_bytes: " << memg.getValue("max_usage_in_bytes"));
 
-    CGroup("memory:/").assignPid(::getpid());
+    CGroup memtop("memory:/");
+    memtop.assignPid(::getpid());
+    memtop.setCommonValue("procs", std::to_string(::getpid()));
+
     BOOST_CHECK_NO_THROW(memg.destroy());
 }
 
 BOOST_AUTO_TEST_CASE(DevicesParams)
 {
-    DevicesCGroup devcg("/");
-    std::vector<DevicePermission> list = devcg.list();
+    DevicesCGroup devgrp("/tmp");
+
+    BOOST_CHECK_NO_THROW(devgrp.create());
+
+    std::vector<DevicePermission> list;
+    BOOST_CHECK_NO_THROW(list = devgrp.list());
     for (__attribute__((unused)) const auto& i : list) {
         LOGD(std::string("perm = ") + i.type + " " +
              std::to_string(i.major) + ":" + std::to_string(i.minor) + " " + i.permission);
     }
+
+    BOOST_CHECK_NO_THROW(devgrp.destroy());
+}
+
+BOOST_AUTO_TEST_CASE(CGroupConfigSerialization)
+{
+    CGroupsConfig cfg;
+    std::string tmpConfigFile = "/tmp/cgconfig.conf";
+
+    BOOST_CHECK_NO_THROW(config::saveToJsonString(cfg));
+
+    cfg.subsystems.push_back(SubsystemConfig{"cpu", "/tmp/cgroup/cpu"});
+
+    CGroupConfig cpucfg = {"cpu", "/testcpu", {}, {}};
+    cfg.cgroups.push_back(cpucfg);
+    config::saveToJsonFile(tmpConfigFile, cfg);
+
+    CGroupsConfig cfg2;
+    BOOST_CHECK_NO_THROW(config::loadFromJsonFile(tmpConfigFile, cfg2));
+    BOOST_CHECK(cfg2.subsystems.size()==cfg.subsystems.size());
+}
+
+BOOST_AUTO_TEST_CASE(CGroupCommands)
+{
+    CGroupsConfig cfg;
+    Subsystem sub("cpu");
+    std::string mp = sub.isAttached() ? sub.getMountPoint() : "/tmp/cgroup/cpu";
+
+    cfg.subsystems.push_back(SubsystemConfig{"cpu", mp});
+    CGroupConfig cpucfg = {"cpu", "/testcpu", {}, {}};
+    cfg.cgroups.push_back(cpucfg);
+
+    CGroupMakeAll cmd(cfg);
+    BOOST_CHECK_NO_THROW(cmd.execute());
+
+    CGroup cpugrp("cpu", "/testcpu");
+    BOOST_CHECK_NO_THROW(cpugrp.destroy());
 }
 
 BOOST_AUTO_TEST_SUITE_END()
index 75b94c1..2776be6 100644 (file)
@@ -151,7 +151,7 @@ BOOST_AUTO_TEST_CASE(NetworkConfigSerialization)
     config::saveToJsonFile(tmpConfigFile, cfg);
 
     NetworkConfig cfg2;
-    config::loadFromJsonFile(tmpConfigFile, cfg2);
+    BOOST_CHECK_NO_THROW(config::loadFromJsonFile(tmpConfigFile, cfg2));
 
     int ifnum = cfg.getInterfaces().size();
     for (int i = 0; i < ifnum; ++i) {