blob: 951aa5fbdfd5f9b59439f350175e7a43ccd32cd7 [file] [log] [blame]
Krzysztof Grobelny64b75a52020-09-18 10:17:16 +02001#include "report_manager.hpp"
2
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +00003#include "interfaces/types.hpp"
Wludzik, Jozefe2362792020-10-27 17:23:55 +01004#include "report.hpp"
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +00005#include "utils/transform.hpp"
Wludzik, Jozefe2362792020-10-27 17:23:55 +01006
7#include <phosphor-logging/log.hpp>
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +02008#include <sdbusplus/exception.hpp>
9
Wludzik, Jozefe2362792020-10-27 17:23:55 +010010#include <stdexcept>
Krzysztof Grobelny64b75a52020-09-18 10:17:16 +020011#include <system_error>
12
Krzysztof Grobelny64b75a52020-09-18 10:17:16 +020013ReportManager::ReportManager(
Wludzik, Jozef2f9f9b82020-10-13 09:07:45 +020014 std::unique_ptr<interfaces::ReportFactory> reportFactoryIn,
Wludzik, Jozefe2362792020-10-27 17:23:55 +010015 std::unique_ptr<interfaces::JsonStorage> reportStorageIn,
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +020016 const std::shared_ptr<sdbusplus::asio::object_server>& objServerIn) :
Wludzik, Jozef2f9f9b82020-10-13 09:07:45 +020017 reportFactory(std::move(reportFactoryIn)),
Wludzik, Jozefe2362792020-10-27 17:23:55 +010018 reportStorage(std::move(reportStorageIn)), objServer(objServerIn)
Krzysztof Grobelny64b75a52020-09-18 10:17:16 +020019{
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +020020 reports.reserve(maxReports);
Krzysztof Grobelny6ccfcbf2020-11-04 09:31:36 +010021
Wludzik, Jozefe2362792020-10-27 17:23:55 +010022 loadFromPersistent();
Krzysztof Grobelny64b75a52020-09-18 10:17:16 +020023
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +020024 reportManagerIface = objServer->add_unique_interface(
Wludzik, Jozef2f9f9b82020-10-13 09:07:45 +020025 reportManagerPath, reportManagerIfaceName, [this](auto& dbusIface) {
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +020026 dbusIface.register_property_r(
Wludzik, Jozef503c1582020-12-11 14:48:01 +010027 "MaxReports", size_t{}, sdbusplus::vtable::property_::const_,
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +020028 [](const auto&) { return maxReports; });
29 dbusIface.register_property_r(
30 "MinInterval", uint64_t{}, sdbusplus::vtable::property_::const_,
31 [](const auto&) -> uint64_t { return minInterval.count(); });
Krzysztof Grobelny64b75a52020-09-18 10:17:16 +020032
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +020033 dbusIface.register_method(
Wludzik, Jozefe2362792020-10-27 17:23:55 +010034 "AddReport", [this](boost::asio::yield_context& yield,
35 const std::string& reportName,
Wludzik, Jozef2f9f9b82020-10-13 09:07:45 +020036 const std::string& reportingType,
37 const bool emitsReadingsUpdate,
38 const bool logToMetricReportsCollection,
39 const uint64_t interval,
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +000040 ReadingParameters metricParams) {
Wludzik, Jozefe2362792020-10-27 17:23:55 +010041 return addReport(yield, reportName, reportingType,
42 emitsReadingsUpdate,
43 logToMetricReportsCollection,
44 std::chrono::milliseconds(interval),
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +000045 std::move(metricParams))
46 .getPath();
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +020047 });
48 });
Krzysztof Grobelny64b75a52020-09-18 10:17:16 +020049}
50
Wludzik, Jozef2f9f9b82020-10-13 09:07:45 +020051void ReportManager::removeReport(const interfaces::Report* report)
Krzysztof Grobelny64b75a52020-09-18 10:17:16 +020052{
Wludzik, Jozefcb88cfd2020-09-28 16:38:57 +020053 reports.erase(
54 std::remove_if(reports.begin(), reports.end(),
55 [report](const auto& x) { return report == x.get(); }),
56 reports.end());
Krzysztof Grobelny64b75a52020-09-18 10:17:16 +020057}
Wludzik, Jozefe2362792020-10-27 17:23:55 +010058
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +000059void ReportManager::verifyAddReport(const std::string& reportName,
Wludzik, Jozefbc766b42020-12-08 16:06:22 +010060 const std::string& reportingType,
61 std::chrono::milliseconds interval,
62 const ReadingParameters& readingParams)
Wludzik, Jozefe2362792020-10-27 17:23:55 +010063{
64 if (reports.size() >= maxReports)
65 {
66 throw sdbusplus::exception::SdBusError(
67 static_cast<int>(std::errc::too_many_files_open),
68 "Reached maximal report count");
69 }
70
71 for (const auto& report : reports)
72 {
73 if (report->getName() == reportName)
74 {
75 throw sdbusplus::exception::SdBusError(
76 static_cast<int>(std::errc::file_exists), "Duplicate report");
77 }
78 }
79
Wludzik, Jozefbc766b42020-12-08 16:06:22 +010080 auto found = std::find(supportedReportingType.begin(),
81 supportedReportingType.end(), reportingType);
82 if (found == supportedReportingType.end())
83 {
84 throw sdbusplus::exception::SdBusError(
85 static_cast<int>(std::errc::invalid_argument),
86 "Invalid reportingType");
87 }
88
89 if (reportingType == "Periodic" && interval < minInterval)
Wludzik, Jozefe2362792020-10-27 17:23:55 +010090 {
91 throw sdbusplus::exception::SdBusError(
92 static_cast<int>(std::errc::invalid_argument), "Invalid interval");
93 }
Wludzik, Jozefbc766b42020-12-08 16:06:22 +010094
95 for (const auto& param : readingParams)
96 {
97 const auto& sensors = std::get<0>(param);
98 if (sensors.size() != 1)
99 {
100 throw sdbusplus::exception::SdBusError(
101 static_cast<int>(std::errc::not_supported),
102 "Only single sensor per metric is allowed");
103 }
104 }
Wludzik, Jozef503c1582020-12-11 14:48:01 +0100105 if (readingParams.size() > maxReadingParams)
Wludzik, Jozefbc766b42020-12-08 16:06:22 +0100106 {
107 throw sdbusplus::exception::SdBusError(
108 static_cast<int>(std::errc::argument_list_too_long),
109 "Too many reading parameters");
110 }
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +0000111}
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100112
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +0000113interfaces::Report& ReportManager::addReport(
114 boost::asio::yield_context& yield, const std::string& reportName,
115 const std::string& reportingType, const bool emitsReadingsUpdate,
116 const bool logToMetricReportsCollection, std::chrono::milliseconds interval,
117 ReadingParameters metricParams)
118{
Wludzik, Jozefbc766b42020-12-08 16:06:22 +0100119 verifyAddReport(reportName, reportingType, interval, metricParams);
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +0000120
121 reports.emplace_back(reportFactory->make(
122 yield, reportName, reportingType, emitsReadingsUpdate,
123 logToMetricReportsCollection, interval, std::move(metricParams), *this,
124 *reportStorage));
125 return *reports.back();
126}
127
128interfaces::Report& ReportManager::addReport(
129 const std::string& reportName, const std::string& reportingType,
130 const bool emitsReadingsUpdate, const bool logToMetricReportsCollection,
131 std::chrono::milliseconds interval,
132 std::vector<LabeledMetricParameters> labeledMetricParams)
133{
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +0000134 auto metricParams = utils::transform(
135 labeledMetricParams, [](const LabeledMetricParameters& param) {
136 using namespace utils::tstring;
137
138 return ReadingParameters::value_type(
139 utils::transform(param.at_index<0>(),
140 [](const LabeledSensorParameters& p) {
141 return sdbusplus::message::object_path(
142 p.at_label<Path>());
143 }),
144 param.at_index<1>(), param.at_index<2>(), param.at_index<3>());
145 });
146
Wludzik, Jozefbc766b42020-12-08 16:06:22 +0100147 verifyAddReport(reportName, reportingType, interval, metricParams);
148
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +0000149 reports.emplace_back(reportFactory->make(
150 reportName, reportingType, emitsReadingsUpdate,
151 logToMetricReportsCollection, interval, std::move(metricParams), *this,
152 *reportStorage, labeledMetricParams));
153 return *reports.back();
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100154}
155
156void ReportManager::loadFromPersistent()
157{
158 std::vector<interfaces::JsonStorage::FilePath> paths =
159 reportStorage->list();
160
161 for (const auto& path : paths)
162 {
163 std::optional<nlohmann::json> data = reportStorage->load(path);
164 try
165 {
166 size_t version = data->at("Version").get<size_t>();
167 if (version != Report::reportVersion)
168 {
169 throw std::logic_error("Invalid version");
170 }
171 std::string& name = data->at("Name").get_ref<std::string&>();
172 std::string& reportingType =
173 data->at("ReportingType").get_ref<std::string&>();
174 bool emitsReadingsSignal =
175 data->at("EmitsReadingsUpdate").get<bool>();
176 bool logToMetricReportsCollection =
177 data->at("LogToMetricReportsCollection").get<bool>();
178 uint64_t interval = data->at("Interval").get<uint64_t>();
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +0000179 auto readingParameters =
180 data->at("ReadingParameters")
181 .get<std::vector<LabeledMetricParameters>>();
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100182
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +0000183 addReport(name, reportingType, emitsReadingsSignal,
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100184 logToMetricReportsCollection,
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +0000185 std::chrono::milliseconds(interval),
186 std::move(readingParameters));
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100187 }
188 catch (const std::exception& e)
189 {
190 phosphor::logging::log<phosphor::logging::level::ERR>(
191 "Failed to load report from storage",
192 phosphor::logging::entry(
Wludzik, Jozef982c5b52021-01-02 12:05:21 +0100193 "FILENAME=%s",
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100194 static_cast<std::filesystem::path>(path).c_str()),
Wludzik, Jozef982c5b52021-01-02 12:05:21 +0100195 phosphor::logging::entry("EXCEPTION_MSG=%s", e.what()));
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100196 reportStorage->remove(path);
197 }
198 }
199}