blob: 21a9736176667262f716ae42b9618165ca5df50c [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"
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +00004#include "types/report_types.hpp"
Krzysztof Grobelnye8fc5752021-02-05 14:30:45 +00005#include "utils/conversion.hpp"
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +00006#include "utils/transform.hpp"
Wludzik, Jozefe2362792020-10-27 17:23:55 +01007
8#include <phosphor-logging/log.hpp>
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +02009#include <sdbusplus/exception.hpp>
10
Wludzik, Jozefe2362792020-10-27 17:23:55 +010011#include <stdexcept>
Krzysztof Grobelny64b75a52020-09-18 10:17:16 +020012#include <system_error>
13
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +000014ReadingParameters
15 convertToReadingParameters(ReadingParametersPastVersion params)
16{
17 return utils::transform(params, [](const auto& param) {
18 using namespace std::chrono_literals;
19
20 return ReadingParameters::value_type(
21 std::vector{{std::get<0>(param)}}, std::get<1>(param),
22 std::get<2>(param), std::get<3>(param),
23 utils::enumToString(CollectionTimeScope::point), 0u);
24 });
25}
26
Krzysztof Grobelny64b75a52020-09-18 10:17:16 +020027ReportManager::ReportManager(
Wludzik, Jozef2f9f9b82020-10-13 09:07:45 +020028 std::unique_ptr<interfaces::ReportFactory> reportFactoryIn,
Wludzik, Jozefe2362792020-10-27 17:23:55 +010029 std::unique_ptr<interfaces::JsonStorage> reportStorageIn,
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +020030 const std::shared_ptr<sdbusplus::asio::object_server>& objServerIn) :
Wludzik, Jozef2f9f9b82020-10-13 09:07:45 +020031 reportFactory(std::move(reportFactoryIn)),
Wludzik, Jozefe2362792020-10-27 17:23:55 +010032 reportStorage(std::move(reportStorageIn)), objServer(objServerIn)
Krzysztof Grobelny64b75a52020-09-18 10:17:16 +020033{
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +020034 reports.reserve(maxReports);
Krzysztof Grobelny6ccfcbf2020-11-04 09:31:36 +010035
Wludzik, Jozefe2362792020-10-27 17:23:55 +010036 loadFromPersistent();
Krzysztof Grobelny64b75a52020-09-18 10:17:16 +020037
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +020038 reportManagerIface = objServer->add_unique_interface(
Wludzik, Jozef2f9f9b82020-10-13 09:07:45 +020039 reportManagerPath, reportManagerIfaceName, [this](auto& dbusIface) {
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +020040 dbusIface.register_property_r(
Wludzik, Jozef503c1582020-12-11 14:48:01 +010041 "MaxReports", size_t{}, sdbusplus::vtable::property_::const_,
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +020042 [](const auto&) { return maxReports; });
43 dbusIface.register_property_r(
Karol Niczyj32859b62021-05-19 10:20:46 +020044 "MaxReportNameLength", size_t{},
45 sdbusplus::vtable::property_::const_,
46 [](const auto&) { return maxReportNameLength; });
47 dbusIface.register_property_r(
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +020048 "MinInterval", uint64_t{}, sdbusplus::vtable::property_::const_,
49 [](const auto&) -> uint64_t { return minInterval.count(); });
Krzysztof Grobelny64b75a52020-09-18 10:17:16 +020050
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +020051 dbusIface.register_method(
Wludzik, Jozefe2362792020-10-27 17:23:55 +010052 "AddReport", [this](boost::asio::yield_context& yield,
53 const std::string& reportName,
Wludzik, Jozef2f9f9b82020-10-13 09:07:45 +020054 const std::string& reportingType,
55 const bool emitsReadingsUpdate,
56 const bool logToMetricReportsCollection,
57 const uint64_t interval,
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +000058 ReadingParametersPastVersion metricParams) {
Lukasz Kazmierczak7e098e92021-09-16 15:59:56 +020059 constexpr auto enabledDefault = true;
Szymon Dompke3eb56862021-09-20 15:32:04 +020060 constexpr uint64_t appendLimitDefault = 0;
61 constexpr ReportUpdates reportUpdatesDefault =
62 ReportUpdates::Overwrite;
63 return addReport(
64 yield, reportName, reportingType,
65 emitsReadingsUpdate,
66 logToMetricReportsCollection,
67 Milliseconds(interval), appendLimitDefault,
68 reportUpdatesToString(reportUpdatesDefault),
69 convertToReadingParameters(
70 std::move(metricParams)),
71 enabledDefault)
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +000072 .getPath();
73 });
74
75 dbusIface.register_method(
76 "AddReportFutureVersion",
Szymon Dompke3eb56862021-09-20 15:32:04 +020077
78 [this](
79 boost::asio::yield_context& yield,
80 const std::string& reportName,
81 const std::string& reportingType,
82 const std::string& reportUpdates,
83 const uint64_t appendLimit, const bool emitsReadingsUpdate,
84 const bool logToMetricReportsCollection,
85 const uint64_t interval, ReadingParameters metricParams) {
Lukasz Kazmierczak7e098e92021-09-16 15:59:56 +020086 constexpr auto enabledDefault = true;
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +000087 return addReport(yield, reportName, reportingType,
88 emitsReadingsUpdate,
89 logToMetricReportsCollection,
Szymon Dompke3eb56862021-09-20 15:32:04 +020090 Milliseconds(interval), appendLimit,
91 reportUpdates, std::move(metricParams),
92 enabledDefault)
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +000093 .getPath();
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +020094 });
95 });
Krzysztof Grobelny64b75a52020-09-18 10:17:16 +020096}
97
Wludzik, Jozef2f9f9b82020-10-13 09:07:45 +020098void ReportManager::removeReport(const interfaces::Report* report)
Krzysztof Grobelny64b75a52020-09-18 10:17:16 +020099{
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +0200100 reports.erase(
101 std::remove_if(reports.begin(), reports.end(),
102 [report](const auto& x) { return report == x.get(); }),
103 reports.end());
Krzysztof Grobelny64b75a52020-09-18 10:17:16 +0200104}
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100105
Karol Niczyj32859b62021-05-19 10:20:46 +0200106void ReportManager::verifyReportNameLength(const std::string& reportName)
107{
108 if (reportName.length() > maxReportNameLength)
109 {
110 throw sdbusplus::exception::SdBusError(
111 static_cast<int>(std::errc::invalid_argument),
Szymon Dompkee28aa532021-10-27 12:33:12 +0200112 "Report name exceeds maximum length");
Karol Niczyj32859b62021-05-19 10:20:46 +0200113 }
114}
115
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000116void ReportManager::verifyAddReport(
117 const std::string& reportName, const std::string& reportingType,
Szymon Dompke3eb56862021-09-20 15:32:04 +0200118 Milliseconds interval, const std::string& reportUpdates,
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000119 const std::vector<LabeledMetricParameters>& readingParams)
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100120{
121 if (reports.size() >= maxReports)
122 {
123 throw sdbusplus::exception::SdBusError(
124 static_cast<int>(std::errc::too_many_files_open),
125 "Reached maximal report count");
126 }
127
Karol Niczyj32859b62021-05-19 10:20:46 +0200128 verifyReportNameLength(reportName);
129
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100130 for (const auto& report : reports)
131 {
132 if (report->getName() == reportName)
133 {
134 throw sdbusplus::exception::SdBusError(
135 static_cast<int>(std::errc::file_exists), "Duplicate report");
136 }
137 }
138
Szymon Dompke3eb56862021-09-20 15:32:04 +0200139 if (std::find(supportedReportingType.begin(), supportedReportingType.end(),
140 reportingType) == supportedReportingType.end())
Wludzik, Jozefbc766b42020-12-08 16:06:22 +0100141 {
142 throw sdbusplus::exception::SdBusError(
143 static_cast<int>(std::errc::invalid_argument),
144 "Invalid reportingType");
145 }
146
Szymon Dompke3eb56862021-09-20 15:32:04 +0200147 verifyReportUpdates(reportUpdates);
148
Wludzik, Jozefbc766b42020-12-08 16:06:22 +0100149 if (reportingType == "Periodic" && interval < minInterval)
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100150 {
151 throw sdbusplus::exception::SdBusError(
152 static_cast<int>(std::errc::invalid_argument), "Invalid interval");
153 }
Wludzik, Jozefbc766b42020-12-08 16:06:22 +0100154
Wludzik, Jozef503c1582020-12-11 14:48:01 +0100155 if (readingParams.size() > maxReadingParams)
Krzysztof Grobelnye8fc5752021-02-05 14:30:45 +0000156
Wludzik, Jozefbc766b42020-12-08 16:06:22 +0100157 {
158 throw sdbusplus::exception::SdBusError(
159 static_cast<int>(std::errc::argument_list_too_long),
160 "Too many reading parameters");
161 }
Krzysztof Grobelnye8fc5752021-02-05 14:30:45 +0000162
163 try
164 {
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000165 namespace ts = utils::tstring;
166
167 for (const LabeledMetricParameters& item : readingParams)
Krzysztof Grobelnye8fc5752021-02-05 14:30:45 +0000168 {
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000169 utils::toOperationType(
170 utils::toUnderlying(item.at_label<ts::OperationType>()));
Krzysztof Grobelnye8fc5752021-02-05 14:30:45 +0000171 }
172 }
173 catch (const std::exception& e)
174 {
175 throw sdbusplus::exception::SdBusError(
176 static_cast<int>(std::errc::invalid_argument), e.what());
177 }
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +0000178}
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100179
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +0000180interfaces::Report& ReportManager::addReport(
181 boost::asio::yield_context& yield, const std::string& reportName,
182 const std::string& reportingType, const bool emitsReadingsUpdate,
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000183 const bool logToMetricReportsCollection, Milliseconds interval,
Szymon Dompke3eb56862021-09-20 15:32:04 +0200184 const uint64_t appendLimit, const std::string& reportUpdates,
Lukasz Kazmierczak7e098e92021-09-16 15:59:56 +0200185 ReadingParameters metricParams, const bool enabled)
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +0000186{
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000187 auto labeledMetricParams =
188 reportFactory->convertMetricParams(yield, metricParams);
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +0000189
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000190 return addReport(reportName, reportingType, emitsReadingsUpdate,
Szymon Dompke3eb56862021-09-20 15:32:04 +0200191 logToMetricReportsCollection, interval, appendLimit,
192 reportUpdates, std::move(labeledMetricParams), enabled);
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +0000193}
194
195interfaces::Report& ReportManager::addReport(
196 const std::string& reportName, const std::string& reportingType,
197 const bool emitsReadingsUpdate, const bool logToMetricReportsCollection,
Szymon Dompke3eb56862021-09-20 15:32:04 +0200198 Milliseconds interval, const uint64_t appendLimit,
199 const std::string& reportUpdates,
Lukasz Kazmierczak7e098e92021-09-16 15:59:56 +0200200 std::vector<LabeledMetricParameters> labeledMetricParams,
201 const bool enabled)
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +0000202{
Szymon Dompke3eb56862021-09-20 15:32:04 +0200203 verifyAddReport(reportName, reportingType, interval, reportUpdates,
204 labeledMetricParams);
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +0000205
Szymon Dompke3eb56862021-09-20 15:32:04 +0200206 reports.emplace_back(reportFactory->make(
207 reportName, reportingType, emitsReadingsUpdate,
208 logToMetricReportsCollection, interval, appendLimit, reportUpdates,
209 *this, *reportStorage, labeledMetricParams, enabled));
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +0000210 return *reports.back();
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100211}
212
213void ReportManager::loadFromPersistent()
214{
215 std::vector<interfaces::JsonStorage::FilePath> paths =
216 reportStorage->list();
217
218 for (const auto& path : paths)
219 {
220 std::optional<nlohmann::json> data = reportStorage->load(path);
221 try
222 {
Lukasz Kazmierczak7e098e92021-09-16 15:59:56 +0200223 bool enabled = data->at("Enabled").get<bool>();
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100224 size_t version = data->at("Version").get<size_t>();
225 if (version != Report::reportVersion)
226 {
227 throw std::logic_error("Invalid version");
228 }
229 std::string& name = data->at("Name").get_ref<std::string&>();
230 std::string& reportingType =
231 data->at("ReportingType").get_ref<std::string&>();
232 bool emitsReadingsSignal =
233 data->at("EmitsReadingsUpdate").get<bool>();
234 bool logToMetricReportsCollection =
235 data->at("LogToMetricReportsCollection").get<bool>();
236 uint64_t interval = data->at("Interval").get<uint64_t>();
Szymon Dompke3eb56862021-09-20 15:32:04 +0200237 uint64_t appendLimit = data->at("AppendLimit").get<uint64_t>();
238 std::string reportUpdates =
239 data->at("ReportUpdates").get<std::string>();
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +0000240 auto readingParameters =
241 data->at("ReadingParameters")
242 .get<std::vector<LabeledMetricParameters>>();
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100243
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +0000244 addReport(name, reportingType, emitsReadingsSignal,
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000245 logToMetricReportsCollection, Milliseconds(interval),
Szymon Dompke3eb56862021-09-20 15:32:04 +0200246 appendLimit, reportUpdates, std::move(readingParameters),
247 enabled);
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100248 }
249 catch (const std::exception& e)
250 {
251 phosphor::logging::log<phosphor::logging::level::ERR>(
252 "Failed to load report from storage",
253 phosphor::logging::entry(
Wludzik, Jozef982c5b52021-01-02 12:05:21 +0100254 "FILENAME=%s",
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100255 static_cast<std::filesystem::path>(path).c_str()),
Wludzik, Jozef982c5b52021-01-02 12:05:21 +0100256 phosphor::logging::entry("EXCEPTION_MSG=%s", e.what()));
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100257 reportStorage->remove(path);
258 }
259 }
260}
Wludzik, Jozefd960e1f2021-01-08 09:25:59 +0100261
262void ReportManager::updateReport(const std::string& name)
263{
264 for (auto& report : reports)
265 {
266 if (report->getName() == name)
267 {
268 report->updateReadings();
269 return;
270 }
271 }
272}
Szymon Dompke3eb56862021-09-20 15:32:04 +0200273
274void ReportManager::verifyReportUpdates(const std::string& reportUpdates)
275{
276 if (std::find(supportedReportUpdates.begin(), supportedReportUpdates.end(),
277 reportUpdates) == supportedReportUpdates.end())
278 {
279 throw sdbusplus::exception::SdBusError(
280 static_cast<int>(std::errc::invalid_argument),
281 "Invalid ReportUpdates");
282 }
283}