blob: d23b58909ce122fccc5294b2eacdff906c570b78 [file] [log] [blame]
Krzysztof Grobelny64b75a52020-09-18 10:17:16 +02001#include "report_manager.hpp"
2
Wludzik, Jozefe2362792020-10-27 17:23:55 +01003#include "report.hpp"
4
5#include <phosphor-logging/log.hpp>
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +02006#include <sdbusplus/exception.hpp>
7
Wludzik, Jozefe2362792020-10-27 17:23:55 +01008#include <stdexcept>
Krzysztof Grobelny64b75a52020-09-18 10:17:16 +02009#include <system_error>
10
Krzysztof Grobelny64b75a52020-09-18 10:17:16 +020011ReportManager::ReportManager(
Wludzik, Jozef2f9f9b82020-10-13 09:07:45 +020012 std::unique_ptr<interfaces::ReportFactory> reportFactoryIn,
Wludzik, Jozefe2362792020-10-27 17:23:55 +010013 std::unique_ptr<interfaces::JsonStorage> reportStorageIn,
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +020014 const std::shared_ptr<sdbusplus::asio::object_server>& objServerIn) :
Wludzik, Jozef2f9f9b82020-10-13 09:07:45 +020015 reportFactory(std::move(reportFactoryIn)),
Wludzik, Jozefe2362792020-10-27 17:23:55 +010016 reportStorage(std::move(reportStorageIn)), objServer(objServerIn)
Krzysztof Grobelny64b75a52020-09-18 10:17:16 +020017{
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +020018 reports.reserve(maxReports);
Wludzik, Jozefe2362792020-10-27 17:23:55 +010019 loadFromPersistent();
Krzysztof Grobelny64b75a52020-09-18 10:17:16 +020020
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +020021 reportManagerIface = objServer->add_unique_interface(
Wludzik, Jozef2f9f9b82020-10-13 09:07:45 +020022 reportManagerPath, reportManagerIfaceName, [this](auto& dbusIface) {
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +020023 dbusIface.register_property_r(
24 "MaxReports", uint32_t{}, sdbusplus::vtable::property_::const_,
25 [](const auto&) { return maxReports; });
26 dbusIface.register_property_r(
27 "MinInterval", uint64_t{}, sdbusplus::vtable::property_::const_,
28 [](const auto&) -> uint64_t { return minInterval.count(); });
Krzysztof Grobelny64b75a52020-09-18 10:17:16 +020029
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +020030 dbusIface.register_method(
Wludzik, Jozefe2362792020-10-27 17:23:55 +010031 "AddReport", [this](boost::asio::yield_context& yield,
32 const std::string& reportName,
Wludzik, Jozef2f9f9b82020-10-13 09:07:45 +020033 const std::string& reportingType,
34 const bool emitsReadingsUpdate,
35 const bool logToMetricReportsCollection,
36 const uint64_t interval,
37 const ReadingParameters& metricParams) {
Wludzik, Jozefe2362792020-10-27 17:23:55 +010038 return addReport(yield, reportName, reportingType,
39 emitsReadingsUpdate,
40 logToMetricReportsCollection,
41 std::chrono::milliseconds(interval),
42 metricParams)
43 ->getPath();
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +020044 });
45 });
Krzysztof Grobelny64b75a52020-09-18 10:17:16 +020046}
47
Wludzik, Jozef2f9f9b82020-10-13 09:07:45 +020048void ReportManager::removeReport(const interfaces::Report* report)
Krzysztof Grobelny64b75a52020-09-18 10:17:16 +020049{
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +020050 reports.erase(
51 std::remove_if(reports.begin(), reports.end(),
52 [report](const auto& x) { return report == x.get(); }),
53 reports.end());
Krzysztof Grobelny64b75a52020-09-18 10:17:16 +020054}
Wludzik, Jozefe2362792020-10-27 17:23:55 +010055
56std::unique_ptr<interfaces::Report>& ReportManager::addReport(
57 std::optional<std::reference_wrapper<boost::asio::yield_context>> yield,
58 const std::string& reportName, const std::string& reportingType,
59 const bool emitsReadingsUpdate, const bool logToMetricReportsCollection,
60 std::chrono::milliseconds interval, const ReadingParameters& metricParams)
61{
62 if (reports.size() >= maxReports)
63 {
64 throw sdbusplus::exception::SdBusError(
65 static_cast<int>(std::errc::too_many_files_open),
66 "Reached maximal report count");
67 }
68
69 for (const auto& report : reports)
70 {
71 if (report->getName() == reportName)
72 {
73 throw sdbusplus::exception::SdBusError(
74 static_cast<int>(std::errc::file_exists), "Duplicate report");
75 }
76 }
77
78 if (interval < minInterval)
79 {
80 throw sdbusplus::exception::SdBusError(
81 static_cast<int>(std::errc::invalid_argument), "Invalid interval");
82 }
83
84 reports.emplace_back(
85 reportFactory->make(yield, reportName, reportingType,
86 emitsReadingsUpdate, logToMetricReportsCollection,
87 interval, metricParams, *this, *reportStorage));
88 return reports.back();
89}
90
91void ReportManager::loadFromPersistent()
92{
93 std::vector<interfaces::JsonStorage::FilePath> paths =
94 reportStorage->list();
95
96 for (const auto& path : paths)
97 {
98 std::optional<nlohmann::json> data = reportStorage->load(path);
99 try
100 {
101 size_t version = data->at("Version").get<size_t>();
102 if (version != Report::reportVersion)
103 {
104 throw std::logic_error("Invalid version");
105 }
106 std::string& name = data->at("Name").get_ref<std::string&>();
107 std::string& reportingType =
108 data->at("ReportingType").get_ref<std::string&>();
109 bool emitsReadingsSignal =
110 data->at("EmitsReadingsUpdate").get<bool>();
111 bool logToMetricReportsCollection =
112 data->at("LogToMetricReportsCollection").get<bool>();
113 uint64_t interval = data->at("Interval").get<uint64_t>();
114 ReadingParameters readingParameters;
115 for (auto& item : data->at("ReadingParameters"))
116 {
117 readingParameters.emplace_back(
118 LabeledReadingParameter::from_json(item));
119 }
120
121 addReport(std::nullopt, name, reportingType, emitsReadingsSignal,
122 logToMetricReportsCollection,
123 std::chrono::milliseconds(interval), readingParameters);
124 }
125 catch (const std::exception& e)
126 {
127 phosphor::logging::log<phosphor::logging::level::ERR>(
128 "Failed to load report from storage",
129 phosphor::logging::entry(
130 "filename=",
131 static_cast<std::filesystem::path>(path).c_str()),
132 phosphor::logging::entry("msg=", e.what()));
133 reportStorage->remove(path);
134 }
135 }
136}