blob: e40d9a44bc4ae0e660a0795b265bce99b86b0bde [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) {
Wludzik, Jozefe2362792020-10-27 17:23:55 +010059 return addReport(yield, reportName, reportingType,
60 emitsReadingsUpdate,
61 logToMetricReportsCollection,
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +000062 Milliseconds(interval),
63 convertToReadingParameters(
64 std::move(metricParams)))
65 .getPath();
66 });
67
68 dbusIface.register_method(
69 "AddReportFutureVersion",
70 [this](boost::asio::yield_context& yield,
71 const std::string& reportName,
72 const std::string& reportingType,
73 const bool emitsReadingsUpdate,
74 const bool logToMetricReportsCollection,
75 const uint64_t interval,
76 ReadingParameters metricParams) {
77 return addReport(yield, reportName, reportingType,
78 emitsReadingsUpdate,
79 logToMetricReportsCollection,
80 Milliseconds(interval),
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +000081 std::move(metricParams))
82 .getPath();
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +020083 });
84 });
Krzysztof Grobelny64b75a52020-09-18 10:17:16 +020085}
86
Wludzik, Jozef2f9f9b82020-10-13 09:07:45 +020087void ReportManager::removeReport(const interfaces::Report* report)
Krzysztof Grobelny64b75a52020-09-18 10:17:16 +020088{
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +020089 reports.erase(
90 std::remove_if(reports.begin(), reports.end(),
91 [report](const auto& x) { return report == x.get(); }),
92 reports.end());
Krzysztof Grobelny64b75a52020-09-18 10:17:16 +020093}
Wludzik, Jozefe2362792020-10-27 17:23:55 +010094
Karol Niczyj32859b62021-05-19 10:20:46 +020095void ReportManager::verifyReportNameLength(const std::string& reportName)
96{
97 if (reportName.length() > maxReportNameLength)
98 {
99 throw sdbusplus::exception::SdBusError(
100 static_cast<int>(std::errc::invalid_argument),
101 "Report name exceed maximum length");
102 }
103}
104
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000105void ReportManager::verifyAddReport(
106 const std::string& reportName, const std::string& reportingType,
107 Milliseconds interval,
108 const std::vector<LabeledMetricParameters>& readingParams)
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100109{
110 if (reports.size() >= maxReports)
111 {
112 throw sdbusplus::exception::SdBusError(
113 static_cast<int>(std::errc::too_many_files_open),
114 "Reached maximal report count");
115 }
116
Karol Niczyj32859b62021-05-19 10:20:46 +0200117 verifyReportNameLength(reportName);
118
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100119 for (const auto& report : reports)
120 {
121 if (report->getName() == reportName)
122 {
123 throw sdbusplus::exception::SdBusError(
124 static_cast<int>(std::errc::file_exists), "Duplicate report");
125 }
126 }
127
Wludzik, Jozefbc766b42020-12-08 16:06:22 +0100128 auto found = std::find(supportedReportingType.begin(),
129 supportedReportingType.end(), reportingType);
130 if (found == supportedReportingType.end())
131 {
132 throw sdbusplus::exception::SdBusError(
133 static_cast<int>(std::errc::invalid_argument),
134 "Invalid reportingType");
135 }
136
137 if (reportingType == "Periodic" && interval < minInterval)
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100138 {
139 throw sdbusplus::exception::SdBusError(
140 static_cast<int>(std::errc::invalid_argument), "Invalid interval");
141 }
Wludzik, Jozefbc766b42020-12-08 16:06:22 +0100142
Wludzik, Jozef503c1582020-12-11 14:48:01 +0100143 if (readingParams.size() > maxReadingParams)
Krzysztof Grobelnye8fc5752021-02-05 14:30:45 +0000144
Wludzik, Jozefbc766b42020-12-08 16:06:22 +0100145 {
146 throw sdbusplus::exception::SdBusError(
147 static_cast<int>(std::errc::argument_list_too_long),
148 "Too many reading parameters");
149 }
Krzysztof Grobelnye8fc5752021-02-05 14:30:45 +0000150
151 try
152 {
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000153 namespace ts = utils::tstring;
154
155 for (const LabeledMetricParameters& item : readingParams)
Krzysztof Grobelnye8fc5752021-02-05 14:30:45 +0000156 {
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000157 utils::toOperationType(
158 utils::toUnderlying(item.at_label<ts::OperationType>()));
Krzysztof Grobelnye8fc5752021-02-05 14:30:45 +0000159 }
160 }
161 catch (const std::exception& e)
162 {
163 throw sdbusplus::exception::SdBusError(
164 static_cast<int>(std::errc::invalid_argument), e.what());
165 }
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +0000166}
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100167
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +0000168interfaces::Report& ReportManager::addReport(
169 boost::asio::yield_context& yield, const std::string& reportName,
170 const std::string& reportingType, const bool emitsReadingsUpdate,
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000171 const bool logToMetricReportsCollection, Milliseconds interval,
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +0000172 ReadingParameters metricParams)
173{
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000174 auto labeledMetricParams =
175 reportFactory->convertMetricParams(yield, metricParams);
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +0000176
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000177 return addReport(reportName, reportingType, emitsReadingsUpdate,
178 logToMetricReportsCollection, interval,
179 std::move(labeledMetricParams));
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +0000180}
181
182interfaces::Report& ReportManager::addReport(
183 const std::string& reportName, const std::string& reportingType,
184 const bool emitsReadingsUpdate, const bool logToMetricReportsCollection,
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000185 Milliseconds interval,
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +0000186 std::vector<LabeledMetricParameters> labeledMetricParams)
187{
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000188 verifyAddReport(reportName, reportingType, interval, labeledMetricParams);
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +0000189
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000190 reports.emplace_back(
191 reportFactory->make(reportName, reportingType, emitsReadingsUpdate,
192 logToMetricReportsCollection, interval, *this,
193 *reportStorage, labeledMetricParams));
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +0000194 return *reports.back();
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100195}
196
197void ReportManager::loadFromPersistent()
198{
199 std::vector<interfaces::JsonStorage::FilePath> paths =
200 reportStorage->list();
201
202 for (const auto& path : paths)
203 {
204 std::optional<nlohmann::json> data = reportStorage->load(path);
205 try
206 {
207 size_t version = data->at("Version").get<size_t>();
208 if (version != Report::reportVersion)
209 {
210 throw std::logic_error("Invalid version");
211 }
212 std::string& name = data->at("Name").get_ref<std::string&>();
213 std::string& reportingType =
214 data->at("ReportingType").get_ref<std::string&>();
215 bool emitsReadingsSignal =
216 data->at("EmitsReadingsUpdate").get<bool>();
217 bool logToMetricReportsCollection =
218 data->at("LogToMetricReportsCollection").get<bool>();
219 uint64_t interval = data->at("Interval").get<uint64_t>();
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +0000220 auto readingParameters =
221 data->at("ReadingParameters")
222 .get<std::vector<LabeledMetricParameters>>();
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100223
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +0000224 addReport(name, reportingType, emitsReadingsSignal,
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000225 logToMetricReportsCollection, Milliseconds(interval),
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +0000226 std::move(readingParameters));
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100227 }
228 catch (const std::exception& e)
229 {
230 phosphor::logging::log<phosphor::logging::level::ERR>(
231 "Failed to load report from storage",
232 phosphor::logging::entry(
Wludzik, Jozef982c5b52021-01-02 12:05:21 +0100233 "FILENAME=%s",
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100234 static_cast<std::filesystem::path>(path).c_str()),
Wludzik, Jozef982c5b52021-01-02 12:05:21 +0100235 phosphor::logging::entry("EXCEPTION_MSG=%s", e.what()));
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100236 reportStorage->remove(path);
237 }
238 }
239}
Wludzik, Jozefd960e1f2021-01-08 09:25:59 +0100240
241void ReportManager::updateReport(const std::string& name)
242{
243 for (auto& report : reports)
244 {
245 if (report->getName() == name)
246 {
247 report->updateReadings();
248 return;
249 }
250 }
251}