blob: 1677bb3896d0976bb5f7ea3e1df786db092ec520 [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"
Szymon Dompke32305f12022-07-05 15:37:21 +02006#include "utils/dbus_path_utils.hpp"
7#include "utils/make_id_name.hpp"
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +00008#include "utils/transform.hpp"
Wludzik, Jozefe2362792020-10-27 17:23:55 +01009
10#include <phosphor-logging/log.hpp>
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +020011#include <sdbusplus/exception.hpp>
12
Wludzik, Jozefe2362792020-10-27 17:23:55 +010013#include <stdexcept>
Krzysztof Grobelny64b75a52020-09-18 10:17:16 +020014#include <system_error>
15
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +000016ReadingParameters
17 convertToReadingParameters(ReadingParametersPastVersion params)
18{
19 return utils::transform(params, [](const auto& param) {
20 using namespace std::chrono_literals;
21
Krzysztof Grobelnyb8cc78d2021-11-29 15:54:53 +010022 const auto& [sensorPath, operationType, id, metadata] = param;
23
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +000024 return ReadingParameters::value_type(
Krzysztof Grobelnyb8cc78d2021-11-29 15:54:53 +010025 std::vector<
26 std::tuple<sdbusplus::message::object_path, std::string>>{
27 {sensorPath, metadata}},
28 operationType, id, utils::enumToString(CollectionTimeScope::point),
29 0u);
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +000030 });
31}
32
Krzysztof Grobelny64b75a52020-09-18 10:17:16 +020033ReportManager::ReportManager(
Wludzik, Jozef2f9f9b82020-10-13 09:07:45 +020034 std::unique_ptr<interfaces::ReportFactory> reportFactoryIn,
Wludzik, Jozefe2362792020-10-27 17:23:55 +010035 std::unique_ptr<interfaces::JsonStorage> reportStorageIn,
Krzysztof Grobelnye6d48872022-02-08 13:41:30 +010036 const std::shared_ptr<sdbusplus::asio::object_server>& objServerIn) :
Wludzik, Jozef2f9f9b82020-10-13 09:07:45 +020037 reportFactory(std::move(reportFactoryIn)),
Krzysztof Grobelnye6d48872022-02-08 13:41:30 +010038 reportStorage(std::move(reportStorageIn)), objServer(objServerIn)
Krzysztof Grobelny64b75a52020-09-18 10:17:16 +020039{
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +020040 reports.reserve(maxReports);
Krzysztof Grobelny6ccfcbf2020-11-04 09:31:36 +010041
Wludzik, Jozefe2362792020-10-27 17:23:55 +010042 loadFromPersistent();
Krzysztof Grobelny64b75a52020-09-18 10:17:16 +020043
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +020044 reportManagerIface = objServer->add_unique_interface(
Wludzik, Jozef2f9f9b82020-10-13 09:07:45 +020045 reportManagerPath, reportManagerIfaceName, [this](auto& dbusIface) {
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +020046 dbusIface.register_property_r(
Wludzik, Jozef503c1582020-12-11 14:48:01 +010047 "MaxReports", size_t{}, sdbusplus::vtable::property_::const_,
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +020048 [](const auto&) { return maxReports; });
49 dbusIface.register_property_r(
50 "MinInterval", uint64_t{}, sdbusplus::vtable::property_::const_,
51 [](const auto&) -> uint64_t { return minInterval.count(); });
Krzysztof Grobelny60fee072022-01-13 16:25:04 +010052 dbusIface.register_property_r(
53 "SupportedOperationTypes", std::vector<std::string>{},
54 sdbusplus::vtable::property_::const_,
55 [](const auto&) -> std::vector<std::string> {
Szymon Dompkefdb06a12022-02-11 11:04:44 +010056 return utils::transform<std::vector>(
Krzysztof Grobelny60fee072022-01-13 16:25:04 +010057 utils::convDataOperationType, [](const auto& item) {
58 return std::string(item.first);
59 });
60 });
Krzysztof Grobelny64b75a52020-09-18 10:17:16 +020061
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +020062 dbusIface.register_method(
Wludzik, Jozefe2362792020-10-27 17:23:55 +010063 "AddReport", [this](boost::asio::yield_context& yield,
Krzysztof Grobelnyb8cc78d2021-11-29 15:54:53 +010064 const std::string& reportId,
Wludzik, Jozef2f9f9b82020-10-13 09:07:45 +020065 const std::string& reportingType,
66 const bool emitsReadingsUpdate,
67 const bool logToMetricReportsCollection,
68 const uint64_t interval,
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +000069 ReadingParametersPastVersion metricParams) {
Lukasz Kazmierczak7e098e92021-09-16 15:59:56 +020070 constexpr auto enabledDefault = true;
Szymon Dompke3eb56862021-09-20 15:32:04 +020071 constexpr uint64_t appendLimitDefault = 0;
72 constexpr ReportUpdates reportUpdatesDefault =
Krzysztof Grobelny51497a02021-11-09 14:56:22 +010073 ReportUpdates::overwrite;
74
75 std::vector<ReportAction> reportActions;
76
77 if (emitsReadingsUpdate)
78 {
79 reportActions.emplace_back(
80 ReportAction::emitsReadingsUpdate);
81 }
82 if (logToMetricReportsCollection)
83 {
84 reportActions.emplace_back(
85 ReportAction::logToMetricReportsCollection);
86 }
87
Krzysztof Grobelnyb8cc78d2021-11-29 15:54:53 +010088 return addReport(yield, reportId, reportId,
Krzysztof Grobelny51497a02021-11-09 14:56:22 +010089 utils::toReportingType(reportingType),
90 reportActions, Milliseconds(interval),
91 appendLimitDefault, reportUpdatesDefault,
92 convertToReadingParameters(
93 std::move(metricParams)),
94 enabledDefault)
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +000095 .getPath();
96 });
97
98 dbusIface.register_method(
99 "AddReportFutureVersion",
Krzysztof Grobelnyb8cc78d2021-11-29 15:54:53 +0100100 [this](
101 boost::asio::yield_context& yield,
102 const std::string& reportId, const std::string& reportName,
103 const std::string& reportingType,
104 const std::string& reportUpdates,
105 const uint64_t appendLimit,
106 const std::vector<std::string>& reportActions,
107 const uint64_t interval, ReadingParameters metricParams) {
Lukasz Kazmierczak7e098e92021-09-16 15:59:56 +0200108 constexpr auto enabledDefault = true;
Krzysztof Grobelnyb8cc78d2021-11-29 15:54:53 +0100109 return addReport(yield, reportId, reportName,
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100110 utils::toReportingType(reportingType),
111 utils::transform(
112 reportActions,
113 [](const auto& reportAction) {
114 return utils::toReportAction(
115 reportAction);
116 }),
Szymon Dompke3eb56862021-09-20 15:32:04 +0200117 Milliseconds(interval), appendLimit,
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100118 utils::toReportUpdates(reportUpdates),
119 std::move(metricParams), enabledDefault)
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +0000120 .getPath();
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +0200121 });
122 });
Krzysztof Grobelny64b75a52020-09-18 10:17:16 +0200123}
124
Wludzik, Jozef2f9f9b82020-10-13 09:07:45 +0200125void ReportManager::removeReport(const interfaces::Report* report)
Krzysztof Grobelny64b75a52020-09-18 10:17:16 +0200126{
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +0200127 reports.erase(
128 std::remove_if(reports.begin(), reports.end(),
129 [report](const auto& x) { return report == x.get(); }),
130 reports.end());
Krzysztof Grobelny64b75a52020-09-18 10:17:16 +0200131}
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100132
Szymon Dompke32305f12022-07-05 15:37:21 +0200133void ReportManager::verifyMetricParameters(
134 const std::vector<LabeledMetricParameters>& readingParams)
135{
136 namespace ts = utils::tstring;
137
138 for (auto readingParam : readingParams)
139 {
140 if (readingParam.at_label<ts::Id>().length() >
141 utils::constants::maxIdNameLength)
142 {
143 throw sdbusplus::exception::SdBusError(
144 static_cast<int>(std::errc::invalid_argument),
145 "MetricId too long");
146 }
147 }
148}
149
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000150void ReportManager::verifyAddReport(
Krzysztof Grobelnyb8cc78d2021-11-29 15:54:53 +0100151 const std::string& reportId, const std::string& reportName,
152 const ReportingType reportingType, Milliseconds interval,
Ankita Vilas Gawadecd5b0b72022-01-20 20:55:04 +0000153 const ReportUpdates reportUpdates, const uint64_t appendLimit,
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000154 const std::vector<LabeledMetricParameters>& readingParams)
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100155{
Szymon Dompke32305f12022-07-05 15:37:21 +0200156 namespace ts = utils::tstring;
157
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100158 if (reports.size() >= maxReports)
159 {
160 throw sdbusplus::exception::SdBusError(
161 static_cast<int>(std::errc::too_many_files_open),
162 "Reached maximal report count");
163 }
164
Krzysztof Grobelnye6c417c2022-02-02 17:25:53 +0100165 if (appendLimit > maxAppendLimit &&
166 appendLimit != std::numeric_limits<uint64_t>::max())
Ankita Vilas Gawadecd5b0b72022-01-20 20:55:04 +0000167 {
168 throw sdbusplus::exception::SdBusError(
169 static_cast<int>(std::errc::invalid_argument),
170 "Append limit out of range");
171 }
172
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200173 if ((reportingType == ReportingType::periodic && interval < minInterval) ||
174 (reportingType != ReportingType::periodic &&
175 interval != Milliseconds{0}))
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100176 {
177 throw sdbusplus::exception::SdBusError(
178 static_cast<int>(std::errc::invalid_argument), "Invalid interval");
179 }
Wludzik, Jozefbc766b42020-12-08 16:06:22 +0100180
Ankita Vilas Gawadecd5b0b72022-01-20 20:55:04 +0000181 size_t metricCount = 0;
182 for (auto metricParam : readingParams)
183 {
184 auto metricParamsVec =
185 metricParam.at_label<utils::tstring::SensorPath>();
186 metricCount += metricParamsVec.size();
187 }
Krzysztof Grobelnye8fc5752021-02-05 14:30:45 +0000188
Ankita Vilas Gawadecd5b0b72022-01-20 20:55:04 +0000189 if (readingParams.size() > maxNumberMetrics ||
190 metricCount > maxNumberMetrics)
Wludzik, Jozefbc766b42020-12-08 16:06:22 +0100191 {
192 throw sdbusplus::exception::SdBusError(
193 static_cast<int>(std::errc::argument_list_too_long),
194 "Too many reading parameters");
195 }
Krzysztof Grobelnye8fc5752021-02-05 14:30:45 +0000196
Szymon Dompke32305f12022-07-05 15:37:21 +0200197 verifyMetricParameters(readingParams);
198
Krzysztof Grobelnye8fc5752021-02-05 14:30:45 +0000199 try
200 {
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000201 for (const LabeledMetricParameters& item : readingParams)
Krzysztof Grobelnye8fc5752021-02-05 14:30:45 +0000202 {
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000203 utils::toOperationType(
204 utils::toUnderlying(item.at_label<ts::OperationType>()));
Krzysztof Grobelnye8fc5752021-02-05 14:30:45 +0000205 }
206 }
207 catch (const std::exception& e)
208 {
209 throw sdbusplus::exception::SdBusError(
210 static_cast<int>(std::errc::invalid_argument), e.what());
211 }
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +0000212}
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100213
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +0000214interfaces::Report& ReportManager::addReport(
Krzysztof Grobelnyb8cc78d2021-11-29 15:54:53 +0100215 boost::asio::yield_context& yield, const std::string& reportId,
216 const std::string& reportName, const ReportingType reportingType,
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100217 const std::vector<ReportAction>& reportActions, Milliseconds interval,
218 const uint64_t appendLimit, const ReportUpdates reportUpdates,
Lukasz Kazmierczak7e098e92021-09-16 15:59:56 +0200219 ReadingParameters metricParams, const bool enabled)
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +0000220{
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000221 auto labeledMetricParams =
222 reportFactory->convertMetricParams(yield, metricParams);
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +0000223
Krzysztof Grobelnyb8cc78d2021-11-29 15:54:53 +0100224 return addReport(reportId, reportName, reportingType, reportActions,
225 interval, appendLimit, reportUpdates,
Krzysztof Grobelny493e62e2022-02-14 10:55:50 +0100226 std::move(labeledMetricParams), enabled, Readings{});
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +0000227}
228
229interfaces::Report& ReportManager::addReport(
Krzysztof Grobelnyb8cc78d2021-11-29 15:54:53 +0100230 const std::string& reportId, const std::string& reportName,
231 const ReportingType reportingType,
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100232 const std::vector<ReportAction>& reportActions, Milliseconds interval,
233 const uint64_t appendLimit, const ReportUpdates reportUpdates,
Lukasz Kazmierczak7e098e92021-09-16 15:59:56 +0200234 std::vector<LabeledMetricParameters> labeledMetricParams,
Krzysztof Grobelny493e62e2022-02-14 10:55:50 +0100235 const bool enabled, Readings readings)
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +0000236{
Krzysztof Grobelnyb8cc78d2021-11-29 15:54:53 +0100237 const auto existingReportIds = utils::transform(
238 reports, [](const auto& report) { return report->getId(); });
239
Szymon Dompke32305f12022-07-05 15:37:21 +0200240 auto [id, name] = utils::makeIdName(reportId, reportName, reportNameDefault,
241 existingReportIds);
Krzysztof Grobelnyb8cc78d2021-11-29 15:54:53 +0100242
243 verifyAddReport(id, name, reportingType, interval, reportUpdates,
Ankita Vilas Gawadecd5b0b72022-01-20 20:55:04 +0000244 appendLimit, labeledMetricParams);
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +0000245
Krzysztof Grobelny493e62e2022-02-14 10:55:50 +0100246 reports.emplace_back(
247 reportFactory->make(id, name, reportingType, reportActions, interval,
248 appendLimit, reportUpdates, *this, *reportStorage,
249 labeledMetricParams, enabled, std::move(readings)));
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +0000250 return *reports.back();
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100251}
252
253void ReportManager::loadFromPersistent()
254{
255 std::vector<interfaces::JsonStorage::FilePath> paths =
256 reportStorage->list();
257
258 for (const auto& path : paths)
259 {
260 std::optional<nlohmann::json> data = reportStorage->load(path);
261 try
262 {
263 size_t version = data->at("Version").get<size_t>();
264 if (version != Report::reportVersion)
265 {
266 throw std::logic_error("Invalid version");
267 }
Krzysztof Grobelnyb8cc78d2021-11-29 15:54:53 +0100268 bool enabled = data->at("Enabled").get<bool>();
269 std::string& id = data->at("Id").get_ref<std::string&>();
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100270 std::string& name = data->at("Name").get_ref<std::string&>();
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100271
272 uint32_t reportingType = data->at("ReportingType").get<uint32_t>();
273 std::vector<ReportAction> reportActions = utils::transform(
274 data->at("ReportActions").get<std::vector<uint32_t>>(),
275 [](const auto reportAction) {
276 return utils::toReportAction(reportAction);
277 });
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100278 uint64_t interval = data->at("Interval").get<uint64_t>();
Szymon Dompke3eb56862021-09-20 15:32:04 +0200279 uint64_t appendLimit = data->at("AppendLimit").get<uint64_t>();
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100280 uint32_t reportUpdates = data->at("ReportUpdates").get<uint32_t>();
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +0000281 auto readingParameters =
282 data->at("ReadingParameters")
283 .get<std::vector<LabeledMetricParameters>>();
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100284
Krzysztof Grobelny493e62e2022-02-14 10:55:50 +0100285 Readings readings = {};
286
287 if (auto it = data->find("MetricValues"); it != data->end())
288 {
289 const auto labeledReadings = it->get<LabeledReadings>();
290 readings = utils::toReadings(labeledReadings);
291 }
292
Krzysztof Grobelnyb8cc78d2021-11-29 15:54:53 +0100293 addReport(id, name, utils::toReportingType(reportingType),
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100294 reportActions, Milliseconds(interval), appendLimit,
295 utils::toReportUpdates(reportUpdates),
Krzysztof Grobelny493e62e2022-02-14 10:55:50 +0100296 std::move(readingParameters), enabled,
297 std::move(readings));
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100298 }
299 catch (const std::exception& e)
300 {
301 phosphor::logging::log<phosphor::logging::level::ERR>(
302 "Failed to load report from storage",
303 phosphor::logging::entry(
Wludzik, Jozef982c5b52021-01-02 12:05:21 +0100304 "FILENAME=%s",
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100305 static_cast<std::filesystem::path>(path).c_str()),
Wludzik, Jozef982c5b52021-01-02 12:05:21 +0100306 phosphor::logging::entry("EXCEPTION_MSG=%s", e.what()));
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100307 reportStorage->remove(path);
308 }
309 }
310}