From 40e9e5c6518f1821e406eb3877ed2fc8dee6f3b5 Mon Sep 17 00:00:00 2001
From: Piotr Bartosiewicz
Date: Tue, 18 Nov 2014 13:34:58 +0100
Subject: [PATCH 01/16] Lxc networking
[Bug/Feature] Add lxc network config. Remove dead network code.
[Cause] N/A
[Solution] N/A
[Verification] Build, install, run
Change-Id: I2883858dbd571a01c93f6cc8c6b47cffe970a42a
---
packaging/security-containers.spec | 1 +
server/configs/lxc-templates/business.sh | 34 ++++-
server/configs/lxc-templates/private.sh | 34 ++++-
server/container.cpp | 11 --
server/container.hpp | 3 -
server/network-admin.cpp | 152 ---------------------
server/network-admin.hpp | 83 -----------
tests/unit_tests/server/configs/CMakeLists.txt | 13 --
.../ut-network-admin/containers/buggy.conf.in | 11 --
.../ut-network-admin/containers/missing.conf | 11 --
.../ut-network-admin/containers/test.conf.in | 11 --
tests/unit_tests/server/ut-network-admin.cpp | 85 ------------
12 files changed, 67 insertions(+), 382 deletions(-)
delete mode 100644 server/network-admin.cpp
delete mode 100644 server/network-admin.hpp
delete mode 100644 tests/unit_tests/server/configs/ut-network-admin/containers/buggy.conf.in
delete mode 100644 tests/unit_tests/server/configs/ut-network-admin/containers/missing.conf
delete mode 100644 tests/unit_tests/server/configs/ut-network-admin/containers/test.conf.in
delete mode 100644 tests/unit_tests/server/ut-network-admin.cpp
diff --git a/packaging/security-containers.spec b/packaging/security-containers.spec
index 11e7c99..99c0d1d 100644
--- a/packaging/security-containers.spec
+++ b/packaging/security-containers.spec
@@ -28,6 +28,7 @@ BuildRequires: pkgconfig(glib-2.0)
BuildRequires: pkgconfig(libsystemd-journal)
BuildRequires: pkgconfig(sqlite3)
Requires(post): libcap-tools
+Requires: bridge-utils
%description
This package provides a daemon used to manage containers - start, stop and switch
diff --git a/server/configs/lxc-templates/business.sh b/server/configs/lxc-templates/business.sh
index 09d67ca..21f7d2e 100755
--- a/server/configs/lxc-templates/business.sh
+++ b/server/configs/lxc-templates/business.sh
@@ -19,6 +19,9 @@ do
esac
done
+br_name="virbr-${name}"
+sub_net="101" # TODO from param
+
# XXX assume rootfs if mounted from iso
# Prepare container configuration file
@@ -35,6 +38,35 @@ lxc.pts = 256
lxc.tty = 0
lxc.mount.auto = proc sys cgroup
-lxc.mount.entry = /var/run/containers/business/run var/run none rw,bind 0 0
+lxc.mount.entry = /var/run/containers/${name}/run var/run none rw,bind 0 0
+
+lxc.network.type = veth
+lxc.network.link = ${br_name}
+lxc.network.flags = up
+lxc.network.name = eth0
+lxc.network.veth.pair = veth-${name}
+lxc.network.ipv4.gateway = 10.0.${sub_net}.1
+lxc.network.ipv4 = 10.0.${sub_net}.2/24
+
+lxc.hook.pre-start = ${path}/pre-start.sh
+
+#lxc.loglevel = TRACE
+#lxc.logfile = /tmp/${name}.log
+EOF
+
+# prepare pre start hook
+cat <> ${path}/pre-start.sh
+if [ -z "\$(/usr/sbin/brctl show | /bin/grep -P "${br_name}\t")" ]
+then
+ /usr/sbin/brctl addbr ${br_name}
+ /usr/sbin/brctl setfd ${br_name} 0
+ /sbin/ifconfig ${br_name} 10.0.${sub_net}.1 netmask 255.255.255.0 up
+fi
+if [ -z "\$(/usr/sbin/iptables -t nat -S | /bin/grep MASQUERADE)" ]
+then
+ /bin/echo 1 > /proc/sys/net/ipv4/ip_forward
+ /usr/sbin/iptables -t nat -A POSTROUTING -s 10.0.0.0/16 ! -d 10.0.0.0/16 -j MASQUERADE
+fi
EOF
+chmod 755 ${path}/pre-start.sh
diff --git a/server/configs/lxc-templates/private.sh b/server/configs/lxc-templates/private.sh
index 731ff72..542093a 100755
--- a/server/configs/lxc-templates/private.sh
+++ b/server/configs/lxc-templates/private.sh
@@ -19,6 +19,9 @@ do
esac
done
+br_name="virbr-${name}"
+sub_net="102" # TODO from param
+
# XXX assume rootfs if mounted from iso
# Prepare container configuration file
@@ -35,6 +38,35 @@ lxc.pts = 256
lxc.tty = 0
lxc.mount.auto = proc sys cgroup
-lxc.mount.entry = /var/run/containers/private/run var/run none rw,bind 0 0
+lxc.mount.entry = /var/run/containers/${name}/run var/run none rw,bind 0 0
+
+lxc.network.type = veth
+lxc.network.link = ${br_name}
+lxc.network.flags = up
+lxc.network.name = eth0
+lxc.network.veth.pair = veth-${name}
+lxc.network.ipv4.gateway = 10.0.${sub_net}.1
+lxc.network.ipv4 = 10.0.${sub_net}.2/24
+
+lxc.hook.pre-start = ${path}/pre-start.sh
+
+#lxc.loglevel = TRACE
+#lxc.logfile = /tmp/${name}.log
+EOF
+
+# prepare pre start hook
+cat <> ${path}/pre-start.sh
+if [ -z "\$(/usr/sbin/brctl show | /bin/grep -P "${br_name}\t")" ]
+then
+ /usr/sbin/brctl addbr ${br_name}
+ /usr/sbin/brctl setfd ${br_name} 0
+ /sbin/ifconfig ${br_name} 10.0.${sub_net}.1 netmask 255.255.255.0 up
+fi
+if [ -z "\$(/usr/sbin/iptables -t nat -S | /bin/grep MASQUERADE)" ]
+then
+ /bin/echo 1 > /proc/sys/net/ipv4/ip_forward
+ /usr/sbin/iptables -t nat -A POSTROUTING -s 10.0.0.0/16 ! -d 10.0.0.0/16 -j MASQUERADE
+fi
EOF
+chmod 755 ${path}/pre-start.sh
diff --git a/server/container.cpp b/server/container.cpp
index 17d383e..3fe421f 100644
--- a/server/container.cpp
+++ b/server/container.cpp
@@ -66,18 +66,10 @@ Container::Container(const std::string& containersPath,
mPermittedToRecv.push_back(boost::regex(r));
}
- //const std::string baseConfigPath = utils::dirName(containerConfigPath);
- //mConfig.config = fs::absolute(mConfig.config, baseConfigPath).string();
- //mConfig.networkConfig = fs::absolute(mConfig.networkConfig, baseConfigPath).string();
- //mConfig.networkFilterConfig = fs::absolute(mConfig.networkFilterConfig,
- // baseConfigPath).string();
if (!mConfig.runMountPoint.empty()) {
mRunMountPoint = fs::absolute(mConfig.runMountPoint, baseRunMountPointPath).string();
}
- //LOGT("Creating Network Admin " << mConfig.networkConfig);
- mNetworkAdmin.reset(new NetworkAdmin(mConfig));
- //LOGT("Creating Container Admin " << mConfig.config);
mAdmin.reset(new ContainerAdmin(containersPath, lxcTemplatePrefix, mConfig));
}
@@ -127,7 +119,6 @@ void Container::start()
if (mConfig.enableDbusIntegration) {
mConnectionTransport.reset(new ContainerConnectionTransport(mRunMountPoint));
}
- mNetworkAdmin->start();
mAdmin->start();
if (mConfig.enableDbusIntegration) {
connect();
@@ -167,7 +158,6 @@ void Container::stop()
Lock lock(mReconnectMutex);
disconnect();
mAdmin->stop();
- mNetworkAdmin->stop();
mConnectionTransport.reset();
}
@@ -239,7 +229,6 @@ void Container::goBackground()
void Container::setDetachOnExit()
{
Lock lock(mReconnectMutex);
- mNetworkAdmin->setDetachOnExit();
mAdmin->setDetachOnExit();
if (mConnectionTransport) {
mConnectionTransport->setDetachOnExit();
diff --git a/server/container.hpp b/server/container.hpp
index 0fcd837..f4140b0 100644
--- a/server/container.hpp
+++ b/server/container.hpp
@@ -30,8 +30,6 @@
#include "container-admin.hpp"
#include "container-connection.hpp"
#include "container-connection-transport.hpp"
-#include "network-admin.hpp"
-
#include
#include
@@ -218,7 +216,6 @@ private:
std::vector mPermittedToSend;
std::vector mPermittedToRecv;
std::unique_ptr mConnectionTransport;
- std::unique_ptr mNetworkAdmin;
std::unique_ptr mAdmin;
std::unique_ptr mConnection;
std::thread mReconnectThread;
diff --git a/server/network-admin.cpp b/server/network-admin.cpp
deleted file mode 100644
index a649d48..0000000
--- a/server/network-admin.cpp
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- * 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 Implementation of class for administrating single network
- */
-
-#include "config.hpp"
-
-#include "network-admin.hpp"
-#include "exception.hpp"
-
-//#include "libvirt/helpers.hpp"
-#include "logger/logger.hpp"
-#include "utils/fs.hpp"
-
-#include
-
-
-namespace security_containers {
-
-namespace {
-
-//std::string getNetworkName(virNetworkPtr net)
-//{
-// assert(net);
-//
-// const char* name = virNetworkGetName(net);
-// if (name == nullptr) {
-// LOGE("Failed to get the network's id:\n"
-// << libvirt::libvirtFormatError());
-// throw ContainerOperationException();
-// }
-//
-// return name;
-//}
-
-} // namespace
-
-
-NetworkAdmin::NetworkAdmin(const ContainerConfig& config)
- : mConfig(config),
- //mNWFilter(utils::readFileContent(mConfig.networkFilterConfig)),
- //mNetwork(utils::readFileContent(mConfig.networkConfig)),
- mId("TODO"),//mId(getNetworkName(mNetwork.get())),
- mDetachOnExit(false)
-{
- LOGD(mId << ": Instantiating NetworkAdmin object");
-}
-
-
-NetworkAdmin::~NetworkAdmin()
-{
- LOGD(mId << ": Destroying NetworkAdmin object...");
- // Try to stop
- if (!mDetachOnExit) {
- try {
- stop();
- } catch (ServerException&) {
- LOGE(mId << ": Failed to stop the network");
- }
- }
-
- LOGD(mId << ": NetworkAdmin object destroyed");
-}
-
-
-const std::string& NetworkAdmin::getId() const
-{
- return mId;
-}
-
-
-void NetworkAdmin::start()
-{
-// assert(mNetwork);
-//
-// LOGD(mId << ": Starting...");
-// if (isActive()) {
-// LOGD(mId << ": Already running - nothing to do...");
-// return;
-// }
-//
-// if (virNetworkCreate(mNetwork.get()) < 0) {
-// LOGE(mId << ": Failed to start the network\n"
-// << libvirt::libvirtFormatError());
-// throw ContainerOperationException();
-// }
-//
-// LOGD(mId << ": Started");
-}
-
-
-void NetworkAdmin::stop()
-{
-// assert(mNetwork);
-//
-// LOGD(mId << ": Stopping procedure started...");
-// if (!isActive()) {
-// LOGD(mId << ": Already crashed/down/off - nothing to do");
-// return;
-// }
-//
-// if (virNetworkDestroy(mNetwork.get()) < 0) {
-// LOGE(mId << ": Failed to destroy the network\n"
-// << libvirt::libvirtFormatError());
-// throw ContainerOperationException();
-// }
-//
-// LOGD(mId << ": Stopping procedure ended");
-}
-
-
-bool NetworkAdmin::isActive()
-{
-// assert(mNetwork);
-// int ret = virNetworkIsActive(mNetwork.get());
-// if (ret < 0) {
-// LOGE(mId << ": Failed to get network state\n"
-// << libvirt::libvirtFormatError());
-// throw ContainerOperationException();
-// }
-// return ret > 0;
- return false;
-}
-
-
-void NetworkAdmin::setDetachOnExit()
-{
-// mDetachOnExit = true;
-// mNWFilter.setDetachOnExit();
-}
-
-
-} // namespace security_containers
diff --git a/server/network-admin.hpp b/server/network-admin.hpp
deleted file mode 100644
index 66a6f75..0000000
--- a/server/network-admin.hpp
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * 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 Declaration of the class for administrating single network
- */
-
-
-#ifndef SERVER_NETWORK_ADMIN_HPP
-#define SERVER_NETWORK_ADMIN_HPP
-
-#include "container-config.hpp"
-
-//#include "libvirt/network-filter.hpp"
-//#include "libvirt/network.hpp"
-
-
-namespace security_containers {
-
-
-class NetworkAdmin {
-
-public:
-
- NetworkAdmin(const ContainerConfig& config);
- virtual ~NetworkAdmin();
-
- /**
- * Get the network id
- */
- const std::string& getId() const;
-
- /**
- * Start network.
- */
- void start();
-
- /**
- * Stop network.
- */
- void stop();
-
- /**
- * @return Is the network active?
- */
- bool isActive();
-
- /**
- * Set whether container should be detached on exit.
- */
- void setDetachOnExit();
-
-
-private:
- const ContainerConfig& mConfig;
- //libvirt::LibvirtNWFilter mNWFilter;
- //libvirt::LibvirtNetwork mNetwork;
- const std::string mId;
- bool mDetachOnExit;
-};
-
-
-} // namespace security_containers
-
-
-#endif // SERVER_NETWORK_ADMIN_HPP
diff --git a/tests/unit_tests/server/configs/CMakeLists.txt b/tests/unit_tests/server/configs/CMakeLists.txt
index b3f8a70..17e10a2 100644
--- a/tests/unit_tests/server/configs/CMakeLists.txt
+++ b/tests/unit_tests/server/configs/CMakeLists.txt
@@ -31,8 +31,6 @@ FILE(GLOB container_container_CONF ut-container/containers/*.conf)
FILE(GLOB admin_container_CONF ut-container-admin/containers/*.conf)
-FILE(GLOB network_container_CONF ut-network-admin/containers/*.conf)
-
FILE(GLOB connection_CONF ut-container-connection/*.conf)
@@ -43,12 +41,6 @@ CONFIGURE_FILE(ut-server/buggy-daemon.conf.in
${CMAKE_BINARY_DIR}/ut-server/buggy-daemon.conf @ONLY)
FILE(GLOB server_manager_CONF_GEN ${CMAKE_BINARY_DIR}/ut-server/*.conf)
-CONFIGURE_FILE(ut-network-admin/containers/test.conf.in
- ${CMAKE_BINARY_DIR}/ut-network-admin/containers/test.conf @ONLY)
-CONFIGURE_FILE(ut-network-admin/containers/buggy.conf.in
- ${CMAKE_BINARY_DIR}/ut-network-admin/containers/buggy.conf @ONLY)
-FILE(GLOB network_container_CONF_GEN ${CMAKE_BINARY_DIR}/ut-network-admin/containers/*.conf)
-
CONFIGURE_FILE(ut-container/containers/test-dbus.conf.in
${CMAKE_BINARY_DIR}/ut-container/containers/test-dbus.conf @ONLY)
FILE(GLOB container_container_CONF_GEN ${CMAKE_BINARY_DIR}/ut-container/containers/*.conf)
@@ -103,11 +95,6 @@ INSTALL(FILES ${container_container_CONF_GEN}
INSTALL(FILES ${admin_container_CONF}
DESTINATION ${SC_TEST_CONFIG_INSTALL_DIR}/server/ut-container-admin/containers)
-INSTALL(FILES ${network_container_CONF}
- DESTINATION ${SC_TEST_CONFIG_INSTALL_DIR}/server/ut-network-admin/containers)
-INSTALL(FILES ${network_container_CONF_GEN}
- DESTINATION ${SC_TEST_CONFIG_INSTALL_DIR}/server/ut-network-admin/containers)
-
INSTALL(FILES ${connection_CONF}
DESTINATION ${SC_TEST_CONFIG_INSTALL_DIR}/server/ut-container-connection)
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
deleted file mode 100644
index f4be18d..0000000
--- a/tests/unit_tests/server/configs/ut-network-admin/containers/buggy.conf.in
+++ /dev/null
@@ -1,11 +0,0 @@
-{
- "privilege" : 10,
- "vt" : -1,
- "switchToDefaultAfterTimeout" : true,
- "enableDbusIntegration" : false,
- "cpuQuotaForeground" : -1,
- "cpuQuotaBackground" : 1000,
- "runMountPoint" : "",
- "permittedToSend" : [],
- "permittedToRecv" : []
-}
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
deleted file mode 100644
index f4be18d..0000000
--- a/tests/unit_tests/server/configs/ut-network-admin/containers/missing.conf
+++ /dev/null
@@ -1,11 +0,0 @@
-{
- "privilege" : 10,
- "vt" : -1,
- "switchToDefaultAfterTimeout" : true,
- "enableDbusIntegration" : false,
- "cpuQuotaForeground" : -1,
- "cpuQuotaBackground" : 1000,
- "runMountPoint" : "",
- "permittedToSend" : [],
- "permittedToRecv" : []
-}
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
deleted file mode 100644
index f4be18d..0000000
--- a/tests/unit_tests/server/configs/ut-network-admin/containers/test.conf.in
+++ /dev/null
@@ -1,11 +0,0 @@
-{
- "privilege" : 10,
- "vt" : -1,
- "switchToDefaultAfterTimeout" : true,
- "enableDbusIntegration" : false,
- "cpuQuotaForeground" : -1,
- "cpuQuotaBackground" : 1000,
- "runMountPoint" : "",
- "permittedToSend" : [],
- "permittedToRecv" : []
-}
diff --git a/tests/unit_tests/server/ut-network-admin.cpp b/tests/unit_tests/server/ut-network-admin.cpp
deleted file mode 100644
index f120ac6..0000000
--- a/tests/unit_tests/server/ut-network-admin.cpp
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * 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 NetworkAdmin class
- */
-
-//#include "config.hpp"
-//#include "ut.hpp"
-//
-//#include "network-admin.hpp"
-//
-//#include "utils/exception.hpp"
-////#include "libvirt/exception.hpp"
-//#include "config/manager.hpp"
-//
-//
-//using namespace security_containers;
-//
-//namespace {
-//
-//const std::string TEST_CONFIG_PATH = SC_TEST_CONFIG_INSTALL_DIR "/server/ut-network-admin/containers/test.conf";
-//const std::string BUGGY_CONFIG_PATH = SC_TEST_CONFIG_INSTALL_DIR "/server/ut-network-admin/containers/buggy.conf";
-//const std::string MISSING_CONFIG_PATH = SC_TEST_CONFIG_INSTALL_DIR "/server/ut-network-admin/containers/missing.conf";
-//
-//} // namespace
-//
-//
-//BOOST_AUTO_TEST_SUITE(NetworkAdminSuite)
-//
-//BOOST_AUTO_TEST_CASE(ConstructorDestructorTest)
-//{
-// ContainerConfig config;
-// config::loadFromFile(TEST_CONFIG_PATH, config);
-// std::unique_ptr admin;
-// BOOST_REQUIRE_NO_THROW(admin.reset(new NetworkAdmin(config)));
-// BOOST_REQUIRE_NO_THROW(admin.reset());
-//}
-//
-////BOOST_AUTO_TEST_CASE(BuggyConfigTest)
-////{
-//// ContainerConfig config;
-//// config::loadFromFile(BUGGY_CONFIG_PATH, config);
-//// BOOST_REQUIRE_THROW(NetworkAdmin na(config), LibvirtOperationException);
-////}
-//
-//BOOST_AUTO_TEST_CASE(MissingConfigTest)
-//{
-// ContainerConfig config;
-// config::loadFromFile(MISSING_CONFIG_PATH, config);
-// BOOST_REQUIRE_THROW(NetworkAdmin na(config), UtilsException);
-//}
-//
-//BOOST_AUTO_TEST_CASE(StartStopTest)
-//{
-// ContainerConfig config;
-// config::loadFromFile(TEST_CONFIG_PATH, config);
-// NetworkAdmin net(config);
-//
-// BOOST_CHECK(!net.isActive());
-// BOOST_CHECK_NO_THROW(net.start());
-// BOOST_CHECK(net.isActive());
-// BOOST_CHECK_NO_THROW(net.stop());
-// BOOST_CHECK(!net.isActive());
-//}
-//
-//BOOST_AUTO_TEST_SUITE_END()
--
2.7.4
From 1d05535e3b32d1b1451d90cd1090417e66e1d17c Mon Sep 17 00:00:00 2001
From: Mateusz Malicki
Date: Fri, 14 Nov 2014 16:38:16 +0100
Subject: [PATCH 02/16] Implement lookup_domain_by_id function in server,
client and cli
[Bug/Feature] Implement lookup_domain_by_id function in server, client and cli
[Cause] N/A
[Solution] N/A
[Verification] Build, run appropriate function (through cli)
Change-Id: I2908e760613532caadcc9c58a1d522d4ac7767c4
---
cli/command-line-interface.cpp | 45 ++++++++++++++++++++
cli/command-line-interface.hpp | 8 ++++
cli/main.cpp | 8 ++++
client/security-containers-client-impl.cpp | 67 ++++++++++++++++++++++++++++--
client/security-containers-client.h | 2 +-
server/common-dbus-definitions.hpp | 1 +
server/container.cpp | 5 +++
server/container.hpp | 5 +++
server/containers-manager.cpp | 34 +++++++++++++++
server/containers-manager.hpp | 1 +
server/host-connection.cpp | 15 +++++++
server/host-connection.hpp | 9 ++++
server/host-dbus-definitions.hpp | 5 +++
13 files changed, 201 insertions(+), 4 deletions(-)
diff --git a/cli/command-line-interface.cpp b/cli/command-line-interface.cpp
index f3768d0..d027e63 100644
--- a/cli/command-line-interface.cpp
+++ b/cli/command-line-interface.cpp
@@ -30,6 +30,7 @@
#include
#include
#include
+#include
using namespace std;
@@ -80,6 +81,37 @@ finish:
}
}
+ostream& operator<<(ostream& out, const VsmDomainState& state)
+{
+ const char* name;
+ switch (state) {
+ case STOPPED: name = "STOPPED"; break;
+ case STARTING: name = "STARTING"; break;
+ case RUNNING: name = "RUNNING"; break;
+ case STOPPING: name = "STOPPING"; break;
+ case ABORTING: name = "ABORTING"; break;
+ case FREEZING: name = "FREEZING"; break;
+ case FROZEN: name = "FROZEN"; break;
+ case THAWED: name = "THAWED"; break;
+ case LOCKED: name = "LOCKED"; break;
+ case MAX_STATE: name = "MAX_STATE"; break;
+ case ACTIVATING: name = "ACTIVATING"; break;
+ default: name = "MAX_STATE (ERROR)";
+ }
+
+ out << name;
+ return out;
+}
+
+ostream& operator<<(ostream& out, const VsmDomain& domain)
+{
+ out << "Name: " << domain->id
+ << "\nTerminal: " << domain->terminal
+ << "\nState: " << domain->state
+ << "\nRoot: " << domain->rootfs_path;
+ return out;
+}
+
} // namespace
void CommandLineInterface::printUsage(std::ostream& out) const
@@ -122,5 +154,18 @@ void create_domain(int pos, int argc, const char** argv)
one_shot(bind(vsm_create_domain, _1, argv[pos + 1], nullptr));
}
+void lookup_domain_by_id(int pos, int argc, const char** argv)
+{
+ using namespace std::placeholders;
+ if (argc <= pos + 1) {
+ throw runtime_error("Not enough parameters");
+ }
+
+ VsmDomain domain;
+ one_shot(bind(vsm_lookup_domain_by_id, _1, argv[pos + 1], &domain));
+ cout << domain << endl;
+ vsm_domain_free(domain);
+}
+
} // namespace cli
} // namespace security_containers
diff --git a/cli/command-line-interface.hpp b/cli/command-line-interface.hpp
index 27415c1..c254d84 100644
--- a/cli/command-line-interface.hpp
+++ b/cli/command-line-interface.hpp
@@ -110,6 +110,14 @@ void set_active_container(int pos, int argc, const char** argv);
*/
void create_domain(int pos, int argc, const char** argv);
+/**
+ * Parses command line arguments and call vsm_lookup_domain_by_id
+ *
+ * @see vsm_lookup_domain_by_id
+ */
+void lookup_domain_by_id(int pos, int argc, const char** argv);
+
+
} // namespace cli
} // namespace security_containers
diff --git a/cli/main.cpp b/cli/main.cpp
index 135385d..d701475 100644
--- a/cli/main.cpp
+++ b/cli/main.cpp
@@ -48,6 +48,14 @@ std::map commands = {
"Create and add container",
{{"container_id", "id container name"}}
}
+ },
+ {
+ "lookup_domain_by_id", {
+ lookup_domain_by_id,
+ "lookup_domain_by_id container_id",
+ "Prints informations about domain",
+ {{"container_id", "id container name"}}
+ }
}
};
diff --git a/client/security-containers-client-impl.cpp b/client/security-containers-client-impl.cpp
index 205a8b2..2fcc776 100644
--- a/client/security-containers-client-impl.cpp
+++ b/client/security-containers-client-impl.cpp
@@ -88,6 +88,50 @@ void toBasic(GVariant* in, char** str)
*str = buf;
}
+VsmDomainState getDomainState(const char* state)
+{
+ if (strcmp(state, "STOPPED") == 0) {
+ return STOPPED;
+ } else if (strcmp(state, "STARTING") == 0) {
+ return STARTING;
+ } else if (strcmp(state, "RUNNING") == 0) {
+ return RUNNING;
+ } else if (strcmp(state, "STOPPING") == 0) {
+ return STOPPING;
+ } else if (strcmp(state, "ABORTING") == 0) {
+ return ABORTING;
+ } else if (strcmp(state, "FREEZING") == 0) {
+ return FREEZING;
+ } else if (strcmp(state, "FROZEN") == 0) {
+ return FROZEN;
+ } else if (strcmp(state, "THAWED") == 0) {
+ return THAWED;
+ } else if (strcmp(state, "LOCKED") == 0) {
+ return LOCKED;
+ } else if (strcmp(state, "MAX_STATE") == 0) {
+ return MAX_STATE;
+ } else if (strcmp(state, "ACTIVATING") == 0) {
+ return ACTIVATING;
+ }
+ assert(!"UNKNOWN STATE");
+ return (VsmDomainState)-1;
+}
+
+void toBasic(GVariant* in, VsmDomain* domain)
+{
+ const char* id;
+ const char* path;
+ const char* state;
+ int terminal;
+ VsmDomain vsmDomain = (VsmDomain)malloc(sizeof(*vsmDomain));
+ g_variant_get(in, "(siss)", &id, &terminal, &state, &path);
+ vsmDomain->id = strdup(id);
+ vsmDomain->terminal = terminal;
+ vsmDomain->state = getDomainState(state);
+ vsmDomain->rootfs_path = strdup(path);
+ *domain = vsmDomain;
+}
+
template
void toArray(GVariant* in, T** scArray)
{
@@ -360,10 +404,27 @@ VsmStatus Client::vsm_lookup_domain_by_pid(int pid, VsmString* id) noexcept
return vsm_get_status();
}
-VsmStatus Client::vsm_lookup_domain_by_id(const char*, VsmDomain*) noexcept
+VsmStatus Client::vsm_lookup_domain_by_id(const char* id, VsmDomain* domain) noexcept
{
- mStatus = Status(VSMCLIENT_OTHER_ERROR, "Not implemented");
- return vsm_get_status();
+ assert(id);
+ assert(domain);
+
+ GVariant* out;
+ GVariant* args_in = g_variant_new("(s)", id);
+ VsmStatus ret = callMethod(HOST_INTERFACE,
+ api::host::METHOD_GET_CONTAINER_INFO,
+ args_in,
+ "((siss))",
+ &out);
+ if (ret != VSMCLIENT_SUCCESS) {
+ return ret;
+ }
+ GVariant* unpacked;
+ g_variant_get(out, "(*)", &unpacked);
+ toBasic(unpacked, domain);
+ g_variant_unref(unpacked);
+ g_variant_unref(out);
+ return ret;
}
VsmStatus Client::vsm_lookup_domain_by_terminal_id(int, VsmString*) noexcept
diff --git a/client/security-containers-client.h b/client/security-containers-client.h
index 6419870..ee16e01 100644
--- a/client/security-containers-client.h
+++ b/client/security-containers-client.h
@@ -338,7 +338,7 @@ VsmStatus vsm_lookup_domain_by_pid(VsmClient client, int pid, VsmString* id);
* @param[in] id domain name
* @param[out] domain domain informations
* @return status of this function call
- * @remark Use @p vsm_doamin_free() to free memory occupied by @p domain
+ * @remark Use @p vsm_domain_free() to free memory occupied by @p domain
*/
VsmStatus vsm_lookup_domain_by_id(VsmClient client, const char* id, VsmDomain* domain);
diff --git a/server/common-dbus-definitions.hpp b/server/common-dbus-definitions.hpp
index 8821b34..14bb037 100644
--- a/server/common-dbus-definitions.hpp
+++ b/server/common-dbus-definitions.hpp
@@ -33,6 +33,7 @@ namespace api {
const std::string ERROR_FORBIDDEN = "org.tizen.containers.Error.Forbidden";
const std::string ERROR_FORWARDED = "org.tizen.containers.Error.Forwarded";
const std::string ERROR_UNKNOWN_ID = "org.tizen.containers.Error.UnknownId";
+const std::string ERROR_INTERNAL = "org.tizen.containers.Error.Internal";
const std::string METHOD_PROXY_CALL = "ProxyCall";
diff --git a/server/container.cpp b/server/container.cpp
index 59328db..f4ac2cc 100644
--- a/server/container.cpp
+++ b/server/container.cpp
@@ -211,6 +211,11 @@ std::string Container::getDbusAddress()
return mDbusAddress;
}
+int Container::getVT() const
+{
+ return mConfig.vt;
+}
+
bool Container::activateVT()
{
Lock lock(mReconnectMutex);
diff --git a/server/container.hpp b/server/container.hpp
index 6800f7a..46fafec 100644
--- a/server/container.hpp
+++ b/server/container.hpp
@@ -204,6 +204,11 @@ public:
*/
std::string getDbusAddress();
+ /**
+ * Get id of VT
+ */
+ int getVT() const;
+
private:
ContainerConfig mConfig;
std::vector mPermittedToSend;
diff --git a/server/containers-manager.cpp b/server/containers-manager.cpp
index d0d0a36..466a4e6 100644
--- a/server/containers-manager.cpp
+++ b/server/containers-manager.cpp
@@ -102,6 +102,9 @@ ContainersManager::ContainersManager(const std::string& managerConfigPath): mDet
mHostConnection.setGetActiveContainerIdCallback(bind(&ContainersManager::handleGetActiveContainerIdCall,
this, _1));
+ mHostConnection.setGetContainerInfoCallback(bind(&ContainersManager::handleGetContainerInfoCall,
+ this, _1, _2));
+
mHostConnection.setSetActiveContainerCallback(bind(&ContainersManager::handleSetActiveContainerCall,
this, _1, _2));
@@ -497,6 +500,37 @@ void ContainersManager::handleGetActiveContainerIdCall(dbus::MethodResultBuilder
}
}
+void ContainersManager::handleGetContainerInfoCall(const std::string& id,
+ dbus::MethodResultBuilder::Pointer result)
+{
+ LOGI("GetContainerInfo call");
+ if (mContainers.count(id) == 0) {
+ LOGE("No container with id=" << id);
+ result->setError(api::ERROR_UNKNOWN_ID, "No such container id");
+ return;
+ }
+ const auto& container = mContainers[id];
+ const char* state;
+ //TODO: Use the lookup map.
+ if (container->isRunning()) {
+ state = "RUNNING";
+ } else if (container->isStopped()) {
+ state = "STOPPED";
+ } else if (container->isPaused()) {
+ state = "FROZEN";
+ } else {
+ LOGE("Unrecognized state of container id=" << id);
+ result->setError(api::ERROR_INTERNAL, "Unrecognized state of container");
+ return;
+ }
+ const std::string rootPath = boost::filesystem::absolute(id, mConfig.containersPath).string();
+ result->set(g_variant_new("((siss))",
+ id.c_str(),
+ container->getVT(),
+ state,
+ rootPath.c_str()));
+}
+
void ContainersManager::handleSetActiveContainerCall(const std::string& id,
dbus::MethodResultBuilder::Pointer result)
{
diff --git a/server/containers-manager.hpp b/server/containers-manager.hpp
index 3cbf833..d2efce1 100644
--- a/server/containers-manager.hpp
+++ b/server/containers-manager.hpp
@@ -124,6 +124,7 @@ private:
void handleDbusStateChanged(const std::string& containerId, const std::string& dbusAddress);
void handleGetContainerIdsCall(dbus::MethodResultBuilder::Pointer result);
void handleGetActiveContainerIdCall(dbus::MethodResultBuilder::Pointer result);
+ void handleGetContainerInfoCall(const std::string& id, dbus::MethodResultBuilder::Pointer result);
void handleSetActiveContainerCall(const std::string& id,
dbus::MethodResultBuilder::Pointer result);
void handleAddContainerCall(const std::string& id,
diff --git a/server/host-connection.cpp b/server/host-connection.cpp
index d25bee7..1b38a9c 100644
--- a/server/host-connection.cpp
+++ b/server/host-connection.cpp
@@ -125,6 +125,11 @@ void HostConnection::setGetActiveContainerIdCallback(const GetActiveContainerIdC
mGetActiveContainerIdCallback = callback;
}
+void HostConnection::setGetContainerInfoCallback(const GetContainerInfoCallback& callback)
+{
+ mGetContainerInfoCallback = callback;
+}
+
void HostConnection::setSetActiveContainerCallback(const SetActiveContainerCallback& callback)
{
mSetActiveContainerCallback = callback;
@@ -205,6 +210,16 @@ void HostConnection::onMessageCall(const std::string& objectPath,
return;
}
+ if (methodName == api::host::METHOD_GET_CONTAINER_INFO){
+ const gchar* id = NULL;
+ g_variant_get(parameters, "(&s)", &id);
+
+ if (mGetContainerInfoCallback) {
+ mGetContainerInfoCallback(id, result);
+ }
+ return;
+ }
+
if (methodName == api::host::METHOD_ADD_CONTAINER) {
const gchar* id = NULL;
g_variant_get(parameters, "(&s)", &id);
diff --git a/server/host-connection.hpp b/server/host-connection.hpp
index c5d1bcc..1dacd11 100644
--- a/server/host-connection.hpp
+++ b/server/host-connection.hpp
@@ -59,6 +59,9 @@ public:
)> GetActiveContainerIdCallback;
typedef std::function GetContainerInfoCallback;
+ typedef std::function SetActiveContainerCallback;
typedef std::function"
" "
" "
+ " "
+ " "
+ " "
+ " "
" "
" "
" "
--
2.7.4
From 20e2b2163f5de0b032fa8bdecfce0a46bba34825 Mon Sep 17 00:00:00 2001
From: Piotr Bartosiewicz
Date: Wed, 19 Nov 2014 13:37:16 +0100
Subject: [PATCH 03/16] Fix compilation problems
[Bug/Feature] Code does not build using older gcc
[Cause] N/A
[Solution] N/A
[Verification] Build
Change-Id: Ifd7dd7bce080ac16983a23d30585ace08a522f05
---
common/lxc/domain.cpp | 2 +-
tests/unit_tests/client/ut-client.cpp | 15 ++++++++++-----
tests/unit_tests/lxc/ut-domain.cpp | 3 ++-
tests/unit_tests/server/ut-container-admin.cpp | 6 +++++-
tests/unit_tests/server/ut-container.cpp | 6 +++++-
tests/unit_tests/server/ut-containers-manager.cpp | 15 +++++++++++----
tests/unit_tests/server/ut-server.cpp | 6 +++++-
7 files changed, 39 insertions(+), 14 deletions(-)
diff --git a/common/lxc/domain.cpp b/common/lxc/domain.cpp
index 57228c0..bc2e74b 100644
--- a/common/lxc/domain.cpp
+++ b/common/lxc/domain.cpp
@@ -195,7 +195,7 @@ bool LxcDomain::unfreeze()
bool LxcDomain::setRunLevel(int runLevel)
{
- auto callback = [](void* param) {
+ auto callback = [](void* param) -> int {
utils::RunLevel runLevel = *reinterpret_cast(param);
return utils::setRunLevel(runLevel) ? 0 : 1;
};
diff --git a/tests/unit_tests/client/ut-client.cpp b/tests/unit_tests/client/ut-client.cpp
index 9847a92..6e0aab0 100644
--- a/tests/unit_tests/client/ut-client.cpp
+++ b/tests/unit_tests/client/ut-client.cpp
@@ -56,14 +56,19 @@ struct Loop {
struct Fixture {
Loop loop;
- utils::ScopedDir mContainersPathGuard = CONTAINERS_PATH;
- utils::ScopedDir mRun1Guard = utils::ScopedDir("/tmp/ut-run1");
- utils::ScopedDir mRun2Guard = utils::ScopedDir("/tmp/ut-run2");
- utils::ScopedDir mRun3Guard = utils::ScopedDir("/tmp/ut-run3");
+ utils::ScopedDir mContainersPathGuard;
+ utils::ScopedDir mRun1Guard;
+ utils::ScopedDir mRun2Guard;
+ utils::ScopedDir mRun3Guard;
ContainersManager cm;
- Fixture(): cm(TEST_DBUS_CONFIG_PATH)
+ Fixture()
+ : mContainersPathGuard(CONTAINERS_PATH)
+ , mRun1Guard("/tmp/ut-run1")
+ , mRun2Guard("/tmp/ut-run2")
+ , mRun3Guard("/tmp/ut-run3")
+ , cm(TEST_DBUS_CONFIG_PATH)
{
cm.startAll();
}
diff --git a/tests/unit_tests/lxc/ut-domain.cpp b/tests/unit_tests/lxc/ut-domain.cpp
index 206d2c7..aa6c3a9 100644
--- a/tests/unit_tests/lxc/ut-domain.cpp
+++ b/tests/unit_tests/lxc/ut-domain.cpp
@@ -44,9 +44,10 @@ const std::string DOMAIN_NAME = "ut-domain";
const std::string TEMPLATE = SC_TEST_LXC_TEMPLATES_INSTALL_DIR "/minimal.sh";
struct Fixture {
- utils::ScopedDir mLxcDirGuard = LXC_PATH;
+ utils::ScopedDir mLxcDirGuard;
Fixture()
+ : mLxcDirGuard(LXC_PATH)
{
cleanup();
}
diff --git a/tests/unit_tests/server/ut-container-admin.cpp b/tests/unit_tests/server/ut-container-admin.cpp
index 6d2ba6c..ae00abf 100644
--- a/tests/unit_tests/server/ut-container-admin.cpp
+++ b/tests/unit_tests/server/ut-container-admin.cpp
@@ -46,10 +46,14 @@ const std::string LXC_TEMPLATES_PATH = SC_TEST_LXC_TEMPLATES_INSTALL_DIR;
struct Fixture {
utils::ScopedGlibLoop mLoop;
- utils::ScopedDir mContainersPathGuard = CONTAINERS_PATH;
+ utils::ScopedDir mContainersPathGuard;
ContainerConfig mConfig;
+ Fixture()
+ : mContainersPathGuard(CONTAINERS_PATH)
+ {}
+
std::unique_ptr create(const std::string& configPath)
{
config::loadFromFile(configPath, mConfig);
diff --git a/tests/unit_tests/server/ut-container.cpp b/tests/unit_tests/server/ut-container.cpp
index fe5aa64..c42b80d 100644
--- a/tests/unit_tests/server/ut-container.cpp
+++ b/tests/unit_tests/server/ut-container.cpp
@@ -54,9 +54,13 @@ const std::string LXC_TEMPLATES_PATH = SC_TEST_LXC_TEMPLATES_INSTALL_DIR;
struct Fixture {
utils::ScopedGlibLoop mLoop;
- utils::ScopedDir mContainersPathGuard = CONTAINERS_PATH;
+ utils::ScopedDir mContainersPathGuard;
utils::ScopedDir mRunGuard;
+ Fixture()
+ : mContainersPathGuard(CONTAINERS_PATH)
+ {}
+
std::unique_ptr create(const std::string& configPath)
{
return std::unique_ptr(new Container(CONTAINERS_PATH,
diff --git a/tests/unit_tests/server/ut-containers-manager.cpp b/tests/unit_tests/server/ut-containers-manager.cpp
index 317981d..399cd12 100644
--- a/tests/unit_tests/server/ut-containers-manager.cpp
+++ b/tests/unit_tests/server/ut-containers-manager.cpp
@@ -379,10 +379,17 @@ private:
struct Fixture {
security_containers::utils::ScopedGlibLoop mLoop;
- utils::ScopedDir mContainersPathGuard = CONTAINERS_PATH;
- utils::ScopedDir mRun1Guard = utils::ScopedDir("/tmp/ut-run1");
- utils::ScopedDir mRun2Guard = utils::ScopedDir("/tmp/ut-run2");
- utils::ScopedDir mRun3Guard = utils::ScopedDir("/tmp/ut-run3");
+ utils::ScopedDir mContainersPathGuard;
+ utils::ScopedDir mRun1Guard;
+ utils::ScopedDir mRun2Guard;
+ utils::ScopedDir mRun3Guard;
+
+ Fixture()
+ : mContainersPathGuard(CONTAINERS_PATH)
+ , mRun1Guard("/tmp/ut-run1")
+ , mRun2Guard("/tmp/ut-run2")
+ , mRun3Guard("/tmp/ut-run3")
+ {}
};
} // namespace
diff --git a/tests/unit_tests/server/ut-server.cpp b/tests/unit_tests/server/ut-server.cpp
index 2dbfabc..1c3c46b 100644
--- a/tests/unit_tests/server/ut-server.cpp
+++ b/tests/unit_tests/server/ut-server.cpp
@@ -38,7 +38,11 @@ namespace {
const std::string CONTAINERS_PATH = "/tmp/ut-containers"; // the same as in daemon.conf
struct Fixture {
- security_containers::utils::ScopedDir mContainersPathGuard = CONTAINERS_PATH;
+ security_containers::utils::ScopedDir mContainersPathGuard;
+
+ Fixture()
+ : mContainersPathGuard(CONTAINERS_PATH)
+ {}
};
} // namespace
--
2.7.4
From 47782bbb0c4b7bf91aa773718d0c9f681fba6eaf Mon Sep 17 00:00:00 2001
From: Jan Olszak
Date: Wed, 19 Nov 2014 15:26:28 +0100
Subject: [PATCH 04/16] Fixing build brake for gcc 4.6
[Bug/Feature] N/A
[Cause] N/A
[Solution] N/A
[Verification] Build with older gcc
Change-Id: I0c889f7d79e10403a18b915c0c30e91400542de4
---
common/ipc/internals/processor.cpp | 13 ++++++++-----
1 file changed, 8 insertions(+), 5 deletions(-)
diff --git a/common/ipc/internals/processor.cpp b/common/ipc/internals/processor.cpp
index 50327c0..5634880 100644
--- a/common/ipc/internals/processor.cpp
+++ b/common/ipc/internals/processor.cpp
@@ -109,7 +109,8 @@ Processor::PeerID Processor::addPeer(const std::shared_ptr& socketPtr)
{
Lock lock(mSocketsMutex);
peerID = getNextPeerID();
- mNewSockets.emplace(peerID, std::move(socketPtr));
+ SocketInfo socketInfo(peerID, std::move(socketPtr));
+ mNewSockets.push(std::move(socketInfo));
}
LOGI("New peer added. Id: " << peerID);
mEventQueue.send(Event::NEW_PEER);
@@ -392,7 +393,7 @@ bool Processor::handleEvent()
return false;
}
- mSockets.emplace(socketInfo.peerID, std::move(socketInfo.socketPtr));
+ mSockets[socketInfo.peerID] = std::move(socketInfo.socketPtr);
}
resetPolling();
if (mNewPeerCallback) {
@@ -454,9 +455,11 @@ bool Processor::handleCall()
if (mReturnCallbacks.count(messageID) != 0) {
LOGE("There already was a return callback for messageID: " << messageID);
}
- mReturnCallbacks.emplace(messageID, ReturnCallbacks(call.peerID,
- std::move(call.parse),
- std::move(call.process)));
+
+ // move insertion
+ mReturnCallbacks[messageID] = std::move(ReturnCallbacks(call.peerID,
+ std::move(call.parse),
+ std::move(call.process)));
}
try {
--
2.7.4
From e3d2a40e88a88c3319bf3d06378549b4e1ce1e5e Mon Sep 17 00:00:00 2001
From: Piotr Bartosiewicz
Date: Thu, 20 Nov 2014 13:09:49 +0100
Subject: [PATCH 05/16] Fix lxc templates
[Bug/Feature] Tests was failing on some images
[Cause] N/A
[Solution] N/A
[Verification] Build, install, run tests
Change-Id: I9b2029539a4c5567b6eaed178ef1df2b7dce3c44
---
tests/unit_tests/lxc/templates/minimal-dbus1.sh | 3 +++
tests/unit_tests/lxc/templates/minimal-dbus2.sh | 3 +++
tests/unit_tests/lxc/templates/minimal-dbus3.sh | 3 +++
tests/unit_tests/lxc/templates/minimal.sh | 8 +++++++-
4 files changed, 16 insertions(+), 1 deletion(-)
diff --git a/tests/unit_tests/lxc/templates/minimal-dbus1.sh b/tests/unit_tests/lxc/templates/minimal-dbus1.sh
index 35f816f..ff1f2de 100755
--- a/tests/unit_tests/lxc/templates/minimal-dbus1.sh
+++ b/tests/unit_tests/lxc/templates/minimal-dbus1.sh
@@ -23,6 +23,7 @@ done
ROOTFS_DIRS="\
${rootfs}/bin \
${rootfs}/dev \
+${rootfs}/dev/pts \
${rootfs}/etc \
${rootfs}/home \
${rootfs}/lib \
@@ -34,6 +35,7 @@ ${rootfs}/sbin \
${rootfs}/sys \
${rootfs}/tmp \
${rootfs}/usr \
+${rootfs}/opt \
${rootfs}/var \
${rootfs}/var/run
"
@@ -62,6 +64,7 @@ lxc.mount.entry = /etc etc none ro,bind 0 0
lxc.mount.entry = /lib lib none ro,bind 0 0
lxc.mount.entry = /sbin sbin none ro,bind 0 0
lxc.mount.entry = /usr usr none ro,rbind 0 0
+lxc.mount.entry = /opt opt none ro,rbind 0 0
lxc.mount.entry = /tmp/ut-run1 var/run none rw,bind 0 0
EOF
diff --git a/tests/unit_tests/lxc/templates/minimal-dbus2.sh b/tests/unit_tests/lxc/templates/minimal-dbus2.sh
index f8f963e..86984b7 100755
--- a/tests/unit_tests/lxc/templates/minimal-dbus2.sh
+++ b/tests/unit_tests/lxc/templates/minimal-dbus2.sh
@@ -23,6 +23,7 @@ done
ROOTFS_DIRS="\
${rootfs}/bin \
${rootfs}/dev \
+${rootfs}/dev/pts \
${rootfs}/etc \
${rootfs}/home \
${rootfs}/lib \
@@ -34,6 +35,7 @@ ${rootfs}/sbin \
${rootfs}/sys \
${rootfs}/tmp \
${rootfs}/usr \
+${rootfs}/opt \
${rootfs}/var \
${rootfs}/var/run
"
@@ -62,6 +64,7 @@ lxc.mount.entry = /etc etc none ro,bind 0 0
lxc.mount.entry = /lib lib none ro,bind 0 0
lxc.mount.entry = /sbin sbin none ro,bind 0 0
lxc.mount.entry = /usr usr none ro,rbind 0 0
+lxc.mount.entry = /opt opt none ro,rbind 0 0
lxc.mount.entry = /tmp/ut-run2 var/run none rw,bind 0 0
EOF
diff --git a/tests/unit_tests/lxc/templates/minimal-dbus3.sh b/tests/unit_tests/lxc/templates/minimal-dbus3.sh
index 68f4f11..034b4fd 100755
--- a/tests/unit_tests/lxc/templates/minimal-dbus3.sh
+++ b/tests/unit_tests/lxc/templates/minimal-dbus3.sh
@@ -23,6 +23,7 @@ done
ROOTFS_DIRS="\
${rootfs}/bin \
${rootfs}/dev \
+${rootfs}/dev/pts \
${rootfs}/etc \
${rootfs}/home \
${rootfs}/lib \
@@ -34,6 +35,7 @@ ${rootfs}/sbin \
${rootfs}/sys \
${rootfs}/tmp \
${rootfs}/usr \
+${rootfs}/opt \
${rootfs}/var \
${rootfs}/var/run
"
@@ -62,6 +64,7 @@ lxc.mount.entry = /etc etc none ro,bind 0 0
lxc.mount.entry = /lib lib none ro,bind 0 0
lxc.mount.entry = /sbin sbin none ro,bind 0 0
lxc.mount.entry = /usr usr none ro,rbind 0 0
+lxc.mount.entry = /opt opt none ro,rbind 0 0
lxc.mount.entry = /tmp/ut-run3 var/run none rw,bind 0 0
EOF
diff --git a/tests/unit_tests/lxc/templates/minimal.sh b/tests/unit_tests/lxc/templates/minimal.sh
index 547661e..873277e 100755
--- a/tests/unit_tests/lxc/templates/minimal.sh
+++ b/tests/unit_tests/lxc/templates/minimal.sh
@@ -23,6 +23,7 @@ done
ROOTFS_DIRS="\
${rootfs}/bin \
${rootfs}/dev \
+${rootfs}/dev/pts \
${rootfs}/etc \
${rootfs}/home \
${rootfs}/lib \
@@ -33,7 +34,8 @@ ${rootfs}/run \
${rootfs}/sbin \
${rootfs}/sys \
${rootfs}/tmp \
-${rootfs}/usr
+${rootfs}/usr \
+${rootfs}/opt
"
/bin/mkdir ${ROOTFS_DIRS}
@@ -52,6 +54,9 @@ lxc.haltsignal = SIGTERM
lxc.pts = 256
lxc.tty = 0
+#lxc.loglevel = TRACE
+#lxc.logfile = /tmp/${name}.log
+
lxc.cgroup.devices.deny = a
lxc.mount.auto = proc sys cgroup
@@ -60,6 +65,7 @@ lxc.mount.entry = /etc etc none ro,bind 0 0
lxc.mount.entry = /lib lib none ro,bind 0 0
lxc.mount.entry = /sbin sbin none ro,bind 0 0
lxc.mount.entry = /usr usr none ro,rbind 0 0
+lxc.mount.entry = /opt opt none ro,rbind 0 0
EOF
if [ "$(uname -m)" = "x86_64" ]; then
--
2.7.4
From 7ea2c7bdeffd0ebc8514840af180574b835b6784 Mon Sep 17 00:00:00 2001
From: Jan Olszak
Date: Mon, 17 Nov 2014 12:58:32 +0100
Subject: [PATCH 06/16] IPC: NONBLOCK sockets
[Bug/Feature] All writes and reads have timeout
Timeout in callSync removes the peer
[Cause] N/A
[Solution] N/A
[Verification] Build, install, run tests
Change-Id: I86213b04e435a48bc56ae6f995a0c364b712a4d0
---
common/ipc/internals/event-queue.hpp | 12 ++++
common/ipc/internals/eventfd.cpp | 2 +-
common/ipc/internals/processor.cpp | 120 +++++++++++++++++++++++++++-------
common/ipc/internals/processor.hpp | 92 +++++++++++++++++++-------
common/ipc/internals/socket.cpp | 12 +++-
common/ipc/internals/utils.cpp | 123 ++++++++++++++++++++++++++---------
common/ipc/internals/utils.hpp | 6 +-
common/ipc/types.cpp | 4 ++
common/ipc/types.hpp | 2 +
tests/unit_tests/ipc/ut-ipc.cpp | 60 +++++++++++++++++
10 files changed, 349 insertions(+), 84 deletions(-)
diff --git a/common/ipc/internals/event-queue.hpp b/common/ipc/internals/event-queue.hpp
index 82cb2ff..b50f0c4 100644
--- a/common/ipc/internals/event-queue.hpp
+++ b/common/ipc/internals/event-queue.hpp
@@ -71,6 +71,11 @@ public:
*/
MessageType receive();
+ /**
+ * @return is the queue empty
+ */
+ bool isEmpty();
+
private:
typedef std::lock_guard Lock;
@@ -106,6 +111,13 @@ MessageType EventQueue::receive()
return mess;
}
+template
+bool EventQueue::isEmpty()
+{
+ Lock lock(mCommunicationMutex);
+ return mMessages.empty();
+}
+
} // namespace ipc
} // namespace security_containers
diff --git a/common/ipc/internals/eventfd.cpp b/common/ipc/internals/eventfd.cpp
index c8a17b6..37cf7dd 100644
--- a/common/ipc/internals/eventfd.cpp
+++ b/common/ipc/internals/eventfd.cpp
@@ -39,7 +39,7 @@ namespace ipc {
EventFD::EventFD()
{
- mFD = ::eventfd(0, EFD_SEMAPHORE);
+ mFD = ::eventfd(0, EFD_SEMAPHORE | EFD_NONBLOCK);
if (mFD == -1) {
LOGE("Error in eventfd: " << std::string(strerror(errno)));
throw IPCException("Error in eventfd: " + std::string(strerror(errno)));
diff --git a/common/ipc/internals/processor.cpp b/common/ipc/internals/processor.cpp
index 5634880..9677991 100644
--- a/common/ipc/internals/processor.cpp
+++ b/common/ipc/internals/processor.cpp
@@ -48,9 +48,6 @@ namespace ipc {
LOGE("Callback threw an error: " << e.what()); \
}
-
-
-
const Processor::MethodID Processor::RETURN_METHOD_ID = std::numeric_limits::max();
Processor::Processor(const PeerCallback& newPeerCallback,
@@ -118,9 +115,31 @@ Processor::PeerID Processor::addPeer(const std::shared_ptr& socketPtr)
return peerID;
}
-void Processor::removePeer(const PeerID peerID, Status status)
+void Processor::removePeer(const PeerID peerID)
{
- LOGW("Removing naughty peer. ID: " << peerID);
+ std::shared_ptr conditionPtr(new std::condition_variable());
+
+ {
+ Lock lock(mSocketsMutex);
+ RemovePeerRequest request(peerID, conditionPtr);
+ mPeersToDelete.push(std::move(request));
+ }
+
+ mEventQueue.send(Event::DELETE_PEER);
+
+ auto isPeerDeleted = [&peerID, this] {
+ Lock lock(mSocketsMutex);
+ return mSockets.count(peerID) == 0;
+ };
+
+ std::mutex mutex;
+ std::unique_lock lock(mutex);
+ conditionPtr->wait(lock, isPeerDeleted);
+}
+
+void Processor::removePeerInternal(const PeerID peerID, Status status)
+{
+ LOGW("Removing peer. ID: " << peerID);
{
Lock lock(mSocketsMutex);
mSockets.erase(peerID);
@@ -141,9 +160,49 @@ void Processor::removePeer(const PeerID peerID, Status status)
}
}
+ if (mRemovedPeerCallback) {
+ // Notify about the deletion
+ mRemovedPeerCallback(peerID);
+ }
+
resetPolling();
}
+void Processor::cleanCommunication()
+{
+ while (!mEventQueue.isEmpty()) {
+ switch (mEventQueue.receive()) {
+ case Event::FINISH: {
+ LOGD("Event FINISH after FINISH");
+ break;
+ }
+ case Event::CALL: {
+ LOGD("Event CALL after FINISH");
+ Call call = getCall();
+ IGNORE_EXCEPTIONS(call.process(Status::CLOSING, call.data));
+ break;
+ }
+
+ case Event::NEW_PEER: {
+ LOGD("Event NEW_PEER after FINISH");
+ break;
+ }
+
+ case Event::DELETE_PEER: {
+ LOGD("Event DELETE_PEER after FINISH");
+ RemovePeerRequest request;
+ {
+ Lock lock(mSocketsMutex);
+ request = std::move(mPeersToDelete.front());
+ mPeersToDelete.pop();
+ }
+ request.conditionPtr->notify_all();
+ break;
+ }
+ }
+ }
+}
+
void Processor::resetPolling()
{
LOGI("Resetting polling");
@@ -198,6 +257,8 @@ void Processor::run()
continue;
}
}
+
+ cleanCommunication();
}
@@ -215,11 +276,10 @@ bool Processor::handleLostConnections()
peersToRemove.push_back(socketIt->first);
}
}
-
}
for (const PeerID peerID : peersToRemove) {
- removePeer(peerID, Status::PEER_DISCONNECTED);
+ removePeerInternal(peerID, Status::PEER_DISCONNECTED);
}
return !peersToRemove.empty();
@@ -280,7 +340,7 @@ bool Processor::onReturnValue(const PeerID peerID,
mReturnCallbacks.erase(messageID);
} catch (const std::out_of_range&) {
LOGW("No return callback for messageID: " << messageID);
- removePeer(peerID, Status::NAUGHTY_PEER);
+ removePeerInternal(peerID, Status::NAUGHTY_PEER);
return true;
}
@@ -291,7 +351,7 @@ bool Processor::onReturnValue(const PeerID peerID,
} catch (const std::exception& e) {
LOGE("Exception during parsing: " << e.what());
IGNORE_EXCEPTIONS(returnCallbacks.process(Status::PARSING_ERROR, data));
- removePeer(peerID, Status::PARSING_ERROR);
+ removePeerInternal(peerID, Status::PARSING_ERROR);
return true;
}
@@ -314,7 +374,7 @@ bool Processor::onRemoteCall(const PeerID peerID,
methodCallbacks = mMethodsCallbacks.at(methodID);
} catch (const std::out_of_range&) {
LOGW("No method callback for methodID: " << methodID);
- removePeer(peerID, Status::NAUGHTY_PEER);
+ removePeerInternal(peerID, Status::NAUGHTY_PEER);
return true;
}
@@ -324,7 +384,7 @@ bool Processor::onRemoteCall(const PeerID peerID,
data = methodCallbacks->parse(socket.getFD());
} catch (const std::exception& e) {
LOGE("Exception during parsing: " << e.what());
- removePeer(peerID, Status::PARSING_ERROR);
+ removePeerInternal(peerID, Status::PARSING_ERROR);
return true;
}
@@ -334,7 +394,7 @@ bool Processor::onRemoteCall(const PeerID peerID,
returnData = methodCallbacks->method(data);
} catch (const std::exception& e) {
LOGE("Exception in method handler: " << e.what());
- removePeer(peerID, Status::NAUGHTY_PEER);
+ removePeerInternal(peerID, Status::NAUGHTY_PEER);
return true;
}
@@ -347,7 +407,7 @@ bool Processor::onRemoteCall(const PeerID peerID,
methodCallbacks->serialize(socket.getFD(), returnData);
} catch (const std::exception& e) {
LOGE("Exception during serialization: " << e.what());
- removePeer(peerID, Status::SERIALIZATION_ERROR);
+ removePeerInternal(peerID, Status::SERIALIZATION_ERROR);
return true;
}
@@ -402,6 +462,20 @@ bool Processor::handleEvent()
}
return true;
}
+
+ case Event::DELETE_PEER: {
+ LOGD("Event DELETE_PEER");
+ RemovePeerRequest request;
+ {
+ Lock lock(mSocketsMutex);
+ request = std::move(mPeersToDelete.front());
+ mPeersToDelete.pop();
+ }
+
+ removePeerInternal(request.peerID, Status::REMOVED_PEER);
+ request.conditionPtr->notify_all();
+ return true;
+ }
}
return false;
@@ -447,39 +521,37 @@ bool Processor::handleCall()
return false;
}
- MessageID messageID = getNextMessageID();
-
{
// Set what to do with the return message
Lock lock(mReturnCallbacksMutex);
- if (mReturnCallbacks.count(messageID) != 0) {
- LOGE("There already was a return callback for messageID: " << messageID);
+ if (mReturnCallbacks.count(call.messageID) != 0) {
+ LOGE("There already was a return callback for messageID: " << call.messageID);
}
// move insertion
- mReturnCallbacks[messageID] = std::move(ReturnCallbacks(call.peerID,
- std::move(call.parse),
- std::move(call.process)));
+ mReturnCallbacks[call.messageID] = std::move(ReturnCallbacks(call.peerID,
+ std::move(call.parse),
+ std::move(call.process)));
}
try {
// Send the call with the socket
Socket::Guard guard = socketPtr->getGuard();
socketPtr->write(&call.methodID, sizeof(call.methodID));
- socketPtr->write(&messageID, sizeof(messageID));
+ socketPtr->write(&call.messageID, sizeof(call.messageID));
call.serialize(socketPtr->getFD(), call.data);
} catch (const std::exception& e) {
LOGE("Error during sending a message: " << e.what());
// Inform about the error
- IGNORE_EXCEPTIONS(mReturnCallbacks[messageID].process(Status::SERIALIZATION_ERROR, call.data));
+ IGNORE_EXCEPTIONS(mReturnCallbacks[call.messageID].process(Status::SERIALIZATION_ERROR, call.data));
{
Lock lock(mReturnCallbacksMutex);
- mReturnCallbacks.erase(messageID);
+ mReturnCallbacks.erase(call.messageID);
}
- removePeer(call.peerID, Status::SERIALIZATION_ERROR);
+ removePeerInternal(call.peerID, Status::SERIALIZATION_ERROR);
return true;
}
diff --git a/common/ipc/internals/processor.hpp b/common/ipc/internals/processor.hpp
index 3df3f9c..e34bdb6 100644
--- a/common/ipc/internals/processor.hpp
+++ b/common/ipc/internals/processor.hpp
@@ -65,7 +65,6 @@ const unsigned int DEFAULT_MAX_NUMBER_OF_PEERS = 500;
* - Rest: The data written in a callback. One type per method.ReturnCallbacks
*
* TODO:
-* - error codes passed to async callbacks
* - remove ReturnCallbacks on peer disconnect
* - on sync timeout erase the return callback
* - don't throw timeout if the message is already processed
@@ -73,12 +72,15 @@ const unsigned int DEFAULT_MAX_NUMBER_OF_PEERS = 500;
* - removePeer API function
* - error handling - special message type
* - some mutexes may not be needed
+* - make addPeer synchronous like removePeer
*/
class Processor {
public:
typedef std::function PeerCallback;
typedef unsigned int PeerID;
typedef unsigned int MethodID;
+ typedef unsigned int MessageID;
+
/**
* Method ID. Used to indicate a message with the return value.
@@ -122,6 +124,13 @@ public:
PeerID addPeer(const std::shared_ptr& socketPtr);
/**
+ * Request removing peer and wait
+ *
+ * @param peerID id of the peer
+ */
+ void removePeer(const PeerID peerID);
+
+ /**
* Saves the callbacks connected to the method id.
* When a message with the given method id is received,
* the data will be passed to the serialization callback through file descriptor.
@@ -171,17 +180,16 @@ public:
* @tparam ReceivedDataType data type to receive
*/
template
- void callAsync(const MethodID methodID,
- const PeerID peerID,
- const std::shared_ptr& data,
- const typename ResultHandler::type& process);
+ MessageID callAsync(const MethodID methodID,
+ const PeerID peerID,
+ const std::shared_ptr& data,
+ const typename ResultHandler::type& process);
private:
typedef std::function& data)> SerializeCallback;
typedef std::function(int fd)> ParseCallback;
typedef std::lock_guard Lock;
- typedef unsigned int MessageID;
struct Call {
Call(const Call& other) = delete;
@@ -195,6 +203,7 @@ private:
SerializeCallback serialize;
ParseCallback parse;
ResultHandler::type process;
+ MessageID messageID;
};
struct MethodHandlers {
@@ -238,10 +247,26 @@ private:
std::shared_ptr socketPtr;
};
+ struct RemovePeerRequest {
+ RemovePeerRequest(const RemovePeerRequest& other) = delete;
+ RemovePeerRequest& operator=(const RemovePeerRequest&) = delete;
+ RemovePeerRequest() = default;
+ RemovePeerRequest(RemovePeerRequest&&) = default;
+ RemovePeerRequest& operator=(RemovePeerRequest &&) = default;
+
+ RemovePeerRequest(const PeerID peerID,
+ const std::shared_ptr& conditionPtr)
+ : peerID(peerID), conditionPtr(conditionPtr) {}
+
+ PeerID peerID;
+ std::shared_ptr conditionPtr;
+ };
+
enum class Event : int {
FINISH, // Shutdown request
CALL, // New method call in the queue
- NEW_PEER // New peer in the queue
+ NEW_PEER, // New peer in the queue
+ DELETE_PEER // Delete peer
};
EventQueue mEventQueue;
@@ -258,6 +283,7 @@ private:
std::mutex mSocketsMutex;
std::unordered_map > mSockets;
std::queue mNewSockets;
+ std::queue mPeersToDelete;
// Mutex for modifying the map with return callbacks
std::mutex mReturnCallbacksMutex;
@@ -292,8 +318,8 @@ private:
MessageID getNextMessageID();
PeerID getNextPeerID();
Call getCall();
- void removePeer(const PeerID peerID, Status status);
-
+ void removePeerInternal(const PeerID peerID, Status status);
+ void cleanCommunication();
};
template
@@ -336,10 +362,10 @@ void Processor::addMethodHandler(const MethodID methodID,
}
template
-void Processor::callAsync(const MethodID methodID,
- const PeerID peerID,
- const std::shared_ptr& data,
- const typename ResultHandler::type& process)
+Processor::MessageID Processor::callAsync(const MethodID methodID,
+ const PeerID peerID,
+ const std::shared_ptr& data,
+ const typename ResultHandler::type& process)
{
static_assert(config::isVisitable::value,
"Use the libConfig library");
@@ -357,6 +383,7 @@ void Processor::callAsync(const MethodID methodID,
call.peerID = peerID;
call.methodID = methodID;
call.data = data;
+ call.messageID = getNextMessageID();
call.parse = [](const int fd)->std::shared_ptr {
std::shared_ptr data(new ReceivedDataType());
@@ -379,6 +406,8 @@ void Processor::callAsync(const MethodID methodID,
}
mEventQueue.send(Event::CALL);
+
+ return call.messageID;
}
@@ -400,30 +429,43 @@ std::shared_ptr Processor::callSync(const MethodID methodID,
std::shared_ptr result;
- std::mutex mtx;
- std::unique_lock lck(mtx);
+ std::mutex mutex;
std::condition_variable cv;
Status returnStatus = ipc::Status::UNDEFINED;
- auto process = [&result, &cv, &returnStatus](Status status, std::shared_ptr returnedData) {
+ auto process = [&result, &mutex, &cv, &returnStatus](Status status, std::shared_ptr returnedData) {
+ std::unique_lock lock(mutex);
returnStatus = status;
result = returnedData;
- cv.notify_one();
+ cv.notify_all();
};
- callAsync(methodID,
- peerID,
- data,
- process);
+ MessageID messageID = callAsync(methodID,
+ peerID,
+ data,
+ process);
auto isResultInitialized = [&returnStatus]() {
return returnStatus != ipc::Status::UNDEFINED;
};
- if (!cv.wait_for(lck, std::chrono::milliseconds(timeoutMS), isResultInitialized)) {
- LOGE("Function call timeout; methodID: " << methodID);
- throw IPCTimeoutException("Function call timeout; methodID: " + std::to_string(methodID));
+ std::unique_lock lock(mutex);
+ if (!cv.wait_for(lock, std::chrono::milliseconds(timeoutMS), isResultInitialized)) {
+ bool isTimeout = false;
+ {
+ Lock lock(mReturnCallbacksMutex);
+ if (1 == mReturnCallbacks.erase(messageID)) {
+ isTimeout = true;
+ }
+ }
+ if (isTimeout) {
+ removePeer(peerID);
+ LOGE("Function call timeout; methodID: " << methodID);
+ throw IPCTimeoutException("Function call timeout; methodID: " + std::to_string(methodID));
+ } else {
+ // Timeout started during the return value processing, so wait for it to finish
+ cv.wait(lock, isResultInitialized);
+ }
}
throwOnError(returnStatus);
diff --git a/common/ipc/internals/socket.cpp b/common/ipc/internals/socket.cpp
index 002b9cf..4ac977a 100644
--- a/common/ipc/internals/socket.cpp
+++ b/common/ipc/internals/socket.cpp
@@ -102,8 +102,8 @@ int Socket::getSystemdSocket(const std::string& path)
{
int n = ::sd_listen_fds(-1 /*Block further calls to sd_listen_fds*/);
if (n < 0) {
- LOGE("sd_listen_fds fails with errno: " + n);
- throw IPCException("sd_listen_fds fails with errno: " + n);
+ LOGE("sd_listen_fds fails with errno: " << n);
+ throw IPCException("sd_listen_fds fails with errno: " + std::to_string(n));
}
for (int fd = SD_LISTEN_FDS_START;
@@ -193,6 +193,14 @@ Socket Socket::connectSocket(const std::string& path)
throw IPCException("Error in connect: " + std::string(strerror(errno)));
}
+ // Nonblock socket
+ int flags = fcntl(fd, F_GETFL, 0);
+ if (-1 == fcntl(fd, F_SETFL, flags | O_NONBLOCK)) {
+ ::close(fd);
+ LOGE("Error in fcntl: " + std::string(strerror(errno)));
+ throw IPCException("Error in fcntl: " + std::string(strerror(errno)));
+ }
+
return Socket(fd);
}
diff --git a/common/ipc/internals/utils.cpp b/common/ipc/internals/utils.cpp
index e98b60d..bb11c80 100644
--- a/common/ipc/internals/utils.cpp
+++ b/common/ipc/internals/utils.cpp
@@ -30,16 +30,63 @@
#include
#include
+#include
#include
-
+#include
#include
#include
namespace fs = boost::filesystem;
+namespace chr = std::chrono;
namespace security_containers {
namespace ipc {
+namespace {
+
+void waitForEvent(int fd,
+ short event,
+ const chr::high_resolution_clock::time_point deadline)
+{
+ // Wait for the rest of the data
+ struct pollfd fds[1];
+ fds[0].fd = fd;
+ fds[0].events = event | POLLHUP;
+
+ for (;;) {
+ chr::milliseconds timeoutMS = chr::duration_cast(deadline - chr::high_resolution_clock::now());
+ if (timeoutMS.count() < 0) {
+ LOGE("Timeout in read");
+ throw IPCException("Timeout in read");
+ }
+
+ int ret = ::poll(fds, 1 /*fds size*/, timeoutMS.count());
+
+ if (ret == -1) {
+ if (errno == EINTR) {
+ continue;
+ }
+ LOGE("Error in poll: " + std::string(strerror(errno)));
+ throw IPCException("Error in poll: " + std::string(strerror(errno)));
+ }
+
+ if (ret == 0) {
+ LOGE("Timeout in read");
+ throw IPCException("Timeout in read");
+ }
+
+ if (fds[0].revents & POLLHUP) {
+ LOGE("Peer disconnected");
+ throw IPCException("Peer disconnected");
+ }
+
+ // Here Comes the Sun
+ break;
+ }
+}
+
+} // namespace
+
void close(int fd)
{
if (fd < 0) {
@@ -59,46 +106,62 @@ void close(int fd)
}
}
-void write(int fd, const void* bufferPtr, const size_t size)
+void write(int fd, const void* bufferPtr, const size_t size, int timeoutMS)
{
+ chr::high_resolution_clock::time_point deadline = chr::high_resolution_clock::now() +
+ chr::milliseconds(timeoutMS);
+
size_t nTotal = 0;
- int n;
+ for (;;) {
+ int n = ::write(fd,
+ reinterpret_cast(bufferPtr) + nTotal,
+ size - nTotal);
+ if (n > 0) {
+ nTotal += n;
+ } else if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) {
+ // Neglected errors
+ LOGD("Retrying write");
+ } else {
+ LOGE("Error during reading: " + std::string(strerror(errno)));
+ throw IPCException("Error during reading: " + std::string(strerror(errno)));
+ }
- do {
- n = ::write(fd,
- reinterpret_cast(bufferPtr) + nTotal,
- size - nTotal);
- if (n < 0) {
- if (errno == EINTR) {
- LOGD("Write interrupted by a signal, retrying");
- continue;
- }
- LOGE("Error during writing: " + std::string(strerror(errno)));
- throw IPCException("Error during witting: " + std::string(strerror(errno)));
+ if (nTotal >= size) {
+ // All data is written, break loop
+ break;
+ } else {
+ waitForEvent(fd, POLLOUT, deadline);
}
- nTotal += n;
- } while (nTotal < size);
+ }
}
-void read(int fd, void* bufferPtr, const size_t size)
+void read(int fd, void* bufferPtr, const size_t size, int timeoutMS)
{
- size_t nTotal = 0;
- int n;
+ chr::high_resolution_clock::time_point deadline = chr::high_resolution_clock::now() +
+ chr::milliseconds(timeoutMS);
- do {
- n = ::read(fd,
- reinterpret_cast(bufferPtr) + nTotal,
- size - nTotal);
- if (n < 0) {
- if (errno == EINTR) {
- LOGD("Read interrupted by a signal, retrying");
- continue;
- }
+ size_t nTotal = 0;
+ for (;;) {
+ int n = ::read(fd,
+ reinterpret_cast(bufferPtr) + nTotal,
+ size - nTotal);
+ if (n > 0) {
+ nTotal += n;
+ } else if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) {
+ // Neglected errors
+ LOGD("Retrying read");
+ } else {
LOGE("Error during reading: " + std::string(strerror(errno)));
throw IPCException("Error during reading: " + std::string(strerror(errno)));
}
- nTotal += n;
- } while (nTotal < size);
+
+ if (nTotal >= size) {
+ // All data is read, break loop
+ break;
+ } else {
+ waitForEvent(fd, POLLIN, deadline);
+ }
+ }
}
unsigned int getMaxFDNumber()
diff --git a/common/ipc/internals/utils.hpp b/common/ipc/internals/utils.hpp
index 0b1815d..a9a79a0 100644
--- a/common/ipc/internals/utils.hpp
+++ b/common/ipc/internals/utils.hpp
@@ -42,8 +42,9 @@ void close(int fd);
* @param fd file descriptor
* @param bufferPtr pointer to the data buffer
* @param size size of data to write
+ * @param timeoutMS timeout in milliseconds
*/
-void write(int fd, const void* bufferPtr, const size_t size);
+void write(int fd, const void* bufferPtr, const size_t size, int timeoutMS = 500);
/**
* Read from a file descriptor, throw on error.
@@ -51,8 +52,9 @@ void write(int fd, const void* bufferPtr, const size_t size);
* @param fd file descriptor
* @param bufferPtr pointer to the data buffer
* @param size size of the data to read
+ * @param timeoutMS timeout in milliseconds
*/
-void read(int fd, void* bufferPtr, const size_t size);
+void read(int fd, void* bufferPtr, const size_t size, int timeoutMS = 500);
/**
* @return the max number of file descriptors for this process.
diff --git a/common/ipc/types.cpp b/common/ipc/types.cpp
index e0ffc5b..bce862c 100644
--- a/common/ipc/types.cpp
+++ b/common/ipc/types.cpp
@@ -37,6 +37,8 @@ std::string toString(const Status status)
case Status::SERIALIZATION_ERROR: return "Exception during writing/serializing data to the socket";
case Status::PEER_DISCONNECTED: return "No such peer. Might got disconnected.";
case Status::NAUGHTY_PEER: return "Peer performed a forbidden action.";
+ case Status::REMOVED_PEER: return "Removing peer";
+ case Status::CLOSING: return "Closing IPC";
case Status::UNDEFINED: return "Undefined state";
default: return "Unknown status";
}
@@ -56,6 +58,8 @@ void throwOnError(const Status status)
case Status::SERIALIZATION_ERROR: throw IPCSerializationException(message);
case Status::PEER_DISCONNECTED: throw IPCPeerDisconnectedException(message);
case Status::NAUGHTY_PEER: throw IPCNaughtyPeerException(message);
+ case Status::REMOVED_PEER: throw IPCException(message);
+ case Status::CLOSING: throw IPCException(message);
case Status::UNDEFINED: throw IPCException(message);
default: return throw IPCException(message);
}
diff --git a/common/ipc/types.hpp b/common/ipc/types.hpp
index c07e504..1bfaa4e 100644
--- a/common/ipc/types.hpp
+++ b/common/ipc/types.hpp
@@ -40,6 +40,8 @@ enum class Status : int {
SERIALIZATION_ERROR,
PEER_DISCONNECTED,
NAUGHTY_PEER,
+ REMOVED_PEER,
+ CLOSING,
UNDEFINED
};
diff --git a/tests/unit_tests/ipc/ut-ipc.cpp b/tests/unit_tests/ipc/ut-ipc.cpp
index ea70b45..5d284bd 100644
--- a/tests/unit_tests/ipc/ut-ipc.cpp
+++ b/tests/unit_tests/ipc/ut-ipc.cpp
@@ -71,6 +71,27 @@ struct SendData {
)
};
+struct LongSendData {
+ LongSendData(int i = 0, int waitTime = 1000): mSendData(i), mWaitTime(waitTime), intVal(i) {}
+
+ template
+ void accept(Visitor visitor)
+ {
+ std::this_thread::sleep_for(std::chrono::milliseconds(mWaitTime));
+ mSendData.accept(visitor);
+ }
+ template
+ void accept(Visitor visitor) const
+ {
+ std::this_thread::sleep_for(std::chrono::milliseconds(mWaitTime));
+ mSendData.accept(visitor);
+ }
+
+ SendData mSendData;
+ int mWaitTime;
+ int intVal;
+};
+
struct EmptyData {
CONFIG_REGISTER_EMPTY
};
@@ -441,6 +462,45 @@ BOOST_AUTO_TEST_CASE(DisconnectedPeerErrorTest)
}
+BOOST_AUTO_TEST_CASE(ReadTimeoutTest)
+{
+ Service s(socketPath);
+ auto longEchoCallback = [](std::shared_ptr& data) {
+ return std::shared_ptr(new LongSendData(data->intVal));
+ };
+ s.addMethodHandler(1, longEchoCallback);
+ s.start();
+
+ Client c(socketPath);
+ c.start();
+
+ // Test timeout on read
+ std::shared_ptr sentData(new SendData(334));
+ BOOST_CHECK_THROW((c.callSync(1, sentData, 100)), IPCException);
+}
+
+
+BOOST_AUTO_TEST_CASE(WriteTimeoutTest)
+{
+ Service s(socketPath);
+ s.addMethodHandler(1, echoCallback);
+ s.start();
+
+ Client c(socketPath);
+ c.start();
+
+ // Test echo with a minimal timeout
+ std::shared_ptr sentDataA(new LongSendData(34, 10 /*ms*/));
+ std::shared_ptr recvData = c.callSync(1, sentDataA, 100);
+ BOOST_CHECK_EQUAL(recvData->intVal, sentDataA->intVal);
+
+ // Test timeout on write
+ std::shared_ptr sentDataB(new LongSendData(34, 1000 /*ms*/));
+ BOOST_CHECK_THROW((c.callSync(1, sentDataB, 100)), IPCTimeoutException);
+}
+
+
+
// BOOST_AUTO_TEST_CASE(ConnectionLimitTest)
// {
// unsigned oldLimit = ipc::getMaxFDNumber();
--
2.7.4
From ee57290a9ebdb2d3d6bc5f99950c9962ae8096d2 Mon Sep 17 00:00:00 2001
From: Jan Olszak
Date: Mon, 24 Nov 2014 17:30:27 +0100
Subject: [PATCH 07/16] IPC: Refactoring
[Bug/Feature] N/A
[Cause] N/A
[Solution] N/A
[Verification] Build, install, run tests
Change-Id: I421b6af0c5da5b6f1d73d69e491e976f84894272
---
common/ipc/internals/processor.cpp | 158 ++++++++++++++++++++-----------------
common/ipc/internals/processor.hpp | 16 ++--
2 files changed, 89 insertions(+), 85 deletions(-)
diff --git a/common/ipc/internals/processor.cpp b/common/ipc/internals/processor.cpp
index 9677991..9aadfff 100644
--- a/common/ipc/internals/processor.cpp
+++ b/common/ipc/internals/processor.cpp
@@ -110,7 +110,7 @@ Processor::PeerID Processor::addPeer(const std::shared_ptr& socketPtr)
mNewSockets.push(std::move(socketInfo));
}
LOGI("New peer added. Id: " << peerID);
- mEventQueue.send(Event::NEW_PEER);
+ mEventQueue.send(Event::ADD_PEER);
return peerID;
}
@@ -125,7 +125,7 @@ void Processor::removePeer(const PeerID peerID)
mPeersToDelete.push(std::move(request));
}
- mEventQueue.send(Event::DELETE_PEER);
+ mEventQueue.send(Event::REMOVE_PEER);
auto isPeerDeleted = [&peerID, this] {
Lock lock(mSocketsMutex);
@@ -168,41 +168,6 @@ void Processor::removePeerInternal(const PeerID peerID, Status status)
resetPolling();
}
-void Processor::cleanCommunication()
-{
- while (!mEventQueue.isEmpty()) {
- switch (mEventQueue.receive()) {
- case Event::FINISH: {
- LOGD("Event FINISH after FINISH");
- break;
- }
- case Event::CALL: {
- LOGD("Event CALL after FINISH");
- Call call = getCall();
- IGNORE_EXCEPTIONS(call.process(Status::CLOSING, call.data));
- break;
- }
-
- case Event::NEW_PEER: {
- LOGD("Event NEW_PEER after FINISH");
- break;
- }
-
- case Event::DELETE_PEER: {
- LOGD("Event DELETE_PEER after FINISH");
- RemovePeerRequest request;
- {
- Lock lock(mSocketsMutex);
- request = std::move(mPeersToDelete.front());
- mPeersToDelete.pop();
- }
- request.conditionPtr->notify_all();
- break;
- }
- }
- }
-}
-
void Processor::resetPolling()
{
LOGI("Resetting polling");
@@ -432,53 +397,63 @@ bool Processor::handleEvent()
case Event::CALL: {
LOGD("Event CALL");
- return handleCall();
+ return onCall();
}
- case Event::NEW_PEER: {
- LOGD("Event NEW_PEER");
- SocketInfo socketInfo;
- {
- Lock lock(mSocketsMutex);
+ case Event::ADD_PEER: {
+ LOGD("Event ADD_PEER");
+ return onNewPeer();
+ }
- socketInfo = std::move(mNewSockets.front());
- mNewSockets.pop();
+ case Event::REMOVE_PEER: {
+ LOGD("Event REMOVE_PEER");
+ return onRemovePeer();
+ }
+ }
- if (mSockets.size() > mMaxNumberOfPeers) {
- LOGE("There are too many peers. I don't accept the connection with " << socketInfo.peerID);
- return false;
- }
- if (mSockets.count(socketInfo.peerID) != 0) {
- LOGE("There already was a socket for peerID: " << socketInfo.peerID);
- return false;
- }
+ return false;
+}
- mSockets[socketInfo.peerID] = std::move(socketInfo.socketPtr);
- }
- resetPolling();
- if (mNewPeerCallback) {
- // Notify about the new user.
- mNewPeerCallback(socketInfo.peerID);
- }
- return true;
- }
+bool Processor::onNewPeer()
+{
+ SocketInfo socketInfo;
+ {
+ Lock lock(mSocketsMutex);
- case Event::DELETE_PEER: {
- LOGD("Event DELETE_PEER");
- RemovePeerRequest request;
- {
- Lock lock(mSocketsMutex);
- request = std::move(mPeersToDelete.front());
- mPeersToDelete.pop();
+ socketInfo = std::move(mNewSockets.front());
+ mNewSockets.pop();
+
+ if (mSockets.size() > mMaxNumberOfPeers) {
+ LOGE("There are too many peers. I don't accept the connection with " << socketInfo.peerID);
+ return false;
+ }
+ if (mSockets.count(socketInfo.peerID) != 0) {
+ LOGE("There already was a socket for peerID: " << socketInfo.peerID);
+ return false;
}
- removePeerInternal(request.peerID, Status::REMOVED_PEER);
- request.conditionPtr->notify_all();
- return true;
+ mSockets[socketInfo.peerID] = std::move(socketInfo.socketPtr);
}
+ resetPolling();
+ if (mNewPeerCallback) {
+ // Notify about the new user.
+ mNewPeerCallback(socketInfo.peerID);
}
+ return true;
+}
- return false;
+bool Processor::onRemovePeer()
+{
+ RemovePeerRequest request;
+ {
+ Lock lock(mSocketsMutex);
+ request = std::move(mPeersToDelete.front());
+ mPeersToDelete.pop();
+ }
+
+ removePeerInternal(request.peerID, Status::REMOVED_PEER);
+ request.conditionPtr->notify_all();
+ return true;
}
Processor::MessageID Processor::getNextMessageID()
@@ -505,7 +480,7 @@ Processor::Call Processor::getCall()
return call;
}
-bool Processor::handleCall()
+bool Processor::onCall()
{
LOGT("Handle call (from another thread) to send a message.");
Call call = getCall();
@@ -558,5 +533,40 @@ bool Processor::handleCall()
return false;
}
+void Processor::cleanCommunication()
+{
+ while (!mEventQueue.isEmpty()) {
+ switch (mEventQueue.receive()) {
+ case Event::FINISH: {
+ LOGD("Event FINISH after FINISH");
+ break;
+ }
+ case Event::CALL: {
+ LOGD("Event CALL after FINISH");
+ Call call = getCall();
+ IGNORE_EXCEPTIONS(call.process(Status::CLOSING, call.data));
+ break;
+ }
+
+ case Event::ADD_PEER: {
+ LOGD("Event ADD_PEER after FINISH");
+ break;
+ }
+
+ case Event::REMOVE_PEER: {
+ LOGD("Event REMOVE_PEER after FINISH");
+ RemovePeerRequest request;
+ {
+ Lock lock(mSocketsMutex);
+ request = std::move(mPeersToDelete.front());
+ mPeersToDelete.pop();
+ }
+ request.conditionPtr->notify_all();
+ break;
+ }
+ }
+ }
+}
+
} // namespace ipc
} // namespace security_containers
diff --git a/common/ipc/internals/processor.hpp b/common/ipc/internals/processor.hpp
index e34bdb6..7554eb8 100644
--- a/common/ipc/internals/processor.hpp
+++ b/common/ipc/internals/processor.hpp
@@ -65,14 +65,7 @@ const unsigned int DEFAULT_MAX_NUMBER_OF_PEERS = 500;
* - Rest: The data written in a callback. One type per method.ReturnCallbacks
*
* TODO:
-* - remove ReturnCallbacks on peer disconnect
-* - on sync timeout erase the return callback
-* - don't throw timeout if the message is already processed
-* - naming convention or methods that just commissions the PROCESS thread to do something
-* - removePeer API function
-* - error handling - special message type
* - some mutexes may not be needed
-* - make addPeer synchronous like removePeer
*/
class Processor {
public:
@@ -81,7 +74,6 @@ public:
typedef unsigned int MethodID;
typedef unsigned int MessageID;
-
/**
* Method ID. Used to indicate a message with the return value.
*/
@@ -265,8 +257,8 @@ private:
enum class Event : int {
FINISH, // Shutdown request
CALL, // New method call in the queue
- NEW_PEER, // New peer in the queue
- DELETE_PEER // Delete peer
+ ADD_PEER, // New peer in the queue
+ REMOVE_PEER // Remove peer
};
EventQueue mEventQueue;
@@ -303,7 +295,9 @@ private:
void run();
bool handleEvent();
- bool handleCall();
+ bool onCall();
+ bool onNewPeer();
+ bool onRemovePeer();
bool handleLostConnections();
bool handleInputs();
bool handleInput(const PeerID peerID, const Socket& socket);
--
2.7.4
From 873c1046ffe0a34ab7ec0a4d48e59e1adae754d3 Mon Sep 17 00:00:00 2001
From: Piotr Bartosiewicz
Date: Mon, 24 Nov 2014 17:10:29 +0100
Subject: [PATCH 08/16] Fix create container from template
[Bug/Feature] Templates stops working after migration to lxc
[Cause] N/A
[Solution] N/A
[Verification] Build, install, run tests
Change-Id: Ifbc0db612391eb7460b757b3cd12dda79183178b
---
common/utils/environment.cpp | 10 +++--
common/utils/environment.hpp | 2 +-
server/configs/CMakeLists.txt | 4 ++
server/configs/lxc-templates/template.sh | 72 ++++++++++++++++++++++++++++++++
server/configs/templates/template.conf | 3 ++
server/containers-manager.cpp | 26 +++++-------
6 files changed, 98 insertions(+), 19 deletions(-)
create mode 100755 server/configs/lxc-templates/template.sh
diff --git a/common/utils/environment.cpp b/common/utils/environment.cpp
index eaaef12..73c7057 100644
--- a/common/utils/environment.cpp
+++ b/common/utils/environment.cpp
@@ -84,8 +84,9 @@ bool dropRoot(uid_t uid, gid_t gid, const std::vector& caps)
return true;
}
-bool launchAsRoot(const std::function& func)
+bool launchAsRoot(const std::function& func)
{
+ // TODO optimize if getuid() == 0
pid_t pid = fork();
if (pid < 0) {
LOGE("Fork failed: " << strerror(errno));
@@ -99,8 +100,11 @@ bool launchAsRoot(const std::function& func)
}
try {
- func();
- } catch (std::exception& e) {
+ if (!func()) {
+ LOGE("Failed to successfully execute func");
+ ::exit(EXIT_FAILURE);
+ }
+ } catch (const std::exception& e) {
LOGE("Failed to successfully execute func: " << e.what());
::exit(EXIT_FAILURE);
}
diff --git a/common/utils/environment.hpp b/common/utils/environment.hpp
index 120b6ac..07a767e 100644
--- a/common/utils/environment.hpp
+++ b/common/utils/environment.hpp
@@ -50,7 +50,7 @@ bool dropRoot(uid_t uid, gid_t gid, const std::vector& caps);
*
* This function forks, sets UID 0 to child process and calls func.
*/
-bool launchAsRoot(const std::function& func);
+bool launchAsRoot(const std::function& func);
} // namespace utils
diff --git a/server/configs/CMakeLists.txt b/server/configs/CMakeLists.txt
index ab4a94f..e4f9df9 100644
--- a/server/configs/CMakeLists.txt
+++ b/server/configs/CMakeLists.txt
@@ -21,6 +21,7 @@ MESSAGE(STATUS "Installing configs to " ${SC_CONFIG_INSTALL_DIR})
FILE(GLOB container_CONF containers/*.conf)
FILE(GLOB admin_CONF lxc-templates/*.sh)
+FILE(GLOB template_CONF templates/*.conf)
## Generate ####################################################################
CONFIGURE_FILE(systemd/security-containers.service.in
@@ -44,5 +45,8 @@ INSTALL(FILES ${container_CONF}
INSTALL(PROGRAMS ${admin_CONF}
DESTINATION ${SC_CONFIG_INSTALL_DIR}/lxc-templates)
+INSTALL(PROGRAMS ${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/lxc-templates/template.sh b/server/configs/lxc-templates/template.sh
new file mode 100755
index 0000000..c03a050
--- /dev/null
+++ b/server/configs/lxc-templates/template.sh
@@ -0,0 +1,72 @@
+#!/bin/bash
+
+echo LXC template, args: $@
+
+options=$(getopt -o p:n: -l rootfs:,path:,name: -- "$@")
+if [ $? -ne 0 ]; then
+ exit 1
+fi
+eval set -- "$options"
+
+while true
+do
+ case "$1" in
+ -p|--path) path=$2; shift 2;;
+ --rootfs) rootfs=$2; shift 2;;
+ -n|--name) name=$2; shift 2;;
+ --) shift 1; break ;;
+ *) break ;;
+ esac
+done
+
+br_name="virbr-${name}"
+sub_net="103" # TODO from param
+
+# XXX assume rootfs if mounted from iso
+
+# Prepare container configuration file
+> ${path}/config
+cat <> ${path}/config
+lxc.utsname = ${name}
+lxc.rootfs = ${rootfs}
+
+# userns 1-to-1 mapping
+#lxc.id_map = u 0 0 65536
+#lxc.id_map = g 0 0 65536
+
+lxc.pts = 256
+lxc.tty = 0
+
+lxc.mount.auto = proc sys cgroup
+lxc.mount.entry = /var/run/containers/${name}/run var/run none rw,bind 0 0
+
+lxc.network.type = veth
+lxc.network.link = ${br_name}
+lxc.network.flags = up
+lxc.network.name = eth0
+lxc.network.veth.pair = veth-${name}
+lxc.network.ipv4.gateway = 10.0.${sub_net}.1
+lxc.network.ipv4 = 10.0.${sub_net}.2/24
+
+lxc.hook.pre-start = ${path}/pre-start.sh
+
+#lxc.loglevel = TRACE
+#lxc.logfile = /tmp/${name}.log
+EOF
+
+# prepare pre start hook
+cat <> ${path}/pre-start.sh
+if [ -z "\$(/usr/sbin/brctl show | /bin/grep -P "${br_name}\t")" ]
+then
+ /usr/sbin/brctl addbr ${br_name}
+ /usr/sbin/brctl setfd ${br_name} 0
+ /sbin/ifconfig ${br_name} 10.0.${sub_net}.1 netmask 255.255.255.0 up
+fi
+if [ -z "\$(/usr/sbin/iptables -t nat -S | /bin/grep MASQUERADE)" ]
+then
+ /bin/echo 1 > /proc/sys/net/ipv4/ip_forward
+ /usr/sbin/iptables -t nat -A POSTROUTING -s 10.0.0.0/16 ! -d 10.0.0.0/16 -j MASQUERADE
+fi
+EOF
+
+chmod 755 ${path}/pre-start.sh
diff --git a/server/configs/templates/template.conf b/server/configs/templates/template.conf
index a8f47fc..f91bf5f 100644
--- a/server/configs/templates/template.conf
+++ b/server/configs/templates/template.conf
@@ -1,4 +1,7 @@
{
+ "name" : "~NAME~",
+ "lxcTemplate" : "template.sh",
+ "initWithArgs" : [],
"cpuQuotaForeground" : -1,
"cpuQuotaBackground" : 1000,
"privilege" : 10,
diff --git a/server/containers-manager.cpp b/server/containers-manager.cpp
index 62dbc14..def04c2 100644
--- a/server/containers-manager.cpp
+++ b/server/containers-manager.cpp
@@ -41,9 +41,6 @@
#include
#include
-#include
-#include
-#include
#include
#include
#include
@@ -70,7 +67,6 @@ const std::string HOST_ID = "host";
const std::string CONTAINER_TEMPLATE_CONFIG_PATH = "template.conf";
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;
@@ -522,12 +518,15 @@ void ContainersManager::handleGetContainerInfoCall(const std::string& id,
result->setError(api::ERROR_INTERNAL, "Unrecognized state of container");
return;
}
- const std::string rootPath = boost::filesystem::absolute(id, mConfig.containersPath).string();
+ const auto containerPath = boost::filesystem::absolute(id, mConfig.containersPath);
+ const auto rootfsDir = boost::filesystem::path("rootfs");
+ const auto rootfsPath = containerPath / rootfsDir;
+
result->set(g_variant_new("((siss))",
id.c_str(),
container->getVT(),
state,
- rootPath.c_str()));
+ rootfsPath.string().c_str()));
}
void ContainersManager::handleSetActiveContainerCall(const std::string& id,
@@ -581,14 +580,10 @@ void ContainersManager::generateNewConfig(const std::string& id,
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
+ // TODO change algorithm after implementing removeContainer
std::string thirdOctetStr = std::to_string(CONTAINER_IP_BASE_THIRD_OCTET + mContainers.size() + 1);
- LOGD("ip_third_octet: " << thirdOctetStr);
+ LOGD("IP third octet: " << thirdOctetStr);
resultConfig = boost::regex_replace(resultConfig, CONTAINER_IP_THIRD_OCTET_REGEX, thirdOctetStr);
if (!utils::saveFileContent(resultPath, resultConfig)) {
@@ -630,7 +625,7 @@ void ContainersManager::handleAddContainerCall(const std::string& id,
}
// copy container image if config contains path to image
- LOGT("image path: " << mConfig.containerImagePath);
+ LOGT("Image path: " << mConfig.containerImagePath);
if (!mConfig.containerImagePath.empty()) {
auto copyImageContentsWrapper = std::bind(&utils::copyImageContents,
mConfig.containerImagePath,
@@ -659,6 +654,7 @@ void ContainersManager::handleAddContainerCall(const std::string& id,
} catch(const std::exception& e) {
LOGW("Failed to remove data: " << boost::diagnostic_information(e));
}
+ return true;
};
try {
@@ -682,13 +678,13 @@ void ContainersManager::handleAddContainerCall(const std::string& id,
return;
}
- auto resultCallback = [this, id, result, containerPathStr, removeAllWrapper](bool succeeded) {
+ auto resultCallback = [this, id, result](bool succeeded) {
if (succeeded) {
focus(id);
result->setVoid();
} else {
LOGE("Failed to start container.");
- utils::launchAsRoot(std::bind(removeAllWrapper, containerPathStr));
+ // TODO removeContainer
result->setError(api::host::ERROR_CONTAINER_CREATE_FAILED,
"Failed to start container.");
}
--
2.7.4
From 42b000bb7378f7d1e686306008767ff0e7c8babe Mon Sep 17 00:00:00 2001
From: Dariusz Michaluk
Date: Tue, 25 Nov 2014 14:47:46 +0100
Subject: [PATCH 09/16] Fix RPM build error
[Bug/Feature] RPM build error
[Cause] Installed but unpackaged file found
[Solution] Add file
[Verification] Build
Change-Id: Ic4f8258386ae9a289c637cf28ac878effda0e197
Signed-off-by: Dariusz Michaluk
---
packaging/security-containers.spec | 2 ++
1 file changed, 2 insertions(+)
diff --git a/packaging/security-containers.spec b/packaging/security-containers.spec
index ee5ee83..3425c51 100644
--- a/packaging/security-containers.spec
+++ b/packaging/security-containers.spec
@@ -43,9 +43,11 @@ 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/lxc-templates
+%dir /etc/security-containers/templates
%config /etc/security-containers/daemon.conf
%config /etc/security-containers/containers/*.conf
%attr(755,root,root) /etc/security-containers/lxc-templates/*.sh
+%config /etc/security-containers/templates/*.conf
%{_unitdir}/security-containers.service
%{_unitdir}/multi-user.target.wants/security-containers.service
/etc/dbus-1/system.d/org.tizen.containers.host.conf
--
2.7.4
From e47bd19c9bb22feaebb71432ded3b2d609ac7e45 Mon Sep 17 00:00:00 2001
From: Piotr Bartosiewicz
Date: Tue, 25 Nov 2014 14:47:58 +0100
Subject: [PATCH 10/16] Templated network configuration
[Bug/Feature] N/A
[Cause] N/A
[Solution] N/A
[Verification] Build, install, run test
Change-Id: I46af4da7ad656b05193184fc972c1d7489eb25f6
---
common/lxc/domain.cpp | 7 ++-
common/lxc/domain.hpp | 2 +-
server/configs/containers/business.conf | 4 +-
server/configs/containers/private.conf | 4 +-
server/configs/lxc-templates/business.sh | 72 ----------------------
server/configs/lxc-templates/private.sh | 72 ----------------------
server/configs/lxc-templates/template.sh | 15 +++--
server/configs/templates/template.conf | 2 +
server/container-admin.cpp | 11 +++-
server/container-config.hpp | 12 ++++
.../ut-client/containers/console1-dbus.conf.in | 2 +
.../ut-client/containers/console2-dbus.conf.in | 2 +
.../ut-client/containers/console3-dbus.conf.in | 2 +
tests/unit_tests/lxc/ut-domain.cpp | 17 ++---
.../ut-container-admin/containers/buggy.conf | 2 +
.../ut-container-admin/containers/missing.conf | 2 +
.../containers/test-no-shutdown.conf | 2 +
.../ut-container-admin/containers/test.conf | 2 +
.../configs/ut-container/containers/buggy.conf | 2 +
.../ut-container/containers/test-dbus.conf.in | 2 +
.../configs/ut-container/containers/test.conf | 2 +
.../containers/console1-dbus.conf.in | 2 +
.../ut-containers-manager/containers/console1.conf | 2 +
.../containers/console2-dbus.conf.in | 2 +
.../ut-containers-manager/containers/console2.conf | 2 +
.../containers/console3-dbus.conf.in | 2 +
.../ut-containers-manager/containers/console3.conf | 2 +
.../configs/ut-server/containers/container1.conf | 2 +
.../configs/ut-server/containers/container2.conf | 2 +
.../configs/ut-server/containers/container3.conf | 2 +
30 files changed, 93 insertions(+), 163 deletions(-)
delete mode 100755 server/configs/lxc-templates/business.sh
delete mode 100755 server/configs/lxc-templates/private.sh
diff --git a/common/lxc/domain.cpp b/common/lxc/domain.cpp
index bc2e74b..191f405 100644
--- a/common/lxc/domain.cpp
+++ b/common/lxc/domain.cpp
@@ -93,9 +93,12 @@ LxcDomain::State LxcDomain::getState()
return STATE_MAP.at(str);
}
-bool LxcDomain::create(const std::string& templatePath)
+bool LxcDomain::create(const std::string& templatePath, const char* const* argv)
{
- if (!mContainer->create(mContainer, templatePath.c_str(), NULL, NULL, 0, NULL)) {
+ if (!mContainer->create(mContainer,
+ templatePath.c_str(),
+ NULL, NULL, 0,
+ const_cast(argv))) {
LOGE("Could not create domain " + getName());
return false;
}
diff --git a/common/lxc/domain.hpp b/common/lxc/domain.hpp
index 8421d6d..60ae5a4 100644
--- a/common/lxc/domain.hpp
+++ b/common/lxc/domain.hpp
@@ -64,7 +64,7 @@ public:
State getState();
- bool create(const std::string& templatePath);
+ bool create(const std::string& templatePath, const char* const* argv);
bool destroy();
bool start(const char* const* argv);
diff --git a/server/configs/containers/business.conf b/server/configs/containers/business.conf
index 92eb06d..b211ce3 100644
--- a/server/configs/containers/business.conf
+++ b/server/configs/containers/business.conf
@@ -1,7 +1,9 @@
{
"name" : "business",
- "lxcTemplate" : "business.sh",
+ "lxcTemplate" : "template.sh",
"initWithArgs" : [],
+ "ipv4Gateway" : "10.0.102.1",
+ "ipv4" : "10.0.102.2",
"cpuQuotaForeground" : -1,
"cpuQuotaBackground" : 10000,
"enableDbusIntegration" : true,
diff --git a/server/configs/containers/private.conf b/server/configs/containers/private.conf
index 074f4f3..b4fb56a 100644
--- a/server/configs/containers/private.conf
+++ b/server/configs/containers/private.conf
@@ -1,7 +1,9 @@
{
"name" : "private",
- "lxcTemplate" : "private.sh",
+ "lxcTemplate" : "template.sh",
"initWithArgs" : [],
+ "ipv4Gateway" : "10.0.101.1",
+ "ipv4" : "10.0.101.2",
"cpuQuotaForeground" : -1,
"cpuQuotaBackground" : 10000,
"enableDbusIntegration" : true,
diff --git a/server/configs/lxc-templates/business.sh b/server/configs/lxc-templates/business.sh
deleted file mode 100755
index 21f7d2e..0000000
--- a/server/configs/lxc-templates/business.sh
+++ /dev/null
@@ -1,72 +0,0 @@
-#!/bin/bash
-
-echo LXC template, args: $@
-
-options=$(getopt -o p:n: -l rootfs:,path:,name: -- "$@")
-if [ $? -ne 0 ]; then
- exit 1
-fi
-eval set -- "$options"
-
-while true
-do
- case "$1" in
- -p|--path) path=$2; shift 2;;
- --rootfs) rootfs=$2; shift 2;;
- -n|--name) name=$2; shift 2;;
- --) shift 1; break ;;
- *) break ;;
- esac
-done
-
-br_name="virbr-${name}"
-sub_net="101" # TODO from param
-
-# XXX assume rootfs if mounted from iso
-
-# Prepare container configuration file
-> ${path}/config
-cat <> ${path}/config
-lxc.utsname = ${name}
-lxc.rootfs = ${rootfs}
-
-# userns 1-to-1 mapping
-#lxc.id_map = u 0 0 65536
-#lxc.id_map = g 0 0 65536
-
-lxc.pts = 256
-lxc.tty = 0
-
-lxc.mount.auto = proc sys cgroup
-lxc.mount.entry = /var/run/containers/${name}/run var/run none rw,bind 0 0
-
-lxc.network.type = veth
-lxc.network.link = ${br_name}
-lxc.network.flags = up
-lxc.network.name = eth0
-lxc.network.veth.pair = veth-${name}
-lxc.network.ipv4.gateway = 10.0.${sub_net}.1
-lxc.network.ipv4 = 10.0.${sub_net}.2/24
-
-lxc.hook.pre-start = ${path}/pre-start.sh
-
-#lxc.loglevel = TRACE
-#lxc.logfile = /tmp/${name}.log
-EOF
-
-# prepare pre start hook
-cat <> ${path}/pre-start.sh
-if [ -z "\$(/usr/sbin/brctl show | /bin/grep -P "${br_name}\t")" ]
-then
- /usr/sbin/brctl addbr ${br_name}
- /usr/sbin/brctl setfd ${br_name} 0
- /sbin/ifconfig ${br_name} 10.0.${sub_net}.1 netmask 255.255.255.0 up
-fi
-if [ -z "\$(/usr/sbin/iptables -t nat -S | /bin/grep MASQUERADE)" ]
-then
- /bin/echo 1 > /proc/sys/net/ipv4/ip_forward
- /usr/sbin/iptables -t nat -A POSTROUTING -s 10.0.0.0/16 ! -d 10.0.0.0/16 -j MASQUERADE
-fi
-EOF
-
-chmod 755 ${path}/pre-start.sh
diff --git a/server/configs/lxc-templates/private.sh b/server/configs/lxc-templates/private.sh
deleted file mode 100755
index 542093a..0000000
--- a/server/configs/lxc-templates/private.sh
+++ /dev/null
@@ -1,72 +0,0 @@
-#!/bin/bash
-
-echo LXC template, args: $@
-
-options=$(getopt -o p:n: -l rootfs:,path:,name: -- "$@")
-if [ $? -ne 0 ]; then
- exit 1
-fi
-eval set -- "$options"
-
-while true
-do
- case "$1" in
- -p|--path) path=$2; shift 2;;
- --rootfs) rootfs=$2; shift 2;;
- -n|--name) name=$2; shift 2;;
- --) shift 1; break ;;
- *) break ;;
- esac
-done
-
-br_name="virbr-${name}"
-sub_net="102" # TODO from param
-
-# XXX assume rootfs if mounted from iso
-
-# Prepare container configuration file
-> ${path}/config
-cat <> ${path}/config
-lxc.utsname = ${name}
-lxc.rootfs = ${rootfs}
-
-# userns 1-to-1 mapping
-#lxc.id_map = u 0 0 65536
-#lxc.id_map = g 0 0 65536
-
-lxc.pts = 256
-lxc.tty = 0
-
-lxc.mount.auto = proc sys cgroup
-lxc.mount.entry = /var/run/containers/${name}/run var/run none rw,bind 0 0
-
-lxc.network.type = veth
-lxc.network.link = ${br_name}
-lxc.network.flags = up
-lxc.network.name = eth0
-lxc.network.veth.pair = veth-${name}
-lxc.network.ipv4.gateway = 10.0.${sub_net}.1
-lxc.network.ipv4 = 10.0.${sub_net}.2/24
-
-lxc.hook.pre-start = ${path}/pre-start.sh
-
-#lxc.loglevel = TRACE
-#lxc.logfile = /tmp/${name}.log
-EOF
-
-# prepare pre start hook
-cat <> ${path}/pre-start.sh
-if [ -z "\$(/usr/sbin/brctl show | /bin/grep -P "${br_name}\t")" ]
-then
- /usr/sbin/brctl addbr ${br_name}
- /usr/sbin/brctl setfd ${br_name} 0
- /sbin/ifconfig ${br_name} 10.0.${sub_net}.1 netmask 255.255.255.0 up
-fi
-if [ -z "\$(/usr/sbin/iptables -t nat -S | /bin/grep MASQUERADE)" ]
-then
- /bin/echo 1 > /proc/sys/net/ipv4/ip_forward
- /usr/sbin/iptables -t nat -A POSTROUTING -s 10.0.0.0/16 ! -d 10.0.0.0/16 -j MASQUERADE
-fi
-EOF
-
-chmod 755 ${path}/pre-start.sh
diff --git a/server/configs/lxc-templates/template.sh b/server/configs/lxc-templates/template.sh
index c03a050..531ec30 100755
--- a/server/configs/lxc-templates/template.sh
+++ b/server/configs/lxc-templates/template.sh
@@ -2,7 +2,7 @@
echo LXC template, args: $@
-options=$(getopt -o p:n: -l rootfs:,path:,name: -- "$@")
+options=$(getopt -o p:n: -l rootfs:,path:,name:,ipv4:,ipv4-gateway: -- "$@")
if [ $? -ne 0 ]; then
exit 1
fi
@@ -14,13 +14,14 @@ do
-p|--path) path=$2; shift 2;;
--rootfs) rootfs=$2; shift 2;;
-n|--name) name=$2; shift 2;;
+ --ipv4) ipv4=$2; shift 2;;
+ --ipv4-gateway) ipv4_gateway=$2; shift 2;;
--) shift 1; break ;;
*) break ;;
esac
done
br_name="virbr-${name}"
-sub_net="103" # TODO from param
# XXX assume rootfs if mounted from iso
@@ -40,13 +41,16 @@ lxc.tty = 0
lxc.mount.auto = proc sys cgroup
lxc.mount.entry = /var/run/containers/${name}/run var/run none rw,bind 0 0
+# create a separate network per container
+# - it forbids traffic sniffing (like macvlan in bridge mode)
+# - it enables traffic controlling from host using iptables
lxc.network.type = veth
lxc.network.link = ${br_name}
lxc.network.flags = up
lxc.network.name = eth0
lxc.network.veth.pair = veth-${name}
-lxc.network.ipv4.gateway = 10.0.${sub_net}.1
-lxc.network.ipv4 = 10.0.${sub_net}.2/24
+lxc.network.ipv4.gateway = ${ipv4_gateway}
+lxc.network.ipv4 = ${ipv4}/24
lxc.hook.pre-start = ${path}/pre-start.sh
@@ -55,12 +59,13 @@ lxc.hook.pre-start = ${path}/pre-start.sh
EOF
# prepare pre start hook
+> ${path}/pre-start.sh
cat <> ${path}/pre-start.sh
if [ -z "\$(/usr/sbin/brctl show | /bin/grep -P "${br_name}\t")" ]
then
/usr/sbin/brctl addbr ${br_name}
/usr/sbin/brctl setfd ${br_name} 0
- /sbin/ifconfig ${br_name} 10.0.${sub_net}.1 netmask 255.255.255.0 up
+ /sbin/ifconfig ${br_name} ${ipv4_gateway} netmask 255.255.255.0 up
fi
if [ -z "\$(/usr/sbin/iptables -t nat -S | /bin/grep MASQUERADE)" ]
then
diff --git a/server/configs/templates/template.conf b/server/configs/templates/template.conf
index f91bf5f..1939d51 100644
--- a/server/configs/templates/template.conf
+++ b/server/configs/templates/template.conf
@@ -2,6 +2,8 @@
"name" : "~NAME~",
"lxcTemplate" : "template.sh",
"initWithArgs" : [],
+ "ipv4Gateway" : "10.0.~IP~.1",
+ "ipv4" : "10.0.~IP~.2",
"cpuQuotaForeground" : -1,
"cpuQuotaBackground" : 1000,
"privilege" : 10,
diff --git a/server/container-admin.cpp b/server/container-admin.cpp
index 71185db..ef8ae0f 100644
--- a/server/container-admin.cpp
+++ b/server/container-admin.cpp
@@ -91,7 +91,16 @@ ContainerAdmin::ContainerAdmin(const std::string& containersPath,
const std::string lxcTemplate = utils::getAbsolutePath(config.lxcTemplate,
lxcTemplatePrefix);
LOGI(mId << ": Creating domain from template: " << lxcTemplate);
- if (!mDom.create(lxcTemplate)) {
+ std::vector args;
+ if (!config.ipv4Gateway.empty()) {
+ args.push_back("--ipv4-gateway");
+ args.push_back(config.ipv4Gateway);
+ }
+ if (!config.ipv4.empty()) {
+ args.push_back("--ipv4");
+ args.push_back(config.ipv4);
+ }
+ if (!mDom.create(lxcTemplate, Args(args).getAsCArray())) {
throw ContainerOperationException("Could not create domain");
}
}
diff --git a/server/container-config.hpp b/server/container-config.hpp
index 95030e0..779415d 100644
--- a/server/container-config.hpp
+++ b/server/container-config.hpp
@@ -53,6 +53,16 @@ struct ContainerConfig {
std::vector initWithArgs;
/**
+ * IP v4 gateway address
+ */
+ std::string ipv4Gateway;
+
+ /**
+ * IP v4 address
+ */
+ std::string ipv4;
+
+ /**
* Privilege of the container.
* The smaller the value the more important the container
*/
@@ -107,6 +117,8 @@ struct ContainerConfig {
name,
lxcTemplate,
initWithArgs,
+ ipv4Gateway,
+ ipv4,
privilege,
vt,
switchToDefaultAfterTimeout,
diff --git a/tests/unit_tests/client/configs/ut-client/containers/console1-dbus.conf.in b/tests/unit_tests/client/configs/ut-client/containers/console1-dbus.conf.in
index 6855a28..bf8d1fc 100644
--- a/tests/unit_tests/client/configs/ut-client/containers/console1-dbus.conf.in
+++ b/tests/unit_tests/client/configs/ut-client/containers/console1-dbus.conf.in
@@ -2,6 +2,8 @@
"name" : "ut-containers-manager-console1-dbus",
"lxcTemplate" : "minimal-dbus1.sh",
"initWithArgs" : ["/bin/sh", "-c", "trap exit SIGTERM; /usr/bin/dbus-daemon --config-file=@SC_TEST_CONFIG_INSTALL_DIR@/server/ut-containers-manager/ut-dbus.conf --fork; read"],
+ "ipv4Gateway" : "",
+ "ipv4" : "",
"privilege" : 20,
"vt" : -1,
"switchToDefaultAfterTimeout" : true,
diff --git a/tests/unit_tests/client/configs/ut-client/containers/console2-dbus.conf.in b/tests/unit_tests/client/configs/ut-client/containers/console2-dbus.conf.in
index 728522a..73ff1b3 100644
--- a/tests/unit_tests/client/configs/ut-client/containers/console2-dbus.conf.in
+++ b/tests/unit_tests/client/configs/ut-client/containers/console2-dbus.conf.in
@@ -2,6 +2,8 @@
"name" : "ut-containers-manager-console2-dbus",
"lxcTemplate" : "minimal-dbus2.sh",
"initWithArgs" : ["/bin/sh", "-c", "trap exit SIGTERM; /usr/bin/dbus-daemon --config-file=@SC_TEST_CONFIG_INSTALL_DIR@/server/ut-containers-manager/ut-dbus.conf --fork; read"],
+ "ipv4Gateway" : "",
+ "ipv4" : "",
"privilege" : 20,
"vt" : -1,
"switchToDefaultAfterTimeout" : false,
diff --git a/tests/unit_tests/client/configs/ut-client/containers/console3-dbus.conf.in b/tests/unit_tests/client/configs/ut-client/containers/console3-dbus.conf.in
index d273e57..c8a0a01 100644
--- a/tests/unit_tests/client/configs/ut-client/containers/console3-dbus.conf.in
+++ b/tests/unit_tests/client/configs/ut-client/containers/console3-dbus.conf.in
@@ -2,6 +2,8 @@
"name" : "ut-containers-manager-console3-dbus",
"lxcTemplate" : "minimal-dbus3.sh",
"initWithArgs" : ["/bin/sh", "-c", "trap exit SIGTERM; /usr/bin/dbus-daemon --config-file=@SC_TEST_CONFIG_INSTALL_DIR@/server/ut-containers-manager/ut-dbus.conf --fork; read"],
+ "ipv4Gateway" : "",
+ "ipv4" : "",
"privilege" : 20,
"vt" : -1,
"switchToDefaultAfterTimeout" : true,
diff --git a/tests/unit_tests/lxc/ut-domain.cpp b/tests/unit_tests/lxc/ut-domain.cpp
index aa6c3a9..a529f9f 100644
--- a/tests/unit_tests/lxc/ut-domain.cpp
+++ b/tests/unit_tests/lxc/ut-domain.cpp
@@ -42,6 +42,7 @@ using namespace security_containers::lxc;
const std::string LXC_PATH = "/tmp/ut-lxc/";
const std::string DOMAIN_NAME = "ut-domain";
const std::string TEMPLATE = SC_TEST_LXC_TEMPLATES_INSTALL_DIR "/minimal.sh";
+const char* TEMPLATE_ARGS[] = {NULL};
struct Fixture {
utils::ScopedDir mLxcDirGuard;
@@ -89,7 +90,7 @@ BOOST_AUTO_TEST_CASE(CreateDestroyTest)
LxcDomain lxc(LXC_PATH, DOMAIN_NAME);
BOOST_CHECK(!lxc.isDefined());
- BOOST_CHECK(lxc.create(TEMPLATE));
+ BOOST_CHECK(lxc.create(TEMPLATE, TEMPLATE_ARGS));
BOOST_CHECK(lxc.isDefined());
BOOST_CHECK_EQUAL(lxc.getConfigItem("lxc.rootfs"), LXC_PATH + DOMAIN_NAME + "/rootfs");
@@ -104,7 +105,7 @@ BOOST_AUTO_TEST_CASE(StartShutdownTest)
{
{
LxcDomain lxc(LXC_PATH, DOMAIN_NAME);
- BOOST_CHECK(lxc.create(TEMPLATE));
+ BOOST_CHECK(lxc.create(TEMPLATE, TEMPLATE_ARGS));
}
LxcDomain lxc(LXC_PATH, DOMAIN_NAME);
BOOST_CHECK(lxc.getState() == LxcDomain::State::STOPPED);
@@ -127,7 +128,7 @@ BOOST_AUTO_TEST_CASE(StartStopTest)
{
{
LxcDomain lxc(LXC_PATH, DOMAIN_NAME);
- BOOST_CHECK(lxc.create(TEMPLATE));
+ BOOST_CHECK(lxc.create(TEMPLATE, TEMPLATE_ARGS));
}
LxcDomain lxc(LXC_PATH, DOMAIN_NAME);
BOOST_CHECK(lxc.getState() == LxcDomain::State::STOPPED);
@@ -149,7 +150,7 @@ BOOST_AUTO_TEST_CASE(StartHasStoppedTest)
{
{
LxcDomain lxc(LXC_PATH, DOMAIN_NAME);
- BOOST_CHECK(lxc.create(TEMPLATE));
+ BOOST_CHECK(lxc.create(TEMPLATE, TEMPLATE_ARGS));
}
LxcDomain lxc(LXC_PATH, DOMAIN_NAME);
BOOST_CHECK(lxc.getState() == LxcDomain::State::STOPPED);
@@ -170,7 +171,7 @@ BOOST_AUTO_TEST_CASE(StartHasStoppedTest)
BOOST_AUTO_TEST_CASE(FreezeUnfreezeTest)
{
LxcDomain lxc(LXC_PATH, DOMAIN_NAME);
- BOOST_CHECK(lxc.create(TEMPLATE));
+ BOOST_CHECK(lxc.create(TEMPLATE, TEMPLATE_ARGS));
const char* argv[] = {
"/bin/sh",
"-c",
@@ -193,7 +194,7 @@ BOOST_AUTO_TEST_CASE(FreezeUnfreezeTest)
BOOST_AUTO_TEST_CASE(FreezeStopTest)
{
LxcDomain lxc(LXC_PATH, DOMAIN_NAME);
- BOOST_CHECK(lxc.create(TEMPLATE));
+ BOOST_CHECK(lxc.create(TEMPLATE, TEMPLATE_ARGS));
const char* argv[] = {
"/bin/sh",
"-c",
@@ -216,8 +217,8 @@ BOOST_AUTO_TEST_CASE(FreezeStopTest)
BOOST_AUTO_TEST_CASE(RepeatTest)
{
LxcDomain lxc(LXC_PATH, DOMAIN_NAME);
- BOOST_CHECK(lxc.create(TEMPLATE));
- BOOST_CHECK(!lxc.create(TEMPLATE));// forbidden
+ BOOST_CHECK(lxc.create(TEMPLATE, TEMPLATE_ARGS));
+ BOOST_CHECK(!lxc.create(TEMPLATE, TEMPLATE_ARGS));// forbidden
const char* argv[] = {
"/bin/sh",
"-c",
diff --git a/tests/unit_tests/server/configs/ut-container-admin/containers/buggy.conf b/tests/unit_tests/server/configs/ut-container-admin/containers/buggy.conf
index 22f5810..ffa8652 100644
--- a/tests/unit_tests/server/configs/ut-container-admin/containers/buggy.conf
+++ b/tests/unit_tests/server/configs/ut-container-admin/containers/buggy.conf
@@ -2,6 +2,8 @@
"name" : "ut-container-admin-test",
"lxcTemplate" : "minimal.sh",
"initWithArgs" : ["/foo"],
+ "ipv4Gateway" : "",
+ "ipv4" : "",
"privilege" : 10,
"vt" : -1,
"switchToDefaultAfterTimeout" : true,
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 6ff36fe..686dde2 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
@@ -2,6 +2,8 @@
"name" : "ut-container-admin-test",
"lxcTemplate" : "missing.sh",
"initWithArgs" : ["/bin/sh", "-c", "trap exit SIGTERM; read"],
+ "ipv4Gateway" : "",
+ "ipv4" : "",
"privilege" : 10,
"vt" : -1,
"switchToDefaultAfterTimeout" : true,
diff --git a/tests/unit_tests/server/configs/ut-container-admin/containers/test-no-shutdown.conf b/tests/unit_tests/server/configs/ut-container-admin/containers/test-no-shutdown.conf
index 7877f8e..307afd5 100644
--- a/tests/unit_tests/server/configs/ut-container-admin/containers/test-no-shutdown.conf
+++ b/tests/unit_tests/server/configs/ut-container-admin/containers/test-no-shutdown.conf
@@ -2,6 +2,8 @@
"name" : "ut-container-admin-test",
"lxcTemplate" : "minimal.sh",
"initWithArgs" : ["/bin/sh"],
+ "ipv4Gateway" : "",
+ "ipv4" : "",
"privilege" : 10,
"vt" : -1,
"switchToDefaultAfterTimeout" : true,
diff --git a/tests/unit_tests/server/configs/ut-container-admin/containers/test.conf b/tests/unit_tests/server/configs/ut-container-admin/containers/test.conf
index a7cf00d..76f4a70 100644
--- a/tests/unit_tests/server/configs/ut-container-admin/containers/test.conf
+++ b/tests/unit_tests/server/configs/ut-container-admin/containers/test.conf
@@ -2,6 +2,8 @@
"name" : "ut-container-admin-test",
"lxcTemplate" : "minimal.sh",
"initWithArgs" : ["/bin/sh", "-c", "trap exit SIGTERM; read"],
+ "ipv4Gateway" : "",
+ "ipv4" : "",
"privilege" : 10,
"vt" : -1,
"switchToDefaultAfterTimeout" : true,
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 c31efc5..2af10da 100644
--- a/tests/unit_tests/server/configs/ut-container/containers/buggy.conf
+++ b/tests/unit_tests/server/configs/ut-container/containers/buggy.conf
@@ -2,6 +2,8 @@
"name" : "ut-container-test",
"lxcTemplate" : "/buggy/path",
"initWithArgs" : ["/bin/sh", "-c", "trap exit SIGTERM; read"],
+ "ipv4Gateway" : "",
+ "ipv4" : "",
"privilege" : 10,
"vt" : -1,
"switchToDefaultAfterTimeout" : true,
diff --git a/tests/unit_tests/server/configs/ut-container/containers/test-dbus.conf.in b/tests/unit_tests/server/configs/ut-container/containers/test-dbus.conf.in
index e3eaf9b..f8e60f6 100644
--- a/tests/unit_tests/server/configs/ut-container/containers/test-dbus.conf.in
+++ b/tests/unit_tests/server/configs/ut-container/containers/test-dbus.conf.in
@@ -2,6 +2,8 @@
"name" : "ut-container-test-dbus",
"lxcTemplate" : "minimal-dbus1.sh",
"initWithArgs" : ["/bin/sh", "-c", "trap exit SIGTERM; /usr/bin/dbus-daemon --config-file=@SC_TEST_CONFIG_INSTALL_DIR@/server/ut-container/ut-dbus.conf --fork; read"],
+ "ipv4Gateway" : "",
+ "ipv4" : "",
"privilege" : 10,
"vt" : -1,
"switchToDefaultAfterTimeout" : true,
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 ec6bf54..1264669 100644
--- a/tests/unit_tests/server/configs/ut-container/containers/test.conf
+++ b/tests/unit_tests/server/configs/ut-container/containers/test.conf
@@ -2,6 +2,8 @@
"name" : "ut-container-test",
"lxcTemplate" : "minimal.sh",
"initWithArgs" : ["/bin/sh", "-c", "trap exit SIGTERM; read"],
+ "ipv4Gateway" : "",
+ "ipv4" : "",
"privilege" : 10,
"vt" : -1,
"switchToDefaultAfterTimeout" : true,
diff --git a/tests/unit_tests/server/configs/ut-containers-manager/containers/console1-dbus.conf.in b/tests/unit_tests/server/configs/ut-containers-manager/containers/console1-dbus.conf.in
index 6855a28..bf8d1fc 100644
--- a/tests/unit_tests/server/configs/ut-containers-manager/containers/console1-dbus.conf.in
+++ b/tests/unit_tests/server/configs/ut-containers-manager/containers/console1-dbus.conf.in
@@ -2,6 +2,8 @@
"name" : "ut-containers-manager-console1-dbus",
"lxcTemplate" : "minimal-dbus1.sh",
"initWithArgs" : ["/bin/sh", "-c", "trap exit SIGTERM; /usr/bin/dbus-daemon --config-file=@SC_TEST_CONFIG_INSTALL_DIR@/server/ut-containers-manager/ut-dbus.conf --fork; read"],
+ "ipv4Gateway" : "",
+ "ipv4" : "",
"privilege" : 20,
"vt" : -1,
"switchToDefaultAfterTimeout" : true,
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 2bc7251..1ca1e5f 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
@@ -2,6 +2,8 @@
"name" : "ut-containers-manager-console1",
"lxcTemplate" : "minimal.sh",
"initWithArgs" : ["/bin/sh", "-c", "trap exit SIGTERM; read"],
+ "ipv4Gateway" : "",
+ "ipv4" : "",
"privilege" : 20,
"vt" : -1,
"switchToDefaultAfterTimeout" : true,
diff --git a/tests/unit_tests/server/configs/ut-containers-manager/containers/console2-dbus.conf.in b/tests/unit_tests/server/configs/ut-containers-manager/containers/console2-dbus.conf.in
index 728522a..73ff1b3 100644
--- a/tests/unit_tests/server/configs/ut-containers-manager/containers/console2-dbus.conf.in
+++ b/tests/unit_tests/server/configs/ut-containers-manager/containers/console2-dbus.conf.in
@@ -2,6 +2,8 @@
"name" : "ut-containers-manager-console2-dbus",
"lxcTemplate" : "minimal-dbus2.sh",
"initWithArgs" : ["/bin/sh", "-c", "trap exit SIGTERM; /usr/bin/dbus-daemon --config-file=@SC_TEST_CONFIG_INSTALL_DIR@/server/ut-containers-manager/ut-dbus.conf --fork; read"],
+ "ipv4Gateway" : "",
+ "ipv4" : "",
"privilege" : 20,
"vt" : -1,
"switchToDefaultAfterTimeout" : false,
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 9a0134f..155910b 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
@@ -2,6 +2,8 @@
"name" : "ut-containers-manager-console2",
"lxcTemplate" : "minimal.sh",
"initWithArgs" : ["/bin/sh", "-c", "trap exit SIGTERM; read"],
+ "ipv4Gateway" : "",
+ "ipv4" : "",
"privilege" : 10,
"vt" : -1,
"switchToDefaultAfterTimeout" : true,
diff --git a/tests/unit_tests/server/configs/ut-containers-manager/containers/console3-dbus.conf.in b/tests/unit_tests/server/configs/ut-containers-manager/containers/console3-dbus.conf.in
index d273e57..c8a0a01 100644
--- a/tests/unit_tests/server/configs/ut-containers-manager/containers/console3-dbus.conf.in
+++ b/tests/unit_tests/server/configs/ut-containers-manager/containers/console3-dbus.conf.in
@@ -2,6 +2,8 @@
"name" : "ut-containers-manager-console3-dbus",
"lxcTemplate" : "minimal-dbus3.sh",
"initWithArgs" : ["/bin/sh", "-c", "trap exit SIGTERM; /usr/bin/dbus-daemon --config-file=@SC_TEST_CONFIG_INSTALL_DIR@/server/ut-containers-manager/ut-dbus.conf --fork; read"],
+ "ipv4Gateway" : "",
+ "ipv4" : "",
"privilege" : 20,
"vt" : -1,
"switchToDefaultAfterTimeout" : true,
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 6ff8900..a144c79 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
@@ -2,6 +2,8 @@
"name" : "ut-containers-manager-console3",
"lxcTemplate" : "minimal.sh",
"initWithArgs" : ["/bin/sh", "-c", "trap exit SIGTERM; read"],
+ "ipv4Gateway" : "",
+ "ipv4" : "",
"privilege" : 15,
"vt" : -1,
"switchToDefaultAfterTimeout" : true,
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 d232bc3..995efb4 100644
--- a/tests/unit_tests/server/configs/ut-server/containers/container1.conf
+++ b/tests/unit_tests/server/configs/ut-server/containers/container1.conf
@@ -2,6 +2,8 @@
"name" : "ut-server-container1",
"lxcTemplate" : "minimal.sh",
"initWithArgs" : ["/bin/sh", "-c", "trap exit SIGTERM; read"],
+ "ipv4Gateway" : "",
+ "ipv4" : "",
"privilege" : 20,
"vt" : -1,
"switchToDefaultAfterTimeout" : true,
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 650782f..1e9b3b7 100644
--- a/tests/unit_tests/server/configs/ut-server/containers/container2.conf
+++ b/tests/unit_tests/server/configs/ut-server/containers/container2.conf
@@ -2,6 +2,8 @@
"name" : "ut-server-container2",
"lxcTemplate" : "minimal.sh",
"initWithArgs" : ["/bin/sh", "-c", "trap exit SIGTERM; read"],
+ "ipv4Gateway" : "",
+ "ipv4" : "",
"privilege" : 10,
"vt" : -1,
"switchToDefaultAfterTimeout" : true,
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 0d9f947..47396f5 100644
--- a/tests/unit_tests/server/configs/ut-server/containers/container3.conf
+++ b/tests/unit_tests/server/configs/ut-server/containers/container3.conf
@@ -2,6 +2,8 @@
"name" : "ut-server-container3",
"lxcTemplate" : "minimal.sh",
"initWithArgs" : ["/bin/sh", "-c", "trap exit SIGTERM; read"],
+ "ipv4Gateway" : "",
+ "ipv4" : "",
"privilege" : 15,
"vt" : -1,
"switchToDefaultAfterTimeout" : true,
--
2.7.4
From 734be9c06a56b1492ea90589ebfb6af0667d7841 Mon Sep 17 00:00:00 2001
From: Dariusz Michaluk
Date: Tue, 25 Nov 2014 14:33:28 +0100
Subject: [PATCH 11/16] Add client stubs for domain lifetime management
[Bug/Feature] Client stubs for domain lifetime management
[Cause] N/A
[Solution] N/A
[Verification] Build
Change-Id: I4b6b659e4de5e18d2b00851ecbdeacfd80e3d442
Signed-off-by: Dariusz Michaluk
---
client/security-containers-client-impl.cpp | 12 ++++++++++++
client/security-containers-client-impl.hpp | 10 ++++++++++
client/security-containers-client.cpp | 10 ++++++++++
client/security-containers-client.h | 18 ++++++++++++++++++
4 files changed, 50 insertions(+)
diff --git a/client/security-containers-client-impl.cpp b/client/security-containers-client-impl.cpp
index 2fcc776..0f08a02 100644
--- a/client/security-containers-client-impl.cpp
+++ b/client/security-containers-client-impl.cpp
@@ -471,6 +471,18 @@ VsmStatus Client::vsm_start_domain(const char*) noexcept
return vsm_get_status();
}
+VsmStatus Client::vsm_lock_domain(const char*) noexcept
+{
+ mStatus = Status(VSMCLIENT_OTHER_ERROR, "Not implemented");
+ return vsm_get_status();
+}
+
+VsmStatus Client::vsm_unlock_domain(const char*) noexcept
+{
+ mStatus = Status(VSMCLIENT_OTHER_ERROR, "Not implemented");
+ return vsm_get_status();
+}
+
VsmStatus Client::vsm_add_state_callback(VsmContainerDbusStateCallback containerDbusStateCallback,
void* data,
VsmSubscriptionId* subscriptionId) noexcept
diff --git a/client/security-containers-client-impl.hpp b/client/security-containers-client-impl.hpp
index 48e1c19..df07099 100644
--- a/client/security-containers-client-impl.hpp
+++ b/client/security-containers-client-impl.hpp
@@ -159,6 +159,16 @@ public:
VsmStatus vsm_start_domain(const char* id) noexcept;
/**
+ * @see ::vsm_lock_domain
+ */
+ VsmStatus vsm_lock_domain(const char* id) noexcept;
+
+ /**
+ * @see ::vsm_unlock_domain
+ */
+ VsmStatus vsm_unlock_domain(const char* id) noexcept;
+
+ /**
* @see ::vsm_add_state_callback
*/
VsmStatus vsm_add_state_callback(VsmContainerDbusStateCallback containerDbusStateCallback,
diff --git a/client/security-containers-client.cpp b/client/security-containers-client.cpp
index e867a9e..b96718f 100644
--- a/client/security-containers-client.cpp
+++ b/client/security-containers-client.cpp
@@ -173,6 +173,16 @@ API VsmStatus vsm_start_domain(VsmClient client, const char* id)
return getClient(client).vsm_start_domain(id);
}
+API VsmStatus vsm_lock_domain(VsmClient client, const char* id)
+{
+ return getClient(client).vsm_lock_domain(id);
+}
+
+API VsmStatus vsm_unlock_domain(VsmClient client, const char* id)
+{
+ return getClient(client).vsm_unlock_domain(id);
+}
+
API VsmStatus vsm_add_state_callback(VsmClient client,
VsmContainerDbusStateCallback containerDbusStateCallback,
void* data,
diff --git a/client/security-containers-client.h b/client/security-containers-client.h
index ee16e01..b796c16 100644
--- a/client/security-containers-client.h
+++ b/client/security-containers-client.h
@@ -401,6 +401,24 @@ VsmStatus vsm_shutdown_domain(VsmClient client, const char* id);
VsmStatus vsm_start_domain(VsmClient client, const char* id);
/**
+ * Lock domain
+ *
+ * @param[in] client security-containers-server's client
+ * @param[in] id domain name
+ * @return status of this function call
+ */
+VsmStatus vsm_lock_domain(VsmClient client, const char* id);
+
+/**
+ * Unlock domain
+ *
+ * @param[in] client security-containers-server's client
+ * @param[in] id domain name
+ * @return status of this function call
+ */
+VsmStatus vsm_unlock_domain(VsmClient client, const char* id);
+
+/**
* Register dbus state change callback function.
*
* @note The callback function will be invoked on a different thread.
--
2.7.4
From 8bf786c5dbd0a19132e439fc0800a613aa4fa544 Mon Sep 17 00:00:00 2001
From: Dariusz Michaluk
Date: Tue, 25 Nov 2014 16:13:41 +0100
Subject: [PATCH 12/16] Added lock_domain/unlock_domain to cli
[Feature] Ability to lock/unlock domain through cli
[Cause] The need for the ability to lock/unlock domains
[Solution] Add lock_domain/unlock_domain cli function
[Verification] Build, install, run
Change-Id: I4a017b328f0b44913f0561bd444e913c68f67359
Signed-off-by: Dariusz Michaluk
---
cli/command-line-interface.cpp | 22 ++++++++++++++++++++++
cli/command-line-interface.hpp | 14 ++++++++++++++
cli/main.cpp | 16 ++++++++++++++++
3 files changed, 52 insertions(+)
diff --git a/cli/command-line-interface.cpp b/cli/command-line-interface.cpp
index d027e63..0549afd 100644
--- a/cli/command-line-interface.cpp
+++ b/cli/command-line-interface.cpp
@@ -154,6 +154,28 @@ void create_domain(int pos, int argc, const char** argv)
one_shot(bind(vsm_create_domain, _1, argv[pos + 1], nullptr));
}
+void lock_domain(int pos, int argc, const char** argv)
+{
+ using namespace std::placeholders;
+
+ if (argc <= pos + 1) {
+ throw runtime_error("Not enough parameters");
+ }
+
+ one_shot(bind(vsm_lock_domain, _1, argv[pos + 1]));
+}
+
+void unlock_domain(int pos, int argc, const char** argv)
+{
+ using namespace std::placeholders;
+
+ if (argc <= pos + 1) {
+ throw runtime_error("Not enough parameters");
+ }
+
+ one_shot(bind(vsm_unlock_domain, _1, argv[pos + 1]));
+}
+
void lookup_domain_by_id(int pos, int argc, const char** argv)
{
using namespace std::placeholders;
diff --git a/cli/command-line-interface.hpp b/cli/command-line-interface.hpp
index c254d84..41f5048 100644
--- a/cli/command-line-interface.hpp
+++ b/cli/command-line-interface.hpp
@@ -111,6 +111,20 @@ void set_active_container(int pos, int argc, const char** argv);
void create_domain(int pos, int argc, const char** argv);
/**
+ * Parses command line arguments and call vsm_lock_domain
+ *
+ * @see vsm_lock_domain
+ */
+void lock_domain(int pos, int argc, const char** argv);
+
+/**
+ * Parses command line arguments and call vsm_unlock_domain
+ *
+ * @see vsm_unlock_domain
+ */
+void unlock_domain(int pos, int argc, const char** argv);
+
+/**
* Parses command line arguments and call vsm_lookup_domain_by_id
*
* @see vsm_lookup_domain_by_id
diff --git a/cli/main.cpp b/cli/main.cpp
index d701475..774881b 100644
--- a/cli/main.cpp
+++ b/cli/main.cpp
@@ -50,6 +50,22 @@ std::map commands = {
}
},
{
+ "lock_domain", {
+ lock_domain,
+ "lock_domain container_id",
+ "Lock container",
+ {{"container_id", "id container name"}}
+ }
+ },
+ {
+ "unlock_domain", {
+ unlock_domain,
+ "unlock_domain container_id",
+ "Unlock container",
+ {{"container_id", "id container name"}}
+ }
+ },
+ {
"lookup_domain_by_id", {
lookup_domain_by_id,
"lookup_domain_by_id container_id",
--
2.7.4
From 67c0aa5c4ea021326fd0d1565143543e29f468a2 Mon Sep 17 00:00:00 2001
From: Dariusz Michaluk
Date: Mon, 24 Nov 2014 15:33:27 +0100
Subject: [PATCH 13/16] Add tizen common (with wayland) lxc template
Change-Id: If6d1fe2641f9a36a7d3a8c16b9a658661491ff13
Signed-off-by: Dariusz Michaluk
---
.../configs/lxc-templates/tizen-common-wayland.sh | 398 +++++++++++++++++++++
1 file changed, 398 insertions(+)
create mode 100755 server/configs/lxc-templates/tizen-common-wayland.sh
diff --git a/server/configs/lxc-templates/tizen-common-wayland.sh b/server/configs/lxc-templates/tizen-common-wayland.sh
new file mode 100755
index 0000000..002e1f7
--- /dev/null
+++ b/server/configs/lxc-templates/tizen-common-wayland.sh
@@ -0,0 +1,398 @@
+#!/bin/bash
+
+# lxc-tizen template script
+#
+# Copyright (c) 2000 - 2014 Samsung Electronics Co., Ltd All Rights Reserved
+#
+# Contact: Dariusz Michaluk
+#
+# 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.
+
+usage()
+{
+ cat <
+ [-p|--path=] [-r|--rootfs=] [-v|--vt=]
+ [--ipv4=] [--ipv4-gateway=] [-h|--help]
+Mandatory args:
+ -n,--name container name
+Optional args:
+ -p,--path path to container config files, defaults to /var/lib/lxc
+ --rootfs path to container rootfs, defaults to /var/lib/lxc/[NAME]/rootfs
+ -v,--vt container virtual terminal
+ --ipv4 container IP address
+ --ipv4-gateway container gateway
+ -h,--help print help
+EOF
+ return 0
+}
+
+options=$(getopt -o hp:v:n: -l help,rootfs:,path:,vt:,name:,ipv4:,ipv4-gateway: -- "$@")
+if [ $? -ne 0 ]; then
+ usage $(basename $0)
+ exit 1
+fi
+eval set -- "$options"
+
+while true
+do
+ case "$1" in
+ -h|--help) usage $0 && exit 0;;
+ --rootfs) rootfs=$2; shift 2;;
+ -p|--path) path=$2; shift 2;;
+ -v|--vt) vt=$2; shift 2;;
+ -n|--name) name=$2; shift 2;;
+ --ipv4) ipv4=$2; shift 2;;
+ --ipv4-gateway) ipv4_gateway=$2; shift 2;;
+ --) shift 1; break ;;
+ *) break ;;
+ esac
+done
+
+if [ "$(id -u)" != "0" ]; then
+ echo "This script should be run as 'root'"
+ exit 1
+fi
+
+if [ -z $name ]; then
+ echo "Container name must be given"
+ exit 1
+fi
+
+if [ -z "$path" ]; then
+ echo "'path' parameter is required"
+ exit 1
+fi
+
+br_name="virbr-${name}"
+
+# Prepare container rootfs
+ROOTFS_DIRS="\
+${rootfs}/bin \
+${rootfs}/dev \
+${rootfs}/etc \
+${rootfs}/home \
+${rootfs}/home/alice \
+${rootfs}/home/bob \
+${rootfs}/home/carol \
+${rootfs}/home/guest \
+${rootfs}/lib \
+${rootfs}/media \
+${rootfs}/mnt \
+${rootfs}/opt \
+${rootfs}/proc \
+${rootfs}/root \
+${rootfs}/run \
+${rootfs}/run/dbus \
+${rootfs}/run/memory \
+${rootfs}/run/systemd \
+${rootfs}/run/udev \
+${rootfs}/sbin \
+${rootfs}/sys \
+${rootfs}/tmp \
+${rootfs}/usr \
+${path}/hooks \
+${path}/scripts \
+${path}/systemd \
+${path}/systemd/system \
+${path}/systemd/user
+"
+/bin/mkdir ${ROOTFS_DIRS}
+/bin/chown alice:users ${rootfs}/home/alice
+/bin/chown bob:users ${rootfs}/home/bob
+/bin/chown carol:users ${rootfs}/home/carol
+/bin/chown guest:users ${rootfs}/home/guest
+
+/bin/ln -s /dev/null ${path}/systemd/system/bluetooth.service
+/bin/ln -s /dev/null ${path}/systemd/system/sshd.service
+/bin/ln -s /dev/null ${path}/systemd/system/sshd.socket
+/bin/ln -s /dev/null ${path}/systemd/system/sshd@.service
+/bin/ln -s /dev/null ${path}/systemd/system/systemd-udevd.service
+/bin/ln -s /dev/null ${path}/systemd/system/user-session-launch@seat0-5100.service
+/bin/ln -s /dev/null ${path}/systemd/system/vconf-setup.service
+
+cat <>${path}/systemd/system/display-manager-run.service
+# Run weston with framebuffer backend on selected virtual terminal.
+[Unit]
+Description=Weston display daemon
+
+[Service]
+User=display
+WorkingDirectory=/run/%u
+# FIXME: log files shouldn't be stored in tmpfs directories (can get quite big and have side effects)
+#ExecStart=/bin/sh -c 'backend=drm ; [ -d /dev/dri ] || backend=fbdev ; exec /usr/bin/weston --backend=$backend-backend.so -i0 --log=/run/%u/weston.log'
+ExecStart=/usr/bin/weston --backend=fbdev-backend.so -i0 --log=/tmp/weston.log --tty=${vt}
+#StandardInput=tty
+#TTYPath=/dev/tty7
+EnvironmentFile=/etc/systemd/system/weston
+Restart=on-failure
+RestartSec=10
+
+#adding the capability to configure ttys
+#may be needed if the user 'display' doesn't own the tty
+CapabilityBoundingSet=CAP_SYS_TTY_CONFIG
+
+[Install]
+WantedBy=graphical.target
+EOF
+
+cat <>${path}/systemd/system/display-manager.path
+# Wayland socket path is changed to /tmp directory.
+[Unit]
+Description=Wait for wayland socket
+Requires=display-manager-run.service
+After=display-manager-run.service
+
+[Path]
+PathExists=/tmp/wayland-0
+EOF
+
+cat <>${path}/systemd/system/display-manager.service
+# Wayland socket path is changed to /tmp directory.
+[Unit]
+Description=Display manager setup service
+Requires=display-manager-run.service
+After=display-manager-run.service
+
+[Service]
+Type=oneshot
+ExecStart=/usr/bin/chmod g+w /tmp/wayland-0
+#ExecStart=/usr/bin/chsmack -a User /tmp/wayland-0
+
+[Install]
+WantedBy=graphical.target
+EOF
+
+cat <>${path}/systemd/system/weston
+# path to display manager runtime dir
+XDG_RUNTIME_DIR=/tmp
+XDG_CONFIG_HOME=/etc/systemd/system
+EOF
+
+cat <>${path}/systemd/system/weston.ini
+# Weston config for container.
+[core]
+modules=desktop-shell.so
+
+[shell]
+background-image=/usr/share/backgrounds/tizen/golfe-morbihan.jpg
+background-color=0xff002244
+background-type=scale-crop
+panel-color=0x95333333
+locking=true
+panel=false
+animation=zoom
+#binding-modifier=ctrl
+num-workspaces=4
+#cursor-theme=whiteglass
+#cursor-size=24
+startup-animation=fade
+
+#lockscreen-icon=/usr/share/icons/gnome/256x256/actions/lock.png
+#lockscreen=/usr/share/backgrounds/gnome/Garden.jpg
+#homescreen=/usr/share/backgrounds/gnome/Blinds.jpg
+
+## weston
+
+[launcher]
+icon=/usr/share/icons/tizen/32x32/terminal.png
+path=/usr/bin/weston-terminal
+
+[screensaver]
+# Uncomment path to disable screensaver
+duration=600
+
+[input-method]
+path=/usr/libexec/weston-keyboard
+#path=/bin/weekeyboard
+
+#[keyboard]
+#keymap_layout=fr
+
+#[output]
+#name=LVDS1
+#mode=1680x1050
+#transform=90
+#icc_profile=/usr/share/color/icc/colord/Bluish.icc
+
+#[output]
+#name=VGA1
+#mode=173.00 1920 2048 2248 2576 1080 1083 1088 1120 -hsync +vsync
+#transform=flipped
+
+#[output]
+#name=X1
+#mode=1024x768
+#transform=flipped-270
+
+#[touchpad]
+#constant_accel_factor = 50
+#min_accel_factor = 0.16
+#max_accel_factor = 1.0
+
+[output]
+name=DP1
+default_output=1
+EOF
+
+cat <>${path}/systemd/user/weston-user.service
+# Wayland socket path is changed to /tmp directory.
+[Unit]
+Description=Shared weston session
+
+[Service]
+ExecStartPre=/usr/bin/ln -sf /tmp/wayland-0 /run/user/%U/
+ExecStart=/bin/sh -l -c "/usr/bin/tz-launcher -c /usr/share/applications/tizen/launcher.conf %h/.applications/desktop"
+EnvironmentFile=/etc/sysconfig/weston-user
+
+[Install]
+WantedBy=default.target
+EOF
+
+# Prepare host configuration
+cat <>/etc/udev/rules.d/99-tty.rules
+SUBSYSTEM=="tty", KERNEL=="tty${vt}", OWNER="display", SECLABEL{smack}="^"
+EOF
+
+cat </etc/systemd/system/display-manager-run.service
+# Run weston with framebuffer backend on tty7.
+[Unit]
+Description=Weston display daemon
+
+[Service]
+User=display
+WorkingDirectory=/run/%u
+# FIXME: log files shouldn't be stored in tmpfs directories (can get quite big and have side effects)
+#ExecStart=/bin/sh -c 'backend=drm ; [ -d /dev/dri ] || backend=fbdev ; exec /usr/bin/weston --backend=$backend-backend.so -i0 --log=/run/%u/weston.log'
+ExecStart=/usr/bin/weston --backend=fbdev-backend.so -i0 --log=/run/%u/weston.log
+StandardInput=tty
+TTYPath=/dev/tty7
+EnvironmentFile=/etc/sysconfig/weston
+Restart=on-failure
+RestartSec=10
+
+#adding the capability to configure ttys
+#may be needed if the user 'display' doesn't own the tty
+#CapabilityBoundingSet=CAP_SYS_TTY_CONFIG
+
+[Install]
+WantedBy=graphical.target
+EOF
+
+# Prepare container configuration file
+cat <>${path}/config
+lxc.utsname = ${name}
+lxc.rootfs = ${rootfs}
+
+#lxc.cap.drop = audit_control
+#lxc.cap.drop = audit_write
+#lxc.cap.drop = mac_admin
+#lxc.cap.drop = mac_override
+#lxc.cap.drop = mknod
+#lxc.cap.drop = setfcap
+#lxc.cap.drop = setpcap
+#lxc.cap.drop = sys_admin
+#lxc.cap.drop = sys_boot
+#lxc.cap.drop = sys_chroot #required by SSH
+#lxc.cap.drop = sys_module
+#lxc.cap.drop = sys_nice
+#lxc.cap.drop = sys_pacct
+#lxc.cap.drop = sys_rawio
+#lxc.cap.drop = sys_resource
+#lxc.cap.drop = sys_time
+#lxc.cap.drop = sys_tty_config #required by getty
+
+lxc.cgroup.devices.deny = a
+lxc.cgroup.devices.allow = c 1:* rwm #/dev/null, /dev/zero, ...
+lxc.cgroup.devices.allow = c 5:* rwm #/dev/console, /dev/ptmx, ...
+lxc.cgroup.devices.allow = c 136:* rwm #/dev/pts/0 ...
+lxc.cgroup.devices.allow = c 10:223 rwm #/dev/uinput
+lxc.cgroup.devices.allow = c 13:64 rwm #/dev/input/event0
+lxc.cgroup.devices.allow = c 13:65 rwm #/dev/input/event1
+lxc.cgroup.devices.allow = c 13:66 rwm #/dev/input/event2
+lxc.cgroup.devices.allow = c 13:67 rwm #/dev/input/event3
+lxc.cgroup.devices.allow = c 13:68 rwm #/dev/input/event4
+lxc.cgroup.devices.allow = c 13:69 rwm #/dev/input/event5
+lxc.cgroup.devices.allow = c 13:63 rwm #/dev/input/mice
+lxc.cgroup.devices.allow = c 13:32 rwm #/dev/input/mouse0
+lxc.cgroup.devices.allow = c 226:0 rwm #/dev/dri/card0
+lxc.cgroup.devices.allow = c 2:* rwm #/dev/pty
+
+lxc.pts = 256
+lxc.tty = 0
+#lxc.console=/dev/tty1
+lxc.kmsg = 0
+
+#lxc.cgroup.cpu.shares = 1024
+#lxc.cgroup.cpuset.cpus = 0,1,2,3
+#lxc.cgroup.memory.limit_in_bytes = 512M
+#lxc.cgroup.memory.memsw.limit_in_bytes = 1G
+#lxc.cgroup.blkio.weight = 500
+
+lxc.mount.auto = proc sys:rw cgroup
+lxc.mount = ${path}/fstab
+
+# create a separate network per container
+# - it forbids traffic sniffing (like macvlan in bridge mode)
+# - it enables traffic controlling from host using iptables
+lxc.network.type = veth
+lxc.network.link = ${br_name}
+lxc.network.flags = up
+lxc.network.name = eth0
+lxc.network.veth.pair = veth-${name}
+lxc.network.ipv4.gateway = ${ipv4_gateway}
+lxc.network.ipv4 = ${ipv4}/24
+
+lxc.hook.pre-start = ${path}/hooks/pre-start.sh
+#lxc.hook.post-stop = ${path}/hooks/post-stop.sh
+EOF
+
+# Prepare container hook files
+cat <>${path}/hooks/pre-start.sh
+if [ -z "\$(/usr/sbin/brctl show | /bin/grep -P "${br_name}\t")" ]
+then
+ /usr/sbin/brctl addbr ${br_name}
+ /usr/sbin/brctl setfd ${br_name} 0
+ /sbin/ifconfig ${br_name} ${ipv4_gateway} netmask 255.255.255.0 up
+fi
+if [ -z "\$(/usr/sbin/iptables -t nat -S | /bin/grep MASQUERADE)" ]
+then
+ /bin/echo 1 > /proc/sys/net/ipv4/ip_forward
+ /usr/sbin/iptables -t nat -A POSTROUTING -s 10.0.0.0/16 ! -d 10.0.0.0/16 -j MASQUERADE
+fi
+EOF
+
+chmod 770 ${path}/hooks/pre-start.sh
+
+# Prepare container fstab file
+cat <>${path}/fstab
+/bin bin none ro,bind 0 0
+/etc etc none ro,bind 0 0
+${path}/systemd/system etc/systemd/system none ro,bind 0 0
+${path}/systemd/user etc/systemd/user none ro,bind 0 0
+/lib lib none ro,bind 0 0
+/media media none ro,bind 0 0
+/mnt mnt none ro,bind 0 0
+/sbin sbin none ro,bind 0 0
+/usr usr none ro,rbind 0 0
+/opt opt none rw,rbind 0 0
+devtmpfs dev devtmpfs rw,relatime,mode=755 0 0
+devpts dev/pts devpts rw,relatime,gid=5,mode=620,ptmxmode=000 0 0
+/run/dbus run/dbus none rw,bind 0 0
+/run/memory run/memory none rw,bind 0 0
+/run/systemd run/systemd none rw,bind 0 0
+/run/udev run/udev none rw,bind 0 0
+/sys/fs/smackfs sys/fs/smackfs none rw,bind 0 0
+#tmpfs run tmpfs rw,nosuid,nodev,mode=755 0 0
+EOF
--
2.7.4
From 24a8cab8c347623492ea89d32e8d250e9e1e1c03 Mon Sep 17 00:00:00 2001
From: Mateusz Malicki
Date: Wed, 26 Nov 2014 15:24:00 +0100
Subject: [PATCH 14/16] Added testing union in config file
[Bug/Feature] Testing union in config file
[Cause] Added union to config
[Solution] Added union field in testing structure
[Verification] Build, install, run scs tests
Change-Id: I538e6ea370ea1a57f647bbde0f040b1585a4fd0a
---
tests/unit_tests/config/ut-configuration.cpp | 47 ++++++++++++++++++++++++++--
1 file changed, 45 insertions(+), 2 deletions(-)
diff --git a/tests/unit_tests/config/ut-configuration.cpp b/tests/unit_tests/config/ut-configuration.cpp
index 1d72bd8..7f9703b 100644
--- a/tests/unit_tests/config/ut-configuration.cpp
+++ b/tests/unit_tests/config/ut-configuration.cpp
@@ -26,6 +26,7 @@
#include "config.hpp"
#include "ut.hpp"
#include "config/fields.hpp"
+#include "config/fields-union.hpp"
#include "config/manager.hpp"
#include
#include
@@ -62,6 +63,14 @@ struct TestConfig {
)
};
+ struct SubConfigOption {
+ CONFIG_DECLARE_UNION
+ (
+ SubConfig,
+ int
+ )
+ };
+
int intVal;
std::int64_t int64Val;
std::string stringVal;
@@ -76,6 +85,10 @@ struct TestConfig {
SubConfig subObj;
std::vector subVector;
+ SubConfigOption union1;
+ SubConfigOption union2;
+ std::vector unions;
+
CONFIG_REGISTER
(
intVal,
@@ -90,7 +103,11 @@ struct TestConfig {
doubleVector,
subObj,
- subVector
+ subVector,
+
+ union1,
+ union2,
+ unions
)
};
@@ -111,7 +128,14 @@ const std::string jsonTestString =
"\"doubleVector\": [ 0.000000, 1.000000, 2.000000 ], "
"\"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 } } ] }";
+ "{ \"intVal\": 456, \"intVector\": [ 5, 6 ], \"subSubObj\": { \"intVal\": 567 } } ], "
+ "\"union1\": { \"type\": \"int\", \"value\": 2 }, "
+ "\"union2\": { \"type\": \"SubConfig\", \"value\": { \"intVal\": 54321, \"intVector\": [ 1 ], "
+ "\"subSubObj\": { \"intVal\": 234 } } }, "
+ "\"unions\": [ "
+ "{ \"type\": \"int\", \"value\": 2 }, "
+ "{ \"type\": \"SubConfig\", \"value\": { \"intVal\": 54321, \"intVector\": [ 1 ], "
+ "\"subSubObj\": { \"intVal\": 234 } } } ] }";
// Floating point tolerance as a number of rounding errors
const int TOLERANCE = 1;
@@ -344,4 +368,23 @@ BOOST_AUTO_TEST_CASE(FromToFDTest)
fs::remove(fifoPath);
}
+BOOST_AUTO_TEST_CASE(ConfigUnion)
+{
+ TestConfig testConfig;
+ BOOST_REQUIRE_NO_THROW(loadFromString(jsonTestString, testConfig));
+
+ BOOST_CHECK(testConfig.union1.is());
+ BOOST_CHECK(!testConfig.union1.is());
+ BOOST_CHECK_EQUAL(testConfig.union1.as(), 2);
+ BOOST_CHECK(!testConfig.union2.is());
+ BOOST_CHECK(testConfig.union2.is());
+ TestConfig::SubConfig& subConfig = testConfig.union2.as();
+ BOOST_CHECK_EQUAL(subConfig.intVal, 54321);
+ BOOST_CHECK(testConfig.unions[0].is());
+ BOOST_CHECK(testConfig.unions[1].is());
+
+ std::string out = saveToString(testConfig);
+ BOOST_CHECK_EQUAL(out, jsonTestString);
+}
+
BOOST_AUTO_TEST_SUITE_END()
--
2.7.4
From 14ad168b8ffff24f1775e497e4762d1682c544f9 Mon Sep 17 00:00:00 2001
From: Piotr Bartosiewicz
Date: Thu, 27 Nov 2014 16:39:33 +0100
Subject: [PATCH 15/16] Support for destroying container
[Bug/Feature] N/A
[Cause] N/A
[Solution] N/A
[Verification] Build, install, run tests
Change-Id: I4303284b06fdebf452a040c9dfa2c1cddc0b8abf
---
cli/command-line-interface.cpp | 11 +++
cli/command-line-interface.hpp | 7 ++
cli/main.cpp | 8 ++
client/security-containers-client-impl.cpp | 9 ++-
client/security-containers-client.cpp | 2 +-
client/security-containers-client.h | 2 +-
server/common-dbus-definitions.hpp | 2 +-
server/container-admin.cpp | 14 ++++
server/container-admin.hpp | 6 ++
server/container.cpp | 6 ++
server/container.hpp | 5 ++
server/containers-manager.cpp | 94 +++++++++++++++-------
server/containers-manager.hpp | 17 +++-
server/host-connection.cpp | 24 ++++--
server/host-connection.hpp | 15 +++-
server/host-dbus-definitions.hpp | 9 ++-
tests/unit_tests/client/ut-client.cpp | 2 +-
tests/unit_tests/server/configs/CMakeLists.txt | 9 ++-
.../empty-dbus-daemon.conf.in | 22 +++++
.../ut-containers-manager/templates/template.conf | 11 ---
.../templates/template.conf.in | 16 ++++
tests/unit_tests/server/ut-containers-manager.cpp | 83 ++++++++++++-------
22 files changed, 279 insertions(+), 95 deletions(-)
create mode 100644 tests/unit_tests/server/configs/ut-containers-manager/empty-dbus-daemon.conf.in
delete 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.conf.in
diff --git a/cli/command-line-interface.cpp b/cli/command-line-interface.cpp
index 0549afd..b46871d 100644
--- a/cli/command-line-interface.cpp
+++ b/cli/command-line-interface.cpp
@@ -154,6 +154,17 @@ void create_domain(int pos, int argc, const char** argv)
one_shot(bind(vsm_create_domain, _1, argv[pos + 1], nullptr));
}
+void destroy_domain(int pos, int argc, const char** argv)
+{
+ using namespace std::placeholders;
+
+ if (argc <= pos + 1) {
+ throw runtime_error("Not enough parameters");
+ }
+
+ one_shot(bind(vsm_destroy_domain, _1, argv[pos + 1], 1));
+}
+
void lock_domain(int pos, int argc, const char** argv)
{
using namespace std::placeholders;
diff --git a/cli/command-line-interface.hpp b/cli/command-line-interface.hpp
index 41f5048..360f46c 100644
--- a/cli/command-line-interface.hpp
+++ b/cli/command-line-interface.hpp
@@ -111,6 +111,13 @@ void set_active_container(int pos, int argc, const char** argv);
void create_domain(int pos, int argc, const char** argv);
/**
+ * Parses command line arguments and call vsm_destroy_domain
+ *
+ * @see vsm_destroy_domain
+ */
+void destroy_domain(int pos, int argc, const char** argv);
+
+/**
* Parses command line arguments and call vsm_lock_domain
*
* @see vsm_lock_domain
diff --git a/cli/main.cpp b/cli/main.cpp
index 774881b..0ceb1e5 100644
--- a/cli/main.cpp
+++ b/cli/main.cpp
@@ -50,6 +50,14 @@ std::map commands = {
}
},
{
+ "destroy_domain", {
+ destroy_domain,
+ "destroy_domain container_id",
+ "Destroy container",
+ {{"container_id", "id container name"}}
+ }
+ },
+ {
"lock_domain", {
lock_domain,
"lock_domain container_id",
diff --git a/client/security-containers-client-impl.cpp b/client/security-containers-client-impl.cpp
index 0f08a02..1a6e999 100644
--- a/client/security-containers-client-impl.cpp
+++ b/client/security-containers-client-impl.cpp
@@ -450,13 +450,14 @@ VsmStatus Client::vsm_create_domain(const char* id, const char* tname) noexcept
}
GVariant* args_in = g_variant_new("(s)", id);
- return callMethod(HOST_INTERFACE, api::host::METHOD_ADD_CONTAINER, args_in);
+ return callMethod(HOST_INTERFACE, api::host::METHOD_CREATE_CONTAINER, args_in);
}
-VsmStatus Client::vsm_destroy_domain(const char*) noexcept
+VsmStatus Client::vsm_destroy_domain(const char* id) noexcept
{
- mStatus = Status(VSMCLIENT_OTHER_ERROR, "Not implemented");
- return vsm_get_status();
+ assert(id);
+ GVariant* args_in = g_variant_new("(s)", id);
+ return callMethod(HOST_INTERFACE, api::host::METHOD_DESTROY_CONTAINER, args_in);
}
VsmStatus Client::vsm_shutdown_domain(const char*) noexcept
diff --git a/client/security-containers-client.cpp b/client/security-containers-client.cpp
index b96718f..ef571c8 100644
--- a/client/security-containers-client.cpp
+++ b/client/security-containers-client.cpp
@@ -158,7 +158,7 @@ API VsmStatus vsm_create_domain(VsmClient client, const char* id, const char* tn
return getClient(client).vsm_create_domain(id, tname);
}
-API VsmStatus vsm_destroy_domain(VsmClient client, const char* id)
+API VsmStatus vsm_destroy_domain(VsmClient client, const char* id, int /*force*/)
{
return getClient(client).vsm_destroy_domain(id);
}
diff --git a/client/security-containers-client.h b/client/security-containers-client.h
index b796c16..e7e738c 100644
--- a/client/security-containers-client.h
+++ b/client/security-containers-client.h
@@ -380,7 +380,7 @@ VsmStatus vsm_create_domain(VsmClient client, const char* id, const char* tname)
* @param[in] force if 0 data will be kept, otherwise data will be lost
* @return status of this function call
*/
-VsmStatus vsm_destroy_domain(VsmStatus clent, const char* id, int force);
+VsmStatus vsm_destroy_domain(VsmClient clent, const char* id, int force);
/**
* Shutdown domain
diff --git a/server/common-dbus-definitions.hpp b/server/common-dbus-definitions.hpp
index 14bb037..77d0949 100644
--- a/server/common-dbus-definitions.hpp
+++ b/server/common-dbus-definitions.hpp
@@ -32,7 +32,7 @@ namespace security_containers {
namespace api {
const std::string ERROR_FORBIDDEN = "org.tizen.containers.Error.Forbidden";
const std::string ERROR_FORWARDED = "org.tizen.containers.Error.Forwarded";
-const std::string ERROR_UNKNOWN_ID = "org.tizen.containers.Error.UnknownId";
+const std::string ERROR_INVALID_ID = "org.tizen.containers.Error.InvalidId";
const std::string ERROR_INTERNAL = "org.tizen.containers.Error.Internal";
const std::string METHOD_PROXY_CALL = "ProxyCall";
diff --git a/server/container-admin.cpp b/server/container-admin.cpp
index ef8ae0f..65179c3 100644
--- a/server/container-admin.cpp
+++ b/server/container-admin.cpp
@@ -111,6 +111,15 @@ ContainerAdmin::~ContainerAdmin()
{
LOGD(mId << ": Destroying ContainerAdmin object...");
+ if (mDestroyOnExit) {
+ if (!mDom.stop()) {
+ LOGE(mId << ": Failed to stop the container");
+ }
+ if (!mDom.destroy()) {
+ LOGE(mId << ": Failed to destroy the container");
+ }
+ }
+
if (!mDetachOnExit) {
// Try to forcefully stop
if (!mDom.stop()) {
@@ -271,6 +280,11 @@ void ContainerAdmin::setDetachOnExit()
mDetachOnExit = true;
}
+void ContainerAdmin::setDestroyOnExit()
+{
+ mDestroyOnExit = true;
+}
+
std::int64_t ContainerAdmin::getSchedulerQuota()
{
// assert(mDom);
diff --git a/server/container-admin.hpp b/server/container-admin.hpp
index 79b0193..f3c9a4f 100644
--- a/server/container-admin.hpp
+++ b/server/container-admin.hpp
@@ -116,6 +116,11 @@ public:
void setDetachOnExit();
/**
+ * Set if container should be destroyed on exit.
+ */
+ void setDestroyOnExit();
+
+ /**
* @return Scheduler CFS quota,
* TODO: this function is only for UNIT TESTS
*/
@@ -126,6 +131,7 @@ private:
lxc::LxcDomain mDom;
const std::string mId;
bool mDetachOnExit;
+ bool mDestroyOnExit;
void setSchedulerParams(std::uint64_t cpuShares, std::uint64_t vcpuPeriod, std::int64_t vcpuQuota);
};
diff --git a/server/container.cpp b/server/container.cpp
index 80decd5..c371d8a 100644
--- a/server/container.cpp
+++ b/server/container.cpp
@@ -240,6 +240,12 @@ void Container::setDetachOnExit()
}
}
+void Container::setDestroyOnExit()
+{
+ Lock lock(mReconnectMutex);
+ mAdmin->setDestroyOnExit();
+}
+
bool Container::isRunning()
{
Lock lock(mReconnectMutex);
diff --git a/server/container.hpp b/server/container.hpp
index 76e098a..bc1303c 100644
--- a/server/container.hpp
+++ b/server/container.hpp
@@ -135,6 +135,11 @@ public:
void setDetachOnExit();
/**
+ * Set if container should be destroyed on exit.
+ */
+ void setDestroyOnExit();
+
+ /**
* @return Is the container running?
*/
bool isRunning();
diff --git a/server/containers-manager.cpp b/server/containers-manager.cpp
index def04c2..5a6a32b 100644
--- a/server/containers-manager.cpp
+++ b/server/containers-manager.cpp
@@ -101,11 +101,14 @@ ContainersManager::ContainersManager(const std::string& managerConfigPath): mDet
mHostConnection.setSetActiveContainerCallback(bind(&ContainersManager::handleSetActiveContainerCall,
this, _1, _2));
- mHostConnection.setAddContainerCallback(bind(&ContainersManager::handleAddContainerCall,
- this, _1, _2));
+ mHostConnection.setCreateContainerCallback(bind(&ContainersManager::handleCreateContainerCall,
+ this, _1, _2));
+
+ mHostConnection.setDestroyContainerCallback(bind(&ContainersManager::handleDestroyContainerCall,
+ this, _1, _2));
for (auto& containerConfig : mConfig.containerConfigs) {
- addContainer(containerConfig);
+ createContainer(containerConfig);
}
// check if default container exists, throw ContainerOperationException if not found
@@ -143,7 +146,7 @@ ContainersManager::~ContainersManager()
LOGD("ContainersManager object destroyed");
}
-void ContainersManager::addContainer(const std::string& containerConfig)
+void ContainersManager::createContainer(const std::string& containerConfig)
{
std::string baseConfigPath = utils::dirName(mConfigPath);
std::string containerConfigPath = utils::getAbsolutePath(containerConfig, baseConfigPath);
@@ -177,6 +180,20 @@ void ContainersManager::addContainer(const std::string& containerConfig)
mContainers.insert(ContainerMap::value_type(id, std::move(c)));
}
+void ContainersManager::destroyContainer(const std::string& containerId)
+{
+ // TODO mutex for mContainers access
+ auto it = mContainers.find(containerId);
+ if (it == mContainers.end()) {
+ LOGE("Failed to destroy container " << containerId << ": no such container");
+ throw ContainerOperationException("No such container");
+ }
+
+ // TODO give back the focus
+ it->second->setDestroyOnExit();
+ mContainers.erase(it);
+}
+
void ContainersManager::focus(const std::string& containerId)
{
/* try to access the object first to throw immediately if it doesn't exist */
@@ -440,7 +457,7 @@ void ContainersManager::handleProxyCall(const std::string& caller,
ContainerMap::const_iterator targetIter = mContainers.find(target);
if (targetIter == mContainers.end()) {
LOGE("Target container '" << target << "' not found");
- result->setError(api::ERROR_UNKNOWN_ID, "Unknown proxy call target");
+ result->setError(api::ERROR_INVALID_ID, "Unknown proxy call target");
return;
}
@@ -501,7 +518,7 @@ void ContainersManager::handleGetContainerInfoCall(const std::string& id,
LOGI("GetContainerInfo call");
if (mContainers.count(id) == 0) {
LOGE("No container with id=" << id);
- result->setError(api::ERROR_UNKNOWN_ID, "No such container id");
+ result->setError(api::ERROR_INVALID_ID, "No such container id");
return;
}
const auto& container = mContainers[id];
@@ -536,7 +553,7 @@ void ContainersManager::handleSetActiveContainerCall(const std::string& id,
auto container = mContainers.find(id);
if (container == mContainers.end()){
LOGE("No container with id=" << id );
- result->setError(api::ERROR_UNKNOWN_ID, "No such container id");
+ result->setError(api::ERROR_INVALID_ID, "No such container id");
return;
}
@@ -597,33 +614,30 @@ void ContainersManager::generateNewConfig(const std::string& id,
fs::perms::others_read);
}
-void ContainersManager::handleAddContainerCall(const std::string& id,
- dbus::MethodResultBuilder::Pointer result)
+void ContainersManager::handleCreateContainerCall(const std::string& id,
+ dbus::MethodResultBuilder::Pointer result)
{
if (id.empty()) {
LOGE("Failed to add container - invalid name.");
- result->setError(api::host::ERROR_CONTAINER_CREATE_FAILED,
- "Failed to add container - invalid name.");
+ result->setError(api::ERROR_INVALID_ID, "Invalid name");
return;
}
- LOGI("Adding container " << id);
+ LOGI("Creating 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!");
+ result->setError(api::ERROR_INVALID_ID, "Already exists");
return;
}
+ const std::string containerPathStr = utils::createFilePath(mConfig.containersPath, "/", id, "/");
+
// copy container image if config contains path to image
LOGT("Image path: " << mConfig.containerImagePath);
if (!mConfig.containerImagePath.empty()) {
@@ -633,8 +647,7 @@ void ContainersManager::handleAddContainerCall(const std::string& id,
if (!utils::launchAsRoot(copyImageContentsWrapper)) {
LOGE("Failed to copy container image.");
- result->setError(api::host::ERROR_CONTAINER_CREATE_FAILED,
- "Failed to copy container image.");
+ result->setError(api::ERROR_INTERNAL, "Failed to copy container image.");
return;
}
}
@@ -647,7 +660,7 @@ void ContainersManager::handleAddContainerCall(const std::string& id,
std::string configPath = utils::createFilePath(templateDir, "/", CONTAINER_TEMPLATE_CONFIG_PATH);
std::string newConfigPath = utils::createFilePath(configDir, "/containers/", id + ".conf");
- auto removeAllWrapper = [](const std::string& path) {
+ auto removeAllWrapper = [](const std::string& path) -> bool {
try {
LOGD("Removing copied data");
fs::remove_all(fs::path(path));
@@ -662,19 +675,19 @@ void ContainersManager::handleAddContainerCall(const std::string& id,
generateNewConfig(id, configPath, newConfigPath);
} catch (SecurityContainersException& e) {
- LOGE(e.what());
+ LOGE("Generate config failed: " << e.what());
utils::launchAsRoot(std::bind(removeAllWrapper, containerPathStr));
- result->setError(api::host::ERROR_CONTAINER_CREATE_FAILED, e.what());
+ result->setError(api::ERROR_INTERNAL, "Failed to generate config");
return;
}
- LOGT("Adding new container");
+ LOGT("Creating new container");
try {
- addContainer(newConfigPath);
+ createContainer(newConfigPath);
} catch (SecurityContainersException& e) {
- LOGE(e.what());
+ LOGE("Creating new container failed: " << e.what());
utils::launchAsRoot(std::bind(removeAllWrapper, containerPathStr));
- result->setError(api::host::ERROR_CONTAINER_CREATE_FAILED, e.what());
+ result->setError(api::ERROR_INTERNAL, "Failed to create container");
return;
}
@@ -685,11 +698,36 @@ void ContainersManager::handleAddContainerCall(const std::string& id,
} else {
LOGE("Failed to start container.");
// TODO removeContainer
- result->setError(api::host::ERROR_CONTAINER_CREATE_FAILED,
- "Failed to start container.");
+ result->setError(api::ERROR_INTERNAL, "Failed to start container");
}
};
mContainers[id]->startAsync(resultCallback);
}
+void ContainersManager::handleDestroyContainerCall(const std::string& id,
+ dbus::MethodResultBuilder::Pointer result)
+{
+ if (mContainers.find(id) == mContainers.end()) {
+ LOGE("Failed to destroy container - no such container id: " << id);
+ result->setError(api::ERROR_INVALID_ID, "No such container id");
+ return;
+ }
+
+ LOGI("Destroying container " << id);
+
+ auto destroyer = [id, result, this] {
+ try {
+ destroyContainer(id);
+ } catch (const SecurityContainersException& e) {
+ LOGE("Error during container destruction: " << e.what());
+ result->setError(api::ERROR_INTERNAL, "Failed to destroy container");
+ return;
+ }
+ result->setVoid();
+ };
+
+ std::thread thread(destroyer);
+ thread.detach(); //TODO fix it
+}
+
} // namespace security_containers
diff --git a/server/containers-manager.hpp b/server/containers-manager.hpp
index 16a8cf5..70637bc 100644
--- a/server/containers-manager.hpp
+++ b/server/containers-manager.hpp
@@ -47,11 +47,18 @@ public:
~ContainersManager();
/**
- * Add new container.
+ * Create new container.
*
* @param containerConfig config of new container
*/
- void addContainer(const std::string& containerConfig);
+ void createContainer(const std::string& containerConfig);
+
+ /**
+ * Destroy container.
+ *
+ * @param containerId id of the container
+ */
+ void destroyContainer(const std::string& containerId);
/**
* Focus this container, put it to the foreground.
@@ -126,8 +133,10 @@ private:
void handleGetContainerInfoCall(const std::string& id, dbus::MethodResultBuilder::Pointer result);
void handleSetActiveContainerCall(const std::string& id,
dbus::MethodResultBuilder::Pointer result);
- void handleAddContainerCall(const std::string& id,
- dbus::MethodResultBuilder::Pointer result);
+ void handleCreateContainerCall(const std::string& id,
+ dbus::MethodResultBuilder::Pointer result);
+ void handleDestroyContainerCall(const std::string& id,
+ dbus::MethodResultBuilder::Pointer result);
};
diff --git a/server/host-connection.cpp b/server/host-connection.cpp
index 1b38a9c..b7d72b7 100644
--- a/server/host-connection.cpp
+++ b/server/host-connection.cpp
@@ -135,9 +135,14 @@ void HostConnection::setSetActiveContainerCallback(const SetActiveContainerCallb
mSetActiveContainerCallback = callback;
}
-void HostConnection::setAddContainerCallback(const AddContainerCallback& callback)
+void HostConnection::setCreateContainerCallback(const CreateContainerCallback& callback)
{
- mAddContainerCallback = callback;
+ mCreateContainerCallback = callback;
+}
+
+void HostConnection::setDestroyContainerCallback(const DestroyContainerCallback& callback)
+{
+ mDestroyContainerCallback = callback;
}
void HostConnection::onMessageCall(const std::string& objectPath,
@@ -220,12 +225,21 @@ void HostConnection::onMessageCall(const std::string& objectPath,
return;
}
- if (methodName == api::host::METHOD_ADD_CONTAINER) {
+ if (methodName == api::host::METHOD_CREATE_CONTAINER) {
+ const gchar* id = NULL;
+ g_variant_get(parameters, "(&s)", &id);
+
+ if (mCreateContainerCallback){
+ mCreateContainerCallback(id, result);
+ }
+ }
+
+ if (methodName == api::host::METHOD_DESTROY_CONTAINER) {
const gchar* id = NULL;
g_variant_get(parameters, "(&s)", &id);
- if (mAddContainerCallback){
- mAddContainerCallback(id, result);
+ if (mDestroyContainerCallback){
+ mDestroyContainerCallback(id, result);
}
}
}
diff --git a/server/host-connection.hpp b/server/host-connection.hpp
index 1dacd11..8392578 100644
--- a/server/host-connection.hpp
+++ b/server/host-connection.hpp
@@ -65,7 +65,10 @@ public:
)> SetActiveContainerCallback;
typedef std::function AddContainerCallback;
+ )> CreateContainerCallback;
+ typedef std::function DestroyContainerCallback;
/**
* Register proxy call callback
@@ -105,7 +108,12 @@ public:
/**
* Register a callback called to create new container
*/
- void setAddContainerCallback(const AddContainerCallback& callback);
+ void setCreateContainerCallback(const CreateContainerCallback& callback);
+
+ /**
+ * Register a callback called to destroy container
+ */
+ void setDestroyContainerCallback(const DestroyContainerCallback& callback);
/**
* Make a proxy call
@@ -129,7 +137,8 @@ private:
GetActiveContainerIdCallback mGetActiveContainerIdCallback;
GetContainerInfoCallback mGetContainerInfoCallback;
SetActiveContainerCallback mSetActiveContainerCallback;
- AddContainerCallback mAddContainerCallback;
+ CreateContainerCallback mCreateContainerCallback;
+ DestroyContainerCallback mDestroyContainerCallback;
void onNameAcquired();
void onNameLost();
diff --git a/server/host-dbus-definitions.hpp b/server/host-dbus-definitions.hpp
index a722aee..b7b49c4 100644
--- a/server/host-dbus-definitions.hpp
+++ b/server/host-dbus-definitions.hpp
@@ -37,14 +37,14 @@ 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_GET_CONTAINER_INFO = "GetContainerInfo";
const std::string METHOD_SET_ACTIVE_CONTAINER = "SetActiveContainer";
-const std::string METHOD_ADD_CONTAINER = "AddContainer";
+const std::string METHOD_CREATE_CONTAINER = "CreateContainer";
+const std::string METHOD_DESTROY_CONTAINER = "DestroyContainer";
const std::string SIGNAL_CONTAINER_DBUS_STATE = "ContainerDbusState";
@@ -77,7 +77,10 @@ const std::string DEFINITION =
" "
" "
" "
- " "
+ " "
+ " "
+ " "
+ " "
" "
" "
" "
diff --git a/tests/unit_tests/client/ut-client.cpp b/tests/unit_tests/client/ut-client.cpp
index d6b3fbb..934a062 100644
--- a/tests/unit_tests/client/ut-client.cpp
+++ b/tests/unit_tests/client/ut-client.cpp
@@ -213,7 +213,7 @@ BOOST_AUTO_TEST_CASE(SetActiveContainerTest)
vsm_client_free(client);
}
-BOOST_AUTO_TEST_CASE(AddContainerTest)
+BOOST_AUTO_TEST_CASE(CreateContainerTest)
{
const std::string newActiveContainerId = "";
diff --git a/tests/unit_tests/server/configs/CMakeLists.txt b/tests/unit_tests/server/configs/CMakeLists.txt
index 17e10a2..fc73fd4 100644
--- a/tests/unit_tests/server/configs/CMakeLists.txt
+++ b/tests/unit_tests/server/configs/CMakeLists.txt
@@ -24,7 +24,6 @@ FILE(GLOB server_container_CONF ut-server/containers/*.conf)
FILE(GLOB manager_manager_CONF ut-containers-manager/*.conf)
FILE(GLOB manager_container_CONF ut-containers-manager/containers/*.conf)
-FILE(GLOB manager_admin_TEMPLATE ut-containers-manager/templates/*.conf)
FILE(GLOB container_CONF ut-container/*.conf)
FILE(GLOB container_container_CONF ut-container/containers/*.conf)
@@ -55,6 +54,8 @@ CONFIGURE_FILE(ut-containers-manager/buggy-foreground-daemon.conf.in
${CMAKE_BINARY_DIR}/ut-containers-manager/buggy-foreground-daemon.conf @ONLY)
CONFIGURE_FILE(ut-containers-manager/test-dbus-daemon.conf.in
${CMAKE_BINARY_DIR}/ut-containers-manager/test-dbus-daemon.conf @ONLY)
+CONFIGURE_FILE(ut-containers-manager/empty-dbus-daemon.conf.in
+ ${CMAKE_BINARY_DIR}/ut-containers-manager/empty-dbus-daemon.conf @ONLY)
FILE(GLOB manager_manager_CONF_GEN ${CMAKE_BINARY_DIR}/ut-containers-manager/*.conf)
CONFIGURE_FILE(ut-containers-manager/containers/console1-dbus.conf.in
@@ -65,6 +66,10 @@ CONFIGURE_FILE(ut-containers-manager/containers/console3-dbus.conf.in
${CMAKE_BINARY_DIR}/ut-containers-manager/containers/console3-dbus.conf @ONLY)
FILE(GLOB manager_container_CONF_GEN ${CMAKE_BINARY_DIR}/ut-containers-manager/containers/*.conf)
+CONFIGURE_FILE(ut-containers-manager/templates/template.conf.in
+ ${CMAKE_BINARY_DIR}/ut-containers-manager/templates/template.conf @ONLY)
+FILE(GLOB manager_container_TEMPLATE_GEN ${CMAKE_BINARY_DIR}/ut-containers-manager/templates/*.conf)
+
## Install #####################################################################
INSTALL(FILES ${server_manager_CONF}
@@ -82,7 +87,7 @@ INSTALL(FILES ${manager_container_CONF}
DESTINATION ${SC_TEST_CONFIG_INSTALL_DIR}/server/ut-containers-manager/containers)
INSTALL(FILES ${manager_container_CONF_GEN}
DESTINATION ${SC_TEST_CONFIG_INSTALL_DIR}/server/ut-containers-manager/containers)
-INSTALL(FILES ${manager_admin_TEMPLATE}
+INSTALL(FILES ${manager_container_TEMPLATE_GEN}
DESTINATION ${SC_TEST_CONFIG_INSTALL_DIR}/server/ut-containers-manager/templates)
INSTALL(FILES ${container_CONF}
diff --git a/tests/unit_tests/server/configs/ut-containers-manager/empty-dbus-daemon.conf.in b/tests/unit_tests/server/configs/ut-containers-manager/empty-dbus-daemon.conf.in
new file mode 100644
index 0000000..82f6c0e
--- /dev/null
+++ b/tests/unit_tests/server/configs/ut-containers-manager/empty-dbus-daemon.conf.in
@@ -0,0 +1,22 @@
+{
+ "containerConfigs" : [],
+ "foregroundId" : "",
+ "defaultId" : "",
+ "containersPath" : "/tmp/ut-containers",
+ "containerImagePath" : "",
+ "containerTemplatePath" : "templates",
+ "containerNewConfigPrefix" : "@SC_TEST_CONFIG_INSTALL_DIR@/server/ut-containers-manager/",
+ "runMountPointPrefix" : "",
+ "lxcTemplatePrefix" : "@SC_TEST_LXC_TEMPLATES_INSTALL_DIR@",
+ "inputConfig" : {"enabled" : false,
+ "device" : "/dev/doesnotexist",
+ "code" : 139,
+ "numberOfEvents" : 2,
+ "timeWindowMs" : 500},
+ "proxyCallRules" : [{"caller" : "*",
+ "target" : "*",
+ "targetBusName" : "org.tizen.containers.tests",
+ "targetObjectPath" : "*",
+ "targetInterface" : "*",
+ "targetMethod" : "*"}]
+}
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
deleted file mode 100644
index 1229c12..0000000
--- a/tests/unit_tests/server/configs/ut-containers-manager/templates/template.conf
+++ /dev/null
@@ -1,11 +0,0 @@
-{
- "privilege" : 20,
- "vt" : -1,
- "switchToDefaultAfterTimeout" : true,
- "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.conf.in b/tests/unit_tests/server/configs/ut-containers-manager/templates/template.conf.in
new file mode 100644
index 0000000..f01cfff
--- /dev/null
+++ b/tests/unit_tests/server/configs/ut-containers-manager/templates/template.conf.in
@@ -0,0 +1,16 @@
+{
+ "name" : "~NAME~",
+ "lxcTemplate" : "minimal-dbus1.sh",
+ "initWithArgs" : ["/bin/sh", "-c", "trap exit SIGTERM; /usr/bin/dbus-daemon --config-file=@SC_TEST_CONFIG_INSTALL_DIR@/server/ut-containers-manager/ut-dbus.conf --fork; read"],
+ "ipv4Gateway" : "",
+ "ipv4" : "",
+ "privilege" : 20,
+ "vt" : -1,
+ "switchToDefaultAfterTimeout" : true,
+ "enableDbusIntegration" : true,
+ "cpuQuotaForeground" : -1,
+ "cpuQuotaBackground" : 1000,
+ "runMountPoint" : "/tmp/ut-run1",
+ "permittedToSend" : [ "/tmp/.*" ],
+ "permittedToRecv" : [ "/tmp/.*" ]
+}
diff --git a/tests/unit_tests/server/ut-containers-manager.cpp b/tests/unit_tests/server/ut-containers-manager.cpp
index 399cd12..46f659f 100644
--- a/tests/unit_tests/server/ut-containers-manager.cpp
+++ b/tests/unit_tests/server/ut-containers-manager.cpp
@@ -62,6 +62,7 @@ namespace {
const std::string TEST_CONFIG_PATH = SC_TEST_CONFIG_INSTALL_DIR "/server/ut-containers-manager/test-daemon.conf";
const std::string TEST_DBUS_CONFIG_PATH = SC_TEST_CONFIG_INSTALL_DIR "/server/ut-containers-manager/test-dbus-daemon.conf";
+const std::string EMPTY_DBUS_CONFIG_PATH = SC_TEST_CONFIG_INSTALL_DIR "/server/ut-containers-manager/empty-dbus-daemon.conf";
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";
@@ -85,7 +86,7 @@ public:
typedef std::function TestApiMethodCallback;
- typedef std::function AddContainerResultCallback;
+ typedef std::function VoidResultCallback;
typedef std::map Dbuses;
@@ -308,8 +309,8 @@ public:
}
- void callAsyncMethodAddContainer(const std::string& id,
- const AddContainerResultCallback& result)
+ void callAsyncMethodCreateContainer(const std::string& id,
+ const VoidResultCallback& result)
{
auto asyncResult = [result](dbus::AsyncMethodCallResult& asyncMethodCallResult) {
BOOST_CHECK(g_variant_is_of_type(asyncMethodCallResult.get(), G_VARIANT_TYPE_UNIT));
@@ -321,7 +322,26 @@ public:
mClient->callMethodAsync(api::host::BUS_NAME,
api::host::OBJECT_PATH,
api::host::INTERFACE,
- api::host::METHOD_ADD_CONTAINER,
+ api::host::METHOD_CREATE_CONTAINER,
+ parameters,
+ "()",
+ asyncResult);
+ }
+
+ void callAsyncMethodDestroyContainer(const std::string& id,
+ const VoidResultCallback& 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_DESTROY_CONTAINER,
parameters,
"()",
asyncResult);
@@ -938,32 +958,33 @@ BOOST_AUTO_TEST_CASE(SetActiveContainerTest)
DbusException);
}
-//TODO fix it
-//BOOST_AUTO_TEST_CASE(AddContainerTest)
-//{
-// const std::string newContainerId = "test1234";
-// const std::vector newContainerConfigs = {
-// TEST_CONTAINER_CONF_PATH + newContainerId + ".conf",
-// };
-// 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
-// cm.focus(newContainerId);
-// BOOST_CHECK(cm.getRunningForegroundContainerId() == newContainerId);
-//}
+BOOST_AUTO_TEST_CASE(CreateDestroyContainerTest)
+{
+ const std::string newContainerId = "test1234";
+
+ ContainersManager cm(EMPTY_DBUS_CONFIG_PATH);
+ cm.startAll();
+
+ Latch callDone;
+ auto resultCallback = [&]() {
+ callDone.set();
+ };
+
+ DbusAccessory dbus(DbusAccessory::HOST_ID);
+
+ // create new container
+ dbus.callAsyncMethodCreateContainer(newContainerId, resultCallback);
+ BOOST_REQUIRE(callDone.wait(EVENT_TIMEOUT));
+
+ // focus new container
+ cm.focus(newContainerId);
+ BOOST_CHECK(cm.getRunningForegroundContainerId() == newContainerId);
+
+ // destroy container
+ dbus.callAsyncMethodDestroyContainer(newContainerId, resultCallback);
+ BOOST_REQUIRE(callDone.wait(EVENT_TIMEOUT));
+
+ BOOST_CHECK(cm.getRunningForegroundContainerId() == "");
+}
BOOST_AUTO_TEST_SUITE_END()
--
2.7.4
From 7f7ca51f217acca99c35d06c6144ca6ace55e9c2 Mon Sep 17 00:00:00 2001
From: Jan Olszak
Date: Thu, 27 Nov 2014 14:02:11 +0100
Subject: [PATCH 16/16] IPC: Signals
[Bug/Feature] Signals in the IPC mechanism
[Cause] N/A
[Solution] N/A
[Verification] Build, install, run tests
Change-Id: Ie84b88ffa2956e744216d9ff7e9c227631f78e50
---
common/ipc/client.cpp | 15 ++
common/ipc/client.hpp | 67 +++++++-
common/ipc/internals/processor.cpp | 185 +++++++++++++++++----
common/ipc/internals/processor.hpp | 318 ++++++++++++++++++++++++++++++-------
common/ipc/service.cpp | 15 ++
common/ipc/service.hpp | 65 +++++++-
common/ipc/types.hpp | 11 +-
tests/unit_tests/ipc/ut-ipc.cpp | 197 ++++++++++++++---------
8 files changed, 707 insertions(+), 166 deletions(-)
diff --git a/common/ipc/client.cpp b/common/ipc/client.cpp
index c1651f3..c806e7b 100644
--- a/common/ipc/client.cpp
+++ b/common/ipc/client.cpp
@@ -63,6 +63,11 @@ void Client::start()
LOGD("Started client");
}
+bool Client::isStarted()
+{
+ return mProcessor.isStarted();
+}
+
void Client::stop()
{
LOGD("Stopping client...");
@@ -70,6 +75,16 @@ void Client::stop()
LOGD("Stopped");
}
+void Client::setNewPeerCallback(const PeerCallback& newPeerCallback)
+{
+ mProcessor.setNewPeerCallback(newPeerCallback);
+}
+
+void Client::setRemovedPeerCallback(const PeerCallback& removedPeerCallback)
+{
+ mProcessor.setRemovedPeerCallback(removedPeerCallback);
+}
+
void Client::removeMethod(const MethodID methodID)
{
LOGD("Removing method id: " << methodID);
diff --git a/common/ipc/client.hpp b/common/ipc/client.hpp
index 7429b24..3178474 100644
--- a/common/ipc/client.hpp
+++ b/common/ipc/client.hpp
@@ -45,8 +45,6 @@ namespace ipc {
*/
class Client {
public:
- typedef Processor::MethodID MethodID;
-
/**
* @param serverPath path to the server's socket
*/
@@ -62,11 +60,30 @@ public:
void start();
/**
+ * @return is the communication thread running
+ */
+ bool isStarted();
+
+ /**
* Stops all worker thread
*/
void stop();
/**
+ * Set the callback called for each new connection to a peer
+ *
+ * @param newPeerCallback the callback
+ */
+ void setNewPeerCallback(const PeerCallback& newPeerCallback);
+
+ /**
+ * Set the callback called when connection to a peer is lost
+ *
+ * @param removedPeerCallback the callback
+ */
+ void setRemovedPeerCallback(const PeerCallback& removedPeerCallback);
+
+ /**
* Saves the callback connected to the method id.
* When a message with the given method id is received
* the data will be parsed and passed to this callback.
@@ -79,6 +96,19 @@ public:
const typename MethodHandler::type& method);
/**
+ * Saves the callback connected to the method id.
+ * When a message with the given method id is received
+ * the data will be parsed and passed to this callback.
+ *
+ * @param methodID API dependent id of the method
+ * @param SignalHandler signal handling implementation
+ * @tparam ReceivedDataType data type to serialize
+ */
+ template
+ void addSignalHandler(const MethodID methodID,
+ const typename SignalHandler::type& signal);
+
+ /**
* Removes the callback
*
* @param methodID API dependent id of the method
@@ -112,8 +142,21 @@ public:
const std::shared_ptr& data,
const typename ResultHandler::type& resultCallback);
+ /**
+ * Send a signal to the peer.
+ * There is no return value from the peer
+ * Sends any data only if a peer registered this a signal
+ *
+ * @param methodID API dependent id of the method
+ * @param data data to sent
+ * @tparam SentDataType data type to send
+ */
+ template
+ void signal(const MethodID methodID,
+ const std::shared_ptr& data);
+
private:
- Processor::PeerID mServiceID;
+ PeerID mServiceID;
Processor mProcessor;
std::string mSocketPath;
};
@@ -127,6 +170,15 @@ void Client::addMethodHandler(const MethodID methodID,
LOGD("Added method with id " << methodID);
}
+template
+void Client::addSignalHandler(const MethodID methodID,
+ const typename SignalHandler::type& handler)
+{
+ LOGD("Adding signal with id " << methodID);
+ mProcessor.addSignalHandler(methodID, handler);
+ LOGD("Added signal with id " << methodID);
+}
+
template
std::shared_ptr Client::callSync(const MethodID methodID,
const std::shared_ptr& data,
@@ -150,6 +202,15 @@ void Client::callAsync(const MethodID methodID,
LOGD("Async called method: " << methodID);
}
+template
+void Client::signal(const MethodID methodID,
+ const std::shared_ptr& data)
+{
+ LOGD("Signaling: " << methodID);
+ mProcessor.signal(methodID, data);
+ LOGD("Signaled: " << methodID);
+}
+
} // namespace ipc
} // namespace security_containers
diff --git a/common/ipc/internals/processor.cpp b/common/ipc/internals/processor.cpp
index 9aadfff..dc7df42 100644
--- a/common/ipc/internals/processor.cpp
+++ b/common/ipc/internals/processor.cpp
@@ -28,7 +28,6 @@
#include "ipc/internals/processor.hpp"
#include "ipc/internals/utils.hpp"
-#include
#include
#include
#include
@@ -48,7 +47,8 @@ namespace ipc {
LOGE("Callback threw an error: " << e.what()); \
}
-const Processor::MethodID Processor::RETURN_METHOD_ID = std::numeric_limits::max();
+const MethodID Processor::RETURN_METHOD_ID = std::numeric_limits::max();
+const MethodID Processor::REGISTER_SIGNAL_METHOD_ID = std::numeric_limits::max() - 1;
Processor::Processor(const PeerCallback& newPeerCallback,
const PeerCallback& removedPeerCallback,
@@ -60,6 +60,11 @@ Processor::Processor(const PeerCallback& newPeerCallback,
mPeerIDCounter(0)
{
LOGT("Creating Processor");
+ using namespace std::placeholders;
+
+ addMethodHandlerInternal(REGISTER_SIGNAL_METHOD_ID,
+ std::bind(&Processor::onNewSignals, this, _1, _2));
+
}
Processor::~Processor()
@@ -73,10 +78,15 @@ Processor::~Processor()
LOGT("Destroyed Processor");
}
+bool Processor::isStarted()
+{
+ return mThread.joinable();
+}
+
void Processor::start()
{
LOGT("Starting Processor");
- if (!mThread.joinable()) {
+ if (!isStarted()) {
mThread = std::thread(&Processor::run, this);
}
LOGT("Started Processor");
@@ -85,13 +95,25 @@ void Processor::start()
void Processor::stop()
{
LOGT("Stopping Processor");
- if (mThread.joinable()) {
+ if (isStarted()) {
mEventQueue.send(Event::FINISH);
mThread.join();
}
LOGT("Stopped Processor");
}
+void Processor::setNewPeerCallback(const PeerCallback& newPeerCallback)
+{
+ Lock lock(mCallbacksMutex);
+ mNewPeerCallback = newPeerCallback;
+}
+
+void Processor::setRemovedPeerCallback(const PeerCallback& removedPeerCallback)
+{
+ Lock lock(mCallbacksMutex);
+ mRemovedPeerCallback = removedPeerCallback;
+}
+
void Processor::removeMethod(const MethodID methodID)
{
LOGT("Removing method " << methodID);
@@ -99,7 +121,7 @@ void Processor::removeMethod(const MethodID methodID)
mMethodsCallbacks.erase(methodID);
}
-Processor::PeerID Processor::addPeer(const std::shared_ptr& socketPtr)
+PeerID Processor::addPeer(const std::shared_ptr& socketPtr)
{
LOGT("Adding socket");
PeerID peerID;
@@ -127,7 +149,7 @@ void Processor::removePeer(const PeerID peerID)
mEventQueue.send(Event::REMOVE_PEER);
- auto isPeerDeleted = [&peerID, this] {
+ auto isPeerDeleted = [&peerID, this]()->bool {
Lock lock(mSocketsMutex);
return mSockets.count(peerID) == 0;
};
@@ -143,6 +165,16 @@ void Processor::removePeerInternal(const PeerID peerID, Status status)
{
Lock lock(mSocketsMutex);
mSockets.erase(peerID);
+
+ // Remove from signal addressees
+ for (auto it = mSignalsPeers.begin(); it != mSignalsPeers.end();) {
+ it->second.remove(peerID);
+ if (it->second.empty()) {
+ it = mSignalsPeers.erase(it);
+ } else {
+ ++it;
+ }
+ }
}
{
@@ -160,9 +192,13 @@ void Processor::removePeerInternal(const PeerID peerID, Status status)
}
}
- if (mRemovedPeerCallback) {
- // Notify about the deletion
- mRemovedPeerCallback(peerID);
+
+ {
+ Lock lock(mCallbacksMutex);
+ if (mRemovedPeerCallback) {
+ // Notify about the deletion
+ mRemovedPeerCallback(peerID);
+ }
}
resetPolling();
@@ -284,14 +320,46 @@ bool Processor::handleInput(const PeerID peerID, const Socket& socket)
if (methodID == RETURN_METHOD_ID) {
return onReturnValue(peerID, socket, messageID);
+
} else {
- return onRemoteCall(peerID, socket, methodID, messageID);
+ Lock lock(mCallsMutex);
+ if (mMethodsCallbacks.count(methodID)) {
+ // Method
+ std::shared_ptr methodCallbacks = mMethodsCallbacks.at(methodID);
+ mCallsMutex.unlock();
+ return onRemoteCall(peerID, socket, methodID, messageID, methodCallbacks);
+
+ } else if (mSignalsCallbacks.count(methodID)) {
+ // Signal
+ std::shared_ptr signalCallbacks = mSignalsCallbacks.at(methodID);
+ mCallsMutex.unlock();
+ return onRemoteSignal(peerID, socket, methodID, messageID, signalCallbacks);
+
+ } else {
+ // Nothing
+ mCallsMutex.unlock();
+ LOGW("No method or signal callback for methodID: " << methodID);
+ removePeerInternal(peerID, Status::NAUGHTY_PEER);
+ return true;
+ }
}
}
return false;
}
+std::shared_ptr Processor::onNewSignals(const PeerID peerID,
+ std::shared_ptr& data)
+{
+ LOGD("New signals for peer: " << peerID);
+ Lock lock(mSocketsMutex);
+ for (MethodID methodID : data->ids) {
+ mSignalsPeers[methodID].push_back(peerID);
+ }
+
+ return std::make_shared();
+}
+
bool Processor::onReturnValue(const PeerID peerID,
const Socket& socket,
const MessageID messageID)
@@ -326,23 +394,44 @@ bool Processor::onReturnValue(const PeerID peerID,
return false;
}
-bool Processor::onRemoteCall(const PeerID peerID,
- const Socket& socket,
- const MethodID methodID,
- const MessageID messageID)
+bool Processor::onRemoteSignal(const PeerID peerID,
+ const Socket& socket,
+ const MethodID methodID,
+ const MessageID messageID,
+ std::shared_ptr signalCallbacks)
{
- LOGI("Remote call; methodID: " << methodID << " messageID: " << messageID);
+ LOGI("Remote signal; methodID: " << methodID << " messageID: " << messageID);
- std::shared_ptr methodCallbacks;
+ std::shared_ptr data;
try {
- Lock lock(mCallsMutex);
- methodCallbacks = mMethodsCallbacks.at(methodID);
- } catch (const std::out_of_range&) {
- LOGW("No method callback for methodID: " << methodID);
+ LOGT("Parsing incoming data");
+ data = signalCallbacks->parse(socket.getFD());
+ } catch (const std::exception& e) {
+ LOGE("Exception during parsing: " << e.what());
+ removePeerInternal(peerID, Status::PARSING_ERROR);
+ return true;
+ }
+
+ LOGT("Signal callback for methodID: " << methodID << "; messageID: " << messageID);
+ try {
+ signalCallbacks->signal(peerID, data);
+ } catch (const std::exception& e) {
+ LOGE("Exception in method handler: " << e.what());
removePeerInternal(peerID, Status::NAUGHTY_PEER);
return true;
}
+ return false;
+}
+
+bool Processor::onRemoteCall(const PeerID peerID,
+ const Socket& socket,
+ const MethodID methodID,
+ const MessageID messageID,
+ std::shared_ptr methodCallbacks)
+{
+ LOGI("Remote call; methodID: " << methodID << " messageID: " << messageID);
+
std::shared_ptr data;
try {
LOGT("Parsing incoming data");
@@ -356,7 +445,7 @@ bool Processor::onRemoteCall(const PeerID peerID,
LOGT("Process callback for methodID: " << methodID << "; messageID: " << messageID);
std::shared_ptr returnData;
try {
- returnData = methodCallbacks->method(data);
+ returnData = methodCallbacks->method(peerID, data);
} catch (const std::exception& e) {
LOGE("Exception in method handler: " << e.what());
removePeerInternal(peerID, Status::NAUGHTY_PEER);
@@ -434,10 +523,44 @@ bool Processor::onNewPeer()
mSockets[socketInfo.peerID] = std::move(socketInfo.socketPtr);
}
+
+
+ // Broadcast the new signal to peers
+ LOGW("Sending handled signals");
+ std::list peersIDs;
+ {
+ Lock lock(mSocketsMutex);
+ for (const auto kv : mSockets) {
+ peersIDs.push_back(kv.first);
+ }
+ }
+
+ std::vector ids;
+ {
+ Lock lock(mSocketsMutex);
+ for (const auto kv : mSignalsCallbacks) {
+ ids.push_back(kv.first);
+ }
+ }
+ auto data = std::make_shared(ids);
+
+ for (const PeerID peerID : peersIDs) {
+ callInternal(REGISTER_SIGNAL_METHOD_ID,
+ peerID,
+ data,
+ discardResultHandler);
+ }
+ LOGW("Sent handled signals");
+
+
resetPolling();
- if (mNewPeerCallback) {
- // Notify about the new user.
- mNewPeerCallback(socketInfo.peerID);
+
+ {
+ Lock lock(mCallbacksMutex);
+ if (mNewPeerCallback) {
+ // Notify about the new user.
+ mNewPeerCallback(socketInfo.peerID);
+ }
}
return true;
}
@@ -456,13 +579,13 @@ bool Processor::onRemovePeer()
return true;
}
-Processor::MessageID Processor::getNextMessageID()
+MessageID Processor::getNextMessageID()
{
// TODO: This method of generating UIDs is buggy. To be changed.
return ++mMessageIDCounter;
}
-Processor::PeerID Processor::getNextPeerID()
+PeerID Processor::getNextPeerID()
{
// TODO: This method of generating UIDs is buggy. To be changed.
return ++mPeerIDCounter;
@@ -496,14 +619,12 @@ bool Processor::onCall()
return false;
}
- {
- // Set what to do with the return message
+ if (call.parse && call.process) {
+ // Set what to do with the return message, but only if needed
Lock lock(mReturnCallbacksMutex);
if (mReturnCallbacks.count(call.messageID) != 0) {
LOGE("There already was a return callback for messageID: " << call.messageID);
}
-
- // move insertion
mReturnCallbacks[call.messageID] = std::move(ReturnCallbacks(call.peerID,
std::move(call.parse),
std::move(call.process)));
@@ -544,7 +665,9 @@ void Processor::cleanCommunication()
case Event::CALL: {
LOGD("Event CALL after FINISH");
Call call = getCall();
- IGNORE_EXCEPTIONS(call.process(Status::CLOSING, call.data));
+ if (call.process) {
+ IGNORE_EXCEPTIONS(call.process(Status::CLOSING, call.data));
+ }
break;
}
diff --git a/common/ipc/internals/processor.hpp b/common/ipc/internals/processor.hpp
index 7554eb8..e43fe62 100644
--- a/common/ipc/internals/processor.hpp
+++ b/common/ipc/internals/processor.hpp
@@ -31,6 +31,7 @@
#include "ipc/types.hpp"
#include "config/manager.hpp"
#include "config/is-visitable.hpp"
+#include "config/fields.hpp"
#include "logger/logger.hpp"
#include
@@ -43,14 +44,16 @@
#include
#include
#include
+#include
#include
#include
namespace security_containers {
namespace ipc {
-namespace {
+
const unsigned int DEFAULT_MAX_NUMBER_OF_PEERS = 500;
-}
+const unsigned int DEFAULT_METHOD_TIMEOUT = 1000;
+
/**
* This class wraps communication via UX sockets
*
@@ -66,18 +69,25 @@ const unsigned int DEFAULT_MAX_NUMBER_OF_PEERS = 500;
*
* TODO:
* - some mutexes may not be needed
+* - synchronous call to many peers
+* - implement CallQueue class
+* - implement HandlerStore class for storing both signals and methods
+* - API for removing signals
+* - implement CallbackStore - thread safe calling/setting callbacks
+* - helper function for removing from unordered map
*/
class Processor {
public:
- typedef std::function PeerCallback;
- typedef unsigned int PeerID;
- typedef unsigned int MethodID;
- typedef unsigned int MessageID;
-
/**
- * Method ID. Used to indicate a message with the return value.
+ * Used to indicate a message with the return value.
*/
static const MethodID RETURN_METHOD_ID;
+
+ /**
+ * Indicates an Processor's internal request/broadcast to register a Signal
+ */
+ static const MethodID REGISTER_SIGNAL_METHOD_ID;
+
/**
* Constructs the Processor, but doesn't start it.
* The object is ready to add methods.
@@ -101,12 +111,31 @@ public:
void start();
/**
+ * @return is processor running
+ */
+ bool isStarted();
+
+ /**
* Stops the processing thread.
* No incoming data will be handled after.
*/
void stop();
/**
+ * Set the callback called for each new connection to a peer
+ *
+ * @param newPeerCallback the callback
+ */
+ void setNewPeerCallback(const PeerCallback& newPeerCallback);
+
+ /**
+ * Set the callback called when connection to a peer is lost
+ *
+ * @param removedPeerCallback the callback
+ */
+ void setRemovedPeerCallback(const PeerCallback& removedPeerCallback);
+
+ /**
* From now on socket is owned by the Processor object.
* Calls the newPeerCallback.
*
@@ -139,6 +168,24 @@ public:
const typename MethodHandler::type& process);
/**
+ * Saves the callbacks connected to the method id.
+ * When a message with the given method id is received,
+ * the data will be passed to the serialization callback through file descriptor.
+ *
+ * Then the process callback will be called with the parsed data.
+ * There is no return data to send back.
+ *
+ * Adding signal sends a registering message to all peers
+ *
+ * @param methodID API dependent id of the method
+ * @param process data processing callback
+ * @tparam ReceivedDataType data type to receive
+ */
+ template
+ void addSignalHandler(const MethodID methodID,
+ const typename SignalHandler::type& process);
+
+ /**
* Removes the callback
*
* @param methodID API dependent id of the method
@@ -178,11 +225,42 @@ public:
const typename ResultHandler::type& process);
+ /**
+ * Send a signal to the peer.
+ * There is no return value from the peer
+ * Sends any data only if a peer registered this a signal
+ *
+ * @param methodID API dependent id of the method
+ * @param data data to sent
+ * @tparam SentDataType data type to send
+ */
+ template
+ void signal(const MethodID methodID,
+ const std::shared_ptr& data);
+
+
private:
typedef std::function& data)> SerializeCallback;
typedef std::function(int fd)> ParseCallback;
typedef std::lock_guard Lock;
+ struct EmptyData {
+ CONFIG_REGISTER_EMPTY
+ };
+
+ struct RegisterSignalsMessage {
+ RegisterSignalsMessage() = default;
+ RegisterSignalsMessage(const std::vector ids)
+ : ids(ids) {}
+
+ std::vector ids;
+
+ CONFIG_REGISTER
+ (
+ ids
+ )
+ };
+
struct Call {
Call(const Call& other) = delete;
Call& operator=(const Call&) = delete;
@@ -210,6 +288,17 @@ private:
MethodHandler::type method;
};
+ struct SignalHandlers {
+ SignalHandlers(const SignalHandlers& other) = delete;
+ SignalHandlers& operator=(const SignalHandlers&) = delete;
+ SignalHandlers() = default;
+ SignalHandlers(SignalHandlers&&) = default;
+ SignalHandlers& operator=(SignalHandlers &&) = default;
+
+ ParseCallback parse;
+ SignalHandler::type signal;
+ };
+
struct ReturnCallbacks {
ReturnCallbacks(const ReturnCallbacks& other) = delete;
ReturnCallbacks& operator=(const ReturnCallbacks&) = delete;
@@ -269,6 +358,8 @@ private:
std::mutex mCallsMutex;
std::queue mCalls;
std::unordered_map> mMethodsCallbacks;
+ std::unordered_map> mSignalsCallbacks;
+ std::unordered_map