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