blob: 38b9f16a29124c5c79d85e8b7923f3cacedc8ae5 [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 Grobelny753e4b32021-02-11 12:58:58 +00004#include "types/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 Grobelny753e4b32021-02-11 12:58:58 +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::get<0>(param), std::get<1>(param), std::get<2>(param),
22 std::get<3>(param), utils::enumToString(CollectionTimeScope::point),
23 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(
44 "MinInterval", uint64_t{}, sdbusplus::vtable::property_::const_,
45 [](const auto&) -> uint64_t { return minInterval.count(); });
Krzysztof Grobelny64b75a52020-09-18 10:17:16 +020046
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +020047 dbusIface.register_method(
Wludzik, Jozefe2362792020-10-27 17:23:55 +010048 "AddReport", [this](boost::asio::yield_context& yield,
49 const std::string& reportName,
Wludzik, Jozef2f9f9b82020-10-13 09:07:45 +020050 const std::string& reportingType,
51 const bool emitsReadingsUpdate,
52 const bool logToMetricReportsCollection,
53 const uint64_t interval,
Krzysztof Grobelny753e4b32021-02-11 12:58:58 +000054 ReadingParametersPastVersion metricParams) {
55 return addReport(yield, reportName, reportingType,
56 emitsReadingsUpdate,
57 logToMetricReportsCollection,
58 std::chrono::milliseconds(interval),
59 convertToReadingParameters(
60 std::move(metricParams)))
61 .getPath();
62 });
63
64 dbusIface.register_method(
65 "AddReportFutureVersion",
66 [this](boost::asio::yield_context& yield,
67 const std::string& reportName,
68 const std::string& reportingType,
69 const bool emitsReadingsUpdate,
70 const bool logToMetricReportsCollection,
71 const uint64_t interval,
72 ReadingParameters metricParams) {
Wludzik, Jozefe2362792020-10-27 17:23:55 +010073 return addReport(yield, reportName, reportingType,
74 emitsReadingsUpdate,
75 logToMetricReportsCollection,
76 std::chrono::milliseconds(interval),
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +000077 std::move(metricParams))
78 .getPath();
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +020079 });
80 });
Krzysztof Grobelny64b75a52020-09-18 10:17:16 +020081}
82
Wludzik, Jozef2f9f9b82020-10-13 09:07:45 +020083void ReportManager::removeReport(const interfaces::Report* report)
Krzysztof Grobelny64b75a52020-09-18 10:17:16 +020084{
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +020085 reports.erase(
86 std::remove_if(reports.begin(), reports.end(),
87 [report](const auto& x) { return report == x.get(); }),
88 reports.end());
Krzysztof Grobelny64b75a52020-09-18 10:17:16 +020089}
Wludzik, Jozefe2362792020-10-27 17:23:55 +010090
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +000091void ReportManager::verifyAddReport(const std::string& reportName,
Wludzik, Jozefbc766b42020-12-08 16:06:22 +010092 const std::string& reportingType,
93 std::chrono::milliseconds interval,
94 const ReadingParameters& readingParams)
Wludzik, Jozefe2362792020-10-27 17:23:55 +010095{
96 if (reports.size() >= maxReports)
97 {
98 throw sdbusplus::exception::SdBusError(
99 static_cast<int>(std::errc::too_many_files_open),
100 "Reached maximal report count");
101 }
102
103 for (const auto& report : reports)
104 {
105 if (report->getName() == reportName)
106 {
107 throw sdbusplus::exception::SdBusError(
108 static_cast<int>(std::errc::file_exists), "Duplicate report");
109 }
110 }
111
Wludzik, Jozefbc766b42020-12-08 16:06:22 +0100112 auto found = std::find(supportedReportingType.begin(),
113 supportedReportingType.end(), reportingType);
114 if (found == supportedReportingType.end())
115 {
116 throw sdbusplus::exception::SdBusError(
117 static_cast<int>(std::errc::invalid_argument),
118 "Invalid reportingType");
119 }
120
121 if (reportingType == "Periodic" && interval < minInterval)
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100122 {
123 throw sdbusplus::exception::SdBusError(
124 static_cast<int>(std::errc::invalid_argument), "Invalid interval");
125 }
Wludzik, Jozefbc766b42020-12-08 16:06:22 +0100126
Wludzik, Jozef503c1582020-12-11 14:48:01 +0100127 if (readingParams.size() > maxReadingParams)
Krzysztof Grobelnye8fc5752021-02-05 14:30:45 +0000128
Wludzik, Jozefbc766b42020-12-08 16:06:22 +0100129 {
130 throw sdbusplus::exception::SdBusError(
131 static_cast<int>(std::errc::argument_list_too_long),
132 "Too many reading parameters");
133 }
Krzysztof Grobelnye8fc5752021-02-05 14:30:45 +0000134
135 try
136 {
137 for (const auto& item : readingParams)
138 {
139 utils::stringToOperationType(std::get<1>(item));
140 }
141 }
142 catch (const std::exception& e)
143 {
144 throw sdbusplus::exception::SdBusError(
145 static_cast<int>(std::errc::invalid_argument), e.what());
146 }
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +0000147}
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100148
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +0000149interfaces::Report& ReportManager::addReport(
150 boost::asio::yield_context& yield, const std::string& reportName,
151 const std::string& reportingType, const bool emitsReadingsUpdate,
152 const bool logToMetricReportsCollection, std::chrono::milliseconds interval,
153 ReadingParameters metricParams)
154{
Wludzik, Jozefbc766b42020-12-08 16:06:22 +0100155 verifyAddReport(reportName, reportingType, interval, metricParams);
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +0000156
157 reports.emplace_back(reportFactory->make(
158 yield, reportName, reportingType, emitsReadingsUpdate,
159 logToMetricReportsCollection, interval, std::move(metricParams), *this,
160 *reportStorage));
161 return *reports.back();
162}
163
164interfaces::Report& ReportManager::addReport(
165 const std::string& reportName, const std::string& reportingType,
166 const bool emitsReadingsUpdate, const bool logToMetricReportsCollection,
167 std::chrono::milliseconds interval,
168 std::vector<LabeledMetricParameters> labeledMetricParams)
169{
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +0000170 auto metricParams = utils::transform(
171 labeledMetricParams, [](const LabeledMetricParameters& param) {
172 using namespace utils::tstring;
173
174 return ReadingParameters::value_type(
Krzysztof Grobelnye8fc5752021-02-05 14:30:45 +0000175 sdbusplus::message::object_path(
176 param.at_index<0>().at_label<Path>()),
177 utils::enumToString(param.at_index<1>()), param.at_index<2>(),
Krzysztof Grobelny753e4b32021-02-11 12:58:58 +0000178 param.at_index<3>(), utils::enumToString(param.at_index<4>()),
179 param.at_index<5>().t.count());
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +0000180 });
181
Wludzik, Jozefbc766b42020-12-08 16:06:22 +0100182 verifyAddReport(reportName, reportingType, interval, metricParams);
183
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +0000184 reports.emplace_back(reportFactory->make(
185 reportName, reportingType, emitsReadingsUpdate,
186 logToMetricReportsCollection, interval, std::move(metricParams), *this,
187 *reportStorage, labeledMetricParams));
188 return *reports.back();
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100189}
190
191void ReportManager::loadFromPersistent()
192{
193 std::vector<interfaces::JsonStorage::FilePath> paths =
194 reportStorage->list();
195
196 for (const auto& path : paths)
197 {
198 std::optional<nlohmann::json> data = reportStorage->load(path);
199 try
200 {
201 size_t version = data->at("Version").get<size_t>();
202 if (version != Report::reportVersion)
203 {
204 throw std::logic_error("Invalid version");
205 }
206 std::string& name = data->at("Name").get_ref<std::string&>();
207 std::string& reportingType =
208 data->at("ReportingType").get_ref<std::string&>();
209 bool emitsReadingsSignal =
210 data->at("EmitsReadingsUpdate").get<bool>();
211 bool logToMetricReportsCollection =
212 data->at("LogToMetricReportsCollection").get<bool>();
213 uint64_t interval = data->at("Interval").get<uint64_t>();
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +0000214 auto readingParameters =
215 data->at("ReadingParameters")
216 .get<std::vector<LabeledMetricParameters>>();
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100217
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +0000218 addReport(name, reportingType, emitsReadingsSignal,
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100219 logToMetricReportsCollection,
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +0000220 std::chrono::milliseconds(interval),
221 std::move(readingParameters));
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100222 }
223 catch (const std::exception& e)
224 {
225 phosphor::logging::log<phosphor::logging::level::ERR>(
226 "Failed to load report from storage",
227 phosphor::logging::entry(
Wludzik, Jozef982c5b52021-01-02 12:05:21 +0100228 "FILENAME=%s",
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100229 static_cast<std::filesystem::path>(path).c_str()),
Wludzik, Jozef982c5b52021-01-02 12:05:21 +0100230 phosphor::logging::entry("EXCEPTION_MSG=%s", e.what()));
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100231 reportStorage->remove(path);
232 }
233 }
234}
Wludzik, Jozefd960e1f2021-01-08 09:25:59 +0100235
236void ReportManager::updateReport(const std::string& name)
237{
238 for (auto& report : reports)
239 {
240 if (report->getName() == name)
241 {
242 report->updateReadings();
243 return;
244 }
245 }
246}