Capture the libvirt logs and output them using our log system
authorLukasz Pawelczyk <l.pawelczyk@partner.samsung.com>
Tue, 8 Apr 2014 15:12:42 +0000 (17:12 +0200)
committerJan Olszak <j.olszak@samsung.com>
Mon, 19 May 2014 11:47:15 +0000 (13:47 +0200)
[Bug/Feature]   Capture the libvirt logs and output them using our log system
[Cause]         Libvirt logs were sent to stdout effectively limiting our
                internal logging system to capture and store them.
[Solution]      Turn off libvirt stdout error reporting (warnings left for now)
                and capture messages using libvirt's getLastError().
[Verification]  Build, install, run tests on host.

Change-Id: I7bff428ea605697f5d63842ee7175492fb62f579
Signed-off-by: Lukasz Pawelczyk <l.pawelczyk@partner.samsung.com>
common/libvirt/connection.cpp
common/libvirt/domain.cpp
common/libvirt/helpers.cpp [new file with mode: 0644]
common/libvirt/helpers.hpp [new file with mode: 0644]
server/container-admin.cpp
server/container-admin.hpp

index 3c2a3b6..01b1a7b 100644 (file)
@@ -23,6 +23,7 @@
  */
 
 #include "log/logger.hpp"
+#include "libvirt/helpers.hpp"
 #include "libvirt/connection.hpp"
 #include "libvirt/exception.hpp"
 
@@ -33,10 +34,13 @@ namespace libvirt {
 
 LibvirtConnection::LibvirtConnection(const std::string& uri)
 {
+    libvirtInitialize();
+
     mCon = virConnectOpen(uri.c_str());
 
     if (mCon == NULL) {
-        LOGE("Failed to open connection to libvirtd");
+        LOGE("Failed to open a connection to the libvirtd:\n"
+             << libvirtFormatError());
         throw LibvirtOperationException();
     }
 }
@@ -44,7 +48,8 @@ LibvirtConnection::LibvirtConnection(const std::string& uri)
 LibvirtConnection::~LibvirtConnection()
 {
     if (virConnectClose(mCon) < 0) {
-        LOGE("Error while disconnecting from libvirt");
+        LOGE("Error while disconnecting from the libvirtd:\n"
+             << libvirtFormatError());
     };
 }
 
index 5c41a51..ec29d7b 100644 (file)
@@ -24,6 +24,7 @@
 
 #include "log/logger.hpp"
 #include "libvirt/domain.hpp"
+#include "libvirt/helpers.hpp"
 #include "libvirt/exception.hpp"
 
 #include <cassert>
@@ -39,7 +40,8 @@ LibvirtDomain::LibvirtDomain(const std::string& configXML)
     mDom = virDomainDefineXML(mCon.get(), configXML.c_str());
 
     if (mDom == NULL) {
-        LOGE("Error during domain defining");
+        LOGE("Error while defining a domain:\n"
+             << libvirtFormatError());
         throw LibvirtOperationException();
     }
 }
@@ -47,11 +49,13 @@ LibvirtDomain::LibvirtDomain(const std::string& configXML)
 LibvirtDomain::~LibvirtDomain()
 {
     if (virDomainUndefine(mDom) < 0) {
-        LOGE("Error during domain undefine");
+        LOGE("Error while undefining the domain:\n"
+             << libvirtFormatError());
     }
 
     if (virDomainFree(mDom) < 0) {
-        LOGE("Error during domain destruction");
+        LOGE("Error while destroying the domain object:\n"
+             << libvirtFormatError());
     }
 }
 
