Proper switching focus between containers without freezing background ones
authorLukasz Pawelczyk <l.pawelczyk@partner.samsung.com>
Fri, 28 Mar 2014 12:39:21 +0000 (13:39 +0100)
committerJan Olszak <j.olszak@samsung.com>
Mon, 19 May 2014 11:47:15 +0000 (13:47 +0200)
[Bug/Feature]   The current focus switching was freezing all
                background containers
[Cause]         N/A
[Solution]      The idea is that a background container should be able to
                respond to messages/notifications. It cannot be frozen.
                At least not completely (user applications might, system
                daemons/services shouldn't). This change starts the
                foundations for such operations:
                - added functions for settings and getting scheduler
                  options for CFS scheduler using libvirt API
                - some cleanups in ContainerAdmin class
                - removal of getAdmin() and new API for the Container class
                - new tests for all the new functionalities
                - restructurization of config files for unit_tests
                  (one directory of configs per class)
                - removal of "config" in: /etc/security-containers/config/
[Verification]  Build, install, run tests on host, build RPM

Change-Id: I2288b71632a6c8043fe47244fa9c0754241cba88
Signed-off-by: Lukasz Pawelczyk <l.pawelczyk@partner.samsung.com>
36 files changed:
CMakeLists.txt
astylerc
packaging/security-containers.spec
src/server/config/containers/xminimal.conf
src/server/include/scs-container-admin.hpp
src/server/include/scs-container-config.hpp
src/server/include/scs-container-manager-config.hpp
src/server/include/scs-container-manager.hpp
src/server/include/scs-container.hpp
src/server/src/scs-container-admin.cpp
src/server/src/scs-container-manager.cpp
src/server/src/scs-container.cpp
src/server/unit_tests/CMakeLists.txt
src/server/unit_tests/config/ut-scs-container-admin/containers/buggy.conf [new file with mode: 0644]
src/server/unit_tests/config/ut-scs-container-admin/containers/missing.conf [new file with mode: 0644]
src/server/unit_tests/config/ut-scs-container-admin/containers/test.conf [new file with mode: 0644]
src/server/unit_tests/config/ut-scs-container-admin/libvirt-config/buggy.xml [moved from src/server/unit_tests/config/ut-scs-container-manager/libvirt-config/buggy.xml with 100% similarity]
src/server/unit_tests/config/ut-scs-container-admin/libvirt-config/test.xml [moved from src/server/unit_tests/config/ut-scs-container-manager/libvirt-config/test.xml with 100% similarity]
src/server/unit_tests/config/ut-scs-container-manager/buggy-daemon.conf
src/server/unit_tests/config/ut-scs-container-manager/buggy-foreground-daemon.conf [new file with mode: 0644]
src/server/unit_tests/config/ut-scs-container-manager/containers/buggy.conf [deleted file]
src/server/unit_tests/config/ut-scs-container-manager/containers/console.conf [deleted file]
src/server/unit_tests/config/ut-scs-container-manager/containers/console1.conf
src/server/unit_tests/config/ut-scs-container-manager/containers/console2.conf [new file with mode: 0644]
src/server/unit_tests/config/ut-scs-container-manager/containers/console3.conf [new file with mode: 0644]
src/server/unit_tests/config/ut-scs-container-manager/containers/test.conf [deleted file]
src/server/unit_tests/config/ut-scs-container-manager/libvirt-config/console2.xml [moved from src/server/unit_tests/config/ut-scs-container-manager/libvirt-config/console.xml with 87% similarity]
src/server/unit_tests/config/ut-scs-container-manager/libvirt-config/console3.xml [new file with mode: 0644]
src/server/unit_tests/config/ut-scs-container-manager/test-daemon.conf
src/server/unit_tests/config/ut-scs-container/containers/buggy.conf [new file with mode: 0644]
src/server/unit_tests/config/ut-scs-container/containers/test.conf [new file with mode: 0644]
src/server/unit_tests/config/ut-scs-container/libvirt-config/test.xml [new file with mode: 0644]
src/server/unit_tests/ut-dbus-connection.cpp
src/server/unit_tests/ut-scs-container-admin.cpp
src/server/unit_tests/ut-scs-container-manager.cpp
src/server/unit_tests/ut-scs-container.cpp

index 340b1bf..bc1e262 100644 (file)
@@ -79,7 +79,7 @@ IF(NOT DEFINED SCRIPT_INSTALL_DIR)
     SET(SCRIPT_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/sbin")
 ENDIF(NOT DEFINED SCRIPT_INSTALL_DIR)
 
-SET(SC_CONFIG_INSTALL_DIR ${SYSCONF_INSTALL_DIR}/security-containers/config)
+SET(SC_CONFIG_INSTALL_DIR ${SYSCONF_INSTALL_DIR}/security-containers)
 
 ADD_SUBDIRECTORY(src)
 
index eecd3ee..c9619b6 100644 (file)
--- a/astylerc
+++ b/astylerc
@@ -3,7 +3,7 @@ suffix=none
 indent=spaces=4
 indent-col1-comments
 min-conditional-indent=2
-max-instatement-indent=40
+max-instatement-indent=100
 pad-oper
 pad-header
 unpad-paren
index 7477661..38dfedc 100644 (file)
@@ -23,9 +23,9 @@ between them. A process from inside a container can request a switch of context
 
 %files
 %attr(755,root,root) %{_bindir}/security-containers-server
-%config %attr(644,root,root) /etc/security-containers/config/daemon.conf
-%config %attr(644,root,root) /etc/security-containers/config/containers/xminimal.conf
-%config %attr(400,root,root) /etc/security-containers/config/libvirt-config/*.xml
+%config %attr(644,root,root) /etc/security-containers/daemon.conf
+%config %attr(644,root,root) /etc/security-containers/containers/xminimal.conf
+%config %attr(400,root,root) /etc/security-containers/libvirt-config/*.xml
 
 %prep
 %setup -q
@@ -103,7 +103,11 @@ Unit tests for both: server and client.
 %attr(755,root,root) %{script_dir}/sc_all_tests.py
 %attr(755,root,root) %{script_dir}/sc_launch_test.py
 %{script_dir}/sc_test_parser.py
-%config %attr(644,root,root) /etc/security-containers/config/tests/ut-scs-container-manager/*.conf
-%config %attr(644,root,root) /etc/security-containers/config/tests/ut-scs-container-manager/containers/*.conf
-%config %attr(644,root,root) /etc/security-containers/config/tests/ut-scs-container-manager/libvirt-config/*.xml
-%config %attr(644,root,root) /etc/security-containers/config/tests/ut-dbus-connection/*.conf
+%config %attr(644,root,root) /etc/security-containers/tests/ut-scs-container-manager/*.conf
+%config %attr(644,root,root) /etc/security-containers/tests/ut-scs-container-manager/containers/*.conf
+%config %attr(644,root,root) /etc/security-containers/tests/ut-scs-container-manager/libvirt-config/*.xml
+%config %attr(644,root,root) /etc/security-containers/tests/ut-scs-container/containers/*.conf
+%config %attr(644,root,root) /etc/security-containers/tests/ut-scs-container/libvirt-config/*.xml
+%config %attr(644,root,root) /etc/security-containers/tests/ut-scs-container-admin/containers/*.conf
+%config %attr(644,root,root) /etc/security-containers/tests/ut-scs-container-admin/libvirt-config/*.xml
+%config %attr(644,root,root) /etc/security-containers/tests/ut-dbus-connection/*.conf
index 7d6210f..dfc1e49 100644 (file)
@@ -1,4 +1,6 @@
 {
+    "cpuQuotaForeground" : 1,
+    "cpuQuotaBackground" : 0.01,
     "privilege" : 10,
     "config" : "../libvirt-config/xminimal.xml"
 }
index 261df60..7aa7977 100644 (file)
 #ifndef SECURITY_CONTAINERS_SERVER_CONTAINER_ADMIN_HPP
 #define SECURITY_CONTAINERS_SERVER_CONTAINER_ADMIN_HPP
 
+#include "scs-container-config.hpp"
+
 #include <string>
+#include <cstdint>
 #include <libvirt/libvirt.h>
 
 namespace security_containers {
 
+enum class SchedulerLevel {
+    FOREGROUND,
+    BACKGROUND
+};
+
 class ContainerAdmin {
 
 public:
-    ContainerAdmin(const std::string& libvirtConfigPath);
+    ContainerAdmin(ContainerConfig& config);
     virtual ~ContainerAdmin();
 
     /**
@@ -43,7 +51,7 @@ public:
     std::string getId();
 
     /**
-     * Boot the container
+     * Boot the container to the background.
      */
     void start();
 
@@ -60,7 +68,7 @@ public:
     void shutdown();
 
     /**
-     * @return Is the process started?
+     * @return Is the container running?
      */
     bool isRunning();
 
@@ -69,7 +77,7 @@ public:
      * because it checks different internal libvirt's states. There are other states,
      * (e.g. paused) when the container isn't runnig nor stopped.
      *
-     * @return Is the process stopped?
+     * @return Is the container stopped?
      */
     bool isStopped();
 
@@ -91,11 +99,24 @@ public:
      */
     bool isPaused();
 
+    /**
+     * Sets the containers scheduler CFS quota.
+     */
+    void setSchedulerLevel(SchedulerLevel sched);
+
+    /**
+     * @return Scheduler CFS quota,
+     * TODO: this function is only for UNIT TESTS
+     */
+    std::int64_t getSchedulerQuota();
+
 private:
     // TODO: secure those pointers from exceptions (e.g. in constructor)
     virConnectPtr mVir = NULL; // pointer to the connection with libvirt
     virDomainPtr  mDom = NULL; // pointer to the domain
 
+    ContainerConfig& mConfig;
+
     // TODO: This is a temporary sollution.
     const std::string mDefaultConfigXML = "<domain type=\"lxc\">\
                                          <name>cnsl</name>\
@@ -113,9 +134,8 @@ private:
     void disconnect(); // release mVir
     void define(const std::string& configXML); // containers can't share the same libvirt configuration
     void undefine();
-
     int  getState();   // get the libvirt's domain state
-    bool isPMSuspended(); // the cotainer suspended by the power manager
+    void setSchedulerParams(std::uint64_t cpuShares, std::uint64_t vcpuPeriod, std::int64_t vcpuQuota);
 };
 }
 #endif // SECURITY_CONTAINERS_SERVER_CONTAINER_ADMIN_HPP
