Group: Security/Other
Summary: Daemon for managing containers
BuildRequires: cmake
-BuildRequires: libvirt
BuildRequires: libvirt-devel
-BuildRequires: libjson
BuildRequires: libjson-devel
BuildRequires: pkgconfig(glib-2.0)
+Requires: libvirt
+Requires: libjson
+Requires: libboost_program_options
+Requires: libboost_test
%description
This package provides a daemon used to manage containers - start, stop and switch
--- /dev/null
+/*
+ * Copyright (c) 2000 - 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Contact: Bumjin Im <bj.im@samsung.com>
+ *
+ * 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 log-backend-null.hpp
+ * @author Pawel Broda (p.broda@partner.samsung.com)
+ * @brief Null backend for logger
+ */
+
+
+#ifndef LOG_BACKEND_NULL_HPP
+#define LOG_BACKEND_NULL_HPP
+
+#include "log-backend.hpp"
+
+namespace security_containers {
+namespace log {
+
+/**
+ Null logging backend
+ */
+class NullLogger : public LogBackend {
+public:
+ void log(const std::string& /*message*/) override {}
+};
+
+} // namespace log
+} // namespace security_containers
+
+#endif // LOG_BACKEND_NULL_HPP
--- /dev/null
+/*
+ * Copyright (c) 2000 - 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Contact: Bumjin Im <bj.im@samsung.com>
+ *
+ * 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 log-backend-stderr.hpp
+ * @author Pawel Broda (p.broda@partner.samsung.com)
+ * @brief Stderr backend for logger
+ */
+
+
+#ifndef LOG_BACKEND_STDERR_HPP
+#define LOG_BACKEND_STDERR_HPP
+
+#include "log-backend.hpp"
+
+namespace security_containers {
+namespace log {
+
+/**
+ Stderr logging backend
+ */
+class StderrBackend : public LogBackend {
+public:
+ void log(const std::string& message) override;
+};
+
+} // namespace log
+} // namespace security_containers
+
+#endif // LOG_BACKEND_STDERR_HPP
--- /dev/null
+/*
+ * Copyright (c) 2000 - 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Contact: Bumjin Im <bj.im@samsung.com>
+ *
+ * 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 log-backend.hpp
+ * @author Pawel Broda (p.broda@partner.samsung.com)
+ * @brief Logging backend
+ */
+
+
+#ifndef LOG_BACKEND_HPP
+#define LOG_BACKEND_HPP
+
+#include <string>
+
+namespace security_containers {
+namespace log {
+
+/**
+ Abstract class for logger
+ */
+class LogBackend {
+public:
+ virtual void log(const std::string& message) = 0;
+ virtual ~LogBackend() {}
+};
+
+} // namespace log
+} // namespace security_containers
+
+#endif // LOG_BACKEND_HPP
/**
* @file log.hpp
* @author Jan Olszak (j.olszak@samsung.com)
- * @brief Logging macros
+ * @brief Logger
*/
#ifndef LOG_HPP
#define LOG_HPP
-#include <iostream>
+#include "log-backend.hpp"
+
+#include <sstream>
#include <string.h>
+namespace security_containers {
+namespace log {
+
+enum class LogLevel {
+ TRACE, DEBUG, INFO, WARN, ERROR
+};
+
+class Logger {
+public:
+ Logger(const std::string& severity, const std::string& file, const int line);
+ void logMessage(const std::string& message);
+
+ static void setLogLevel(LogLevel level);
+ static LogLevel getLogLevel(void);
+ static void setLogBackend(LogBackend* pBackend);
+
+private:
+ std::ostringstream mLogLine;
+};
+
+} // namespace log
+} // namespace security_containers
+
+
#define BASE_FILE (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__)
-#define LOG_LEVEL(level, ...) \
- std::cout << "[" << level << "] " << BASE_FILE << ":" << __LINE__ << " " \
- << __VA_ARGS__ << std::endl
+#define LOG(SEVERITY, MESSAGE) \
+ do { \
+ if (security_containers::log::Logger::getLogLevel() <= \
+ security_containers::log::LogLevel::SEVERITY) { \
+ std::ostringstream message; \
+ message << MESSAGE; \
+ security_containers::log::Logger logger(#SEVERITY, BASE_FILE, __LINE__); \
+ logger.logMessage(message.str()); \
+ } \
+ } while(0)
-#define LOGE(...) LOG_LEVEL("ERROR", __VA_ARGS__)
-#define LOGW(...) LOG_LEVEL("WARN ", __VA_ARGS__)
-#define LOGI(...) LOG_LEVEL("INFO ", __VA_ARGS__)
-#define LOGD(...) LOG_LEVEL("DEBUG", __VA_ARGS__)
-#define LOGT(...) LOG_LEVEL("TRACE", __VA_ARGS__)
+#define LOGE(MESSAGE) LOG(ERROR, MESSAGE)
+#define LOGW(MESSAGE) LOG(WARN, MESSAGE)
+#define LOGI(MESSAGE) LOG(INFO, MESSAGE)
+#define LOGD(MESSAGE) LOG(DEBUG, MESSAGE)
+#define LOGT(MESSAGE) LOG(TRACE, MESSAGE)
#endif // LOG_HPP
--- /dev/null
+/*
+ * Copyright (c) 2000 - 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Contact: Bumjin Im <bj.im@samsung.com>
+ *
+ * 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 log-backend-stderr.cpp
+ * @author Pawel Broda (p.broda@partner.samsung.com)
+ * @brief Stderr backend for logger
+ */
+
+
+#include "log-backend-stderr.hpp"
+
+#include <stdio.h>
+
+namespace security_containers {
+namespace log {
+
+void StderrBackend::log(const std::string& message)
+{
+ fprintf(stderr, "%s", message.c_str());
+}
+
+} // namespace log
+} // namespace security_containers
--- /dev/null
+/*
+ * Copyright (c) 2000 - 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Contact: Bumjin Im <bj.im@samsung.com>
+ *
+ * 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 log.cpp
+ * @author Pawel Broda (p.broda@partner.samsung.com)
+ * @brief Logger
+ */
+
+#include "log.hpp"
+#include "log-backend-null.hpp"
+
+#include <iomanip>
+#include <memory>
+#include <mutex>
+
+namespace security_containers {
+namespace log {
+
+namespace {
+
+volatile LogLevel gLogLevel = LogLevel::DEBUG;
+std::unique_ptr<LogBackend> gLogBackendPtr(new NullLogger());
+std::mutex gLogMutex;
+
+} // namespace
+
+Logger::Logger(const std::string& severity, const std::string& file, const int line)
+{
+ mLogLine << std::left << std::setw(8) << '[' + severity + ']'
+ << file << ':'
+ << line << ' ';
+}
+
+void Logger::logMessage(const std::string& message)
+{
+ mLogLine << message << std::endl;
+ std::unique_lock<std::mutex> lock(gLogMutex);
+ gLogBackendPtr->log(mLogLine.str());
+}
+
+void Logger::setLogLevel(LogLevel level)
+{
+ gLogLevel = level;
+}
+
+LogLevel Logger::getLogLevel(void)
+{
+ return gLogLevel;
+}
+
+void Logger::setLogBackend(LogBackend* pBackend)
+{
+ std::unique_lock<std::mutex> lock(gLogMutex);
+ gLogBackendPtr.reset(pBackend);
+}
+
+} // namespace log
+} // namespace security_containers
* @brief Main file for the Security Containers Daemon
*/
+#include "log.hpp"
+#include "log-backend-stderr.hpp"
#include "utils-glib-loop.hpp"
#include "utils-latch.hpp"
-#include "log.hpp"
+
+#include <boost/algorithm/string.hpp>
#include <boost/program_options.hpp>
#include <iostream>
#include <signal.h>
-namespace security_containers {
+namespace po = boost::program_options;
+
+namespace security_containers {
namespace {
utils::Latch signalLatch;
}
} // namespace
-
} // namespace security_containers
namespace {
const std::string PROGRAM_NAME_AND_VERSION =
"Security Containers Server " PROGRAM_VERSION;
-} // namespace
+using namespace security_containers::log;
-namespace po = boost::program_options;
+/**
+ * Resolve if given log severity level is valid
+ *
+ * @param s log severity level
+ * @return LogLevel when valid,
+ * otherwise exception po::validation_error::invalid_option_value thrown
+ */
+LogLevel validateLogLevel(const std::string& s)
+{
+ std::string s_capitalized = boost::to_upper_copy(s);
+
+ if (s_capitalized == "ERROR") {
+ return LogLevel::ERROR;
+ } else if (s_capitalized == "WARN") {
+ return LogLevel::WARN;
+ } else if (s_capitalized == "INFO") {
+ return LogLevel::INFO;
+ } else if (s_capitalized == "DEBUG") {
+ return LogLevel::DEBUG;
+ } else if (s_capitalized == "TRACE") {
+ return LogLevel::TRACE;
+ } else {
+ throw po::validation_error(po::validation_error::invalid_option_value);
+ }
+}
+
+} // namespace
int main(int argc, char* argv[])
{
- po::options_description desc("Allowed options");
+ try {
+ po::options_description desc("Allowed options");
- desc.add_options()
- ("help,h", "print this help")
- ("version,v", "show application version")
- ;
+ desc.add_options()
+ ("help,h", "print this help")
+ ("version,v", "show application version")
+ ("log-level", po::value<std::string>()->default_value("DEBUG"), "set log level")
+ ;
- po::variables_map vm;
- po::basic_parsed_options< char > parsed =
- po::command_line_parser(argc, argv).options(desc).allow_unregistered().run();
+ po::variables_map vm;
+ po::basic_parsed_options< char > parsed =
+ po::command_line_parser(argc, argv).options(desc).allow_unregistered().run();
- std::vector<std::string> unrecognized_options =
- po::collect_unrecognized(parsed.options, po::include_positional);
+ std::vector<std::string> unrecognized_options =
+ po::collect_unrecognized(parsed.options, po::include_positional);
- if (!unrecognized_options.empty()) {
- std::cout << "Unrecognized options: ";
+ if (!unrecognized_options.empty()) {
+ std::cerr << "Unrecognized options: ";
- for (auto& uo : unrecognized_options) {
- std::cout << ' ' << uo;
- }
+ for (auto& uo : unrecognized_options) {
+ std::cerr << ' ' << uo;
+ }
- std::cout << std::endl << std::endl;
- std::cout << desc << std::endl;
+ std::cerr << std::endl << std::endl;
+ std::cerr << desc << std::endl;
- return 1;
- }
+ return 1;
+ }
+
+ po::store(parsed, vm);
+ po::notify(vm);
- po::store(parsed, vm);
- po::notify(vm);
+ if (vm.count("help")) {
+ std::cout << desc << std::endl;
+ return 0;
+ } else if (vm.count("version")) {
+ std::cout << PROGRAM_NAME_AND_VERSION << std::endl;
+ return 0;
+ }
- if (vm.count("help")) {
- std::cout << desc << std::endl;
- return 0;
- } else if (vm.count("version")) {
- std::cout << PROGRAM_NAME_AND_VERSION << std::endl;
- return 0;
+ if (vm.count("log-level")) {
+ using namespace security_containers::log;
+ LogLevel level = validateLogLevel(vm["log-level"].as<std::string>());
+ Logger::setLogLevel(level);
+ Logger::setLogBackend(new StderrBackend());
+ }
+ } catch (std::exception& e) {
+ std::cerr << e.what() << std::endl;
+ return 1;
}
security_containers::runDaemon();
return 0;
}
-
MESSAGE(STATUS "Generating makefile for the Server unit tests...")
FILE(GLOB_RECURSE project_SRCS *.cpp)
-FILE(GLOB src_SRCS ${SERVER_FOLDER}/src/scs-container-admin.cpp
+FILE(GLOB src_SRCS ${SERVER_FOLDER}/src/dbus-connection.cpp
+ ${SERVER_FOLDER}/src/log.cpp
+ ${SERVER_FOLDER}/src/log-backend.cpp
+ ${SERVER_FOLDER}/src/log-backend-stderr.cpp
+ ${SERVER_FOLDER}/src/scs-container-admin.cpp
${SERVER_FOLDER}/src/scs-container.cpp
${SERVER_FOLDER}/src/scs-container-manager.cpp
${SERVER_FOLDER}/src/scs-configuration.cpp
- ${SERVER_FOLDER}/src/dbus-connection.cpp
${SERVER_FOLDER}/src/utils-glib-loop.cpp
${SERVER_FOLDER}/src/utils-file-wait.cpp
${SERVER_FOLDER}/src/utils-latch.cpp)
+
## Setup target ################################################################
SET(UT_SERVER_CODENAME "${PROJECT_NAME}-server-unit-tests")
ADD_EXECUTABLE(${UT_SERVER_CODENAME} ${project_SRCS} ${src_SRCS})
/**
* @file ut-log.cpp
- * @author Lukasz Kostyra (l.kostyra@samsung.com)
- * @brief Unit tests for security-containers logging system
+ * @author Pawel Broda (p.broda@partner.samsung.com)
+ * @brief Unit tests of the log utility
*/
#include "ut.hpp"
#include "log.hpp"
+#include "log-backend.hpp"
+#include "log-backend-stderr.hpp"
+
BOOST_AUTO_TEST_SUITE(LogSuite)
-BOOST_AUTO_TEST_CASE(DumpAllLogTypes)
+using namespace security_containers::log;
+
+class StubbedBackend : public LogBackend {
+public:
+ StubbedBackend(std::ostringstream& s) : mLogStream(s) {}
+
+ // stubbed function
+ void log(const std::string& s) override
+ {
+ mLogStream << s;
+ }
+
+private:
+ std::ostringstream& mLogStream;
+};
+
+class TestLog {
+public:
+ TestLog(LogLevel level)
+ {
+ Logger::setLogLevel(level);
+ Logger::setLogBackend(new StubbedBackend(mLogStream));
+ }
+
+ ~TestLog()
+ {
+ Logger::setLogLevel(LogLevel::TRACE);
+ Logger::setLogBackend(new StderrBackend());
+ }
+
+ // helpers
+ bool logContains(const std::string& expression) const
+ {
+ std::string s = mLogStream.str();
+ if (s.find(expression) != std::string::npos) {
+ return true;
+ }
+ return false;
+ }
+private:
+ std::ostringstream mLogStream;
+};
+
+void exampleTestLogs(void)
+{
+ LOGE("test log error " << "1");
+ LOGW("test log warn " << "2");
+ LOGI("test log info " << "3");
+ LOGD("test log debug " << "4");
+ LOGT("test log trace " << "5");
+}
+
+BOOST_AUTO_TEST_CASE(LogLevelSetandGet)
+{
+ Logger::setLogLevel(LogLevel::TRACE);
+ BOOST_CHECK(LogLevel::TRACE == Logger::getLogLevel());
+
+ Logger::setLogLevel(LogLevel::DEBUG);
+ BOOST_CHECK(LogLevel::DEBUG == Logger::getLogLevel());
+
+ Logger::setLogLevel(LogLevel::INFO);
+ BOOST_CHECK(LogLevel::INFO == Logger::getLogLevel());
+
+ Logger::setLogLevel(LogLevel::WARN);
+ BOOST_CHECK(LogLevel::WARN == Logger::getLogLevel());
+
+ Logger::setLogLevel(LogLevel::ERROR);
+ BOOST_CHECK(LogLevel::ERROR == Logger::getLogLevel());
+}
+
+BOOST_AUTO_TEST_CASE(TestLogsError)
{
- LOGE("Logging an error message.");
- LOGW("Logging a warning.");
- LOGI("Logging some information.");
- LOGD("Logging debug information.");
- LOGT("Logging trace information.");
+ TestLog tf(LogLevel::ERROR);
+ exampleTestLogs();
+
+ BOOST_CHECK(tf.logContains("[ERROR]") == true);
+ BOOST_CHECK(tf.logContains("[WARN]") == false);
+ BOOST_CHECK(tf.logContains("[INFO]") == false);
+ BOOST_CHECK(tf.logContains("[DEBUG]") == false);
+ BOOST_CHECK(tf.logContains("[TRACE]") == false);
+}
+
+BOOST_AUTO_TEST_CASE(TestLogsWarn)
+{
+ TestLog tf(LogLevel::WARN);
+ exampleTestLogs();
+
+ BOOST_CHECK(tf.logContains("[ERROR]") == true);
+ BOOST_CHECK(tf.logContains("[WARN]") == true);
+ BOOST_CHECK(tf.logContains("[INFO]") == false);
+ BOOST_CHECK(tf.logContains("[DEBUG]") == false);
+ BOOST_CHECK(tf.logContains("[TRACE]") == false);
+}
+
+BOOST_AUTO_TEST_CASE(TestLogsInfo)
+{
+ TestLog tf(LogLevel::INFO);
+ exampleTestLogs();
+
+ BOOST_CHECK(tf.logContains("[ERROR]") == true);
+ BOOST_CHECK(tf.logContains("[WARN]") == true);
+ BOOST_CHECK(tf.logContains("[INFO]") == true);
+ BOOST_CHECK(tf.logContains("[DEBUG]") == false);
+ BOOST_CHECK(tf.logContains("[TRACE]") == false);
}
+BOOST_AUTO_TEST_CASE(TestLogsDebug)
+{
+ TestLog tf(LogLevel::DEBUG);
+ exampleTestLogs();
+
+ BOOST_CHECK(tf.logContains("[ERROR]") == true);
+ BOOST_CHECK(tf.logContains("[WARN]") == true);
+ BOOST_CHECK(tf.logContains("[INFO]") == true);
+ BOOST_CHECK(tf.logContains("[DEBUG]") == true);
+ BOOST_CHECK(tf.logContains("[TRACE]") == false);
+}
+
+BOOST_AUTO_TEST_CASE(TestLogsTrace)
+{
+ TestLog tf(LogLevel::TRACE);
+ exampleTestLogs();
+
+ BOOST_CHECK(tf.logContains("[ERROR]") == true);
+ BOOST_CHECK(tf.logContains("[WARN]") == true);
+ BOOST_CHECK(tf.logContains("[INFO]") == true);
+ BOOST_CHECK(tf.logContains("[DEBUG]") == true);
+ BOOST_CHECK(tf.logContains("[TRACE]") == true);
+}
+
+
BOOST_AUTO_TEST_SUITE_END()
* @brief Main file for the Security Containers Daemon unit tests
*/
+#include "log.hpp"
+#include "log-backend-stderr.hpp"
-#define BOOST_TEST_MODULE Main
-#include "ut.hpp"
+#include <boost/test/included/unit_test.hpp>
+#include <boost/test/unit_test.hpp> // for unit_test framework
+
+
+using namespace boost::unit_test;
+using namespace security_containers::log;
+
+test_suite* init_unit_test_suite(int /*argc*/, char** /*argv*/)
+{
+ Logger::setLogLevel(LogLevel::TRACE);
+ Logger::setLogBackend(new StderrBackend());
+
+ return NULL;
+}