1 #include "report_manager.hpp"
2
3 #include "report.hpp"
4 #include "types/report_types.hpp"
5 #include "utils/conversion.hpp"
6 #include "utils/dbus_path_utils.hpp"
7 #include "utils/make_id_name.hpp"
8 #include "utils/transform.hpp"
9
10 #include <phosphor-logging/log.hpp>
11 #include <sdbusplus/exception.hpp>
12 #include <sdbusplus/unpack_properties.hpp>
13
14 #include <optional>
15 #include <stdexcept>
16 #include <system_error>
17
ReportManager(std::unique_ptr<interfaces::ReportFactory> reportFactoryIn,std::unique_ptr<interfaces::JsonStorage> reportStorageIn,const std::shared_ptr<sdbusplus::asio::object_server> & objServerIn)18 ReportManager::ReportManager(
19 std::unique_ptr<interfaces::ReportFactory> reportFactoryIn,
20 std::unique_ptr<interfaces::JsonStorage> reportStorageIn,
21 const std::shared_ptr<sdbusplus::asio::object_server>& objServerIn) :
22 reportFactory(std::move(reportFactoryIn)),
23 reportStorage(std::move(reportStorageIn)), objServer(objServerIn)
24 {
25 reports.reserve(maxReports);
26
27 loadFromPersistent();
28
29 reportManagerIface = objServer->add_unique_interface(
30 reportManagerPath, reportManagerIfaceName, [this](auto& dbusIface) {
31 dbusIface.register_property_r(
32 "MaxReports", size_t{}, sdbusplus::vtable::property_::const_,
33 [](const auto&) { return maxReports; });
34 dbusIface.register_property_r(
35 "MinInterval", uint64_t{}, sdbusplus::vtable::property_::const_,
36 [](const auto&) -> uint64_t { return minInterval.count(); });
37 dbusIface.register_property_r(
38 "SupportedOperationTypes", std::vector<std::string>{},
39 sdbusplus::vtable::property_::const_,
40 [](const auto&) -> std::vector<std::string> {
41 return utils::transform<std::vector>(
42 utils::convDataOperationType, [](const auto& item) {
43 return std::string(item.first);
44 });
45 });
46 dbusIface.register_method(
47 "AddReport",
48 [this](boost::asio::yield_context& yield, std::string reportId,
49 std::string reportName, std::string reportingType,
50 std::string reportUpdates, uint64_t appendLimit,
51 std::vector<std::string> reportActions,
52 uint64_t interval, ReadingParameters readingParameters,
53 bool enabled) {
54 if (reportingType.empty())
55 {
56 reportingType =
57 utils::enumToString(ReportingType::onRequest);
58 }
59
60 if (reportUpdates.empty())
61 {
62 reportUpdates =
63 utils::enumToString(ReportUpdates::overwrite);
64 }
65
66 if (appendLimit == std::numeric_limits<uint64_t>::max())
67 {
68 appendLimit = maxAppendLimit;
69 }
70
71 if (interval == std::numeric_limits<uint64_t>::max())
72 {
73 interval = 0;
74 }
75
76 return addReport(yield, reportId, reportName,
77 utils::toReportingType(reportingType),
78 utils::transform(
79 reportActions,
80 [](const auto& reportAction) {
81 return utils::toReportAction(
82 reportAction);
83 }),
84 Milliseconds(interval), appendLimit,
85 utils::toReportUpdates(reportUpdates),
86 readingParameters, enabled)
87 .getPath();
88 });
89 });
90 }
91
removeReport(const interfaces::Report * report)92 void ReportManager::removeReport(const interfaces::Report* report)
93 {
94 reports.erase(
95 std::remove_if(reports.begin(), reports.end(),
96 [report](const auto& x) { return report == x.get(); }),
97 reports.end());
98 }
99
verifyAddReport(const std::string & reportId,const std::string & reportName,const ReportingType reportingType,Milliseconds interval,const ReportUpdates reportUpdates,const uint64_t appendLimit,const std::vector<LabeledMetricParameters> & readingParams)100 void ReportManager::verifyAddReport(
101 const std::string& reportId, const std::string& reportName,
102 const ReportingType reportingType, Milliseconds interval,
103 const ReportUpdates reportUpdates, const uint64_t appendLimit,
104 const std::vector<LabeledMetricParameters>& readingParams)
105 {
106 namespace ts = utils::tstring;
107
108 if (reports.size() >= maxReports)
109 {
110 throw sdbusplus::exception::SdBusError(
111 static_cast<int>(std::errc::too_many_files_open),
112 "Reached maximal report count");
113 }
114
115 if (appendLimit > maxAppendLimit &&
116 appendLimit != std::numeric_limits<uint64_t>::max())
117 {
118 throw errors::InvalidArgument("AppendLimit", "Out of range.");
119 }
120
121 if ((reportingType == ReportingType::periodic && interval < minInterval) ||
122 (reportingType != ReportingType::periodic &&
123 interval != Milliseconds{0}))
124 {
125 throw errors::InvalidArgument("Interval");
126 }
127
128 verifyMetricParams(readingParams);
129
130 for (const LabeledMetricParameters& item : readingParams)
131 {
132 utils::toOperationType(
133 utils::toUnderlying(item.at_label<ts::OperationType>()));
134 }
135 }
136
addReport(boost::asio::yield_context & yield,const std::string & reportId,const std::string & reportName,const ReportingType reportingType,const std::vector<ReportAction> & reportActions,Milliseconds interval,const uint64_t appendLimit,const ReportUpdates reportUpdates,ReadingParameters metricParams,const bool enabled)137 interfaces::Report& ReportManager::addReport(
138 boost::asio::yield_context& yield, const std::string& reportId,
139 const std::string& reportName, const ReportingType reportingType,
140 const std::vector<ReportAction>& reportActions, Milliseconds interval,
141 const uint64_t appendLimit, const ReportUpdates reportUpdates,
142 ReadingParameters metricParams, const bool enabled)
143 {
144 auto labeledMetricParams =
145 reportFactory->convertMetricParams(yield, metricParams);
146
147 return addReport(reportId, reportName, reportingType, reportActions,
148 interval, appendLimit, reportUpdates,
149 std::move(labeledMetricParams), enabled, Readings{});
150 }
151
addReport(const std::string & reportId,const std::string & reportName,const ReportingType reportingType,const std::vector<ReportAction> & reportActions,Milliseconds interval,const uint64_t appendLimit,const ReportUpdates reportUpdates,std::vector<LabeledMetricParameters> labeledMetricParams,const bool enabled,Readings readings)152 interfaces::Report& ReportManager::addReport(
153 const std::string& reportId, const std::string& reportName,
154 const ReportingType reportingType,
155 const std::vector<ReportAction>& reportActions, Milliseconds interval,
156 const uint64_t appendLimit, const ReportUpdates reportUpdates,
157 std::vector<LabeledMetricParameters> labeledMetricParams,
158 const bool enabled, Readings readings)
159 {
160 const auto existingReportIds = utils::transform(
161 reports, [](const auto& report) { return report->getId(); });
162
163 auto [id, name] = utils::makeIdName(reportId, reportName, reportNameDefault,
164 existingReportIds);
165
166 verifyAddReport(id, name, reportingType, interval, reportUpdates,
167 appendLimit, labeledMetricParams);
168
169 reports.emplace_back(
170 reportFactory->make(id, name, reportingType, reportActions, interval,
171 appendLimit, reportUpdates, *this, *reportStorage,
172 labeledMetricParams, enabled, std::move(readings)));
173 return *reports.back();
174 }
175
loadFromPersistent()176 void ReportManager::loadFromPersistent()
177 {
178 std::vector<interfaces::JsonStorage::FilePath> paths =
179 reportStorage->list();
180
181 for (const auto& path : paths)
182 {
183 std::optional<nlohmann::json> data = reportStorage->load(path);
184 try
185 {
186 size_t version = data->at("Version").get<size_t>();
187 if (version != Report::reportVersion)
188 {
189 throw std::logic_error("Invalid version");
190 }
191 bool enabled = data->at("Enabled").get<bool>();
192 std::string& id = data->at("Id").get_ref<std::string&>();
193 std::string& name = data->at("Name").get_ref<std::string&>();
194
195 uint32_t reportingType = data->at("ReportingType").get<uint32_t>();
196 std::vector<ReportAction> reportActions = utils::transform(
197 data->at("ReportActions").get<std::vector<uint32_t>>(),
198 [](const auto reportAction) {
199 return utils::toReportAction(reportAction);
200 });
201 uint64_t interval = data->at("Interval").get<uint64_t>();
202 uint64_t appendLimit = data->at("AppendLimit").get<uint64_t>();
203 uint32_t reportUpdates = data->at("ReportUpdates").get<uint32_t>();
204 auto readingParameters =
205 data->at("ReadingParameters")
206 .get<std::vector<LabeledMetricParameters>>();
207
208 Readings readings = {};
209
210 if (auto it = data->find("MetricValues"); it != data->end())
211 {
212 const auto labeledReadings = it->get<LabeledReadings>();
213 readings = utils::toReadings(labeledReadings);
214 }
215
216 addReport(id, name, utils::toReportingType(reportingType),
217 reportActions, Milliseconds(interval), appendLimit,
218 utils::toReportUpdates(reportUpdates),
219 std::move(readingParameters), enabled,
220 std::move(readings));
221 }
222 catch (const std::exception& e)
223 {
224 phosphor::logging::log<phosphor::logging::level::ERR>(
225 "Failed to load report from storage",
226 phosphor::logging::entry(
227 "FILENAME=%s",
228 static_cast<std::filesystem::path>(path).c_str()),
229 phosphor::logging::entry("EXCEPTION_MSG=%s", e.what()));
230 reportStorage->remove(path);
231 }
232 }
233 }
234
verifyMetricParams(const std::vector<LabeledMetricParameters> & metricParams)235 void ReportManager::verifyMetricParams(
236 const std::vector<LabeledMetricParameters>& metricParams)
237 {
238 size_t metricCount = 0;
239 for (const auto& metricParam : metricParams)
240 {
241 auto metricParamsVec =
242 metricParam.at_label<utils::tstring::SensorPath>();
243 metricCount += metricParamsVec.size();
244 }
245
246 if (metricParams.size() > ReportManager::maxNumberMetrics ||
247 metricCount > ReportManager::maxNumberMetrics)
248 {
249 throw errors::InvalidArgument("ReadingParameters", "Too many");
250 }
251 }
252