index dccfbdc..5787182 100644 (file)
@@ -44,9 +44,21 @@ struct ContainerConfig : public ConfigurationBase {
      */
     std::string config;
 
+    /**
+     * Container's CFS quota in us when it's in the foreground
+     */
+    double cpuQuotaForeground;
+
+    /**
+     * Container's CFS quota in us when it's in the background
+     */
+    double cpuQuotaBackground;
+
     CONFIG_REGISTER {
         CONFIG_VALUE(privilege)
         CONFIG_VALUE(config)
+        CONFIG_VALUE(cpuQuotaForeground)
+        CONFIG_VALUE(cpuQuotaBackground)
     }
 };
 
index d9b90b2..1bfa8be 100644 (file)
@@ -41,8 +41,14 @@ struct ContainerManagerConfig : public ConfigurationBase {
      */
     std::vector<std::string> containerConfigs;
 
+    /**
+     * An ID of a currently focused/foreground container.
+     */
+    std::string foregroundId;
+
     CONFIG_REGISTER {
         CONFIG_VALUE(containerConfigs)
+        CONFIG_VALUE(foregroundId)
     }
 };
 
index 315d780..7f2cba2 100644 (file)
@@ -43,7 +43,7 @@ public:
     ~ContainerManager();
 
     /**
-     * Switch to this container.
+     * Focus this container, put it to the foreground.
      * Method blocks until the focus is switched.
      *
      * @param containerId id of the container
@@ -61,20 +61,16 @@ public:
     void stopAll();
 
     /**
-     * @return id of the currently running container
+     * @return id of the currently focused/foreground container
      */
