From 70c609070756512c76ab883311dae531c27a8d37 Mon Sep 17 00:00:00 2001 From: "Maciej J. Karpiuk" Date: Thu, 15 Oct 2015 11:42:52 +0200 Subject: [PATCH] lxcpp: provisioning implementation (part 1) [Feature] Provisioning implementation for lxcpp (declare, list, remove) [Cause] N/A [Solution] N/A [Verification] Build, install, run tests Change-Id: I3823587de023a9f1a9e34208ae9e188521dbe3b1 --- libs/lxcpp/commands/command.hpp | 6 +- libs/lxcpp/commands/provision.cpp | 89 +++++++++++++++ libs/lxcpp/commands/provision.hpp | 116 ++++++++++++++++++++ libs/lxcpp/container-config.hpp | 12 +- libs/lxcpp/container-impl.cpp | 98 ++++++++++++++++- libs/lxcpp/container-impl.hpp | 22 ++++ libs/lxcpp/container.hpp | 23 ++++ libs/lxcpp/exception.hpp | 5 + libs/lxcpp/guard/guard.cpp | 9 ++ libs/lxcpp/provision-config.cpp | 115 +++++++++++++++++++ libs/lxcpp/provision-config.hpp | 170 +++++++++++++++++++++++++++++ tests/unit_tests/lxcpp/ut-provisioning.cpp | 164 ++++++++++++++++++++++++++++ 12 files changed, 826 insertions(+), 3 deletions(-) create mode 100644 libs/lxcpp/commands/provision.cpp create mode 100644 libs/lxcpp/commands/provision.hpp create mode 100644 libs/lxcpp/provision-config.cpp create mode 100644 libs/lxcpp/provision-config.hpp create mode 100644 tests/unit_tests/lxcpp/ut-provisioning.cpp diff --git a/libs/lxcpp/commands/command.hpp b/libs/lxcpp/commands/command.hpp index cd301ee..a1ba473 100644 --- a/libs/lxcpp/commands/command.hpp +++ b/libs/lxcpp/commands/command.hpp @@ -28,9 +28,13 @@ namespace lxcpp { class Command { public: + // do sth [mandatory] virtual void execute() = 0; + + // roll-back execute() action [optional] + virtual void revert() {} }; } // namespace lxcpp -#endif // LXCPP_COMMANDS_COMMAND_HPP \ No newline at end of file +#endif // LXCPP_COMMANDS_COMMAND_HPP diff --git a/libs/lxcpp/commands/provision.cpp b/libs/lxcpp/commands/provision.cpp new file mode 100644 index 0000000..ba97393 --- /dev/null +++ b/libs/lxcpp/commands/provision.cpp @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * @author Maciej Karpiuk (m.karpiuk2@samsung.com) + * @brief Add new provisioned file/dir/link/mount command + */ + +#include "lxcpp/commands/provision.hpp" +#include "lxcpp/container.hpp" +#include "lxcpp/provision-config.hpp" + +namespace lxcpp { + +void Provisions::execute() +{ + for(const auto & file : mConfig.mProvisions.files) { + ProvisionFile(mConfig, file).execute(); + } + + for(const auto & mount : mConfig.mProvisions.mounts) { + ProvisionMount(mConfig, mount).execute(); + } + + for(const auto & link : mConfig.mProvisions.links) { + ProvisionLink(mConfig, link).execute(); + } +} +void Provisions::revert() +{ + for(const auto & file : mConfig.mProvisions.files) { + ProvisionFile(mConfig, file).revert(); + } + + for(const auto & mount : mConfig.mProvisions.mounts) { + ProvisionMount(mConfig, mount).revert(); + } + + for(const auto & link : mConfig.mProvisions.links) { + ProvisionLink(mConfig, link).revert(); + } +} + + +void ProvisionFile::execute() +{ + // MJK TODO: add file +} +void ProvisionFile::revert() +{ + // MJK TODO: remove file from container +} + + +void ProvisionMount::execute() +{ + // MJK TODO: add mount +} +void ProvisionMount::revert() +{ + // MJK TODO: remove mount from container +} + + +void ProvisionLink::execute() +{ + // MJK TODO: add link +} +void ProvisionLink::revert() +{ + // MJK TODO: remove link from container +} + +} // namespace lxcpp diff --git a/libs/lxcpp/commands/provision.hpp b/libs/lxcpp/commands/provision.hpp new file mode 100644 index 0000000..0b7411a --- /dev/null +++ b/libs/lxcpp/commands/provision.hpp @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * @author Maciej Karpiuk (m.karpiuk2@samsung.com) + * @brief Add new provisioned file/dir/link/mount command + */ + +#ifndef LXCPP_COMMAND_PROVISION_HPP +#define LXCPP_COMMAND_PROVISION_HPP + +#include "lxcpp/commands/command.hpp" +#include "lxcpp/container-config.hpp" +#include "lxcpp/provision-config.hpp" + +#include + +namespace lxcpp { + +class Provisions final: Command { +public: + /** + * Runs call in the container's context + * + * Add/remove all file/fifo/dir/mount/link provisions to/from the container + */ + Provisions(ContainerConfig &config) : mConfig(config) + { + } + + void execute(); + void revert(); + +private: + ContainerConfig& mConfig; +}; + + +class ProvisionFile final: Command { +public: + /** + * Runs call in the container's context + * + * Add/remove new file/fifo/dir provision to/from the container + */ + ProvisionFile(ContainerConfig &config, const provision::File &file) : + mConfig(config), mFile(file) + { + } + + void execute(); + void revert(); + +private: + ContainerConfig& mConfig; + const provision::File& mFile; +}; + +class ProvisionMount final: Command { +public: + /** + * Runs call in the container's context + * + * Add/remove new mount provision to/from the container + */ + ProvisionMount(ContainerConfig &config, const provision::Mount &mount) : + mConfig(config), mMount(mount) + { + } + + void execute(); + void revert(); + +private: + ContainerConfig& mConfig; + const provision::Mount& mMount; +}; + +class ProvisionLink final: Command { +public: + /** + * Runs call in the container's context + * + * Add/remove link provision to/from the container + */ + ProvisionLink(ContainerConfig &config, const provision::Link &link) : + mConfig(config), mLink(link) + { + } + + void execute(); + void revert(); + +private: + ContainerConfig& mConfig; + const provision::Link& mLink; +}; + +} // namespace lxcpp + +#endif // LXCPP_COMMAND_PROVISION_HPP diff --git a/libs/lxcpp/container-config.hpp b/libs/lxcpp/container-config.hpp index 4fbf86d..1a487cf 100644 --- a/libs/lxcpp/container-config.hpp +++ b/libs/lxcpp/container-config.hpp @@ -27,6 +27,7 @@ #include "lxcpp/logger-config.hpp" #include "lxcpp/network-config.hpp" #include "lxcpp/terminal-config.hpp" +#include "lxcpp/provision-config.hpp" #include #include @@ -117,6 +118,14 @@ struct ContainerConfig { */ int mNamespaces; + /** + * available files/dirs/mounts/links + * + * Set: by container provision manipulation methods + * Get: getFiles(), getMounts(), getLinks() + */ + ProvisionConfig mProvisions; + ContainerConfig() : mGuardPid(-1), mInitPid(-1), mNamespaces(0) {} CONFIG_REGISTER @@ -128,7 +137,8 @@ struct ContainerConfig { mInit, mLogger, mTerminals, - mNamespaces + mNamespaces, + mProvisions ) }; diff --git a/libs/lxcpp/container-impl.cpp b/libs/lxcpp/container-impl.cpp index e19012c..29d6cb0 100644 --- a/libs/lxcpp/container-impl.cpp +++ b/libs/lxcpp/container-impl.cpp @@ -31,6 +31,7 @@ #include "lxcpp/commands/start.hpp" #include "lxcpp/commands/stop.hpp" #include "lxcpp/commands/prep-host-terminal.hpp" +#include "lxcpp/commands/provision.hpp" #include "logger/logger.hpp" #include "utils/exception.hpp" @@ -170,7 +171,7 @@ void ContainerImpl::start() void ContainerImpl::stop() { - // TODO: things to do when shuttting down the container: + // TODO: things to do when shutting down the container: // - close PTY master FDs from the config so we won't keep PTYs open Stop stop(mConfig); @@ -215,6 +216,12 @@ void ContainerImpl::console() console.execute(); } +bool ContainerImpl::isRunning() const +{ + // TODO: race condition may occur, sync needed + return getInitPid() != -1; +} + void ContainerImpl::addInterfaceConfig(const std::string& hostif, const std::string& zoneif, InterfaceType type, @@ -305,4 +312,93 @@ void ContainerImpl::delInetAddr(const std::string& ifname, const InetAddr& addr) ni.delInetAddr(addr); } +void ContainerImpl::declareFile(const provision::File::Type type, + const std::string& path, + const int32_t flags, + const int32_t mode) +{ + provision::File newFile({type, path, flags, mode}); + mConfig.mProvisions.addFile(newFile); + // TODO: update guard config + + if (isRunning()) { + ProvisionFile fileCmd(mConfig, newFile); + fileCmd.execute(); + } +} + +const FileVector& ContainerImpl::getFiles() const +{ + return mConfig.mProvisions.getFiles(); +} + +void ContainerImpl::removeFile(const provision::File& item) +{ + mConfig.mProvisions.removeFile(item); + + if (isRunning()) { + ProvisionFile fileCmd(mConfig, item); + fileCmd.revert(); + } +} + +void ContainerImpl::declareMount(const std::string& source, + const std::string& target, + const std::string& type, + const int64_t flags, + const std::string& data) +{ + provision::Mount newMount({source, target, type, flags, data}); + mConfig.mProvisions.addMount(newMount); + // TODO: update guard config + + if (isRunning()) { + ProvisionMount mountCmd(mConfig, newMount); + mountCmd.execute(); + } +} + +const MountVector& ContainerImpl::getMounts() const +{ + return mConfig.mProvisions.getMounts(); +} + +void ContainerImpl::removeMount(const provision::Mount& item) +{ + mConfig.mProvisions.removeMount(item); + + if (isRunning()) { + ProvisionMount mountCmd(mConfig, item); + mountCmd.revert(); + } +} + +void ContainerImpl::declareLink(const std::string& source, + const std::string& target) +{ + provision::Link newLink({source, target}); + mConfig.mProvisions.addLink(newLink); + // TODO: update guard config + + if (isRunning()) { + ProvisionLink linkCmd(mConfig, newLink); + linkCmd.execute(); + } +} + +const LinkVector& ContainerImpl::getLinks() const +{ + return mConfig.mProvisions.getLinks(); +} + +void ContainerImpl::removeLink(const provision::Link& item) +{ + mConfig.mProvisions.removeLink(item); + + if (isRunning()) { + ProvisionLink linkCmd(mConfig, item); + linkCmd.revert(); + } +} + } // namespace lxcpp diff --git a/libs/lxcpp/container-impl.hpp b/libs/lxcpp/container-impl.hpp index d3db492..f1cba58 100644 --- a/libs/lxcpp/container-impl.hpp +++ b/libs/lxcpp/container-impl.hpp @@ -69,6 +69,7 @@ public: void attach(const std::vector& argv, const std::string& cwdInContainer); void console(); + bool isRunning() const; // Network interfaces setup/config /** @@ -96,6 +97,27 @@ public: void addInetAddr(const std::string& ifname, const InetAddr& addr); void delInetAddr(const std::string& ifname, const InetAddr& addr); + // Provisioning + void declareFile(const provision::File::Type type, + const std::string& path, + const int32_t flags, + const int32_t mode); + const FileVector& getFiles() const; + void removeFile(const provision::File& item); + + void declareMount(const std::string& source, + const std::string& target, + const std::string& type, + const int64_t flags, + const std::string& data); + const MountVector& getMounts() const; + void removeMount(const provision::Mount& item); + + void declareLink(const std::string& source, + const std::string& target); + const LinkVector& getLinks() const; + void removeLink(const provision::Link& item); + private: ContainerConfig mConfig; }; diff --git a/libs/lxcpp/container.hpp b/libs/lxcpp/container.hpp index 096463b..2d0e696 100644 --- a/libs/lxcpp/container.hpp +++ b/libs/lxcpp/container.hpp @@ -25,6 +25,7 @@ #define LXCPP_CONTAINER_HPP #include "lxcpp/network-config.hpp" +#include "lxcpp/provision-config.hpp" #include "lxcpp/logger-config.hpp" #include @@ -78,6 +79,7 @@ public: virtual void attach(const std::vector& argv, const std::string& cwdInContainer) = 0; virtual void console() = 0; + virtual bool isRunning() const = 0; // Network interfaces setup/config virtual void addInterfaceConfig(const std::string& hostif, @@ -100,6 +102,27 @@ public: virtual void setDown(const std::string& ifname) = 0; virtual void addInetAddr(const std::string& ifname, const InetAddr& addr) = 0; virtual void delInetAddr(const std::string& ifname, const InetAddr& addr) = 0; + + // Provisioning + virtual void declareFile(const provision::File::Type type, + const std::string& path, + const int32_t flags, + const int32_t mode) = 0; + virtual const FileVector& getFiles() const = 0; + virtual void removeFile(const provision::File& item) = 0; + + virtual void declareMount(const std::string& source, + const std::string& target, + const std::string& type, + const int64_t flags, + const std::string& data) = 0; + virtual const MountVector& getMounts() const = 0; + virtual void removeMount(const provision::Mount& item) = 0; + + virtual void declareLink(const std::string& source, + const std::string& target) = 0; + virtual const LinkVector& getLinks() const = 0; + virtual void removeLink(const provision::Link& item) = 0; }; } // namespace lxcpp diff --git a/libs/lxcpp/exception.hpp b/libs/lxcpp/exception.hpp index 387e2eb..37fec5a 100644 --- a/libs/lxcpp/exception.hpp +++ b/libs/lxcpp/exception.hpp @@ -96,6 +96,11 @@ struct ConfigureException: public Exception { : Exception(message) {} }; +struct ProvisionException: public Exception { + explicit ProvisionException(const std::string& message = "Provision error") + : Exception(message) {} +}; + } // namespace lxcpp #endif // LXCPP_EXCEPTION_HPP diff --git a/libs/lxcpp/guard/guard.cpp b/libs/lxcpp/guard/guard.cpp index 4f56771..f96fe7a 100644 --- a/libs/lxcpp/guard/guard.cpp +++ b/libs/lxcpp/guard/guard.cpp @@ -25,6 +25,7 @@ #include "lxcpp/guard/guard.hpp" #include "lxcpp/process.hpp" #include "lxcpp/commands/prep-guest-terminal.hpp" +#include "lxcpp/commands/provision.hpp" #include "config/manager.hpp" #include "logger/logger.hpp" @@ -42,6 +43,9 @@ int startContainer(void* data) // TODO: container preparation part 2 + Provisions provisions(config); + provisions.execute(); + PrepGuestTerminal terminals(config.mTerminals); terminals.execute(); @@ -96,6 +100,11 @@ int Guard::execute() int status = lxcpp::waitpid(initPid); LOGD("Init exited with status: " << status); + + // TODO: cleanup after child exits + Provisions provisions(mConfig); + provisions.revert(); + return status; } diff --git a/libs/lxcpp/provision-config.cpp b/libs/lxcpp/provision-config.cpp new file mode 100644 index 0000000..459ba70 --- /dev/null +++ b/libs/lxcpp/provision-config.cpp @@ -0,0 +1,115 @@ +/* + * Copyright (C) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * @author Maciej Karpiuk (m.karpiuk2@samsung.com) + * @brief Provisioning configuration + */ + +#include +#include +#include "lxcpp/container-config.hpp" + +using namespace lxcpp; +using namespace provision; + +void ProvisionConfig::addFile(const File& newFile) +{ + auto it = std::find(files.begin(), files.end(), newFile); + if (it != files.end()) { + const std::string msg = + "Can't add file. Provision already exists: " + newFile.getId(); + LOGE(msg); + throw ProvisionException(msg); + } + files.push_back(newFile); +} + +const FileVector& ProvisionConfig::getFiles() const +{ + return files; +} + +void ProvisionConfig::removeFile(const File& item) +{ + const auto it = std::find(files.begin(), files.end(), item); + if (it == files.end()) { + const std::string msg = "Can't find provision: " + item.getId(); + LOGE(msg); + throw ProvisionException(msg); + } + files.erase(it); +} + + +void ProvisionConfig::addMount(const Mount& newMount) +{ + auto it = std::find(mounts.begin(), mounts.end(), newMount); + if (it != mounts.end()) { + const std::string msg = + "Can't add mount. Provision already exists: " + newMount.getId(); + LOGE(msg); + throw ProvisionException(msg); + } + mounts.push_back(newMount); +} + +const MountVector& ProvisionConfig::getMounts() const +{ + return mounts; +} + +void ProvisionConfig::removeMount(const Mount& item) +{ + const auto it = std::find(mounts.begin(), mounts.end(), item); + if (it == mounts.end()) { + const std::string msg = "Can't find provision: " + item.getId(); + LOGE(msg); + throw ProvisionException(msg); + } + mounts.erase(it); +} + + +void ProvisionConfig::addLink(const Link& newLink) +{ + auto it = std::find(links.begin(), links.end(), newLink); + if (it != links.end()) { + const std::string msg = + "Can't add link. Provision already exists: " + newLink.getId(); + LOGE(msg); + throw ProvisionException(msg); + } + links.push_back(newLink); +} + +const LinkVector& ProvisionConfig::getLinks() const +{ + return links; +} + +void ProvisionConfig::removeLink(const Link& item) +{ + const auto it = std::find(links.begin(), links.end(), item); + if (it == links.end()) { + const std::string msg = "Can't find provision: " + item.getId(); + LOGE(msg); + throw ProvisionException(msg); + } + links.erase(it); +} diff --git a/libs/lxcpp/provision-config.hpp b/libs/lxcpp/provision-config.hpp new file mode 100644 index 0000000..fb9cbc4 --- /dev/null +++ b/libs/lxcpp/provision-config.hpp @@ -0,0 +1,170 @@ +/* + * Copyright (C) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * @author Maciej Karpiuk (m.karpiuk2@samsung.com) + * @brief Provisioning configuration + */ + +#ifndef LXCPP_PROVISION_CONFIG_HPP +#define LXCPP_PROVISION_CONFIG_HPP + +#include "config/config.hpp" +#include "config/fields.hpp" +#include "config/fields-union.hpp" + +#include +#include +#include + +namespace lxcpp { +namespace provision { + +typedef std::string ProvisionID; + +/** + * Provision configuration items + */ +struct File +{ + enum class Type : int + { + DIRECTORY, + FIFO, + REGULAR + }; + + ProvisionID getId() const + { + return "file " + + path + " " + + std::to_string(static_cast(type)) + " " + + std::to_string(flags) + " " + + std::to_string(mode); + } + + Type type; + std::string path; + std::int32_t flags; + std::int32_t mode; + + CONFIG_REGISTER + ( + type, + path, + flags, + mode + ) + + bool operator==(const File& m) const + { + return ((m.type == type) && (m.path == path) && + (m.flags == flags) && (m.mode == mode)); + } +}; + +struct Mount +{ + ProvisionID getId() const + { + return "mount " + + source + " " + + target + " " + + type + " " + + std::to_string(flags) + " " + + data; + } + + std::string source; + std::string target; + std::string type; + std::int64_t flags; + std::string data; + + CONFIG_REGISTER + ( + source, + target, + type, + flags, + data + ) + + bool operator==(const Mount& m) const + { + return ((m.source == source) && (m.target == target) && (m.type == type) && + (m.flags == flags) && (m.data == data)); + } +}; + +struct Link +{ + ProvisionID getId() const + { + return "link " + source + " " + target; + } + + std::string source; + std::string target; + + CONFIG_REGISTER + ( + source, + target + ) + + bool operator==(const Link& m) const + { + return ((m.source == source) && (m.target == target)); + } +}; +} // namespace provision + +typedef std::vector FileVector; +typedef std::vector MountVector; +typedef std::vector LinkVector; + +struct ProvisionConfig +{ + FileVector files; + MountVector mounts; + LinkVector links; + + void addFile(const provision::File& newFile); + const FileVector& getFiles() const; + void removeFile(const provision::File& item); + + void addMount(const provision::Mount& newMount); + const MountVector& getMounts() const; + void removeMount(const provision::Mount& item); + + void addLink(const provision::Link& newLink); + const LinkVector& getLinks() const; + void removeLink(const provision::Link& item); + + CONFIG_REGISTER + ( + files, + mounts, + links + ) +}; + +} // namespace lxcpp + +#endif // LXCPP_PROVISION_CONFIG_HPP diff --git a/tests/unit_tests/lxcpp/ut-provisioning.cpp b/tests/unit_tests/lxcpp/ut-provisioning.cpp new file mode 100644 index 0000000..d2a535c --- /dev/null +++ b/tests/unit_tests/lxcpp/ut-provisioning.cpp @@ -0,0 +1,164 @@ +/* + * Copyright (C) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * @author Maciej Karpiuk (m.karpiuk2@samsung.com) + * @brief Unit tests of lxcpp provisioning + */ + +#include "config.hpp" +#include "config/manager.hpp" +#include "lxcpp/lxcpp.hpp" +#include "lxcpp/container.hpp" +#include "lxcpp/container-config.hpp" +#include "lxcpp/provision-config.hpp" +#include "ut.hpp" +#include "utils/scoped-dir.hpp" +#include + +namespace { + +using namespace lxcpp; +using namespace config; +using namespace provision; + +const std::string TEST_DIR = "/tmp/ut-provisioning"; +const std::string ROOT_DIR = TEST_DIR + "/root"; + +struct Fixture { + Fixture() : mTestPath(ROOT_DIR) { + container = std::unique_ptr(createContainer("ProvisioningTester", ROOT_DIR)); + } + ~Fixture() {} + + std::unique_ptr container; + utils::ScopedDir mTestPath; +}; + +} // namespace + + +BOOST_FIXTURE_TEST_SUITE(LxcppProvisioningSuite, Fixture) + +BOOST_AUTO_TEST_CASE(ListProvisionsEmptyContainer) +{ + BOOST_REQUIRE(container->getFiles().size() == 0); + BOOST_REQUIRE(container->getMounts().size() == 0); + BOOST_REQUIRE(container->getLinks().size() == 0); +} + +BOOST_AUTO_TEST_CASE(AddDeclareFile) +{ + container->declareFile(File::Type::FIFO, "path", 0747, 0777); + container->declareFile(File::Type::REGULAR, "path", 0747, 0777); + + std::vector fileList = container->getFiles(); + BOOST_REQUIRE_EQUAL(fileList.size(), 2); + + BOOST_REQUIRE(fileList[0].type == File::Type::FIFO); + BOOST_REQUIRE(fileList[0].path == "path"); + BOOST_REQUIRE(fileList[0].flags == 0747); + BOOST_REQUIRE(fileList[0].mode == 0777); + BOOST_REQUIRE(fileList[1].type == File::Type::REGULAR); + + BOOST_REQUIRE_NO_THROW(container->removeFile(fileList[0])); + BOOST_REQUIRE_EQUAL(container->getFiles().size(), 1); + File dummyFile({File::Type::FIFO, "dummy", 1, 2}); + BOOST_REQUIRE_THROW(container->removeFile(dummyFile), ProvisionException); + BOOST_REQUIRE_NO_THROW(container->removeFile(fileList[1])); + BOOST_REQUIRE_EQUAL(container->getFiles().size(), 0); +} + +BOOST_AUTO_TEST_CASE(AddDeclareMount) +{ + container->declareMount("/fake/path1", "/fake/path2", "tmpfs", 077, "fake"); + container->declareMount("/fake/path2", "/fake/path2", "tmpfs", 077, "fake"); + BOOST_CHECK_THROW(container->declareMount("/fake/path2", "/fake/path2", "tmpfs", 077, "fake"), + ProvisionException); + + std::vector mountList = container->getMounts(); + BOOST_REQUIRE_EQUAL(mountList.size(), 2); + + BOOST_REQUIRE(mountList[0].source == "/fake/path1"); + BOOST_REQUIRE(mountList[0].target == "/fake/path2"); + BOOST_REQUIRE(mountList[0].type == "tmpfs"); + BOOST_REQUIRE(mountList[0].flags == 077); + BOOST_REQUIRE(mountList[0].data == "fake"); + + BOOST_REQUIRE(mountList[1].source == "/fake/path2"); + BOOST_REQUIRE(mountList[1].target == "/fake/path2"); + BOOST_REQUIRE(mountList[1].type == "tmpfs"); + BOOST_REQUIRE(mountList[1].flags == 077); + BOOST_REQUIRE(mountList[1].data == "fake"); + + BOOST_REQUIRE_NO_THROW(container->removeMount(mountList[0])); + BOOST_REQUIRE_EQUAL(container->getMounts().size(), 1); + Mount dummyMount({"a", "b", "c", 1, "d"}); + BOOST_REQUIRE_THROW(container->removeMount(dummyMount), ProvisionException); + BOOST_REQUIRE_NO_THROW(container->removeMount(mountList[1])); + BOOST_REQUIRE_EQUAL(container->getMounts().size(), 0); +} + +BOOST_AUTO_TEST_CASE(AddDeclareLink) +{ + container->declareLink("/fake/path1", "/fake/path2"); + container->declareLink("/fake/path2", "/fake/path2"); + BOOST_CHECK_THROW(container->declareLink("/fake/path2", "/fake/path2"), + ProvisionException); + + std::vector linkList = container->getLinks(); + BOOST_REQUIRE_EQUAL(linkList.size(), 2); + + BOOST_REQUIRE(linkList[0].source == "/fake/path1"); + BOOST_REQUIRE(linkList[0].target == "/fake/path2"); + BOOST_REQUIRE(linkList[1].source == "/fake/path2"); + BOOST_REQUIRE(linkList[1].target == "/fake/path2"); + + BOOST_REQUIRE_NO_THROW(container->removeLink(linkList[0])); + BOOST_REQUIRE_EQUAL(container->getLinks().size(), 1); + Link dummyLink({"a", "b"}); + BOOST_REQUIRE_THROW(container->removeLink(dummyLink), ProvisionException); + BOOST_REQUIRE_NO_THROW(container->removeLink(linkList[1])); + BOOST_REQUIRE_EQUAL(container->getLinks().size(), 0); +} + +BOOST_AUTO_TEST_CASE(ProvisioningConfigSerialization) +{ + std::string tmpConfigFile = "/tmp/fileconfig.conf"; + std::string tmpConfigMount = "/tmp/mountconfig.conf"; + std::string tmpConfigLink = "/tmp/linkconfig.conf"; + + File saved_file ({File::Type::REGULAR, "path", 0747, 0777}); + Mount saved_mount({"/fake/path1", "/fake/path2", "tmpfs", 077, "fake"}); + Link saved_link ({"/fake/path1", "/fake/path2"}); + config::saveToJsonFile(tmpConfigFile, saved_file); + config::saveToJsonFile(tmpConfigMount, saved_mount); + config::saveToJsonFile(tmpConfigLink, saved_link); + + File loaded_file; + Mount loaded_mount; + Link loaded_link; + config::loadFromJsonFile(tmpConfigFile, loaded_file); + config::loadFromJsonFile(tmpConfigMount, loaded_mount); + config::loadFromJsonFile(tmpConfigLink, loaded_link); + BOOST_REQUIRE(saved_file == loaded_file); + BOOST_REQUIRE(saved_mount == loaded_mount); + BOOST_REQUIRE(saved_link == loaded_link); +} + +BOOST_AUTO_TEST_SUITE_END() -- 2.7.4