blob: ab76a319cc3afaa163cc1f81c1a3f8ac4d1cb868 [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 =
Krzysztof Grobelny51497a02021-11-09 14:56:22 +010062 ReportUpdates::overwrite;
63
64 std::vector<ReportAction> reportActions;
65
66 if (emitsReadingsUpdate)
67 {
68 reportActions.emplace_back(
69 ReportAction::emitsReadingsUpdate);
70 }
71 if (logToMetricReportsCollection)
72 {
73 reportActions.emplace_back(
74 ReportAction::logToMetricReportsCollection);
75 }
76
77 return addReport(yield, reportName,
78 utils::toReportingType(reportingType),
79 reportActions, Milliseconds(interval),
80 appendLimitDefault, reportUpdatesDefault,
81 convertToReadingParameters(
82 std::move(metricParams)),
83 enabledDefault)
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +000084 .getPath();
85 });
86
87 dbusIface.register_method(
88 "AddReportFutureVersion",
Krzysztof Grobelny51497a02021-11-09 14:56:22 +010089 [this](boost::asio::yield_context& yield,
90 const std::string& reportName,
91 const std::string& reportingType,
92 const std::string& reportUpdates,
93 const uint64_t appendLimit,
94 const std::vector<std::string>& reportActions,
95 const uint64_t interval,
96 ReadingParameters metricParams) {
Lukasz Kazmierczak7e098e92021-09-16 15:59:56 +020097 constexpr auto enabledDefault = true;
Krzysztof Grobelny51497a02021-11-09 14:56:22 +010098 return addReport(yield, reportName,
99 utils::toReportingType(reportingType),
100 utils::transform(
101 reportActions,
102 [](const auto& reportAction) {
103 return utils::toReportAction(
104 reportAction);
105 }),
Szymon Dompke3eb56862021-09-20 15:32:04 +0200106 Milliseconds(interval), appendLimit,
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100107 utils::toReportUpdates(reportUpdates),
108 std::move(metricParams), enabledDefault)
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +0000109 .getPath();
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +0200110 });
111 });
Krzysztof Grobelny64b75a52020-09-18 10:17:16 +0200112}
113
Wludzik, Jozef2f9f9b82020-10-13 09:07:45 +0200114void ReportManager::removeReport(const interfaces::Report* report)
Krzysztof Grobelny64b75a52020-09-18 10:17:16 +0200115{
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +0200116 reports.erase(
117 std::remove_if(reports.begin(), reports.end(),
118 [report](const auto& x) { return report == x.get(); }),
119 reports.end());
Krzysztof Grobelny64b75a52020-09-18 10:17:16 +0200120}
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100121
Karol Niczyj32859b62021-05-19 10:20:46 +0200122void ReportManager::verifyReportNameLength(const std::string& reportName)
123{
124 if (reportName.length() > maxReportNameLength)
125 {
126 throw sdbusplus::exception::SdBusError(
127 static_cast<int>(std::errc::invalid_argument),
Szymon Dompkee28aa532021-10-27 12:33:12 +0200128 "Report name exceeds maximum length");
Karol Niczyj32859b62021-05-19 10:20:46 +0200129 }
130}
131
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000132void ReportManager::verifyAddReport(
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100133 const std::string& reportName, const ReportingType reportingType,
134 Milliseconds interval, const ReportUpdates reportUpdates,
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000135 const std::vector<LabeledMetricParameters>& readingParams)
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100136{
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100137 if (reportingType == ReportingType::onChange)
138 {
139 throw sdbusplus::exception::SdBusError(
140 static_cast<int>(std::errc::invalid_argument),
141 "Invalid reportingType");
142 }
143
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100144 if (reports.size() >= maxReports)
145 {
146 throw sdbusplus::exception::SdBusError(
147 static_cast<int>(std::errc::too_many_files_open),
148 "Reached maximal report count");
149 }
150
Karol Niczyj32859b62021-05-19 10:20:46 +0200151 verifyReportNameLength(reportName);
152
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100153 for (const auto& report : reports)
154 {
155 if (report->getName() == reportName)
156 {
157 throw sdbusplus::exception::SdBusError(
158 static_cast<int>(std::errc::file_exists), "Duplicate report");
159 }
160 }
161
Szymon Dompke3eb56862021-09-20 15:32:04 +0200162 verifyReportUpdates(reportUpdates);
163
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100164 if (reportingType == ReportingType::periodic && interval < minInterval)
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100165 {
166 throw sdbusplus::exception::SdBusError(
167 static_cast<int>(std::errc::invalid_argument), "Invalid interval");
168 }
Wludzik, Jozefbc766b42020-12-08 16:06:22 +0100169
Wludzik, Jozef503c1582020-12-11 14:48:01 +0100170 if (readingParams.size() > maxReadingParams)
Krzysztof Grobelnye8fc5752021-02-05 14:30:45 +0000171
Wludzik, Jozefbc766b42020-12-08 16:06:22 +0100172 {
173 throw sdbusplus::exception::SdBusError(
174 static_cast<int>(std::errc::argument_list_too_long),
175 "Too many reading parameters");
176 }
Krzysztof Grobelnye8fc5752021-02-05 14:30:45 +0000177
178 try
179 {
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000180 namespace ts = utils::tstring;
181
182 for (const LabeledMetricParameters& item : readingParams)
Krzysztof Grobelnye8fc5752021-02-05 14:30:45 +0000183 {
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000184 utils::toOperationType(
185 utils::toUnderlying(item.at_label<ts::OperationType>()));
Krzysztof Grobelnye8fc5752021-02-05 14:30:45 +0000186 }
187 }
188 catch (const std::exception& e)
189 {
190 throw sdbusplus::exception::SdBusError(
191 static_cast<int>(std::errc::invalid_argument), e.what());
192 }
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +0000193}
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100194
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +0000195interfaces::Report& ReportManager::addReport(
196 boost::asio::yield_context& yield, const std::string& reportName,
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100197 const ReportingType reportingType,
198 const std::vector<ReportAction>& reportActions, Milliseconds interval,
199 const uint64_t appendLimit, const ReportUpdates reportUpdates,
Lukasz Kazmierczak7e098e92021-09-16 15:59:56 +0200200 ReadingParameters metricParams, const bool enabled)
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +0000201{
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000202 auto labeledMetricParams =
203 reportFactory->convertMetricParams(yield, metricParams);
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +0000204
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100205 return addReport(reportName, reportingType, reportActions, interval,
206 appendLimit, reportUpdates, std::move(labeledMetricParams),
207 enabled);
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +0000208}
209
210interfaces::Report& ReportManager::addReport(
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100211 const std::string& reportName, const ReportingType reportingType,
212 const std::vector<ReportAction>& reportActions, Milliseconds interval,
213 const uint64_t appendLimit, const ReportUpdates reportUpdates,
Lukasz Kazmierczak7e098e92021-09-16 15:59:56 +0200214 std::vector<LabeledMetricParameters> labeledMetricParams,
215 const bool enabled)
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +0000216{
Szymon Dompke3eb56862021-09-20 15:32:04 +0200217 verifyAddReport(reportName, reportingType, interval, reportUpdates,
218 labeledMetricParams);
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +0000219
Szymon Dompke3eb56862021-09-20 15:32:04 +0200220 reports.emplace_back(reportFactory->make(
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100221 reportName, reportingType, reportActions, interval, appendLimit,
222 reportUpdates, *this, *reportStorage, labeledMetricParams, enabled));
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +0000223 return *reports.back();
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100224}
225
226void ReportManager::loadFromPersistent()
227{
228 std::vector<interfaces::JsonStorage::FilePath> paths =
229 reportStorage->list();
230
231 for (const auto& path : paths)
232 {
233 std::optional<nlohmann::json> data = reportStorage->load(path);
234 try
235 {
Lukasz Kazmierczak7e098e92021-09-16 15:59:56 +0200236 bool enabled = data->at("Enabled").get<bool>();
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100237 size_t version = data->at("Version").get<size_t>();
238 if (version != Report::reportVersion)
239 {
240 throw std::logic_error("Invalid version");
241 }
242 std::string& name = data->at("Name").get_ref<std::string&>();
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100243
244 uint32_t reportingType = data->at("ReportingType").get<uint32_t>();
245 std::vector<ReportAction> reportActions = utils::transform(
246 data->at("ReportActions").get<std::vector<uint32_t>>(),
247 [](const auto reportAction) {
248 return utils::toReportAction(reportAction);
249 });
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100250 uint64_t interval = data->at("Interval").get<uint64_t>();
Szymon Dompke3eb56862021-09-20 15:32:04 +0200251 uint64_t appendLimit = data->at("AppendLimit").get<uint64_t>();
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100252 uint32_t reportUpdates = data->at("ReportUpdates").get<uint32_t>();
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +0000253 auto readingParameters =
254 data->at("ReadingParameters")
255 .get<std::vector<LabeledMetricParameters>>();
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100256
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100257 addReport(name, utils::toReportingType(reportingType),
258 reportActions, Milliseconds(interval), appendLimit,
259 utils::toReportUpdates(reportUpdates),
260 std::move(readingParameters), enabled);
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100261 }
262 catch (const std::exception& e)
263 {
264 phosphor::logging::log<phosphor::logging::level::ERR>(
265 "Failed to load report from storage",
266 phosphor::logging::entry(
Wludzik, Jozef982c5b52021-01-02 12:05:21 +0100267 "FILENAME=%s",
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100268 static_cast<std::filesystem::path>(path).c_str()),
Wludzik, Jozef982c5b52021-01-02 12:05:21 +0100269 phosphor::logging::entry("EXCEPTION_MSG=%s", e.what()));
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100270 reportStorage->remove(path);
271 }
272 }
273}
Wludzik, Jozefd960e1f2021-01-08 09:25:59 +0100274
275void ReportManager::updateReport(const std::string& name)
276{
277 for (auto& report : reports)
278 {
279 if (report->getName() == name)
280 {
281 report->updateReadings();
282 return;
283 }
284 }
285}
Szymon Dompke3eb56862021-09-20 15:32:04 +0200286
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100287void ReportManager::verifyReportUpdates(const ReportUpdates reportUpdates)
Szymon Dompke3eb56862021-09-20 15:32:04 +0200288{
289 if (std::find(supportedReportUpdates.begin(), supportedReportUpdates.end(),
290 reportUpdates) == supportedReportUpdates.end())
291 {
292 throw sdbusplus::exception::SdBusError(
293 static_cast<int>(std::errc::invalid_argument),
294 "Invalid ReportUpdates");
295 }
296}