diff --git a/common/libvirt/helpers.cpp b/common/libvirt/helpers.cpp
new file mode 100644 (file)
index 0000000..58ee7b2
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ *  Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Contact: Lukasz Pawelczyk <l.pawelczyk@partner.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
+ * @author  Lukasz Pawelczyk (l.pawelczyk@partner.samsung.com)
+ * @brief   A function helpers for the libvirt library
+ */
+
+#include "log/logger.hpp"
+
+#include <mutex>
+#include <libvirt/virterror.h>
+
+
+namespace security_containers {
+namespace libvirt {
+
+
+namespace {
+
+std::once_flag gInitFlag;
+
+/**
+ * This function intentionally is not displaying any errors,
+ * we log them ourselves elsewhere.
+ * It is however displaying warnings for the time being so we can
+ * learn whether such situations occur.
+ */
+void libvirtErrorFunction(void* /*userData*/, virErrorPtr error)
+{
+    if (error->level == VIR_ERR_WARNING) {
+        LOGW("LIBVIRT reported a warning: \n" << error->message);
+    }
+}
+
+} // namespace
+
+void libvirtInitialize(void)
+{
+    std::call_once(gInitFlag, []() {
+            virInitialize();
+            virSetErrorFunc(NULL, &libvirtErrorFunction);
+        });
+}
+
+std::string libvirtFormatError(const std::string& domainName = std::string())
+{
+    std::string ret;
+
+    virErrorPtr error = virGetLastError();
+
+    if (error == NULL) {
+        return ret;
+    }
+
+    if (!domainName.empty()) {
+        ret += "LIBVIRT Domain: " + domainName + "\n";
+    }
+
+    if (error->message) {
+        ret += "LIBVIRT Message: " + std::string(error->message);
+    }
+
+    return ret;
+}
+
+
+} // namespace libvirt
+} // namespace security_containers
diff --git a/common/libvirt/helpers.hpp b/common/libvirt/helpers.hpp
new file mode 100644 (file)
index 0000000..fb9e899
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ *  Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Contact: Lukasz Pawelczyk <l.pawelczyk@partner.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
+ * @author  Lukasz Pawelczyk (l.pawelczyk@partner.samsung.com)
+ * @brief   A function helpers for the libvirt library
+ */
+
+#ifndef COMMON_LIBVIRT_HELPERS_HPP
+#define COMMON_LIBVIRT_HELPERS_HPP
+
+#include <string>
+
+
+namespace security_containers {
+namespace libvirt {
+
+
+/**
+ * Initialize libvirt library in a thread safety manner
+ */
+void libvirtInitialize(void);
+
+/**
+ * Formats libvirt's last error. Might include
+ * the affected domain's name if it exists.
+ */
+std::string libvirtFormatError(const std::string& domainName = std::string());
+
+
+} // namespace libvirt
+} // namespace security_containers
+
+
+#endif // COMMON_LIBVIRT_HELPERS_HPP
index f51fa8f..3f4a6ca 100644 (file)
@@ -25,6 +25,7 @@
 #include "container-admin.hpp"
 #include "exception.hpp"
 
+#include "libvirt/helpers.hpp"
 #include "log/logger.hpp"
 #include "utils/fs.hpp"
 
 namespace security_containers {
 
 
+namespace {
+
+std::string getDomainName(virDomainPtr dom)
+{
+    assert(dom != NULL);
+
+    const char* name;
+    if ((name = virDomainGetName(dom)) == NULL) {
+        LOGE("Failed to get the domain's id:\n"
+             << libvirt::libvirtFormatError());
+        throw DomainOperationException();
+    }
+
+    return name;
+}
+
+} // namespace
+
 const std::uint64_t DEFAULT_CPU_SHARES = 1024;
 const std::uint64_t DEFAULT_VCPU_PERIOD_MS = 100000;
 
 ContainerAdmin::ContainerAdmin(ContainerConfig& config)
-    : mConfig(config), mDom(utils::readFileContent(mConfig.config))
+    : mConfig(config), mDom(utils::readFileContent(mConfig.config)), mId(getDomainName(mDom.get()))
 {
 }
 
@@ -63,17 +82,9 @@ ContainerAdmin::~ContainerAdmin()
 }
 
 
-std::string ContainerAdmin::getId()
+const std::string& ContainerAdmin::getId() const
 {
-    assert(mDom.get() != NULL);
-
-    const char* id;
-    if ((id = virDomainGetName(mDom.get())) == NULL) {
-        LOGE("Failed to get container's id");
-        throw DomainOperationException();
-    }
-
-    return id;
+    return mId;
 }
 
 
@@ -91,7 +102,8 @@ void ContainerAdmin::start()
     u_int flags = VIR_DOMAIN_START_AUTODESTROY;
 
     if (virDomainCreateWithFlags(mDom.get(), flags) < 0) {
-        LOGE("Failed to start the container");
+        LOGE("Failed to start the domain:\n"
+             << libvirt::libvirtFormatError(mId));
         throw DomainOperationException();
     }
 