-    std::string getRunningContainerId();
-
-    /**
-     * @return vector of suspended container ids
-     */
-    std::vector<std::string> getSuspendedContainerIds();
+    std::string getRunningForegroundContainerId();
 
 private:
     ContainerManagerConfig mConfig;
     // TODO: secure this pointer from exceptions (e.g. in constructor)
     virConnectPtr mVir = NULL; // pointer to the connection with libvirt
-    std::unordered_map<std::string, std::unique_ptr<Container>> mContainers; // map of containers, id is the key
+    typedef std::unordered_map<std::string, std::unique_ptr<Container>> ContainerMap;
+    ContainerMap mContainers; // map of containers, id is the key
 
     void connect();
     void disconnect();
index 5cf2f2f..3fc12e7 100644 (file)
@@ -41,7 +41,56 @@ public:
     Container(Container&&) = default;
     virtual ~Container();
 
-    ContainerAdmin& getAdmin();
+    /**
+     * Get the container id
+     */
+    std::string getId();
+
+    /**
+     * Get the container privilege
+     */
+    int getPrivilege();
+
+    /**
+     * Boot the container to the background.
+     */
+    void start();
+
+    /**
+     * Forcefully stop the container.
+     */
+    void stop();
+
+    /**
+     * Setup this container to be put in the foreground.
+     * I.e. set appropriate scheduler level.
+     */
+    void goForeground();
+
+    /**
+     * Setup this container to be put in the background.
+     * I.e. set appropriate scheduler level.
+     */
+    void goBackground();
+
+    /**
+     * @return Is the container running?
+     */
+    bool isRunning();
+
+    /**
+     * Check if the container is stopped. It's NOT equivalent to !isRunning,
+     * because it checks different internal libvirt's states. There are other states,
+     * (e.g. paused) when the container isn't runnig nor stopped.
+     *
+     * @return Is the container stopped?
+     */
+    bool isStopped();
+
+    /**
+     * @return Is the container in a paused state?
+     */
+    bool isPaused();
 
 private:
     ContainerConfig mConfig;
index aa6d54e..8b3fa65 100644 (file)
 #include <string>
 #include <fstream>
 #include <streambuf>
