blob: 18636f877ab69a842e63b22212a211759b829767 [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 Grobelnyb8cc78d2021-11-29 15:54:53 +01006#include "utils/generate_id.hpp"
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +00007#include "utils/transform.hpp"
Wludzik, Jozefe2362792020-10-27 17:23:55 +01008
9#include <phosphor-logging/log.hpp>
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +020010#include <sdbusplus/exception.hpp>
11
Wludzik, Jozefe2362792020-10-27 17:23:55 +010012#include <stdexcept>
Krzysztof Grobelny64b75a52020-09-18 10:17:16 +020013#include <system_error>
14
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +000015ReadingParameters
16 convertToReadingParameters(ReadingParametersPastVersion params)
17{
18 return utils::transform(params, [](const auto& param) {
19 using namespace std::chrono_literals;
20
Krzysztof Grobelnyb8cc78d2021-11-29 15:54:53 +010021 const auto& [sensorPath, operationType, id, metadata] = param;
22
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +000023 return ReadingParameters::value_type(
Krzysztof Grobelnyb8cc78d2021-11-29 15:54:53 +010024 std::vector<
25 std::tuple<sdbusplus::message::object_path, std::string>>{
26 {sensorPath, metadata}},
27 operationType, id, utils::enumToString(CollectionTimeScope::point),
28 0u);
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +000029 });
30}
31
Krzysztof Grobelny64b75a52020-09-18 10:17:16 +020032ReportManager::ReportManager(
Wludzik, Jozef2f9f9b82020-10-13 09:07:45 +020033 std::unique_ptr<interfaces::ReportFactory> reportFactoryIn,
Wludzik, Jozefe2362792020-10-27 17:23:55 +010034 std::unique_ptr<interfaces::JsonStorage> reportStorageIn,
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +020035 const std::shared_ptr<sdbusplus::asio::object_server>& objServerIn) :
Wludzik, Jozef2f9f9b82020-10-13 09:07:45 +020036 reportFactory(std::move(reportFactoryIn)),
Wludzik, Jozefe2362792020-10-27 17:23:55 +010037 reportStorage(std::move(reportStorageIn)), objServer(objServerIn)
Krzysztof Grobelny64b75a52020-09-18 10:17:16 +020038{
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +020039 reports.reserve(maxReports);
Krzysztof Grobelny6ccfcbf2020-11-04 09:31:36 +010040
Wludzik, Jozefe2362792020-10-27 17:23:55 +010041 loadFromPersistent();
Krzysztof Grobelny64b75a52020-09-18 10:17:16 +020042
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +020043 reportManagerIface = objServer->add_unique_interface(
Wludzik, Jozef2f9f9b82020-10-13 09:07:45 +020044 reportManagerPath, reportManagerIfaceName, [this](auto& dbusIface) {
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +020045 dbusIface.register_property_r(
Wludzik, Jozef503c1582020-12-11 14:48:01 +010046 "MaxReports", size_t{}, sdbusplus::vtable::property_::const_,
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +020047 [](const auto&) { return maxReports; });
48 dbusIface.register_property_r(
Krzysztof Grobelnyb8cc78d2021-11-29 15:54:53 +010049 "MaxReportIdLength", size_t{},
Karol Niczyj32859b62021-05-19 10:20:46 +020050 sdbusplus::vtable::property_::const_,
Krzysztof Grobelnyb8cc78d2021-11-29 15:54:53 +010051 [](const auto&) { return maxReportIdLength; });
Karol Niczyj32859b62021-05-19 10:20:46 +020052 dbusIface.register_property_r(
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +020053 "MinInterval", uint64_t{}, sdbusplus::vtable::property_::const_,
54 [](const auto&) -> uint64_t { return minInterval.count(); });
Krzysztof Grobelny64b75a52020-09-18 10:17:16 +020055
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +020056 dbusIface.register_method(
Wludzik, Jozefe2362792020-10-27 17:23:55 +010057 "AddReport", [this](boost::asio::yield_context& yield,
Krzysztof Grobelnyb8cc78d2021-11-29 15:54:53 +010058 const std::string& reportId,
Wludzik, Jozef2f9f9b82020-10-13 09:07:45 +020059 const std::string& reportingType,
60 const bool emitsReadingsUpdate,
61 const bool logToMetricReportsCollection,
62 const uint64_t interval,
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +000063 ReadingParametersPastVersion metricParams) {
Lukasz Kazmierczak7e098e92021-09-16 15:59:56 +020064 constexpr auto enabledDefault = true;
Szymon Dompke3eb56862021-09-20 15:32:04 +020065 constexpr uint64_t appendLimitDefault = 0;
66 constexpr ReportUpdates reportUpdatesDefault =
Krzysztof Grobelny51497a02021-11-09 14:56:22 +010067 ReportUpdates::overwrite;
68
69 std::vector<ReportAction> reportActions;
70
71 if (emitsReadingsUpdate)
72 {
73 reportActions.emplace_back(
74 ReportAction::emitsReadingsUpdate);
75 }
76 if (logToMetricReportsCollection)
77 {
78 reportActions.emplace_back(
79 ReportAction::logToMetricReportsCollection);
80 }
81
Krzysztof Grobelnyb8cc78d2021-11-29 15:54:53 +010082 return addReport(yield, reportId, reportId,
Krzysztof Grobelny51497a02021-11-09 14:56:22 +010083 utils::toReportingType(reportingType),
84 reportActions, Milliseconds(interval),
85 appendLimitDefault, reportUpdatesDefault,
86 convertToReadingParameters(
87 std::move(metricParams)),
88 enabledDefault)
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +000089 .getPath();
90 });
91
92 dbusIface.register_method(
93 "AddReportFutureVersion",
Krzysztof Grobelnyb8cc78d2021-11-29 15:54:53 +010094 [this](
95 boost::asio::yield_context& yield,
96 const std::string& reportId, const std::string& reportName,
97 const std::string& reportingType,
98 const std::string& reportUpdates,
99 const uint64_t appendLimit,
100 const std::vector<std::string>& reportActions,
101 const uint64_t interval, ReadingParameters metricParams) {
Lukasz Kazmierczak7e098e92021-09-16 15:59:56 +0200102 constexpr auto enabledDefault = true;
Krzysztof Grobelnyb8cc78d2021-11-29 15:54:53 +0100103 return addReport(yield, reportId, reportName,
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100104 utils::toReportingType(reportingType),
105 utils::transform(
106 reportActions,
107 [](const auto& reportAction) {
108 return utils::toReportAction(
109 reportAction);
110 }),
Szymon Dompke3eb56862021-09-20 15:32:04 +0200111 Milliseconds(interval), appendLimit,
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100112 utils::toReportUpdates(reportUpdates),
113 std::move(metricParams), enabledDefault)
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +0000114 .getPath();
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +0200115 });
116 });
Krzysztof Grobelny64b75a52020-09-18 10:17:16 +0200117}
118
Wludzik, Jozef2f9f9b82020-10-13 09:07:45 +0200119void ReportManager::removeReport(const interfaces::Report* report)
Krzysztof Grobelny64b75a52020-09-18 10:17:16 +0200120{
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +0200121 reports.erase(
122 std::remove_if(reports.begin(), reports.end(),
123 [report](const auto& x) { return report == x.get(); }),
124 reports.end());
Krzysztof Grobelny64b75a52020-09-18 10:17:16 +0200125}
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100126
Krzysztof Grobelnyb8cc78d2021-11-29 15:54:53 +0100127void ReportManager::verifyReportIdLength(const std::string& reportId)
Karol Niczyj32859b62021-05-19 10:20:46 +0200128{
Krzysztof Grobelnyb8cc78d2021-11-29 15:54:53 +0100129 if (reportId.length() > maxReportIdLength)
Karol Niczyj32859b62021-05-19 10:20:46 +0200130 {
131 throw sdbusplus::exception::SdBusError(
132 static_cast<int>(std::errc::invalid_argument),
Krzysztof Grobelnyb8cc78d2021-11-29 15:54:53 +0100133 "Report id exceeds maximum length");
Karol Niczyj32859b62021-05-19 10:20:46 +0200134 }
135}
136
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000137void ReportManager::verifyAddReport(
Krzysztof Grobelnyb8cc78d2021-11-29 15:54:53 +0100138 const std::string& reportId, const std::string& reportName,
139 const ReportingType reportingType, Milliseconds interval,
140 const ReportUpdates reportUpdates,
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000141 const std::vector<LabeledMetricParameters>& readingParams)
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100142{
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100143 if (reportingType == ReportingType::onChange)
144 {
145 throw sdbusplus::exception::SdBusError(
146 static_cast<int>(std::errc::invalid_argument),
147 "Invalid reportingType");
148 }
149
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100150 if (reports.size() >= maxReports)
151 {
152 throw sdbusplus::exception::SdBusError(
153 static_cast<int>(std::errc::too_many_files_open),
154 "Reached maximal report count");
155 }
156
Krzysztof Grobelnyb8cc78d2021-11-29 15:54:53 +0100157 verifyReportIdLength(reportId);
158 utils::verifyIdCharacters(reportId);
Karol Niczyj32859b62021-05-19 10:20:46 +0200159
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100160 for (const auto& report : reports)
161 {
Krzysztof Grobelnyb8cc78d2021-11-29 15:54:53 +0100162 if (report->getId() == reportId)
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100163 {
164 throw sdbusplus::exception::SdBusError(
165 static_cast<int>(std::errc::file_exists), "Duplicate report");
166 }
167 }
168
Szymon Dompke3eb56862021-09-20 15:32:04 +0200169 verifyReportUpdates(reportUpdates);
170
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100171 if (reportingType == ReportingType::periodic && interval < minInterval)
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100172 {
173 throw sdbusplus::exception::SdBusError(
174 static_cast<int>(std::errc::invalid_argument), "Invalid interval");
175 }
Wludzik, Jozefbc766b42020-12-08 16:06:22 +0100176
Wludzik, Jozef503c1582020-12-11 14:48:01 +0100177 if (readingParams.size() > maxReadingParams)
Krzysztof Grobelnye8fc5752021-02-05 14:30:45 +0000178
Wludzik, Jozefbc766b42020-12-08 16:06:22 +0100179 {
180 throw sdbusplus::exception::SdBusError(
181 static_cast<int>(std::errc::argument_list_too_long),
182 "Too many reading parameters");
183 }
Krzysztof Grobelnye8fc5752021-02-05 14:30:45 +0000184
185 try
186 {
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000187 namespace ts = utils::tstring;
188
189 for (const LabeledMetricParameters& item : readingParams)
Krzysztof Grobelnye8fc5752021-02-05 14:30:45 +0000190 {
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000191 utils::toOperationType(
192 utils::toUnderlying(item.at_label<ts::OperationType>()));
Krzysztof Grobelnye8fc5752021-02-05 14:30:45 +0000193 }
194 }
195 catch (const std::exception& e)
196 {
197 throw sdbusplus::exception::SdBusError(
198 static_cast<int>(std::errc::invalid_argument), e.what());
199 }
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +0000200}
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100201
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +0000202interfaces::Report& ReportManager::addReport(
Krzysztof Grobelnyb8cc78d2021-11-29 15:54:53 +0100203 boost::asio::yield_context& yield, const std::string& reportId,
204 const std::string& reportName, const ReportingType reportingType,
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100205 const std::vector<ReportAction>& reportActions, Milliseconds interval,
206 const uint64_t appendLimit, const ReportUpdates reportUpdates,
Lukasz Kazmierczak7e098e92021-09-16 15:59:56 +0200207 ReadingParameters metricParams, const bool enabled)
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +0000208{
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000209 auto labeledMetricParams =
210 reportFactory->convertMetricParams(yield, metricParams);
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +0000211
Krzysztof Grobelnyb8cc78d2021-11-29 15:54:53 +0100212 return addReport(reportId, reportName, reportingType, reportActions,
213 interval, appendLimit, reportUpdates,
214 std::move(labeledMetricParams), enabled);
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +0000215}
216
217interfaces::Report& ReportManager::addReport(
Krzysztof Grobelnyb8cc78d2021-11-29 15:54:53 +0100218 const std::string& reportId, const std::string& reportName,
219 const ReportingType reportingType,
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100220 const std::vector<ReportAction>& reportActions, Milliseconds interval,
221 const uint64_t appendLimit, const ReportUpdates reportUpdates,
Lukasz Kazmierczak7e098e92021-09-16 15:59:56 +0200222 std::vector<LabeledMetricParameters> labeledMetricParams,
223 const bool enabled)
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +0000224{
Krzysztof Grobelnyb8cc78d2021-11-29 15:54:53 +0100225 std::string name = reportName;
226 if (name.empty())
227 {
228 name = "Report";
229 }
230
231 const auto existingReportIds = utils::transform(
232 reports, [](const auto& report) { return report->getId(); });
233
234 std::string id =
235 utils::generateId(reportId, name, existingReportIds, maxReportIdLength);
236
237 verifyAddReport(id, name, reportingType, interval, reportUpdates,
Szymon Dompke3eb56862021-09-20 15:32:04 +0200238 labeledMetricParams);
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +0000239
Szymon Dompke3eb56862021-09-20 15:32:04 +0200240 reports.emplace_back(reportFactory->make(
Krzysztof Grobelnyb8cc78d2021-11-29 15:54:53 +0100241 id, name, reportingType, reportActions, interval, appendLimit,
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100242 reportUpdates, *this, *reportStorage, labeledMetricParams, enabled));
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +0000243 return *reports.back();
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100244}
245
246void ReportManager::loadFromPersistent()
247{
248 std::vector<interfaces::JsonStorage::FilePath> paths =
249 reportStorage->list();
250
251 for (const auto& path : paths)
252 {
253 std::optional<nlohmann::json> data = reportStorage->load(path);
254 try
255 {
256 size_t version = data->at("Version").get<size_t>();
257 if (version != Report::reportVersion)
258 {
259 throw std::logic_error("Invalid version");
260 }
Krzysztof Grobelnyb8cc78d2021-11-29 15:54:53 +0100261 bool enabled = data->at("Enabled").get<bool>();
262 std::string& id = data->at("Id").get_ref<std::string&>();
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100263 std::string& name = data->at("Name").get_ref<std::string&>();
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100264
265 uint32_t reportingType = data->at("ReportingType").get<uint32_t>();
266 std::vector<ReportAction> reportActions = utils::transform(
267 data->at("ReportActions").get<std::vector<uint32_t>>(),
268 [](const auto reportAction) {
269 return utils::toReportAction(reportAction);
270 });
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100271 uint64_t interval = data->at("Interval").get<uint64_t>();
Szymon Dompke3eb56862021-09-20 15:32:04 +0200272 uint64_t appendLimit = data->at("AppendLimit").get<uint64_t>();
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100273 uint32_t reportUpdates = data->at("ReportUpdates").get<uint32_t>();
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +0000274 auto readingParameters =
275 data->at("ReadingParameters")
276 .get<std::vector<LabeledMetricParameters>>();
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100277
Krzysztof Grobelnyb8cc78d2021-11-29 15:54:53 +0100278 addReport(id, name, utils::toReportingType(reportingType),
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100279 reportActions, Milliseconds(interval), appendLimit,
280 utils::toReportUpdates(reportUpdates),
281 std::move(readingParameters), enabled);
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100282 }
283 catch (const std::exception& e)
284 {
285 phosphor::logging::log<phosphor::logging::level::ERR>(
286 "Failed to load report from storage",
287 phosphor::logging::entry(
Wludzik, Jozef982c5b52021-01-02 12:05:21 +0100288 "FILENAME=%s",
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100289 static_cast<std::filesystem::path>(path).c_str()),
Wludzik, Jozef982c5b52021-01-02 12:05:21 +0100290 phosphor::logging::entry("EXCEPTION_MSG=%s", e.what()));
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100291 reportStorage->remove(path);
292 }
293 }
294}
Wludzik, Jozefd960e1f2021-01-08 09:25:59 +0100295
Krzysztof Grobelnyb8cc78d2021-11-29 15:54:53 +0100296void ReportManager::updateReport(const std::string& id)
Wludzik, Jozefd960e1f2021-01-08 09:25:59 +0100297{
298 for (auto& report : reports)
299 {
Krzysztof Grobelnyb8cc78d2021-11-29 15:54:53 +0100300 if (report->getId() == id)
Wludzik, Jozefd960e1f2021-01-08 09:25:59 +0100301 {
302 report->updateReadings();
303 return;
304 }
305 }
306}
Szymon Dompke3eb56862021-09-20 15:32:04 +0200307
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100308void ReportManager::verifyReportUpdates(const ReportUpdates reportUpdates)
Szymon Dompke3eb56862021-09-20 15:32:04 +0200309{
310 if (std::find(supportedReportUpdates.begin(), supportedReportUpdates.end(),
311 reportUpdates) == supportedReportUpdates.end())
312 {
313 throw sdbusplus::exception::SdBusError(
314 static_cast<int>(std::errc::invalid_argument),
315 "Invalid ReportUpdates");
316 }
317}