blob: 9ea602622e5f45b338d23b231194dd9209f7321c [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(
31 "MinInterval", uint64_t{}, sdbusplus::vtable::property_::const_,
32 [](const auto&) -> uint64_t { return minInterval.count(); });
Krzysztof Grobelny64b75a52020-09-18 10:17:16 +020033
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +020034 dbusIface.register_method(
Wludzik, Jozefe2362792020-10-27 17:23:55 +010035 "AddReport", [this](boost::asio::yield_context& yield,
36 const std::string& reportName,
Wludzik, Jozef2f9f9b82020-10-13 09:07:45 +020037 const std::string& reportingType,
38 const bool emitsReadingsUpdate,
39 const bool logToMetricReportsCollection,
40 const uint64_t interval,
Krzysztof Grobelny9f9ff902021-03-05 14:57:53 +000041 ReadingParameters metricParams) {
Wludzik, Jozefe2362792020-10-27 17:23:55 +010042 return addReport(yield, reportName, reportingType,
43 emitsReadingsUpdate,
44 logToMetricReportsCollection,
45 std::chrono::milliseconds(interval),
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +000046 std::move(metricParams))
47 .getPath();
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +020048 });
49 });
Krzysztof Grobelny64b75a52020-09-18 10:17:16 +020050}
51
Wludzik, Jozef2f9f9b82020-10-13 09:07:45 +020052void ReportManager::removeReport(const interfaces::Report* report)
Krzysztof Grobelny64b75a52020-09-18 10:17:16 +020053{
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +020054 reports.erase(
55 std::remove_if(reports.begin(), reports.end(),
56 [report](const auto& x) { return report == x.get(); }),
57 reports.end());
Krzysztof Grobelny64b75a52020-09-18 10:17:16 +020058}
Wludzik, Jozefe2362792020-10-27 17:23:55 +010059
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +000060void ReportManager::verifyAddReport(const std::string& reportName,
Wludzik, Jozefbc766b42020-12-08 16:06:22 +010061 const std::string& reportingType,
62 std::chrono::milliseconds interval,
63 const ReadingParameters& readingParams)
Wludzik, Jozefe2362792020-10-27 17:23:55 +010064{
65 if (reports.size() >= maxReports)
66 {
67 throw sdbusplus::exception::SdBusError(
68 static_cast<int>(std::errc::too_many_files_open),
69 "Reached maximal report count");
70 }
71
72 for (const auto& report : reports)
73 {
74 if (report->getName() == reportName)
75 {
76 throw sdbusplus::exception::SdBusError(
77 static_cast<int>(std::errc::file_exists), "Duplicate report");
78 }
79 }
80
Wludzik, Jozefbc766b42020-12-08 16:06:22 +010081 auto found = std::find(supportedReportingType.begin(),
82 supportedReportingType.end(), reportingType);
83 if (found == supportedReportingType.end())
84 {
85 throw sdbusplus::exception::SdBusError(
86 static_cast<int>(std::errc::invalid_argument),
87 "Invalid reportingType");
88 }
89
90 if (reportingType == "Periodic" && interval < minInterval)
Wludzik, Jozefe2362792020-10-27 17:23:55 +010091 {
92 throw sdbusplus::exception::SdBusError(
93 static_cast<int>(std::errc::invalid_argument), "Invalid interval");
94 }
Wludzik, Jozefbc766b42020-12-08 16:06:22 +010095
Wludzik, Jozef503c1582020-12-11 14:48:01 +010096 if (readingParams.size() > maxReadingParams)
Krzysztof Grobelnye8fc5752021-02-05 14:30:45 +000097
Wludzik, Jozefbc766b42020-12-08 16:06:22 +010098 {
99 throw sdbusplus::exception::SdBusError(
100 static_cast<int>(std::errc::argument_list_too_long),
101 "Too many reading parameters");
102 }
Krzysztof Grobelnye8fc5752021-02-05 14:30:45 +0000103
104 try
105 {
106 for (const auto& item : readingParams)
107 {
108 utils::stringToOperationType(std::get<1>(item));
109 }
110 }
111 catch (const std::exception& e)
112 {
113 throw sdbusplus::exception::SdBusError(
114 static_cast<int>(std::errc::invalid_argument), e.what());
115 }
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +0000116}
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100117
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +0000118interfaces::Report& ReportManager::addReport(
119 boost::asio::yield_context& yield, const std::string& reportName,
120 const std::string& reportingType, const bool emitsReadingsUpdate,
121 const bool logToMetricReportsCollection, std::chrono::milliseconds interval,
122 ReadingParameters metricParams)
123{
Wludzik, Jozefbc766b42020-12-08 16:06:22 +0100124 verifyAddReport(reportName, reportingType, interval, metricParams);
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +0000125
126 reports.emplace_back(reportFactory->make(
127 yield, reportName, reportingType, emitsReadingsUpdate,
128 logToMetricReportsCollection, interval, std::move(metricParams), *this,
129 *reportStorage));
130 return *reports.back();
131}
132
133interfaces::Report& ReportManager::addReport(
134 const std::string& reportName, const std::string& reportingType,
135 const bool emitsReadingsUpdate, const bool logToMetricReportsCollection,
136 std::chrono::milliseconds interval,
137 std::vector<LabeledMetricParameters> labeledMetricParams)
138{
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +0000139 auto metricParams = utils::transform(
140 labeledMetricParams, [](const LabeledMetricParameters& param) {
141 using namespace utils::tstring;
142
143 return ReadingParameters::value_type(
Krzysztof Grobelnye8fc5752021-02-05 14:30:45 +0000144 sdbusplus::message::object_path(
145 param.at_index<0>().at_label<Path>()),
146 utils::enumToString(param.at_index<1>()), param.at_index<2>(),
Krzysztof Grobelny9f9ff902021-03-05 14:57:53 +0000147 param.at_index<3>());
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +0000148 });
149
Wludzik, Jozefbc766b42020-12-08 16:06:22 +0100150 verifyAddReport(reportName, reportingType, interval, metricParams);
151
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +0000152 reports.emplace_back(reportFactory->make(
153 reportName, reportingType, emitsReadingsUpdate,
154 logToMetricReportsCollection, interval, std::move(metricParams), *this,
155 *reportStorage, labeledMetricParams));
156 return *reports.back();
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100157}
158
159void ReportManager::loadFromPersistent()
160{
161 std::vector<interfaces::JsonStorage::FilePath> paths =
162 reportStorage->list();
163
164 for (const auto& path : paths)
165 {
166 std::optional<nlohmann::json> data = reportStorage->load(path);
167 try
168 {
169 size_t version = data->at("Version").get<size_t>();
170 if (version != Report::reportVersion)
171 {
172 throw std::logic_error("Invalid version");
173 }
174 std::string& name = data->at("Name").get_ref<std::string&>();
175 std::string& reportingType =
176 data->at("ReportingType").get_ref<std::string&>();
177 bool emitsReadingsSignal =
178 data->at("EmitsReadingsUpdate").get<bool>();
179 bool logToMetricReportsCollection =
180 data->at("LogToMetricReportsCollection").get<bool>();
181 uint64_t interval = data->at("Interval").get<uint64_t>();
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +0000182 auto readingParameters =
183 data->at("ReadingParameters")
184 .get<std::vector<LabeledMetricParameters>>();
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100185
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +0000186 addReport(name, reportingType, emitsReadingsSignal,
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100187 logToMetricReportsCollection,
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +0000188 std::chrono::milliseconds(interval),
189 std::move(readingParameters));
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100190 }
191 catch (const std::exception& e)
192 {
193 phosphor::logging::log<phosphor::logging::level::ERR>(
194 "Failed to load report from storage",
195 phosphor::logging::entry(
Wludzik, Jozef982c5b52021-01-02 12:05:21 +0100196 "FILENAME=%s",
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100197 static_cast<std::filesystem::path>(path).c_str()),
Wludzik, Jozef982c5b52021-01-02 12:05:21 +0100198 phosphor::logging::entry("EXCEPTION_MSG=%s", e.what()));
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100199 reportStorage->remove(path);
200 }
201 }
202}
Wludzik, Jozefd960e1f2021-01-08 09:25:59 +0100203
204void ReportManager::updateReport(const std::string& name)
205{
206 for (auto& report : reports)
207 {
208 if (report->getName() == name)
209 {
210 report->updateReadings();
211 return;
212 }
213 }
214}