blob: 24087c39ec0c45bfe29bf20429a832abbd57b4a0 [file] [log] [blame]
Krzysztof Grobelny64b75a52020-09-18 10:17:16 +02001#include "report_manager.hpp"
2
Krzysztof Grobelny9f9ff902021-03-05 14:57:53 +00003#include "interfaces/types.hpp"
Wludzik, Jozefe2362792020-10-27 17:23:55 +01004#include "report.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 Grobelny64b75a52020-09-18 10:17:16 +020014ReportManager::ReportManager(
Wludzik, Jozef2f9f9b82020-10-13 09:07:45 +020015 std::unique_ptr<interfaces::ReportFactory> reportFactoryIn,
Wludzik, Jozefe2362792020-10-27 17:23:55 +010016 std::unique_ptr<interfaces::JsonStorage> reportStorageIn,
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +020017 const std::shared_ptr<sdbusplus::asio::object_server>& objServerIn) :
Wludzik, Jozef2f9f9b82020-10-13 09:07:45 +020018 reportFactory(std::move(reportFactoryIn)),
Wludzik, Jozefe2362792020-10-27 17:23:55 +010019 reportStorage(std::move(reportStorageIn)), objServer(objServerIn)
Krzysztof Grobelny64b75a52020-09-18 10:17:16 +020020{
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +020021 reports.reserve(maxReports);
Krzysztof Grobelny6ccfcbf2020-11-04 09:31:36 +010022
Wludzik, Jozefe2362792020-10-27 17:23:55 +010023 loadFromPersistent();
Krzysztof Grobelny64b75a52020-09-18 10:17:16 +020024
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +020025 reportManagerIface = objServer->add_unique_interface(
Wludzik, Jozef2f9f9b82020-10-13 09:07:45 +020026 reportManagerPath, reportManagerIfaceName, [this](auto& dbusIface) {
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +020027 dbusIface.register_property_r(
Wludzik, Jozef503c1582020-12-11 14:48:01 +010028 "MaxReports", size_t{}, sdbusplus::vtable::property_::const_,
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +020029 [](const auto&) { return maxReports; });
30 dbusIface.register_property_r(
Karol Niczyj32859b62021-05-19 10:20:46 +020031 "MaxReportNameLength", size_t{},
32 sdbusplus::vtable::property_::const_,
33 [](const auto&) { return maxReportNameLength; });
34 dbusIface.register_property_r(
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +020035 "MinInterval", uint64_t{}, sdbusplus::vtable::property_::const_,
36 [](const auto&) -> uint64_t { return minInterval.count(); });
Krzysztof Grobelny64b75a52020-09-18 10:17:16 +020037
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +020038 dbusIface.register_method(
Wludzik, Jozefe2362792020-10-27 17:23:55 +010039 "AddReport", [this](boost::asio::yield_context& yield,
40 const std::string& reportName,
Wludzik, Jozef2f9f9b82020-10-13 09:07:45 +020041 const std::string& reportingType,
42 const bool emitsReadingsUpdate,
43 const bool logToMetricReportsCollection,
44 const uint64_t interval,
Krzysztof Grobelny9f9ff902021-03-05 14:57:53 +000045 ReadingParameters metricParams) {
Wludzik, Jozefe2362792020-10-27 17:23:55 +010046 return addReport(yield, reportName, reportingType,
47 emitsReadingsUpdate,
48 logToMetricReportsCollection,
49 std::chrono::milliseconds(interval),
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +000050 std::move(metricParams))
51 .getPath();
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +020052 });
53 });
Krzysztof Grobelny64b75a52020-09-18 10:17:16 +020054}
55
Wludzik, Jozef2f9f9b82020-10-13 09:07:45 +020056void ReportManager::removeReport(const interfaces::Report* report)
Krzysztof Grobelny64b75a52020-09-18 10:17:16 +020057{
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +020058 reports.erase(
59 std::remove_if(reports.begin(), reports.end(),
60 [report](const auto& x) { return report == x.get(); }),
61 reports.end());
Krzysztof Grobelny64b75a52020-09-18 10:17:16 +020062}
Wludzik, Jozefe2362792020-10-27 17:23:55 +010063
Karol Niczyj32859b62021-05-19 10:20:46 +020064void ReportManager::verifyReportNameLength(const std::string& reportName)
65{
66 if (reportName.length() > maxReportNameLength)
67 {
68 throw sdbusplus::exception::SdBusError(
69 static_cast<int>(std::errc::invalid_argument),
70 "Report name exceed maximum length");
71 }
72}
73
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +000074void ReportManager::verifyAddReport(const std::string& reportName,
Wludzik, Jozefbc766b42020-12-08 16:06:22 +010075 const std::string& reportingType,
76 std::chrono::milliseconds interval,
77 const ReadingParameters& readingParams)
Wludzik, Jozefe2362792020-10-27 17:23:55 +010078{
79 if (reports.size() >= maxReports)
80 {
81 throw sdbusplus::exception::SdBusError(
82 static_cast<int>(std::errc::too_many_files_open),
83 "Reached maximal report count");
84 }
85
Karol Niczyj32859b62021-05-19 10:20:46 +020086 verifyReportNameLength(reportName);
87
Wludzik, Jozefe2362792020-10-27 17:23:55 +010088 for (const auto& report : reports)
89 {
90 if (report->getName() == reportName)
91 {
92 throw sdbusplus::exception::SdBusError(
93 static_cast<int>(std::errc::file_exists), "Duplicate report");
94 }
95 }
96
Wludzik, Jozefbc766b42020-12-08 16:06:22 +010097 auto found = std::find(supportedReportingType.begin(),
98 supportedReportingType.end(), reportingType);
99 if (found == supportedReportingType.end())
100 {
101 throw sdbusplus::exception::SdBusError(
102 static_cast<int>(std::errc::invalid_argument),
103 "Invalid reportingType");
104 }
105
106 if (reportingType == "Periodic" && interval < minInterval)
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100107 {
108 throw sdbusplus::exception::SdBusError(
109 static_cast<int>(std::errc::invalid_argument), "Invalid interval");
110 }
Wludzik, Jozefbc766b42020-12-08 16:06:22 +0100111
Wludzik, Jozef503c1582020-12-11 14:48:01 +0100112 if (readingParams.size() > maxReadingParams)
Krzysztof Grobelnye8fc5752021-02-05 14:30:45 +0000113
Wludzik, Jozefbc766b42020-12-08 16:06:22 +0100114 {
115 throw sdbusplus::exception::SdBusError(
116 static_cast<int>(std::errc::argument_list_too_long),
117 "Too many reading parameters");
118 }
Krzysztof Grobelnye8fc5752021-02-05 14:30:45 +0000119
120 try
121 {
122 for (const auto& item : readingParams)
123 {
124 utils::stringToOperationType(std::get<1>(item));
125 }
126 }
127 catch (const std::exception& e)
128 {
129 throw sdbusplus::exception::SdBusError(
130 static_cast<int>(std::errc::invalid_argument), e.what());
131 }
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +0000132}
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100133
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +0000134interfaces::Report& ReportManager::addReport(
135 boost::asio::yield_context& yield, const std::string& reportName,
136 const std::string& reportingType, const bool emitsReadingsUpdate,
137 const bool logToMetricReportsCollection, std::chrono::milliseconds interval,
138 ReadingParameters metricParams)
139{
Wludzik, Jozefbc766b42020-12-08 16:06:22 +0100140 verifyAddReport(reportName, reportingType, interval, metricParams);
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +0000141
142 reports.emplace_back(reportFactory->make(
143 yield, reportName, reportingType, emitsReadingsUpdate,
144 logToMetricReportsCollection, interval, std::move(metricParams), *this,
145 *reportStorage));
146 return *reports.back();
147}
148
149interfaces::Report& ReportManager::addReport(
150 const std::string& reportName, const std::string& reportingType,
151 const bool emitsReadingsUpdate, const bool logToMetricReportsCollection,
152 std::chrono::milliseconds interval,
153 std::vector<LabeledMetricParameters> labeledMetricParams)
154{
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +0000155 auto metricParams = utils::transform(
156 labeledMetricParams, [](const LabeledMetricParameters& param) {
157 using namespace utils::tstring;
158
159 return ReadingParameters::value_type(
Krzysztof Grobelnye8fc5752021-02-05 14:30:45 +0000160 sdbusplus::message::object_path(
161 param.at_index<0>().at_label<Path>()),
162 utils::enumToString(param.at_index<1>()), param.at_index<2>(),
Krzysztof Grobelny9f9ff902021-03-05 14:57:53 +0000163 param.at_index<3>());
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +0000164 });
165
Wludzik, Jozefbc766b42020-12-08 16:06:22 +0100166 verifyAddReport(reportName, reportingType, interval, metricParams);
167
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +0000168 reports.emplace_back(reportFactory->make(
169 reportName, reportingType, emitsReadingsUpdate,
170 logToMetricReportsCollection, interval, std::move(metricParams), *this,
171 *reportStorage, labeledMetricParams));
172 return *reports.back();
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100173}
174
175void ReportManager::loadFromPersistent()
176{
177 std::vector<interfaces::JsonStorage::FilePath> paths =
178 reportStorage->list();
179
180 for (const auto& path : paths)
181 {
182 std::optional<nlohmann::json> data = reportStorage->load(path);
183 try
184 {
185 size_t version = data->at("Version").get<size_t>();
186 if (version != Report::reportVersion)
187 {
188 throw std::logic_error("Invalid version");
189 }
190 std::string& name = data->at("Name").get_ref<std::string&>();
191 std::string& reportingType =
192 data->at("ReportingType").get_ref<std::string&>();
193 bool emitsReadingsSignal =
194 data->at("EmitsReadingsUpdate").get<bool>();
195 bool logToMetricReportsCollection =
196 data->at("LogToMetricReportsCollection").get<bool>();
197 uint64_t interval = data->at("Interval").get<uint64_t>();
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +0000198 auto readingParameters =
199 data->at("ReadingParameters")
200 .get<std::vector<LabeledMetricParameters>>();
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100201
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +0000202 addReport(name, reportingType, emitsReadingsSignal,
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100203 logToMetricReportsCollection,
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +0000204 std::chrono::milliseconds(interval),
205 std::move(readingParameters));
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100206 }
207 catch (const std::exception& e)
208 {
209 phosphor::logging::log<phosphor::logging::level::ERR>(
210 "Failed to load report from storage",
211 phosphor::logging::entry(
Wludzik, Jozef982c5b52021-01-02 12:05:21 +0100212 "FILENAME=%s",
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100213 static_cast<std::filesystem::path>(path).c_str()),
Wludzik, Jozef982c5b52021-01-02 12:05:21 +0100214 phosphor::logging::entry("EXCEPTION_MSG=%s", e.what()));
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100215 reportStorage->remove(path);
216 }
217 }
218}
Wludzik, Jozefd960e1f2021-01-08 09:25:59 +0100219
220void ReportManager::updateReport(const std::string& name)
221{
222 for (auto& report : reports)
223 {
224 if (report->getName() == name)
225 {
226 report->updateReadings();
227 return;
228 }
229 }
230}