@@ -114,7 +126,8 @@ void ContainerAdmin::stop()
     u_int flags = VIR_DOMAIN_DESTROY_DEFAULT;
 
     if (virDomainDestroyFlags(mDom.get(), flags) < 0) {
-        LOGE("Error during domain stopping");
+        LOGE("Error while stopping the domain:\n"
+             << libvirt::libvirtFormatError(mId));
         throw DomainOperationException();
     }
 }
@@ -131,7 +144,8 @@ void ContainerAdmin::shutdown()
     resume();
 
     if (virDomainShutdown(mDom.get()) < 0) {
-        LOGE("Error during domain shutdown");
+        LOGE("Error while shutting down the domain:\n"
+             << libvirt::libvirtFormatError(mId));
         throw DomainOperationException();
     }
 }
@@ -161,7 +175,8 @@ void ContainerAdmin::suspend()
     }
 
     if (virDomainSuspend(mDom.get()) < 0) {
-        LOGE("Error during domain suspension");
+        LOGE("Error while suspending the domain:\n"
+             << libvirt::libvirtFormatError(mId));
         throw DomainOperationException();
     }
 }
@@ -176,7 +191,8 @@ void ContainerAdmin::resume()
     }
 
     if (virDomainResume(mDom.get()) < 0) {
-        LOGE("Error during domain resumming");
+        LOGE("Error while resumming the domain:\n"
+             << libvirt::libvirtFormatError(mId));
         throw DomainOperationException();
     }
 }
@@ -195,7 +211,8 @@ int ContainerAdmin::getState()
     int state;
 
     if (virDomainGetState(mDom.get(), &state, NULL, 0)) {
-        LOGE("Error during getting domain's state");
+        LOGE("Error whilte getting the domain's state:\n"
+             << libvirt::libvirtFormatError(mId));
         throw DomainOperationException();
     }
 
@@ -238,7 +255,8 @@ void ContainerAdmin::setSchedulerParams(std::uint64_t cpuShares, std::uint64_t v
     virTypedParamsAddLLong(&paramsTmp, &numParamsBuff, &maxParams, VIR_DOMAIN_SCHEDULER_VCPU_QUOTA, vcpuQuota);
 
     if (virDomainSetSchedulerParameters(mDom.get(), params.get(), numParamsBuff) < 0) {
-        LOGE("Error whilte setting scheduler params");
+        LOGE("Error whilte setting the domain's scheduler params:\n"
+             << libvirt::libvirtFormatError(mId));
         throw DomainOperationException();
     }
 }
@@ -252,14 +270,16 @@ std::int64_t ContainerAdmin::getSchedulerQuota()
     std::unique_ptr<char, void(*)(void*)> type(virDomainGetSchedulerType(mDom.get(), &numParamsBuff), free);
 
     if (type == NULL || numParamsBuff <= 0 || strcmp(type.get(), "posix") != 0) {
-        LOGE("Error while getting scheduler type");
+        LOGE("Error while getting the domain's scheduler type:\n"
+             << libvirt::libvirtFormatError(mId));
         throw DomainOperationException();
     }
 
     std::unique_ptr<virTypedParameter[]> params(new virTypedParameter[numParamsBuff]);
 
     if (virDomainGetSchedulerParameters(mDom.get(), params.get(), &numParamsBuff) < 0) {
-        LOGE("Error whilte getting scheduler parameters");
+        LOGE("Error while getting the domain's scheduler params:\n"
+             << libvirt::libvirtFormatError(mId));
         throw DomainOperationException();
     }
 
@@ -268,7 +288,8 @@ std::int64_t ContainerAdmin::getSchedulerQuota()
                                numParamsBuff,
                                VIR_DOMAIN_SCHEDULER_VCPU_QUOTA,
                                &quota) <= 0) {
-        LOGE("Error whilte getting scheduler quota parameter");
+        LOGE("Error while getting the domain's scheduler quota param:\n"
+             << libvirt::libvirtFormatError(mId));
         throw DomainOperationException();
     }
 
index dc4a9d0..7738ba1 100644 (file)
@@ -53,7 +53,7 @@ public:
     /**
      * Get the container id
      */
-    std::string getId();
+    const std::string& getId() const;
 
     /**
      * Boot the container to the background.
@@ -118,6 +118,7 @@ public:
 private:
     ContainerConfig& mConfig;
     libvirt::LibvirtDomain mDom;
+    const std::string mId;
 
     int getState();   // get the libvirt's domain state
     void setSchedulerParams(std::uint64_t cpuShares, std::uint64_t vcpuPeriod, std::int64_t vcpuQuota);