+#include <memory>
+#include <cstdint>
 
 namespace security_containers {
 
-ContainerAdmin::ContainerAdmin(const std::string& libvirtConfigPath)
+const std::uint64_t DEFAULT_CPU_SHARES = 1024;
+const std::uint64_t DEFAULT_VCPU_PERIOD_MS = 100000;
+
+ContainerAdmin::ContainerAdmin(ContainerConfig& config)
+    : mConfig(config)
 {
     connect();
-    std::ifstream t(libvirtConfigPath);
+    std::ifstream t(mConfig.config);
     if (!t.is_open()) {
         LOGE("libvirt config file is missing");
         throw ConfigException();
@@ -50,7 +56,6 @@ ContainerAdmin::~ContainerAdmin()
 {
     // Try to shutdown
     try {
-        resume();
         shutdown();
     } catch (ServerException& e) {}
 
@@ -123,6 +128,11 @@ void ContainerAdmin::start()
         LOGE("Failed to start the container");
         throw DomainOperationException();
     }
+
+    // TODO: the container should be started in the background,
+    // unfortunately libvirt doesn't allow us to set cgroups
+    // before the start, hence we do it immediately afterwards
+    setSchedulerLevel(SchedulerLevel::BACKGROUND);
 }
 
 
@@ -131,7 +141,7 @@ void ContainerAdmin::stop()
     assert(mVir != NULL);
     assert(mDom != NULL);
 
-    if (!isRunning()) {
+    if (isStopped()) {
         return;
     }
 
@@ -150,10 +160,12 @@ void ContainerAdmin::shutdown()
     assert(mVir != NULL);
     assert(mDom != NULL);
 
-    if (!isRunning()) {
+    if (isStopped()) {
         return;
     }
 
+    resume();
+
     if (virDomainShutdown(mDom) < 0) {
         LOGE("Error during domain shutdown");
         throw DomainOperationException();
@@ -223,7 +235,7 @@ void ContainerAdmin::suspend()
         return;
     }
 
-    if (isPMSuspended() || virDomainSuspend(mDom) < 0) {
+    if (virDomainSuspend(mDom) < 0) {
         LOGE("Error during domain suspension");
         throw DomainOperationException();
     }
@@ -239,7 +251,7 @@ void ContainerAdmin::resume()
         return;
     }
 
-    if (isPMSuspended() || virDomainResume(mDom) < 0) {
+    if (virDomainResume(mDom) < 0) {
         LOGE("Error during domain resumming");
         throw DomainOperationException();
     }
@@ -252,12 +264,6 @@ bool ContainerAdmin::isPaused()
 }
 
 
-bool ContainerAdmin::isPMSuspended()
-{
-    return getState() == VIR_DOMAIN_PMSUSPENDED;
-}
-
-
 int ContainerAdmin::getState()
 {
     assert(mVir != NULL);
@@ -273,4 +279,79 @@ int ContainerAdmin::getState()
     return state;
 }
 
+
+void ContainerAdmin::setSchedulerLevel(SchedulerLevel sched)
+{
+    switch (sched) {
+    case SchedulerLevel::FOREGROUND:
+        setSchedulerParams(DEFAULT_CPU_SHARES,
+                           DEFAULT_VCPU_PERIOD_MS,
+                           mConfig.cpuQuotaForeground);
+        break;
+    case SchedulerLevel::BACKGROUND:
+        setSchedulerParams(DEFAULT_CPU_SHARES,
+                           DEFAULT_VCPU_PERIOD_MS,
+                           mConfig.cpuQuotaBackground);
+        break;
+    default:
+        assert(!"Unknown sched parameter value");
+    }
+}
+
+
+void ContainerAdmin::setSchedulerParams(std::uint64_t cpuShares, std::uint64_t vcpuPeriod, std::int64_t vcpuQuota)
+{
+    assert(mVir != NULL);
+    assert(mDom != NULL);
+
+    int maxParams = 3;
+    int numParamsBuff = 0;
+
+    std::unique_ptr<virTypedParameter[]> params(new virTypedParameter[maxParams]);
+
+    virTypedParameterPtr paramsTmp = params.get();
+
+    virTypedParamsAddULLong(&paramsTmp, &numParamsBuff, &maxParams, VIR_DOMAIN_SCHEDULER_CPU_SHARES, cpuShares);
+    virTypedParamsAddULLong(&paramsTmp, &numParamsBuff, &maxParams, VIR_DOMAIN_SCHEDULER_VCPU_PERIOD, vcpuPeriod);
+    virTypedParamsAddLLong(&paramsTmp, &numParamsBuff, &maxParams, VIR_DOMAIN_SCHEDULER_VCPU_QUOTA, vcpuQuota);
+
+    if (virDomainSetSchedulerParameters(mDom, params.get(), numParamsBuff) < 0) {
+        LOGE("Error whilte setting scheduler params");
+        throw DomainOperationException();
+    }
+}
+
+
+std::int64_t ContainerAdmin::getSchedulerQuota()
+{
+    assert(mVir != NULL);
+    assert(mDom != NULL);
+
+    int numParamsBuff;
+    std::unique_ptr<char, void(*)(void*)> type(virDomainGetSchedulerType(mDom, &numParamsBuff), free);
+
+    if (type == NULL || numParamsBuff <= 0 || strcmp(type.get(), "posix") != 0) {
+        LOGE("Error while getting scheduler type");
+        throw DomainOperationException();
+    }
+
+    std::unique_ptr<virTypedParameter[]> params(new virTypedParameter[numParamsBuff]);
+
+    if (virDomainGetSchedulerParameters(mDom, params.get(), &numParamsBuff) < 0) {
+        LOGE("Error whilte getting scheduler parameters");
+        throw DomainOperationException();
+    }
+
+    long long quota;
+    if (virTypedParamsGetLLong(params.get(),
+                               numParamsBuff,
+                               VIR_DOMAIN_SCHEDULER_VCPU_QUOTA,
+                               &quota) <= 0) {
+        LOGE("Error whilte getting scheduler quota parameter");
+        throw DomainOperationException();
+    }
+
+    return quota;
+}
+
 } // namespace security_containers
index d705e99..da31f67 100644 (file)
 
 #include <assert.h>
 #include <string>
+#include <climits>
 
 namespace security_containers {
 
+
 ContainerManager::ContainerManager(const std::string& managerConfigPath)
 {
     mConfig.parseFile(managerConfigPath);
@@ -50,7 +52,7 @@ ContainerManager::ContainerManager(const std::string& managerConfigPath)
 
         LOGT("Creating Container " << containerConfigPath);
         std::unique_ptr<Container> c(new Container(containerConfigPath));
-        std::string id = c->getAdmin().getId();
+        std::string id = c->getId();
         mContainers.emplace(id, std::move(c));
     }
 }
@@ -69,49 +71,59 @@ ContainerManager::~ContainerManager()
 
 void ContainerManager::focus(const std::string& containerId)
 {
+    /* try to access the object first to throw immediately if it doesn't exist */
+    ContainerMap::mapped_type& foregroundContainer = mContainers.at(containerId);
+
     for (auto& container : mContainers) {
-        container.second->getAdmin().suspend();
+        container.second->goBackground();
     }
-    mContainers.at(containerId)->getAdmin().resume();
+    mConfig.foregroundId = foregroundContainer->getId();
+    foregroundContainer->goForeground();
 }
 
 
 void ContainerManager::startAll()
 {
+    bool isForegroundFound = false;
+
     for (auto& container : mContainers) {
-        container.second->getAdmin().start();
+        container.second->start();
+
+        if (container.first == mConfig.foregroundId) {
+            isForegroundFound = true;
+            container.second->goForeground();
+        }
     }
-}
 
+    if (!isForegroundFound) {
+        auto foregroundIterator = std::min_element(mContainers.begin(), mContainers.end(),
+                                                   [](ContainerMap::value_type &c1, ContainerMap::value_type &c2) {
+                                                       return c1.second->getPrivilege() < c2.second->getPrivilege();
+                                                   });
 
-void ContainerManager::stopAll()
-{
-    for (auto& container : mContainers) {
-        container.second->getAdmin().stop();
+        mConfig.foregroundId = foregroundIterator->second->getId();
+        foregroundIterator->second->goForeground();
     }
 }
 
 
-std::string ContainerManager::getRunningContainerId()
+void ContainerManager::stopAll()
 {
     for (auto& container : mContainers) {
-        if (container.second->getAdmin().isRunning()) {
-            return container.first;
-        }
+        container.second->stop();
     }
-    return "";
 }
 
 
-std::vector<std::string> ContainerManager::getSuspendedContainerIds()
+std::string ContainerManager::getRunningForegroundContainerId()
 {
-    std::vector<std::string> retContainerIds;
     for (auto& container : mContainers) {
-        if (container.second->getAdmin().isPaused()) {
-            retContainerIds.push_back(container.first);
+        if (container.first == mConfig.foregroundId &&
+            container.second->isRunning()) {
+            return container.first;
         }
     }
-    return retContainerIds;
+    return "";
 }
 
 
index 3cf24c1..17d1c53 100644 (file)
@@ -43,8 +43,9 @@ Container::Container(const std::string& containerConfigPath)
         libvirtConfigPath = utils::createFilePath(baseConfigPath, "/", mConfig.config);
     }
 
-    LOGT("Creating Container Admin " << libvirtConfigPath);
-    mAdmin.reset(new ContainerAdmin(libvirtConfigPath));
+    mConfig.config = libvirtConfigPath;
+    LOGT("Creating Container Admin " << mConfig.config);
+    mAdmin.reset(new ContainerAdmin(mConfig));
 }
 
 
@@ -52,11 +53,59 @@ Container::~Container()
 {
 }
 
-ContainerAdmin& Container::getAdmin()
+
+std::string Container::getId()
 {
-    assert(mAdmin.get() != NULL);
+    return mAdmin->getId();
+}
+
 
-    return *mAdmin;
+int Container::getPrivilege()
+{
+    return mConfig.privilege;
 }
 
+
+void Container::start()
+{
+    return mAdmin->start();
+}
+
+
+void Container::stop()
+{
+    return mAdmin->stop();
+}
+
+
+void Container::goForeground()
+{
+    mAdmin->setSchedulerLevel(SchedulerLevel::FOREGROUND);
+}
+
+
+void Container::goBackground()
+{
+    mAdmin->setSchedulerLevel(SchedulerLevel::BACKGROUND);
+}
+
+
+bool Container::isRunning()
+{
+    return mAdmin->isRunning();
+}
+
+
+bool Container::isStopped()
+{
+    return mAdmin->isStopped();
+}
+
+
+bool Container::isPaused()
+{
+    return mAdmin->isPaused();
+}
+
+
 } // namespace security_containers
index c786992..1b48518 100644 (file)
@@ -47,16 +47,34 @@ TARGET_LINK_LIBRARIES(${UT_SERVER_CODENAME} ${UT_SERVER_DEPS_LIBRARIES} ${Boost_
 ## Install #####################################################################
 INSTALL(TARGETS ${UT_SERVER_CODENAME} DESTINATION bin)
 
-FILE(GLOB manager_CONF         ${SERVER_FOLDER}/unit_tests/config/ut-scs-container-manager/*.conf)
-FILE(GLOB container_CONF       ${SERVER_FOLDER}/unit_tests/config/ut-scs-container-manager/containers/*.conf)
-FILE(GLOB containeradmin_CONF  ${SERVER_FOLDER}/unit_tests/config/ut-scs-container-manager/libvirt-config/*.xml)
-FILE(GLOB dbus_CONF            ${SERVER_FOLDER}/unit_tests/config/ut-dbus-connection/*.conf)
+FILE(GLOB manager_manager_CONF      ${SERVER_FOLDER}/unit_tests/config/ut-scs-container-manager/*.conf)
+FILE(GLOB manager_container_CONF    ${SERVER_FOLDER}/unit_tests/config/ut-scs-container-manager/containers/*.conf)
+FILE(GLOB manager_admin_CONF        ${SERVER_FOLDER}/unit_tests/config/ut-scs-container-manager/libvirt-config/*.xml)
 
-INSTALL(FILES        ${manager_CONF}
+FILE(GLOB container_container_CONF  ${SERVER_FOLDER}/unit_tests/config/ut-scs-container/containers/*.conf)
+FILE(GLOB container_admin_CONF      ${SERVER_FOLDER}/unit_tests/config/ut-scs-container/libvirt-config/*.xml)
+
+FILE(GLOB admin_container_CONF      ${SERVER_FOLDER}/unit_tests/config/ut-scs-container-admin/containers/*.conf)
+FILE(GLOB admin_admin_CONF          ${SERVER_FOLDER}/unit_tests/config/ut-scs-container-admin/libvirt-config/*.xml)
+
+FILE(GLOB dbus_CONF                 ${SERVER_FOLDER}/unit_tests/config/ut-dbus-connection/*.conf)
+
+INSTALL(FILES        ${manager_manager_CONF}
         DESTINATION  ${SC_CONFIG_INSTALL_DIR}/tests/ut-scs-container-manager)
-INSTALL(FILES        ${container_CONF}
+INSTALL(FILES        ${manager_container_CONF}
         DESTINATION  ${SC_CONFIG_INSTALL_DIR}/tests/ut-scs-container-manager/containers)
-INSTALL(FILES        ${containeradmin_CONF}
+INSTALL(FILES        ${manager_admin_CONF}
         DESTINATION  ${SC_CONFIG_INSTALL_DIR}/tests/ut-scs-container-manager/libvirt-config)
+
+INSTALL(FILES        ${container_container_CONF}
+        DESTINATION  ${SC_CONFIG_INSTALL_DIR}/tests/ut-scs-container/containers)
+INSTALL(FILES        ${container_admin_CONF}
+        DESTINATION  ${SC_CONFIG_INSTALL_DIR}/tests/ut-scs-container/libvirt-config)
+
+INSTALL(FILES        ${admin_container_CONF}
+        DESTINATION  ${SC_CONFIG_INSTALL_DIR}/tests/ut-scs-container-admin/containers)
+INSTALL(FILES        ${admin_admin_CONF}
+        DESTINATION  ${SC_CONFIG_INSTALL_DIR}/tests/ut-scs-container-admin/libvirt-config)
+
 INSTALL(FILES        ${dbus_CONF}
         DESTINATION  ${SC_CONFIG_INSTALL_DIR}/tests/ut-dbus-connection)
diff --git a/src/server/unit_tests/config/ut-scs-container-admin/containers/buggy.conf b/src/server/unit_tests/config/ut-scs-container-admin/containers/buggy.conf
new file mode 100644 (file)
index 0000000..aba5971
--- /dev/null
@@ -0,0 +1,6 @@
+{
+    "privilege" : 10,
+    "config" : "/etc/security-containers/tests/ut-scs-container-admin/libvirt-config/buggy.xml",
+    "cpuQuotaForeground" : -1,
+    "cpuQuotaBackground" : 1000
+}
diff --git a/src/server/unit_tests/config/ut-scs-container-admin/containers/missing.conf b/src/server/unit_tests/config/ut-scs-container-admin/containers/missing.conf
new file mode 100644 (file)
index 0000000..0e31a4b
--- /dev/null
@@ -0,0 +1,6 @@
+{
+    "privilege" : 10,
+    "config" : "/this/is/a/missing/file/path/missing.xml",
+    "cpuQuotaForeground" : -1,
+    "cpuQuotaBackground" : 1000
+}
diff --git a/src/server/unit_tests/config/ut-scs-container-admin/containers/test.conf b/src/server/unit_tests/config/ut-scs-container-admin/containers/test.conf
new file mode 100644 (file)
index 0000000..c87fde0
--- /dev/null
@@ -0,0 +1,6 @@
+{
+    "privilege" : 10,
+    "config" : "/etc/security-containers/tests/ut-scs-container-admin/libvirt-config/test.xml",
+    "cpuQuotaForeground" : -1,
+    "cpuQuotaBackground" : 1000
+}
index 7b2695b..9b737a1 100644 (file)
@@ -1,3 +1,4 @@
 {
-    "containerConfigs" : ["containers/console.conf", "missing/file/path/missing.conf"]
+    "containerConfigs" : ["containers/console1.conf", "missing/file/path/missing.conf", "containers/console3.conf"],
+    "foregroundId" : "console1"
 }
diff --git a/src/server/unit_tests/config/ut-scs-container-manager/buggy-foreground-daemon.conf b/src/server/unit_tests/config/ut-scs-container-manager/buggy-foreground-daemon.conf
new file mode 100644 (file)
index 0000000..780e97e
--- /dev/null
@@ -0,0 +1,4 @@
+{
+    "containerConfigs" : ["containers/console1.conf", "containers/console2.conf", "containers/console3.conf"],
+    "foregroundId" : "this_id_does_not_exist"
+}
diff --git a/src/server/unit_tests/config/ut-scs-container-manager/containers/buggy.conf b/src/server/unit_tests/config/ut-scs-container-manager/containers/buggy.conf
deleted file mode 100644 (file)
index 3dd9594..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-{
-    "privilege" : 10,
-    "config" : "/missing/file/path/libvirt.xml"
-}
diff --git a/src/server/unit_tests/config/ut-scs-container-manager/containers/console.conf b/src/server/unit_tests/config/ut-scs-container-manager/containers/console.conf
deleted file mode 100644 (file)
index 733adc6..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-{
-    "privilege" : 10,
-    "config" : "../libvirt-config/console.xml"
-}
index 7ede773..9c57182 100644 (file)
@@ -1,4 +1,6 @@
 {
     "privilege" : 20,
-    "config" : "../libvirt-config/console1.xml"
+    "config" : "../libvirt-config/console1.xml",
+    "cpuQuotaForeground" : -1,
+    "cpuQuotaBackground" : 1000
 }
diff --git a/src/server/unit_tests/config/ut-scs-container-manager/containers/console2.conf b/src/server/unit_tests/config/ut-scs-container-manager/containers/console2.conf
new file mode 100644 (file)
index 0000000..6d664de
--- /dev/null
@@ -0,0 +1,6 @@
+{
+    "privilege" : 10,
+    "config" : "../libvirt-config/console2.xml",
+    "cpuQuotaForeground" : -1,
+    "cpuQuotaBackground" : 1000
+}
diff --git a/src/server/unit_tests/config/ut-scs-container-manager/containers/console3.conf b/src/server/unit_tests/config/ut-scs-container-manager/containers/console3.conf
new file mode 100644 (file)
index 0000000..a60470b
--- /dev/null
@@ -0,0 +1,6 @@
+{
+    "privilege" : 15,
+    "config" : "../libvirt-config/console3.xml",
+    "cpuQuotaForeground" : -1,
+    "cpuQuotaBackground" : 1000
+}
diff --git a/src/server/unit_tests/config/ut-scs-container-manager/containers/test.conf b/src/server/unit_tests/config/ut-scs-container-manager/containers/test.conf
deleted file mode 100644 (file)
index 2c90e3f..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-{
-    "privilege" : 10,
-    "config" : "../libvirt-config/test.xml"
-}
diff --git a/src/server/unit_tests/config/ut-scs-container-manager/libvirt-config/console3.xml b/src/server/unit_tests/config/ut-scs-container-manager/libvirt-config/console3.xml
new file mode 100644 (file)
index 0000000..36ee997
--- /dev/null
@@ -0,0 +1,11 @@
+<domain type="lxc">
+    <name>console3</name>
+    <memory>102400</memory>
+    <os>
+        <type>exe</type>
+        <init>/bin/sh</init>
+    </os>
+    <devices>
+        <console type="pty"/>
+    </devices>
+</domain>
index 7bb6d40..4608ad4 100644 (file)
@@ -1,3 +1,4 @@
 {
-    "containerConfigs" : ["containers/console.conf", "containers/console1.conf"]
+    "containerConfigs" : ["containers/console1.conf", "containers/console2.conf", "containers/console3.conf"],
+    "foregroundId" : "console1"
 }
diff --git a/src/server/unit_tests/config/ut-scs-container/containers/buggy.conf b/src/server/unit_tests/config/ut-scs-container/containers/buggy.conf
new file mode 100644 (file)
index 0000000..6ab887b
--- /dev/null
@@ -0,0 +1,6 @@
+{
+    "privilege" : 10,
+    "config" : "/missing/file/path/libvirt.xml",
+    "cpuQuotaForeground" : -1,
+    "cpuQuotaBackground" : 1000
+}
diff --git a/src/server/unit_tests/config/ut-scs-container/containers/test.conf b/src/server/unit_tests/config/ut-scs-container/containers/test.conf
new file mode 100644 (file)
index 0000000..6da72ca
--- /dev/null
@@ -0,0 +1,6 @@
+{
+    "privilege" : 10,
+    "config" : "../libvirt-config/test.xml",
+    "cpuQuotaForeground" : -1,
+    "cpuQuotaBackground" : 1000
+}
diff --git a/src/server/unit_tests/config/ut-scs-container/libvirt-config/test.xml b/src/server/unit_tests/config/ut-scs-container/libvirt-config/test.xml
new file mode 100644 (file)
index 0000000..91633b0
--- /dev/null
@@ -0,0 +1,12 @@
+<domain type="lxc">
+    <name>test</name>
+    <memory>102400</memory>
+    <on_poweroff>destroy</on_poweroff>
+    <os>
+        <type>exe</type>
+        <init>/bin/sh</init>
+    </os>
+    <devices>
+        <console type="pty"/>
+    </devices>
+</domain>
index 65820b0..628ed0b 100644 (file)
@@ -49,7 +49,7 @@ namespace {
 const char* DBUS_DAEMON_PROC = "/bin/dbus-daemon";
 const char* const DBUS_DAEMON_ARGS[] = {
     DBUS_DAEMON_PROC,
-    "--config-file=/etc/security-containers/config/tests/ut-dbus-connection/ut-dbus.conf",
+    "--config-file=/etc/security-containers/tests/ut-dbus-connection/ut-dbus.conf",
     "--nofork",
     NULL
 };
index bad0d5a..e638be5 100644 (file)
 
 #include <memory>
 #include <string>
+#include <thread>
+#include <chrono>
 
 
 BOOST_AUTO_TEST_SUITE(ContainerAdminSuite)
 
 using namespace security_containers;
 
-const std::string TEST_CONFIG_PATH = "/etc/security-containers/config/tests/ut-scs-container-manager/libvirt-config/test.xml";
-const std::string BUGGY_CONFIG_PATH = "/etc/security-containers/config/tests/ut-scs-container-manager/libvirt-config/buggy.xml";
-const std::string MISSING_CONFIG_PATH = "/this/is/a/missing/file/path/missing.xml";
+const std::string TEST_CONFIG_PATH = "/etc/security-containers/tests/ut-scs-container-admin/containers/test.conf";
+const std::string BUGGY_CONFIG_PATH = "/etc/security-containers/tests/ut-scs-container-admin/containers/buggy.conf";
+const std::string MISSING_CONFIG_PATH = "/etc/security-containers/tests/ut-scs-container-admin/containers/missing.conf";
 
 
 BOOST_AUTO_TEST_CASE(ConstructorTest)
 {
-    BOOST_REQUIRE_NO_THROW(ContainerAdmin ca(TEST_CONFIG_PATH));
+    ContainerConfig config; config.parseFile(TEST_CONFIG_PATH);
+    BOOST_REQUIRE_NO_THROW(ContainerAdmin ca(config));
 }
 
 BOOST_AUTO_TEST_CASE(DestructorTest)
 {
-    std::unique_ptr<ContainerAdmin> ca(new ContainerAdmin(TEST_CONFIG_PATH));
+    ContainerConfig config; config.parseFile(TEST_CONFIG_PATH);
+    std::unique_ptr<ContainerAdmin> ca(new ContainerAdmin(config));
     BOOST_REQUIRE_NO_THROW(ca.reset());
 }
 
 BOOST_AUTO_TEST_CASE(BuggyConfigTest)
 {
-    BOOST_REQUIRE_THROW(ContainerAdmin ca(BUGGY_CONFIG_PATH), ServerException);
+    ContainerConfig config; config.parseFile(BUGGY_CONFIG_PATH);
+    BOOST_REQUIRE_THROW(ContainerAdmin ca(config), ServerException);
 }
 
 BOOST_AUTO_TEST_CASE(MissingConfigTest)
 {
-    BOOST_REQUIRE_THROW(ContainerAdmin ca(MISSING_CONFIG_PATH), ConfigException);
+    ContainerConfig config; config.parseFile(MISSING_CONFIG_PATH);
+    BOOST_REQUIRE_THROW(ContainerAdmin ca(config), ConfigException);
 }
 
 BOOST_AUTO_TEST_CASE(StartTest)
 {
-    ContainerAdmin ca(TEST_CONFIG_PATH);
+    ContainerConfig config; config.parseFile(TEST_CONFIG_PATH);
+    ContainerAdmin ca(config);
     BOOST_REQUIRE_NO_THROW(ca.start());
     BOOST_CHECK(ca.isRunning());
 }
 
 BOOST_AUTO_TEST_CASE(StopTest)
 {
-    ContainerAdmin ca(TEST_CONFIG_PATH);
+    ContainerConfig config; config.parseFile(TEST_CONFIG_PATH);
+    ContainerAdmin ca(config);
     BOOST_REQUIRE_NO_THROW(ca.start());
     BOOST_CHECK(ca.isRunning());
     BOOST_REQUIRE_NO_THROW(ca.stop())
@@ -80,7 +88,8 @@ BOOST_AUTO_TEST_CASE(StopTest)
 
 BOOST_AUTO_TEST_CASE(ShutdownTest)
 {
-    ContainerAdmin ca(TEST_CONFIG_PATH);
+    ContainerConfig config; config.parseFile(TEST_CONFIG_PATH);
+    ContainerAdmin ca(config);
     BOOST_REQUIRE_NO_THROW(ca.start())
     BOOST_CHECK(ca.isRunning());
     BOOST_REQUIRE_NO_THROW(ca.shutdown())
@@ -91,18 +100,24 @@ BOOST_AUTO_TEST_CASE(ShutdownTest)
 
 BOOST_AUTO_TEST_CASE(SuspendTest)
 {
-    ContainerAdmin ca(TEST_CONFIG_PATH);
+    ContainerConfig config; config.parseFile(TEST_CONFIG_PATH);
+    ContainerAdmin ca(config);
     BOOST_REQUIRE_NO_THROW(ca.start())
     BOOST_CHECK(ca.isRunning());
-    BOOST_REQUIRE_NO_THROW(ca.suspend())
+    // TODO: fix the libvirt usage so this is not required
+    std::this_thread::sleep_for(std::chrono::seconds(1));
+    BOOST_REQUIRE_NO_THROW(ca.suspend());
     BOOST_CHECK(!ca.isRunning());
     BOOST_CHECK(ca.isPaused());
 }
 
 BOOST_AUTO_TEST_CASE(ResumeTest)
 {
-    ContainerAdmin ca(TEST_CONFIG_PATH);
+    ContainerConfig config; config.parseFile(TEST_CONFIG_PATH);
+    ContainerAdmin ca(config);
     BOOST_REQUIRE_NO_THROW(ca.start());
+    // TODO: fix the libvirt usage so this is not required
+    std::this_thread::sleep_for(std::chrono::seconds(1));
     BOOST_REQUIRE_NO_THROW(ca.suspend())
     BOOST_CHECK(ca.isPaused());
     BOOST_REQUIRE_NO_THROW(ca.resume());
@@ -110,4 +125,16 @@ BOOST_AUTO_TEST_CASE(ResumeTest)
     BOOST_CHECK(ca.isRunning());
 }
 
+BOOST_AUTO_TEST_CASE(SchedulerLevelTest)
+{
+    ContainerConfig config; config.parseFile(TEST_CONFIG_PATH);
+    ContainerAdmin ca(config);
+    BOOST_REQUIRE_NO_THROW(ca.start());
+    BOOST_REQUIRE(ca.getSchedulerQuota() == config.cpuQuotaBackground);
+    BOOST_REQUIRE_NO_THROW(ca.setSchedulerLevel(SchedulerLevel::FOREGROUND));
+    BOOST_REQUIRE(ca.getSchedulerQuota() == config.cpuQuotaForeground);
+    BOOST_REQUIRE_NO_THROW(ca.setSchedulerLevel(SchedulerLevel::BACKGROUND));
+    BOOST_REQUIRE(ca.getSchedulerQuota() == config.cpuQuotaBackground);
+}
+
 BOOST_AUTO_TEST_SUITE_END()
index 55fd94a..35b7707 100644 (file)
@@ -35,8 +35,9 @@ BOOST_AUTO_TEST_SUITE(ContainerManagerSuite)
 
 using namespace security_containers;
 
-const std::string TEST_CONFIG_PATH = "/etc/security-containers/config/tests/ut-scs-container-manager/test-daemon.conf";
-const std::string BUGGY_CONFIG_PATH = "/etc/security-containers/config/tests/ut-scs-container-manager/buggy-daemon.conf";
+const std::string TEST_CONFIG_PATH = "/etc/security-containers/tests/ut-scs-container-manager/test-daemon.conf";
+const std::string BUGGY_CONFIG_PATH = "/etc/security-containers/tests/ut-scs-container-manager/buggy-daemon.conf";
+const std::string BUGGY_FOREGROUND_CONFIG_PATH = "/etc/security-containers/tests/ut-scs-container-manager/buggy-foreground-daemon.conf";
 const std::string MISSING_CONFIG_PATH = "/this/is/a/missing/file/path/missing-daemon.conf";
 
 
@@ -65,7 +66,14 @@ BOOST_AUTO_TEST_CASE(StartAllTest)
 {
     ContainerManager cm(TEST_CONFIG_PATH);
     BOOST_REQUIRE_NO_THROW(cm.startAll());
-    BOOST_CHECK(!cm.getRunningContainerId().empty());
+    BOOST_CHECK(cm.getRunningForegroundContainerId() == "console1");
+}
+
+BOOST_AUTO_TEST_CASE(BuggyForegroundTest)
+{
+    ContainerManager cm(BUGGY_FOREGROUND_CONFIG_PATH);
+    BOOST_REQUIRE_NO_THROW(cm.startAll());
+    BOOST_CHECK(cm.getRunningForegroundContainerId() == "console2");
 }
 
 BOOST_AUTO_TEST_CASE(StopAllTest)
@@ -73,20 +81,19 @@ BOOST_AUTO_TEST_CASE(StopAllTest)
     ContainerManager cm(TEST_CONFIG_PATH);
     BOOST_REQUIRE_NO_THROW(cm.startAll());
     BOOST_REQUIRE_NO_THROW(cm.stopAll());
-    BOOST_CHECK(cm.getRunningContainerId().empty());
-
+    BOOST_CHECK(cm.getRunningForegroundContainerId().empty());
 }
 
 BOOST_AUTO_TEST_CASE(FocusTest)
 {
     ContainerManager cm(TEST_CONFIG_PATH);
     BOOST_REQUIRE_NO_THROW(cm.startAll());
-    BOOST_REQUIRE_NO_THROW(cm.focus("console"));
-    BOOST_CHECK(!cm.getSuspendedContainerIds().empty());
-    BOOST_TEST_MESSAGE("Suspended");
-    for (auto& id : cm.getSuspendedContainerIds()) {
-        BOOST_TEST_MESSAGE(id);
-    }
+    BOOST_REQUIRE_NO_THROW(cm.focus("console2"));
+    BOOST_CHECK(cm.getRunningForegroundContainerId() == "console2");
+    BOOST_REQUIRE_NO_THROW(cm.focus("console1"));
+    BOOST_CHECK(cm.getRunningForegroundContainerId() == "console1");
+    BOOST_REQUIRE_NO_THROW(cm.focus("console3"));
+    BOOST_CHECK(cm.getRunningForegroundContainerId() == "console3");
 }
 
 BOOST_AUTO_TEST_SUITE_END()
index 6486cec..8d49caa 100644 (file)
@@ -35,8 +35,8 @@ BOOST_AUTO_TEST_SUITE(ContainerSuite)
 
 using namespace security_containers;
 
-const std::string TEST_CONFIG_PATH = "/etc/security-containers/config/tests/ut-scs-container-manager/containers/test.conf";
-const std::string BUGGY_CONFIG_PATH = "/etc/security-containers/config/tests/ut-scs-container-manager/containers/buggy.conf";
+const std::string TEST_CONFIG_PATH = "/etc/security-containers/tests/ut-scs-container/containers/test.conf";
+const std::string BUGGY_CONFIG_PATH = "/etc/security-containers/tests/ut-scs-container/containers/buggy.conf";
 const std::string MISSING_CONFIG_PATH = "/this/is/a/missing/file/path/config.conf";
 
 
@@ -61,10 +61,5 @@ BOOST_AUTO_TEST_CASE(MissingConfigTest)
     BOOST_REQUIRE_THROW(Container c(MISSING_CONFIG_PATH), ConfigException);
 }
 
-BOOST_AUTO_TEST_CASE(AdminTest)
-{
-    std::unique_ptr<Container> c(new Container(TEST_CONFIG_PATH));
-    //BOOST_REQUIRE(c->getAdmin());
-}
 
 BOOST_AUTO_TEST_SUITE_END()