From 206d66b951ce02f6ce30c1eed355c8699cd20de8 Mon Sep 17 00:00:00 2001 From: Piotr Bartosiewicz Date: Tue, 19 Aug 2014 14:34:01 +0200 Subject: [PATCH 01/16] [Unit tests] Handle segmentation faults [Bug/Feature] No message was printed when unit tests was terminated by some signal. [Cause] N/A [Solution] N/A [Verification] Build, install, run good and crashing tests. Change-Id: Ib8a8abae09e3dfa2d2badd8c78f87440eb834c4c --- tests/scripts/sc_launch_test.py | 10 ++++++++-- tests/scripts/sc_test_parser.py | 8 ++++++++ 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/tests/scripts/sc_launch_test.py b/tests/scripts/sc_launch_test.py index 81d6d62..6bdbcfe 100755 --- a/tests/scripts/sc_launch_test.py +++ b/tests/scripts/sc_launch_test.py @@ -42,7 +42,9 @@ def launchTest(cmd=[], externalToolCmd=[], parsing=True): if parsing: parser = Parser() - p = subprocess.Popen(" ".join(externalToolCmd + cmd + _defLaunchArgs), + command = " ".join(externalToolCmd + cmd + _defLaunchArgs) + log.info("Invoking `" + command + "`") + p = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) @@ -51,10 +53,14 @@ def launchTest(cmd=[], externalToolCmd=[], parsing=True): domResult = minidom.parseString(testResult) log.XMLSummary(domResult) log.failedTestSummary(cmd[0]) + if p.returncode < 0: + log.terminatedBySignal(" ".join(cmd), -p.returncode) else: # Launching process without coloring does not require report in XML form # Avoid providing --report_format=XML, redirect std* by default to system's std* - p = subprocess.Popen(" ".join(externalToolCmd + cmd + _defLaunchArgs[1:]), + command = " ".join(externalToolCmd + cmd + _defLaunchArgs[1:]) + log.info("Invoking `" + command + "`") + p = subprocess.Popen(command, shell=True) p.wait() diff --git a/tests/scripts/sc_test_parser.py b/tests/scripts/sc_test_parser.py index 8d4b289..5299814 100644 --- a/tests/scripts/sc_test_parser.py +++ b/tests/scripts/sc_test_parser.py @@ -82,6 +82,14 @@ class Logger(object): for test in self.__failedTests: self.error(self.__indentChar + commandPrefix + test) + def terminatedBySignal(self, bin, signum): + self.error("\n=========== FAILED ===========\n") + signame = {2:"SIGINT", 9:"SIGKILL", 11:"SIGSEGV", 15:"SIGTERM"} + siginfo = signame.get(signum, 'signal ' + str(signum)) + self.error('Terminated by ' + siginfo) + if signum == 11: # SIGSEGV + self.error("\nUse following command to launch debugger:") + self.error(self.__indentChar + "sc_launch_test.py --gdb " + bin) class Parser(object): -- 2.7.4 From 51a73747a270ef176596365e5e5958aaeed87645 Mon Sep 17 00:00:00 2001 From: Mateusz Malicki Date: Thu, 14 Aug 2014 18:03:51 +0200 Subject: [PATCH 02/16] Client library functions [Feature] Add more functions to the client library. [Cause] N/A [Solution] N/A [Verification] Build, install, run test suite Client Change-Id: Ided49f0363c5bb94669c272fda745510cd21d985 --- client/security-containers-client-impl.cpp | 165 +++++++++++++++++++++ client/security-containers-client-impl.hpp | 33 +++++ client/security-containers-client.cpp | 33 +++++ client/security-containers-client.h | 77 ++++++++++ .../ut-client/containers/console1-dbus.conf | 1 + .../ut-client/containers/console2-dbus.conf | 1 + .../ut-client/containers/console3-dbus.conf | 1 + .../ut-client/libvirt-config/network1-filter.xml | 3 + .../ut-client/libvirt-config/network2-filter.xml | 3 + .../ut-client/libvirt-config/network3-filter.xml | 3 + tests/unit_tests/client/ut-client.cpp | 120 +++++++++++++++ 11 files changed, 440 insertions(+) create mode 100644 tests/unit_tests/client/configs/ut-client/libvirt-config/network1-filter.xml create mode 100644 tests/unit_tests/client/configs/ut-client/libvirt-config/network2-filter.xml create mode 100644 tests/unit_tests/client/configs/ut-client/libvirt-config/network3-filter.xml diff --git a/client/security-containers-client-impl.cpp b/client/security-containers-client-impl.cpp index 87c30f8..17315b0 100644 --- a/client/security-containers-client-impl.cpp +++ b/client/security-containers-client-impl.cpp @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -47,6 +48,11 @@ const string SCCLIENT_EXCEPTION_MSG = "unspecified exception"; const DbusInterfaceInfo hostDbusInterfaceInfo(api::host::BUS_NAME, api::host::OBJECT_PATH, api::host::INTERFACE); +const DbusInterfaceInfo domainDbusInterfaceInfo(api::container::BUS_NAME, + api::container::OBJECT_PATH, + api::container::INTERFACE); + +template struct fake_dependency: public std::false_type {}; unique_ptr loop; @@ -75,6 +81,45 @@ void toDict(GVariant* in, ScArrayString* keys, ScArrayString* values) *values = outv; } +template +void toBasic(GVariant* in, T str) +{ + static_assert(fake_dependency::value, "Must use specialization"); + assert(!"Must use specialization"); +} + +template<> +void toBasic(GVariant* in, char** str) +{ + assert(in); + assert(str); + + gsize length; + const gchar* src = g_variant_get_string(in, &length); + char* buf = strndup(src, length); + *str = buf; +} + +template +void toArray(GVariant* in, T** scArray) +{ + assert(in); + assert(scArray); + + gsize size = g_variant_n_children(in); + T* ids = (T*)calloc(size + 1, sizeof(T)); + + GVariantIter iter; + GVariant* child; + + g_variant_iter_init(&iter, in); + for (int i = 0; (child = g_variant_iter_next_value(&iter)); i++) { + toBasic(child, &ids[i]); + g_variant_unref(child); + } + *scArray = ids; +} + ScStatus toStatus(const std::exception& ex) { if (typeid(DbusCustomException) == typeid(ex)) { @@ -203,6 +248,33 @@ ScStatus Client::callMethod(const DbusInterfaceInfo& info, return sc_get_status(); } +ScStatus Client::signalSubscribe(const DbusInterfaceInfo& info, + const string& name, + SignalCallback signalCallback) +{ + auto onSignal = [=](const std::string& /*senderBusName*/, + const std::string & objectPath, + const std::string & interface, + const std::string & signalName, + GVariant * parameters) { + if (objectPath == info.objectPath && + interface == info.interface && + signalName == name) { + + signalCallback(parameters); + } + }; + try { + mConnection->signalSubscribe(onSignal, info.busName); + mStatus = Status(SCCLIENT_SUCCESS); + } catch (const std::exception& ex) { + mStatus = Status(toStatus(ex), ex.what()); + } catch (...) { + mStatus = Status(SCCLIENT_EXCEPTION); + } + return sc_get_status(); +} + const char* Client::sc_get_status_message() noexcept { return mStatus.mMsg.c_str(); @@ -234,3 +306,96 @@ ScStatus Client::sc_get_container_dbuses(ScArrayString* keys, ScArrayString* val g_variant_unref(out); return ret; } + +ScStatus Client::sc_get_container_ids(ScArrayString* array) noexcept +{ + assert(array); + + GVariant* out; + ScStatus ret = callMethod(hostDbusInterfaceInfo, + api::host::METHOD_GET_CONTAINER_ID_LIST, + NULL, + "(as)", + &out); + if (ret != SCCLIENT_SUCCESS) { + return ret; + } + GVariant* unpacked; + g_variant_get(out, "(*)", &unpacked); + toArray(unpacked, array); + g_variant_unref(unpacked); + g_variant_unref(out); + return ret; +} + +ScStatus Client::sc_get_active_container_id(ScString* id) noexcept +{ + assert(id); + + GVariant* out; + ScStatus ret = callMethod(hostDbusInterfaceInfo, + api::host::METHOD_GET_ACTIVE_CONTAINER_ID, + NULL, + "(s)", + &out); + if (ret != SCCLIENT_SUCCESS) { + return ret; + } + GVariant* unpacked; + g_variant_get(out, "(*)", &unpacked); + toBasic(unpacked, id); + g_variant_unref(unpacked); + g_variant_unref(out); + return ret; +} + +ScStatus Client::sc_set_active_container(const char* id) noexcept +{ + assert(id); + + GVariant* args_in = g_variant_new("(s)", id); + return callMethod(hostDbusInterfaceInfo, api::host::METHOD_SET_ACTIVE_CONTAINER, args_in); +} + +ScStatus Client::sc_container_dbus_state(ScContainerDbusStateCallback containerDbusStateCallback) + noexcept +{ + assert(containerDbusStateCallback); + + auto onSigal = [ = ](GVariant * parameters) { + const char* container; + const char* dbusAddress; + g_variant_get(parameters, "(&s&s)", &container, &dbusAddress); + containerDbusStateCallback(container, dbusAddress); + }; + + return signalSubscribe(hostDbusInterfaceInfo, + api::host::SIGNAL_CONTAINER_DBUS_STATE, + onSigal); +} + +ScStatus Client::sc_notify_active_container(const char* application, const char* message) noexcept +{ + assert(application); + assert(message); + + GVariant* args_in = g_variant_new("(ss)", application, message); + return callMethod(domainDbusInterfaceInfo, + api::container::METHOD_NOTIFY_ACTIVE_CONTAINER, + args_in); +} + +ScStatus Client::sc_notification(ScNotificationCallback notificationCallback) noexcept +{ + assert(notificationCallback); + + auto onSigal = [ = ](GVariant * parameters) { + const char* container; + const char* application; + const char* message; + g_variant_get(parameters, "(&s&s&s)", &container, &application, &message); + notificationCallback(container, application, message); + }; + + return signalSubscribe(domainDbusInterfaceInfo, api::container::SIGNAL_NOTIFICATION, onSigal); +} diff --git a/client/security-containers-client-impl.hpp b/client/security-containers-client-impl.hpp index f823cd1..aafcae0 100644 --- a/client/security-containers-client-impl.hpp +++ b/client/security-containers-client-impl.hpp @@ -52,6 +52,7 @@ struct DbusInterfaceInfo { */ class Client { private: + typedef std::function SignalCallback; struct Status { Status(ScStatus status); Status(ScStatus status, const std::string& msg); @@ -67,6 +68,9 @@ private: GVariant* args_in, const std::string& args_spec_out = std::string(), GVariant** args_out = NULL); + ScStatus signalSubscribe(const DbusInterfaceInfo& info, + const std::string& name, + SignalCallback signalCallback); public: Client() noexcept; @@ -103,6 +107,35 @@ public: ScStatus sc_get_container_dbuses(ScArrayString* keys, ScArrayString* values) noexcept; /** + * @see ::sc_get_container_ids + */ + ScStatus sc_get_container_ids(ScArrayString* array) noexcept; + + /** + * @see ::sc_get_active_container_id + */ + ScStatus sc_get_active_container_id(ScString* id) noexcept; + + /** + * @see ::sc_set_active_container + */ + ScStatus sc_set_active_container(const char* id) noexcept; + + /** + * @see ::sc_container_dbus_state + */ + ScStatus sc_container_dbus_state(ScContainerDbusStateCallback containerDbusStateCallback) noexcept; + + /** + * @see ::sc_notify_active_container + */ + ScStatus sc_notify_active_container(const char* application, const char* message) noexcept; + + /** + * @see ::sc_notification + */ + ScStatus sc_notification(ScNotificationCallback notificationCallback) noexcept; + /** * @see ::sc_start */ static ScStatus sc_start() noexcept; diff --git a/client/security-containers-client.cpp b/client/security-containers-client.cpp index 572f166..12a3d6d 100644 --- a/client/security-containers-client.cpp +++ b/client/security-containers-client.cpp @@ -135,3 +135,36 @@ API ScStatus sc_get_container_dbuses(ScClient client, ScArrayString* keys, ScArr { return getClient(client)->sc_get_container_dbuses(keys, values); } + +API ScStatus sc_get_container_ids(ScClient client, ScArrayString* array) +{ + return getClient(client)->sc_get_container_ids(array); +} + +API ScStatus sc_get_active_container_id(ScClient client, ScString* id) +{ + return getClient(client)->sc_get_active_container_id(id); +} + +API ScStatus sc_set_active_container(ScClient client, const char* id) +{ + return getClient(client)->sc_set_active_container(id); +} + +API ScStatus sc_container_dbus_state(ScClient client, + ScContainerDbusStateCallback containerDbusStateCallback) +{ + return getClient(client)->sc_container_dbus_state(containerDbusStateCallback); +} + +API ScStatus sc_notify_active_container(ScClient client, + const char* application, + const char* message) +{ + return getClient(client)->sc_notify_active_container(application, message); +} + +API ScStatus sc_notification(ScClient client, ScNotificationCallback notificationCallback) +{ + return getClient(client)->sc_notification(notificationCallback); +} diff --git a/client/security-containers-client.h b/client/security-containers-client.h index 692df31..01ca12c 100644 --- a/client/security-containers-client.h +++ b/client/security-containers-client.h @@ -149,6 +149,11 @@ void sc_string_free(ScString string); ************************************************************************************************/ /** + * Dbus state change callback function signature. + */ +typedef void (*ScContainerDbusStateCallback)(const char* containerId, const char* dbusAddress); + +/** * Get dbus address of each container. * * @param[in] client security-containers-server's client. @@ -159,6 +164,78 @@ void sc_string_free(ScString string); */ ScStatus sc_get_container_dbuses(ScClient client, ScArrayString* keys, ScArrayString* values); +/** + * Get containers name. + * + * @param[in] client security-containers-server's client. + * @param[out] array Array of containers name. + * @return Status of this function call. + */ +ScStatus sc_get_container_ids(ScClient client, ScArrayString* array); + +/** + * Get active container name. + * + * @param[in] client security-containers-server's client. + * @param[out] id Active container name. + * @return Status of this function call. + */ +ScStatus sc_get_active_container_id(ScClient client, ScString* id); + +/** + * Set active container. + * + * @param client security-containers-server's client. + * @param id Container name. + * @return Status of this function call. + */ +ScStatus sc_set_active_container(ScClient client, const char* id); + +/** + * Register dbus state change callback function. + * + * The callback function will be invoked on a different thread + * + * @param client security-containers-server's client. + * @param containerDbusStateCallback Callback function. + * @return Status of this function call. + */ +ScStatus sc_container_dbus_state(ScClient client, + ScContainerDbusStateCallback containerDbusStateCallback); + + +/************************************************************************************************* + * + * org.tizen.containers.domain.manager interface + * + ************************************************************************************************/ + +/** + * Notification callback function signature. + */ +typedef void (*ScNotificationCallback)(const char* container, + const char* application, + const char* message); +/** + * Send message to active container. + * + * @param client security-containers-server's client. + * @param application Application name. + * @param message Message. + * @return Status of this function call. + */ +ScStatus sc_notify_active_container(ScClient client, const char* application, const char* message); + +/** + * Register notification callback function. + * + * The callback function will be invoked on a different thread. + * + * @param client security-containers-server's client. + * @param notificationCallback Callback function. + * @return Status of this function call. + */ +ScStatus sc_notification(ScClient client, ScNotificationCallback notificationCallback); #ifdef __cplusplus } #endif diff --git a/tests/unit_tests/client/configs/ut-client/containers/console1-dbus.conf b/tests/unit_tests/client/configs/ut-client/containers/console1-dbus.conf index ef49f19..af3380b 100644 --- a/tests/unit_tests/client/configs/ut-client/containers/console1-dbus.conf +++ b/tests/unit_tests/client/configs/ut-client/containers/console1-dbus.conf @@ -3,6 +3,7 @@ "switchToDefaultAfterTimeout" : true, "config" : "../libvirt-config/console1-dbus.xml", "networkConfig" : "../libvirt-config/network1.xml", + "networkFilterConfig" : "../libvirt-config/network1-filter.xml", "cpuQuotaForeground" : -1, "cpuQuotaBackground" : 1000, "runMountPoint" : "/tmp/ut-containers-manager/console1-dbus", diff --git a/tests/unit_tests/client/configs/ut-client/containers/console2-dbus.conf b/tests/unit_tests/client/configs/ut-client/containers/console2-dbus.conf index 76c5e49..0db0a8a 100644 --- a/tests/unit_tests/client/configs/ut-client/containers/console2-dbus.conf +++ b/tests/unit_tests/client/configs/ut-client/containers/console2-dbus.conf @@ -3,6 +3,7 @@ "switchToDefaultAfterTimeout" : false, "config" : "../libvirt-config/console2-dbus.xml", "networkConfig" : "../libvirt-config/network2.xml", + "networkFilterConfig" : "../libvirt-config/network2-filter.xml", "cpuQuotaForeground" : -1, "cpuQuotaBackground" : 1000, "runMountPoint" : "/tmp/ut-containers-manager/console2-dbus", diff --git a/tests/unit_tests/client/configs/ut-client/containers/console3-dbus.conf b/tests/unit_tests/client/configs/ut-client/containers/console3-dbus.conf index 592cbfa..14a8a60 100644 --- a/tests/unit_tests/client/configs/ut-client/containers/console3-dbus.conf +++ b/tests/unit_tests/client/configs/ut-client/containers/console3-dbus.conf @@ -3,6 +3,7 @@ "switchToDefaultAfterTimeout" : true, "config" : "../libvirt-config/console3-dbus.xml", "networkConfig" : "../libvirt-config/network3.xml", + "networkFilterConfig" : "../libvirt-config/network3-filter.xml", "cpuQuotaForeground" : -1, "cpuQuotaBackground" : 1000, "runMountPoint" : "/tmp/ut-containers-manager/console3-dbus", diff --git a/tests/unit_tests/client/configs/ut-client/libvirt-config/network1-filter.xml b/tests/unit_tests/client/configs/ut-client/libvirt-config/network1-filter.xml new file mode 100644 index 0000000..bf39965 --- /dev/null +++ b/tests/unit_tests/client/configs/ut-client/libvirt-config/network1-filter.xml @@ -0,0 +1,3 @@ + + abc79a77-0209-41a2-ab82-f767dfa5897e + diff --git a/tests/unit_tests/client/configs/ut-client/libvirt-config/network2-filter.xml b/tests/unit_tests/client/configs/ut-client/libvirt-config/network2-filter.xml new file mode 100644 index 0000000..f33c816 --- /dev/null +++ b/tests/unit_tests/client/configs/ut-client/libvirt-config/network2-filter.xml @@ -0,0 +1,3 @@ + + 703f53eb-c602-4383-9de9-62bbe843ba31 + diff --git a/tests/unit_tests/client/configs/ut-client/libvirt-config/network3-filter.xml b/tests/unit_tests/client/configs/ut-client/libvirt-config/network3-filter.xml new file mode 100644 index 0000000..04310bd --- /dev/null +++ b/tests/unit_tests/client/configs/ut-client/libvirt-config/network3-filter.xml @@ -0,0 +1,3 @@ + + 40943fcc-faec-4bfe-9e89-104945164d35 + diff --git a/tests/unit_tests/client/ut-client.cpp b/tests/unit_tests/client/ut-client.cpp index 1755874..cab82e1 100644 --- a/tests/unit_tests/client/ut-client.cpp +++ b/tests/unit_tests/client/ut-client.cpp @@ -27,14 +27,19 @@ #include "ut.hpp" #include +#include "utils/latch.hpp" #include "containers-manager.hpp" #include #include #include #include +#include +#include +#include using namespace security_containers; +using namespace security_containers::utils; namespace { @@ -46,6 +51,7 @@ struct Fixture { ~Fixture() { sc_stop(); }; }; +const int EVENT_TIMEOUT = 5000; ///< ms const std::map EXPECTED_DBUSES_STARTED = { {"ut-containers-manager-console1-dbus", "unix:path=/tmp/ut-containers-manager/console1-dbus/dbus/system_bus_socket"}, @@ -65,6 +71,13 @@ void convertDictToMap(ScArrayString keys, } } +void convertArrayToSet(ScArrayString values, std::set& ret) +{ + for (char** iValues = values; *iValues; iValues++) { + ret.insert(*iValues); + } +} + int getArrayStringLength(ScArrayString astring, int max_len = -1) { int i = 0; @@ -76,6 +89,15 @@ int getArrayStringLength(ScArrayString astring, int max_len = -1) return i; } +Latch signalReceivedLatch; +std::vector< std::tuple > receivedSignalMsg; + +void NotificationTestCallback(const char* container, const char* application, const char* message) +{ + receivedSignalMsg.push_back(std::make_tuple(container, application, message)); + signalReceivedLatch.set(); +} + } // namespace BOOST_FIXTURE_TEST_SUITE(Client, Fixture) @@ -116,4 +138,102 @@ BOOST_AUTO_TEST_CASE(GetContainerDbusesTest) BOOST_WARN_NO_THROW(cm.reset()); } +BOOST_AUTO_TEST_CASE(GetContainerIdsTest) +{ + std::unique_ptr cm; + BOOST_REQUIRE_NO_THROW(cm.reset(new ContainersManager(TEST_DBUS_CONFIG_PATH))); + cm->startAll(); + ScClient client; + ScStatus status = sc_get_client(&client, SCCLIENT_SYSTEM_TYPE); + BOOST_REQUIRE(!sc_is_failed(status)); + ScArrayString values; + status = sc_get_container_ids(client, &values); + BOOST_REQUIRE(!sc_is_failed(status)); + BOOST_CHECK_EQUAL(getArrayStringLength(values, EXPECTED_DBUSES_STARTED.size() + 1), + EXPECTED_DBUSES_STARTED.size()); + + std::set containers; + convertArrayToSet(values, containers); + + for (const auto& container : containers) { + BOOST_CHECK(EXPECTED_DBUSES_STARTED.find(container) != EXPECTED_DBUSES_STARTED.cend()); + } + sc_array_string_free(values); + sc_client_free(client); + + BOOST_WARN_NO_THROW(cm.reset()); +} + +BOOST_AUTO_TEST_CASE(GetActiveContainerIdTest) +{ + std::unique_ptr cm; + BOOST_REQUIRE_NO_THROW(cm.reset(new ContainersManager(TEST_DBUS_CONFIG_PATH))); + cm->startAll(); + + ScClient client; + ScStatus status = sc_get_client(&client, SCCLIENT_SYSTEM_TYPE); + BOOST_REQUIRE(!sc_is_failed(status)); + ScString container; + status = sc_get_active_container_id(client, &container); + BOOST_REQUIRE(!sc_is_failed(status)); + + BOOST_CHECK_EQUAL(container, cm->getRunningForegroundContainerId()); + + sc_string_free(container); + sc_client_free(client); + + BOOST_WARN_NO_THROW(cm.reset()); +} + +BOOST_AUTO_TEST_CASE(SetActiveContainerTest) +{ + std::string newActiveContainerId = "ut-containers-manager-console2-dbus"; + + std::unique_ptr cm; + BOOST_REQUIRE_NO_THROW(cm.reset(new ContainersManager(TEST_DBUS_CONFIG_PATH))); + cm->startAll(); + BOOST_REQUIRE_NE(newActiveContainerId, cm->getRunningForegroundContainerId()); + + ScClient client; + ScStatus status = sc_get_client(&client, SCCLIENT_SYSTEM_TYPE); + BOOST_REQUIRE(!sc_is_failed(status)); + status = sc_set_active_container(client, newActiveContainerId.c_str()); + BOOST_REQUIRE(!sc_is_failed(status)); + BOOST_CHECK_EQUAL(newActiveContainerId, cm->getRunningForegroundContainerId()); + sc_client_free(client); + BOOST_WARN_NO_THROW(cm.reset()); +} + +BOOST_AUTO_TEST_CASE(NotificationTest) +{ + std::string activeContainerId = "ut-containers-manager-console1-dbus"; + std::unique_ptr cm; + BOOST_REQUIRE_NO_THROW(cm.reset(new ContainersManager(TEST_DBUS_CONFIG_PATH))); + cm->startAll(); + + std::map clients; + for (const auto& it : EXPECTED_DBUSES_STARTED) { + ScClient client; + ScStatus status = sc_get_client(&client, SCCLIENT_CUSTOM_TYPE, it.second.c_str()); + BOOST_REQUIRE(!sc_is_failed(status)); + clients[it.first] = client; + } + for (auto& client : clients) { + ScStatus status = sc_notification(client.second, NotificationTestCallback); + BOOST_REQUIRE(!sc_is_failed(status)); + } + for (auto& client : clients) { + ScStatus status = sc_notify_active_container(client.second, "app", "msg"); + BOOST_REQUIRE(!sc_is_failed(status)); + } + + BOOST_CHECK(signalReceivedLatch.waitForN(clients.size() - 1, EVENT_TIMEOUT)); + BOOST_CHECK(signalReceivedLatch.empty()); + + for (auto& client : clients) { + sc_client_free(client.second); + } + BOOST_WARN_NO_THROW(cm.reset()); +} + BOOST_AUTO_TEST_SUITE_END() -- 2.7.4 From 8f1989c65cb93980c22d6af3787a5f637f37bb0f Mon Sep 17 00:00:00 2001 From: Jan Olszak Date: Wed, 20 Aug 2014 12:50:45 +0200 Subject: [PATCH 03/16] Tests of a function for key creation [Bug/Feature] Tests of key creation [Cause] N/A [Solution] N/A [Verification] Build, install, run tests Change-Id: I4c7fbaec78dbba6f847e3c9275d62c3e4a4ef098 --- server/container.hpp | 1 + tests/unit_tests/config/ut-kvstore.cpp | 13 +++++++++++++ 2 files changed, 14 insertions(+) diff --git a/server/container.hpp b/server/container.hpp index c29b860..f2d67c0 100644 --- a/server/container.hpp +++ b/server/container.hpp @@ -32,6 +32,7 @@ #include "container-connection-transport.hpp" #include "network-admin.hpp" + #include #include #include diff --git a/tests/unit_tests/config/ut-kvstore.cpp b/tests/unit_tests/config/ut-kvstore.cpp index a1e5591..66efc2b 100644 --- a/tests/unit_tests/config/ut-kvstore.cpp +++ b/tests/unit_tests/config/ut-kvstore.cpp @@ -228,4 +228,17 @@ BOOST_AUTO_TEST_CASE(ClearTest) BOOST_CHECK_THROW(c.get(KEY), ConfigException); } +BOOST_AUTO_TEST_CASE(KeyTest) +{ + BOOST_CHECK_EQUAL(key(), ""); + BOOST_CHECK_EQUAL(key<>(), ""); + BOOST_CHECK_EQUAL(key(""), ""); + BOOST_CHECK_EQUAL(key("KEY"), "KEY"); + BOOST_CHECK_EQUAL(key<>("KEY"), "KEY"); + BOOST_CHECK_EQUAL(key("KEY", "A"), "KEY.A"); + BOOST_CHECK_EQUAL(key("KEY", 1, 2.2), "KEY.1.2.2"); + BOOST_CHECK_EQUAL(key("KEY", 1, "B"), "KEY.1.B"); + BOOST_CHECK_EQUAL(key<'_'>("KEY", 1, 2.2), "KEY_1_2.2"); +} + BOOST_AUTO_TEST_SUITE_END() -- 2.7.4 From d9a52d5c3fe981b305080feb6386080902ae2a27 Mon Sep 17 00:00:00 2001 From: Piotr Bartosiewicz Date: Thu, 21 Aug 2014 18:02:49 +0200 Subject: [PATCH 04/16] Client library cleanup [Bug/Feature] N/A [Cause] N/A [Solution] N/A [Verification] Build, install, run tests Change-Id: Idd5feb3fe6ec78a9c3ad3ffbb5f26efda0abbaec --- client/security-containers-client-impl.cpp | 110 ++++++++---------------- client/security-containers-client-impl.hpp | 16 ++-- client/security-containers-client.cpp | 73 ++++++---------- client/security-containers-client.h | 131 ++++++++++++++--------------- common/utils/glib-loop.cpp | 11 +++ tests/scripts/sc_test_parser.py | 11 ++- tests/unit_tests/client/ut-client.cpp | 106 ++++++++++------------- 7 files changed, 198 insertions(+), 260 deletions(-) diff --git a/client/security-containers-client-impl.cpp b/client/security-containers-client-impl.cpp index 17315b0..9e0a54a 100644 --- a/client/security-containers-client-impl.cpp +++ b/client/security-containers-client-impl.cpp @@ -31,7 +31,6 @@ #include #include -#include #include #include @@ -42,19 +41,14 @@ using namespace security_containers::utils; namespace { -const string SCCLIENT_SUCCESS_MSG; -const string SCCLIENT_EXCEPTION_MSG = "unspecified exception"; +const DbusInterfaceInfo HOST_INTERFACE(api::host::BUS_NAME, + api::host::OBJECT_PATH, + api::host::INTERFACE); +const DbusInterfaceInfo CONTAINER_INTERFACE(api::container::BUS_NAME, + api::container::OBJECT_PATH, + api::container::INTERFACE); -const DbusInterfaceInfo hostDbusInterfaceInfo(api::host::BUS_NAME, - api::host::OBJECT_PATH, - api::host::INTERFACE); -const DbusInterfaceInfo domainDbusInterfaceInfo(api::container::BUS_NAME, - api::container::OBJECT_PATH, - api::container::INTERFACE); - -template struct fake_dependency: public std::false_type {}; - -unique_ptr loop; +unique_ptr gGlibLoop; void toDict(GVariant* in, ScArrayString* keys, ScArrayString* values) { @@ -81,14 +75,6 @@ void toDict(GVariant* in, ScArrayString* keys, ScArrayString* values) *values = outv; } -template -void toBasic(GVariant* in, T str) -{ - static_assert(fake_dependency::value, "Must use specialization"); - assert(!"Must use specialization"); -} - -template<> void toBasic(GVariant* in, char** str) { assert(in); @@ -123,64 +109,47 @@ void toArray(GVariant* in, T** scArray) ScStatus toStatus(const std::exception& ex) { if (typeid(DbusCustomException) == typeid(ex)) { - return SCCLIENT_DBUS_CUSTOM_EXCEPTION; + return SCCLIENT_CUSTOM_ERROR; } else if (typeid(DbusIOException) == typeid(ex)) { - return SCCLIENT_DBUS_IO_EXCEPTION; + return SCCLIENT_IO_ERROR; } else if (typeid(DbusOperationException) == typeid(ex)) { - return SCCLIENT_DBUS_OPERATION_EXCEPTION; + return SCCLIENT_OPERATION_FAILED; } else if (typeid(DbusInvalidArgumentException) == typeid(ex)) { - return SCCLIENT_DBUS_INVALID_ARGUMENT_EXCEPTION; + return SCCLIENT_INVALID_ARGUMENT; } else if (typeid(DbusException) == typeid(ex)) { - return SCCLIENT_DBUS_EXCEPTION; + return SCCLIENT_OTHER_ERROR; } - return SCCLIENT_RUNTIME_EXCEPTION; + return SCCLIENT_OTHER_ERROR; } } //namespace -ScStatus Client::sc_start() noexcept +ScStatus Client::sc_start_glib_loop() noexcept { try { - if (!loop) { - loop.reset(new ScopedGlibLoop()); + if (!gGlibLoop) { + gGlibLoop.reset(new ScopedGlibLoop()); } - } catch (const exception& ex) { - return toStatus(ex); - } catch (...) { - return SCCLIENT_EXCEPTION; + } catch (const exception&) { + return SCCLIENT_OTHER_ERROR; } return SCCLIENT_SUCCESS; } -ScStatus Client::sc_stop() noexcept +ScStatus Client::sc_stop_glib_loop() noexcept { try { - if (loop) { - loop.reset(); - } - } catch (const exception& ex) { - return toStatus(ex); - } catch (...) { - return SCCLIENT_EXCEPTION; + gGlibLoop.reset(); + } catch (const exception&) { + return SCCLIENT_OTHER_ERROR; } return SCCLIENT_SUCCESS; } -Client::Status::Status(ScStatus status) - : mScStatus(status) +Client::Status::Status() + : mScStatus(SCCLIENT_SUCCESS), mMsg() { - switch (status) { - case SCCLIENT_EXCEPTION: - mMsg = SCCLIENT_EXCEPTION_MSG; - break; - case SCCLIENT_SUCCESS: - mMsg = SCCLIENT_SUCCESS_MSG; - break; - default: - assert(!"Logic error. You must specify a message."); - mMsg = std::string(); - } } Client::Status::Status(ScStatus status, const std::string& msg) @@ -189,7 +158,6 @@ Client::Status::Status(ScStatus status, const std::string& msg) } Client::Client() noexcept - : mStatus(SCCLIENT_SUCCESS) { } @@ -201,11 +169,9 @@ ScStatus Client::createSystem() noexcept { try { mConnection = DbusConnection::createSystem(); - mStatus = Status(SCCLIENT_SUCCESS); + mStatus = Status(); } catch (const exception& ex) { mStatus = Status(toStatus(ex), ex.what()); - } catch (...) { - mStatus = Status(SCCLIENT_EXCEPTION); } return sc_get_status(); } @@ -214,11 +180,9 @@ ScStatus Client::create(const string& address) noexcept { try { mConnection = DbusConnection::create(address); - mStatus = Status(SCCLIENT_SUCCESS); + mStatus = Status(); } catch (const exception& ex) { mStatus = Status(toStatus(ex), ex.what()); - } catch (...) { - mStatus = Status(SCCLIENT_EXCEPTION); } return sc_get_status(); } @@ -239,11 +203,9 @@ ScStatus Client::callMethod(const DbusInterfaceInfo& info, if (args_out != NULL) { *args_out = ret.release(); } - mStatus = Status(SCCLIENT_SUCCESS); + mStatus = Status(); } catch (const exception& ex) { mStatus = Status(toStatus(ex), ex.what()); - } catch (...) { - mStatus = Status(SCCLIENT_EXCEPTION); } return sc_get_status(); } @@ -266,11 +228,9 @@ ScStatus Client::signalSubscribe(const DbusInterfaceInfo& info, }; try { mConnection->signalSubscribe(onSignal, info.busName); - mStatus = Status(SCCLIENT_SUCCESS); + mStatus = Status(); } catch (const std::exception& ex) { mStatus = Status(toStatus(ex), ex.what()); - } catch (...) { - mStatus = Status(SCCLIENT_EXCEPTION); } return sc_get_status(); } @@ -291,7 +251,7 @@ ScStatus Client::sc_get_container_dbuses(ScArrayString* keys, ScArrayString* val assert(values); GVariant* out; - ScStatus ret = callMethod(hostDbusInterfaceInfo, + ScStatus ret = callMethod(HOST_INTERFACE, api::host::METHOD_GET_CONTAINER_DBUSES, NULL, "(a{ss})", @@ -312,7 +272,7 @@ ScStatus Client::sc_get_container_ids(ScArrayString* array) noexcept assert(array); GVariant* out; - ScStatus ret = callMethod(hostDbusInterfaceInfo, + ScStatus ret = callMethod(HOST_INTERFACE, api::host::METHOD_GET_CONTAINER_ID_LIST, NULL, "(as)", @@ -333,7 +293,7 @@ ScStatus Client::sc_get_active_container_id(ScString* id) noexcept assert(id); GVariant* out; - ScStatus ret = callMethod(hostDbusInterfaceInfo, + ScStatus ret = callMethod(HOST_INTERFACE, api::host::METHOD_GET_ACTIVE_CONTAINER_ID, NULL, "(s)", @@ -354,7 +314,7 @@ ScStatus Client::sc_set_active_container(const char* id) noexcept assert(id); GVariant* args_in = g_variant_new("(s)", id); - return callMethod(hostDbusInterfaceInfo, api::host::METHOD_SET_ACTIVE_CONTAINER, args_in); + return callMethod(HOST_INTERFACE, api::host::METHOD_SET_ACTIVE_CONTAINER, args_in); } ScStatus Client::sc_container_dbus_state(ScContainerDbusStateCallback containerDbusStateCallback) @@ -369,7 +329,7 @@ ScStatus Client::sc_container_dbus_state(ScContainerDbusStateCallback containerD containerDbusStateCallback(container, dbusAddress); }; - return signalSubscribe(hostDbusInterfaceInfo, + return signalSubscribe(HOST_INTERFACE, api::host::SIGNAL_CONTAINER_DBUS_STATE, onSigal); } @@ -380,7 +340,7 @@ ScStatus Client::sc_notify_active_container(const char* application, const char* assert(message); GVariant* args_in = g_variant_new("(ss)", application, message); - return callMethod(domainDbusInterfaceInfo, + return callMethod(CONTAINER_INTERFACE, api::container::METHOD_NOTIFY_ACTIVE_CONTAINER, args_in); } @@ -397,5 +357,5 @@ ScStatus Client::sc_notification(ScNotificationCallback notificationCallback) no notificationCallback(container, application, message); }; - return signalSubscribe(domainDbusInterfaceInfo, api::container::SIGNAL_NOTIFICATION, onSigal); + return signalSubscribe(CONTAINER_INTERFACE, api::container::SIGNAL_NOTIFICATION, onSigal); } diff --git a/client/security-containers-client-impl.hpp b/client/security-containers-client-impl.hpp index aafcae0..d6c9c0d 100644 --- a/client/security-containers-client-impl.hpp +++ b/client/security-containers-client-impl.hpp @@ -54,7 +54,7 @@ class Client { private: typedef std::function SignalCallback; struct Status { - Status(ScStatus status); + Status(); Status(ScStatus status, const std::string& msg); ScStatus mScStatus; std::string mMsg; @@ -79,15 +79,15 @@ public: /** * Create client with system dbus address. * - * @return Status of this function call. + * @return status of this function call */ ScStatus createSystem() noexcept; /** * Create client. * - * @param address Dbus socket address. - * @return Status of this function call. + * @param address Dbus socket address + * @return status of this function call */ ScStatus create(const std::string& address) noexcept; @@ -136,14 +136,14 @@ public: */ ScStatus sc_notification(ScNotificationCallback notificationCallback) noexcept; /** - * @see ::sc_start + * @see ::sc_start_glib_loop */ - static ScStatus sc_start() noexcept; + static ScStatus sc_start_glib_loop() noexcept; /** - * @see ::sc_stop + * @see ::sc_stop_glib_loop */ - static ScStatus sc_stop() noexcept; + static ScStatus sc_stop_glib_loop() noexcept; }; #endif /* SECURITY_CONTAINERS_CLIENT_IMPL_HPP */ diff --git a/client/security-containers-client.cpp b/client/security-containers-client.cpp index 12a3d6d..f0b3f63 100644 --- a/client/security-containers-client.cpp +++ b/client/security-containers-client.cpp @@ -27,7 +27,6 @@ #include "security-containers-client.h" #include "security-containers-client-impl.hpp" -#include #include #ifndef API @@ -38,63 +37,39 @@ using namespace std; namespace { -typedef Client* ClientPtr; - -ClientPtr getClient(ScClient client) +Client& getClient(ScClient client) { assert(client); - return reinterpret_cast(client); + return *reinterpret_cast(client); } } // namespace /* external */ -API ScStatus sc_start() +API ScStatus sc_start_glib_loop() { - return Client::sc_start(); + return Client::sc_start_glib_loop(); } -API ScStatus sc_stop() +API ScStatus sc_stop_glib_loop() { - return Client::sc_stop(); + return Client::sc_stop_glib_loop(); } -API ScStatus sc_get_client(ScClient* client, ScClientType type, ...) +API ScClient sc_client_create() { - const char* address = NULL; - va_list vl; - va_start(vl, type); - if (type == SCCLIENT_CUSTOM_TYPE) { - address = va_arg(vl, const char*); - assert(address); - } - va_end(vl); - - assert(client); Client* clientPtr = new(nothrow) Client(); - *client = reinterpret_cast(clientPtr); - if (clientPtr == NULL) { - return SCCLIENT_NOT_ENOUGH_MEMORY; - } + return reinterpret_cast(clientPtr); +} - ScStatus status; - switch (type) { - case SCCLIENT_CUSTOM_TYPE: - status = clientPtr->create(address); - break; - case SCCLIENT_SYSTEM_TYPE: - status = clientPtr->createSystem(); - break; - default: - assert(!"Logic error. No such ScClient type"); - status = SCCLIENT_EXCEPTION; - } - return status; +API ScStatus sc_connect(ScClient client) +{ + return getClient(client).createSystem(); } -API int sc_is_failed(ScStatus status) +API ScStatus sc_connect_custom(ScClient client, const char* address) { - return status != SCCLIENT_SUCCESS ? 1 : 0; + return getClient(client).create(address); } API void sc_array_string_free(ScArrayString astring) @@ -117,54 +92,54 @@ API void sc_string_free(ScString string) API void sc_client_free(ScClient client) { if (client != NULL) { - delete getClient(client); + delete &getClient(client); } } API const char* sc_get_status_message(ScClient client) { - return getClient(client)->sc_get_status_message(); + return getClient(client).sc_get_status_message(); } API ScStatus sc_get_status(ScClient client) { - return getClient(client)->sc_get_status(); + return getClient(client).sc_get_status(); } API ScStatus sc_get_container_dbuses(ScClient client, ScArrayString* keys, ScArrayString* values) { - return getClient(client)->sc_get_container_dbuses(keys, values); + return getClient(client).sc_get_container_dbuses(keys, values); } API ScStatus sc_get_container_ids(ScClient client, ScArrayString* array) { - return getClient(client)->sc_get_container_ids(array); + return getClient(client).sc_get_container_ids(array); } API ScStatus sc_get_active_container_id(ScClient client, ScString* id) { - return getClient(client)->sc_get_active_container_id(id); + return getClient(client).sc_get_active_container_id(id); } API ScStatus sc_set_active_container(ScClient client, const char* id) { - return getClient(client)->sc_set_active_container(id); + return getClient(client).sc_set_active_container(id); } API ScStatus sc_container_dbus_state(ScClient client, ScContainerDbusStateCallback containerDbusStateCallback) { - return getClient(client)->sc_container_dbus_state(containerDbusStateCallback); + return getClient(client).sc_container_dbus_state(containerDbusStateCallback); } API ScStatus sc_notify_active_container(ScClient client, const char* application, const char* message) { - return getClient(client)->sc_notify_active_container(application, message); + return getClient(client).sc_notify_active_container(application, message); } API ScStatus sc_notification(ScClient client, ScNotificationCallback notificationCallback) { - return getClient(client)->sc_notification(notificationCallback); + return getClient(client).sc_notification(notificationCallback); } diff --git a/client/security-containers-client.h b/client/security-containers-client.h index 01ca12c..aeb69fb 100644 --- a/client/security-containers-client.h +++ b/client/security-containers-client.h @@ -54,90 +54,89 @@ typedef ScString* ScArrayString; * Completion status of communication function. */ typedef enum { - SCCLIENT_DBUS_CUSTOM_EXCEPTION, - SCCLIENT_DBUS_IO_EXCEPTION, - SCCLIENT_DBUS_OPERATION_EXCEPTION, - SCCLIENT_DBUS_INVALID_ARGUMENT_EXCEPTION, - SCCLIENT_DBUS_EXCEPTION, - SCCLIENT_NOT_ENOUGH_MEMORY, - SCCLIENT_RUNTIME_EXCEPTION, - SCCLIENT_EXCEPTION, - SCCLIENT_SUCCESS + SCCLIENT_CUSTOM_ERROR, ///< User specified error + SCCLIENT_IO_ERROR, ///< Input/Output error + SCCLIENT_OPERATION_FAILED, ///< Operation failed + SCCLIENT_INVALID_ARGUMENT, ///< Invalid argument + SCCLIENT_OTHER_ERROR, ///< Other error + SCCLIENT_SUCCESS ///< Success } ScStatus; -typedef enum { - SCCLIENT_SYSTEM_TYPE, - SCCLIENT_CUSTOM_TYPE -} ScClientType; - /** - * Initialize communication resources. + * Start glib loop. + * + * Do not call this function if the application creates glib loop itself. + * Otherwise call it before any other function from this library. + * + * @return status of this function call */ -ScStatus sc_start(); +ScStatus sc_start_glib_loop(); /** - * Release communication resources. + * Stop glib loop. * - * @return Status of this function call. + * @return status of this function call */ -ScStatus sc_stop(); +ScStatus sc_stop_glib_loop(); /** - * Create a security-containers-server's client. + * Create a new security-containers-server's client. * - * After calling this function a connection to security-containers-server is established. - * - * @param[out] client security-containers-server's client who will be returned. - * Client can be broken. To check this you must call sc_is_failed(). - * Broken client can't be used to communicate with security-containers-server. - * @param[in] type Type of client. - * @param[in] @optional address Dbus socket address (significant only for type SCCLIENT_CUSTOM_TYPE). - * @return Status of this function call. + * @return created client */ -ScStatus sc_get_client(ScClient* client, ScClientType type, /* const char* address */ ...); +ScClient sc_client_create(); /** * Release client resources. * - * @param client security-containers-server's client. + * @param client security-containers-server's client */ void sc_client_free(ScClient client); /** + * Get status code of last security-containers-server communication. + * + * @param client security-containers-server's client + * @return status of this function call + */ +ScStatus sc_get_status(ScClient client); + +/** * Get status message of the last security-containers-server communication. * - * @param client security-containers-server's client. - * @return Last status message from security-containers-server communication. + * @param client security-containers-server's client + * @return last status message from security-containers-server communication */ const char* sc_get_status_message(ScClient client); /** - * Get status code of last security-containers-server communication. + * Connect client to the security-containers-server. * - * @param client security-containers-server's client. - * @return Status of this function call. + * @param client security-containers-server's client + * @return status of this function call */ -ScStatus sc_get_status(ScClient client); +ScStatus sc_connect(ScClient client); /** - * Check if security-containers-server communication function fail. + * Connect client to the security-containers-server via custom address. * - * @param status Value returned by security-containers-server communication function. - * @return 0 if succeeded otherwise 1. + * @param client security-containers-server's client + * @param address dbus address + * @return status of this function call */ -int sc_is_failed(ScStatus status); +ScStatus sc_connect_custom(ScClient client, const char* address); /** * Release ScArrayString. * - * @param astring ScArrayString. + * @param astring ScArrayString */ void sc_array_string_free(ScArrayString astring); /** * Release ScString. * - * @param string ScString. + * @param string ScString */ void sc_string_free(ScString string); @@ -156,38 +155,38 @@ typedef void (*ScContainerDbusStateCallback)(const char* containerId, const char /** * Get dbus address of each container. * - * @param[in] client security-containers-server's client. - * @param[out] keys Array of containers name. - * @param[out] values Array of containers dbus address. - * @return Status of this function call. - * @post keys[i] corresponds to values[i]. + * @param[in] client security-containers-server's client + * @param[out] keys array of containers name + * @param[out] values array of containers dbus address + * @return status of this function call + * @post keys[i] corresponds to values[i] */ ScStatus sc_get_container_dbuses(ScClient client, ScArrayString* keys, ScArrayString* values); /** * Get containers name. * - * @param[in] client security-containers-server's client. - * @param[out] array Array of containers name. - * @return Status of this function call. + * @param[in] client security-containers-server's client + * @param[out] array array of containers name + * @return status of this function call */ ScStatus sc_get_container_ids(ScClient client, ScArrayString* array); /** * Get active container name. * - * @param[in] client security-containers-server's client. - * @param[out] id Active container name. - * @return Status of this function call. + * @param[in] client security-containers-server's client + * @param[out] id active container name + * @return status of this function call */ ScStatus sc_get_active_container_id(ScClient client, ScString* id); /** * Set active container. * - * @param client security-containers-server's client. - * @param id Container name. - * @return Status of this function call. + * @param client security-containers-server's client + * @param id container name + * @return status of this function call */ ScStatus sc_set_active_container(ScClient client, const char* id); @@ -196,9 +195,9 @@ ScStatus sc_set_active_container(ScClient client, const char* id); * * The callback function will be invoked on a different thread * - * @param client security-containers-server's client. - * @param containerDbusStateCallback Callback function. - * @return Status of this function call. + * @param client security-containers-server's client + * @param containerDbusStateCallback callback function + * @return status of this function call */ ScStatus sc_container_dbus_state(ScClient client, ScContainerDbusStateCallback containerDbusStateCallback); @@ -219,10 +218,10 @@ typedef void (*ScNotificationCallback)(const char* container, /** * Send message to active container. * - * @param client security-containers-server's client. - * @param application Application name. - * @param message Message. - * @return Status of this function call. + * @param client security-containers-server's client + * @param application application name + * @param message message + * @return status of this function call */ ScStatus sc_notify_active_container(ScClient client, const char* application, const char* message); @@ -231,9 +230,9 @@ ScStatus sc_notify_active_container(ScClient client, const char* application, co * * The callback function will be invoked on a different thread. * - * @param client security-containers-server's client. - * @param notificationCallback Callback function. - * @return Status of this function call. + * @param client security-containers-server's client + * @param notificationCallback callback function + * @return status of this function call */ ScStatus sc_notification(ScClient client, ScNotificationCallback notificationCallback); #ifdef __cplusplus diff --git a/common/utils/glib-loop.cpp b/common/utils/glib-loop.cpp index a735e1e..3d76928 100644 --- a/common/utils/glib-loop.cpp +++ b/common/utils/glib-loop.cpp @@ -26,15 +26,25 @@ #include "utils/glib-loop.hpp" #include "utils/callback-wrapper.hpp" +#include +#include #include namespace security_containers { namespace utils { +namespace { +std::atomic_bool gLoopPresent(false); +} + ScopedGlibLoop::ScopedGlibLoop() : mLoop(g_main_loop_new(NULL, FALSE), g_main_loop_unref) { + if (gLoopPresent.exchange(true)) { + // only one loop per process + assert(0 && "Loop is already running"); + } #if !GLIB_CHECK_VERSION(2,36,0) g_type_init(); #endif @@ -52,6 +62,7 @@ ScopedGlibLoop::~ScopedGlibLoop() //stop loop and wait g_main_loop_quit(mLoop.get()); mLoopThread.join(); + gLoopPresent = false; } void Glib::addTimerEvent(const unsigned int intervalMs, diff --git a/tests/scripts/sc_test_parser.py b/tests/scripts/sc_test_parser.py index 5299814..b8ec404 100644 --- a/tests/scripts/sc_test_parser.py +++ b/tests/scripts/sc_test_parser.py @@ -84,10 +84,17 @@ class Logger(object): def terminatedBySignal(self, bin, signum): self.error("\n=========== FAILED ===========\n") - signame = {2:"SIGINT", 9:"SIGKILL", 11:"SIGSEGV", 15:"SIGTERM"} + signame = { 2: "SIGINT (Interrupt)", + 3: "SIGQUIT (Quit)", + 5: "SIGTRAP (Trace trap)", + 6: "SIGABRT (Abort)", + 8: "SIGFPE (Floating-point exception)", + 9: "SIGKILL (Kill)", + 11: "SIGSEGV (Segmentation fault)", + 15: "SIGTERM (Termination)"} siginfo = signame.get(signum, 'signal ' + str(signum)) self.error('Terminated by ' + siginfo) - if signum == 11: # SIGSEGV + if signum in [5, 6, 8, 11]: self.error("\nUse following command to launch debugger:") self.error(self.__indentChar + "sc_launch_test.py --gdb " + bin) diff --git a/tests/unit_tests/client/ut-client.cpp b/tests/unit_tests/client/ut-client.cpp index cab82e1..dc6045a 100644 --- a/tests/unit_tests/client/ut-client.cpp +++ b/tests/unit_tests/client/ut-client.cpp @@ -46,9 +46,19 @@ namespace { const std::string TEST_DBUS_CONFIG_PATH = SC_TEST_CONFIG_INSTALL_DIR "/client/ut-client/test-dbus-daemon.conf"; +struct Loop { + Loop() { sc_start_glib_loop(); }; + ~Loop() { sc_stop_glib_loop(); }; +}; + struct Fixture { - Fixture() { sc_start(); }; - ~Fixture() { sc_stop(); }; + Loop loop; + ContainersManager cm; + + Fixture(): cm(TEST_DBUS_CONFIG_PATH) + { + cm.startAll(); + }; }; const int EVENT_TIMEOUT = 5000; ///< ms @@ -64,8 +74,8 @@ void convertDictToMap(ScArrayString keys, ScArrayString values, std::map& ret) { - char** iKeys; - char** iValues; + ScArrayString iKeys; + ScArrayString iValues; for (iKeys = keys, iValues = values; *iKeys && *iValues; iKeys++, iValues++) { ret.insert(std::make_pair(*iKeys, *iValues)); } @@ -73,7 +83,7 @@ void convertDictToMap(ScArrayString keys, void convertArrayToSet(ScArrayString values, std::set& ret) { - for (char** iValues = values; *iValues; iValues++) { + for (ScArrayString iValues = values; *iValues; iValues++) { ret.insert(*iValues); } } @@ -104,25 +114,23 @@ BOOST_FIXTURE_TEST_SUITE(Client, Fixture) BOOST_AUTO_TEST_CASE(NotRunningServerTest) { - ScClient client; - ScStatus status = sc_get_client(&client, - SCCLIENT_CUSTOM_TYPE, - EXPECTED_DBUSES_STARTED.begin()->second.c_str()); - BOOST_CHECK(sc_is_failed(status)); + cm.stopAll(); + + ScClient client = sc_client_create(); + ScStatus status = sc_connect_custom(client, + EXPECTED_DBUSES_STARTED.begin()->second.c_str()); + BOOST_CHECK_EQUAL(SCCLIENT_IO_ERROR, status); sc_client_free(client); } BOOST_AUTO_TEST_CASE(GetContainerDbusesTest) { - std::unique_ptr cm; - BOOST_REQUIRE_NO_THROW(cm.reset(new ContainersManager(TEST_DBUS_CONFIG_PATH))); - cm->startAll(); - ScClient client; - ScStatus status = sc_get_client(&client, SCCLIENT_SYSTEM_TYPE); - BOOST_REQUIRE(!sc_is_failed(status)); + ScClient client = sc_client_create(); + ScStatus status = sc_connect(client); + BOOST_REQUIRE_EQUAL(SCCLIENT_SUCCESS, status); ScArrayString keys, values; status = sc_get_container_dbuses(client, &keys, &values); - BOOST_REQUIRE(!sc_is_failed(status)); + BOOST_REQUIRE_EQUAL(SCCLIENT_SUCCESS, status); BOOST_CHECK_EQUAL(getArrayStringLength(keys, EXPECTED_DBUSES_STARTED.size() + 1), EXPECTED_DBUSES_STARTED.size()); @@ -135,20 +143,16 @@ BOOST_AUTO_TEST_CASE(GetContainerDbusesTest) sc_array_string_free(keys); sc_array_string_free(values); sc_client_free(client); - BOOST_WARN_NO_THROW(cm.reset()); } BOOST_AUTO_TEST_CASE(GetContainerIdsTest) { - std::unique_ptr cm; - BOOST_REQUIRE_NO_THROW(cm.reset(new ContainersManager(TEST_DBUS_CONFIG_PATH))); - cm->startAll(); - ScClient client; - ScStatus status = sc_get_client(&client, SCCLIENT_SYSTEM_TYPE); - BOOST_REQUIRE(!sc_is_failed(status)); + ScClient client = sc_client_create(); + ScStatus status = sc_connect(client); + BOOST_REQUIRE_EQUAL(SCCLIENT_SUCCESS, status); ScArrayString values; status = sc_get_container_ids(client, &values); - BOOST_REQUIRE(!sc_is_failed(status)); + BOOST_REQUIRE_EQUAL(SCCLIENT_SUCCESS, status); BOOST_CHECK_EQUAL(getArrayStringLength(values, EXPECTED_DBUSES_STARTED.size() + 1), EXPECTED_DBUSES_STARTED.size()); @@ -160,71 +164,54 @@ BOOST_AUTO_TEST_CASE(GetContainerIdsTest) } sc_array_string_free(values); sc_client_free(client); - - BOOST_WARN_NO_THROW(cm.reset()); } BOOST_AUTO_TEST_CASE(GetActiveContainerIdTest) { - std::unique_ptr cm; - BOOST_REQUIRE_NO_THROW(cm.reset(new ContainersManager(TEST_DBUS_CONFIG_PATH))); - cm->startAll(); - - ScClient client; - ScStatus status = sc_get_client(&client, SCCLIENT_SYSTEM_TYPE); - BOOST_REQUIRE(!sc_is_failed(status)); + ScClient client = sc_client_create(); + ScStatus status = sc_connect(client); + BOOST_REQUIRE_EQUAL(SCCLIENT_SUCCESS, status); ScString container; status = sc_get_active_container_id(client, &container); - BOOST_REQUIRE(!sc_is_failed(status)); + BOOST_REQUIRE_EQUAL(SCCLIENT_SUCCESS, status); - BOOST_CHECK_EQUAL(container, cm->getRunningForegroundContainerId()); + BOOST_CHECK_EQUAL(container, cm.getRunningForegroundContainerId()); sc_string_free(container); sc_client_free(client); - - BOOST_WARN_NO_THROW(cm.reset()); } BOOST_AUTO_TEST_CASE(SetActiveContainerTest) { - std::string newActiveContainerId = "ut-containers-manager-console2-dbus"; + const std::string newActiveContainerId = "ut-containers-manager-console2-dbus"; - std::unique_ptr cm; - BOOST_REQUIRE_NO_THROW(cm.reset(new ContainersManager(TEST_DBUS_CONFIG_PATH))); - cm->startAll(); - BOOST_REQUIRE_NE(newActiveContainerId, cm->getRunningForegroundContainerId()); + BOOST_REQUIRE_NE(newActiveContainerId, cm.getRunningForegroundContainerId()); - ScClient client; - ScStatus status = sc_get_client(&client, SCCLIENT_SYSTEM_TYPE); - BOOST_REQUIRE(!sc_is_failed(status)); + ScClient client = sc_client_create(); + ScStatus status = sc_connect(client); + BOOST_REQUIRE_EQUAL(SCCLIENT_SUCCESS, status); status = sc_set_active_container(client, newActiveContainerId.c_str()); - BOOST_REQUIRE(!sc_is_failed(status)); - BOOST_CHECK_EQUAL(newActiveContainerId, cm->getRunningForegroundContainerId()); + BOOST_REQUIRE_EQUAL(SCCLIENT_SUCCESS, status); + BOOST_CHECK_EQUAL(newActiveContainerId, cm.getRunningForegroundContainerId()); sc_client_free(client); - BOOST_WARN_NO_THROW(cm.reset()); } BOOST_AUTO_TEST_CASE(NotificationTest) { - std::string activeContainerId = "ut-containers-manager-console1-dbus"; - std::unique_ptr cm; - BOOST_REQUIRE_NO_THROW(cm.reset(new ContainersManager(TEST_DBUS_CONFIG_PATH))); - cm->startAll(); - std::map clients; for (const auto& it : EXPECTED_DBUSES_STARTED) { - ScClient client; - ScStatus status = sc_get_client(&client, SCCLIENT_CUSTOM_TYPE, it.second.c_str()); - BOOST_REQUIRE(!sc_is_failed(status)); + ScClient client = sc_client_create(); + ScStatus status = sc_connect_custom(client, it.second.c_str()); + BOOST_REQUIRE_EQUAL(SCCLIENT_SUCCESS, status); clients[it.first] = client; } for (auto& client : clients) { ScStatus status = sc_notification(client.second, NotificationTestCallback); - BOOST_REQUIRE(!sc_is_failed(status)); + BOOST_REQUIRE_EQUAL(SCCLIENT_SUCCESS, status); } for (auto& client : clients) { ScStatus status = sc_notify_active_container(client.second, "app", "msg"); - BOOST_REQUIRE(!sc_is_failed(status)); + BOOST_REQUIRE_EQUAL(SCCLIENT_SUCCESS, status); } BOOST_CHECK(signalReceivedLatch.waitForN(clients.size() - 1, EVENT_TIMEOUT)); @@ -233,7 +220,6 @@ BOOST_AUTO_TEST_CASE(NotificationTest) for (auto& client : clients) { sc_client_free(client.second); } - BOOST_WARN_NO_THROW(cm.reset()); } BOOST_AUTO_TEST_SUITE_END() -- 2.7.4 From 215491384b817b0fe1ddc69cca2dffa084bd2f97 Mon Sep 17 00:00:00 2001 From: Jan Olszak Date: Mon, 25 Aug 2014 16:03:05 +0200 Subject: [PATCH 05/16] Tests of serialization to and from KVStore [Bug/Feature] Tests of the serialization [Cause] N/A [Solution] N/A [Verification] Build, install, run tests Change-Id: If8fb03c39093847e607a5b0e7980a9f972053b56 --- tests/unit_tests/config/ut-configuration.cpp | 105 +++++++++++++++++++++++++-- 1 file changed, 98 insertions(+), 7 deletions(-) diff --git a/tests/unit_tests/config/ut-configuration.cpp b/tests/unit_tests/config/ut-configuration.cpp index 7d304db..6220a58 100644 --- a/tests/unit_tests/config/ut-configuration.cpp +++ b/tests/unit_tests/config/ut-configuration.cpp @@ -27,7 +27,9 @@ #include "ut.hpp" #include "config/fields.hpp" #include "config/manager.hpp" +#include +namespace fs = boost::filesystem; using namespace config; BOOST_AUTO_TEST_SUITE(ConfigurationSuite) @@ -35,11 +37,23 @@ BOOST_AUTO_TEST_SUITE(ConfigurationSuite) struct TestConfig { // subtree class struct SubConfig { + + struct SubSubConfig { + int intVal; + + CONFIG_REGISTER + ( + intVal + ) + }; + int intVal; + SubSubConfig subSubObj; CONFIG_REGISTER ( - intVal + intVal, + subSubObj ) }; @@ -87,8 +101,9 @@ const std::string jsonTestString = "\"intVector\": [ 1, 2, 3 ], " "\"stringVector\": [ \"a\", \"b\" ], " "\"doubleVector\": [ 0.000000, 1.000000, 2.000000 ], " - "\"subObj\": { \"intVal\": 54321 }, " - "\"subVector\": [ { \"intVal\": 123 }, { \"intVal\": 456 } ] }"; + "\"subObj\": { \"intVal\": 54321, \"subSubObj\": { \"intVal\": 234 } }, " + "\"subVector\": [ { \"intVal\": 123, \"subSubObj\": { \"intVal\": 345 } }, " + "{ \"intVal\": 456, \"subSubObj\": { \"intVal\": 567 } } ] }"; // Floating point tolerance as a number of rounding errors const int TOLERANCE = 1; @@ -125,6 +140,8 @@ BOOST_AUTO_TEST_CASE(FromStringTest) BOOST_REQUIRE_EQUAL(2, testConfig.subVector.size()); BOOST_CHECK_EQUAL(123, testConfig.subVector[0].intVal); BOOST_CHECK_EQUAL(456, testConfig.subVector[1].intVal); + BOOST_CHECK_EQUAL(345, testConfig.subVector[0].subSubObj.intVal); + BOOST_CHECK_EQUAL(567, testConfig.subVector[1].subSubObj.intVal); } @@ -140,10 +157,10 @@ BOOST_AUTO_TEST_CASE(ToStringTest) namespace loadErrorsTest { #define DECLARE_CONFIG(name, type) \ -struct name { \ - type field; \ - CONFIG_REGISTER(field) \ -}; + struct name { \ + type field; \ + CONFIG_REGISTER(field) \ + }; DECLARE_CONFIG(IntConfig, int) DECLARE_CONFIG(StringConfig, std::string) DECLARE_CONFIG(DoubleConfig, double) @@ -268,4 +285,78 @@ BOOST_AUTO_TEST_CASE(HasVisibleInternalHelperTest) BOOST_CHECK(isVisitable()); } +namespace saveLoadKVStoreTest { + +// This struct is like TestConfig, but without a list of structures. +struct PoorTestConfig { + // subtree class + struct SubConfig { + + struct SubSubConfig { + int intVal; + + CONFIG_REGISTER + ( + intVal + ) + }; + + int intVal; + SubSubConfig subSubObj; + + CONFIG_REGISTER + ( + intVal, + subSubObj + ) + }; + + int intVal; + std::int64_t int64Val; + std::string stringVal; + double doubleVal; + bool boolVal; + + std::vector intVector; + std::vector stringVector; + std::vector doubleVector; + + SubConfig subObj; + + CONFIG_REGISTER + ( + intVal, + int64Val, + stringVal, + doubleVal, + boolVal, + + intVector, + stringVector, + doubleVector, + + subObj + ) +}; +} // saveLoadKVStoreTest + + +BOOST_AUTO_TEST_CASE(FromToKVStoreTest) +{ + using namespace saveLoadKVStoreTest; + + // TODO: Change this to TestConfig and delete PoorTestConfig when serialization is implemented + PoorTestConfig config; + loadFromString(jsonTestString, config); + + std::string dbPath = fs::unique_path("/tmp/kvstore-%%%%.db3").string(); + + saveToKVStore(dbPath, config); + loadFromKVStore(dbPath, config); + saveToKVStore(dbPath, config, "some_config"); + loadFromKVStore(dbPath, config, "some_config"); + + fs::remove(dbPath); +} + BOOST_AUTO_TEST_SUITE_END() -- 2.7.4 From f235c0f5920a1dad41061311c2e89ccfb006104d Mon Sep 17 00:00:00 2001 From: Piotr Bartosiewicz Date: Wed, 27 Aug 2014 11:44:41 +0200 Subject: [PATCH 06/16] Fix possible UB in unit tests [Bug/Feature] Possible use of destroyed object in case when timeout was reached. [Cause] N/A [Solution] N/A [Verification] Build, install, run tests Change-Id: Ie4cf064c4c5e5171079e836f1b4ca24b2962121c --- tests/unit_tests/client/ut-client.cpp | 27 ++++++++++++----------- tests/unit_tests/dbus/ut-connection.cpp | 8 +++---- tests/unit_tests/server/ut-containers-manager.cpp | 18 ++++++++------- tests/unit_tests/server/ut-input-monitor.cpp | 8 +++++++ tests/unit_tests/utils/ut-callback-guard.cpp | 2 +- tests/unit_tests/utils/ut-glib-loop.cpp | 7 +++--- 6 files changed, 40 insertions(+), 30 deletions(-) diff --git a/tests/unit_tests/client/ut-client.cpp b/tests/unit_tests/client/ut-client.cpp index dc6045a..f3c636f 100644 --- a/tests/unit_tests/client/ut-client.cpp +++ b/tests/unit_tests/client/ut-client.cpp @@ -47,8 +47,8 @@ const std::string TEST_DBUS_CONFIG_PATH = SC_TEST_CONFIG_INSTALL_DIR "/client/ut-client/test-dbus-daemon.conf"; struct Loop { - Loop() { sc_start_glib_loop(); }; - ~Loop() { sc_stop_glib_loop(); }; + Loop() { sc_start_glib_loop(); } + ~Loop() { sc_stop_glib_loop(); } }; struct Fixture { @@ -58,7 +58,7 @@ struct Fixture { Fixture(): cm(TEST_DBUS_CONFIG_PATH) { cm.startAll(); - }; + } }; const int EVENT_TIMEOUT = 5000; ///< ms @@ -99,15 +99,6 @@ int getArrayStringLength(ScArrayString astring, int max_len = -1) return i; } -Latch signalReceivedLatch; -std::vector< std::tuple > receivedSignalMsg; - -void NotificationTestCallback(const char* container, const char* application, const char* message) -{ - receivedSignalMsg.push_back(std::make_tuple(container, application, message)); - signalReceivedLatch.set(); -} - } // namespace BOOST_FIXTURE_TEST_SUITE(Client, Fixture) @@ -198,6 +189,16 @@ BOOST_AUTO_TEST_CASE(SetActiveContainerTest) BOOST_AUTO_TEST_CASE(NotificationTest) { + // TODO add a void* to callback parameter and pass this two variables + // so that they no longer need to be global + static Latch signalReceivedLatch; + static std::vector< std::tuple > receivedSignalMsg; + + auto callback = [](const char* container, const char* application, const char* message) { + receivedSignalMsg.push_back(std::make_tuple(container, application, message)); + signalReceivedLatch.set(); + }; + std::map clients; for (const auto& it : EXPECTED_DBUSES_STARTED) { ScClient client = sc_client_create(); @@ -206,7 +207,7 @@ BOOST_AUTO_TEST_CASE(NotificationTest) clients[it.first] = client; } for (auto& client : clients) { - ScStatus status = sc_notification(client.second, NotificationTestCallback); + ScStatus status = sc_notification(client.second, callback); BOOST_REQUIRE_EQUAL(SCCLIENT_SUCCESS, status); } for (auto& client : clients) { diff --git a/tests/unit_tests/dbus/ut-connection.cpp b/tests/unit_tests/dbus/ut-connection.cpp index 18d4f7b..1352f85 100644 --- a/tests/unit_tests/dbus/ut-connection.cpp +++ b/tests/unit_tests/dbus/ut-connection.cpp @@ -375,6 +375,7 @@ BOOST_AUTO_TEST_CASE(MethodAsyncCallTest) ScopedDbusDaemon daemon; ScopedGlibLoop loop; Latch nameAcquired; + Latch callDone; DbusConnection::Pointer conn1 = DbusConnection::create(DBUS_ADDRESS); DbusConnection::Pointer conn2 = DbusConnection::create(DBUS_ADDRESS); @@ -406,8 +407,6 @@ BOOST_AUTO_TEST_CASE(MethodAsyncCallTest) }; conn1->registerObject(TESTAPI_OBJECT_PATH, TESTAPI_DEFINITION, handler); - Latch callDone; - auto asyncResult1 = [&](dbus::AsyncMethodCallResult& asyncMethodCallResult) { BOOST_CHECK(g_variant_is_of_type(asyncMethodCallResult.get(), G_VARIANT_TYPE_UNIT)); callDone.set(); @@ -455,6 +454,8 @@ BOOST_AUTO_TEST_CASE(MethodAsyncCallAsyncHandlerTest) ScopedDbusDaemon daemon; ScopedGlibLoop loop; Latch nameAcquired; + Latch handlerDone; + Latch callDone; DbusConnection::Pointer conn1 = DbusConnection::create(DBUS_ADDRESS); DbusConnection::Pointer conn2 = DbusConnection::create(DBUS_ADDRESS); @@ -464,7 +465,6 @@ BOOST_AUTO_TEST_CASE(MethodAsyncCallAsyncHandlerTest) [] {}); BOOST_REQUIRE(nameAcquired.wait(EVENT_TIMEOUT)); - Latch handlerDone; std::string strResult; MethodResultBuilder::Pointer deferredResult; @@ -486,8 +486,6 @@ BOOST_AUTO_TEST_CASE(MethodAsyncCallAsyncHandlerTest) }; conn1->registerObject(TESTAPI_OBJECT_PATH, TESTAPI_DEFINITION, handler); - Latch callDone; - auto asyncResult = [&](dbus::AsyncMethodCallResult& asyncMethodCallResult) { const gchar* ret = NULL; g_variant_get(asyncMethodCallResult.get(), "(&s)", &ret); diff --git a/tests/unit_tests/server/ut-containers-manager.cpp b/tests/unit_tests/server/ut-containers-manager.cpp index e8dc5de..e578a35 100644 --- a/tests/unit_tests/server/ut-containers-manager.cpp +++ b/tests/unit_tests/server/ut-containers-manager.cpp @@ -415,13 +415,14 @@ BOOST_AUTO_TEST_CASE(NotifyActiveContainerTest) ContainersManager cm(TEST_DBUS_CONFIG_PATH); cm.startAll(); + Latch signalReceivedLatch; + std::map> signalReceivedSourcesMap; + std::map> dbuses; for (int i = 1; i <= TEST_DBUS_CONNECTION_CONTAINERS_COUNT; ++i) { dbuses[i] = std::unique_ptr(new DbusAccessory(i)); } - Latch signalReceivedLatch; - std::map> signalReceivedSourcesMap; auto handler = [](Latch& latch, std::vector& receivedSignalSources, const std::string& /*senderBusName*/, @@ -518,15 +519,16 @@ BOOST_AUTO_TEST_CASE(MoveFileTest) ContainersManager cm(TEST_DBUS_CONFIG_PATH); cm.startAll(); + Latch notificationLatch; + std::string notificationSource; + std::string notificationPath; + std::string notificationRetcode; + std::map> dbuses; for (int i = 1; i <= 2; ++i) { dbuses[i] = std::unique_ptr(new DbusAccessory(i)); } - Latch notificationLatch; - std::string notificationSource; - std::string notificationPath; - std::string notificationRetcode; auto handler = [&](const std::string& /*senderBusName*/, const std::string& objectPath, const std::string& interface, @@ -763,11 +765,11 @@ BOOST_AUTO_TEST_CASE(GetContainerDbusesTest) BOOST_AUTO_TEST_CASE(ContainerDbusesSignalsTest) { - DbusAccessory host(DbusAccessory::HOST_ID); - Latch signalLatch; DbusAccessory::Dbuses collectedDbuses; + DbusAccessory host(DbusAccessory::HOST_ID); + auto onSignal = [&] (const std::string& /*senderBusName*/, const std::string& objectPath, const std::string& interface, diff --git a/tests/unit_tests/server/ut-input-monitor.cpp b/tests/unit_tests/server/ut-input-monitor.cpp index 13f1d51..99b0bd2 100644 --- a/tests/unit_tests/server/ut-input-monitor.cpp +++ b/tests/unit_tests/server/ut-input-monitor.cpp @@ -113,6 +113,8 @@ BOOST_AUTO_TEST_CASE(Config_deviceFilePathNotExisting) InputMonitorException); } +namespace { + void sendNEvents(Fixture& f, unsigned int noOfEventsToSend) { Latch eventLatch; @@ -146,6 +148,8 @@ void sendNEvents(Fixture& f, unsigned int noOfEventsToSend) BOOST_CHECK(!eventLatch.wait(10)); } +} // namespace + BOOST_AUTO_TEST_CASE(Event_oneAtATime) { sendNEvents(*this, 1); @@ -156,6 +160,8 @@ BOOST_AUTO_TEST_CASE(Event_tenAtATime) sendNEvents(*this, 10); } +namespace { + void sendNEventsWithPauses(Fixture& f, unsigned int noOfEventsToSend) { Latch eventLatch; @@ -194,6 +200,8 @@ void sendNEventsWithPauses(Fixture& f, unsigned int noOfEventsToSend) BOOST_CHECK(!eventLatch.wait(10)); } +} // namespace + BOOST_AUTO_TEST_CASE(Event_oneAtATimeWithPauses) { sendNEventsWithPauses(*this, 1); diff --git a/tests/unit_tests/utils/ut-callback-guard.cpp b/tests/unit_tests/utils/ut-callback-guard.cpp index 6a503b0..9e1e6b2 100644 --- a/tests/unit_tests/utils/ut-callback-guard.cpp +++ b/tests/unit_tests/utils/ut-callback-guard.cpp @@ -68,9 +68,9 @@ BOOST_AUTO_TEST_CASE(SimpleTest) BOOST_AUTO_TEST_CASE(ThreadTest) { - CallbackGuard guard; Latch trackerCreated; Latch trackerCanBeDestroyed; + CallbackGuard guard; std::future future = std::async(std::launch::async, [&]() -> bool { CallbackGuard::Tracker tracker = guard.spawn(); diff --git a/tests/unit_tests/utils/ut-glib-loop.cpp b/tests/unit_tests/utils/ut-glib-loop.cpp index 63fc3ee..af07eef 100644 --- a/tests/unit_tests/utils/ut-glib-loop.cpp +++ b/tests/unit_tests/utils/ut-glib-loop.cpp @@ -29,7 +29,7 @@ #include "utils/latch.hpp" #include "utils/glib-loop.hpp" -#include +#include BOOST_AUTO_TEST_SUITE(UtilsGlibLoopSuite) @@ -48,11 +48,12 @@ const unsigned int TIMER_WAIT_FOR = 2 * TIMER_NUMBER * TIMER_INTERVAL_MS; BOOST_AUTO_TEST_CASE(GlibTimerEventTest) { ScopedGlibLoop loop; - CallbackGuard guard; Latch latch; + std::atomic_uint counter(0); + + CallbackGuard guard; Glib::OnTimerEventCallback callback = [&]()->bool { - static unsigned int counter = 0; latch.set(); if (++counter >= TIMER_NUMBER) { return false; -- 2.7.4 From 325048b28534032b1401f65eed2580e9a9d64167 Mon Sep 17 00:00:00 2001 From: Dariusz Michaluk Date: Fri, 22 Aug 2014 11:29:37 +0200 Subject: [PATCH 07/16] Fix incorrect network configuration [Feature] Fix incorrect network configuration. [Cause] Incorrect network netmask, filter name, ip address. [Solution] N/A [Verification] Build, install on new minimal image, run tests. Change-Id: Idc1ddcd06c73297581f778b78d392bc34020c3cc Signed-off-by: Dariusz Michaluk --- server/configs/libvirt-config/business-network.xml | 2 +- server/configs/libvirt-config/business-nwfilter.xml | 6 +++--- server/configs/libvirt-config/business.xml | 2 +- server/configs/libvirt-config/private-network.xml | 2 +- server/configs/libvirt-config/private-nwfilter.xml | 6 +++--- server/configs/libvirt-config/private.xml | 2 +- tests/integration_tests/network_tests/network_common.py | 2 +- 7 files changed, 11 insertions(+), 11 deletions(-) diff --git a/server/configs/libvirt-config/business-network.xml b/server/configs/libvirt-config/business-network.xml index beb5c80..dbfc6c4 100644 --- a/server/configs/libvirt-config/business-network.xml +++ b/server/configs/libvirt-config/business-network.xml @@ -4,7 +4,7 @@ - + diff --git a/server/configs/libvirt-config/business-nwfilter.xml b/server/configs/libvirt-config/business-nwfilter.xml index ea7453e..6548f58 100644 --- a/server/configs/libvirt-config/business-nwfilter.xml +++ b/server/configs/libvirt-config/business-nwfilter.xml @@ -1,8 +1,8 @@ - + - + - + diff --git a/server/configs/libvirt-config/business.xml b/server/configs/libvirt-config/business.xml index c2539e9..7564d8b 100644 --- a/server/configs/libvirt-config/business.xml +++ b/server/configs/libvirt-config/business.xml @@ -99,7 +99,7 @@ - + diff --git a/server/configs/libvirt-config/private-network.xml b/server/configs/libvirt-config/private-network.xml index f917b52..7dec5a9 100644 --- a/server/configs/libvirt-config/private-network.xml +++ b/server/configs/libvirt-config/private-network.xml @@ -4,7 +4,7 @@ - + diff --git a/server/configs/libvirt-config/private-nwfilter.xml b/server/configs/libvirt-config/private-nwfilter.xml index f3bd8ca..12dc793 100644 --- a/server/configs/libvirt-config/private-nwfilter.xml +++ b/server/configs/libvirt-config/private-nwfilter.xml @@ -1,8 +1,8 @@ - + - + - + diff --git a/server/configs/libvirt-config/private.xml b/server/configs/libvirt-config/private.xml index d6ce465..b665a80 100644 --- a/server/configs/libvirt-config/private.xml +++ b/server/configs/libvirt-config/private.xml @@ -99,7 +99,7 @@ - + diff --git a/tests/integration_tests/network_tests/network_common.py b/tests/integration_tests/network_tests/network_common.py index 2b64920..63289a6 100755 --- a/tests/integration_tests/network_tests/network_common.py +++ b/tests/integration_tests/network_tests/network_common.py @@ -235,7 +235,7 @@ def twoNetworks(): # 0. Test data containers_list = [CONTAINER_T1, CONTAINER_T2] dest_containers_list = [CONTAINER_T2, CONTAINER_T1] - test_ip_list = [["192.168.101.2"], ["192.168.102.2"]] + test_ip_list = [["10.0.101.2"], ["10.0.102.2"]] test_1_expected_res = [ 0, 0] test_2_expected_res = [-1, -1] -- 2.7.4 From 269a8b8134def75be0b97c9379282a6845e93f48 Mon Sep 17 00:00:00 2001 From: Mateusz Malicki Date: Wed, 27 Aug 2014 14:19:40 +0200 Subject: [PATCH 08/16] Added extra parameter to be passed to client callback functions [Bug/Feature] Possibility to pass parameters to callback functions [Cause] N/A [Solution] N/A [Verification] Build, install, run tests Change-Id: I8f060912aa3370b697c384289395ec1b884e3288 --- client/security-containers-client-impl.cpp | 14 +++++----- client/security-containers-client-impl.hpp | 5 ++-- client/security-containers-client.cpp | 11 +++++--- client/security-containers-client.h | 14 +++++++--- tests/unit_tests/client/ut-client.cpp | 41 +++++++++++++++++++++--------- 5 files changed, 56 insertions(+), 29 deletions(-) diff --git a/client/security-containers-client-impl.cpp b/client/security-containers-client-impl.cpp index 9e0a54a..3487dab 100644 --- a/client/security-containers-client-impl.cpp +++ b/client/security-containers-client-impl.cpp @@ -317,16 +317,16 @@ ScStatus Client::sc_set_active_container(const char* id) noexcept return callMethod(HOST_INTERFACE, api::host::METHOD_SET_ACTIVE_CONTAINER, args_in); } -ScStatus Client::sc_container_dbus_state(ScContainerDbusStateCallback containerDbusStateCallback) - noexcept +ScStatus Client::sc_container_dbus_state(ScContainerDbusStateCallback containerDbusStateCallback, + void* data) noexcept { assert(containerDbusStateCallback); - auto onSigal = [ = ](GVariant * parameters) { + auto onSigal = [=](GVariant * parameters) { const char* container; const char* dbusAddress; g_variant_get(parameters, "(&s&s)", &container, &dbusAddress); - containerDbusStateCallback(container, dbusAddress); + containerDbusStateCallback(container, dbusAddress, data); }; return signalSubscribe(HOST_INTERFACE, @@ -345,16 +345,16 @@ ScStatus Client::sc_notify_active_container(const char* application, const char* args_in); } -ScStatus Client::sc_notification(ScNotificationCallback notificationCallback) noexcept +ScStatus Client::sc_notification(ScNotificationCallback notificationCallback, void* data) noexcept { assert(notificationCallback); - auto onSigal = [ = ](GVariant * parameters) { + auto onSigal = [=](GVariant * parameters) { const char* container; const char* application; const char* message; g_variant_get(parameters, "(&s&s&s)", &container, &application, &message); - notificationCallback(container, application, message); + notificationCallback(container, application, message, data); }; return signalSubscribe(CONTAINER_INTERFACE, api::container::SIGNAL_NOTIFICATION, onSigal); diff --git a/client/security-containers-client-impl.hpp b/client/security-containers-client-impl.hpp index d6c9c0d..13f06d3 100644 --- a/client/security-containers-client-impl.hpp +++ b/client/security-containers-client-impl.hpp @@ -124,7 +124,8 @@ public: /** * @see ::sc_container_dbus_state */ - ScStatus sc_container_dbus_state(ScContainerDbusStateCallback containerDbusStateCallback) noexcept; + ScStatus sc_container_dbus_state(ScContainerDbusStateCallback containerDbusStateCallback, + void* data) noexcept; /** * @see ::sc_notify_active_container @@ -134,7 +135,7 @@ public: /** * @see ::sc_notification */ - ScStatus sc_notification(ScNotificationCallback notificationCallback) noexcept; + ScStatus sc_notification(ScNotificationCallback notificationCallback, void* data) noexcept; /** * @see ::sc_start_glib_loop */ diff --git a/client/security-containers-client.cpp b/client/security-containers-client.cpp index f0b3f63..285d373 100644 --- a/client/security-containers-client.cpp +++ b/client/security-containers-client.cpp @@ -127,9 +127,10 @@ API ScStatus sc_set_active_container(ScClient client, const char* id) } API ScStatus sc_container_dbus_state(ScClient client, - ScContainerDbusStateCallback containerDbusStateCallback) + ScContainerDbusStateCallback containerDbusStateCallback, + void* data) { - return getClient(client).sc_container_dbus_state(containerDbusStateCallback); + return getClient(client).sc_container_dbus_state(containerDbusStateCallback, data); } API ScStatus sc_notify_active_container(ScClient client, @@ -139,7 +140,9 @@ API ScStatus sc_notify_active_container(ScClient client, return getClient(client).sc_notify_active_container(application, message); } -API ScStatus sc_notification(ScClient client, ScNotificationCallback notificationCallback) +API ScStatus sc_notification(ScClient client, + ScNotificationCallback notificationCallback, + void* data) { - return getClient(client).sc_notification(notificationCallback); + return getClient(client).sc_notification(notificationCallback, data); } diff --git a/client/security-containers-client.h b/client/security-containers-client.h index aeb69fb..d1d6e95 100644 --- a/client/security-containers-client.h +++ b/client/security-containers-client.h @@ -150,7 +150,9 @@ void sc_string_free(ScString string); /** * Dbus state change callback function signature. */ -typedef void (*ScContainerDbusStateCallback)(const char* containerId, const char* dbusAddress); +typedef void (*ScContainerDbusStateCallback)(const char* containerId, + const char* dbusAddress, + void* data); /** * Get dbus address of each container. @@ -197,10 +199,12 @@ ScStatus sc_set_active_container(ScClient client, const char* id); * * @param client security-containers-server's client * @param containerDbusStateCallback callback function + * @param data some extra data that will be passed to callback function * @return status of this function call */ ScStatus sc_container_dbus_state(ScClient client, - ScContainerDbusStateCallback containerDbusStateCallback); + ScContainerDbusStateCallback containerDbusStateCallback, + void* data); /************************************************************************************************* @@ -214,7 +218,8 @@ ScStatus sc_container_dbus_state(ScClient client, */ typedef void (*ScNotificationCallback)(const char* container, const char* application, - const char* message); + const char* message, + void* data); /** * Send message to active container. * @@ -232,9 +237,10 @@ ScStatus sc_notify_active_container(ScClient client, const char* application, co * * @param client security-containers-server's client * @param notificationCallback callback function + * @param data some extra data that will be passed to callback function * @return status of this function call */ -ScStatus sc_notification(ScClient client, ScNotificationCallback notificationCallback); +ScStatus sc_notification(ScClient client, ScNotificationCallback notificationCallback, void* data); #ifdef __cplusplus } #endif diff --git a/tests/unit_tests/client/ut-client.cpp b/tests/unit_tests/client/ut-client.cpp index f3c636f..c6249cd 100644 --- a/tests/unit_tests/client/ut-client.cpp +++ b/tests/unit_tests/client/ut-client.cpp @@ -189,16 +189,25 @@ BOOST_AUTO_TEST_CASE(SetActiveContainerTest) BOOST_AUTO_TEST_CASE(NotificationTest) { - // TODO add a void* to callback parameter and pass this two variables - // so that they no longer need to be global - static Latch signalReceivedLatch; - static std::vector< std::tuple > receivedSignalMsg; - - auto callback = [](const char* container, const char* application, const char* message) { - receivedSignalMsg.push_back(std::make_tuple(container, application, message)); - signalReceivedLatch.set(); + const std::string MSG_CONTENT = "msg"; + const std::string MSG_APP = "app"; + + struct CallbackData { + Latch signalReceivedLatch; + std::vector< std::tuple > receivedSignalMsg; + }; + + auto callback = [](const char* container, + const char* application, + const char* message, + void* data) + { + CallbackData& callbackData = *reinterpret_cast(data); + callbackData.receivedSignalMsg.push_back(std::make_tuple(container, application, message)); + callbackData.signalReceivedLatch.set(); }; + CallbackData callbackData; std::map clients; for (const auto& it : EXPECTED_DBUSES_STARTED) { ScClient client = sc_client_create(); @@ -207,16 +216,24 @@ BOOST_AUTO_TEST_CASE(NotificationTest) clients[it.first] = client; } for (auto& client : clients) { - ScStatus status = sc_notification(client.second, callback); + ScStatus status = sc_notification(client.second, callback, &callbackData); BOOST_REQUIRE_EQUAL(SCCLIENT_SUCCESS, status); } for (auto& client : clients) { - ScStatus status = sc_notify_active_container(client.second, "app", "msg"); + ScStatus status = sc_notify_active_container(client.second, + MSG_APP.c_str(), + MSG_CONTENT.c_str()); BOOST_REQUIRE_EQUAL(SCCLIENT_SUCCESS, status); } - BOOST_CHECK(signalReceivedLatch.waitForN(clients.size() - 1, EVENT_TIMEOUT)); - BOOST_CHECK(signalReceivedLatch.empty()); + BOOST_CHECK(callbackData.signalReceivedLatch.waitForN(clients.size() - 1, EVENT_TIMEOUT)); + BOOST_CHECK(callbackData.signalReceivedLatch.empty()); + + for (const auto& msg : callbackData.receivedSignalMsg) { + BOOST_CHECK(clients.count(std::get<0>(msg)) > 0); + BOOST_CHECK_EQUAL(std::get<1>(msg), MSG_APP); + BOOST_CHECK_EQUAL(std::get<2>(msg), MSG_CONTENT); + } for (auto& client : clients) { sc_client_free(client.second); -- 2.7.4 From 7b9356173b7765ab27d2796ecd3f4afa8fdfb263 Mon Sep 17 00:00:00 2001 From: Mateusz Malicki Date: Wed, 27 Aug 2014 15:25:45 +0200 Subject: [PATCH 09/16] Added sc_file_move_request client library function [Bug/Feature] Added sc_file_move_request client library function [Cause] N/A [Solution] N/A [Verification] Build, install, run tests Change-Id: I6c0449a06a4b9b3ad9c17fda16d00099100f71ed --- client/security-containers-client-impl.cpp | 27 +++++++++++++++++++++++++++ client/security-containers-client-impl.hpp | 4 ++++ client/security-containers-client.cpp | 5 +++++ client/security-containers-client.h | 9 +++++++++ tests/unit_tests/client/ut-client.cpp | 16 ++++++++++++++++ 5 files changed, 61 insertions(+) diff --git a/client/security-containers-client-impl.cpp b/client/security-containers-client-impl.cpp index 3487dab..8486ae7 100644 --- a/client/security-containers-client-impl.cpp +++ b/client/security-containers-client-impl.cpp @@ -345,6 +345,33 @@ ScStatus Client::sc_notify_active_container(const char* application, const char* args_in); } +ScStatus Client::sc_file_move_request(const char* destContainer, const char* path) noexcept +{ + assert(destContainer); + assert(path); + + GVariant* out; + GVariant* args_in = g_variant_new("(ss)", destContainer, path); + ScStatus ret = callMethod(CONTAINER_INTERFACE, + api::container::METHOD_FILE_MOVE_REQUEST, + args_in, + "(s)", + &out); + + if (ret != SCCLIENT_SUCCESS) { + return ret; + } + const gchar* retcode = NULL;; + g_variant_get(out, "(&s)", &retcode); + if (strcmp(retcode, api::container::FILE_MOVE_SUCCEEDED.c_str()) != 0) { + mStatus = Status(SCCLIENT_CUSTOM_ERROR, retcode); + g_variant_unref(out); + return sc_get_status(); + } + g_variant_unref(out); + return ret; +} + ScStatus Client::sc_notification(ScNotificationCallback notificationCallback, void* data) noexcept { assert(notificationCallback); diff --git a/client/security-containers-client-impl.hpp b/client/security-containers-client-impl.hpp index 13f06d3..10aecaf 100644 --- a/client/security-containers-client-impl.hpp +++ b/client/security-containers-client-impl.hpp @@ -133,6 +133,10 @@ public: ScStatus sc_notify_active_container(const char* application, const char* message) noexcept; /** + * @see ::sc_file_move_request + */ + ScStatus sc_file_move_request(const char* destContainer, const char* path) noexcept; + /** * @see ::sc_notification */ ScStatus sc_notification(ScNotificationCallback notificationCallback, void* data) noexcept; diff --git a/client/security-containers-client.cpp b/client/security-containers-client.cpp index 285d373..b1eb521 100644 --- a/client/security-containers-client.cpp +++ b/client/security-containers-client.cpp @@ -140,6 +140,11 @@ API ScStatus sc_notify_active_container(ScClient client, return getClient(client).sc_notify_active_container(application, message); } +API ScStatus sc_file_move_request(ScClient client, const char* destContainer, const char* path) +{ + return getClient(client).sc_file_move_request(destContainer, path); +} + API ScStatus sc_notification(ScClient client, ScNotificationCallback notificationCallback, void* data) diff --git a/client/security-containers-client.h b/client/security-containers-client.h index d1d6e95..1632497 100644 --- a/client/security-containers-client.h +++ b/client/security-containers-client.h @@ -231,6 +231,15 @@ typedef void (*ScNotificationCallback)(const char* container, ScStatus sc_notify_active_container(ScClient client, const char* application, const char* message); /** + * Move file between containers. + * + * @param client security-containers-server's client + * @param destContainer destination container id + * @param path path to moved file + */ +ScStatus sc_file_move_request(ScClient client, const char* destContainer, const char* path); + +/** * Register notification callback function. * * The callback function will be invoked on a different thread. diff --git a/tests/unit_tests/client/ut-client.cpp b/tests/unit_tests/client/ut-client.cpp index c6249cd..bbf2013 100644 --- a/tests/unit_tests/client/ut-client.cpp +++ b/tests/unit_tests/client/ut-client.cpp @@ -29,6 +29,7 @@ #include "utils/latch.hpp" #include "containers-manager.hpp" +#include "container-dbus-definitions.hpp" #include #include @@ -187,6 +188,21 @@ BOOST_AUTO_TEST_CASE(SetActiveContainerTest) sc_client_free(client); } +BOOST_AUTO_TEST_CASE(FileMoveRequestTest) +{ + const std::string path = "/tmp/fake_path"; + const std::string secondContainer = "fake_container"; + + ScClient client = sc_client_create(); + ScStatus status = sc_connect_custom(client, EXPECTED_DBUSES_STARTED.begin()->second.c_str()); + BOOST_REQUIRE_EQUAL(SCCLIENT_SUCCESS, status); + status = sc_file_move_request(client, secondContainer.c_str(), path.c_str()); + BOOST_REQUIRE_EQUAL(SCCLIENT_CUSTOM_ERROR, status); + BOOST_REQUIRE_EQUAL(api::container::FILE_MOVE_DESTINATION_NOT_FOUND, + sc_get_status_message(client)); + sc_client_free(client); +} + BOOST_AUTO_TEST_CASE(NotificationTest) { const std::string MSG_CONTENT = "msg"; -- 2.7.4 From ee9f863101d7619be4028cc11d659c2306e42532 Mon Sep 17 00:00:00 2001 From: Michal Witanowski Date: Mon, 1 Sep 2014 15:14:49 +0200 Subject: [PATCH 10/16] Make SCS D-Bus independent [Bug/Feature] Allow to run security-containers-server without dbusd inside a container(s). [Cause] N/A [Solution] Add new value to containers' configs: "enableDbusIntegration". [Verification] * build, install, run tests * run SCS with default configuration * run SCS with dbus disabled in one of the containers Change-Id: If6d42487086a4907b231a8422c49c4cbdedfe18f --- server/configs/containers/business.conf | 1 + server/configs/containers/private.conf | 1 + server/container-config.hpp | 7 +++++++ server/container-connection.cpp | 5 ++--- server/container.cpp | 17 +++++++++++------ .../configs/ut-client/containers/console1-dbus.conf | 1 + .../configs/ut-client/containers/console2-dbus.conf | 1 + .../configs/ut-client/containers/console3-dbus.conf | 1 + .../ut-container-admin/containers/buggy.conf.in | 1 + .../ut-container-admin/containers/missing.conf | 1 + .../containers/test-no-shutdown.conf.in | 1 + .../ut-container-admin/containers/test.conf.in | 1 + .../configs/ut-container/containers/buggy.conf | 1 + .../configs/ut-container/containers/test-dbus.conf | 1 + .../configs/ut-container/containers/test.conf | 1 + .../containers/console1-dbus.conf | 1 + .../ut-containers-manager/containers/console1.conf | 1 + .../containers/console2-dbus.conf | 1 + .../ut-containers-manager/containers/console2.conf | 1 + .../containers/console3-dbus.conf | 1 + .../ut-containers-manager/containers/console3.conf | 1 + .../ut-network-admin/containers/buggy.conf.in | 1 + .../ut-network-admin/containers/missing.conf | 1 + .../ut-network-admin/containers/test.conf.in | 1 + .../configs/ut-server/containers/container1.conf | 1 + .../configs/ut-server/containers/container2.conf | 1 + .../configs/ut-server/containers/container3.conf | 1 + tests/unit_tests/server/ut-containers-manager.cpp | 21 ++++++++++++++++----- 28 files changed, 60 insertions(+), 14 deletions(-) diff --git a/server/configs/containers/business.conf b/server/configs/containers/business.conf index 1b711b4..1b3502a 100644 --- a/server/configs/containers/business.conf +++ b/server/configs/containers/business.conf @@ -1,6 +1,7 @@ { "cpuQuotaForeground" : -1, "cpuQuotaBackground" : 1000, + "enableDbusIntegration" : true, "privilege" : 1, "switchToDefaultAfterTimeout" : true, "config" : "../libvirt-config/business.xml", diff --git a/server/configs/containers/private.conf b/server/configs/containers/private.conf index a981caf..62c0f18 100644 --- a/server/configs/containers/private.conf +++ b/server/configs/containers/private.conf @@ -1,6 +1,7 @@ { "cpuQuotaForeground" : -1, "cpuQuotaBackground" : 1000, + "enableDbusIntegration" : true, "privilege" : 10, "switchToDefaultAfterTimeout" : true, "config" : "../libvirt-config/private.xml", diff --git a/server/container-config.hpp b/server/container-config.hpp index e679abb..b506770 100644 --- a/server/container-config.hpp +++ b/server/container-config.hpp @@ -49,6 +49,12 @@ struct ContainerConfig { bool switchToDefaultAfterTimeout; /** + * Specify, if D-Bus communication with the container will be enabled. + * Setting this value to "false" will make the domain API not work inside the container. + */ + bool enableDbusIntegration; + + /** * Container's libvirt (XML) config file. * Location can be relative to the Container's config file. */ @@ -96,6 +102,7 @@ struct ContainerConfig { ( privilege, switchToDefaultAfterTimeout, + enableDbusIntegration, config, networkConfig, networkFilterConfig, diff --git a/server/container-connection.cpp b/server/container-connection.cpp index d3098aa..7eb8447 100644 --- a/server/container-connection.cpp +++ b/server/container-connection.cpp @@ -50,9 +50,8 @@ ContainerConnection::ContainerConnection(const std::string& address, const OnNam , mNameLost(false) { if (address.empty()) { - // TODO: this should throw. Don't return cleanly unless the object is fully usable. - LOGW("The connection to the container is disabled"); - return; + LOGE("Invalid container connection address"); + throw ContainerConnectionException("Invalid container connection address"); } LOGT("Connecting to DBUS on " << address); diff --git a/server/container.cpp b/server/container.cpp index 62b2c65a..60d124e 100644 --- a/server/container.cpp +++ b/server/container.cpp @@ -117,14 +117,17 @@ int Container::getPrivilege() const void Container::start() { Lock lock(mReconnectMutex); - mConnectionTransport.reset(new ContainerConnectionTransport(mRunMountPoint)); + if (mConfig.enableDbusIntegration) { + mConnectionTransport.reset(new ContainerConnectionTransport(mRunMountPoint)); + } mNetworkAdmin->start(); mAdmin->start(); - connect(); + if (mConfig.enableDbusIntegration) { + connect(); + } - // Send to the background only after we're connected, - // otherwise it'd take ages. - LOGD(getId() << ": DBUS connected, sending to the background"); + // Send to the background only after we're connected, otherwise it'd take ages. + LOGD(getId() << ": sending to the background"); goBackground(); } @@ -196,7 +199,9 @@ void Container::setDetachOnExit() Lock lock(mReconnectMutex); mNetworkAdmin->setDetachOnExit(); mAdmin->setDetachOnExit(); - mConnectionTransport->setDetachOnExit(); + if (mConnectionTransport) { + mConnectionTransport->setDetachOnExit(); + } } bool Container::isRunning() diff --git a/tests/unit_tests/client/configs/ut-client/containers/console1-dbus.conf b/tests/unit_tests/client/configs/ut-client/containers/console1-dbus.conf index af3380b..e16f7d6 100644 --- a/tests/unit_tests/client/configs/ut-client/containers/console1-dbus.conf +++ b/tests/unit_tests/client/configs/ut-client/containers/console1-dbus.conf @@ -1,6 +1,7 @@ { "privilege" : 20, "switchToDefaultAfterTimeout" : true, + "enableDbusIntegration" : true, "config" : "../libvirt-config/console1-dbus.xml", "networkConfig" : "../libvirt-config/network1.xml", "networkFilterConfig" : "../libvirt-config/network1-filter.xml", diff --git a/tests/unit_tests/client/configs/ut-client/containers/console2-dbus.conf b/tests/unit_tests/client/configs/ut-client/containers/console2-dbus.conf index 0db0a8a..9aa8e51 100644 --- a/tests/unit_tests/client/configs/ut-client/containers/console2-dbus.conf +++ b/tests/unit_tests/client/configs/ut-client/containers/console2-dbus.conf @@ -1,6 +1,7 @@ { "privilege" : 20, "switchToDefaultAfterTimeout" : false, + "enableDbusIntegration" : true, "config" : "../libvirt-config/console2-dbus.xml", "networkConfig" : "../libvirt-config/network2.xml", "networkFilterConfig" : "../libvirt-config/network2-filter.xml", diff --git a/tests/unit_tests/client/configs/ut-client/containers/console3-dbus.conf b/tests/unit_tests/client/configs/ut-client/containers/console3-dbus.conf index 14a8a60..09ef262 100644 --- a/tests/unit_tests/client/configs/ut-client/containers/console3-dbus.conf +++ b/tests/unit_tests/client/configs/ut-client/containers/console3-dbus.conf @@ -1,6 +1,7 @@ { "privilege" : 20, "switchToDefaultAfterTimeout" : true, + "enableDbusIntegration" : true, "config" : "../libvirt-config/console3-dbus.xml", "networkConfig" : "../libvirt-config/network3.xml", "networkFilterConfig" : "../libvirt-config/network3-filter.xml", diff --git a/tests/unit_tests/server/configs/ut-container-admin/containers/buggy.conf.in b/tests/unit_tests/server/configs/ut-container-admin/containers/buggy.conf.in index 9ebef78..6a0ba2d 100644 --- a/tests/unit_tests/server/configs/ut-container-admin/containers/buggy.conf.in +++ b/tests/unit_tests/server/configs/ut-container-admin/containers/buggy.conf.in @@ -1,6 +1,7 @@ { "privilege" : 10, "switchToDefaultAfterTimeout" : true, + "enableDbusIntegration" : false, "config" : "@SC_TEST_CONFIG_INSTALL_DIR@/server/ut-container-admin/libvirt-config/buggy.xml", "networkConfig" : "", "networkFilterConfig" : "", diff --git a/tests/unit_tests/server/configs/ut-container-admin/containers/missing.conf b/tests/unit_tests/server/configs/ut-container-admin/containers/missing.conf index 1943228..4184401 100644 --- a/tests/unit_tests/server/configs/ut-container-admin/containers/missing.conf +++ b/tests/unit_tests/server/configs/ut-container-admin/containers/missing.conf @@ -1,6 +1,7 @@ { "privilege" : 10, "switchToDefaultAfterTimeout" : true, + "enableDbusIntegration" : false, "config" : "/this/is/a/missing/file/path/missing.xml", "networkConfig" : "", "networkFilterConfig" : "", diff --git a/tests/unit_tests/server/configs/ut-container-admin/containers/test-no-shutdown.conf.in b/tests/unit_tests/server/configs/ut-container-admin/containers/test-no-shutdown.conf.in index 2360ac6..995f5ff 100644 --- a/tests/unit_tests/server/configs/ut-container-admin/containers/test-no-shutdown.conf.in +++ b/tests/unit_tests/server/configs/ut-container-admin/containers/test-no-shutdown.conf.in @@ -1,6 +1,7 @@ { "privilege" : 10, "switchToDefaultAfterTimeout" : true, + "enableDbusIntegration" : false, "config" : "@SC_TEST_CONFIG_INSTALL_DIR@/server/ut-container-admin/libvirt-config/test-no-shutdown.xml", "networkConfig" : "", "networkFilterConfig" : "", diff --git a/tests/unit_tests/server/configs/ut-container-admin/containers/test.conf.in b/tests/unit_tests/server/configs/ut-container-admin/containers/test.conf.in index 52da12a..a1d3d53 100644 --- a/tests/unit_tests/server/configs/ut-container-admin/containers/test.conf.in +++ b/tests/unit_tests/server/configs/ut-container-admin/containers/test.conf.in @@ -1,6 +1,7 @@ { "privilege" : 10, "switchToDefaultAfterTimeout" : true, + "enableDbusIntegration" : false, "config" : "@SC_TEST_CONFIG_INSTALL_DIR@/server/ut-container-admin/libvirt-config/test.xml", "networkConfig" : "", "networkFilterConfig" : "", diff --git a/tests/unit_tests/server/configs/ut-container/containers/buggy.conf b/tests/unit_tests/server/configs/ut-container/containers/buggy.conf index 5f59a89..5992433 100644 --- a/tests/unit_tests/server/configs/ut-container/containers/buggy.conf +++ b/tests/unit_tests/server/configs/ut-container/containers/buggy.conf @@ -1,6 +1,7 @@ { "privilege" : 10, "switchToDefaultAfterTimeout" : true, + "enableDbusIntegration" : false, "config" : "/missing/file/path/libvirt.xml", "networkConfig" : "../libvirt-config/network.xml", "networkFilterConfig" : "../libvirt-config/network-filter.xml", diff --git a/tests/unit_tests/server/configs/ut-container/containers/test-dbus.conf b/tests/unit_tests/server/configs/ut-container/containers/test-dbus.conf index f646f80..6301a5a 100644 --- a/tests/unit_tests/server/configs/ut-container/containers/test-dbus.conf +++ b/tests/unit_tests/server/configs/ut-container/containers/test-dbus.conf @@ -1,6 +1,7 @@ { "privilege" : 10, "switchToDefaultAfterTimeout" : true, + "enableDbusIntegration" : true, "config" : "../libvirt-config/test-dbus.xml", "networkConfig" : "../libvirt-config/network.xml", "networkFilterConfig" : "../libvirt-config/network-filter.xml", diff --git a/tests/unit_tests/server/configs/ut-container/containers/test.conf b/tests/unit_tests/server/configs/ut-container/containers/test.conf index cfd08c4..111d9ee 100644 --- a/tests/unit_tests/server/configs/ut-container/containers/test.conf +++ b/tests/unit_tests/server/configs/ut-container/containers/test.conf @@ -1,6 +1,7 @@ { "privilege" : 10, "switchToDefaultAfterTimeout" : true, + "enableDbusIntegration" : false, "config" : "../libvirt-config/test.xml", "networkConfig" : "../libvirt-config/network.xml", "networkFilterConfig" : "../libvirt-config/network-filter.xml", diff --git a/tests/unit_tests/server/configs/ut-containers-manager/containers/console1-dbus.conf b/tests/unit_tests/server/configs/ut-containers-manager/containers/console1-dbus.conf index af3380b..e16f7d6 100644 --- a/tests/unit_tests/server/configs/ut-containers-manager/containers/console1-dbus.conf +++ b/tests/unit_tests/server/configs/ut-containers-manager/containers/console1-dbus.conf @@ -1,6 +1,7 @@ { "privilege" : 20, "switchToDefaultAfterTimeout" : true, + "enableDbusIntegration" : true, "config" : "../libvirt-config/console1-dbus.xml", "networkConfig" : "../libvirt-config/network1.xml", "networkFilterConfig" : "../libvirt-config/network1-filter.xml", diff --git a/tests/unit_tests/server/configs/ut-containers-manager/containers/console1.conf b/tests/unit_tests/server/configs/ut-containers-manager/containers/console1.conf index e7bcf3f..be47df6 100644 --- a/tests/unit_tests/server/configs/ut-containers-manager/containers/console1.conf +++ b/tests/unit_tests/server/configs/ut-containers-manager/containers/console1.conf @@ -1,6 +1,7 @@ { "privilege" : 20, "switchToDefaultAfterTimeout" : true, + "enableDbusIntegration" : false, "config" : "../libvirt-config/console1.xml", "networkConfig" : "../libvirt-config/network1.xml", "networkFilterConfig" : "../libvirt-config/network1-filter.xml", diff --git a/tests/unit_tests/server/configs/ut-containers-manager/containers/console2-dbus.conf b/tests/unit_tests/server/configs/ut-containers-manager/containers/console2-dbus.conf index 0db0a8a..9aa8e51 100644 --- a/tests/unit_tests/server/configs/ut-containers-manager/containers/console2-dbus.conf +++ b/tests/unit_tests/server/configs/ut-containers-manager/containers/console2-dbus.conf @@ -1,6 +1,7 @@ { "privilege" : 20, "switchToDefaultAfterTimeout" : false, + "enableDbusIntegration" : true, "config" : "../libvirt-config/console2-dbus.xml", "networkConfig" : "../libvirt-config/network2.xml", "networkFilterConfig" : "../libvirt-config/network2-filter.xml", diff --git a/tests/unit_tests/server/configs/ut-containers-manager/containers/console2.conf b/tests/unit_tests/server/configs/ut-containers-manager/containers/console2.conf index 9e0b7c5..4c88170 100644 --- a/tests/unit_tests/server/configs/ut-containers-manager/containers/console2.conf +++ b/tests/unit_tests/server/configs/ut-containers-manager/containers/console2.conf @@ -1,6 +1,7 @@ { "privilege" : 10, "switchToDefaultAfterTimeout" : true, + "enableDbusIntegration" : false, "config" : "../libvirt-config/console2.xml", "networkConfig" : "../libvirt-config/network2.xml", "networkFilterConfig" : "../libvirt-config/network2-filter.xml", diff --git a/tests/unit_tests/server/configs/ut-containers-manager/containers/console3-dbus.conf b/tests/unit_tests/server/configs/ut-containers-manager/containers/console3-dbus.conf index 14a8a60..09ef262 100644 --- a/tests/unit_tests/server/configs/ut-containers-manager/containers/console3-dbus.conf +++ b/tests/unit_tests/server/configs/ut-containers-manager/containers/console3-dbus.conf @@ -1,6 +1,7 @@ { "privilege" : 20, "switchToDefaultAfterTimeout" : true, + "enableDbusIntegration" : true, "config" : "../libvirt-config/console3-dbus.xml", "networkConfig" : "../libvirt-config/network3.xml", "networkFilterConfig" : "../libvirt-config/network3-filter.xml", diff --git a/tests/unit_tests/server/configs/ut-containers-manager/containers/console3.conf b/tests/unit_tests/server/configs/ut-containers-manager/containers/console3.conf index 6ace25e..d6bc429 100644 --- a/tests/unit_tests/server/configs/ut-containers-manager/containers/console3.conf +++ b/tests/unit_tests/server/configs/ut-containers-manager/containers/console3.conf @@ -1,6 +1,7 @@ { "privilege" : 15, "switchToDefaultAfterTimeout" : true, + "enableDbusIntegration" : false, "config" : "../libvirt-config/console3.xml", "networkConfig" : "../libvirt-config/network3.xml", "networkFilterConfig" : "../libvirt-config/network3-filter.xml", diff --git a/tests/unit_tests/server/configs/ut-network-admin/containers/buggy.conf.in b/tests/unit_tests/server/configs/ut-network-admin/containers/buggy.conf.in index 48d0ef8..414b920 100644 --- a/tests/unit_tests/server/configs/ut-network-admin/containers/buggy.conf.in +++ b/tests/unit_tests/server/configs/ut-network-admin/containers/buggy.conf.in @@ -1,6 +1,7 @@ { "privilege" : 10, "switchToDefaultAfterTimeout" : true, + "enableDbusIntegration" : false, "config" : "", "networkConfig" : "@SC_TEST_CONFIG_INSTALL_DIR@/server/ut-network-admin/libvirt-config/buggy-network.xml", "networkFilterConfig" : "@SC_TEST_CONFIG_INSTALL_DIR@/server/ut-network-admin/libvirt-config/buggy-network-filter.xml", diff --git a/tests/unit_tests/server/configs/ut-network-admin/containers/missing.conf b/tests/unit_tests/server/configs/ut-network-admin/containers/missing.conf index b60814d..13ccc44 100644 --- a/tests/unit_tests/server/configs/ut-network-admin/containers/missing.conf +++ b/tests/unit_tests/server/configs/ut-network-admin/containers/missing.conf @@ -1,6 +1,7 @@ { "privilege" : 10, "switchToDefaultAfterTimeout" : true, + "enableDbusIntegration" : false, "config" : "", "networkConfig" : "", "networkFilterConfig" : "", diff --git a/tests/unit_tests/server/configs/ut-network-admin/containers/test.conf.in b/tests/unit_tests/server/configs/ut-network-admin/containers/test.conf.in index 1dce4ea..be65ee2 100644 --- a/tests/unit_tests/server/configs/ut-network-admin/containers/test.conf.in +++ b/tests/unit_tests/server/configs/ut-network-admin/containers/test.conf.in @@ -1,6 +1,7 @@ { "privilege" : 10, "switchToDefaultAfterTimeout" : true, + "enableDbusIntegration" : false, "config" : "", "networkConfig" : "@SC_TEST_CONFIG_INSTALL_DIR@/server/ut-network-admin/libvirt-config/network.xml", "networkFilterConfig" : "@SC_TEST_CONFIG_INSTALL_DIR@/server/ut-network-admin/libvirt-config/network-filter.xml", diff --git a/tests/unit_tests/server/configs/ut-server/containers/container1.conf b/tests/unit_tests/server/configs/ut-server/containers/container1.conf index b0f523f..21fb52a 100644 --- a/tests/unit_tests/server/configs/ut-server/containers/container1.conf +++ b/tests/unit_tests/server/configs/ut-server/containers/container1.conf @@ -1,6 +1,7 @@ { "privilege" : 20, "switchToDefaultAfterTimeout" : true, + "enableDbusIntegration" : false, "config" : "../libvirt-config/container1.xml", "networkConfig" : "../libvirt-config/network1.xml", "networkFilterConfig" : "../libvirt-config/network1-filter.xml", diff --git a/tests/unit_tests/server/configs/ut-server/containers/container2.conf b/tests/unit_tests/server/configs/ut-server/containers/container2.conf index 8a1fde1..6302a39 100644 --- a/tests/unit_tests/server/configs/ut-server/containers/container2.conf +++ b/tests/unit_tests/server/configs/ut-server/containers/container2.conf @@ -1,6 +1,7 @@ { "privilege" : 10, "switchToDefaultAfterTimeout" : true, + "enableDbusIntegration" : false, "config" : "../libvirt-config/container2.xml", "networkConfig" : "../libvirt-config/network2.xml", "networkFilterConfig" : "../libvirt-config/network2-filter.xml", diff --git a/tests/unit_tests/server/configs/ut-server/containers/container3.conf b/tests/unit_tests/server/configs/ut-server/containers/container3.conf index be23c63..b445156 100644 --- a/tests/unit_tests/server/configs/ut-server/containers/container3.conf +++ b/tests/unit_tests/server/configs/ut-server/containers/container3.conf @@ -1,6 +1,7 @@ { "privilege" : 15, "switchToDefaultAfterTimeout" : true, + "enableDbusIntegration" : false, "config" : "../libvirt-config/container3.xml", "networkConfig" : "../libvirt-config/network3.xml", "networkFilterConfig" : "../libvirt-config/network3-filter.xml", diff --git a/tests/unit_tests/server/ut-containers-manager.cpp b/tests/unit_tests/server/ut-containers-manager.cpp index e578a35..54a34bb 100644 --- a/tests/unit_tests/server/ut-containers-manager.cpp +++ b/tests/unit_tests/server/ut-containers-manager.cpp @@ -732,6 +732,11 @@ BOOST_AUTO_TEST_CASE(ProxyCallTest) } namespace { + const DbusAccessory::Dbuses EXPECTED_DBUSES_NO_DBUS = { + {"ut-containers-manager-console1", ""}, + {"ut-containers-manager-console2", ""}, + {"ut-containers-manager-console3", ""}}; + const DbusAccessory::Dbuses EXPECTED_DBUSES_STOPPED = { {"ut-containers-manager-console1-dbus", ""}, {"ut-containers-manager-console2-dbus", ""}, @@ -749,20 +754,26 @@ namespace { BOOST_AUTO_TEST_CASE(GetContainerDbusesTest) { DbusAccessory host(DbusAccessory::HOST_ID); - ContainersManager cm(TEST_DBUS_CONFIG_PATH); BOOST_CHECK(EXPECTED_DBUSES_STOPPED == host.callMethodGetContainerDbuses()); - cm.startAll(); - BOOST_CHECK(EXPECTED_DBUSES_STARTED == host.callMethodGetContainerDbuses()); - cm.stopAll(); - BOOST_CHECK(EXPECTED_DBUSES_STOPPED == host.callMethodGetContainerDbuses()); } +BOOST_AUTO_TEST_CASE(GetContainerDbusesNoDbusTest) +{ + DbusAccessory host(DbusAccessory::HOST_ID); + ContainersManager cm(TEST_CONFIG_PATH); + BOOST_CHECK(EXPECTED_DBUSES_NO_DBUS == host.callMethodGetContainerDbuses()); + cm.startAll(); + BOOST_CHECK(EXPECTED_DBUSES_NO_DBUS == host.callMethodGetContainerDbuses()); + cm.stopAll(); + BOOST_CHECK(EXPECTED_DBUSES_NO_DBUS == host.callMethodGetContainerDbuses()); +} + BOOST_AUTO_TEST_CASE(ContainerDbusesSignalsTest) { Latch signalLatch; -- 2.7.4 From 7f14f774e7ab99d3823b4a7739528ca96454f668 Mon Sep 17 00:00:00 2001 From: Michal Witanowski Date: Tue, 26 Aug 2014 16:55:35 +0200 Subject: [PATCH 11/16] Improve doxygen comments in client header [Bug/Feature] N/A [Cause] N/A [Solution] * more details added * example code provided. [Verification] Run generate_documentation.sh script, verify output. Non-comment parts hasn't been affected. Change-Id: I506913c3047f64f64f1ff2e84c92cff9fda8b43f --- client/security-containers-client.h | 156 +++++++++++++++++++++++++++--------- 1 file changed, 116 insertions(+), 40 deletions(-) diff --git a/client/security-containers-client.h b/client/security-containers-client.h index 1632497..c56e9de 100644 --- a/client/security-containers-client.h +++ b/client/security-containers-client.h @@ -21,6 +21,58 @@ * @file * @author Mateusz Malicki (m.malicki2@samsung.com) * @brief This file contains the public API for Security Containers Client + * + * @par Example usage: + * @code +#include +#include "client/security-containers-client.h" + +int main(int argc, char** argv) +{ + ScStatus status; + ScClient client; + ScArrayString values = NULL; + int ret = 0; + + status = sc_start_glib_loop(); // start glib loop (if not started any yet) + if (SCCLIENT_SUCCESS != status) { + // error! + return 1; + } + + client = sc_client_create(); // create client handle + if (NULL == client) { + // error! + ret = 1; + goto finish; + } + + status = sc_connect(client); // connect to dbus + if (SCCLIENT_SUCCESS != status) { + // error! + ret = 1; + goto finish; + } + + status = sc_get_container_ids(client, &values); + if (SCCLIENT_SUCCESS != status) { + // error! + ret = 1; + goto finish; + } + + // print array + for (ScArrayString iValues = values; *iValues; iValues++) { + printf("%s\n", *iValues); + } + +finish: + sc_array_string_free(values); // free memory + sc_client_free(client); // destroy client handle + sc_stop_glib_loop(); // stop the glib loop (use only with sc_start_glib_loop) + return ret; +} + @endcode */ #ifndef SECURITY_CONTAINERS_CLIENT_H @@ -32,21 +84,21 @@ extern "C" #endif /** - * security-containers-server's client + * security-containers-server's client pointer. */ typedef void* ScClient; /** - * String type. + * NULL-terminated string type. * - * NULL-terminated string. + * @sa sc_array_string_free */ typedef char* ScString; /** - * Array of strings type. + * NULL-terminated array of strings type. * - * Array are NULL-terminated. + * @sa sc_string_free */ typedef ScString* ScArrayString; @@ -65,8 +117,8 @@ typedef enum { /** * Start glib loop. * - * Do not call this function if the application creates glib loop itself. - * Otherwise call it before any other function from this library. + * Do not call this function if an application creates a glib loop itself. + * Otherwise, call it before any other function from this library. * * @return status of this function call */ @@ -75,6 +127,8 @@ ScStatus sc_start_glib_loop(); /** * Stop glib loop. * + * Call only if sc_start_glib_loop() was called. + * * @return status of this function call */ ScStatus sc_stop_glib_loop(); @@ -82,21 +136,21 @@ ScStatus sc_stop_glib_loop(); /** * Create a new security-containers-server's client. * - * @return created client + * @return Created client pointer or NULL on failure. */ ScClient sc_client_create(); /** * Release client resources. * - * @param client security-containers-server's client + * @param[in] client security-containers-server's client */ void sc_client_free(ScClient client); /** * Get status code of last security-containers-server communication. * - * @param client security-containers-server's client + * @param[in] client security-containers-server's client * @return status of this function call */ ScStatus sc_get_status(ScClient client); @@ -104,7 +158,7 @@ ScStatus sc_get_status(ScClient client); /** * Get status message of the last security-containers-server communication. * - * @param client security-containers-server's client + * @param[in] client security-containers-server's client * @return last status message from security-containers-server communication */ const char* sc_get_status_message(ScClient client); @@ -112,7 +166,7 @@ const char* sc_get_status_message(ScClient client); /** * Connect client to the security-containers-server. * - * @param client security-containers-server's client + * @param[in] client security-containers-server's client * @return status of this function call */ ScStatus sc_connect(ScClient client); @@ -120,8 +174,8 @@ ScStatus sc_connect(ScClient client); /** * Connect client to the security-containers-server via custom address. * - * @param client security-containers-server's client - * @param address dbus address + * @param[in] client security-containers-server's client + * @param[in] address dbus address * @return status of this function call */ ScStatus sc_connect_custom(ScClient client, const char* address); @@ -129,7 +183,7 @@ ScStatus sc_connect_custom(ScClient client, const char* address); /** * Release ScArrayString. * - * @param astring ScArrayString + * @param[in] astring ScArrayString */ void sc_array_string_free(ScArrayString astring); @@ -141,14 +195,20 @@ void sc_array_string_free(ScArrayString astring); void sc_string_free(ScString string); -/************************************************************************************************* +/** + * @name Host API * - * org.tizen.containers.host.manager interface + * Functions using org.tizen.containers.host.manager D-Bus interface. * - ************************************************************************************************/ + * @{ + */ /** - * Dbus state change callback function signature. + * Container's D-Bus state change callback function signature. + * + * @param[in] containerId affected container id + * @param[in] dbusAddress new D-Bus address + * @param data custom user's data pointer passed to sc_container_dbus_state() function */ typedef void (*ScContainerDbusStateCallback)(const char* containerId, const char* dbusAddress, @@ -162,6 +222,7 @@ typedef void (*ScContainerDbusStateCallback)(const char* containerId, * @param[out] values array of containers dbus address * @return status of this function call * @post keys[i] corresponds to values[i] + * @remark Use sc_array_string_free() to free memory occupied by @p keys and @p values. */ ScStatus sc_get_container_dbuses(ScClient client, ScArrayString* keys, ScArrayString* values); @@ -171,23 +232,25 @@ ScStatus sc_get_container_dbuses(ScClient client, ScArrayString* keys, ScArraySt * @param[in] client security-containers-server's client * @param[out] array array of containers name * @return status of this function call + * @remark Use sc_array_string_free() to free memory occupied by @p array. */ ScStatus sc_get_container_ids(ScClient client, ScArrayString* array); /** - * Get active container name. + * Get active (foreground) container name. * * @param[in] client security-containers-server's client * @param[out] id active container name * @return status of this function call + * @remark Use @p sc_string_free() to free memory occupied by @p id. */ ScStatus sc_get_active_container_id(ScClient client, ScString* id); /** - * Set active container. + * Set active (foreground) container. * - * @param client security-containers-server's client - * @param id container name + * @param[in] client security-containers-server's client + * @param[in] id container name * @return status of this function call */ ScStatus sc_set_active_container(ScClient client, const char* id); @@ -195,26 +258,35 @@ ScStatus sc_set_active_container(ScClient client, const char* id); /** * Register dbus state change callback function. * - * The callback function will be invoked on a different thread + * @note The callback function will be invoked on a different thread. * - * @param client security-containers-server's client - * @param containerDbusStateCallback callback function - * @param data some extra data that will be passed to callback function + * @param[in] client security-containers-server's client + * @param[in] containerDbusStateCallback callback function + * @param[in] data some extra data that will be passed to callback function * @return status of this function call */ ScStatus sc_container_dbus_state(ScClient client, ScContainerDbusStateCallback containerDbusStateCallback, void* data); +/** @} */ // Host API + -/************************************************************************************************* +/** + * @name Domain API * - * org.tizen.containers.domain.manager interface + * Functions using org.tizen.containers.domain.manager D-Bus interface. * - ************************************************************************************************/ + * @{ + */ /** * Notification callback function signature. + * + * @param[in] container source container + * @param[in] application sending application name + * @param[in] message notification message + * @param data custom user's data pointer passed to sc_notification() */ typedef void (*ScNotificationCallback)(const char* container, const char* application, @@ -223,9 +295,9 @@ typedef void (*ScNotificationCallback)(const char* container, /** * Send message to active container. * - * @param client security-containers-server's client - * @param application application name - * @param message message + * @param[in] client security-containers-server's client + * @param[in] application application name + * @param[in] message message * @return status of this function call */ ScStatus sc_notify_active_container(ScClient client, const char* application, const char* message); @@ -233,23 +305,27 @@ ScStatus sc_notify_active_container(ScClient client, const char* application, co /** * Move file between containers. * - * @param client security-containers-server's client - * @param destContainer destination container id - * @param path path to moved file + * @param[in] client security-containers-server's client + * @param[in] destContainer destination container id + * @param[in] path path to moved file + * @return status of this function call */ ScStatus sc_file_move_request(ScClient client, const char* destContainer, const char* path); /** * Register notification callback function. * - * The callback function will be invoked on a different thread. + * @note The callback function will be invoked on a different thread. * - * @param client security-containers-server's client - * @param notificationCallback callback function - * @param data some extra data that will be passed to callback function + * @param[in] client security-containers-server's client + * @param[in] notificationCallback callback function + * @param[in] data some extra data that will be passed to callback function * @return status of this function call */ ScStatus sc_notification(ScClient client, ScNotificationCallback notificationCallback, void* data); + +/** @} */ // Domain API + #ifdef __cplusplus } #endif -- 2.7.4 From 61e1a446576fc294a9d7f01b197afbcae91540a9 Mon Sep 17 00:00:00 2001 From: Piotr Bartosiewicz Date: Wed, 10 Sep 2014 13:35:50 +0200 Subject: [PATCH 12/16] Unit test cleanup [Bug/Feature] Update unit test of configuration to test changes in libConfig (added missing piece of code). [Cause] N/A [Solution] N/A [Verification] Build, install, run tests Change-Id: Ifab57f3537cfcc4afa046608bd337b5386099b6e --- tests/unit_tests/config/ut-configuration.cpp | 69 +++------------------------- 1 file changed, 6 insertions(+), 63 deletions(-) diff --git a/tests/unit_tests/config/ut-configuration.cpp b/tests/unit_tests/config/ut-configuration.cpp index 6220a58..1e98d22 100644 --- a/tests/unit_tests/config/ut-configuration.cpp +++ b/tests/unit_tests/config/ut-configuration.cpp @@ -285,76 +285,19 @@ BOOST_AUTO_TEST_CASE(HasVisibleInternalHelperTest) BOOST_CHECK(isVisitable()); } -namespace saveLoadKVStoreTest { - -// This struct is like TestConfig, but without a list of structures. -struct PoorTestConfig { - // subtree class - struct SubConfig { - - struct SubSubConfig { - int intVal; - - CONFIG_REGISTER - ( - intVal - ) - }; - - int intVal; - SubSubConfig subSubObj; - - CONFIG_REGISTER - ( - intVal, - subSubObj - ) - }; - - int intVal; - std::int64_t int64Val; - std::string stringVal; - double doubleVal; - bool boolVal; - - std::vector intVector; - std::vector stringVector; - std::vector doubleVector; - - SubConfig subObj; - - CONFIG_REGISTER - ( - intVal, - int64Val, - stringVal, - doubleVal, - boolVal, - - intVector, - stringVector, - doubleVector, - - subObj - ) -}; -} // saveLoadKVStoreTest - - BOOST_AUTO_TEST_CASE(FromToKVStoreTest) { - using namespace saveLoadKVStoreTest; - - // TODO: Change this to TestConfig and delete PoorTestConfig when serialization is implemented - PoorTestConfig config; + TestConfig config; loadFromString(jsonTestString, config); std::string dbPath = fs::unique_path("/tmp/kvstore-%%%%.db3").string(); saveToKVStore(dbPath, config); - loadFromKVStore(dbPath, config); - saveToKVStore(dbPath, config, "some_config"); - loadFromKVStore(dbPath, config, "some_config"); + TestConfig outConfig; + loadFromKVStore(dbPath, outConfig); + + std::string out = saveToString(outConfig); + BOOST_CHECK_EQUAL(out, jsonTestString); fs::remove(dbPath); } -- 2.7.4 From e1302ae96a14947703e37029398bdb059b4f209f Mon Sep 17 00:00:00 2001 From: Lukasz Kostyra Date: Tue, 5 Aug 2014 13:49:56 +0200 Subject: [PATCH 13/16] Add API to create new containers [Feature] Dbus method to add new containers [Cause] Need of dynamic management of containers [Solution] Added dbus API to add new containers. Added new functions to utils needed during dynamic container creation. [Verification] Build, install, run unit tests. Change-Id: I2044c416947dccc3e0e90302f6b56ea49db0baa1 --- CMakeLists.txt | 4 + common/utils/fs.cpp | 89 ++++++++ common/utils/fs.hpp | 12 ++ common/utils/img.cpp | 240 +++++++++++++++++++++ common/utils/img.hpp | 55 +++++ common/utils/paths.hpp | 12 ++ packaging/security-containers.spec | 8 +- server/configs/CMakeLists.txt | 5 +- server/configs/daemon.conf | 3 + .../configs/systemd/security-containers.service.in | 1 + server/configs/templates/template-network.xml | 12 ++ server/configs/templates/template-nwfilter.xml | 9 + server/configs/templates/template.conf | 13 ++ server/configs/templates/template.xml | 123 +++++++++++ server/container-admin.cpp | 4 + server/container.cpp | 28 +++ server/container.hpp | 10 + server/containers-manager-config.hpp | 19 ++ server/containers-manager.cpp | 236 +++++++++++++++++--- server/containers-manager.hpp | 15 +- server/host-connection.cpp | 14 ++ server/host-connection.hpp | 9 + server/host-dbus-definitions.hpp | 5 + server/server.cpp | 18 +- .../client/configs/ut-client/test-dbus-daemon.conf | 3 + tests/unit_tests/server/configs/CMakeLists.txt | 9 + .../ut-containers-manager/buggy-daemon.conf | 3 + .../buggy-default-daemon.conf | 3 + .../buggy-foreground-daemon.conf | 3 + .../templates/template-network.xml | 4 + .../templates/template-nwfilter.xml | 3 + .../ut-containers-manager/templates/template.conf | 13 ++ .../templates/template.xml.in | 15 ++ .../configs/ut-containers-manager/test-daemon.conf | 3 + .../ut-containers-manager/test-dbus-daemon.conf | 3 + .../server/configs/ut-server/buggy-daemon.conf | 3 + .../server/configs/ut-server/test-daemon.conf | 3 + tests/unit_tests/server/ut-containers-manager.cpp | 74 +++++++ tests/unit_tests/utils/ut-fs.cpp | 51 +++++ 39 files changed, 1099 insertions(+), 38 deletions(-) create mode 100644 common/utils/img.cpp create mode 100644 common/utils/img.hpp create mode 100644 server/configs/templates/template-network.xml create mode 100644 server/configs/templates/template-nwfilter.xml create mode 100644 server/configs/templates/template.conf create mode 100644 server/configs/templates/template.xml create mode 100644 tests/unit_tests/server/configs/ut-containers-manager/templates/template-network.xml create mode 100644 tests/unit_tests/server/configs/ut-containers-manager/templates/template-nwfilter.xml create mode 100644 tests/unit_tests/server/configs/ut-containers-manager/templates/template.conf create mode 100644 tests/unit_tests/server/configs/ut-containers-manager/templates/template.xml.in diff --git a/CMakeLists.txt b/CMakeLists.txt index 266773a..9cb880a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -69,10 +69,14 @@ ENDIF(NOT DEFINED LIBVIRT_GROUP) IF(NOT DEFINED INPUT_EVENT_GROUP) SET(INPUT_EVENT_GROUP "input") ENDIF(NOT DEFINED INPUT_EVENT_GROUP) +IF(NOT DEFINED DISK_GROUP) + SET(DISK_GROUP "disk") +ENDIF(NOT DEFINED DISK_GROUP) ADD_DEFINITIONS(-DSECURITY_CONTAINERS_USER="${SECURITY_CONTAINERS_USER}") ADD_DEFINITIONS(-DLIBVIRT_GROUP="${LIBVIRT_GROUP}") ADD_DEFINITIONS(-DINPUT_EVENT_GROUP="${INPUT_EVENT_GROUP}") +ADD_DEFINITIONS(-DDISK_GROUP="${DISK_GROUP}") ## Python packages directory ################################################### diff --git a/common/utils/fs.cpp b/common/utils/fs.cpp index d663831..a03c139 100644 --- a/common/utils/fs.cpp +++ b/common/utils/fs.cpp @@ -39,6 +39,8 @@ #include #include +#include + namespace security_containers { namespace utils { @@ -199,6 +201,63 @@ bool moveFile(const std::string& src, const std::string& dst) return true; } +namespace { + +bool copyDirContentsRec(const boost::filesystem::path& src, const boost::filesystem::path& dst) +{ + namespace fs = boost::filesystem; + + // TODO: Right now this function skips files which produce error when copying. Errors show up + // when: + // a) fs::directory_iterator file(src) is created + // b) fs::copy(...) is called + // In both cases lack of permissions is the issue. + // + // In a) case we can't do much - SCS won't be able to read the directory and its contents. Such + // directories are not common in the filesystem, so they *probably* can be skipped. + // + // In b) case multiple directories have too strict permissions to be directly copied. This + // is a problem for some files crucial to container launch (ex. we cannot copy + // /usr/lib/systemd/systemd because /usr/lib has 555 permissions). + // To fix b) issue, copying must be done in two steps: + // 1. Copy file contents without permissions (this probably can be achieved by opening two + // files in-code with fstream and programatically copying data from one file to another). + // 2. Apply all available file attributes from source (permissions, owner UID/GID, xattrs...) + + try { + for (fs::directory_iterator file(src); + file != fs::directory_iterator(); + ++file) { + fs::path current(file->path()); + + boost::system::error_code ec; + fs::copy(current, dst / current.filename(), ec); + if(ec.value() != boost::system::errc::success) { + LOGW("Failed to copy " << current << ": " << ec.message()); + } + + if (!fs::is_symlink(current) && fs::is_directory(current)) { + if (!copyDirContentsRec(current, dst / current.filename())) { + return false; + } + } + } + } catch (fs::filesystem_error& e) { + LOGW(e.what()); + } + + return true; +} + +} // namespace + +bool copyDirContents(const std::string& src, const std::string& dst) +{ + namespace fs = boost::filesystem; + + return copyDirContentsRec(fs::path(src), fs::path(dst)); +} + bool createDir(const std::string& path, uid_t uid, uid_t gid, boost::filesystem::perms mode) { namespace fs = boost::filesystem; @@ -239,5 +298,35 @@ bool createDir(const std::string& path, uid_t uid, uid_t gid, boost::filesystem: return true; } +bool createEmptyDir(const std::string& path) +{ + namespace fs = boost::filesystem; + + fs::path dirPath(path); + boost::system::error_code ec; + bool cleanDirCreated = false; + + if (!fs::exists(dirPath)) { + if (!fs::create_directory(dirPath, ec)) { + LOGE("Failed to create dir. Error: " << ec.message()); + return false; + } + cleanDirCreated = true; + } else if (!fs::is_directory(dirPath)) { + LOGE("Provided path already exists and is not a dir, cannot create."); + return false; + } + + if (!cleanDirCreated) { + // check if directory is empty if it was already created + if (!fs::is_empty(dirPath)) { + LOGE("Directory has some data inside, cannot be used."); + return false; + } + } + + return true; +} + } // namespace utils } // namespace security_containers diff --git a/common/utils/fs.hpp b/common/utils/fs.hpp index 9cff7a9..0e2f00e 100644 --- a/common/utils/fs.hpp +++ b/common/utils/fs.hpp @@ -87,10 +87,22 @@ bool hasSameMountPoint(const std::string& path1, const std::string& path2, bool& bool moveFile(const std::string& src, const std::string& dst); /** + * Recursively copy contents of src dir to dst dir. + */ +bool copyDirContents(const std::string& src, const std::string& dst); + +/** * Creates a directory with specific UID, GID and permissions set. */ bool createDir(const std::string& path, uid_t uid, uid_t gid, boost::filesystem::perms mode); +/** + * Creates an empty directory, ready to serve as mount point. + * Succeeds either if path did not exist and was created successfully, or if already existing dir + * under the same path is empty and is not a mount point. + */ +bool createEmptyDir(const std::string& path); + } // namespace utils } // namespace security_containers diff --git a/common/utils/img.cpp b/common/utils/img.cpp new file mode 100644 index 0000000..4d7de88 --- /dev/null +++ b/common/utils/img.cpp @@ -0,0 +1,240 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Contact: Lukasz Kostyra + * + * Licensed 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 + */ + +/** + * @file img.hpp + * @author Lukasz Kostyra (l.kostyra@samsung.com) + * @brief Image utility functions declaration + */ + +#include "config.hpp" +#include "logger/logger.hpp" +#include "utils/img.hpp" +#include "utils/fs.hpp" +#include "utils/paths.hpp" + +#include +#include +#include + +namespace security_containers { +namespace utils { + +namespace { + +const std::string LOOP_DEV_PREFIX = "/dev/loop"; +const std::string LOOP_MOUNT_POINT_OPTIONS = ""; +const std::string LOOP_MOUNT_POINT_TYPE = "ext4"; +const unsigned long LOOP_MOUNT_POINT_FLAGS = MS_RDONLY; + +// Writes to ret if loop device (provided in loopdev arg) is free to use. +// Returns true if check was successful, false if loop device FD was unavailable for some reason. +bool isLoopDevFree(const std::string& loopdev, bool& ret) +{ + // initialize + ret = false; + + // open loop device FD + int loopFD = ::open(loopdev.c_str(), O_RDWR); + if (loopFD < 0) { + LOGD("Failed to open loop device descriptor: " << ::strerror(errno)); + return false; + } + + // if ioctl with LOOP_GET_STATUS fails, device is not assigned and free to use + struct loop_info linfo; + if (::ioctl(loopFD, LOOP_GET_STATUS, &linfo)) { + ret = true; + } + + ::close(loopFD); + return true; +} + +bool mountLoop(const std::string& img, + const std::string& loopdev, + const std::string& path, + const std::string& type, + unsigned long flags, + const std::string& options) +{ + // to mount an image, we need to connect image FD with loop device FD + // get image file FD + int fileFD = ::open(img.c_str(), O_RDWR); + if (fileFD < 0) { + LOGD("Failed to open image file descriptor: " << ::strerror(errno)); + return false; + } + + // get loop device FD + int loopFD = ::open(loopdev.c_str(), O_RDWR); + if (loopFD < 0) { + LOGD("Failed to open loop device descriptor: " << ::strerror(errno)); + ::close(fileFD); + return false; + } + + // set loop device + if (::ioctl(loopFD, LOOP_SET_FD, fileFD)) { + LOGD("Failed to assign loop device to image: " << ::strerror(errno)); + ::close(fileFD); + ::close(loopFD); + return false; + } + + // mount loop device to path + if (::mount(loopdev.c_str(), path.c_str(), type.c_str(), flags, options.c_str()) != 0) { + LOGD("Mount failed for '" << path << "', options=" << options << ": " << strerror(errno)); + ::ioctl(loopFD, LOOP_CLR_FD, 0); + ::close(fileFD); + ::close(loopFD); + return false; + } + + ::close(fileFD); + ::close(loopFD); + return true; +} + +} // namespace + +// Finds first available loop device and returns its path through ret. +// Returns false if an error occurs, or if all available loop devices are taken. +bool getFreeLoopDevice(std::string& ret) +{ + for (unsigned int i = 0; i < 8; ++i) { + // build path to loop device + const std::string loopdev = LOOP_DEV_PREFIX + std::to_string(i); + bool isFree = false; + + // check if it is free + if (!isLoopDevFree(loopdev, isFree)) { + LOGD("Failed to check status of " << loopdev); + return false; + } + + // if checked loop device is free, we can exit the function and return it + if (isFree) { + ret = loopdev; + return true; + } + } + + LOGD("All loop devices are taken."); + return false; +} + +bool mountImage(const std::string& image, const std::string& path, const std::string& loopdev) +{ + return mountLoop(image, path, loopdev, + LOOP_MOUNT_POINT_TYPE, + LOOP_MOUNT_POINT_FLAGS, + LOOP_MOUNT_POINT_OPTIONS); +} + +bool umountImage(const std::string& path, const std::string& loopdev) +{ + if (::umount(path.c_str()) != 0) { + LOGD("Umount failed for '" << path << "': " << strerror(errno)); + return false; + } + + // clear loop device + int loopFD = ::open(loopdev.c_str(), O_RDWR); + if (loopFD < 0) { + LOGD("Failed to open fd for loop device 0"); + return false; + } + + if (::ioctl(loopFD, LOOP_CLR_FD, 0) < 0) { + LOGD("Failed to clear loop device."); + close(loopFD); + return false; + } + + close(loopFD); + return true; +} + +bool copyImageContents(const std::string& img, const std::string& dst) +{ + namespace fs = boost::filesystem; + boost::system::error_code ec; + + // make sure that image exists + if (!fs::exists(fs::path(img))) { + LOGE("Image " << img << " does not exist"); + return false; + } + + const std::string mountPoint = createFilePath(dirName(img), "/mp/"); + // create a mount point for copied image + if (!createEmptyDir(mountPoint)) { + LOGE("Cannot create mount point for copied image."); + return false; + } + + // create dst directory + if (!createEmptyDir(dst)) { + LOGE("Cannot create directory for data."); + return false; + } + + // find free loop device for image + std::string loopdev; + if (!utils::getFreeLoopDevice(loopdev)) { + LOGE("Failed to get free loop device."); + return false; + } + + LOGT("Using " << loopdev << " to mount image"); + // mount an image + if (!utils::mountImage(img, loopdev, mountPoint)) { + LOGE("Cannot mount image."); + return false; + } + + // copy data + LOGI("Beginning image copy"); + if (!utils::copyDirContents(mountPoint, dst)) { + LOGE("Failed to copy image."); + utils::umountImage(mountPoint, loopdev); + LOGD("Removing already copied data"); + fs::remove_all(fs::path(dst)); + return false; + } + LOGI("Finished image copy"); + + // umount image + if (!utils::umountImage(mountPoint, loopdev)) { + LOGE("Failed to umount image"); + LOGD("Removing copied data"); + fs::remove_all(fs::path(dst)); + return false; + } + + // remove mount point + if (!fs::remove(fs::path(mountPoint), ec)) { + LOGW("Failed to remove mount point: " << ec.message()); + } + + return true; +} + +} // namespace utils +} // namespace security_containers diff --git a/common/utils/img.hpp b/common/utils/img.hpp new file mode 100644 index 0000000..d42300e --- /dev/null +++ b/common/utils/img.hpp @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Contact: Lukasz Kostyra + * + * Licensed 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 + */ + +/** + * @file img.hpp + * @author Lukasz Kostyra (l.kostyra@samsung.com) + * @brief Image utility functions declaration + */ + +#ifndef COMMON_UTILS_IMG_HPP +#define COMMON_UTILS_IMG_HPP + +namespace security_containers { +namespace utils { + +/** + * Returns string with first free loop device. + */ +bool getFreeLoopDevice(std::string& ret); + +/** + * Mount an ext4 image from file on a given path by using a loop device. + */ +bool mountImage(const std::string& image, const std::string& loopdev, const std::string& path); + +/** + * Umounts previously mounted image. + * This call will also free loop device used to mount specified path. + */ +bool umountImage(const std::string& path, const std::string& loopdev); + +/** + * Mounts an image and copies its contents to dst directory. + */ +bool copyImageContents(const std::string& img, const std::string& dst); + +} // namespace utils +} // namespace security_containers + +#endif // COMMON_UTILS_IMG_HPP diff --git a/common/utils/paths.hpp b/common/utils/paths.hpp index e357c71..14132b4 100644 --- a/common/utils/paths.hpp +++ b/common/utils/paths.hpp @@ -107,6 +107,18 @@ inline std::string dirName(std::string path) return path; } +/* + * Gets absolute path to specified file (if needed) + */ +inline std::string getAbsolutePath(const std::string& path, const std::string& base) +{ + if (path[0] == '/') { + return path; + } else { + return utils::createFilePath(base, "/", path); + } +} + } // namespace utils } // namespace security_containers diff --git a/packaging/security-containers.spec b/packaging/security-containers.spec index 30914b0..97bf4d5 100644 --- a/packaging/security-containers.spec +++ b/packaging/security-containers.spec @@ -5,6 +5,8 @@ # The group that has read and write access to /dev/input/event* devices. # It may vary between platforms. %define input_event_group video +# The group has access to /dev/loop* devices. +%define disk_group disk Name: security-containers Version: 0.1.1 @@ -40,9 +42,12 @@ between them. A process from inside a container can request a switch of context %dir /etc/security-containers %dir /etc/security-containers/containers %dir /etc/security-containers/libvirt-config +%dir /etc/security-containers/templates %config /etc/security-containers/daemon.conf %config /etc/security-containers/containers/*.conf %config /etc/security-containers/libvirt-config/*.xml +%config /etc/security-containers/templates/*.conf +%config /etc/security-containers/templates/*.xml %{_unitdir}/security-containers.service %{_unitdir}/multi-user.target.wants/security-containers.service /etc/dbus-1/system.d/org.tizen.containers.host.conf @@ -65,7 +70,8 @@ between them. A process from inside a container can request a switch of context -DPYTHON_SITELIB=%{python_sitelib} \ -DSECURITY_CONTAINERS_USER=%{scs_user} \ -DLIBVIRT_GROUP=%{libvirt_group} \ - -DINPUT_EVENT_GROUP=%{input_event_group} + -DINPUT_EVENT_GROUP=%{input_event_group} \ + -DDISK_GROUP=%{disk_group} make -k %{?jobs:-j%jobs} %install diff --git a/server/configs/CMakeLists.txt b/server/configs/CMakeLists.txt index def06a2..81859c1 100644 --- a/server/configs/CMakeLists.txt +++ b/server/configs/CMakeLists.txt @@ -21,7 +21,7 @@ MESSAGE(STATUS "Installing configs to " ${SC_CONFIG_INSTALL_DIR}) FILE(GLOB container_CONF containers/*.conf) FILE(GLOB admin_CONF libvirt-config/*.xml) - +FILE(GLOB template_CONF templates/*.conf templates/*.xml) ## Generate #################################################################### CONFIGURE_FILE(systemd/security-containers.service.in @@ -45,5 +45,8 @@ INSTALL(FILES ${container_CONF} INSTALL(FILES ${admin_CONF} DESTINATION ${SC_CONFIG_INSTALL_DIR}/libvirt-config) +INSTALL(FILES ${template_CONF} + DESTINATION ${SC_CONFIG_INSTALL_DIR}/templates) + INSTALL(FILES ${CMAKE_BINARY_DIR}/systemd/security-containers.service DESTINATION ${SYSTEMD_UNIT_DIR}) diff --git a/server/configs/daemon.conf b/server/configs/daemon.conf index 67ef356..db85284 100644 --- a/server/configs/daemon.conf +++ b/server/configs/daemon.conf @@ -1,6 +1,9 @@ { "containerConfigs" : ["containers/private.conf", "containers/business.conf" ], "containersPath" : "/opt/usr/containers", + "containerImagePath" : "/opt/usr/containers/img/system-data.img", + "containerTemplatePath" : "templates", + "containerNewConfigPrefix" : "/var/lib/security-containers", "runMountPointPrefix" : "/var/run/containers", "foregroundId" : "private", "defaultId" : "private", diff --git a/server/configs/systemd/security-containers.service.in b/server/configs/systemd/security-containers.service.in index f06dea3..c271341 100644 --- a/server/configs/systemd/security-containers.service.in +++ b/server/configs/systemd/security-containers.service.in @@ -2,6 +2,7 @@ Description=Security Containers Server After=libvirtd.service Requires=libvirtd.service +ConditionVirtualization=no [Service] Type=simple diff --git a/server/configs/templates/template-network.xml b/server/configs/templates/template-network.xml new file mode 100644 index 0000000..f5ec171 --- /dev/null +++ b/server/configs/templates/template-network.xml @@ -0,0 +1,12 @@ + + ~NAME~ + ~UUID~ + + + + + + + + + diff --git a/server/configs/templates/template-nwfilter.xml b/server/configs/templates/template-nwfilter.xml new file mode 100644 index 0000000..82ea8cc --- /dev/null +++ b/server/configs/templates/template-nwfilter.xml @@ -0,0 +1,9 @@ + + ~UUID~ + + + + + + + diff --git a/server/configs/templates/template.conf b/server/configs/templates/template.conf new file mode 100644 index 0000000..17480a0 --- /dev/null +++ b/server/configs/templates/template.conf @@ -0,0 +1,13 @@ +{ + "cpuQuotaForeground" : -1, + "cpuQuotaBackground" : 1000, + "privilege" : 10, + "switchToDefaultAfterTimeout" : true, + "enableDbusIntegration" : true, + "config" : "../libvirt-config/~NAME~.xml", + "networkConfig" : "../libvirt-config/~NAME~-network.xml", + "networkFilterConfig" : "../libvirt-config/~NAME~-nwfilter.xml", + "runMountPoint" : "~NAME~/run", + "permittedToSend" : [ "/tmp/.*" ], + "permittedToRecv" : [ "/tmp/.*" ] +} diff --git a/server/configs/templates/template.xml b/server/configs/templates/template.xml new file mode 100644 index 0000000..bdb452d --- /dev/null +++ b/server/configs/templates/template.xml @@ -0,0 +1,123 @@ + + ~NAME~ + ~UUID~ + 102400 + + exe + /usr/lib/systemd/systemd + + destroy + restart + destroy + + + + + /dev/fb0 + + + + + /dev/tty2 + + + + + /dev/tty3 + + + + + /dev/tty4 + + + + + /dev/tty5 + + + + + /dev/input/event0 + + + + + /dev/input/event1 + + + + + /dev/input/event2 + + + + + /dev/input/event3 + + + + + /dev/input/event4 + + + + + /dev/input/mice + + + + + /dev/input/mouse0 + + + + + + + /dev/log_events + + + + + /dev/log_main + + + + + /dev/log_radio + + + + + /dev/log_system + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/server/container-admin.cpp b/server/container-admin.cpp index 805e9c1..f60d942 100644 --- a/server/container-admin.cpp +++ b/server/container-admin.cpp @@ -90,6 +90,8 @@ ContainerAdmin::ContainerAdmin(const ContainerConfig& config) throw ContainerOperationException(mId + ": Failed to register a libvirt lifecycle callback"); } + LOGT(mId << ": registered lifecycle callback"); + mRebootCallbackId = virConnectDomainEventRegisterAny(virDomainGetConnect(mDom.get()), mDom.get(), VIR_DOMAIN_EVENT_ID_REBOOT, @@ -103,6 +105,8 @@ ContainerAdmin::ContainerAdmin(const ContainerConfig& config) mLifecycleCallbackId); throw ContainerOperationException(mId + ": Failed to register a libvirt reboot callback"); } + + LOGT(mId << ": registered reboot callback"); } diff --git a/server/container.cpp b/server/container.cpp index 60d124e..494b0ae 100644 --- a/server/container.cpp +++ b/server/container.cpp @@ -91,6 +91,10 @@ Container::~Container() if (mReconnectThread.joinable()) { mReconnectThread.join(); } + + if (mStartThread.joinable()) { + mStartThread.join(); + } } const std::vector& Container::getPermittedToSend() const @@ -131,6 +135,30 @@ void Container::start() goBackground(); } +void Container::startAsync(const StartAsyncResultCallback& callback) +{ + if (mStartThread.joinable()) { + mStartThread.join(); + } + + auto startWrapper = [this, callback]() { + bool succeeded = false; + + try { + start(); + succeeded = true; + } catch(std::exception& e) { + LOGE(getId() << ": failed to start: " << e.what()); + } + + if (callback) { + callback(succeeded); + } + }; + + mStartThread = std::thread(startWrapper); +} + void Container::stop() { Lock lock(mReconnectMutex); diff --git a/server/container.hpp b/server/container.hpp index f2d67c0..f741464 100644 --- a/server/container.hpp +++ b/server/container.hpp @@ -56,6 +56,7 @@ public: typedef ContainerConnection::ProxyCallCallback ProxyCallCallback; typedef std::function DbusStateChangedCallback; + typedef std::function StartAsyncResultCallback; /** * Returns a vector of regexps defining files permitted to be @@ -87,6 +88,14 @@ public: void start(); /** + * Boot the container to the background in separate thread. This function immediately exits + * after container booting is started in another thread. + * + * @param callback Called after starting the container. Passes bool with result of starting. + */ + void startAsync(const StartAsyncResultCallback& callback); + + /** * Try to shutdown the container, if failed, destroy it. */ void stop(); @@ -197,6 +206,7 @@ private: std::unique_ptr mAdmin; std::unique_ptr mConnection; std::thread mReconnectThread; + std::thread mStartThread; mutable std::recursive_mutex mReconnectMutex; NotifyActiveContainerCallback mNotifyCallback; DisplayOffCallback mDisplayOffCallback; diff --git a/server/containers-manager-config.hpp b/server/containers-manager-config.hpp index 310dca3..06b83be 100644 --- a/server/containers-manager-config.hpp +++ b/server/containers-manager-config.hpp @@ -62,6 +62,22 @@ struct ContainersManagerConfig { */ std::string containersPath; + /** + * A path where the containers image reside. Empty path means that containers image won't be + * copied to containersPath when creating new container. + */ + std::string containerImagePath; + + /** + * A path where template configuration files for new containers reside + */ + std::string containerTemplatePath; + + /** + * Prefix added to a path for new container configuration files + */ + std::string containerNewConfigPrefix; + /* * Parameters describing input device used to switch between containers */ @@ -83,6 +99,9 @@ struct ContainersManagerConfig { foregroundId, defaultId, containersPath, + containerImagePath, + containerTemplatePath, + containerNewConfigPrefix, inputConfig, runMountPointPrefix, proxyCallRules diff --git a/server/containers-manager.cpp b/server/containers-manager.cpp index 90a6cfc..5dc909b 100644 --- a/server/containers-manager.cpp +++ b/server/containers-manager.cpp @@ -36,9 +36,14 @@ #include "config/manager.hpp" #include "dbus/exception.hpp" #include "utils/fs.hpp" +#include "utils/img.hpp" #include #include +#include +#include +#include +#include #include #include #include @@ -61,13 +66,25 @@ bool regexMatchVector(const std::string& str, const std::vector& v } const std::string HOST_ID = "host"; +const std::string CONTAINER_TEMPLATE_CONFIG_PATH = "template.conf"; +const std::string CONTAINER_TEMPLATE_LIBVIRT_CONFIG_PATH = "template.xml"; +const std::string CONTAINER_TEMPLATE_LIBVIRT_NETWORK_PATH = "template-network.xml"; +const std::string CONTAINER_TEMPLATE_LIBVIRT_NETWORK_FILTER_PATH = "template-nwfilter.xml"; + +const boost::regex CONTAINER_NAME_REGEX("~NAME~"); +const boost::regex CONTAINER_UUID_REGEX("~UUID~"); +const boost::regex CONTAINER_IP_THIRD_OCTET_REGEX("~IP~"); + +const unsigned int CONTAINER_IP_BASE_THIRD_OCTET = 100; } // namespace ContainersManager::ContainersManager(const std::string& managerConfigPath): mDetachOnExit(false) { LOGD("Instantiating ContainersManager object..."); - config::loadFromFile(managerConfigPath, mConfig); + + mConfigPath = managerConfigPath; + config::loadFromFile(mConfigPath, mConfig); mProxyCallPolicy.reset(new ProxyCallPolicy(mConfig.proxyCallRules)); @@ -87,40 +104,11 @@ ContainersManager::ContainersManager(const std::string& managerConfigPath): mDet mHostConnection.setSetActiveContainerCallback(bind(&ContainersManager::handleSetActiveContainerCall, this, _1, _2)); - for (auto& containerConfig : mConfig.containerConfigs) { - std::string containerConfigPath; - - if (containerConfig[0] == '/') { - containerConfigPath = containerConfig; - } else { - std::string baseConfigPath = utils::dirName(managerConfigPath); - containerConfigPath = utils::createFilePath(baseConfigPath, "/", containerConfig); - } - - LOGD("Creating Container " << containerConfigPath); - std::unique_ptr c(new Container(containerConfigPath, - mConfig.runMountPointPrefix)); - const std::string id = c->getId(); - if (id == HOST_ID) { - throw ContainerOperationException("Cannot use reserved container ID"); - } - - c->setNotifyActiveContainerCallback(bind(&ContainersManager::notifyActiveContainerHandler, - this, id, _1, _2)); + mHostConnection.setAddContainerCallback(bind(&ContainersManager::handleAddContainerCall, + this, _1, _2)); - c->setDisplayOffCallback(bind(&ContainersManager::displayOffHandler, - this, id)); - - c->setFileMoveRequestCallback(std::bind(&ContainersManager::handleContainerMoveFileRequest, - this, id, _1, _2, _3)); - - c->setProxyCallCallback(bind(&ContainersManager::handleProxyCall, - this, id, _1, _2, _3, _4, _5, _6, _7)); - - c->setDbusStateChangedCallback(bind(&ContainersManager::handleDbusStateChanged, - this, id, _1)); - - mContainers.insert(ContainerMap::value_type(id, std::move(c))); + for (auto& containerConfig : mConfig.containerConfigs) { + addContainer(containerConfig); } // check if default container exists, throw ContainerOperationException if not found @@ -139,6 +127,8 @@ ContainersManager::ContainersManager(const std::string& managerConfigPath): mDet std::bind(&ContainersManager::switchingSequenceMonitorNotify, this))); } + + } ContainersManager::~ContainersManager() @@ -156,6 +146,38 @@ ContainersManager::~ContainersManager() LOGD("ContainersManager object destroyed"); } +void ContainersManager::addContainer(const std::string& containerConfig) +{ + std::string baseConfigPath = utils::dirName(mConfigPath); + std::string containerConfigPath = utils::getAbsolutePath(containerConfig, baseConfigPath); + + LOGT("Creating Container " << containerConfigPath); + std::unique_ptr c(new Container(containerConfigPath, + mConfig.runMountPointPrefix)); + const std::string id = c->getId(); + if (id == HOST_ID) { + throw ContainerOperationException("Cannot use reserved container ID"); + } + + using namespace std::placeholders; + c->setNotifyActiveContainerCallback(bind(&ContainersManager::notifyActiveContainerHandler, + this, id, _1, _2)); + + c->setDisplayOffCallback(bind(&ContainersManager::displayOffHandler, + this, id)); + + c->setFileMoveRequestCallback(bind(&ContainersManager::handleContainerMoveFileRequest, + this, id, _1, _2, _3)); + + c->setProxyCallCallback(bind(&ContainersManager::handleProxyCall, + this, id, _1, _2, _3, _4, _5, _6, _7)); + + c->setDbusStateChangedCallback(bind(&ContainersManager::handleDbusStateChanged, + this, id, _1)); + + mContainers.insert(ContainerMap::value_type(id, std::move(c))); +} + void ContainersManager::focus(const std::string& containerId) { /* try to access the object first to throw immediately if it doesn't exist */ @@ -465,4 +487,150 @@ void ContainersManager::handleSetActiveContainerCall(const std::string& id, result->setVoid(); } + +void ContainersManager::generateNewConfig(const std::string& id, + const std::string& templatePath, + const std::string& resultPath) +{ + namespace fs = boost::filesystem; + + std::string resultFileDir = utils::dirName(resultPath); + if (!fs::exists(resultFileDir)) { + if (!utils::createEmptyDir(resultFileDir)) { + LOGE("Unable to create directory for new config."); + throw ContainerOperationException("Unable to create directory for new config."); + } + } + + fs::path resultFile(resultPath); + if (fs::exists(resultFile)) { + LOGT(resultPath << " already exists, removing"); + fs::remove(resultFile); + } + + std::string config; + if (!utils::readFileContent(templatePath, config)) { + LOGE("Failed to read template config file."); + throw ContainerOperationException("Failed to read template config file."); + } + + std::string resultConfig = boost::regex_replace(config, CONTAINER_NAME_REGEX, id); + + boost::uuids::uuid u = boost::uuids::random_generator()(); + std::string uuidStr = to_string(u); + LOGD("uuid: " << uuidStr); + resultConfig = boost::regex_replace(resultConfig, CONTAINER_UUID_REGEX, uuidStr); + + // generate third IP octet for network config + std::string thirdOctetStr = std::to_string(CONTAINER_IP_BASE_THIRD_OCTET + mContainers.size() + 1); + LOGD("ip_third_octet: " << thirdOctetStr); + resultConfig = boost::regex_replace(resultConfig, CONTAINER_IP_THIRD_OCTET_REGEX, thirdOctetStr); + + if (!utils::saveFileContent(resultPath, resultConfig)) { + LOGE("Faield to save new config file."); + throw ContainerOperationException("Failed to save new config file."); + } + + // restrict new config file so that only owner (security-containers) can write it + fs::permissions(resultPath, fs::perms::owner_all | + fs::perms::group_read | + fs::perms::others_read); +} + +void ContainersManager::handleAddContainerCall(const std::string& id, + dbus::MethodResultBuilder::Pointer result) +{ + LOGI("Adding container " << id); + + // TODO: This solution is temporary. It utilizes direct access to config files when creating new + // containers. Update this handler when config database will appear. + namespace fs = boost::filesystem; + + boost::system::error_code ec; + const std::string containerPathStr = utils::createFilePath(mConfig.containersPath, "/", id, "/"); + + // check if container does not exist + if (mContainers.find(id) != mContainers.end()) { + LOGE("Cannot create " << id << " container - already exists!"); + result->setError(api::host::ERROR_CONTAINER_CREATE_FAILED, + "Cannot create " + id + " container - already exists!"); + return; + } + + // copy container image if config contains path to image + LOGT("image path: " << mConfig.containerImagePath); + if (!mConfig.containerImagePath.empty()) { + if (!utils::copyImageContents(mConfig.containerImagePath, containerPathStr)) { + LOGE("Failed to copy container image."); + result->setError(api::host::ERROR_CONTAINER_CREATE_FAILED, + "Failed to copy container image."); + return; + } + } + + // generate paths to new configuration files + std::string baseDir = utils::dirName(mConfigPath); + std::string configDir = utils::getAbsolutePath(mConfig.containerNewConfigPrefix, baseDir); + std::string templateDir = utils::getAbsolutePath(mConfig.containerTemplatePath, baseDir); + + std::string configPath = utils::createFilePath(templateDir, "/", CONTAINER_TEMPLATE_CONFIG_PATH); + std::string newConfigPath = utils::createFilePath(configDir, "/containers/", id + ".conf"); + std::string libvirtConfigPath = utils::createFilePath(templateDir, "/", CONTAINER_TEMPLATE_LIBVIRT_CONFIG_PATH); + std::string newLibvirtConfigPath = utils::createFilePath(configDir, "/libvirt-config/", id + ".xml"); + std::string libvirtNetworkPath = utils::createFilePath(templateDir, "/", CONTAINER_TEMPLATE_LIBVIRT_NETWORK_PATH); + std::string newLibvirtNetworkPath = utils::createFilePath(configDir, "/libvirt-config/", id + "-network.xml"); + std::string libvirtNetworkFilterPath = utils::createFilePath(templateDir, "/", CONTAINER_TEMPLATE_LIBVIRT_NETWORK_FILTER_PATH); + std::string newLibvirtNetworkFilterPath = utils::createFilePath(configDir, "/libvirt-config/", id + "-nwfilter.xml"); + + auto removeAllWrapper = [](const std::string& path) { + try { + LOGD("Removing copied data"); + fs::remove_all(fs::path(path)); + } catch(const boost::exception& e) { + LOGW("Failed to remove data: " << boost::diagnostic_information(e)); + } + }; + + try { + LOGI("Generating config from " << configPath << " to " << newConfigPath); + generateNewConfig(id, configPath, newConfigPath); + + LOGI("Generating config from " << libvirtConfigPath << " to " << newLibvirtConfigPath); + generateNewConfig(id, libvirtConfigPath, newLibvirtConfigPath); + + LOGI("Generating config from " << libvirtNetworkPath << " to " << newLibvirtNetworkPath); + generateNewConfig(id, libvirtNetworkPath, newLibvirtNetworkPath); + + LOGI("Generating config from " << libvirtNetworkFilterPath << " to " << newLibvirtNetworkFilterPath); + generateNewConfig(id, libvirtNetworkFilterPath, newLibvirtNetworkFilterPath); + } catch (SecurityContainersException& e) { + LOGE(e.what()); + removeAllWrapper(containerPathStr); + result->setError(api::host::ERROR_CONTAINER_CREATE_FAILED, e.what()); + return; + } + + LOGT("Adding new container"); + try { + addContainer(newConfigPath); + } catch (SecurityContainersException& e) { + LOGE(e.what()); + removeAllWrapper(containerPathStr); + result->setError(api::host::ERROR_CONTAINER_CREATE_FAILED, e.what()); + return; + } + + auto resultCallback = [result, containerPathStr, removeAllWrapper](bool succeeded) { + if (succeeded) { + result->setVoid(); + } else { + LOGE("Failed to start container."); + removeAllWrapper(containerPathStr); + result->setError(api::host::ERROR_CONTAINER_CREATE_FAILED, + "Failed to start container."); + } + }; + mContainers[id]->startAsync(resultCallback); +} + } // namespace security_containers diff --git a/server/containers-manager.hpp b/server/containers-manager.hpp index 33767a9..cd1194d 100644 --- a/server/containers-manager.hpp +++ b/server/containers-manager.hpp @@ -48,6 +48,13 @@ public: ~ContainersManager(); /** + * Add new container. + * + * @param containerConfig config of new container + */ + void addContainer(const std::string& containerConfig); + + /** * Focus this container, put it to the foreground. * Method blocks until the focus is switched. * @@ -77,6 +84,7 @@ public: private: ContainersManagerConfig mConfig; + std::string mConfigPath; HostConnection mHostConnection; // to hold InputMonitor pointer to monitor if container switching sequence is recognized std::unique_ptr mSwitchingSequenceMonitor; @@ -86,6 +94,10 @@ private: bool mDetachOnExit; void switchingSequenceMonitorNotify(); + void generateNewConfig(const std::string& id, + const std::string& templatePath, + const std::string& resultPath); + void notifyActiveContainerHandler(const std::string& caller, const std::string& appliaction, const std::string& message); @@ -108,7 +120,8 @@ private: void handleGetActiveContainerIdCall(dbus::MethodResultBuilder::Pointer result); void handleSetActiveContainerCall(const std::string& id, dbus::MethodResultBuilder::Pointer result); - + void handleAddContainerCall(const std::string& id, + dbus::MethodResultBuilder::Pointer result); }; diff --git a/server/host-connection.cpp b/server/host-connection.cpp index ae32de2..d25bee7 100644 --- a/server/host-connection.cpp +++ b/server/host-connection.cpp @@ -130,6 +130,11 @@ void HostConnection::setSetActiveContainerCallback(const SetActiveContainerCallb mSetActiveContainerCallback = callback; } +void HostConnection::setAddContainerCallback(const AddContainerCallback& callback) +{ + mAddContainerCallback = callback; +} + void HostConnection::onMessageCall(const std::string& objectPath, const std::string& interface, const std::string& methodName, @@ -199,6 +204,15 @@ void HostConnection::onMessageCall(const std::string& objectPath, } return; } + + if (methodName == api::host::METHOD_ADD_CONTAINER) { + const gchar* id = NULL; + g_variant_get(parameters, "(&s)", &id); + + if (mAddContainerCallback){ + mAddContainerCallback(id, result); + } + } } void HostConnection::proxyCallAsync(const std::string& busName, diff --git a/server/host-connection.hpp b/server/host-connection.hpp index bc9015d..c5d1bcc 100644 --- a/server/host-connection.hpp +++ b/server/host-connection.hpp @@ -60,6 +60,9 @@ public: typedef std::function SetActiveContainerCallback; + typedef std::function AddContainerCallback; /** * Register proxy call callback @@ -92,6 +95,11 @@ public: void setSetActiveContainerCallback(const SetActiveContainerCallback& callback); /** + * Register a callback called to create new container + */ + void setAddContainerCallback(const AddContainerCallback& callback); + + /** * Make a proxy call */ void proxyCallAsync(const std::string& busName, @@ -112,6 +120,7 @@ private: GetContainerIdsCallback mGetContainerIdsCallback; GetActiveContainerIdCallback mGetActiveContainerIdCallback; SetActiveContainerCallback mSetActiveContainerCallback; + AddContainerCallback mAddContainerCallback; void onNameAcquired(); void onNameLost(); diff --git a/server/host-dbus-definitions.hpp b/server/host-dbus-definitions.hpp index 12e8d4a..040b10d 100644 --- a/server/host-dbus-definitions.hpp +++ b/server/host-dbus-definitions.hpp @@ -37,11 +37,13 @@ const std::string OBJECT_PATH = "/org/tizen/containers/host"; const std::string INTERFACE = "org.tizen.containers.host.manager"; const std::string ERROR_CONTAINER_STOPPED = "org.tizen.containers.host.Error.ContainersStopped"; +const std::string ERROR_CONTAINER_CREATE_FAILED = "org.tizen.containers.host.Error.ContainerCreateFailed"; const std::string METHOD_GET_CONTAINER_DBUSES = "GetContainerDbuses"; const std::string METHOD_GET_CONTAINER_ID_LIST = "GetContainerIds"; const std::string METHOD_GET_ACTIVE_CONTAINER_ID = "GetActiveContainerId"; const std::string METHOD_SET_ACTIVE_CONTAINER = "SetActiveContainer"; +const std::string METHOD_ADD_CONTAINER = "AddContainer"; const std::string SIGNAL_CONTAINER_DBUS_STATE = "ContainerDbusState"; @@ -70,6 +72,9 @@ const std::string DEFINITION = " " " " " " + " " + " " + " " " " " " " " diff --git a/server/server.cpp b/server/server.cpp index 5c3420d..547d023 100644 --- a/server/server.cpp +++ b/server/server.cpp @@ -58,6 +58,10 @@ #error "LIBVIRT_GROUP must be defined!" #endif +#ifndef DISK_GROUP +#error "DISK_GROUP must be defined!" +#endif + extern char** environ; namespace security_containers { @@ -165,6 +169,16 @@ bool Server::prepareEnvironment(const std::string& configPath, bool runAsRoot) } } + // create directory for additional container data (if needed) + if (!config.containerNewConfigPrefix.empty()) { + if (!utils::createDir(config.containerNewConfigPrefix, uid, gid, + fs::perms::owner_all | + fs::perms::group_read | fs::perms::group_exe | + fs::perms::others_read | fs::perms::others_exe)) { + return false; + } + } + // Omit supplementaty group setup and root drop if the user is already switched. // This situation will happen during daemon update triggered by SIGUSR1. if (!runAsRoot && geteuid() == uid) { @@ -173,7 +187,9 @@ bool Server::prepareEnvironment(const std::string& configPath, bool runAsRoot) // LIBVIRT_GROUP provides access to libvirt's daemon socket. // INPUT_EVENT_GROUP provides access to /dev/input/event* devices used by InputMonitor. - if (!utils::setSuppGroups({LIBVIRT_GROUP, INPUT_EVENT_GROUP})) { + // DISK_GROUP provides access to /dev/loop* devices, needed when adding new container to copy + // containers image + if (!utils::setSuppGroups({LIBVIRT_GROUP, INPUT_EVENT_GROUP, DISK_GROUP})) { return false; } diff --git a/tests/unit_tests/client/configs/ut-client/test-dbus-daemon.conf b/tests/unit_tests/client/configs/ut-client/test-dbus-daemon.conf index 2a6ad35..707be02 100644 --- a/tests/unit_tests/client/configs/ut-client/test-dbus-daemon.conf +++ b/tests/unit_tests/client/configs/ut-client/test-dbus-daemon.conf @@ -5,6 +5,9 @@ "foregroundId" : "ut-containers-manager-console1-dbus", "defaultId" : "ut-containers-manager-console1-dbus", "containersPath" : "/tmp", + "containerImagePath" : "", + "containerTemplatePath" : "", + "containerNewConfigPrefix" : "", "runMountPointPrefix" : "", "inputConfig" : {"enabled" : false, "device" : "/dev/doesnotexist", diff --git a/tests/unit_tests/server/configs/CMakeLists.txt b/tests/unit_tests/server/configs/CMakeLists.txt index 816a5bc..ee1c7d9 100644 --- a/tests/unit_tests/server/configs/CMakeLists.txt +++ b/tests/unit_tests/server/configs/CMakeLists.txt @@ -26,6 +26,8 @@ FILE(GLOB server_admin_CONF ut-server/libvirt-config/*.xml) FILE(GLOB manager_manager_CONF ut-containers-manager/*.conf) FILE(GLOB manager_container_CONF ut-containers-manager/containers/*.conf) FILE(GLOB manager_admin_CONF ut-containers-manager/libvirt-config/*.xml) +FILE(GLOB manager_admin_TEMPLATE ut-containers-manager/templates/*.conf + ut-containers-manager/templates/*.xml) FILE(GLOB container_CONF ut-container/*.conf) FILE(GLOB container_container_CONF ut-container/containers/*.conf) @@ -61,7 +63,10 @@ CONFIGURE_FILE(ut-containers-manager/libvirt-config/console2-dbus.xml.in ${CMAKE_BINARY_DIR}/ut-containers-manager/libvirt-config/console2-dbus.xml @ONLY) CONFIGURE_FILE(ut-containers-manager/libvirt-config/console3-dbus.xml.in ${CMAKE_BINARY_DIR}/ut-containers-manager/libvirt-config/console3-dbus.xml @ONLY) +CONFIGURE_FILE(ut-containers-manager/templates/template.xml.in + ${CMAKE_BINARY_DIR}/ut-containers-manager/templates/template.xml @ONLY) FILE(GLOB manager_admin_CONF_GEN ${CMAKE_BINARY_DIR}/ut-containers-manager/libvirt-config/*.xml) +FILE(GLOB manager_admin_TEMPLATE_GEN ${CMAKE_BINARY_DIR}/ut-containers-manager/templates/*.xml) CONFIGURE_FILE(ut-container/libvirt-config/test-dbus.xml.in ${CMAKE_BINARY_DIR}/ut-container/libvirt-config/test-dbus.xml @ONLY) @@ -84,6 +89,10 @@ INSTALL(FILES ${manager_admin_CONF} DESTINATION ${SC_TEST_CONFIG_INSTALL_DIR}/server/ut-containers-manager/libvirt-config) INSTALL(FILES ${manager_admin_CONF_GEN} DESTINATION ${SC_TEST_CONFIG_INSTALL_DIR}/server/ut-containers-manager/libvirt-config) +INSTALL(FILES ${manager_admin_TEMPLATE} + DESTINATION ${SC_TEST_CONFIG_INSTALL_DIR}/server/ut-containers-manager/templates) +INSTALL(FILES ${manager_admin_TEMPLATE_GEN} + DESTINATION ${SC_TEST_CONFIG_INSTALL_DIR}/server/ut-containers-manager/templates) INSTALL(FILES ${container_CONF} DESTINATION ${SC_TEST_CONFIG_INSTALL_DIR}/server/ut-container) diff --git a/tests/unit_tests/server/configs/ut-containers-manager/buggy-daemon.conf b/tests/unit_tests/server/configs/ut-containers-manager/buggy-daemon.conf index 92abbe2..5ec98cc 100644 --- a/tests/unit_tests/server/configs/ut-containers-manager/buggy-daemon.conf +++ b/tests/unit_tests/server/configs/ut-containers-manager/buggy-daemon.conf @@ -4,6 +4,9 @@ "foregroundId" : "ut-containers-manager-console1", "defaultId" : "ut-containers-manager-console1", "containersPath" : "/tmp", + "containerImagePath" : "", + "containerTemplatePath" : "templates", + "containerNewConfigPrefix" : "/usr/share/security-containers/tests/server/ut-containers-manager/", "inputConfig" : {"enabled" : false, "device" : "/dev/doesnotexist", "code" : 139, diff --git a/tests/unit_tests/server/configs/ut-containers-manager/buggy-default-daemon.conf b/tests/unit_tests/server/configs/ut-containers-manager/buggy-default-daemon.conf index a19268c..ef5a597 100644 --- a/tests/unit_tests/server/configs/ut-containers-manager/buggy-default-daemon.conf +++ b/tests/unit_tests/server/configs/ut-containers-manager/buggy-default-daemon.conf @@ -4,6 +4,9 @@ "foregroundId" : "ut-containers-manager-console1", "defaultId" : "in_no_way_there_is_a_valid_id_here", "containersPath" : "/tmp", + "containerImagePath" : "", + "containerTemplatePath" : "templates", + "containerNewConfigPrefix" : "/usr/share/security-containers/tests/server/ut-containers-manager/", "inputConfig" : {"enabled" : false, "device" : "/dev/doesnotexist", "code" : 139, diff --git a/tests/unit_tests/server/configs/ut-containers-manager/buggy-foreground-daemon.conf b/tests/unit_tests/server/configs/ut-containers-manager/buggy-foreground-daemon.conf index bcaba00..3faa0f7 100644 --- a/tests/unit_tests/server/configs/ut-containers-manager/buggy-foreground-daemon.conf +++ b/tests/unit_tests/server/configs/ut-containers-manager/buggy-foreground-daemon.conf @@ -4,6 +4,9 @@ "foregroundId" : "this_id_does_not_exist", "defaultId" : "ut-containers-manager-console1", "containersPath" : "/tmp", + "containerImagePath" : "", + "containerTemplatePath" : "templates", + "containerNewConfigPrefix" : "/usr/share/security-containers/tests/server/ut-containers-manager/", "inputConfig" : {"enabled" : false, "device" : "/dev/doesnotexist", "code" : 139, diff --git a/tests/unit_tests/server/configs/ut-containers-manager/templates/template-network.xml b/tests/unit_tests/server/configs/ut-containers-manager/templates/template-network.xml new file mode 100644 index 0000000..b357c0e --- /dev/null +++ b/tests/unit_tests/server/configs/ut-containers-manager/templates/template-network.xml @@ -0,0 +1,4 @@ + + ~NAME~-network + ~UUID~ + diff --git a/tests/unit_tests/server/configs/ut-containers-manager/templates/template-nwfilter.xml b/tests/unit_tests/server/configs/ut-containers-manager/templates/template-nwfilter.xml new file mode 100644 index 0000000..b96197b --- /dev/null +++ b/tests/unit_tests/server/configs/ut-containers-manager/templates/template-nwfilter.xml @@ -0,0 +1,3 @@ + + ~UUID~ + diff --git a/tests/unit_tests/server/configs/ut-containers-manager/templates/template.conf b/tests/unit_tests/server/configs/ut-containers-manager/templates/template.conf new file mode 100644 index 0000000..40dcacc --- /dev/null +++ b/tests/unit_tests/server/configs/ut-containers-manager/templates/template.conf @@ -0,0 +1,13 @@ +{ + "privilege" : 20, + "switchToDefaultAfterTimeout" : true, + "config" : "../libvirt-config/~NAME~.xml", + "networkConfig" : "../libvirt-config/~NAME~-network.xml", + "networkFilterConfig" : "../libvirt-config/~NAME~-nwfilter.xml", + "cpuQuotaForeground" : -1, + "cpuQuotaBackground" : 1000, + "runMountPoint" : "/tmp/ut-containers-manager/~NAME~-dbus", + "enableDbusIntegration" : true, + "permittedToSend" : [ "/tmp/.*" ], + "permittedToRecv" : [ "/tmp/.*" ] +} diff --git a/tests/unit_tests/server/configs/ut-containers-manager/templates/template.xml.in b/tests/unit_tests/server/configs/ut-containers-manager/templates/template.xml.in new file mode 100644 index 0000000..fbb12a5 --- /dev/null +++ b/tests/unit_tests/server/configs/ut-containers-manager/templates/template.xml.in @@ -0,0 +1,15 @@ + + ~NAME~ + ~UUID~ + 102400 + + exe + /usr/bin/dbus-daemon + --nofork + --config-file=@SC_TEST_CONFIG_INSTALL_DIR@/server/ut-containers-manager/ut-dbus.conf + --address=unix:path=/tmp/ut-containers-manager/~NAME~-dbus/dbus/system_bus_socket + + + + + diff --git a/tests/unit_tests/server/configs/ut-containers-manager/test-daemon.conf b/tests/unit_tests/server/configs/ut-containers-manager/test-daemon.conf index 6147c03..9317b9d 100644 --- a/tests/unit_tests/server/configs/ut-containers-manager/test-daemon.conf +++ b/tests/unit_tests/server/configs/ut-containers-manager/test-daemon.conf @@ -4,6 +4,9 @@ "foregroundId" : "ut-containers-manager-console1", "defaultId" : "ut-containers-manager-console1", "containersPath" : "/tmp", + "containerImagePath" : "", + "containerTemplatePath" : "templates", + "containerNewConfigPrefix" : "/usr/share/security-containers/tests/server/ut-containers-manager/", "inputConfig" : {"enabled" : false, "device" : "/dev/doesnotexist", "code" : 139, diff --git a/tests/unit_tests/server/configs/ut-containers-manager/test-dbus-daemon.conf b/tests/unit_tests/server/configs/ut-containers-manager/test-dbus-daemon.conf index 2a6ad35..af183a1 100644 --- a/tests/unit_tests/server/configs/ut-containers-manager/test-dbus-daemon.conf +++ b/tests/unit_tests/server/configs/ut-containers-manager/test-dbus-daemon.conf @@ -5,6 +5,9 @@ "foregroundId" : "ut-containers-manager-console1-dbus", "defaultId" : "ut-containers-manager-console1-dbus", "containersPath" : "/tmp", + "containerImagePath" : "", + "containerTemplatePath" : "templates", + "containerNewConfigPrefix" : "/usr/share/security-containers/tests/server/ut-containers-manager/", "runMountPointPrefix" : "", "inputConfig" : {"enabled" : false, "device" : "/dev/doesnotexist", diff --git a/tests/unit_tests/server/configs/ut-server/buggy-daemon.conf b/tests/unit_tests/server/configs/ut-server/buggy-daemon.conf index cad519c..4758406 100644 --- a/tests/unit_tests/server/configs/ut-server/buggy-daemon.conf +++ b/tests/unit_tests/server/configs/ut-server/buggy-daemon.conf @@ -1,9 +1,12 @@ { "containerConfigs" : ["containers/container1.conf", "missing/file/path/missing.conf", "containers/container3.conf"], "containersPath" : "/tmp", + "containerImagePath" : "", + "containerTemplatePath" : "no_need_for_templates_in_this_test", "runMountPointPrefix" : "", "foregroundId" : "ut-server-container1", "defaultId" : "ut-server-container1", + "containerNewConfigPrefix" : "", "inputConfig" : {"enabled" : false, "device" : "/dev/doesnotexist", "code" : 139, diff --git a/tests/unit_tests/server/configs/ut-server/test-daemon.conf b/tests/unit_tests/server/configs/ut-server/test-daemon.conf index 868f12b..767b3a5 100644 --- a/tests/unit_tests/server/configs/ut-server/test-daemon.conf +++ b/tests/unit_tests/server/configs/ut-server/test-daemon.conf @@ -1,6 +1,9 @@ { "containerConfigs" : ["containers/container1.conf", "containers/container2.conf", "containers/container3.conf"], "containersPath" : "/tmp", + "containerImagePath" : "", + "containerTemplatePath" : "no_need_for_templates_in_this_test", + "containerNewConfigPrefix" : "", "runMountPointPrefix" : "", "foregroundId" : "ut-server-container1", "defaultId" : "ut-server-container1", diff --git a/tests/unit_tests/server/ut-containers-manager.cpp b/tests/unit_tests/server/ut-containers-manager.cpp index 54a34bb..528d744 100644 --- a/tests/unit_tests/server/ut-containers-manager.cpp +++ b/tests/unit_tests/server/ut-containers-manager.cpp @@ -40,6 +40,7 @@ #include "config/exception.hpp" #include "utils/latch.hpp" #include "utils/fs.hpp" +#include "utils/img.hpp" #include #include @@ -63,6 +64,8 @@ const std::string TEST_DBUS_CONFIG_PATH = SC_TEST_CONFIG_INSTALL_DIR "/server/ut const std::string BUGGY_CONFIG_PATH = SC_TEST_CONFIG_INSTALL_DIR "/server/ut-containers-manager/buggy-daemon.conf"; const std::string BUGGY_FOREGROUND_CONFIG_PATH = SC_TEST_CONFIG_INSTALL_DIR "/server/ut-containers-manager/buggy-foreground-daemon.conf"; const std::string BUGGY_DEFAULTID_CONFIG_PATH = SC_TEST_CONFIG_INSTALL_DIR "/server/ut-containers-manager/buggy-default-daemon.conf"; +const std::string TEST_CONTAINER_CONF_PATH = SC_TEST_CONFIG_INSTALL_DIR "/server/ut-containers-manager/containers/"; +const std::string TEST_CONTAINER_LIBVIRT_CONF_PATH = SC_TEST_CONFIG_INSTALL_DIR "/server/ut-containers-manager/libvirt-config/"; const std::string MISSING_CONFIG_PATH = "/this/is/a/missing/file/path/missing-daemon.conf"; const int EVENT_TIMEOUT = 5000; const int TEST_DBUS_CONNECTION_CONTAINERS_COUNT = 3; @@ -81,6 +84,7 @@ public: typedef std::function TestApiMethodCallback; + typedef std::function AddContainerResultCallback; typedef std::map Dbuses; @@ -303,6 +307,25 @@ public: } + void callAsyncMethodAddContainer(const std::string& id, + const AddContainerResultCallback& result) + { + auto asyncResult = [result](dbus::AsyncMethodCallResult& asyncMethodCallResult) { + BOOST_CHECK(g_variant_is_of_type(asyncMethodCallResult.get(), G_VARIANT_TYPE_UNIT)); + result(); + }; + + assert(isHost()); + GVariant* parameters = g_variant_new("(s)", id.c_str()); + mClient->callMethodAsync(api::host::BUS_NAME, + api::host::OBJECT_PATH, + api::host::INTERFACE, + api::host::METHOD_ADD_CONTAINER, + parameters, + "()", + asyncResult); + } + private: const int mId; DbusConnection::Pointer mClient; @@ -331,6 +354,27 @@ std::function expectedMessage(const std::string& me }; } +class FileCleanerRAII { +public: + FileCleanerRAII(const std::vector& filePathsToClean): + mFilePathsToClean(filePathsToClean) + { } + + ~FileCleanerRAII() + { + namespace fs = boost::filesystem; + for (const auto& file : mFilePathsToClean) { + fs::path f(file); + if (fs::exists(f)) { + fs::remove(f); + } + } + } + +private: + const std::vector mFilePathsToClean; +}; + struct Fixture { security_containers::utils::ScopedGlibLoop mLoop; }; @@ -881,4 +925,34 @@ BOOST_AUTO_TEST_CASE(SetActiveContainerTest) DbusException); } +BOOST_AUTO_TEST_CASE(AddContainerTest) +{ + const std::string newContainerId = "test1234"; + const std::vector newContainerConfigs = { + TEST_CONTAINER_CONF_PATH + newContainerId + ".conf", + TEST_CONTAINER_LIBVIRT_CONF_PATH + newContainerId + ".xml", + TEST_CONTAINER_LIBVIRT_CONF_PATH + newContainerId + "-network.xml", + TEST_CONTAINER_LIBVIRT_CONF_PATH + newContainerId + "-nwfilter.xml", + }; + FileCleanerRAII cleaner(newContainerConfigs); + + ContainersManager cm(TEST_DBUS_CONFIG_PATH); + cm.startAll(); + + Latch callDone; + auto resultCallback = [&]() { + callDone.set(); + }; + + DbusAccessory dbus(DbusAccessory::HOST_ID); + + // create new container + dbus.callAsyncMethodAddContainer(newContainerId, resultCallback); + callDone.wait(EVENT_TIMEOUT); + + // focus new container + BOOST_REQUIRE_NO_THROW(cm.focus(newContainerId)); + BOOST_CHECK(cm.getRunningForegroundContainerId() == newContainerId); +} + BOOST_AUTO_TEST_SUITE_END() diff --git a/tests/unit_tests/utils/ut-fs.cpp b/tests/unit_tests/utils/ut-fs.cpp index 8f7c965..43be58a 100644 --- a/tests/unit_tests/utils/ut-fs.cpp +++ b/tests/unit_tests/utils/ut-fs.cpp @@ -44,6 +44,12 @@ const std::string FILE_PATH = SC_TEST_CONFIG_INSTALL_DIR "/utils/ut-fs/file.txt" const std::string FILE_CONTENT = "File content\n" "Line 1\n" "Line 2\n"; +const std::string FILE_CONTENT_2 = "Some other content\n" + "Just to see if\n" + "everything is copied correctly\n"; +const std::string FILE_CONTENT_3 = "More content\n" + "More and more content\n" + "That's a lot of data to test\n"; const std::string BUGGY_FILE_PATH = "/some/missing/file/path/file.txt"; const std::string TMP_PATH = "/tmp"; const std::string FILE_PATH_RANDOM = @@ -52,6 +58,12 @@ const std::string MOUNT_POINT_RANDOM_1 = boost::filesystem::unique_path("/tmp/mountPoint-%%%%").string(); const std::string MOUNT_POINT_RANDOM_2 = boost::filesystem::unique_path("/tmp/mountPoint-%%%%").string(); +const std::string FILE_DIR_RANDOM_1 = + boost::filesystem::unique_path("testDir-%%%%").string(); +const std::string FILE_DIR_RANDOM_2 = + boost::filesystem::unique_path("testDir-%%%%").string(); +const std::string FILE_DIR_RANDOM_3 = + boost::filesystem::unique_path("testDir-%%%%").string(); const std::string FILE_NAME_RANDOM_1 = boost::filesystem::unique_path("testFile-%%%%").string(); const std::string FILE_NAME_RANDOM_2 = @@ -131,4 +143,43 @@ BOOST_AUTO_TEST_CASE(MoveFileTest) BOOST_REQUIRE(fs::remove(MOUNT_POINT_RANDOM_2, ec)); } +BOOST_AUTO_TEST_CASE(CopyDirContentsTest) +{ + namespace fs = boost::filesystem; + std::string src, src_inner, dst, dst_inner; + boost::system::error_code ec; + + src = TMP_PATH + "/" + FILE_DIR_RANDOM_1; + src_inner = src + "/" + FILE_DIR_RANDOM_3; + + dst = TMP_PATH + "/" + FILE_DIR_RANDOM_2; + dst_inner = dst + "/" + FILE_DIR_RANDOM_3; + + // create entire structure with files + BOOST_REQUIRE(fs::create_directory(src, ec)); + BOOST_REQUIRE(ec.value() == 0); + BOOST_REQUIRE(fs::create_directory(src_inner, ec)); + BOOST_REQUIRE(ec.value() == 0); + + BOOST_REQUIRE(saveFileContent(src + "/" + FILE_NAME_RANDOM_1, FILE_CONTENT)); + BOOST_REQUIRE(saveFileContent(src + "/" + FILE_NAME_RANDOM_2, FILE_CONTENT_2)); + BOOST_REQUIRE(saveFileContent(src_inner + "/" + FILE_NAME_RANDOM_1, FILE_CONTENT_3)); + + BOOST_REQUIRE(fs::create_directory(dst, ec)); + BOOST_REQUIRE(ec.value() == 0); + + // copy data + BOOST_CHECK(copyDirContents(src, dst)); + + // check if copy is successful + BOOST_CHECK(fs::exists(dst + "/" + FILE_NAME_RANDOM_1)); + BOOST_CHECK(fs::exists(dst + "/" + FILE_NAME_RANDOM_2)); + BOOST_CHECK(fs::exists(dst_inner)); + BOOST_CHECK(fs::exists(dst_inner + "/" + FILE_NAME_RANDOM_1)); + + BOOST_CHECK_EQUAL(readFileContent(dst + "/" + FILE_NAME_RANDOM_1), FILE_CONTENT); + BOOST_CHECK_EQUAL(readFileContent(dst + "/" + FILE_NAME_RANDOM_2), FILE_CONTENT_2); + BOOST_CHECK_EQUAL(readFileContent(dst_inner + "/" + FILE_NAME_RANDOM_1), FILE_CONTENT_3); +} + BOOST_AUTO_TEST_SUITE_END() -- 2.7.4 From 11ddb3bab10b043797aca9eaa491070aa8510f3d Mon Sep 17 00:00:00 2001 From: Piotr Bartosiewicz Date: Thu, 18 Sep 2014 10:07:15 +0200 Subject: [PATCH 14/16] New get_container_id_by_pid API function [Bug/Feature] Introduce new API function: sc_get_container_id_by_pid [Cause] N/A [Solution] N/A [Verification] Build, install, run tests Change-Id: I8bee78c062bcbbe29fc9e2c651989570c26869d1 --- client/security-containers-client-impl.cpp | 36 +++++++++ client/security-containers-client-impl.hpp | 5 ++ client/security-containers-client.cpp | 5 ++ client/security-containers-client.h | 11 +++ client/utils.cpp | 118 ++++++++++++++++++++++++++++ client/utils.hpp | 32 ++++++++ tests/unit_tests/client/ut-client-utils.cpp | 55 +++++++++++++ tests/unit_tests/client/ut-client.cpp | 37 +++++++++ 8 files changed, 299 insertions(+) create mode 100644 client/utils.cpp create mode 100644 client/utils.hpp create mode 100644 tests/unit_tests/client/ut-client-utils.cpp diff --git a/client/security-containers-client-impl.cpp b/client/security-containers-client-impl.cpp index 8486ae7..a2c51ba 100644 --- a/client/security-containers-client-impl.cpp +++ b/client/security-containers-client-impl.cpp @@ -25,6 +25,7 @@ #include #include "security-containers-client-impl.hpp" +#include "utils.hpp" #include #include #include @@ -33,6 +34,7 @@ #include #include +#include using namespace std; using namespace dbus; @@ -122,6 +124,17 @@ ScStatus toStatus(const std::exception& ex) return SCCLIENT_OTHER_ERROR; } +bool readFirstLineOfFile(const std::string& path, std::string& ret) +{ + std::ifstream file(path); + if (!file) { + return false; + } + + std::getline(file, ret); + return true; +} + } //namespace ScStatus Client::sc_start_glib_loop() noexcept @@ -309,6 +322,29 @@ ScStatus Client::sc_get_active_container_id(ScString* id) noexcept return ret; } +ScStatus Client::sc_get_container_id_by_pid(int pid, ScString* id) noexcept +{ + assert(id); + + const std::string path = "/proc/" + std::to_string(pid) + "/cpuset"; + + std::string cpuset; + if (!readFirstLineOfFile(path, cpuset)) { + mStatus = Status(SCCLIENT_INVALID_ARGUMENT, "Process not found"); + return sc_get_status(); + } + + std::string containerId; + if (!parseContainerIdFromCpuSet(cpuset, containerId)) { + mStatus = Status(SCCLIENT_OTHER_ERROR, "unknown format of cpuset"); + return sc_get_status(); + } + + *id = strdup(containerId.c_str()); + mStatus = Status(); + return sc_get_status();; +} + ScStatus Client::sc_set_active_container(const char* id) noexcept { assert(id); diff --git a/client/security-containers-client-impl.hpp b/client/security-containers-client-impl.hpp index 10aecaf..f1bfacb 100644 --- a/client/security-containers-client-impl.hpp +++ b/client/security-containers-client-impl.hpp @@ -117,6 +117,11 @@ public: ScStatus sc_get_active_container_id(ScString* id) noexcept; /** + * @see ::sc_get_container_id_by_pid + */ + ScStatus sc_get_container_id_by_pid(int pid, ScString* id) noexcept; + + /** * @see ::sc_set_active_container */ ScStatus sc_set_active_container(const char* id) noexcept; diff --git a/client/security-containers-client.cpp b/client/security-containers-client.cpp index b1eb521..cb22544 100644 --- a/client/security-containers-client.cpp +++ b/client/security-containers-client.cpp @@ -121,6 +121,11 @@ API ScStatus sc_get_active_container_id(ScClient client, ScString* id) return getClient(client).sc_get_active_container_id(id); } +API ScStatus sc_get_container_id_by_pid(ScClient client, int pid, ScString* id) +{ + return getClient(client).sc_get_container_id_by_pid(pid, id); +} + API ScStatus sc_set_active_container(ScClient client, const char* id) { return getClient(client).sc_set_active_container(id); diff --git a/client/security-containers-client.h b/client/security-containers-client.h index c56e9de..4d37c3c 100644 --- a/client/security-containers-client.h +++ b/client/security-containers-client.h @@ -247,6 +247,17 @@ ScStatus sc_get_container_ids(ScClient client, ScArrayString* array); ScStatus sc_get_active_container_id(ScClient client, ScString* id); /** + * Get container name of process with given pid. + * + * @param[in] client security-containers-server's client + * @param[in] pid process id + * @param[out] id active container name + * @return status of this function call + * @remark Use @p sc_string_free() to free memory occupied by @p id. + */ +ScStatus sc_get_container_id_by_pid(ScClient client, int pid, ScString* id); + +/** * Set active (foreground) container. * * @param[in] client security-containers-server's client diff --git a/client/utils.cpp b/client/utils.cpp new file mode 100644 index 0000000..98b6905 --- /dev/null +++ b/client/utils.cpp @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Contact: Piotr Bartosiewicz + * + * Licensed 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 + */ + +/** + * @file + * @author Piotr Bartosiewicz (p.bartosiewi@partner.samsung.com) + * @brief Utility functions definition + */ + +#include "config.hpp" +#include "utils.hpp" + +#include + +namespace { + +const std::string CPUSET_HOST = "/"; +const std::string CPUSET_LIBVIRT_PREFIX_OLD = "/machine/"; +const std::string CPUSET_LIBVIRT_SUFFIX_OLD = ".libvirt-lxc"; +const std::string CPUSET_LIBVIRT_PREFIX = "/machine.slice/machine-lxc\\x2d"; +const std::string CPUSET_LIBVIRT_SUFFIX = ".scope"; + +bool parseOldFormat(const std::string& cpuset, std::string& id) +{ + // '/machine/.libvirt-lxc' + if (!boost::starts_with(cpuset, CPUSET_LIBVIRT_PREFIX_OLD)) { + return false; + } + + if (!boost::ends_with(cpuset, CPUSET_LIBVIRT_SUFFIX_OLD)) { + return false; + } + + id.assign(cpuset, + CPUSET_LIBVIRT_PREFIX_OLD.size(), + cpuset.size() - CPUSET_LIBVIRT_PREFIX_OLD.size() - CPUSET_LIBVIRT_SUFFIX_OLD.size()); + return true; +} + +inline int unhex(char c) +{ + if (c >= '0' && c <= '9') { + return c - '0'; + } + if (c >= 'a' && c <= 'f') { + return c - 'a' + 10; + } + if (c >= 'A' && c <= 'F') { + return c - 'A' + 10; + } + return -1; +} + +void unescape(std::string& value) +{ + const size_t len = value.size(); + size_t inPos = 0; + size_t outPos = 0; + while (inPos < len) { + const char c = value[inPos++]; + if (c == '-') { + value[outPos++] = '/'; + } else if (c == '\\' && value[inPos] == 'x') { + const char a = unhex(value[inPos+1]); + const char b = unhex(value[inPos+2]); + value[outPos++] = (char) ((a << 4) | b); + inPos += 3; + } else { + value[outPos++] = c; + } + } + value.resize(outPos); +} + +bool parseNewFormat(const std::string& cpuset, std::string& id) +{ + // '/machine.slice/machine-lxc\x2d.scope' + if (!boost::starts_with(cpuset, CPUSET_LIBVIRT_PREFIX)) { + return false; + } + + if (!boost::ends_with(cpuset, CPUSET_LIBVIRT_SUFFIX)) { + return false; + } + + id = cpuset.substr(CPUSET_LIBVIRT_PREFIX.size(), + cpuset.size() - CPUSET_LIBVIRT_PREFIX.size() - CPUSET_LIBVIRT_SUFFIX.size()); + unescape(id); + return true; +} + +} // namespace + +bool parseContainerIdFromCpuSet(const std::string& cpuset, std::string& id) +{ + if (cpuset == CPUSET_HOST) { + id = "host"; + return true; + } + + return parseNewFormat(cpuset, id) || parseOldFormat(cpuset, id); +} + diff --git a/client/utils.hpp b/client/utils.hpp new file mode 100644 index 0000000..49b83c0 --- /dev/null +++ b/client/utils.hpp @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Contact: Piotr Bartosiewicz + * + * Licensed 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 + */ + +/** + * @file + * @author Piotr Bartosiewicz (p.bartosiewi@partner.samsung.com) + * @brief Utility functions declaration + */ + +#ifndef SECURITY_CONTAINERS_CLIENT_UTILS_HPP +#define SECURITY_CONTAINERS_CLIENT_UTILS_HPP + +#include + +bool parseContainerIdFromCpuSet(const std::string& cpuset, std::string& id); + +#endif // SECURITY_CONTAINERS_CLIENT_UTILS_HPP diff --git a/tests/unit_tests/client/ut-client-utils.cpp b/tests/unit_tests/client/ut-client-utils.cpp new file mode 100644 index 0000000..ac4c1fd --- /dev/null +++ b/tests/unit_tests/client/ut-client-utils.cpp @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Contact: Piotr Bartosiewicz + * + * Licensed 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 + */ + + +/** + * @file + * @author Piotr Bartosiewicz (p.bartosiewi@partner.samsung.com) + * @brief Unit tests of the client utils + */ + +#include +#include "ut.hpp" +#include + + +BOOST_AUTO_TEST_SUITE(ClientUtils) + +BOOST_AUTO_TEST_CASE(ParseContainerIdFromCpuSetTest) +{ + auto testBad = [](const std::string& input) { + std::string ret; + BOOST_CHECK(!parseContainerIdFromCpuSet(input, ret)); + }; + + auto testOK = [](const std::string& input, const std::string& expected) { + std::string ret; + BOOST_CHECK(parseContainerIdFromCpuSet(input, ret)); + BOOST_CHECK_EQUAL(expected, ret); + }; + + testBad(""); + testBad("/foo"); + + testOK("/", "host"); + testOK("/machine/a-b.libvirt-lxc", "a-b"); + testOK("/machine.slice/machine-lxc\\x2da\\x2db.scope", "a-b"); + testOK("/machine.slice/machine-lxc\\x2da-b.scope", "a/b"); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/tests/unit_tests/client/ut-client.cpp b/tests/unit_tests/client/ut-client.cpp index bbf2013..574be39 100644 --- a/tests/unit_tests/client/ut-client.cpp +++ b/tests/unit_tests/client/ut-client.cpp @@ -256,4 +256,41 @@ BOOST_AUTO_TEST_CASE(NotificationTest) } } +BOOST_AUTO_TEST_CASE(GetContainerIdByPidTest1) +{ + ScClient client = sc_client_create(); + ScString container; + ScStatus status = sc_get_container_id_by_pid(client, 1, &container); + BOOST_REQUIRE_EQUAL(SCCLIENT_SUCCESS, status); + + BOOST_CHECK_EQUAL(container, std::string("host")); + + sc_string_free(container); + sc_client_free(client); +} + +BOOST_AUTO_TEST_CASE(GetContainerIdByPidTest2) +{ + std::set ids; + + ScClient client = sc_client_create(); + for (int n = 0; n < 100000; ++n) { + ScString container; + ScStatus status = sc_get_container_id_by_pid(client, n, &container); + if (status == SCCLIENT_SUCCESS) { + ids.insert(container); + sc_string_free(container); + } else { + BOOST_WARN_MESSAGE(status == SCCLIENT_INVALID_ARGUMENT, sc_get_status_message(client)); + } + } + sc_client_free(client); + + BOOST_CHECK(ids.count("host") == 1); + + for (const auto& dbus : EXPECTED_DBUSES_STARTED) { + BOOST_CHECK(ids.count(dbus.first) == 1); + } +} + BOOST_AUTO_TEST_SUITE_END() -- 2.7.4 From ca9fe3b7e0eb6a308dd1215fd427bd97369f04ac Mon Sep 17 00:00:00 2001 From: Jan Olszak Date: Wed, 24 Sep 2014 16:12:13 +0200 Subject: [PATCH 15/16] Adjusting tests to the changed KVStore [Bug/Feature] Added isEmpty() and exists() functions [Cause] N/A [Solution] N/A [Verification] Build, install, run tests Change-Id: Ied7f469599cfdb31104e4f0bc1b67b8cbc2a2cc0 --- tests/unit_tests/config/ut-configuration.cpp | 22 ++++++++++++++++--- tests/unit_tests/config/ut-kvstore.cpp | 32 +++++++++++----------------- 2 files changed, 32 insertions(+), 22 deletions(-) diff --git a/tests/unit_tests/config/ut-configuration.cpp b/tests/unit_tests/config/ut-configuration.cpp index 1e98d22..b205339 100644 --- a/tests/unit_tests/config/ut-configuration.cpp +++ b/tests/unit_tests/config/ut-configuration.cpp @@ -48,11 +48,13 @@ struct TestConfig { }; int intVal; + std::vector intVector; SubSubConfig subSubObj; CONFIG_REGISTER ( intVal, + intVector, subSubObj ) }; @@ -63,6 +65,7 @@ struct TestConfig { double doubleVal; bool boolVal; + std::vector emptyIntVector; std::vector intVector; std::vector stringVector; std::vector doubleVector; @@ -78,6 +81,7 @@ struct TestConfig { doubleVal, boolVal, + emptyIntVector, intVector, stringVector, doubleVector, @@ -98,12 +102,13 @@ const std::string jsonTestString = "\"stringVal\": \"blah\", " "\"doubleVal\": -1.234000, " "\"boolVal\": true, " + "\"emptyIntVector\": [ ], " "\"intVector\": [ 1, 2, 3 ], " "\"stringVector\": [ \"a\", \"b\" ], " "\"doubleVector\": [ 0.000000, 1.000000, 2.000000 ], " - "\"subObj\": { \"intVal\": 54321, \"subSubObj\": { \"intVal\": 234 } }, " - "\"subVector\": [ { \"intVal\": 123, \"subSubObj\": { \"intVal\": 345 } }, " - "{ \"intVal\": 456, \"subSubObj\": { \"intVal\": 567 } } ] }"; + "\"subObj\": { \"intVal\": 54321, \"intVector\": [ 1, 2 ], \"subSubObj\": { \"intVal\": 234 } }, " + "\"subVector\": [ { \"intVal\": 123, \"intVector\": [ 3, 4 ], \"subSubObj\": { \"intVal\": 345 } }, " + "{ \"intVal\": 456, \"intVector\": [ 5, 6 ], \"subSubObj\": { \"intVal\": 567 } } ] }"; // Floating point tolerance as a number of rounding errors const int TOLERANCE = 1; @@ -121,6 +126,8 @@ BOOST_AUTO_TEST_CASE(FromStringTest) BOOST_CHECK_CLOSE(-1.234, testConfig.doubleVal, TOLERANCE); BOOST_CHECK_EQUAL(true, testConfig.boolVal); + BOOST_REQUIRE_EQUAL(0, testConfig.emptyIntVector.size()); + BOOST_REQUIRE_EQUAL(3, testConfig.intVector.size()); BOOST_CHECK_EQUAL(1, testConfig.intVector[0]); BOOST_CHECK_EQUAL(2, testConfig.intVector[1]); @@ -136,12 +143,21 @@ BOOST_AUTO_TEST_CASE(FromStringTest) BOOST_CHECK_CLOSE(2.0, testConfig.doubleVector[2], TOLERANCE); BOOST_CHECK_EQUAL(54321, testConfig.subObj.intVal); + BOOST_CHECK_EQUAL(2, testConfig.subObj.intVector.size()); + BOOST_CHECK_EQUAL(1, testConfig.subObj.intVector[0]); + BOOST_CHECK_EQUAL(2, testConfig.subObj.intVector[1]); + BOOST_CHECK_EQUAL(234, testConfig.subObj.subSubObj.intVal); BOOST_REQUIRE_EQUAL(2, testConfig.subVector.size()); BOOST_CHECK_EQUAL(123, testConfig.subVector[0].intVal); BOOST_CHECK_EQUAL(456, testConfig.subVector[1].intVal); BOOST_CHECK_EQUAL(345, testConfig.subVector[0].subSubObj.intVal); BOOST_CHECK_EQUAL(567, testConfig.subVector[1].subSubObj.intVal); + BOOST_CHECK_EQUAL(3, testConfig.subVector[0].intVector[0]); + BOOST_CHECK_EQUAL(5, testConfig.subVector[1].intVector[0]); + BOOST_CHECK_EQUAL(4, testConfig.subVector[0].intVector[1]); + BOOST_CHECK_EQUAL(6, testConfig.subVector[1].intVector[1]); + } diff --git a/tests/unit_tests/config/ut-kvstore.cpp b/tests/unit_tests/config/ut-kvstore.cpp index 66efc2b..2c9a998 100644 --- a/tests/unit_tests/config/ut-kvstore.cpp +++ b/tests/unit_tests/config/ut-kvstore.cpp @@ -114,33 +114,29 @@ BOOST_AUTO_TEST_CASE(EscapedCharactersTest) std::string HARD_KEY = "[" + KEY; BOOST_CHECK_NO_THROW(c.set(HARD_KEY, "A")); BOOST_CHECK_NO_THROW(c.set(KEY, "B")); - BOOST_CHECK_EQUAL(c.count(HARD_KEY), 1); - BOOST_CHECK_EQUAL(c.count(KEY), 1); - BOOST_CHECK_EQUAL(c.size(), 2); + BOOST_CHECK(c.exists(HARD_KEY)); + BOOST_CHECK(c.exists(KEY)); BOOST_CHECK_NO_THROW(c.clear()); HARD_KEY = "]" + KEY; BOOST_CHECK_NO_THROW(c.set(HARD_KEY, "A")); BOOST_CHECK_NO_THROW(c.set(KEY, "B")); - BOOST_CHECK_EQUAL(c.count(HARD_KEY), 1); - BOOST_CHECK_EQUAL(c.count(KEY), 1); - BOOST_CHECK_EQUAL(c.size(), 2); + BOOST_CHECK(c.exists(HARD_KEY)); + BOOST_CHECK(c.exists(KEY)); BOOST_CHECK_NO_THROW(c.clear()); HARD_KEY = "?" + KEY; BOOST_CHECK_NO_THROW(c.set(HARD_KEY, "A")); BOOST_CHECK_NO_THROW(c.set(KEY, "B")); - BOOST_CHECK_EQUAL(c.count(HARD_KEY), 1); - BOOST_CHECK_EQUAL(c.count(KEY), 1); - BOOST_CHECK_EQUAL(c.size(), 2); + BOOST_CHECK(c.exists(HARD_KEY)); + BOOST_CHECK(c.exists(KEY)); BOOST_CHECK_NO_THROW(c.clear()); HARD_KEY = "*" + KEY; BOOST_CHECK_NO_THROW(c.set(HARD_KEY, "A")); BOOST_CHECK_NO_THROW(c.set(KEY, "B")); - BOOST_CHECK_EQUAL(c.count(HARD_KEY), 1); - BOOST_CHECK_EQUAL(c.count(KEY), 1); - BOOST_CHECK_EQUAL(c.size(), 2); + BOOST_CHECK(c.exists(HARD_KEY)); + BOOST_CHECK(c.exists(KEY)); } namespace { @@ -154,11 +150,11 @@ void testSingleValue(Fixture& f, const A& a, const B& b) // Update BOOST_CHECK_NO_THROW(f.c.set(KEY, b)); BOOST_CHECK_EQUAL(f.c.get(KEY), b); - BOOST_CHECK_EQUAL(f.c.count(KEY), 1); + BOOST_CHECK(f.c.exists(KEY)); // Remove BOOST_CHECK_NO_THROW(f.c.remove(KEY)); - BOOST_CHECK_EQUAL(f.c.count(KEY), 0); + BOOST_CHECK(!f.c.exists(KEY)); BOOST_CHECK_THROW(f.c.get(KEY), ConfigException); } } // namespace @@ -182,8 +178,6 @@ void setVector(Fixture& f, std::vector vec) BOOST_CHECK_NO_THROW(f.c.set(KEY, vec)); BOOST_CHECK_NO_THROW(storedVec = f.c.get >(KEY)) BOOST_CHECK_EQUAL_COLLECTIONS(storedVec.begin(), storedVec.end(), vec.begin(), vec.end()); - BOOST_CHECK_EQUAL(f.c.count(KEY), vec.size()); - BOOST_CHECK_EQUAL(f.c.size(), vec.size()); } template @@ -199,8 +193,8 @@ void testVectorOfValues(Fixture& f, // Remove BOOST_CHECK_NO_THROW(f.c.remove(KEY)); - BOOST_CHECK_EQUAL(f.c.count(KEY), 0); - BOOST_CHECK_EQUAL(f.c.size(), 0); + BOOST_CHECK(!f.c.exists(KEY)); + BOOST_CHECK(f.c.isEmpty()); BOOST_CHECK_THROW(f.c.get >(KEY), ConfigException); BOOST_CHECK_THROW(f.c.get(KEY), ConfigException); } @@ -221,7 +215,7 @@ BOOST_AUTO_TEST_CASE(ClearTest) std::vector vec = {"A", "B"}; BOOST_CHECK_NO_THROW(c.set(KEY, vec)); BOOST_CHECK_NO_THROW(c.clear()); - BOOST_CHECK_EQUAL(c.size(), 0); + BOOST_CHECK(c.isEmpty()); BOOST_CHECK_NO_THROW(c.remove(KEY)); BOOST_CHECK_THROW(c.get>(KEY), ConfigException); -- 2.7.4 From 2d2f8fe00f8c450895a2ef67a698746294d25a0b Mon Sep 17 00:00:00 2001 From: Lukasz Kostyra Date: Thu, 25 Sep 2014 11:59:58 +0200 Subject: [PATCH 16/16] Implement switchingSequenceMonitorNotify and add VT switching support [Feature] switchingSequenceMonitorNotify function implementation and module to handle VT switching [Cause] Nothing happened when user provided input sequence to Input Monitor [Solution] Implemented switchingSequenceMonitorNotify and added VT switching to function ContainersManager::focus. [Verification] Build, install, run unit tests. Tests (especially FocusTest) should pass. Change-Id: Ie4aa7d1679bfaa5a0fdfaf238ebc14a3b8150006 --- CMakeLists.txt | 4 + common/utils/img.cpp | 2 +- common/utils/img.hpp | 2 +- common/utils/vt.cpp | 86 ++++++++++++++++++++++ common/utils/vt.hpp | 36 +++++++++ packaging/security-containers.spec | 7 +- server/CMakeLists.txt | 2 +- server/configs/containers/business.conf | 3 +- server/configs/containers/private.conf | 3 +- server/container-config.hpp | 6 ++ server/container.cpp | 12 +++ server/container.hpp | 7 ++ server/containers-manager.cpp | 28 ++++++- server/containers-manager.hpp | 6 ++ server/server.cpp | 11 ++- .../ut-client/containers/console1-dbus.conf | 1 + .../ut-client/containers/console2-dbus.conf | 1 + .../ut-client/containers/console3-dbus.conf | 1 + .../ut-container-admin/containers/buggy.conf.in | 1 + .../ut-container-admin/containers/missing.conf | 1 + .../containers/test-no-shutdown.conf.in | 1 + .../ut-container-admin/containers/test.conf.in | 1 + .../configs/ut-container/containers/buggy.conf | 1 + .../configs/ut-container/containers/test-dbus.conf | 1 + .../configs/ut-container/containers/test.conf | 1 + .../containers/console1-dbus.conf | 1 + .../ut-containers-manager/containers/console1.conf | 1 + .../containers/console2-dbus.conf | 1 + .../ut-containers-manager/containers/console2.conf | 1 + .../containers/console3-dbus.conf | 1 + .../ut-containers-manager/containers/console3.conf | 1 + .../ut-containers-manager/templates/template.conf | 1 + .../ut-network-admin/containers/buggy.conf.in | 1 + .../ut-network-admin/containers/missing.conf | 1 + .../ut-network-admin/containers/test.conf.in | 1 + .../configs/ut-server/containers/container1.conf | 1 + .../configs/ut-server/containers/container2.conf | 1 + .../configs/ut-server/containers/container3.conf | 1 + 38 files changed, 228 insertions(+), 10 deletions(-) create mode 100644 common/utils/vt.cpp create mode 100644 common/utils/vt.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 9cb880a..c8e74c6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -72,11 +72,15 @@ ENDIF(NOT DEFINED INPUT_EVENT_GROUP) IF(NOT DEFINED DISK_GROUP) SET(DISK_GROUP "disk") ENDIF(NOT DEFINED DISK_GROUP) +IF(NOT DEFINED TTY_GROUP) + SET(TTY_GROUP "tty") +ENDIF(NOT DEFINED TTY_GROUP) ADD_DEFINITIONS(-DSECURITY_CONTAINERS_USER="${SECURITY_CONTAINERS_USER}") ADD_DEFINITIONS(-DLIBVIRT_GROUP="${LIBVIRT_GROUP}") ADD_DEFINITIONS(-DINPUT_EVENT_GROUP="${INPUT_EVENT_GROUP}") ADD_DEFINITIONS(-DDISK_GROUP="${DISK_GROUP}") +ADD_DEFINITIONS(-DTTY_GROUP="${TTY_GROUP}") ## Python packages directory ################################################### diff --git a/common/utils/img.cpp b/common/utils/img.cpp index 4d7de88..bc77491 100644 --- a/common/utils/img.cpp +++ b/common/utils/img.cpp @@ -17,7 +17,7 @@ */ /** - * @file img.hpp + * @file * @author Lukasz Kostyra (l.kostyra@samsung.com) * @brief Image utility functions declaration */ diff --git a/common/utils/img.hpp b/common/utils/img.hpp index d42300e..db47cc6 100644 --- a/common/utils/img.hpp +++ b/common/utils/img.hpp @@ -17,7 +17,7 @@ */ /** - * @file img.hpp + * @file * @author Lukasz Kostyra (l.kostyra@samsung.com) * @brief Image utility functions declaration */ diff --git a/common/utils/vt.cpp b/common/utils/vt.cpp new file mode 100644 index 0000000..22a697e --- /dev/null +++ b/common/utils/vt.cpp @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Contact: Lukasz Kostyra + * + * Licensed 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 + */ + +/** + * @file + * @author Lukasz Kostyra (l.kostyra@samsung.com) + * @brief VT-related utility functions + */ + +#include "config.hpp" +#include "utils/vt.hpp" +#include "logger/logger.hpp" + +#include +#include +#include +#include +#include +#include + +namespace { + +const std::string TTY_DEV = "/dev/tty0"; + +} // namespace + +namespace security_containers { +namespace utils { + +bool activateVT(const int& vt) +{ + int consoleFD = ::open(TTY_DEV.c_str(), O_WRONLY); + if (consoleFD < 0) { + LOGE("console open failed: " << errno << " (" << strerror(errno) << ")"); + return false; + } + + struct vt_stat vtstat; + vtstat.v_active = 0; + if (::ioctl(consoleFD, VT_GETSTATE, &vtstat)) { + LOGE("Failed to get vt state: " << errno << " (" << strerror(errno) << ")"); + ::close(consoleFD); + return false; + } + + if (vtstat.v_active == vt) { + LOGW("vt" << vt << " is already active."); + ::close(consoleFD); + return true; + } + + // activate vt + if (::ioctl(consoleFD, VT_ACTIVATE, vt)) { + LOGE("Failed to activate vt" << vt << ": " << errno << " (" << strerror(errno) << ")"); + ::close(consoleFD); + return false; + } + + // wait until activation is finished + if (::ioctl(consoleFD, VT_WAITACTIVE, vt)) { + LOGE("Failed to wait for vt" << vt << " activation: " << errno << " (" << strerror(errno) << ")"); + ::close(consoleFD); + return false; + } + + ::close(consoleFD); + return true; +} + +} // namespace utils +} // namespace security_containers diff --git a/common/utils/vt.hpp b/common/utils/vt.hpp new file mode 100644 index 0000000..d285806 --- /dev/null +++ b/common/utils/vt.hpp @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Contact: Lukasz Kostyra + * + * Licensed 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 + */ + +/** + * @file + * @author Lukasz Kostyra (l.kostyra@samsung.com) + * @brief VT-related utility functions + */ + +#ifndef COMMON_UTILS_VT_HPP +#define COMMON_UTILS_VT_HPP + +namespace security_containers { +namespace utils { + +bool activateVT(const int& vt); + +} // namespace utils +} // namespace security_containers + +#endif // COMMON_UTILS_VT_HPP diff --git a/packaging/security-containers.spec b/packaging/security-containers.spec index 97bf4d5..fc1c806 100644 --- a/packaging/security-containers.spec +++ b/packaging/security-containers.spec @@ -7,6 +7,8 @@ %define input_event_group video # The group has access to /dev/loop* devices. %define disk_group disk +# The group that has write access to /dev/tty* devices. +%define tty_group tty Name: security-containers Version: 0.1.1 @@ -71,7 +73,8 @@ between them. A process from inside a container can request a switch of context -DSECURITY_CONTAINERS_USER=%{scs_user} \ -DLIBVIRT_GROUP=%{libvirt_group} \ -DINPUT_EVENT_GROUP=%{input_event_group} \ - -DDISK_GROUP=%{disk_group} + -DDISK_GROUP=%{disk_group} \ + -DTTY_GROUP=%{tty_group} make -k %{?jobs:-j%jobs} %install @@ -88,7 +91,7 @@ if [ $1 == 1 ]; then systemctl daemon-reload || : fi # set needed caps on the binary to allow restart without loosing them -setcap CAP_SYS_ADMIN,CAP_MAC_OVERRIDE+ei %{_bindir}/security-containers-server +setcap CAP_SYS_ADMIN,CAP_MAC_OVERRIDE,CAP_SYS_TTY_CONFIG+ei %{_bindir}/security-containers-server %preun # Stop the service before uninstall diff --git a/server/CMakeLists.txt b/server/CMakeLists.txt index 3293307..2237f52 100644 --- a/server/CMakeLists.txt +++ b/server/CMakeLists.txt @@ -45,4 +45,4 @@ ADD_SUBDIRECTORY(configs) INSTALL(TARGETS ${SERVER_CODENAME} DESTINATION bin) ## Set capabilities on server executable ####################################### -INSTALL(CODE "EXECUTE_PROCESS(COMMAND setcap CAP_SYS_ADMIN,CAP_MAC_OVERRIDE+ei \$ENV{DESTDIR}/${CMAKE_INSTALL_PREFIX}/bin/${SERVER_CODENAME})") +INSTALL(CODE "EXECUTE_PROCESS(COMMAND setcap CAP_SYS_ADMIN,CAP_MAC_OVERRIDE,CAP_SYS_TTY_CONFIG+ei \$ENV{DESTDIR}/${CMAKE_INSTALL_PREFIX}/bin/${SERVER_CODENAME})") diff --git a/server/configs/containers/business.conf b/server/configs/containers/business.conf index 1b3502a..600edb1 100644 --- a/server/configs/containers/business.conf +++ b/server/configs/containers/business.conf @@ -1,8 +1,9 @@ { "cpuQuotaForeground" : -1, - "cpuQuotaBackground" : 1000, + "cpuQuotaBackground" : 10000, "enableDbusIntegration" : true, "privilege" : 1, + "vt" : 3, "switchToDefaultAfterTimeout" : true, "config" : "../libvirt-config/business.xml", "networkConfig" : "../libvirt-config/business-network.xml", diff --git a/server/configs/containers/private.conf b/server/configs/containers/private.conf index 62c0f18..71d4bcb 100644 --- a/server/configs/containers/private.conf +++ b/server/configs/containers/private.conf @@ -1,8 +1,9 @@ { "cpuQuotaForeground" : -1, - "cpuQuotaBackground" : 1000, + "cpuQuotaBackground" : 10000, "enableDbusIntegration" : true, "privilege" : 10, + "vt" : 2, "switchToDefaultAfterTimeout" : true, "config" : "../libvirt-config/private.xml", "networkConfig" : "../libvirt-config/private-network.xml", diff --git a/server/container-config.hpp b/server/container-config.hpp index b506770..e0c6760 100644 --- a/server/container-config.hpp +++ b/server/container-config.hpp @@ -43,6 +43,11 @@ struct ContainerConfig { int privilege; /** + * Number of virtual terminal used by xserver inside container + */ + int vt; + + /** * Allow switching to default container after timeout. * Setting this to false will disable switching to default container after timeout. */ @@ -101,6 +106,7 @@ struct ContainerConfig { CONFIG_REGISTER ( privilege, + vt, switchToDefaultAfterTimeout, enableDbusIntegration, config, diff --git a/server/container.cpp b/server/container.cpp index 494b0ae..59328db 100644 --- a/server/container.cpp +++ b/server/container.cpp @@ -29,6 +29,7 @@ #include "logger/logger.hpp" #include "utils/paths.hpp" +#include "utils/vt.hpp" #include "config/manager.hpp" #include @@ -210,6 +211,17 @@ std::string Container::getDbusAddress() return mDbusAddress; } +bool Container::activateVT() +{ + Lock lock(mReconnectMutex); + + if (mConfig.vt >= 0) { + return utils::activateVT(mConfig.vt); + } + + return true; +} + void Container::goForeground() { Lock lock(mReconnectMutex); diff --git a/server/container.hpp b/server/container.hpp index f741464..6800f7a 100644 --- a/server/container.hpp +++ b/server/container.hpp @@ -101,6 +101,13 @@ public: void stop(); /** + * Activate this container's VT + * + * @return Was activation successful? + */ + bool activateVT(); + + /** * Setup this container to be put in the foreground. * I.e. set appropriate scheduler level. */ diff --git a/server/containers-manager.cpp b/server/containers-manager.cpp index 5dc909b..d8858ab 100644 --- a/server/containers-manager.cpp +++ b/server/containers-manager.cpp @@ -183,6 +183,11 @@ void ContainersManager::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); + if (!foregroundContainer->activateVT()) { + LOGE("Failed to activate containers VT. Aborting focus."); + return; + } + for (auto& container : mContainers) { LOGD(container.second->getId() << ": being sent to background"); container.second->goBackground(); @@ -240,10 +245,31 @@ std::string ContainersManager::getRunningForegroundContainerId() return std::string(); } +std::string ContainersManager::getNextToForegroundContainerId() +{ + // handles case where there is no next container + if (mContainers.size() < 2) { + return std::string(); + } + + for (auto it = mContainers.begin(); it != mContainers.end(); ++it) { + if (it->first == mConfig.foregroundId && + it->second->isRunning()) { + auto nextIt = std::next(it); + if (nextIt != mContainers.end()) { + return nextIt->first; + } + } + } + return mContainers.begin()->first; +} + void ContainersManager::switchingSequenceMonitorNotify() { LOGI("switchingSequenceMonitorNotify() called"); - // TODO: implement + + auto nextContainerId = getNextToForegroundContainerId(); + focus(nextContainerId); } diff --git a/server/containers-manager.hpp b/server/containers-manager.hpp index cd1194d..3cbf833 100644 --- a/server/containers-manager.hpp +++ b/server/containers-manager.hpp @@ -78,6 +78,12 @@ public: std::string getRunningForegroundContainerId(); /** + * @return id of next to currently focused/foreground container. If currently focused container + * is last in container map, id of fisrt container from map is returned. + */ + std::string getNextToForegroundContainerId(); + + /** * Set whether ContainersManager should detach containers on exit */ void setContainersDetachOnExit(); diff --git a/server/server.cpp b/server/server.cpp index 547d023..a9ad444 100644 --- a/server/server.cpp +++ b/server/server.cpp @@ -62,6 +62,10 @@ #error "DISK_GROUP must be defined!" #endif +#ifndef TTY_GROUP +#error "TTY_GROUP must be defined!" +#endif + extern char** environ; namespace security_containers { @@ -189,7 +193,7 @@ bool Server::prepareEnvironment(const std::string& configPath, bool runAsRoot) // INPUT_EVENT_GROUP provides access to /dev/input/event* devices used by InputMonitor. // DISK_GROUP provides access to /dev/loop* devices, needed when adding new container to copy // containers image - if (!utils::setSuppGroups({LIBVIRT_GROUP, INPUT_EVENT_GROUP, DISK_GROUP})) { + if (!utils::setSuppGroups({LIBVIRT_GROUP, INPUT_EVENT_GROUP, DISK_GROUP, TTY_GROUP})) { return false; } @@ -197,7 +201,10 @@ bool Server::prepareEnvironment(const std::string& configPath, bool runAsRoot) // NOTE: CAP_MAC_OVERRIDE is temporary and must be removed when "smack namespace" // is introduced. The capability is needed to allow modify SMACK labels of // "/var/run/containers//run" mount point. - return (runAsRoot || utils::dropRoot(uid, gid, {CAP_SYS_ADMIN, CAP_MAC_OVERRIDE})); + // CAP_SYS_TTY_CONFIG is needed to activate virtual terminals through ioctl calls + return (runAsRoot || utils::dropRoot(uid, gid, {CAP_SYS_ADMIN, + CAP_MAC_OVERRIDE, + CAP_SYS_TTY_CONFIG})); } diff --git a/tests/unit_tests/client/configs/ut-client/containers/console1-dbus.conf b/tests/unit_tests/client/configs/ut-client/containers/console1-dbus.conf index e16f7d6..b32dd81 100644 --- a/tests/unit_tests/client/configs/ut-client/containers/console1-dbus.conf +++ b/tests/unit_tests/client/configs/ut-client/containers/console1-dbus.conf @@ -1,5 +1,6 @@ { "privilege" : 20, + "vt" : -1, "switchToDefaultAfterTimeout" : true, "enableDbusIntegration" : true, "config" : "../libvirt-config/console1-dbus.xml", diff --git a/tests/unit_tests/client/configs/ut-client/containers/console2-dbus.conf b/tests/unit_tests/client/configs/ut-client/containers/console2-dbus.conf index 9aa8e51..3dda658 100644 --- a/tests/unit_tests/client/configs/ut-client/containers/console2-dbus.conf +++ b/tests/unit_tests/client/configs/ut-client/containers/console2-dbus.conf @@ -1,5 +1,6 @@ { "privilege" : 20, + "vt" : -1, "switchToDefaultAfterTimeout" : false, "enableDbusIntegration" : true, "config" : "../libvirt-config/console2-dbus.xml", diff --git a/tests/unit_tests/client/configs/ut-client/containers/console3-dbus.conf b/tests/unit_tests/client/configs/ut-client/containers/console3-dbus.conf index 09ef262..0128c09 100644 --- a/tests/unit_tests/client/configs/ut-client/containers/console3-dbus.conf +++ b/tests/unit_tests/client/configs/ut-client/containers/console3-dbus.conf @@ -1,5 +1,6 @@ { "privilege" : 20, + "vt" : -1, "switchToDefaultAfterTimeout" : true, "enableDbusIntegration" : true, "config" : "../libvirt-config/console3-dbus.xml", diff --git a/tests/unit_tests/server/configs/ut-container-admin/containers/buggy.conf.in b/tests/unit_tests/server/configs/ut-container-admin/containers/buggy.conf.in index 6a0ba2d..f9f553e 100644 --- a/tests/unit_tests/server/configs/ut-container-admin/containers/buggy.conf.in +++ b/tests/unit_tests/server/configs/ut-container-admin/containers/buggy.conf.in @@ -1,5 +1,6 @@ { "privilege" : 10, + "vt" : -1, "switchToDefaultAfterTimeout" : true, "enableDbusIntegration" : false, "config" : "@SC_TEST_CONFIG_INSTALL_DIR@/server/ut-container-admin/libvirt-config/buggy.xml", diff --git a/tests/unit_tests/server/configs/ut-container-admin/containers/missing.conf b/tests/unit_tests/server/configs/ut-container-admin/containers/missing.conf index 4184401..8312204 100644 --- a/tests/unit_tests/server/configs/ut-container-admin/containers/missing.conf +++ b/tests/unit_tests/server/configs/ut-container-admin/containers/missing.conf @@ -1,5 +1,6 @@ { "privilege" : 10, + "vt" : -1, "switchToDefaultAfterTimeout" : true, "enableDbusIntegration" : false, "config" : "/this/is/a/missing/file/path/missing.xml", diff --git a/tests/unit_tests/server/configs/ut-container-admin/containers/test-no-shutdown.conf.in b/tests/unit_tests/server/configs/ut-container-admin/containers/test-no-shutdown.conf.in index 995f5ff..135654c 100644 --- a/tests/unit_tests/server/configs/ut-container-admin/containers/test-no-shutdown.conf.in +++ b/tests/unit_tests/server/configs/ut-container-admin/containers/test-no-shutdown.conf.in @@ -1,5 +1,6 @@ { "privilege" : 10, + "vt" : -1, "switchToDefaultAfterTimeout" : true, "enableDbusIntegration" : false, "config" : "@SC_TEST_CONFIG_INSTALL_DIR@/server/ut-container-admin/libvirt-config/test-no-shutdown.xml", diff --git a/tests/unit_tests/server/configs/ut-container-admin/containers/test.conf.in b/tests/unit_tests/server/configs/ut-container-admin/containers/test.conf.in index a1d3d53..de566ea 100644 --- a/tests/unit_tests/server/configs/ut-container-admin/containers/test.conf.in +++ b/tests/unit_tests/server/configs/ut-container-admin/containers/test.conf.in @@ -1,5 +1,6 @@ { "privilege" : 10, + "vt" : -1, "switchToDefaultAfterTimeout" : true, "enableDbusIntegration" : false, "config" : "@SC_TEST_CONFIG_INSTALL_DIR@/server/ut-container-admin/libvirt-config/test.xml", diff --git a/tests/unit_tests/server/configs/ut-container/containers/buggy.conf b/tests/unit_tests/server/configs/ut-container/containers/buggy.conf index 5992433..d0a307e 100644 --- a/tests/unit_tests/server/configs/ut-container/containers/buggy.conf +++ b/tests/unit_tests/server/configs/ut-container/containers/buggy.conf @@ -1,5 +1,6 @@ { "privilege" : 10, + "vt" : -1, "switchToDefaultAfterTimeout" : true, "enableDbusIntegration" : false, "config" : "/missing/file/path/libvirt.xml", diff --git a/tests/unit_tests/server/configs/ut-container/containers/test-dbus.conf b/tests/unit_tests/server/configs/ut-container/containers/test-dbus.conf index 6301a5a..a272aa1 100644 --- a/tests/unit_tests/server/configs/ut-container/containers/test-dbus.conf +++ b/tests/unit_tests/server/configs/ut-container/containers/test-dbus.conf @@ -1,5 +1,6 @@ { "privilege" : 10, + "vt" : -1, "switchToDefaultAfterTimeout" : true, "enableDbusIntegration" : true, "config" : "../libvirt-config/test-dbus.xml", diff --git a/tests/unit_tests/server/configs/ut-container/containers/test.conf b/tests/unit_tests/server/configs/ut-container/containers/test.conf index 111d9ee..bed56de 100644 --- a/tests/unit_tests/server/configs/ut-container/containers/test.conf +++ b/tests/unit_tests/server/configs/ut-container/containers/test.conf @@ -1,5 +1,6 @@ { "privilege" : 10, + "vt" : -1, "switchToDefaultAfterTimeout" : true, "enableDbusIntegration" : false, "config" : "../libvirt-config/test.xml", diff --git a/tests/unit_tests/server/configs/ut-containers-manager/containers/console1-dbus.conf b/tests/unit_tests/server/configs/ut-containers-manager/containers/console1-dbus.conf index e16f7d6..b32dd81 100644 --- a/tests/unit_tests/server/configs/ut-containers-manager/containers/console1-dbus.conf +++ b/tests/unit_tests/server/configs/ut-containers-manager/containers/console1-dbus.conf @@ -1,5 +1,6 @@ { "privilege" : 20, + "vt" : -1, "switchToDefaultAfterTimeout" : true, "enableDbusIntegration" : true, "config" : "../libvirt-config/console1-dbus.xml", diff --git a/tests/unit_tests/server/configs/ut-containers-manager/containers/console1.conf b/tests/unit_tests/server/configs/ut-containers-manager/containers/console1.conf index be47df6..884e56d 100644 --- a/tests/unit_tests/server/configs/ut-containers-manager/containers/console1.conf +++ b/tests/unit_tests/server/configs/ut-containers-manager/containers/console1.conf @@ -1,5 +1,6 @@ { "privilege" : 20, + "vt" : -1, "switchToDefaultAfterTimeout" : true, "enableDbusIntegration" : false, "config" : "../libvirt-config/console1.xml", diff --git a/tests/unit_tests/server/configs/ut-containers-manager/containers/console2-dbus.conf b/tests/unit_tests/server/configs/ut-containers-manager/containers/console2-dbus.conf index 9aa8e51..3dda658 100644 --- a/tests/unit_tests/server/configs/ut-containers-manager/containers/console2-dbus.conf +++ b/tests/unit_tests/server/configs/ut-containers-manager/containers/console2-dbus.conf @@ -1,5 +1,6 @@ { "privilege" : 20, + "vt" : -1, "switchToDefaultAfterTimeout" : false, "enableDbusIntegration" : true, "config" : "../libvirt-config/console2-dbus.xml", diff --git a/tests/unit_tests/server/configs/ut-containers-manager/containers/console2.conf b/tests/unit_tests/server/configs/ut-containers-manager/containers/console2.conf index 4c88170..9928914 100644 --- a/tests/unit_tests/server/configs/ut-containers-manager/containers/console2.conf +++ b/tests/unit_tests/server/configs/ut-containers-manager/containers/console2.conf @@ -1,5 +1,6 @@ { "privilege" : 10, + "vt" : -1, "switchToDefaultAfterTimeout" : true, "enableDbusIntegration" : false, "config" : "../libvirt-config/console2.xml", diff --git a/tests/unit_tests/server/configs/ut-containers-manager/containers/console3-dbus.conf b/tests/unit_tests/server/configs/ut-containers-manager/containers/console3-dbus.conf index 09ef262..0128c09 100644 --- a/tests/unit_tests/server/configs/ut-containers-manager/containers/console3-dbus.conf +++ b/tests/unit_tests/server/configs/ut-containers-manager/containers/console3-dbus.conf @@ -1,5 +1,6 @@ { "privilege" : 20, + "vt" : -1, "switchToDefaultAfterTimeout" : true, "enableDbusIntegration" : true, "config" : "../libvirt-config/console3-dbus.xml", diff --git a/tests/unit_tests/server/configs/ut-containers-manager/containers/console3.conf b/tests/unit_tests/server/configs/ut-containers-manager/containers/console3.conf index d6bc429..8a31b50 100644 --- a/tests/unit_tests/server/configs/ut-containers-manager/containers/console3.conf +++ b/tests/unit_tests/server/configs/ut-containers-manager/containers/console3.conf @@ -1,5 +1,6 @@ { "privilege" : 15, + "vt" : -1, "switchToDefaultAfterTimeout" : true, "enableDbusIntegration" : false, "config" : "../libvirt-config/console3.xml", diff --git a/tests/unit_tests/server/configs/ut-containers-manager/templates/template.conf b/tests/unit_tests/server/configs/ut-containers-manager/templates/template.conf index 40dcacc..aeed716 100644 --- a/tests/unit_tests/server/configs/ut-containers-manager/templates/template.conf +++ b/tests/unit_tests/server/configs/ut-containers-manager/templates/template.conf @@ -1,5 +1,6 @@ { "privilege" : 20, + "vt" : -1, "switchToDefaultAfterTimeout" : true, "config" : "../libvirt-config/~NAME~.xml", "networkConfig" : "../libvirt-config/~NAME~-network.xml", diff --git a/tests/unit_tests/server/configs/ut-network-admin/containers/buggy.conf.in b/tests/unit_tests/server/configs/ut-network-admin/containers/buggy.conf.in index 414b920..695ed15 100644 --- a/tests/unit_tests/server/configs/ut-network-admin/containers/buggy.conf.in +++ b/tests/unit_tests/server/configs/ut-network-admin/containers/buggy.conf.in @@ -1,5 +1,6 @@ { "privilege" : 10, + "vt" : -1, "switchToDefaultAfterTimeout" : true, "enableDbusIntegration" : false, "config" : "", diff --git a/tests/unit_tests/server/configs/ut-network-admin/containers/missing.conf b/tests/unit_tests/server/configs/ut-network-admin/containers/missing.conf index 13ccc44..76492bb 100644 --- a/tests/unit_tests/server/configs/ut-network-admin/containers/missing.conf +++ b/tests/unit_tests/server/configs/ut-network-admin/containers/missing.conf @@ -1,5 +1,6 @@ { "privilege" : 10, + "vt" : -1, "switchToDefaultAfterTimeout" : true, "enableDbusIntegration" : false, "config" : "", diff --git a/tests/unit_tests/server/configs/ut-network-admin/containers/test.conf.in b/tests/unit_tests/server/configs/ut-network-admin/containers/test.conf.in index be65ee2..990da9a 100644 --- a/tests/unit_tests/server/configs/ut-network-admin/containers/test.conf.in +++ b/tests/unit_tests/server/configs/ut-network-admin/containers/test.conf.in @@ -1,5 +1,6 @@ { "privilege" : 10, + "vt" : -1, "switchToDefaultAfterTimeout" : true, "enableDbusIntegration" : false, "config" : "", diff --git a/tests/unit_tests/server/configs/ut-server/containers/container1.conf b/tests/unit_tests/server/configs/ut-server/containers/container1.conf index 21fb52a..984e973 100644 --- a/tests/unit_tests/server/configs/ut-server/containers/container1.conf +++ b/tests/unit_tests/server/configs/ut-server/containers/container1.conf @@ -1,5 +1,6 @@ { "privilege" : 20, + "vt" : -1, "switchToDefaultAfterTimeout" : true, "enableDbusIntegration" : false, "config" : "../libvirt-config/container1.xml", diff --git a/tests/unit_tests/server/configs/ut-server/containers/container2.conf b/tests/unit_tests/server/configs/ut-server/containers/container2.conf index 6302a39..d340530 100644 --- a/tests/unit_tests/server/configs/ut-server/containers/container2.conf +++ b/tests/unit_tests/server/configs/ut-server/containers/container2.conf @@ -1,5 +1,6 @@ { "privilege" : 10, + "vt" : -1, "switchToDefaultAfterTimeout" : true, "enableDbusIntegration" : false, "config" : "../libvirt-config/container2.xml", diff --git a/tests/unit_tests/server/configs/ut-server/containers/container3.conf b/tests/unit_tests/server/configs/ut-server/containers/container3.conf index b445156..a9d9e97 100644 --- a/tests/unit_tests/server/configs/ut-server/containers/container3.conf +++ b/tests/unit_tests/server/configs/ut-server/containers/container3.conf @@ -1,5 +1,6 @@ { "privilege" : 15, + "vt" : -1, "switchToDefaultAfterTimeout" : true, "enableDbusIntegration" : false, "config" : "../libvirt-config/container3.xml", -- 2.7.4