blob: 738dd6d792257ba55738d14f26589397dd7ce15e [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,
Krzysztof Grobelnye6d48872022-02-08 13:41:30 +010035 const std::shared_ptr<sdbusplus::asio::object_server>& objServerIn) :
Wludzik, Jozef2f9f9b82020-10-13 09:07:45 +020036 reportFactory(std::move(reportFactoryIn)),
Krzysztof Grobelnye6d48872022-02-08 13:41:30 +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 Grobelny60fee072022-01-13 16:25:04 +010055 dbusIface.register_property_r(
56 "SupportedOperationTypes", std::vector<std::string>{},
57 sdbusplus::vtable::property_::const_,
58 [](const auto&) -> std::vector<std::string> {
Szymon Dompkefdb06a12022-02-11 11:04:44 +010059 return utils::transform<std::vector>(
Krzysztof Grobelny60fee072022-01-13 16:25:04 +010060 utils::convDataOperationType, [](const auto& item) {
61 return std::string(item.first);
62 });
63 });
Krzysztof Grobelny64b75a52020-09-18 10:17:16 +020064
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +020065 dbusIface.register_method(
Wludzik, Jozefe2362792020-10-27 17:23:55 +010066 "AddReport", [this](boost::asio::yield_context& yield,
Krzysztof Grobelnyb8cc78d2021-11-29 15:54:53 +010067 const std::string& reportId,
Wludzik, Jozef2f9f9b82020-10-13 09:07:45 +020068 const std::string& reportingType,
69 const bool emitsReadingsUpdate,
70 const bool logToMetricReportsCollection,
71 const uint64_t interval,
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +000072 ReadingParametersPastVersion metricParams) {
Lukasz Kazmierczak7e098e92021-09-16 15:59:56 +020073 constexpr auto enabledDefault = true;
Szymon Dompke3eb56862021-09-20 15:32:04 +020074 constexpr uint64_t appendLimitDefault = 0;
75 constexpr ReportUpdates reportUpdatesDefault =
Krzysztof Grobelny51497a02021-11-09 14:56:22 +010076 ReportUpdates::overwrite;
77
78 std::vector<ReportAction> reportActions;
79
80 if (emitsReadingsUpdate)
81 {
82 reportActions.emplace_back(
83 ReportAction::emitsReadingsUpdate);
84 }
85 if (logToMetricReportsCollection)
86 {
87 reportActions.emplace_back(
88 ReportAction::logToMetricReportsCollection);
89 }
90
Krzysztof Grobelnyb8cc78d2021-11-29 15:54:53 +010091 return addReport(yield, reportId, reportId,
Krzysztof Grobelny51497a02021-11-09 14:56:22 +010092 utils::toReportingType(reportingType),
93 reportActions, Milliseconds(interval),
94 appendLimitDefault, reportUpdatesDefault,
95 convertToReadingParameters(
96 std::move(metricParams)),
97 enabledDefault)
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +000098 .getPath();
99 });
100
101 dbusIface.register_method(
102 "AddReportFutureVersion",
Krzysztof Grobelnyb8cc78d2021-11-29 15:54:53 +0100103 [this](
104 boost::asio::yield_context& yield,
105 const std::string& reportId, const std::string& reportName,
106 const std::string& reportingType,
107 const std::string& reportUpdates,
108 const uint64_t appendLimit,
109 const std::vector<std::string>& reportActions,
110 const uint64_t interval, ReadingParameters metricParams) {
Lukasz Kazmierczak7e098e92021-09-16 15:59:56 +0200111 constexpr auto enabledDefault = true;
Krzysztof Grobelnyb8cc78d2021-11-29 15:54:53 +0100112 return addReport(yield, reportId, reportName,
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100113 utils::toReportingType(reportingType),
114 utils::transform(
115 reportActions,
116 [](const auto& reportAction) {
117 return utils::toReportAction(
118 reportAction);
119 }),
Szymon Dompke3eb56862021-09-20 15:32:04 +0200120 Milliseconds(interval), appendLimit,
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100121 utils::toReportUpdates(reportUpdates),
122 std::move(metricParams), enabledDefault)
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +0000123 .getPath();
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +0200124 });
125 });
Krzysztof Grobelny64b75a52020-09-18 10:17:16 +0200126}
127
Wludzik, Jozef2f9f9b82020-10-13 09:07:45 +0200128void ReportManager::removeReport(const interfaces::Report* report)
Krzysztof Grobelny64b75a52020-09-18 10:17:16 +0200129{
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +0200130 reports.erase(
131 std::remove_if(reports.begin(), reports.end(),
132 [report](const auto& x) { return report == x.get(); }),
133 reports.end());
Krzysztof Grobelny64b75a52020-09-18 10:17:16 +0200134}
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100135
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000136void ReportManager::verifyAddReport(
Krzysztof Grobelnyb8cc78d2021-11-29 15:54:53 +0100137 const std::string& reportId, const std::string& reportName,
138 const ReportingType reportingType, Milliseconds interval,
Ankita Vilas Gawadecd5b0b72022-01-20 20:55:04 +0000139 const ReportUpdates reportUpdates, const uint64_t appendLimit,
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000140 const std::vector<LabeledMetricParameters>& readingParams)
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100141{
142 if (reports.size() >= maxReports)
143 {
144 throw sdbusplus::exception::SdBusError(
145 static_cast<int>(std::errc::too_many_files_open),
146 "Reached maximal report count");
147 }
148
Krzysztof Grobelnye6c417c2022-02-02 17:25:53 +0100149 if (appendLimit > maxAppendLimit &&
150 appendLimit != std::numeric_limits<uint64_t>::max())
Ankita Vilas Gawadecd5b0b72022-01-20 20:55:04 +0000151 {
152 throw sdbusplus::exception::SdBusError(
153 static_cast<int>(std::errc::invalid_argument),
154 "Append limit out of range");
155 }
156
Krzysztof Grobelny973b4bb2022-04-25 17:07:27 +0200157 if ((reportingType == ReportingType::periodic && interval < minInterval) ||
158 (reportingType != ReportingType::periodic &&
159 interval != Milliseconds{0}))
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100160 {
161 throw sdbusplus::exception::SdBusError(
162 static_cast<int>(std::errc::invalid_argument), "Invalid interval");
163 }
Wludzik, Jozefbc766b42020-12-08 16:06:22 +0100164
Ankita Vilas Gawadecd5b0b72022-01-20 20:55:04 +0000165 size_t metricCount = 0;
166 for (auto metricParam : readingParams)
167 {
168 auto metricParamsVec =
169 metricParam.at_label<utils::tstring::SensorPath>();
170 metricCount += metricParamsVec.size();
171 }
Krzysztof Grobelnye8fc5752021-02-05 14:30:45 +0000172
Ankita Vilas Gawadecd5b0b72022-01-20 20:55:04 +0000173 if (readingParams.size() > maxNumberMetrics ||
174 metricCount > maxNumberMetrics)
Wludzik, Jozefbc766b42020-12-08 16:06:22 +0100175 {
176 throw sdbusplus::exception::SdBusError(
177 static_cast<int>(std::errc::argument_list_too_long),
178 "Too many reading parameters");
179 }
Krzysztof Grobelnye8fc5752021-02-05 14:30:45 +0000180
181 try
182 {
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000183 namespace ts = utils::tstring;
184
185 for (const LabeledMetricParameters& item : readingParams)
Krzysztof Grobelnye8fc5752021-02-05 14:30:45 +0000186 {
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000187 utils::toOperationType(
188 utils::toUnderlying(item.at_label<ts::OperationType>()));
Krzysztof Grobelnye8fc5752021-02-05 14:30:45 +0000189 }
190 }
191 catch (const std::exception& e)
192 {
193 throw sdbusplus::exception::SdBusError(
194 static_cast<int>(std::errc::invalid_argument), e.what());
195 }
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +0000196}
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100197
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +0000198interfaces::Report& ReportManager::addReport(
Krzysztof Grobelnyb8cc78d2021-11-29 15:54:53 +0100199 boost::asio::yield_context& yield, const std::string& reportId,
200 const std::string& reportName, const ReportingType reportingType,
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100201 const std::vector<ReportAction>& reportActions, Milliseconds interval,
202 const uint64_t appendLimit, const ReportUpdates reportUpdates,
Lukasz Kazmierczak7e098e92021-09-16 15:59:56 +0200203 ReadingParameters metricParams, const bool enabled)
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +0000204{
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000205 auto labeledMetricParams =
206 reportFactory->convertMetricParams(yield, metricParams);
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +0000207
Krzysztof Grobelnyb8cc78d2021-11-29 15:54:53 +0100208 return addReport(reportId, reportName, reportingType, reportActions,
209 interval, appendLimit, reportUpdates,
Krzysztof Grobelny493e62e2022-02-14 10:55:50 +0100210 std::move(labeledMetricParams), enabled, Readings{});
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +0000211}
212
213interfaces::Report& ReportManager::addReport(
Krzysztof Grobelnyb8cc78d2021-11-29 15:54:53 +0100214 const std::string& reportId, const std::string& reportName,
215 const ReportingType reportingType,
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100216 const std::vector<ReportAction>& reportActions, Milliseconds interval,
217 const uint64_t appendLimit, const ReportUpdates reportUpdates,
Lukasz Kazmierczak7e098e92021-09-16 15:59:56 +0200218 std::vector<LabeledMetricParameters> labeledMetricParams,
Krzysztof Grobelny493e62e2022-02-14 10:55:50 +0100219 const bool enabled, Readings readings)
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +0000220{
Krzysztof Grobelnyb8cc78d2021-11-29 15:54:53 +0100221 const auto existingReportIds = utils::transform(
222 reports, [](const auto& report) { return report->getId(); });
223
Krzysztof Grobelnya950e422021-12-31 13:49:00 +0100224 auto [id, name] = utils::generateId(reportId, reportName, reportNameDefault,
225 existingReportIds, maxReportIdLength);
Krzysztof Grobelnyb8cc78d2021-11-29 15:54:53 +0100226
227 verifyAddReport(id, name, reportingType, interval, reportUpdates,
Ankita Vilas Gawadecd5b0b72022-01-20 20:55:04 +0000228 appendLimit, labeledMetricParams);
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +0000229
Krzysztof Grobelny493e62e2022-02-14 10:55:50 +0100230 reports.emplace_back(
231 reportFactory->make(id, name, reportingType, reportActions, interval,
232 appendLimit, reportUpdates, *this, *reportStorage,
233 labeledMetricParams, enabled, std::move(readings)));
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +0000234 return *reports.back();
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100235}
236
237void ReportManager::loadFromPersistent()
238{
239 std::vector<interfaces::JsonStorage::FilePath> paths =
240 reportStorage->list();
241
242 for (const auto& path : paths)
243 {
244 std::optional<nlohmann::json> data = reportStorage->load(path);
245 try
246 {
247 size_t version = data->at("Version").get<size_t>();
248 if (version != Report::reportVersion)
249 {
250 throw std::logic_error("Invalid version");
251 }
Krzysztof Grobelnyb8cc78d2021-11-29 15:54:53 +0100252 bool enabled = data->at("Enabled").get<bool>();
253 std::string& id = data->at("Id").get_ref<std::string&>();
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100254 std::string& name = data->at("Name").get_ref<std::string&>();
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100255
256 uint32_t reportingType = data->at("ReportingType").get<uint32_t>();
257 std::vector<ReportAction> reportActions = utils::transform(
258 data->at("ReportActions").get<std::vector<uint32_t>>(),
259 [](const auto reportAction) {
260 return utils::toReportAction(reportAction);
261 });
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100262 uint64_t interval = data->at("Interval").get<uint64_t>();
Szymon Dompke3eb56862021-09-20 15:32:04 +0200263 uint64_t appendLimit = data->at("AppendLimit").get<uint64_t>();
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100264 uint32_t reportUpdates = data->at("ReportUpdates").get<uint32_t>();
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +0000265 auto readingParameters =
266 data->at("ReadingParameters")
267 .get<std::vector<LabeledMetricParameters>>();
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100268
Krzysztof Grobelny493e62e2022-02-14 10:55:50 +0100269 Readings readings = {};
270
271 if (auto it = data->find("MetricValues"); it != data->end())
272 {
273 const auto labeledReadings = it->get<LabeledReadings>();
274 readings = utils::toReadings(labeledReadings);
275 }
276
Krzysztof Grobelnyb8cc78d2021-11-29 15:54:53 +0100277 addReport(id, name, utils::toReportingType(reportingType),
Krzysztof Grobelny51497a02021-11-09 14:56:22 +0100278 reportActions, Milliseconds(interval), appendLimit,
279 utils::toReportUpdates(reportUpdates),
Krzysztof Grobelny493e62e2022-02-14 10:55:50 +0100280 std::move(readingParameters), enabled,
281 std::move(readings));
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}