Implement Report persistency
Now Report properties are stored in non-volatile memory. It allows
to restore Report after system restart. Persistency of a report is
controlled by Persistency property in Report interface.
Tested:
- Passed unit tests
- Verified that report is stored in /var/lib/telemetry dir
- Verified that report is restored from storage after telemetry
service start
Signed-off-by: Wludzik, Jozef <jozef.wludzik@intel.com>
Change-Id: Iccfe21603eecffc4e174a4403f699b03de320db9
diff --git a/src/report_manager.cpp b/src/report_manager.cpp
index 5944fa9..d23b589 100644
--- a/src/report_manager.cpp
+++ b/src/report_manager.cpp
@@ -1,16 +1,22 @@
#include "report_manager.hpp"
+#include "report.hpp"
+
+#include <phosphor-logging/log.hpp>
#include <sdbusplus/exception.hpp>
+#include <stdexcept>
#include <system_error>
ReportManager::ReportManager(
std::unique_ptr<interfaces::ReportFactory> reportFactoryIn,
+ std::unique_ptr<interfaces::JsonStorage> reportStorageIn,
const std::shared_ptr<sdbusplus::asio::object_server>& objServerIn) :
reportFactory(std::move(reportFactoryIn)),
- objServer(objServerIn)
+ reportStorage(std::move(reportStorageIn)), objServer(objServerIn)
{
reports.reserve(maxReports);
+ loadFromPersistent();
reportManagerIface = objServer->add_unique_interface(
reportManagerPath, reportManagerIfaceName, [this](auto& dbusIface) {
@@ -22,42 +28,19 @@
[](const auto&) -> uint64_t { return minInterval.count(); });
dbusIface.register_method(
- "AddReport", [this](const std::string& reportName,
+ "AddReport", [this](boost::asio::yield_context& yield,
+ const std::string& reportName,
const std::string& reportingType,
const bool emitsReadingsUpdate,
const bool logToMetricReportsCollection,
const uint64_t interval,
const ReadingParameters& metricParams) {
- if (reports.size() >= maxReports)
- {
- throw sdbusplus::exception::SdBusError(
- static_cast<int>(std::errc::too_many_files_open),
- "Reached maximal report count");
- }
-
- for (const auto& report : reports)
- {
- if (report->getName() == reportName)
- {
- throw sdbusplus::exception::SdBusError(
- static_cast<int>(std::errc::file_exists),
- "Duplicate report");
- }
- }
-
- std::chrono::milliseconds reportInterval{interval};
- if (reportInterval < minInterval)
- {
- throw sdbusplus::exception::SdBusError(
- static_cast<int>(std::errc::invalid_argument),
- "Invalid interval");
- }
-
- reports.emplace_back(reportFactory->make(
- reportName, reportingType, emitsReadingsUpdate,
- logToMetricReportsCollection, std::move(reportInterval),
- metricParams, *this));
- return reports.back()->getPath();
+ return addReport(yield, reportName, reportingType,
+ emitsReadingsUpdate,
+ logToMetricReportsCollection,
+ std::chrono::milliseconds(interval),
+ metricParams)
+ ->getPath();
});
});
}
@@ -69,3 +52,85 @@
[report](const auto& x) { return report == x.get(); }),
reports.end());
}
+
+std::unique_ptr<interfaces::Report>& ReportManager::addReport(
+ std::optional<std::reference_wrapper<boost::asio::yield_context>> yield,
+ const std::string& reportName, const std::string& reportingType,
+ const bool emitsReadingsUpdate, const bool logToMetricReportsCollection,
+ std::chrono::milliseconds interval, const ReadingParameters& metricParams)
+{
+ if (reports.size() >= maxReports)
+ {
+ throw sdbusplus::exception::SdBusError(
+ static_cast<int>(std::errc::too_many_files_open),
+ "Reached maximal report count");
+ }
+
+ for (const auto& report : reports)
+ {
+ if (report->getName() == reportName)
+ {
+ throw sdbusplus::exception::SdBusError(
+ static_cast<int>(std::errc::file_exists), "Duplicate report");
+ }
+ }
+
+ if (interval < minInterval)
+ {
+ throw sdbusplus::exception::SdBusError(
+ static_cast<int>(std::errc::invalid_argument), "Invalid interval");
+ }
+
+ reports.emplace_back(
+ reportFactory->make(yield, reportName, reportingType,
+ emitsReadingsUpdate, logToMetricReportsCollection,
+ interval, metricParams, *this, *reportStorage));
+ return reports.back();
+}
+
+void ReportManager::loadFromPersistent()
+{
+ std::vector<interfaces::JsonStorage::FilePath> paths =
+ reportStorage->list();
+
+ for (const auto& path : paths)
+ {
+ std::optional<nlohmann::json> data = reportStorage->load(path);
+ try
+ {
+ size_t version = data->at("Version").get<size_t>();
+ if (version != Report::reportVersion)
+ {
+ throw std::logic_error("Invalid version");
+ }
+ std::string& name = data->at("Name").get_ref<std::string&>();
+ std::string& reportingType =
+ data->at("ReportingType").get_ref<std::string&>();
+ bool emitsReadingsSignal =
+ data->at("EmitsReadingsUpdate").get<bool>();
+ bool logToMetricReportsCollection =
+ data->at("LogToMetricReportsCollection").get<bool>();
+ uint64_t interval = data->at("Interval").get<uint64_t>();
+ ReadingParameters readingParameters;
+ for (auto& item : data->at("ReadingParameters"))
+ {
+ readingParameters.emplace_back(
+ LabeledReadingParameter::from_json(item));
+ }
+
+ addReport(std::nullopt, name, reportingType, emitsReadingsSignal,
+ logToMetricReportsCollection,
+ std::chrono::milliseconds(interval), readingParameters);
+ }
+ catch (const std::exception& e)
+ {
+ phosphor::logging::log<phosphor::logging::level::ERR>(
+ "Failed to load report from storage",
+ phosphor::logging::entry(
+ "filename=",
+ static_cast<std::filesystem::path>(path).c_str()),
+ phosphor::logging::entry("msg=", e.what()));
+ reportStorage->remove(path);
+ }
+ }
+}